- kernel detects CPUs by searching ACPI tables for local apic nodes - each CPU has its own TSS that points to its own stack. All cpus boot on the same boot stack (in sequence) but switch to its private stack as soon as they can. - final booting code in main() placed in bsp_finish_booting() which is executed only after the BSP switches to its final stack - apic functions to send startup interrupts - assembler functions to handle CPU features not needed for single cpu mode like memory barries, HT detection etc. - new files kernel/smp.[ch], kernel/arch/i386/arch_smp.c and kernel/arch/i386/include/arch_smp.h - 16-bit trampoline code for the APs. It is executed by each AP after receiving startup IPIs it brings up the CPUs to 32bit mode and let them spin in an infinite loop so they don't do any damage. - implementation of kernel spinlock - CONFIG_SMP and CONFIG_MAX_CPUS set by the build system
151 lines
4 KiB
C
151 lines
4 KiB
C
#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(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) ;
|
|
|
|
/*
|
|
* 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__ */
|