From 516294151e5969d4f41246784efb41bad961793f Mon Sep 17 00:00:00 2001 From: Greg Haerr Date: Mon, 2 Sep 2024 17:25:41 -0600 Subject: [PATCH 1/2] [kernel] Use early temp stack to avoid irqit stack overruns on faults during startup --- elks/arch/i86/boot/crt0.S | 4 ++-- elks/arch/i86/drivers/char/mem.c | 2 +- elks/arch/i86/kernel/Makefile | 3 ++- elks/arch/i86/kernel/irq.c | 10 ++++++--- elks/arch/i86/kernel/irqtab.S | 38 ++++++++++++++++++++++++++++++-- elks/include/arch/irq.h | 3 ++- elks/include/linuxmt/init.h | 1 - elks/init/main.c | 14 ++++++------ 8 files changed, 57 insertions(+), 18 deletions(-) diff --git a/elks/arch/i86/boot/crt0.S b/elks/arch/i86/boot/crt0.S index 749d6c433..b1e669120 100644 --- a/elks/arch/i86/boot/crt0.S +++ b/elks/arch/i86/boot/crt0.S @@ -45,7 +45,7 @@ _start: mov %ds,%ax mov %ax,%ss // SS=ES=DS - mov $istack,%sp + mov $tstack,%sp // can't use kernel interrupt stack, must have temp stack call start_kernel // fall through into breakpoint if returns @@ -80,7 +80,7 @@ early_putchar: .global _endbss .extern kernel_cs .extern kernel_ds - .extern istack + .extern tstack _endtext: .word 0 diff --git a/elks/arch/i86/drivers/char/mem.c b/elks/arch/i86/drivers/char/mem.c index 5a3ca3188..9c28b8c27 100644 --- a/elks/arch/i86/drivers/char/mem.c +++ b/elks/arch/i86/drivers/char/mem.c @@ -240,7 +240,7 @@ int kmem_ioctl(struct inode *inode, struct file *file, int cmd, char *arg) retword = kernel_ds; break; case MEM_GETFARTEXT: - retword = (unsigned)((long)kernel_init >> 16); + retword = (unsigned)((long)buffer_init >> 16); break; case MEM_GETUSAGE: mm_get_usage (&(mu.free_memory), &(mu.used_memory)); diff --git a/elks/arch/i86/kernel/Makefile b/elks/arch/i86/kernel/Makefile index 125f5f20b..9872fa287 100644 --- a/elks/arch/i86/kernel/Makefile +++ b/elks/arch/i86/kernel/Makefile @@ -39,7 +39,8 @@ OBJS = strace.o system.o irq.o irqtab.o process.o \ entry.o signal.o timer.o ifeq ($(CONFIG_ARCH_IBMPC), y) -OBJS += irq-8259.o timer-8254.o divzero.o +OBJS += irq-8259.o timer-8254.o +#OBJS += divzero.o endif ifeq ($(CONFIG_ARCH_PC98), y) diff --git a/elks/arch/i86/kernel/irq.c b/elks/arch/i86/kernel/irq.c index 0c4399105..c44217ef5 100644 --- a/elks/arch/i86/kernel/irq.c +++ b/elks/arch/i86/kernel/irq.c @@ -124,9 +124,13 @@ void INITPROC irq_init(void) int_handler_add(IDX_SYSCALL, 0x80, _irqit); #ifdef CONFIG_ARCH_IBMPC - /* catch INT 0x00h divide by zero trap */ - irq_action[IDX_DIVZERO] = div0_handler; - int_handler_add(IDX_DIVZERO, 0x00, _irqit); + /* catch INT 0 divide by zero/divide overflow hardware fault */ + /*irq_action[IDX_DIVZERO] = div0_handler; + int_handler_add(IDX_DIVZERO, 0x00, _irqit);*/ + /* install direct panic-only DIV fault handler until known that + * the _irqit version doesn't overwrite the stack + */ + int_handler_add(IDX_DIVZERO, 0x00, div0_handler_panic); #endif #if defined(CONFIG_TIMER_INT0F) || defined(CONFIG_TIMER_INT1C) diff --git a/elks/arch/i86/kernel/irqtab.S b/elks/arch/i86/kernel/irqtab.S index e10442354..d6c0cb7a3 100644 --- a/elks/arch/i86/kernel/irqtab.S +++ b/elks/arch/i86/kernel/irqtab.S @@ -392,10 +392,40 @@ idle_halt: hlt ret + .global div0_handler_panic +// Divide Fault hander - just panic for now +div0_handler_panic: + push %ax // save regs, uses 4+4+10 bytes of current stack + push %bx + push %cx + push %dx + push %ds + + // Recover kernel data segment + // Was pushed by the CALLF of the dynamic handler + mov %sp,%bx + mov %ss:12(%bx),%ds + + mov $dmsg,%ax + push %ax + call panic + pop %ax +1: hlt + jmp 1b + +// pop %ds // restore regs +// pop %dx +// pop %cx +// pop %bx +// pop %ax +// add $4,%sp // skip the trampoline lcall +// iret + .data .global _gint_count .global endistack .global istack + .global tstack .extern current .extern previous @@ -406,10 +436,14 @@ org_irq0: // original BIOS IRQ 0 vector _gint_count: // General interrupts count. Start with 1 .word 1 // because init_task() is in kernel mode #ifdef CHECK_SS -pmsg: .ascii "Running unknown code" - .byte 0 +pmsg: .ascii "Running unknown code\0" #endif +dmsg: .ascii "DIVIDE FAULT\0" + .p2align 1 endistack: .skip ISTACK_BYTES,0 // interrupt stack istack: + + .skip 256,0 // startup temp stack +tstack: diff --git a/elks/include/arch/irq.h b/elks/include/arch/irq.h index f059abb29..fd700f01e 100644 --- a/elks/include/arch/irq.h +++ b/elks/include/arch/irq.h @@ -23,8 +23,9 @@ int request_irq(int,irq_handler,int hflag); int free_irq(int irq); /* irqtab.S */ -void int_vector_set (int vect, word_t proc, word_t seg); void _irqit (void); +void int_vector_set (int vect, word_t proc, word_t seg); +void div0_handler_panic(void); /* irq-8259.c, irq-8018x.c*/ void initialize_irq(void); diff --git a/elks/include/linuxmt/init.h b/elks/include/linuxmt/init.h index 57b436efe..d606be425 100644 --- a/elks/include/linuxmt/init.h +++ b/elks/include/linuxmt/init.h @@ -20,7 +20,6 @@ struct gendisk; struct drive_infot; /* kernel init routines*/ -extern void INITPROC kernel_init(void); extern int INITPROC buffer_init(void); extern void INITPROC console_init(void); extern void INITPROC fs_init(void); diff --git a/elks/init/main.c b/elks/init/main.c index 3c1d39b1e..5b09ae7f0 100644 --- a/elks/init/main.c +++ b/elks/init/main.c @@ -89,8 +89,9 @@ static char * INITPROC option(char *s); #endif static void init_task(void); -static void INITPROC kernel_banner(seg_t start, seg_t end, seg_t init, seg_t extra); static void INITPROC early_kernel_init(void); +static void INITPROC kernel_init(void); +static void INITPROC kernel_banner(seg_t start, seg_t end, seg_t init, seg_t extra); #if TIMER_TEST void testloop(unsigned timer) @@ -118,10 +119,12 @@ void testloop(unsigned timer) /* this procedure called using temp stack then switched, no local vars allowed */ void start_kernel(void) { + printk("START"); early_kernel_init(); /* read bootopts using kernel interrupt stack */ task = heap_alloc(max_tasks * sizeof(struct task_struct), HEAP_TAG_TASK|HEAP_TAG_CLEAR); if (!task) panic("No task mem"); + sched_init(); /* set us (the current stack) to be idle task #0*/ setsp(&task->t_regs.ax); /* change to idle task stack */ kernel_init(); /* continue init running on idle task stack */ @@ -168,17 +171,14 @@ static void INITPROC early_kernel_init(void) #endif } -void INITPROC kernel_init(void) +static void INITPROC kernel_init(void) { - /* set us (the current stack) to be idle task #0*/ - sched_init(); - irq_init(); + irq_init(); /* installs timer and div fault handlers */ /* set console from /bootopts console= or 0=default*/ set_console(boot_console); - /* init direct, bios or headless console*/ - console_init(); + console_init(); /* init direct, bios or headless console*/ #ifdef CONFIG_CHAR_DEV_RS serial_init(); From f44fe9a3dec20df111681a88ddd7f71da146d39c Mon Sep 17 00:00:00 2001 From: Greg Haerr Date: Mon, 2 Sep 2024 17:43:48 -0600 Subject: [PATCH 2/2] Cleanup START message --- elks/arch/i86/boot/setup.S | 10 +++++----- elks/init/main.c | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/elks/arch/i86/boot/setup.S b/elks/arch/i86/boot/setup.S index f83693d9b..46fd92d4a 100644 --- a/elks/arch/i86/boot/setup.S +++ b/elks/arch/i86/boot/setup.S @@ -666,10 +666,10 @@ data_reloc: jmp data_reloc 3: - mov $'\r',%ax - call putc - mov $'\n',%ax - call putc +// mov $'\r',%ax +// call putc +// mov $'\n',%ax +// call putc // Load registers as kernel expects @@ -688,7 +688,7 @@ data_reloc: push %ax push %cx - .hex4sp %ss,"Done SS:" + .hex4sp %ss,"\nDone SS:" .hex4sp %ds,"DS/ES:" .hex4sp %bx,".text size:" .hex4sp %di,".fartext size:" diff --git a/elks/init/main.c b/elks/init/main.c index 5b09ae7f0..09f862657 100644 --- a/elks/init/main.c +++ b/elks/init/main.c @@ -119,7 +119,7 @@ void testloop(unsigned timer) /* this procedure called using temp stack then switched, no local vars allowed */ void start_kernel(void) { - printk("START"); + printk("START\n"); early_kernel_init(); /* read bootopts using kernel interrupt stack */ task = heap_alloc(max_tasks * sizeof(struct task_struct), HEAP_TAG_TASK|HEAP_TAG_CLEAR);