[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 Mardller ([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: