Fix sysenter and syscall features.
Those features were not configured properly and had a race-condition when enabling back interrupts before a sysexit/sysret. Configuration: The BSP is executing tss_init on behalf of APs. Thus any writes in the MSRs in tss_init would end up in the BSP's MSRs leading to: * BSP not using the correct kernel stack. * APs using undefined instruction/stack pointer and code segment upon entering the kernel. Fix: Let the cores writing in their own MSRs. Race-condition: When restoring a process' EFLAGS before a sysexit/sysret interrupts could be enabled while the core was still in the kernel. If an interrupt is triggered at this point it would lead to a deadlock on the BKL down the line. Fix: Disable IF in saved EFLAGS and use sti before sysexit/sysret.
This commit is contained in:
parent
f9accfb8ff
commit
b1b2735c60
|
|
@ -218,6 +218,9 @@ static void ap_finish_booting(void)
|
|||
/* inform the world of our presence. */
|
||||
ap_cpu_ready = cpu;
|
||||
|
||||
/* Set up sysenter/syscall. */
|
||||
setup_sysenter_syscall();
|
||||
|
||||
/*
|
||||
* Finish processor initialisation. CPUs must be excluded from running.
|
||||
* lapic timer calibration locks and unlocks the BKL because of the
|
||||
|
|
@ -298,6 +301,7 @@ void smp_init (void)
|
|||
ioapic_enabled = 0;
|
||||
|
||||
tss_init_all();
|
||||
setup_sysenter_syscall();
|
||||
|
||||
/*
|
||||
* we still run on the boot stack and we cannot use cpuid as its value
|
||||
|
|
|
|||
|
|
@ -249,6 +249,11 @@ reg_t read_ebp(void);
|
|||
*/
|
||||
int tss_init(unsigned cpu, void * kernel_stack);
|
||||
|
||||
/*
|
||||
* Set up MSRs for sysenter or syscall for the current cpu.
|
||||
* Assumes that tss_init has been called before for that cpu ! */
|
||||
void setup_sysenter_syscall(void);
|
||||
|
||||
void int_gate_idt(unsigned vec_nr, vir_bytes offset, unsigned dpl_type);
|
||||
|
||||
void __copy_msg_from_user_end(void);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
#define smp_single_cpu_fallback() do { \
|
||||
tss_init(0, get_k_stack_top(0)); \
|
||||
setup_sysenter_syscall(); \
|
||||
bsp_cpu_id = 0; \
|
||||
ncpus = 1; \
|
||||
bsp_finish_booting(); \
|
||||
|
|
|
|||
|
|
@ -405,6 +405,7 @@ ENTRY(restore_user_context_sysenter)
|
|||
|
||||
/* restore PSW */
|
||||
movl PSWREG(%ebp), %edi /* load desired PSW to EDI */
|
||||
andl $0xfffffdff, %edi /* Clear IF to avoid receiving int. */
|
||||
push %edi
|
||||
popf
|
||||
|
||||
|
|
@ -421,6 +422,7 @@ ENTRY(restore_user_context_syscall)
|
|||
|
||||
/* restore PSW (before we switch to user stack!) */
|
||||
movl PSWREG(%ebp), %edi /* load desired PSW to EDI */
|
||||
andl $0xfffffdff, %edi /* Clear IF to avoid receiving int. */
|
||||
push %edi
|
||||
popf
|
||||
|
||||
|
|
@ -429,6 +431,7 @@ ENTRY(restore_user_context_syscall)
|
|||
mov AXREG(%ebp), %eax /* trap return value */
|
||||
mov BXREG(%ebp), %ebx /* secondary return value */
|
||||
|
||||
sti
|
||||
sysret /* jump to EIP in user */
|
||||
|
||||
ENTRY(restore_user_context_int)
|
||||
|
|
|
|||
|
|
@ -151,35 +151,10 @@ static struct gate_table_s gate_table_exceptions[] = {
|
|||
{ NULL, 0, 0}
|
||||
};
|
||||
|
||||
int tss_init(unsigned cpu, void * kernel_stack)
|
||||
void setup_sysenter_syscall(void)
|
||||
{
|
||||
struct tss_s * t = &tss[cpu];
|
||||
int index = TSS_INDEX(cpu);
|
||||
struct segdesc_s *tssgdt;
|
||||
|
||||
tssgdt = &gdt[index];
|
||||
|
||||
init_param_dataseg(tssgdt, (phys_bytes) t,
|
||||
sizeof(struct tss_s), INTR_PRIVILEGE);
|
||||
tssgdt->access = PRESENT | (INTR_PRIVILEGE << DPL_SHIFT) | TSS_TYPE;
|
||||
|
||||
/* Build TSS. */
|
||||
memset(t, 0, sizeof(*t));
|
||||
t->ds = t->es = t->fs = t->gs = t->ss0 = KERN_DS_SELECTOR;
|
||||
t->cs = KERN_CS_SELECTOR;
|
||||
t->iobase = sizeof(struct tss_s); /* empty i/o permissions map */
|
||||
|
||||
/*
|
||||
* make space for process pointer and cpu id and point to the first
|
||||
* usable word
|
||||
*/
|
||||
k_percpu_stacks[cpu] = t->sp0 = ((unsigned) kernel_stack) - X86_STACK_TOP_RESERVED;
|
||||
/*
|
||||
* set the cpu id at the top of the stack so we know on which cpu is
|
||||
* this stack in use when we trap to kernel
|
||||
*/
|
||||
*((reg_t *)(t->sp0 + 1 * sizeof(reg_t))) = cpu;
|
||||
|
||||
const int cpu = cpuid;
|
||||
struct tss_s const *const t = &tss[cpu];
|
||||
/* Set up Intel SYSENTER support if available. */
|
||||
if(minix_feature_flags & MKF_I386_INTEL_SYSENTER) {
|
||||
ia32_msr_write(INTEL_MSR_SYSENTER_CS, 0, KERN_CS_SELECTOR);
|
||||
|
|
@ -211,7 +186,36 @@ int tss_init(unsigned cpu, void * kernel_stack)
|
|||
set_star_cpu(7);
|
||||
assert(CONFIG_MAX_CPUS <= 8);
|
||||
}
|
||||
}
|
||||
|
||||
int tss_init(unsigned cpu, void * kernel_stack)
|
||||
{
|
||||
struct tss_s * t = &tss[cpu];
|
||||
int index = TSS_INDEX(cpu);
|
||||
struct segdesc_s *tssgdt;
|
||||
|
||||
tssgdt = &gdt[index];
|
||||
|
||||
init_param_dataseg(tssgdt, (phys_bytes) t,
|
||||
sizeof(struct tss_s), INTR_PRIVILEGE);
|
||||
tssgdt->access = PRESENT | (INTR_PRIVILEGE << DPL_SHIFT) | TSS_TYPE;
|
||||
|
||||
/* Build TSS. */
|
||||
memset(t, 0, sizeof(*t));
|
||||
t->ds = t->es = t->fs = t->gs = t->ss0 = KERN_DS_SELECTOR;
|
||||
t->cs = KERN_CS_SELECTOR;
|
||||
t->iobase = sizeof(struct tss_s); /* empty i/o permissions map */
|
||||
|
||||
/*
|
||||
* make space for process pointer and cpu id and point to the first
|
||||
* usable word
|
||||
*/
|
||||
k_percpu_stacks[cpu] = t->sp0 = ((unsigned) kernel_stack) - X86_STACK_TOP_RESERVED;
|
||||
/*
|
||||
* set the cpu id at the top of the stack so we know on which cpu is
|
||||
* this stack in use when we trap to kernel
|
||||
*/
|
||||
*((reg_t *)(t->sp0 + 1 * sizeof(reg_t))) = cpu;
|
||||
return SEG_SELECTOR(index);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ void bsp_finish_booting(void)
|
|||
sprofiling = 0; /* we're not profiling until instructed to */
|
||||
#endif /* SPROFILE */
|
||||
|
||||
setup_sysenter_syscall();
|
||||
cpu_identify();
|
||||
|
||||
vm_running = 0;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user