diff --git a/kernel/kernelcore.S b/kernel/kernelcore.S index f57ba74d..4811f8f0 100644 --- a/kernel/kernelcore.S +++ b/kernel/kernelcore.S @@ -176,12 +176,12 @@ outb %al, $0x92 mov %eax, %cr0 # store the status word # (we are now in protected mode) mov $2*8, %ax # selector two is flat 4GB data data - mov %ax, %ds # set stack and data segments to selector two + mov %ax, %ds # set data, extra, and stack segments to selector two + mov %ax, %es mov %ax, %ss mov $5*8, %ax # set TSS to selector five ltr %ax mov $0, %ax # unused segments are nulled out - mov %ax, %es mov %ax, %fs mov %ax, %gs mov $INTERRUPT_STACK_TOP, %sp # set up initial C stack @@ -404,34 +404,42 @@ intr47: pushl $0 ; pushl $47 ; jmp intr_handler intr48: pushl $0 ; pushl $48 ; jmp intr_syscall intr_handler: - pushl %ds - pushl %ebp # push regs + pushl %ds # push segment registers + pushl %es + pushl %fs + pushl %gs + pushl %ebp # push general regs pushl %edi pushl %esi pushl %edx pushl %ecx pushl %ebx pushl %eax - pushl 36(%esp) # push interrupt code - pushl 36(%esp) # push interrupt number - movl $2*8, %eax # switch to kernel data seg + pushl 48(%esp) # push interrupt code from above + pushl 48(%esp) # push interrupt number from above + movl $2*8, %eax # switch to kernel data seg and extra seg movl %eax, %ds + movl %eax, %es call interrupt_handler addl $4, %esp # remove interrupt number addl $4, %esp # remove interrupt code jmp intr_return intr_syscall: - pushl %ds - pushl %ebp # push regs + pushl %ds # push segment registers + pushl %es + pushl %fs + pushl %gs + pushl %ebp # push general regs pushl %edi pushl %esi pushl %edx pushl %ecx pushl %ebx pushl %eax # note these *are* the syscall args - movl $2*8, %eax # switch to kernel data seg + movl $2*8, %eax # switch to kernel data seg and extra seg movl %eax, %ds + movl %eax, %es call syscall_handler addl $4, %esp # remove the old eax jmp syscall_return @@ -446,6 +454,9 @@ syscall_return: popl %esi popl %edi popl %ebp + popl %gs + popl %fs + popl %es popl %ds addl $4, %esp # remove interrupt num addl $4, %esp # remove detail code diff --git a/kernel/process.c b/kernel/process.c index b95b60fb..a453fcf3 100644 --- a/kernel/process.c +++ b/kernel/process.c @@ -48,6 +48,9 @@ void process_kstack_reset(struct process *p, unsigned entry_point) s->regs2.ebp = (uint32_t) (p->kstack_ptr + 28); s->old_ebp = (uint32_t) (p->kstack_ptr + 32); s->old_eip = (unsigned) intr_return; + s->fs = 0; + s->gs = 0; + s->es = X86_SEGMENT_USER_DATA; s->ds = X86_SEGMENT_USER_DATA; s->cs = X86_SEGMENT_USER_CODE; s->eip = entry_point; diff --git a/kernel/x86.h b/kernel/x86.h index 62ceb276..5d88b2dd 100644 --- a/kernel/x86.h +++ b/kernel/x86.h @@ -57,13 +57,21 @@ struct x86_regs { }; struct x86_stack { + /* Registers saved by process_switch */ struct x86_regs regs2; + /* Stack frame of process_switch */ int32_t old_ebp; int32_t old_eip; + /* Pushed by intr_handler in kernelcore */ struct x86_regs regs1; + int32_t gs; + int32_t fs; + int32_t es; int32_t ds; + /* Pushed by intrXX in kernelcore. */ int32_t intr_num; int32_t intr_code; + /* Pushed by X86 CPU Hardware. */ int32_t eip; int32_t cs; struct x86_eflags eflags; diff --git a/user/sysstat.c b/user/sysstat.c index 4cf37474..a723fdfb 100644 --- a/user/sysstat.c +++ b/user/sysstat.c @@ -11,21 +11,6 @@ See the file LICENSE for details. int main(int argc, char *argv[]) { - /* - This demonstrates (and fixes) a kernel bug. - GCC implements the initialization of the structure on the stack like this: - rep stos %eax,%es:(%edi) - However, basekernel does not automatically set up (or save) the es segment register, - and so the operation crashes. The es register should be set up correctly in kernelcore, - saved and restored when processing interrupts/system calls, and also initialized correctly - using process_kstack_init. - */ - - /* The workaround here is to explicitly set up the es register prior to using it.*/ - - asm("mov %ds, %ax"); - asm("mov %ax, %es"); - struct system_stats s = {0}; if (syscall_system_stats(&s)) {