Hi, This patch makes: -System call fork() did not preserved user registers SI and DI for the child task, and getting user register BP was unnecessa- rily complex. The code was greatly simplified and assembly function fake_save_regs() was completely removed. -Function tswitch() preserved registers BX and DX, but this is not required by the calling conventions. The code was simplified. -Initialization of struct task_struct was repeated at several places in the source tree. Now, function find_empty_process() does some initialization. -Code size was reduced by 128 bytes. Greetings, Juan
diff -Nur elks.orig/arch/i86/boot/crt0.S elks/arch/i86/boot/crt0.S --- elks.orig/arch/i86/boot/crt0.S 2014-10-08 13:43:54.000000000 -0500 +++ elks/arch/i86/boot/crt0.S 2014-10-13 12:43:45.000000000 -0500 @@ -56,7 +56,7 @@ #ifndef CONFIG_ROMCODE mov ss,dx ! in ROMCODE stack is ready placed - mov sp,#(_task + TASK_KSTKTOP) + mov sp,#(_task + TASK_KSTKTOP - 10) #endif ! Space for temporary stack space _bootstack removed!! diff -Nur elks.orig/arch/i86/kernel/process.c elks/arch/i86/kernel/process.c --- elks.orig/arch/i86/kernel/process.c 2014-04-26 22:12:31.000000000 -0500 +++ elks/arch/i86/kernel/process.c 2014-10-13 13:16:47.000000000 -0500 @@ -9,42 +9,7 @@ #include <arch/segment.h> #include <arch/asm-offsets.h> -/* - * This function can only be called with SS=DS=ES=kernel DS - * CS=kernel CS. SS:SP is the relevant kernel stack (IRQ's are - * taken on 'current' kernel stack. - * - * load_regs can also only be called from such a situation, thus - * we don't need to arse about with segment registers. The kernel isn't - * relocating. - * - * To understand this you need to know how the compilers generate 8086 - * stack frames. Functions normally start - * - * push bp ! Save callers BP - * mov bp,sp ! BP so we can use it to index registers - * - * and end - * - * mov sp,bp ! Fastest way to destroy local variables - * pop bp ! Restore callers BP - * ret ! Return address is top of stack now - * - * save_regs() saves the callers registers and state then returns to - * the caller. It in effect freezes a copy of the caller context but - * doesn't prevent it being used temporarily beyond that as we do. - * - * load_regs() restores the callers context and returns skipping out of - * schedule() [our faked setup] back to the right place. - * - * fake_save_regs builds a stack frame that returns a new task to a - * kernel address of our choice using its own stack/context. - * - * ELKS 0.76 7/1999 Fixed for ROMCODE-Version - * Christian Mardm?ller (chm@xxxxxx) - */ - -#ifdef CONFIG_ROMCODE +#ifdef CONFIG_ROMCODE #define stashed_ds [0] @@ -70,10 +35,7 @@ #endif -typedef unsigned short int FsR; - extern int do_signal(void); -extern int fake_save_regs(FsR,FsR); void sig_check(void) { @@ -81,6 +43,33 @@ do_signal(); } +/* + * tswitch(); + * + * This function can only be called with SS=DS=ES=kernel DS and + * CS=kernel CS. SS:SP is the relevant kernel stack (IRQ's are + * taken on 'current' kernel stack. Thus we don't need to arse about + * with segment registers. The kernel isn't relocating. + * + * To understand this you need to know how the compilers generate 8086 + * stack frames. Functions normally start + * + * push bp ! Save callers BP + * mov bp,sp ! BP so we can use it to index registers + * + * and end + * + * mov sp,bp ! Fastest way to destroy local variables + * pop bp ! Restore callers BP + * ret ! Return address is top of stack now + * + * tswitch() saves the "previous" task registers and state. It in effect + * freezes a copy of the caller context. Then restores the "current" + * context and returns running the current task. + * + * ELKS 0.76 7/1999 Fixed for ROMCODE-Version + * Christian Mardm?ller (chm@xxxxxx) + */ #ifndef S_SPLINT_S #asm .text @@ -92,14 +81,10 @@ pushf push di push si - push bx - push dx mov bx,_previous mov TASK_KRNL_SP[bx],sp mov bx,_current mov sp,TASK_KRNL_SP[bx] - pop dx - pop bx pop si pop di popf @@ -226,63 +211,6 @@ ! ! Done. ! - - .globl _fake_save_regs -! -! int used=fake_save_regs(sp,addr); -! -! Build a fake return stack in kernel space so that -! we can have a new task start at a chosen kernel -! function while on its kernel stack. We push the -! registers suitably for -! -_fake_save_regs: -#if 0 - push bp - mov bp,sp - mov bx,4[bp] ! new task ksp - mov ax,6[bp] ! new task start address -! -! Build a dummy stack return frame -! - mov -2[bx],ax ! Return address - mov ax,[bp] ! Caller BP - mov -4[bx],ax ! Save caller BP - mov ax,bx ! Firstly get bx - sub ax,#4 ! This is the apparent BP. It points - ! to caller BP and above it caller return - mov -6[bx],ax ! goes here. -! -! Register State -! - pushf - pop ax - mov -8[bx],ax ! Flags - mov -10[bx],di - mov -12[bx],si - mov -14[bx],bx - mov -16[bx],dx - mov ax,#16 - pop bp - ret -#else - push bp - mov bp,sp - mov bx,4[bp] ! new task ksp - mov ax,6[bp] ! new task start address - pop bp - - mov -2[bx],ax ! Return address - mov -4[bx],bp ! Save caller BP - pushf - pop -6[bx] ! Flags - mov -8[bx],di - mov -10[bx],si - mov -12[bx],bx - mov -14[bx],dx - mov ax,#14 - ret -#endif #endasm #endif @@ -338,26 +266,21 @@ * Make task t fork into kernel space. We are in kernel mode * so we fork onto our kernel stack. */ - -void kfork_proc(register struct task_struct *t,char *addr) + +void kfork_proc(char *addr) { - memset(t, 0, sizeof(struct task_struct)); - t->t_regs.ds = t->t_regs.ss = get_ds(); - t->t_regs.ksp = ((__u16) t->t_kstack) + KSTACK_BYTES; - t->t_regs.ksp -= fake_save_regs((__u16)t->t_regs.ksp,(__u16)addr); + register struct task_struct *t; - t->state = TASK_UNINTERRUPTIBLE; - t->pid = get_pid(); - t->t_kstackm = KSTACK_MAGIC; - t->prev_run = t->next_run = NULL; + t = find_empty_process(); - wake_up_process(t); - schedule(); + t->t_regs.cs = get_cs(); + t->t_regs.ds = t->t_regs.ss = get_ds(); /* Run in kernel space */ + arch_build_stack(t, addr); } /* * Build a user return stack for exec*(). This is quite easy, - * especially as our syscall entry doesnt use the user stack. + * especially as our syscall entry doesnt use the user stack. */ #define USER_FLAGS 0x3200 /* IPL 3, interrupt enabled */ @@ -447,26 +370,28 @@ * we need to do to recover the user's bp. */ -extern void ret_from_syscall(); /* our return address */ - -static void* saved_bp; /* we have to recover user's bp */ - -void arch_build_stack(struct task_struct *t) -{ - char *kstktop = (char *) t->t_kstack+KSTACK_BYTES; +/* + * arch_build_stack(t, addr); + * + * Build a fake return stack in kernel space so that + * we can have a new task start at a chosen kernel + * function while on its kernel stack. We push the + * registers suitably for + */ -/*@i3@*/ t->t_regs.ksp = kstktop - fake_save_regs(kstktop, ret_from_syscall); +extern void ret_from_syscall(); /* our return address */ +void arch_build_stack(struct task_struct *t, char *addr) { -#ifndef S_SPLINT_S -#asm - mov bx,[bp] ! bx = bp on entry to arch_build_stack - mov bx,[bx] ! ax = bp on entry to do_fork = users bp (hopefully!) - mov ax,[bx] ! ax = bp on entry to do_fork = users bp (hopefully!) - mov _saved_bp,ax -#endasm -#endif -} + register __u16 *tsp = (__u16 *)(t->t_kstack + KSTACK_BYTES - 10); + register __u16 *csp = (__u16 *)(current->t_kstack + KSTACK_BYTES - 14); - *(void**) (kstktop-4) = saved_bp; + t->t_regs.ksp = (__u16)tsp; + *tsp++ = *(csp + 6); /* Initial value for SI register */ + *tsp++ = *(csp + 5); /* Initial value for DI register */ + *tsp++ = 0x3202; /* Initial value for FLAGS register */ + *tsp++ = *csp; /* Initial value for BP register */ + if(addr == NULL) + addr = ret_from_syscall; + *tsp = addr; /* Start execution address */ } diff -Nur elks.orig/arch/i86/kernel/system.c elks/arch/i86/kernel/system.c --- elks.orig/arch/i86/kernel/system.c 2014-04-26 22:12:31.000000000 -0500 +++ elks/arch/i86/kernel/system.c 2014-10-11 16:07:46.000000000 -0500 @@ -28,8 +28,6 @@ void setup_arch(seg_t *start, seg_t *end) { - register __ptask taskp; - #ifndef S_SPLINT_S /* * Save segments @@ -53,16 +51,6 @@ arch_segs.lowss = arch_segs.endss; -/* - * arch dependent sched init. Set the kernel SP, - * as we will need this in interrupts. - */ - taskp = &task[0]; - taskp->t_regs.cs = get_cs(); - taskp->t_regs.ds = taskp->t_regs.ss = get_ds(); /* Run in kernel space */ - taskp->t_regs.ksp = ((__u16) taskp->t_kstack) + KSTACK_BYTES; - taskp->t_kstackm = KSTACK_MAGIC; - #ifdef CONFIG_COMPAQ_FAST /* diff -Nur elks.orig/include/linuxmt/init.h elks/include/linuxmt/init.h --- elks.orig/include/linuxmt/init.h 2014-04-26 22:12:31.000000000 -0500 +++ elks/include/linuxmt/init.h 2014-10-11 22:12:27.000000000 -0500 @@ -35,7 +35,7 @@ extern void setup_mm(void); extern void device_setup(void); -extern void kfork_proc(struct task_struct *,void ()); +extern void kfork_proc(void ()); extern void arch_setup_kernel_stack(struct task_struct *); extern void setup_dev(register struct gendisk *); extern void mem_dev_init(void); diff -Nur elks.orig/include/linuxmt/sched.h elks/include/linuxmt/sched.h --- elks.orig/include/linuxmt/sched.h 2014-04-26 22:12:31.000000000 -0500 +++ elks/include/linuxmt/sched.h 2014-10-13 12:58:53.000000000 -0500 @@ -87,7 +87,7 @@ sigset_t signal; /* Signal status */ struct signal_struct sig; /* Signal block */ int dumpable; /* Can core dump */ - + #ifdef CONFIG_SWAP jiff_t last_running; #endif @@ -162,7 +162,8 @@ extern void add_to_runqueue(struct task_struct *); -extern void arch_build_stack(struct task_struct *); +extern struct task_struct *find_empty_process(void); +extern void arch_build_stack(struct task_struct *, char *); extern unsigned int get_ustack(struct task_struct *,int); extern void put_ustack(register struct task_struct *,int,int); diff -Nur elks.orig/init/main.c elks/init/main.c --- elks.orig/init/main.c 2014-04-26 22:12:31.000000000 -0500 +++ elks/init/main.c 2014-10-11 22:15:49.000000000 -0500 @@ -65,7 +65,8 @@ printk("ELKS version %s\n", system_utsname.release); - kfork_proc(&task[1], init_task); + kfork_proc(init_task); + wake_up_process(&task[1]); /* * We are now the idle task. We won't run unless no other process can run. @@ -73,7 +74,6 @@ while (1){ schedule(); } - } static char args[] = "\0\0\0\0\0\0/bin/init\0\0"; diff -Nur elks.orig/kernel/fork.c elks/kernel/fork.c --- elks.orig/kernel/fork.c 2014-04-26 22:12:31.000000000 -0500 +++ elks/kernel/fork.c 2014-10-13 12:56:41.000000000 -0500 @@ -5,13 +5,34 @@ #include <linuxmt/mm.h> #include <linuxmt/sched.h> -int task_slots_unused = MAX_TASKS - 2; -struct task_struct *next_task_slot = &task[2]; +int task_slots_unused = MAX_TASKS; +struct task_struct *next_task_slot = task; + +pid_t get_pid(void) +{ + register struct task_struct *p; + static pid_t last_pid = -1; + +repeat: + if (++last_pid < 0) + last_pid = 1; + + p = &task[1]; + do { + if (p->state == TASK_UNUSED) + continue; + if (p->pid == last_pid || p->pgrp == last_pid || + p->session == last_pid) { + goto repeat; + } + } while (++p < &task[MAX_TASKS]); + return last_pid; +} /* * Find a free task slot. */ -static struct task_struct *find_empty_process(void) +struct task_struct *find_empty_process(void) { register struct task_struct *t; @@ -19,7 +40,7 @@ printk("Only %d slots\n", task_slots_unused); if (!task_slots_unused || current->uid) return NULL; - } + } t = next_task_slot; while (t->state != TASK_UNUSED) { if (++t >= &task[MAX_TASKS]) @@ -27,31 +48,14 @@ } next_task_slot = t; task_slots_unused--; + *t = *current; + t->state = TASK_UNINTERRUPTIBLE; + t->pid = get_pid(); + t->t_kstackm = KSTACK_MAGIC; + t->next_run = t->prev_run = NULL; return t; } - -pid_t get_pid(void) -{ - register struct task_struct *p; - static pid_t last_pid = 0; - -repeat: - if (++last_pid < 0) - last_pid = 1; - - p = &task[0]; - do { - if (p->state == TASK_UNUSED) - continue; - if (p->pid == last_pid || p->pgrp == last_pid || - p->session == last_pid) { - goto repeat; - } - } while (++p < &task[MAX_TASKS]); - return last_pid; -} - /* * Clone a process. */ @@ -66,13 +70,9 @@ if((t = find_empty_process()) == NULL) return -EAGAIN; - /* Copy everything */ - - *t = *currentp; - /* Fix up what's different */ - /* + /* * We do shared text. */ (void) mm_realloc(currentp->mm.cseg); @@ -92,19 +92,12 @@ t->t_regs.ds = t->t_regs.ss = t->mm.dseg; } - t->t_regs.ksp = ((__u16) t->t_kstack) + KSTACK_BYTES; - - t->state = TASK_UNINTERRUPTIBLE; - t->pid = get_pid(); - t->ppid = currentp->pid; - t->t_kstackm = KSTACK_MAGIC; - t->next_run = t->prev_run = NULL; /* * Build a return stack for t. */ - arch_build_stack(t); + arch_build_stack(t, NULL); /* Increase the reference count to all open files */ @@ -118,6 +111,7 @@ t->fs.pwd->i_count++; /* Set up our family tree */ + t->ppid = currentp->pid; t->p_parent = currentp; t->p_nextsib = t->p_child = NULL; t->child_lastend = t->lastend_status = 0; diff -Nur elks.orig/kernel/sched.c elks/kernel/sched.c --- elks.orig/kernel/sched.c 2014-10-08 13:43:54.000000000 -0500 +++ elks/kernel/sched.c 2014-10-13 09:28:34.000000000 -0500 @@ -11,6 +11,7 @@ #include <linuxmt/kernel.h> #include <linuxmt/sched.h> +#include <linuxmt/init.h> #include <linuxmt/timer.h> #include <linuxmt/string.h> @@ -21,7 +22,8 @@ __task task[MAX_TASKS]; unsigned char nr_running; -__ptask current, previous; +__ptask current = task; +__ptask previous; extern int intr_count; @@ -272,23 +274,21 @@ void sched_init(void) { - register struct task_struct *taskp; + register struct task_struct *t = task; /* - * Now create task 0 to be ourself. + * Mark tasks 0-(MAX_TASKS-1) as not in use. */ - taskp = &init_task; - taskp->state = TASK_RUNNING; - taskp->next_run = taskp->prev_run = taskp; - - current = taskp; -/* nr_running = 0;*/ + do { + t->state = TASK_UNUSED; + } while(++t < &task[MAX_TASKS]); /* - * Mark tasks 1-31 as not in use. + * Now create task 0 to be ourself. */ + kfork_proc(NULL); - while(++taskp < &task[MAX_TASKS]) - taskp->state=TASK_UNUSED; - + t = task; + t->state = TASK_RUNNING; + t->next_run = t->prev_run = t; }