Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[IA64] Save I-resources to ia64_sal_os_state

This is a patch related to this discussion.
http://www.spinics.net/lists/linux-ia64/msg07605.html

When INIT is sent, ip/psr/pfs register is stored to the I-resources
(iip/ipsr/ifs registers), and they are copied in the min-state save
area(pmsa_{iip,ipsr,ifs}).

Therefore, in creating pt_regs at ia64_mca_modify_original_stack(),
cr_{iip,ipsr,ifs} should be derived from pmsa_{iip,ipsr,ifs}. But
current code copies pmsa_{xip,xpsr,xfs} to cr_{iip,ipsr,ifs}
when PSR.ic is 0.

finish_pt_regs(struct pt_regs *regs, const pal_min_state_area_t *ms,
unsigned long *nat)
{
(snip)
if (ia64_psr(regs)->ic) {
regs->cr_iip = ms->pmsa_iip;
regs->cr_ipsr = ms->pmsa_ipsr;
regs->cr_ifs = ms->pmsa_ifs;
} else {
regs->cr_iip = ms->pmsa_xip;
regs->cr_ipsr = ms->pmsa_xpsr;
regs->cr_ifs = ms->pmsa_xfs;
}

It's ok when PSR.ic is not 0. But when PSR.ic is 0, this could be
a problem when we investigate kernel as the value of regs->cr_iip does
not point to where INIT really interrupted.

At first I tried to change finish_pt_regs() so that it uses always
pmsa_{iip,ipsr,ifs} for cr_{iip,ipsr,ifs}, but Keith Owens pointed out
it could cause another problem if I change it.

>The only problem I can think of is an MCA/INIT
>arriving while code like SAVE_MIN or SAVE_REST is executing. Back
>tracing at that point using pmsa_iip is going to be a problem, you have
>no idea what state the registers or stack are in.

I confirmed he was right, so I decided to keep it as-is and to
save pmsa_{iip,ipsr,ifs} to ia64_sal_os_state for debugging.

An attached patch is just adding new members into ia64_sal_os_state to
save pmsa_{iip,ipsr,ifs}.

Signed-off-by: Takao Indoh <indou.takao@jp.fujitsu.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>

authored by

Takao Indoh and committed by
Tony Luck
9ee27c76 09b366b7

+13 -3
+5
arch/ia64/include/asm/mca.h
··· 106 106 unsigned long os_status; /* OS status to SAL, enum below */ 107 107 unsigned long context; /* 0 if return to same context 108 108 1 if return to new context */ 109 + 110 + /* I-resources */ 111 + unsigned long iip; 112 + unsigned long ipsr; 113 + unsigned long ifs; 109 114 }; 110 115 111 116 enum {
+8 -3
arch/ia64/kernel/mca.c
··· 888 888 } 889 889 890 890 static void 891 - finish_pt_regs(struct pt_regs *regs, const pal_min_state_area_t *ms, 891 + finish_pt_regs(struct pt_regs *regs, struct ia64_sal_os_state *sos, 892 892 unsigned long *nat) 893 893 { 894 + const pal_min_state_area_t *ms = sos->pal_min_state; 894 895 const u64 *bank; 895 896 896 897 /* If ipsr.ic then use pmsa_{iip,ipsr,ifs}, else use ··· 905 904 regs->cr_iip = ms->pmsa_xip; 906 905 regs->cr_ipsr = ms->pmsa_xpsr; 907 906 regs->cr_ifs = ms->pmsa_xfs; 907 + 908 + sos->iip = ms->pmsa_iip; 909 + sos->ipsr = ms->pmsa_ipsr; 910 + sos->ifs = ms->pmsa_ifs; 908 911 } 909 912 regs->pr = ms->pmsa_pr; 910 913 regs->b0 = ms->pmsa_br0; ··· 1084 1079 memcpy(old_regs, regs, sizeof(*regs)); 1085 1080 old_regs->loadrs = loadrs; 1086 1081 old_unat = old_regs->ar_unat; 1087 - finish_pt_regs(old_regs, ms, &old_unat); 1082 + finish_pt_regs(old_regs, sos, &old_unat); 1088 1083 1089 1084 /* Next stack a struct switch_stack. mca_asm.S built a partial 1090 1085 * switch_stack, copy it and fill in the blanks using pt_regs and ··· 1155 1150 mprintk(KERN_INFO "cpu %d, %s %s, original stack not modified\n", 1156 1151 smp_processor_id(), type, msg); 1157 1152 old_unat = regs->ar_unat; 1158 - finish_pt_regs(regs, ms, &old_unat); 1153 + finish_pt_regs(regs, sos, &old_unat); 1159 1154 return previous_current; 1160 1155 } 1161 1156