[PATCH 5 of 5] General improvements to arch dependent code

Juan Perez-Sanchez <[email protected]>
Newsgroups org.kernel.vger.linux-8086
Message-ID <CAD6VGua-yGmKo6wcK5ifM=+QKMGiAoytL0QzPecC-=BxTZmQ1A@mail.gmail.com>
Hi,

 This patch provides access to members of structures and sizes of
structures from assembly code.

  Currently, access to member structures from assembly is hardcoded in
the source program. For example, to load the user stack pointer from
the task structure, the sequence of instructions is:

    mov bx, _current
    mov ax, 2[bx]

The offset of member t_regs.sp of structure task_struct is 2 (the
second line in the above assembly code). Someone found this offset to
be 2 and put this offset in many places as 2. Unfortunately, the
offsets have to be calculated by the compiler, as the assembler
program knows nothing about structures.

A better approach is to use a symbol instead of 2. For example, in a
"asm-offsets.h" file put:

#define TASK_USER_SP 2

After including the "asm-offsets.h" file, the sequence of assembly
instructions is now:

    mov bx,_current
    mov ax,TASK_USER_SP[bx]

Now if the offset changes, you have to correct the offset in a single place.

The best approach is to generate the file  "asm-offsets.h" by the
compiler itself because the offsets are compiler (and compile options)
dependent. This is the method used in mainstream linux.

This patch implements:

 1. automatic generation of "asm-offsets.h" file from data defined in
"arch/i86/kernel/asm-offsets.c"

 2. Use of the above mechanism to access several members of structure
task_struct in files irqtab.c and process.c

 3. Now that offsets are easy to use, make some simplifications to
interrupt handling code.

 4. Optimization of assembly code of bios16.c file.

There is a reduction of 32 bytes in code size.

The kernel was built and the Image tested in qemu and dioscuri
emulators. Also tested in a ppro pc booting from floppy.

Greetings,

Juan
elksF.patch (application/octet-stream, 13.7 KB)
diff -Nurb elks.orig/arch/i86/kernel/asm-offsets.c elks/arch/i86/kernel/asm-offsets.c
--- elks.orig/arch/i86/kernel/asm-offsets.c	1969-12-31 18:00:00.000000000 -0600
+++ elks/arch/i86/kernel/asm-offsets.c	2012-05-28 17:26:34.000000000 -0500
@@ -0,0 +1,21 @@
+#include <linuxmt/kernel.h>
+#include <linuxmt/sched.h>
+
+#ifndef __BCC__
+#include <stddef.h>
+#else
+#define offsetof(s,m) (size_t)&(((s *)0)->m)
+#endif
+
+extern int TASK_KRNL_SP, TASK_USER_SP, TASK_USER_SS;
+extern int TASK_KSTKTOP, TASK_KSTKT_SI;
+
+void asm_offsets(void)
+{
+    TASK_KRNL_SP = offsetof(struct task_struct, t_regs.ksp);
+    TASK_USER_SP = offsetof(struct task_struct, t_regs.sp);
+    TASK_USER_SS = offsetof(struct task_struct, t_regs.ss);
+    TASK_KSTKTOP = offsetof(struct task_struct, t_kstack) + KSTACK_BYTES;
+    TASK_KSTKT_SI = offsetof(struct task_struct, t_kstack) + KSTACK_BYTES - 2;
+}
+
diff -Nurb elks.orig/arch/i86/kernel/bios16.c elks/arch/i86/kernel/bios16.c
--- elks.orig/arch/i86/kernel/bios16.c	2012-05-11 13:26:27.000000000 -0500
+++ elks/arch/i86/kernel/bios16.c	2012-05-28 18:17:38.000000000 -0500
@@ -58,8 +58,6 @@
 
 ! We have to save DS carefully.	
 
-	mov ax, ds		
-
 #ifdef CONFIG_ROMCODE
         mov bx,#CONFIG_ROM_IRQ_DATA
         mov es,bx       ;es is already stored
@@ -68,64 +66,30 @@
    ! We can find our DS from CS now.
 	seg cs		
 #endif
-	mov our_ds, ax
+	mov our_ds, ds
 
 	mov bx, _bios_data_table
 
 !	Load the register block from the table	
 
+	mov ax,2[bx]
 	mov cx,6[bx]
 	mov dx,8[bx]
 	mov si,10[bx]
 	mov di,12[bx]
 	mov bp,14[bx]
-
-!	ES in 16
-
-	mov ax,16[bx]
-	mov es,ax
-
-!	Flags in 20
-
-	mov ax,20[bx]	
-
-!	Flags to end up with	
-
-	push ax
-
-!	AX final 	
-
-	mov ax, 2[bx]	
-
-!	Stack is now Flags, AX
-
-	push ax		
-
-!	DS value final
-
-	mov ax, 18[bx]  
-
-!	Load BX	
-
-	mov bx, 4[bx]	
-
-!	Stack now holds stuff to restore followed by the call values 
-!	for flags,AX
+	mov es,16[bx]
+	push 18[bx]        ! DS in stack
+	push 20[bx]
+	popf
+	mov bx, 4[bx]      ! Load BX
+!
+!	Stack now holds the call value for DS
+!
+	pop ds             ! DS desired
 
 ! ***** DS is now wrong we cannot load from the array again *****
 
-!	DS desired
-
-	mov ds,ax
-
-!	AX desired	
-
-	pop ax
-
-!	Flags desired
-
-	popf
-
 !	Do a disk interrupt.
 
 	int #0x13
@@ -136,56 +100,35 @@
 
  	pushf
  	push bx
- 	push ax
- 	mov  ax,ds
+	push ds
 
-!	Stack is now returned FL, BX, AX, DS
+!	Stack is now returned FL, BX, DS
 
- 	push ax 
+!	Recover our DS segment
 
 #ifdef CONFIG_ROMCODE
-        mov ax,#CONFIG_ROM_IRQ_DATA
-        mov ds,ax       ;we can use ds for one fetch
+        mov bx,#CONFIG_ROM_IRQ_DATA
+        mov ds,bx       ;we can use ds for one fetch
 #else
    ! We can find our DS from CS now.
 	seg cs		
 #endif
- 	mov  ax, our_ds
-
-!	Recover our DS segment 	
-
- 	mov  ds, ax
- 	mov  bx, _bios_data_table
+ 	mov  ds, our_ds
 
 ! ***** We can now use the bios data table again *****
 
-  	pop ax
-
-!	Save the old DS 
-
-  	mov 18[bx], ax
- 	pop ax
-
-!	Save the old AX 	
-
- 	mov 2[bx], ax
-	pop ax
-
-!	Save the old BX	
+ 	mov  bx, _bios_data_table
 
-	mov 4[bx], ax
+ 	pop 18[bx]         ! Save the old DS
+ 	mov 2[bx],ax       ! Save the old AX
+	pop 4[bx]          ! Save the old BX
 	mov 6[bx], cx
 	mov 8[bx], dx
 	mov 10[bx], si
 	mov 12[bx], di
 	mov 14[bx], bp
-	mov ax,es
-	mov 16[bx], ax
-	pop ax
-
-!	Pop the returned flags off
-
-	mov 20[bx], ax
+	mov 16[bx], es
+	pop 20[bx]         ! Pop the returned flags off
 
 !	Restore things we must save
 
diff -Nurb elks.orig/arch/i86/kernel/irqtab.c elks/arch/i86/kernel/irqtab.c
--- elks.orig/arch/i86/kernel/irqtab.c	2012-05-24 18:22:08.000000000 -0500
+++ elks/arch/i86/kernel/irqtab.c	2012-05-28 17:24:43.000000000 -0500
@@ -1,43 +1,32 @@
 #include <arch/irq.h>
+#include <arch/asm-offsets.h>
 #include <linuxmt/config.h>
 
 /*
  *	Easy way to store our kernel DS
  */
 
-
 /* moving variables from code segment to an extra segment
 /  CONFIG_ROM_IRQ_DATA for the ROM_CODE-Version
 /  ELKS 0.76 7/1999 Christian Mard”ller  ([email protected])
 /  */
 
-
-
 #ifdef CONFIG_ROMCODE 
+/* In ROM-Mode we must generate a physical 3th segment :-)
+/  The segmentaddress is given by CONFIG_ROM_IRQ_DATA,
+/  the offset is constant per #define
+/-------------------------------------------------------*/
+
+   #define SEG_IRQ_DATA es
    #define stashed_ds       [0]
    /*      _our_ds          [18]   bios16.c  */
 
 #else
-   #define stashed_ds       cseg_stashed_ds
-
-#endif
-
-#ifdef CONFIG_ROMCODE
- #define SEG_IRQ_DATA es
-#else
  #define SEG_IRQ_DATA cs
-#endif
+   #define stashed_ds       cseg_stashed_ds
 
 #ifndef S_SPLINT_S
 #asm
-/* In ROM-Mode we must generate a physical 3th segment :-) 
-/  The segmentaddress is given by CONFIG_ROM_IRQ_DATA,
-/  the offset is constant per #define
-/-------------------------------------------------------*/
-
-
-
-#ifndef CONFIG_ROMCODE
 	.globl cseg_stashed_ds
 
         .even
