[PATCH 3 of 5]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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;
 }

[Index of Archives]     [Kernel]     [Linux ia64]     [DCCP]     [Linux for ARM]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux