Unix 在minix中调用汇编宏

Unix 在minix中调用汇编宏,unix,assembly,minix,Unix,Assembly,Minix,我正在开发minix 3.1.7 我想在我的汇编文件中的“/usr/src/kernel/arch/i386/sconst.h”中定义一个宏“SAVE\u PROCESS\u CTX”: /usr/src/kernel/arch/i386/sconst.h: #ifndef __SCONST_H__ #define __SCONST_H__ #include "kernel/const.h" /* Miscellaneous constants used in assembler code.

我正在开发minix 3.1.7

我想在我的汇编文件中的“/usr/src/kernel/arch/i386/sconst.h”中定义一个宏“SAVE\u PROCESS\u CTX”:

/usr/src/kernel/arch/i386/sconst.h:

#ifndef __SCONST_H__
#define __SCONST_H__

#include "kernel/const.h"

/* Miscellaneous constants used in assembler code. */
    W = _WORD_SIZE  /* Machine word size. */

/* Offsets in struct proc. They MUST match proc.h. */
    P_STACKBASE = 0
    GSREG = P_STACKBASE
    FSREG = GSREG+2 /* 386 introduces FS and GS segments*/
    ESREG = FSREG+2
    DSREG = ESREG+2
    DIREG = DSREG+2
    SIREG = DIREG+W
    BPREG = SIREG+W
    STREG = BPREG+W /* hole for another SP*/
    BXREG = STREG+W
    DXREG = BXREG+W
    CXREG = DXREG+W
    AXREG = CXREG+W
    RETADR = AXREG+W    /* return address for save() call*/
    PCREG = RETADR+W
    CSREG = PCREG+W
    PSWREG = CSREG+W
    SPREG = PSWREG+W
    SSREG = SPREG+W
    P_STACKTOP = SSREG+W
    FP_SAVE_AREA_P = P_STACKTOP
    P_LDT_SEL = FP_SAVE_AREA_P + 532
    P_CR3 = P_LDT_SEL+W
    P_CR3_V = P_CR3+4
    P_LDT = P_CR3_V+W
    P_MISC_FLAGS = P_LDT + 50
    Msize = 9   /* size of a message in 32-bit words*/


/*
 * offset to current process pointer right after trap, we assume we always have
 * error code on the stack
 */
#define CURR_PROC_PTR       20

/*
 * tests whether the interrupt was triggered in kernel. If so, jump to the
 * label. Displacement tell the macro ha far is the CS value saved by the trap
 * from the current %esp. The kernel code segment selector has the lower 3 bits
 * zeroed
 */
#define TEST_INT_IN_KERNEL(displ, label)    \
    cmpl    $CS_SELECTOR, displ(%esp)   ;\
    je  label               ;

/*
 * saves the basic interrupt context (no error code) to the process structure
 *
 * displ is the displacement of %esp from the original stack after trap
 * pptr is the process structure pointer
 * tmp is an available temporary register
 */
#define SAVE_TRAP_CTX(displ, pptr, tmp)         \
    movl    (0 + displ)(%esp), tmp          ;\
    movl    tmp, PCREG(pptr)            ;\
    movl    (4 + displ)(%esp), tmp          ;\
    movl    tmp, CSREG(pptr)            ;\
    movl    (8 + displ)(%esp), tmp          ;\
    movl    tmp, PSWREG(pptr)           ;\
    movl    (12 + displ)(%esp), tmp         ;\
    movl    tmp, SPREG(pptr)            ;\
    movl    tmp, STREG(pptr)            ;\
    movl    (16 + displ)(%esp), tmp         ;\
    movl    tmp, SSREG(pptr)            ;

#define SAVE_SEGS(pptr)     \
    mov %ds, %ss:DSREG(pptr)    ;\
    mov %es, %ss:ESREG(pptr)    ;\
    mov %fs, %ss:FSREG(pptr)    ;\
    mov %gs, %ss:GSREG(pptr)    ;

#define RESTORE_SEGS(pptr)      \
    movw    %ss:DSREG(pptr), %ds    ;\
    movw    %ss:ESREG(pptr), %es    ;\
    movw    %ss:FSREG(pptr), %fs    ;\
    movw    %ss:GSREG(pptr), %gs    ;

/*
 * restore kernel segments, %ss is kernnel data segment, %cs is aready set and
 * %fs, %gs are not used
 */
#define RESTORE_KERNEL_SEGS \
    mov %ss, %si    ;\
    mov %si, %ds    ;\
    mov %si, %es    ;\
    movw    $0, %si     ;\
    mov %si, %gs    ;\
    mov %si, %fs    ;

#define SAVE_GP_REGS(pptr)  \
    mov %eax, %ss:AXREG(pptr)       ;\
    mov %ecx, %ss:CXREG(pptr)       ;\
    mov %edx, %ss:DXREG(pptr)       ;\
    mov %ebx, %ss:BXREG(pptr)       ;\
    mov %esi, %ss:SIREG(pptr)       ;\
    mov %edi, %ss:DIREG(pptr)       ;

#define RESTORE_GP_REGS(pptr)   \
    movl    %ss:AXREG(pptr), %eax       ;\
    movl    %ss:CXREG(pptr), %ecx       ;\
    movl    %ss:DXREG(pptr), %edx       ;\
    movl    %ss:BXREG(pptr), %ebx       ;\
    movl    %ss:SIREG(pptr), %esi       ;\
    movl    %ss:DIREG(pptr), %edi       ;

/*
 * save the context of the interrupted process to the structure in the process
 * table. It pushses the %ebp to stack to get a scratch register. After %esi is
 * saved, we can use it to get the saved %ebp from stack and save it to the
 * final location
 *
 * displ is the stack displacement. In case of an exception, there are two extra
 * value on the stack - error code and the exception number
 */
#define SAVE_PROCESS_CTX_NON_LAZY(displ) \
                                \
    cld /* set the direction flag to a known state */   ;\
                                \
    push    %ebp                    ;\
                            ;\
    movl    (CURR_PROC_PTR + 4 + displ)(%esp), %ebp ;\
                            ;\
    /* save the segment registers */        \
    SAVE_SEGS(%ebp)                 ;\
                            \
    SAVE_GP_REGS(%ebp)              ;\
    pop %esi            /* get the orig %ebp and save it */ ;\
    mov %esi, %ss:BPREG(%ebp)           ;\
                            \
    RESTORE_KERNEL_SEGS             ;\
    SAVE_TRAP_CTX(displ, %ebp, %esi)        ;

#define SAVE_PROCESS_CTX(displ)             \
    SAVE_PROCESS_CTX_NON_LAZY(displ)        ;\
    push    %eax                    ;\
    push    %ebx                    ;\
    push    %ecx                    ;\
    push    %edx                    ;\
    push    %ebp                    ;\
    call    _save_fpu               ;\
    pop %ebp                    ;\
    pop %edx                    ;\
    pop %ecx                    ;\
    pop %ebx                    ;\
    pop %eax                    ;

/*
 * clear the IF flag in eflags which are stored somewhere in memory, e.g. on
 * stack. iret or popf will load the new value later
 */
#define CLEAR_IF(where) \
    mov where, %eax                     ;\
    andl    $0xfffffdff, %eax                   ;\
    mov %eax, where                     ;

#endif /* __SCONST_H__ */
在我的文件“/usr/src/kernel/test.s”中:

但我收到错误:在调用宏保存\u进程\u CTX(0)

怎么了

这里有一个文件“mpx.s”,它已经存在于“usr/src/kernel/arch/i386”中,并且使用了相同的宏“SAVE_PROCESS_CTX”,编译时没有问题,但是当调用相同的宏“SAVE_PROCESS_CTX”时,我无法编译该文件,文件如下:

/*
 * This file is part of the lowest layer of the MINIX kernel.  (The other part 
 * is "proc.c".)  The lowest layer does process switching and message handling. 
 * Furthermore it contains the assembler startup code for Minix and the 32-bit 
 * interrupt handlers.  It cooperates with the code in "start.c" to set up a  
 * good environment for main(). 
 *
 * Kernel is entered either because of kernel-calls, ipc-calls, interrupts or
 * exceptions. TSS is set so that the kernel stack is loaded. The user cotext is
 * saved to the proc table and the handler of the event is called. Once the
 * handler is done, switch_to_user() function is called to pick a new process,
 * finish what needs to be done for the next process to run, sets its context
 * and switch to userspace.
 *
 * For communication with the boot monitor at startup time some constant 
 * data are compiled into the beginning of the text segment. This facilitates  
 * reading the data at the start of the boot process, since only the first 
 * sector of the file needs to be read. 
 *
 * Some data storage is also allocated at the end of this file. This data  
 * will be at the start of the data segment of the kernel and will be read 
 * and modified by the boot monitor before the kernel starts.
 */

#include "kernel/kernel.h" /* configures the kernel */

/* sections */

#include <machine/vm.h>

#ifdef __ACK__
.text
begtext:
#ifdef __ACK__
.rom
#else
.data
#endif
begrom:
.data
begdata:
.bss
begbss:
#endif


#include <minix/config.h>
#include <minix/const.h>
#include <minix/com.h>
#include <machine/interrupt.h>
#include "archconst.h"
#include "kernel/const.h"
#include "kernel/proc.h"
#include "sconst.h"

/* Selected 386 tss offsets. */
#define TSS3_S_SP0  4

/*
 * Exported functions 
 * Note: in assembly language the .define statement applied to a function name  
 * is loosely equivalent to a prototype in C code -- it makes it possible to 
 * link to an entity declared in the assembly code but does not create 
 * the entity. 
 */

.globl  _restore_user_context
.globl  _reload_cr3

.globl  _divide_error
.globl  _single_step_exception
.globl  _nmi
.globl  _breakpoint_exception
.globl  _overflow
.globl  _bounds_check
.globl  _inval_opcode
.globl  _copr_not_available
.globl  _double_fault
.globl  _copr_seg_overrun
.globl  _inval_tss
.globl  _segment_not_present
.globl  _stack_exception
.globl  _general_protection
.globl  _page_fault
.globl  _copr_error
.globl  _alignment_check
.globl  _machine_check
.globl  _simd_exception
.globl  _params_size
.globl  _params_offset
.globl  _mon_ds
.globl  _switch_to_user
.globl  _save_fpu

.globl  _hwint00    /* handlers for hardware interrupts */
.globl  _hwint01
.globl  _hwint02
.globl  _hwint03
.globl  _hwint04
.globl  _hwint05
.globl  _hwint06
.globl  _hwint07
.globl  _hwint08
.globl  _hwint09
.globl  _hwint10
.globl  _hwint11
.globl  _hwint12
.globl  _hwint13
.globl  _hwint14
.globl  _hwint15

/* Exported variables. */
.globl  begbss
.globl  begdata

.text
/*===========================================================================*/
/*              MINIX                        */
/*===========================================================================*/
.globl MINIX
MINIX:
/* this is the entry point for the MINIX kernel */
    jmp over_flags  /* skip over the next few bytes */
.short  CLICK_SHIFT /* for the monitor: memory granularity */

flags:
/* boot monitor flags:
 *  call in 386 mode, make bss, make stack, 
 *  load high, don't patch, will return, 
 *  uses generic INT, memory vector, 
 *  new boot code return 
 */
.short  0x01FD  
    nop /* extra byte to sync up disassembler */
over_flags:

/* Set up a C stack frame on the monitor stack.  (The monitor sets cs and ds */
/* right.  The ss descriptor still references the monitor data segment.) */
    movzwl  %sp, %esp   /* monitor stack is a 16 bit stack */
    push    %ebp
    mov %esp, %ebp
    push    %esi
    push    %edi
    cmp $0, 4(%ebp) /* monitor return vector is */
    je  noret   /* nonzero if return possible */
    incl    _mon_return
noret:
    movl    %esp, _mon_sp   /* save stack pointer for later return */

/* Copy the monitor global descriptor table to the address space of kernel and */
/* switch over to it.  Prot_init() can then update it with immediate effect. */

    sgdt    _gdt+GDT_SELECTOR   /* get the monitor gdtr */
    movl    _gdt+GDT_SELECTOR+2, %esi   /* absolute address of GDT */
    mov $_gdt, %ebx /* address of kernel GDT */
    mov $8*8, %ecx  /* copying eight descriptors */
copygdt:
    movb    %es:(%esi), %al
    movb    %al, (%ebx)
    inc %esi
    inc %ebx
    loop    copygdt
    movl    _gdt+DS_SELECTOR+2, %eax    /* base of kernel data */
    and $0x00FFFFFF, %eax   /* only 24 bits */
    add $_gdt, %eax /* eax = vir2phys(gdt) */
    movl    %eax, _gdt+GDT_SELECTOR+2   /* set base of GDT */
    lgdt    _gdt+GDT_SELECTOR   /* switch over to kernel GDT */

/* Locate boot parameters, set up kernel segment registers and stack. */
    mov 8(%ebp), %ebx   /* boot parameters offset */
    mov 12(%ebp), %edx  /* boot parameters length */
    mov 16(%ebp), %eax  /* address of a.out headers */
    movl    %eax, _aout
    mov %ds, %ax    /* kernel data */
    mov %ax, %es
    mov %ax, %fs
    mov %ax, %gs
    mov %ax, %ss
    mov $_k_boot_stktop, %esp   /* set sp to point to the top of kernel stack */

/* Save boot parameters into these global variables for i386 code */
    movl    %edx, _params_size
    movl    %ebx, _params_offset
    movl    $SS_SELECTOR, _mon_ds

/* Call C startup code to set up a proper environment to run main(). */
    push    %edx
    push    %ebx
    push    $SS_SELECTOR
    push    $DS_SELECTOR
    push    $CS_SELECTOR
    call    _cstart /* cstart(cs, ds, mds, parmoff, parmlen) */
    add $5*4, %esp

/* Reload gdtr, idtr and the segment registers to global descriptor table set */
/* up by prot_init(). */

    lgdt    _gdt+GDT_SELECTOR
    lidt    _gdt+IDT_SELECTOR

    ljmp    $CS_SELECTOR, $csinit
csinit:
    movw    $DS_SELECTOR, %ax
    mov %ax, %ds
    mov %ax, %es
    mov %ax, %fs
    mov %ax, %gs
    mov %ax, %ss
    movw    $TSS_SELECTOR, %ax  /* no other TSS is used */
    ltr %ax
    push    $0  /* set flags to known good state */
    popf    /* esp, clear nested task and int enable */
    jmp _main   /* main() */


/*===========================================================================*/
/*              interrupt handlers               */
/*      interrupt handlers for 386 32-bit protected mode         */
/*===========================================================================*/

#define PIC_IRQ_HANDLER(irq)    \
    push    $irq                                    ;\
    call    _irq_handle     /* intr_handle(irq_handlers[irq]) */    ;\
    add $4, %esp                                ;

/*===========================================================================*/
/*              hwint00 - 07                     */
/*===========================================================================*/
/* Note this is a macro, it just looks like a subroutine. */

#define hwint_master(irq) \
    TEST_INT_IN_KERNEL(4, 0f)                   ;\
                                    \
    **SAVE_PROCESS_CTX(0)**                     ;\
    push    %ebp                            ;\
    movl    $0, %ebp    /* for stack trace */           ;\
    call    _context_stop                       ;\
    add $4, %esp                        ;\
    PIC_IRQ_HANDLER(irq)                        ;\
    movb    $END_OF_INT, %al                    ;\
    outb    $INT_CTL    /* reenable interrupts in master pic */ ;\
    jmp _switch_to_user                     ;\
                                    \
0:                                  \
    pusha                               ;\
    call    _context_stop_idle                  ;\
    PIC_IRQ_HANDLER(irq)                        ;\
    movb    $END_OF_INT, %al                    ;\
    outb    $INT_CTL    /* reenable interrupts in master pic */ ;\
    CLEAR_IF(10*4(%esp))                        ;\
    popa                                ;\
    iret                                ;

确保您正在通过C预处理器运行此操作。一些构建工具(如
gcc
)需要扩展名
.S
(大写)。我将文件扩展名从test.S更改为test.S,在Makefile中也更改了,然后立即编译gnu无法编译该文件并为每一行提供语法错误。我只有linux,没有minix,但在这里它可以正常工作。顺便说一句,将答案中的信息编辑到问题中,然后将其删除。你不应该用答案来提供更多的信息。
/*
 * This file is part of the lowest layer of the MINIX kernel.  (The other part 
 * is "proc.c".)  The lowest layer does process switching and message handling. 
 * Furthermore it contains the assembler startup code for Minix and the 32-bit 
 * interrupt handlers.  It cooperates with the code in "start.c" to set up a  
 * good environment for main(). 
 *
 * Kernel is entered either because of kernel-calls, ipc-calls, interrupts or
 * exceptions. TSS is set so that the kernel stack is loaded. The user cotext is
 * saved to the proc table and the handler of the event is called. Once the
 * handler is done, switch_to_user() function is called to pick a new process,
 * finish what needs to be done for the next process to run, sets its context
 * and switch to userspace.
 *
 * For communication with the boot monitor at startup time some constant 
 * data are compiled into the beginning of the text segment. This facilitates  
 * reading the data at the start of the boot process, since only the first 
 * sector of the file needs to be read. 
 *
 * Some data storage is also allocated at the end of this file. This data  
 * will be at the start of the data segment of the kernel and will be read 
 * and modified by the boot monitor before the kernel starts.
 */

#include "kernel/kernel.h" /* configures the kernel */

/* sections */

#include <machine/vm.h>

#ifdef __ACK__
.text
begtext:
#ifdef __ACK__
.rom
#else
.data
#endif
begrom:
.data
begdata:
.bss
begbss:
#endif


#include <minix/config.h>
#include <minix/const.h>
#include <minix/com.h>
#include <machine/interrupt.h>
#include "archconst.h"
#include "kernel/const.h"
#include "kernel/proc.h"
#include "sconst.h"

/* Selected 386 tss offsets. */
#define TSS3_S_SP0  4

/*
 * Exported functions 
 * Note: in assembly language the .define statement applied to a function name  
 * is loosely equivalent to a prototype in C code -- it makes it possible to 
 * link to an entity declared in the assembly code but does not create 
 * the entity. 
 */

.globl  _restore_user_context
.globl  _reload_cr3

.globl  _divide_error
.globl  _single_step_exception
.globl  _nmi
.globl  _breakpoint_exception
.globl  _overflow
.globl  _bounds_check
.globl  _inval_opcode
.globl  _copr_not_available
.globl  _double_fault
.globl  _copr_seg_overrun
.globl  _inval_tss
.globl  _segment_not_present
.globl  _stack_exception
.globl  _general_protection
.globl  _page_fault
.globl  _copr_error
.globl  _alignment_check
.globl  _machine_check
.globl  _simd_exception
.globl  _params_size
.globl  _params_offset
.globl  _mon_ds
.globl  _switch_to_user
.globl  _save_fpu

.globl  _hwint00    /* handlers for hardware interrupts */
.globl  _hwint01
.globl  _hwint02
.globl  _hwint03
.globl  _hwint04
.globl  _hwint05
.globl  _hwint06
.globl  _hwint07
.globl  _hwint08
.globl  _hwint09
.globl  _hwint10
.globl  _hwint11
.globl  _hwint12
.globl  _hwint13
.globl  _hwint14
.globl  _hwint15

/* Exported variables. */
.globl  begbss
.globl  begdata

.text
/*===========================================================================*/
/*              MINIX                        */
/*===========================================================================*/
.globl MINIX
MINIX:
/* this is the entry point for the MINIX kernel */
    jmp over_flags  /* skip over the next few bytes */
.short  CLICK_SHIFT /* for the monitor: memory granularity */

flags:
/* boot monitor flags:
 *  call in 386 mode, make bss, make stack, 
 *  load high, don't patch, will return, 
 *  uses generic INT, memory vector, 
 *  new boot code return 
 */
.short  0x01FD  
    nop /* extra byte to sync up disassembler */
over_flags:

/* Set up a C stack frame on the monitor stack.  (The monitor sets cs and ds */
/* right.  The ss descriptor still references the monitor data segment.) */
    movzwl  %sp, %esp   /* monitor stack is a 16 bit stack */
    push    %ebp
    mov %esp, %ebp
    push    %esi
    push    %edi
    cmp $0, 4(%ebp) /* monitor return vector is */
    je  noret   /* nonzero if return possible */
    incl    _mon_return
noret:
    movl    %esp, _mon_sp   /* save stack pointer for later return */

/* Copy the monitor global descriptor table to the address space of kernel and */
/* switch over to it.  Prot_init() can then update it with immediate effect. */

    sgdt    _gdt+GDT_SELECTOR   /* get the monitor gdtr */
    movl    _gdt+GDT_SELECTOR+2, %esi   /* absolute address of GDT */
    mov $_gdt, %ebx /* address of kernel GDT */
    mov $8*8, %ecx  /* copying eight descriptors */
copygdt:
    movb    %es:(%esi), %al
    movb    %al, (%ebx)
    inc %esi
    inc %ebx
    loop    copygdt
    movl    _gdt+DS_SELECTOR+2, %eax    /* base of kernel data */
    and $0x00FFFFFF, %eax   /* only 24 bits */
    add $_gdt, %eax /* eax = vir2phys(gdt) */
    movl    %eax, _gdt+GDT_SELECTOR+2   /* set base of GDT */
    lgdt    _gdt+GDT_SELECTOR   /* switch over to kernel GDT */

/* Locate boot parameters, set up kernel segment registers and stack. */
    mov 8(%ebp), %ebx   /* boot parameters offset */
    mov 12(%ebp), %edx  /* boot parameters length */
    mov 16(%ebp), %eax  /* address of a.out headers */
    movl    %eax, _aout
    mov %ds, %ax    /* kernel data */
    mov %ax, %es
    mov %ax, %fs
    mov %ax, %gs
    mov %ax, %ss
    mov $_k_boot_stktop, %esp   /* set sp to point to the top of kernel stack */

/* Save boot parameters into these global variables for i386 code */
    movl    %edx, _params_size
    movl    %ebx, _params_offset
    movl    $SS_SELECTOR, _mon_ds

/* Call C startup code to set up a proper environment to run main(). */
    push    %edx
    push    %ebx
    push    $SS_SELECTOR
    push    $DS_SELECTOR
    push    $CS_SELECTOR
    call    _cstart /* cstart(cs, ds, mds, parmoff, parmlen) */
    add $5*4, %esp

/* Reload gdtr, idtr and the segment registers to global descriptor table set */
/* up by prot_init(). */

    lgdt    _gdt+GDT_SELECTOR
    lidt    _gdt+IDT_SELECTOR

    ljmp    $CS_SELECTOR, $csinit
csinit:
    movw    $DS_SELECTOR, %ax
    mov %ax, %ds
    mov %ax, %es
    mov %ax, %fs
    mov %ax, %gs
    mov %ax, %ss
    movw    $TSS_SELECTOR, %ax  /* no other TSS is used */
    ltr %ax
    push    $0  /* set flags to known good state */
    popf    /* esp, clear nested task and int enable */
    jmp _main   /* main() */


/*===========================================================================*/
/*              interrupt handlers               */
/*      interrupt handlers for 386 32-bit protected mode         */
/*===========================================================================*/

#define PIC_IRQ_HANDLER(irq)    \
    push    $irq                                    ;\
    call    _irq_handle     /* intr_handle(irq_handlers[irq]) */    ;\
    add $4, %esp                                ;

/*===========================================================================*/
/*              hwint00 - 07                     */
/*===========================================================================*/
/* Note this is a macro, it just looks like a subroutine. */

#define hwint_master(irq) \
    TEST_INT_IN_KERNEL(4, 0f)                   ;\
                                    \
    **SAVE_PROCESS_CTX(0)**                     ;\
    push    %ebp                            ;\
    movl    $0, %ebp    /* for stack trace */           ;\
    call    _context_stop                       ;\
    add $4, %esp                        ;\
    PIC_IRQ_HANDLER(irq)                        ;\
    movb    $END_OF_INT, %al                    ;\
    outb    $INT_CTL    /* reenable interrupts in master pic */ ;\
    jmp _switch_to_user                     ;\
                                    \
0:                                  \
    pusha                               ;\
    call    _context_stop_idle                  ;\
    PIC_IRQ_HANDLER(irq)                        ;\
    movb    $END_OF_INT, %al                    ;\
    outb    $INT_CTL    /* reenable interrupts in master pic */ ;\
    CLEAR_IF(10*4(%esp))                        ;\
    popa                                ;\
    iret                                ;
#ifndef __SCONST_H__
#define __SCONST_H__

#include "kernel/const.h"

/* Miscellaneous constants used in assembler code. */
    W = _WORD_SIZE  /* Machine word size. */

/* Offsets in struct proc. They MUST match proc.h. */
    P_STACKBASE = 0
    GSREG = P_STACKBASE
    FSREG = GSREG+2 /* 386 introduces FS and GS segments*/
    ESREG = FSREG+2
    DSREG = ESREG+2
    DIREG = DSREG+2
    SIREG = DIREG+W
    BPREG = SIREG+W
    STREG = BPREG+W /* hole for another SP*/
    BXREG = STREG+W
    DXREG = BXREG+W
    CXREG = DXREG+W
    AXREG = CXREG+W
    RETADR = AXREG+W    /* return address for save() call*/
    PCREG = RETADR+W
    CSREG = PCREG+W
    PSWREG = CSREG+W
    SPREG = PSWREG+W
    SSREG = SPREG+W
    P_STACKTOP = SSREG+W
    FP_SAVE_AREA_P = P_STACKTOP
    P_LDT_SEL = FP_SAVE_AREA_P + 532
    P_CR3 = P_LDT_SEL+W
    P_CR3_V = P_CR3+4
    P_LDT = P_CR3_V+W
    P_MISC_FLAGS = P_LDT + 50
    Msize = 9   /* size of a message in 32-bit words*/


/*
 * offset to current process pointer right after trap, we assume we always have
 * error code on the stack
 */
#define CURR_PROC_PTR       20

/*
 * tests whether the interrupt was triggered in kernel. If so, jump to the
 * label. Displacement tell the macro ha far is the CS value saved by the trap
 * from the current %esp. The kernel code segment selector has the lower 3 bits
 * zeroed
 */
#define TEST_INT_IN_KERNEL(displ, label)    \
    cmpl    $CS_SELECTOR, displ(%esp)   ;\
    je  label               ;

/*
 * saves the basic interrupt context (no error code) to the process structure
 *
 * displ is the displacement of %esp from the original stack after trap
 * pptr is the process structure pointer
 * tmp is an available temporary register
 */
#define SAVE_TRAP_CTX(displ, pptr, tmp)         \
    movl    (0 + displ)(%esp), tmp          ;\
    movl    tmp, PCREG(pptr)            ;\
    movl    (4 + displ)(%esp), tmp          ;\
    movl    tmp, CSREG(pptr)            ;\
    movl    (8 + displ)(%esp), tmp          ;\
    movl    tmp, PSWREG(pptr)           ;\
    movl    (12 + displ)(%esp), tmp         ;\
    movl    tmp, SPREG(pptr)            ;\
    movl    tmp, STREG(pptr)            ;\
    movl    (16 + displ)(%esp), tmp         ;\
    movl    tmp, SSREG(pptr)            ;

#define SAVE_SEGS(pptr)     \
    mov %ds, %ss:DSREG(pptr)    ;\
    mov %es, %ss:ESREG(pptr)    ;\
    mov %fs, %ss:FSREG(pptr)    ;\
    mov %gs, %ss:GSREG(pptr)    ;

#define RESTORE_SEGS(pptr)      \
    movw    %ss:DSREG(pptr), %ds    ;\
    movw    %ss:ESREG(pptr), %es    ;\
    movw    %ss:FSREG(pptr), %fs    ;\
    movw    %ss:GSREG(pptr), %gs    ;

/*
 * restore kernel segments, %ss is kernnel data segment, %cs is aready set and
 * %fs, %gs are not used
 */
#define RESTORE_KERNEL_SEGS \
    mov %ss, %si    ;\
    mov %si, %ds    ;\
    mov %si, %es    ;\
    movw    $0, %si     ;\
    mov %si, %gs    ;\
    mov %si, %fs    ;

#define SAVE_GP_REGS(pptr)  \
    mov %eax, %ss:AXREG(pptr)       ;\
    mov %ecx, %ss:CXREG(pptr)       ;\
    mov %edx, %ss:DXREG(pptr)       ;\
    mov %ebx, %ss:BXREG(pptr)       ;\
    mov %esi, %ss:SIREG(pptr)       ;\
    mov %edi, %ss:DIREG(pptr)       ;

#define RESTORE_GP_REGS(pptr)   \
    movl    %ss:AXREG(pptr), %eax       ;\
    movl    %ss:CXREG(pptr), %ecx       ;\
    movl    %ss:DXREG(pptr), %edx       ;\
    movl    %ss:BXREG(pptr), %ebx       ;\
    movl    %ss:SIREG(pptr), %esi       ;\
    movl    %ss:DIREG(pptr), %edi       ;

/*
 * save the context of the interrupted process to the structure in the process
 * table. It pushses the %ebp to stack to get a scratch register. After %esi is
 * saved, we can use it to get the saved %ebp from stack and save it to the
 * final location
 *
 * displ is the stack displacement. In case of an exception, there are two extra
 * value on the stack - error code and the exception number
 */
#define SAVE_PROCESS_CTX_NON_LAZY(displ) \
                                \
    cld /* set the direction flag to a known state */   ;\
                                \
    push    %ebp                    ;\
                            ;\
    movl    (CURR_PROC_PTR + 4 + displ)(%esp), %ebp ;\
                            ;\
    /* save the segment registers */        \
    SAVE_SEGS(%ebp)                 ;\
                            \
    SAVE_GP_REGS(%ebp)              ;\
    pop %esi            /* get the orig %ebp and save it */ ;\
    mov %esi, %ss:BPREG(%ebp)           ;\
                            \
    RESTORE_KERNEL_SEGS             ;\
    SAVE_TRAP_CTX(displ, %ebp, %esi)        ;

**#define SAVE_PROCESS_CTX(displ)               \**
    SAVE_PROCESS_CTX_NON_LAZY(displ)        ;\
    push    %eax                    ;\
    push    %ebx                    ;\
    push    %ecx                    ;\
    push    %edx                    ;\
    push    %ebp                    ;\
    call    _save_fpu               ;\
    pop %ebp                    ;\
    pop %edx                    ;\
    pop %ecx                    ;\
    pop %ebx                    ;\
    pop %eax                    ;