@@ -45,17 +34,12 @@
 cseg_stashed_ds:
 	.word	0
 
-#endif	
-	
-
 #endasm
 #endif
 
+#endif
 
-
-
- 
-void irqtab_init()
+void irqtab_init(void)
 {
 #ifndef S_SPLINT_S
 #asm
@@ -179,7 +163,6 @@
 
 	.text 
 			
-
 _irq1:                   ;keyboard  
 	push	ax
 	mov	ax,#1
@@ -391,8 +374,6 @@
 !
 !	Save all registers
 !
-
-!	cli		! Might not be disabled on an exception
 	push	ds
 	push	es
 	push	bx
@@ -401,18 +382,15 @@
 	push	si
 	push	di
 	push	bp
-		
 !
 !	Recover segments
 !
 #ifdef CONFIG_ROMCODE
         mov bx,#CONFIG_ROM_IRQ_DATA
-        mov es,bx
+        mov ds,bx
+#else
+        seg     cs
 #endif        
-!
-!	Switch segments
-!
-        seg SEG_IRQ_DATA
 	mov	bx,stashed_ds		! Recover the data segment
 	mov	ds,bx
 	mov	es,bx
@@ -433,19 +411,20 @@
 !	User or BIOS etc
 !
 	mov	bx,_current
-	cmp	dx,4[bx]	! entry ss = current->t_regs.ss?
+	cmp	dx,TASK_USER_SS[bx] ! entry ss = current->t_regs.ss?
 	je	utask		! Switch to kernel
 !
 !	Bios etc - switch to interrupt stack
 !
 	mov	sp,#_intstack
-!	lea	sp, _intstack
 	j	switched
 !
 !	User task. Extract kernel SP. (BX already holds current)
+!	At this point, the kernel stack is empty. Thus, we can load
+!       the kernel stack pointer without accesing memory
 !
 utask:
-	mov	sp,[bx]		! switch to kernel stack ptr
+        lea     sp,TASK_KSTKTOP[bx] ! switch to kernel stack ptr
 	inc	ch		! Switch allowable
 !
 !	In ktask state we have a suitable stack. It might be 
@@ -537,18 +516,21 @@
 !	je	nosched			! No
 	call	_schedule		! Task switch
 !
-! Fix current->ksp (_schedule messes it up).
+! This path will return directly to user space
 !
 	pop	ax	! stacked SS
 	pop	cx	! stacked SP
 	mov	bx,_current
 #ifdef CONFIG_ADVANCED_MM
-	mov ax, 4[bx]	! user ds
+	mov ax, TASK_USER_SS[bx] ! user ds
 	mov bp, sp		
 	mov 12[bp], ax	! change the es in the stack
 	mov 14[bp], ax	! change the ds in the stack
 #endif
-	mov	[bx],sp
+!
+!	At this point, the kernel stack is empty. Thus, there in no
+!       need to save the kernel stack pointer.
+!
 	j	noschedpop
 	
 nosched:
@@ -581,7 +563,7 @@
 	iret
 
 	.data
-.globl	_can_tswitch
+        .globl	_can_tswitch
 _can_tswitch:
 	.byte 0
 
diff -Nurb elks.orig/arch/i86/kernel/process.c elks/arch/i86/kernel/process.c
--- elks.orig/arch/i86/kernel/process.c	2012-05-24 18:22:08.000000000 -0500
+++ elks/arch/i86/kernel/process.c	2012-05-28 17:24:43.000000000 -0500
@@ -7,6 +7,7 @@
 #include <linuxmt/types.h>
 
 #include <arch/segment.h>
+#include <arch/asm-offsets.h>
 
 /*
  *	This function can only be called with SS=DS=ES=kernel DS
@@ -99,10 +100,9 @@
 	push bx
 	push dx
 	mov bx,_previous
-	mov [bx],sp
+	mov TASK_KRNL_SP[bx],sp
 	mov bx,_current
-	mov ax,[bx]
-	mov sp,ax
+	mov sp,TASK_KRNL_SP[bx]
 	pop dx
 	pop bx
 	pop si
@@ -144,21 +144,19 @@
 #endif        
 	mov ds,stashed_ds	! the org DS of kernel
 !
-!	Find our TCB
+!	At this point, the kernel stack is empty. Thus, we can push
+!       data into the kernel stack by writing directly to memory
 !
-	mov si,_current
-	mov si,[si]		! pops si and
-        pop -2[si]		! save si in kernel stack
+	mov si,_current         ! pops SI from user stack and pushes
+	pop TASK_KSTKT_SI[si]   ! it directly into kernel stack
 !
 !	Stash user mode stack - needed for stack checking!
 !
-	mov si,_current
-	mov 2[si],sp
+	mov TASK_USER_SP[si],sp
 !
 !	load kernel stack pointer
 !
-	mov sp,[si]
-	sub sp,#2
+        lea sp,TASK_KSTKT_SI[si]
 !
 !	Finish switching to the right things
 !
@@ -213,9 +211,12 @@
 	cli
 	mov	dx,ax
 	mov	bx,_current
-	mov	[bx],sp		! current->ksp is altered by schedule()
-	mov 	sp,2[bx]
-	mov	ax,4[bx]
+!
+!	At this point, the kernel stack is empty. Thus, there in no
+!       need to save the kernel stack pointer.
+!
+	mov 	sp,TASK_USER_SP[bx]
+	mov	ax,TASK_USER_SS[bx]
 !
 !	User segment recovery
 !
@@ -311,8 +312,8 @@
 #asm
 	cli
 	mov bx, _current
-	mov sp, 2[bx]		! user stack offset
-	mov ax, 4[bx]		! user stack segment
+	mov sp, TASK_USER_SP[bx] ! user stack offset
+	mov ax, TASK_USER_SS[bx] ! user stack segment
 	mov ss, ax
 	mov ds, ax
 	mov es, ax
diff -Nurb elks.orig/arch/i86/Makefile elks/arch/i86/Makefile
--- elks.orig/arch/i86/Makefile	2012-05-11 13:26:27.000000000 -0500
+++ elks/arch/i86/Makefile	2012-05-28 17:24:43.000000000 -0500
@@ -13,7 +13,7 @@
 
 CLEANDEP	= 
 
-CLEANME 	= 
+CLEANME 	= $(BASEDIR)/include/arch/asm-offsets.h
 
 DEPEND  	= 
 
@@ -55,6 +55,8 @@
 DRIVERS := $(DRIVERS) $(ARCH_DIR)/drivers/char/chr_drv.a \
 	$(ARCH_DIR)/drivers/block/blk_drv.a
 
+XINCLUDE = $(BASEDIR)/include/arch/asm-offsets.h
+
 #########################################################################
 # Things to make.
 
@@ -83,12 +85,27 @@
 toolkit:
 	${MAKE} -C tools all
 
+$(BASEDIR)/include/arch/asm-offsets.h: kernel/asm-offsets.c
+	$(CC) $(CFLAGS) -S -o asm-offsets.s kernel/asm-offsets.c
+	echo '#ifndef ASM_OFFSETS_H' > $(BASEDIR)/include/arch/asm-offsets.h
+	echo '#define ASM_OFFSETS_H\n' >> $(BASEDIR)/include/arch/asm-offsets.h
+	sed -e '/^[^m].*/ d' \
+	-e 's/\],/  /' \
+	-e 's/ #/ /' \
+	-e 's/ \*/ /' \
+	-e 's/ \$$/0x/' \
+	-e 's/^.*\[_/#define /' \
+	-e 's/ax/0/' \
+	< asm-offsets.s | grep -e define >> $(BASEDIR)/include/arch/asm-offsets.h
+	echo '\n#endif' >> $(BASEDIR)/include/arch/asm-offsets.h
+	rm asm-offsets.s
+
 #########################################################################
 # Image selection.
 
 ifeq ($(CONFIG_ARCH_SIBO), y)
 
-boot/system: $(AARCHIVES) $(ADRIVERS) sibo/crt1.o sibo/crt0.o
+boot/system: $(XINCLUDE) $(AARCHIVES) $(ADRIVERS) sibo/crt1.o sibo/crt0.o
 	(cd $(BASEDIR) ; $(LD) $(LDFLAGS) -t -M $(ARCH_LD) \
 		$(ARCH_DIR)/sibo/crt0.o $(ARCH_DIR)/sibo/crt1.o \
 		init/main.o $(ARCHIVES) $(DRIVERS) \
@@ -103,7 +120,7 @@
 
 else
 
-boot/system:	$(AARCHIVES) $(ADRIVERS) boot/crt1.o boot/crt0.o
+boot/system:	$(XINCLUDE) $(AARCHIVES) $(ADRIVERS) boot/crt1.o boot/crt0.o
 	(cd $(BASEDIR) ; $(LD) $(LDFLAGS) -t -M $(ARCH_LD) \
 		$(ARCH_DIR)/boot/crt0.o $(ARCH_DIR)/boot/crt1.o \
 		init/main.o $(ARCHIVES) $(DRIVERS) \
diff -Nurb elks.orig/arch/i86/sibo/irqtab.c elks/arch/i86/sibo/irqtab.c
--- elks.orig/arch/i86/sibo/irqtab.c	2012-05-24 18:22:08.000000000 -0500
+++ elks/arch/i86/sibo/irqtab.c	2012-05-28 17:24:43.000000000 -0500
@@ -1,4 +1,5 @@
 #include <arch/irq.h>
+#include <arch/asm-offsets.h>
 #include <linuxmt/config.h>
 
 /*
@@ -11,30 +12,21 @@
 /  */
 
 #ifdef CONFIG_ROMCODE
+/* In ROM-Mode we must generate a physical 3th segment :-)
+/  The segmentaddress is given by CONFIG_ROM_IRQ_DATA,
+/  the offset is constant per #define
+/-------------------------------------------------------*/
+
+   #define SEG_IRQ_DATA es
    #define stashed_ds       [0]
    /*      _our_ds          [18]   bios16.c  */
 
 #else
-   #define stashed_ds       cseg_stashed_ds
-
-#endif
-
-#ifdef CONFIG_ROMCODE
- #define SEG_IRQ_DATA es
-#else
  #define SEG_IRQ_DATA cs
-#endif
+   #define stashed_ds       cseg_stashed_ds
 
 #ifndef S_SPLINT_S
 #asm
-/* In ROM-Mode we must generate a physical 3th segment :-)
-/  The segmentaddress is given by CONFIG_ROM_IRQ_DATA,
-/  the offset is constant per #define
-/-------------------------------------------------------*/
-
-
-
-#ifndef CONFIG_ROMCODE
 	.globl	cseg_stashed_ds
 
         .even
@@ -42,9 +34,9 @@
 cseg_stashed_ds:
 	.word	0
 
+#endasm
 #endif
 
-#endasm
 #endif
 
 void irqtab_init(void)
@@ -381,8 +373,6 @@
 !
 !	Save all registers
 !
-
-!	cli		! Might not be disabled on an exception
 	push	ds
 	push	es
 	push	bx
@@ -391,7 +381,6 @@
 	push	si
 	push	di
 	push	bp
-
 !
 !	Recover segments
 !
@@ -407,7 +396,6 @@
 
 	mov	dx,ss			! Get current SS
 	mov	bp,sp			! Get current SP
-	movb	cl,bios_call_cnt_l
 !
 !	Set up task switch controller
 !
@@ -421,19 +409,20 @@
 !	User or BIOS etc
 !
 	mov	bx,_current
-	cmp	dx,4[bx]	! entry ss = current->t_regs.ss?
+	cmp	dx,TASK_USER_SS[bx] ! entry ss = current->t_regs.ss?
 	je	utask		! Switch to kernel
 !
 !	Bios etc - switch to interrupt stack
 !
 	mov	sp,#_intstack
-!	lea	sp, _intstack
 	j	switched
 !
 !	User task. Extract kernel SP. (BX already holds current)
+!	At this point, the kernel stack is empty. Thus, we can load
+!       the kernel stack pointer without accesing memory
 !
 utask:
-	mov	sp,[bx]		! switch to kernel stack ptr
+        lea     sp,TASK_KSTKTOP[bx] ! switch to kernel stack ptr
 	inc	ch		! Switch allowable
 !
 !	In ktask state we have a suitable stack. It might be 
@@ -489,18 +478,21 @@
 !	je	nosched			! No
 	call	_schedule		! Task switch
 !
-! Fix current->ksp (_schedule messes it up).
+! This path will return directly to user space
 !
 	pop	ax	! stacked SS
 	pop	cx	! stacked SP
 	mov	bx,_current
 #ifdef CONFIG_ADVANCED_MM
-	mov ax, 4[bx]	! user ds
+	mov ax, TASK_USER_SS[bx] ! user ds
 	mov bp, sp
 	mov 12[bp], ax	! change the es in the stack
 	mov 14[bp], ax	! change the ds in the stack
 #endif
-	mov	[bx],sp
+!
+!	At this point, the kernel stack is empty. Thus, there in no
+!       need to save the kernel stack pointer.
+!
 	j	noschedpop
 	
 nosched:
@@ -541,8 +533,6 @@
 	.word	0
 seg_stashed_irq0_l:
 	.word	0
-bios_call_cnt_l:
-	.word	0
 
 	.zerow	256		! (was) 128 byte interrupt stack
 _intstack:
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.