mca.c (9336b0836bf789136b51caf9ddd49dcbf1726cf4) mca.c (e9ac054daaecf8a11f2113b60f2b6ce381c4f131)
1/*
2 * File: mca.c
3 * Purpose: Generic MCA handling layer
4 *
5 * Updated for latest kernel
6 * Copyright (C) 2003 Hewlett-Packard Co
7 * David Mosberger-Tang <davidm@hpl.hp.com>
8 *

--- 616 unchanged lines hidden (view full) ---

625 *tr = *fr;
626 fslot = ((unsigned long)fr >> 3) & 63;
627 tslot = ((unsigned long)tr >> 3) & 63;
628 *tnat &= ~(1UL << tslot);
629 nat = (fnat >> fslot) & 1;
630 *tnat |= (nat << tslot);
631}
632
1/*
2 * File: mca.c
3 * Purpose: Generic MCA handling layer
4 *
5 * Updated for latest kernel
6 * Copyright (C) 2003 Hewlett-Packard Co
7 * David Mosberger-Tang <davidm@hpl.hp.com>
8 *

--- 616 unchanged lines hidden (view full) ---

625 *tr = *fr;
626 fslot = ((unsigned long)fr >> 3) & 63;
627 tslot = ((unsigned long)tr >> 3) & 63;
628 *tnat &= ~(1UL << tslot);
629 nat = (fnat >> fslot) & 1;
630 *tnat |= (nat << tslot);
631}
632
633/* Change the comm field on the MCA/INT task to include the pid that
634 * was interrupted, it makes for easier debugging. If that pid was 0
635 * (swapper or nested MCA/INIT) then use the start of the previous comm
636 * field suffixed with its cpu.
637 */
638
639static void
640ia64_mca_modify_comm(const task_t *previous_current)
641{
642 char *p, comm[sizeof(current->comm)];
643 if (previous_current->pid)
644 snprintf(comm, sizeof(comm), "%s %d",
645 current->comm, previous_current->pid);
646 else {
647 int l;
648 if ((p = strchr(previous_current->comm, ' ')))
649 l = p - previous_current->comm;
650 else
651 l = strlen(previous_current->comm);
652 snprintf(comm, sizeof(comm), "%s %*s %d",
653 current->comm, l, previous_current->comm,
654 task_thread_info(previous_current)->cpu);
655 }
656 memcpy(current->comm, comm, sizeof(current->comm));
657}
658
633/* On entry to this routine, we are running on the per cpu stack, see
634 * mca_asm.h. The original stack has not been touched by this event. Some of
635 * the original stack's registers will be in the RBS on this stack. This stack
636 * also contains a partial pt_regs and switch_stack, the rest of the data is in
637 * PAL minstate.
638 *
639 * The first thing to do is modify the original stack to look like a blocked
640 * task so we can run backtrace on the original task. Also mark the per cpu
641 * stack as current to ensure that we use the correct task state, it also means
642 * that we can do backtrace on the MCA/INIT handler code itself.
643 */
644
645static task_t *
646ia64_mca_modify_original_stack(struct pt_regs *regs,
647 const struct switch_stack *sw,
648 struct ia64_sal_os_state *sos,
649 const char *type)
650{
659/* On entry to this routine, we are running on the per cpu stack, see
660 * mca_asm.h. The original stack has not been touched by this event. Some of
661 * the original stack's registers will be in the RBS on this stack. This stack
662 * also contains a partial pt_regs and switch_stack, the rest of the data is in
663 * PAL minstate.
664 *
665 * The first thing to do is modify the original stack to look like a blocked
666 * task so we can run backtrace on the original task. Also mark the per cpu
667 * stack as current to ensure that we use the correct task state, it also means
668 * that we can do backtrace on the MCA/INIT handler code itself.
669 */
670
671static task_t *
672ia64_mca_modify_original_stack(struct pt_regs *regs,
673 const struct switch_stack *sw,
674 struct ia64_sal_os_state *sos,
675 const char *type)
676{
651 char *p, comm[sizeof(current->comm)];
677 char *p;
652 ia64_va va;
653 extern char ia64_leave_kernel[]; /* Need asm address, not function descriptor */
654 const pal_min_state_area_t *ms = sos->pal_min_state;
655 task_t *previous_current;
656 struct pt_regs *old_regs;
657 struct switch_stack *old_sw;
658 unsigned size = sizeof(struct pt_regs) +
659 sizeof(struct switch_stack) + 16;

--- 56 unchanged lines hidden (view full) ---

716 slots = ia64_rse_num_regs(old_bspstore, old_bsp);
717 new_bspstore = (u64 *)((u64)current + IA64_RBS_OFFSET);
718 new_bsp = ia64_rse_skip_regs(new_bspstore, slots);
719 regs->loadrs = (new_bsp - new_bspstore) * 8 << 16;
720
721 /* Verify the previous stack state before we change it */
722 if (user_mode(regs)) {
723 msg = "occurred in user space";
678 ia64_va va;
679 extern char ia64_leave_kernel[]; /* Need asm address, not function descriptor */
680 const pal_min_state_area_t *ms = sos->pal_min_state;
681 task_t *previous_current;
682 struct pt_regs *old_regs;
683 struct switch_stack *old_sw;
684 unsigned size = sizeof(struct pt_regs) +
685 sizeof(struct switch_stack) + 16;

--- 56 unchanged lines hidden (view full) ---

742 slots = ia64_rse_num_regs(old_bspstore, old_bsp);
743 new_bspstore = (u64 *)((u64)current + IA64_RBS_OFFSET);
744 new_bsp = ia64_rse_skip_regs(new_bspstore, slots);
745 regs->loadrs = (new_bsp - new_bspstore) * 8 << 16;
746
747 /* Verify the previous stack state before we change it */
748 if (user_mode(regs)) {
749 msg = "occurred in user space";
750 /* previous_current is guaranteed to be valid when the task was
751 * in user space, so ...
752 */
753 ia64_mca_modify_comm(previous_current);
724 goto no_mod;
725 }
726 if (r13 != sos->prev_IA64_KR_CURRENT) {
727 msg = "inconsistent previous current and r13";
728 goto no_mod;
729 }
730 if ((r12 - r13) >= KERNEL_STACK_SIZE) {
731 msg = "inconsistent r12 and r13";

--- 13 unchanged lines hidden (view full) ---

745 goto no_mod;
746 }
747 size += (ia64_rse_skip_regs(old_bspstore, slots) - old_bspstore) * 8;
748 if (ar_bspstore + size > r12) {
749 msg = "no room for blocked state";
750 goto no_mod;
751 }
752
754 goto no_mod;
755 }
756 if (r13 != sos->prev_IA64_KR_CURRENT) {
757 msg = "inconsistent previous current and r13";
758 goto no_mod;
759 }
760 if ((r12 - r13) >= KERNEL_STACK_SIZE) {
761 msg = "inconsistent r12 and r13";

--- 13 unchanged lines hidden (view full) ---

775 goto no_mod;
776 }
777 size += (ia64_rse_skip_regs(old_bspstore, slots) - old_bspstore) * 8;
778 if (ar_bspstore + size > r12) {
779 msg = "no room for blocked state";
780 goto no_mod;
781 }
782
753 /* Change the comm field on the MCA/INT task to include the pid that
754 * was interrupted, it makes for easier debugging. If that pid was 0
755 * (swapper or nested MCA/INIT) then use the start of the previous comm
756 * field suffixed with its cpu.
757 */
758 if (previous_current->pid)
759 snprintf(comm, sizeof(comm), "%s %d",
760 current->comm, previous_current->pid);
761 else {
762 int l;
763 if ((p = strchr(previous_current->comm, ' ')))
764 l = p - previous_current->comm;
765 else
766 l = strlen(previous_current->comm);
767 snprintf(comm, sizeof(comm), "%s %*s %d",
768 current->comm, l, previous_current->comm,
769 task_thread_info(previous_current)->cpu);
770 }
771 memcpy(current->comm, comm, sizeof(current->comm));
783 ia64_mca_modify_comm(previous_current);
772
773 /* Make the original task look blocked. First stack a struct pt_regs,
774 * describing the state at the time of interrupt. mca_asm.S built a
775 * partial pt_regs, copy it and fill in the blanks using minstate.
776 */
777 p = (char *)r12 - sizeof(*regs);
778 old_regs = (struct pt_regs *)p;
779 memcpy(old_regs, regs, sizeof(*regs));

--- 965 unchanged lines hidden ---
784
785 /* Make the original task look blocked. First stack a struct pt_regs,
786 * describing the state at the time of interrupt. mca_asm.S built a
787 * partial pt_regs, copy it and fill in the blanks using minstate.
788 */
789 p = (char *)r12 - sizeof(*regs);
790 old_regs = (struct pt_regs *)p;
791 memcpy(old_regs, regs, sizeof(*regs));

--- 965 unchanged lines hidden ---