#include "mem.h"
-#include "/sys/src/boot/pc/x16.h"
#undef DELAY
#define PADDR(a) ((a) & ~KZERO)
#define INVLPG BYTE $0x0F; BYTE $0x01; BYTE $0x39 /* INVLPG (%ecx) */
#define WBINVD BYTE $0x0F; BYTE $0x09
+#define VectorSYSCALL 0x40
+
/*
* Macros for calculating offsets within the page directory base
* and page tables. Note that these are assembler-specific hence
*/
TEXT _multibootheader(SB), $0
LONG $0x1BADB002 /* magic */
- LONG $0x00010003 /* flags */
- LONG $-(0x1BADB002 + 0x00010003) /* checksum */
+ LONG $0x00010007 /* flags */
+ LONG $-(0x1BADB002 + 0x00010007) /* checksum */
LONG $_multibootheader-KZERO(SB) /* header_addr */
LONG $_startKADDR-KZERO(SB) /* load_addr */
LONG $edata-KZERO(SB) /* load_end_addr */
LONG $end-KZERO(SB) /* bss_end_addr */
- LONG $_startKADDR-KZERO(SB) /* entry_addr */
+ LONG $_multibootentry-KZERO(SB) /* entry_addr */
LONG $0 /* mode_type */
LONG $0 /* width */
LONG $0 /* height */
- LONG $0 /* depth */
+ LONG $32 /* depth */
+
+/*
+ * the kernel expects the data segment to be page-aligned
+ * multiboot bootloaders put the data segment right behind text
+ */
+TEXT _multibootentry(SB), $0
+ MOVL $etext-KZERO(SB), SI
+ MOVL SI, DI
+ ADDL $0xfff, DI
+ ANDL $~0xfff, DI
+ MOVL $edata-KZERO(SB), CX
+ SUBL DI, CX
+ ADDL CX, SI
+ ADDL CX, DI
+ INCL CX /* one more for post decrement */
+ STD
+ REP; MOVSB
+ MOVL BX, multibootptr-KZERO(SB)
+ MOVL $_startPADDR-KZERO(SB), AX
+ JMP* AX
+
+/* multiboot structure pointer (physical address) */
+TEXT multibootptr(SB), $0
+ LONG $0
/*
* In protected mode with paging turned off and segment registers setup
CLI /* make sure interrupts are off */
/* set up the gdt so we have sane plan 9 style gdts. */
- MOVL $tgdtptr(SB), AX
- ANDL $~KZERO, AX
+ MOVL $tgdtptr-KZERO(SB), AX
MOVL (AX), GDTR
MOVW $1, AX
MOVW AX, MSW
WORD $(3*8)
LONG $tgdt-KZERO(SB)
-TEXT m0rgdtptr(SB), $0
- WORD $(NGDT*8-1)
- LONG $(CPU0GDT-KZERO)
-
-TEXT m0gdtptr(SB), $0
- WORD $(NGDT*8-1)
- LONG $CPU0GDT
-
-TEXT m0idtptr(SB), $0
- WORD $(256*8-1)
- LONG $IDTADDR
+TEXT vtgdtptr(SB), $0
+ WORD $(3*8)
+ LONG $tgdt(SB)
TEXT mode32bit(SB), $0
- /* At this point, the GDT setup is done. */
-
- MOVL $PADDR(CPU0PDB), DI /* clear 4 pages for the tables etc. */
+ MOVL $((CPU0END-CPU0PDB)>>2), CX
+ MOVL $PADDR(CPU0PDB), DI
XORL AX, AX
- MOVL $(4*BY2PG), CX
- SHRL $2, CX
CLD
REP; STOSL
+ MOVL $PADDR(CPU0PTE), DX
+ MOVL $(PTEWRITE|PTEVALID), BX /* page permissions */
+ ORL BX, DX
+
MOVL $PADDR(CPU0PDB), AX
ADDL $PDO(KZERO), AX /* page directory offset for KZERO */
- MOVL $PADDR(CPU0PTE), (AX) /* PTE's for KZERO */
- MOVL $(PTEWRITE|PTEVALID), BX /* page permissions */
- ORL BX, (AX)
- ADDL $4, AX
- MOVL $PADDR(CPU0PTE1), (AX) /* PTE's for KZERO+4MB */
- MOVL $(PTEWRITE|PTEVALID), BX /* page permissions */
- ORL BX, (AX)
+ MOVL DX, 0(AX) /* PTE's for KZERO */
+ ADDL $BY2PG, DX
+ MOVL DX, 4(AX) /* PTE's for KZERO+4MB */
+ ADDL $BY2PG, DX
+ MOVL DX, 8(AX) /* PTE's for KZERO+8MB */
+ ADDL $BY2PG, DX
+ MOVL DX, 12(AX) /* PTE's for KZERO+12MB */
MOVL $PADDR(CPU0PTE), AX /* first page of page table */
- MOVL $1024, CX /* 1024 pages in 4MB */
+ MOVL $end-KZERO(SB), CX
+
+ ADDL $(16*1024), CX /* qemu puts multiboot data after the kernel */
+
+ ADDL $(BY2XPG-1), CX
+ ANDL $~(BY2XPG-1), CX /* round to 4MB */
+ MOVL CX, MemMin-KZERO(SB) /* see memory.c */
+ SHRL $PGSHIFT, CX
+ MOVL BX, DX
_setpte:
- MOVL BX, (AX)
- ADDL $(1<<PGSHIFT), BX
+ MOVL DX, (AX)
+ ADDL $BY2PG, DX
ADDL $4, AX
LOOP _setpte
- MOVL $PADDR(CPU0PTE1), AX /* second page of page table */
- MOVL $1024, CX /* 1024 pages in 4MB */
-_setpte1:
- MOVL BX, (AX)
- ADDL $(1<<PGSHIFT), BX
- ADDL $4, AX
- LOOP _setpte1
-
MOVL $PADDR(CPU0PTE), AX
ADDL $PTO(MACHADDR), AX /* page table entry offset for MACHADDR */
- MOVL $PADDR(CPU0MACH), (AX) /* PTE for Mach */
- MOVL $(PTEWRITE|PTEVALID), BX /* page permissions */
- ORL BX, (AX)
+ ORL $PADDR(CPU0MACH), BX
+ MOVL BX, (AX) /* PTE for Mach */
/*
* Now ready to use the new map. Make sure the processor options are what is wanted.
* be initialised here.
*/
TEXT _startpg(SB), $0
+ MOVL $vtgdtptr(SB), AX
+ MOVL (AX), GDTR
+
MOVL $0, (PDO(0))(CX) /* undo double-map of KZERO at 0 */
MOVL CX, CR3 /* load and flush the mmu */
MOVW AX, GS
RET
-/*
- * Save registers.
- */
-TEXT saveregs(SB), $0
- /* appease 8l */
- SUBL $32, SP
- POPL AX
- POPL AX
- POPL AX
- POPL AX
- POPL AX
- POPL AX
- POPL AX
- POPL AX
-
- PUSHL AX
- PUSHL BX
- PUSHL CX
- PUSHL DX
- PUSHL BP
- PUSHL DI
- PUSHL SI
- PUSHFL
-
- XCHGL 32(SP), AX /* swap return PC and saved flags */
- XCHGL 0(SP), AX
- XCHGL 32(SP), AX
- RET
-
-TEXT restoreregs(SB), $0
- /* appease 8l */
- PUSHL AX
- PUSHL AX
- PUSHL AX
- PUSHL AX
- PUSHL AX
- PUSHL AX
- PUSHL AX
- PUSHL AX
- ADDL $32, SP
-
- XCHGL 32(SP), AX /* swap return PC and saved flags */
- XCHGL 0(SP), AX
- XCHGL 32(SP), AX
-
- POPFL
- POPL SI
- POPL DI
- POPL BP
- POPL DX
- POPL CX
- POPL BX
- POPL AX
- RET
-
/*
* BIOS32.
*/
MOVL CR2, AX
RET
+TEXT putcr2(SB), $0
+ MOVL cr2+0(FP), AX
+ MOVL AX, CR2
+ RET
+
TEXT getcr3(SB), $0 /* CR3 - page directory base */
MOVL CR3, AX
RET
RET
TEXT rdmsr(SB), $0 /* model-specific register */
- MOVL index+0(FP), CX
- RDMSR
- MOVL vlong+4(FP), CX /* &vlong */
- MOVL AX, 0(CX) /* lo */
- MOVL DX, 4(CX) /* hi */
- RET
-
-TEXT tryrdmsr(SB), $0 /* model-specific register */
MOVL $0, BP
MOVL index+0(FP), CX
-TEXT _tryrdmsrinst(SB), $0
+TEXT _rdmsrinst(SB), $0
RDMSR
MOVL vlong+4(FP), CX /* &vlong */
MOVL AX, 0(CX) /* lo */
MOVL DX, 4(CX) /* hi */
- MOVL BP, AX
+ MOVL BP, AX /* BP set to -1 if traped */
RET
TEXT wrmsr(SB), $0
+ MOVL $0, BP
MOVL index+0(FP), CX
MOVL lo+4(FP), AX
MOVL hi+8(FP), DX
+TEXT _wrmsrinst(SB), $0
WRMSR
+ MOVL BP, AX /* BP set to -1 if traped */
RET
-TEXT trywrmsr(SB), $0
- MOVL $0, BP
- MOVL index+0(FP), CX
- MOVL lo+4(FP), AX
- MOVL hi+8(FP), DX
-TEXT _trywrmsrinst(SB), $0
- WRMSR
- MOVL BP, AX
+/* fault-proof memcpy */
+TEXT peek(SB), $0
+ MOVL src+0(FP), SI
+ MOVL dst+4(FP), DI
+ MOVL cnt+8(FP), CX
+ CLD
+TEXT _peekinst(SB), $0
+ REP; MOVSB
+ MOVL CX, AX
RET
/*
* a 386 (Ac bit can't be set). If it's not a 386 and the Id bit can't be
* toggled then it's an older 486 of some kind.
*
- * cpuid(fun, regs[4]);
+ * cpuid(fn, sublvl, regs[4]);
*/
TEXT cpuid(SB), $0
MOVL $0x240000, AX
TESTL $0x200000, AX /* Id */
JZ _cpu486 /* can't toggle this bit on some 486 */
MOVL fn+0(FP), AX
+ MOVL sublvl+4(FP), CX
CPUID
JMP _cpuid
_cpu486:
XORL CX, CX
XORL DX, DX
_cpuid:
- MOVL regs+4(FP), BP
+ MOVL regs+8(FP), BP
MOVL AX, 0(BP)
MOVL BX, 4(BP)
MOVL CX, 8(BP)
* FNxxx variations) so WAIT instructions must be explicitly placed in the
* code as necessary.
*/
-#define FPOFF(l) ;\
- MOVL CR0, AX ;\
- ANDL $0xC, AX /* EM, TS */ ;\
- CMPL AX, $0x8 ;\
- JEQ l ;\
- WAIT ;\
-l: ;\
+#define FPOFF ;\
MOVL CR0, AX ;\
- ANDL $~0x4, AX /* EM=0 */ ;\
ORL $0x28, AX /* NE=1, TS=1 */ ;\
MOVL AX, CR0
MOVL CR0, AX ;\
ANDL $~0xC, AX /* EM=0, TS=0 */ ;\
MOVL AX, CR0
-
+
TEXT fpoff(SB), $0 /* disable */
- FPOFF(l1)
+ FPOFF
RET
TEXT fpinit(SB), $0 /* enable and init */
WAIT
RET
-TEXT fpsave(SB), $0 /* save state and disable */
+TEXT fpx87save0(SB), $0 /* save state and disable */
MOVL p+0(FP), AX
FSAVE 0(AX) /* no WAIT */
- FPOFF(l2)
+ FPOFF
RET
-TEXT fprestore(SB), $0 /* enable and restore state */
+TEXT fpx87restore0(SB), $0 /* enable and restore state */
FPON
MOVL p+0(FP), AX
FRSTOR 0(AX)
WAIT
RET
-TEXT fpstatus(SB), $0 /* get floating point status */
- FSTSW AX
+TEXT fpclear(SB), $0 /* clear pending exceptions */
+ FPON
+ FCLEX /* no WAIT */
+ FPOFF
RET
-TEXT fpenv(SB), $0 /* save state without waiting */
+TEXT fpssesave(SB), $0 /* save state and disable */
MOVL p+0(FP), AX
- FSTENV 0(AX)
+ FXSAVE 0(AX) /* no WAIT */
+ FPOFF
RET
-TEXT fpclear(SB), $0 /* clear pending exceptions */
+TEXT fpsserestore(SB), $0 /* enable and restore state */
FPON
- FCLEX /* no WAIT */
- FPOFF(l3)
+ MOVL p+0(FP), AX
+ FXRSTOR 0(AX)
+ WAIT
+ RET
+
+TEXT ldmxcsr(SB), $0 /* Load MXCSR */
+ LDMXCSR mxcsr+0(FP)
RET
/*
* Test-And-Set
*/
TEXT tas(SB), $0
+TEXT _tas(SB), $0
MOVL $0xDEADDEAD, AX
MOVL lock+0(FP), BX
XCHGL AX, (BX) /* lock->key */
RET
-TEXT _xinc(SB), $0 /* void _xinc(long*); */
- MOVL l+0(FP), AX
- LOCK; INCL 0(AX)
- RET
-
-TEXT _xdec(SB), $0 /* long _xdec(long*); */
- MOVL l+0(FP), BX
- XORL AX, AX
- LOCK; DECL 0(BX)
- JLT _xdeclt
- JGT _xdecgt
- RET
-_xdecgt:
- INCL AX
- RET
-_xdeclt:
- DECL AX
- RET
-
TEXT mb386(SB), $0
POPL AX /* return PC */
PUSHFL
HLT
RET
+TEXT mwait(SB), $0
+ MOVL addr+0(FP), AX
+ MOVL (AX), CX
+ ORL CX, CX
+ JNZ _mwaitdone
+ XORL DX, DX
+ BYTE $0x0f; BYTE $0x01; BYTE $0xc8 /* MONITOR */
+ MOVL (AX), CX
+ ORL CX, CX
+ JNZ _mwaitdone
+ XORL AX, AX
+ BYTE $0x0f; BYTE $0x01; BYTE $0xc9 /* MWAIT */
+_mwaitdone:
+ RET
+
+#define RDRANDAX BYTE $0x0f; BYTE $0xc7; BYTE $0xf0
+
+TEXT rdrand32(SB), $-4
+_rloop32:
+ RDRANDAX
+ JCC _rloop32
+ RET
+
+TEXT rdrandbuf(SB), $0
+ MOVL buf+0(FP), DI
+ MOVL cnt+4(FP), CX
+ CLD
+ MOVL CX, DX
+ SHRL $2, CX
+ CMPL CX, $0
+ JE _rndleft
+_rnddwords:
+ CALL rdrand32(SB)
+ STOSL
+ LOOP _rnddwords
+_rndleft:
+ MOVL DX, CX
+ ANDL $3, CX
+ CMPL CX, $0
+ JE _rnddone
+_rndbytes:
+ CALL rdrand32(SB)
+ STOSB
+ LOOP _rndbytes
+_rnddone:
+ RET
+
+/* debug register access */
+
+TEXT putdr(SB), $0
+ MOVL p+0(FP), SI
+ MOVL 28(SI), AX
+ MOVL AX, DR7
+_putdr01236:
+ MOVL 0(SI), AX
+ MOVL AX, DR0
+ MOVL 4(SI), AX
+ MOVL AX, DR1
+ MOVL 8(SI), AX
+ MOVL AX, DR2
+ MOVL 12(SI), AX
+ MOVL AX, DR3
+ MOVL 24(SI), AX
+ MOVL AX, DR6
+ RET
+
+TEXT putdr01236(SB), $0
+ MOVL p+0(FP), SI
+ JMP _putdr01236
+
+TEXT getdr6(SB), $0
+ MOVL DR6, AX
+ RET
+
+TEXT putdr6(SB), $0
+ MOVL p+0(FP), AX
+ MOVL AX, DR6
+ RET
+
+TEXT putdr7(SB), $0
+ MOVL p+0(FP), AX
+ MOVL AX, DR7
+ RET
+
+/* VMX instructions */
+TEXT vmxon(SB), $0
+ /* VMXON 4(SP) */
+ BYTE $0xf3; BYTE $0x0f; BYTE $0xc7; BYTE $0x74; BYTE $0x24; BYTE $0x04
+ JMP _vmout
+
+TEXT vmxoff(SB), $0
+ BYTE $0x0f; BYTE $0x01; BYTE $0xc4
+ JMP _vmout
+
+TEXT vmclear(SB), $0
+ /* VMCLEAR 4(SP) */
+ BYTE $0x66; BYTE $0x0f; BYTE $0xc7; BYTE $0x74; BYTE $0x24; BYTE $0x04
+ JMP _vmout
+
+TEXT vmlaunch(SB), $0
+ MOVL $0x6C14, DI
+ MOVL SP, DX
+ BYTE $0x0f; BYTE $0x79; BYTE $0xfa /* VMWRITE DX, DI */
+ JBE _vmout
+ MOVL $0x6C16, DI
+ MOVL $vmrestore(SB), DX
+ BYTE $0x0f; BYTE $0x79; BYTE $0xfa /* VMWRITE DX, DI */
+ JBE _vmout
+
+ MOVL resume+4(FP), AX
+ TESTL AX, AX
+ MOVL ureg+0(FP), DI
+ MOVL 4(DI), SI
+ MOVL 8(DI), BP
+ MOVL 16(DI), BX
+ MOVL 20(DI), DX
+ MOVL 24(DI), CX
+ MOVL 28(DI), AX
+ MOVL 0(DI), DI
+ JNE _vmresume
+ BYTE $0x0f; BYTE $0x01; BYTE $0xc2 /* VMLAUNCH */
+ JMP _vmout
+_vmresume:
+ BYTE $0x0f; BYTE $0x01; BYTE $0xc3 /* VMRESUME */
+ JMP _vmout
+
+TEXT vmrestore(SB), $0
+ PUSHL DI
+ MOVL ureg+0(FP), DI
+ POPL 0(DI)
+ MOVL SI, 4(DI)
+ MOVL BP, 8(DI)
+ MOVL BX, 16(DI)
+ MOVL DX, 20(DI)
+ MOVL CX, 24(DI)
+ MOVL AX, 28(DI)
+ XORL AX, AX
+ RET
+
+TEXT vmptrld(SB), $0
+ /* VMPTRLD 4(SP) */
+ BYTE $0x0f; BYTE $0xc7; BYTE $0x74; BYTE $0x24; BYTE $0x04
+ JMP _vmout
+
+TEXT vmwrite(SB), $0
+ MOVL addr+0(FP),DI
+ MOVL val+4(FP),DX
+ /* VMWRITE DX, DI */
+ BYTE $0x0f; BYTE $0x79; BYTE $0xfa
+ JMP _vmout
+
+TEXT vmread(SB), $0
+ MOVL addr+0(FP),DI
+ MOVL valp+4(FP),SI
+ /* VMREAD (SI), DI */
+ BYTE $0x0f; BYTE $0x78; BYTE $0x3e
+ JMP _vmout
+
+TEXT invept(SB), $0
+ MOVL type+0(FP), AX
+ /* INVEPT AX, 8(SP) */
+ BYTE $0x66; BYTE $0x0f; BYTE $0x38; BYTE $0x80; BYTE $0x44; BYTE $0x24; BYTE $0x08
+ JMP _vmout
+
+TEXT invvpid(SB), $0
+ MOVL type+0(FP), AX
+ /* INVVPID AX, 8(SP) */
+ BYTE $0x66; BYTE $0x0f; BYTE $0x38; BYTE $0x81; BYTE $0x44; BYTE $0x24; BYTE $0x08
+ JMP _vmout
+
+_vmout:
+ JC _vmout1
+ JZ _vmout2
+ XORL AX, AX
+ RET
+_vmout1:
+ MOVL $-1, AX
+ RET
+_vmout2:
+ MOVL $-2, AX
+ RET
+
+/*
+ * Used to get to the first process:
+ * set up an interrupt return frame and IRET to user level.
+ */
+TEXT touser(SB), $0
+ PUSHL $(UDSEL) /* old ss */
+ MOVL sp+0(FP), AX /* old sp */
+ PUSHL AX
+ MOVL $0x200, AX /* interrupt enable flag */
+ PUSHL AX /* old flags */
+ PUSHL $(UESEL) /* old cs */
+ PUSHL $(UTZERO+32) /* old pc */
+ MOVL $(UDSEL), AX
+ MOVW AX, DS
+ MOVW AX, ES
+ MOVW AX, GS
+ MOVW AX, FS
+ IRETL
+
/*
* Interrupt/exception handling.
* Each entry in the vector table calls either _strayintr or _strayintrx depending
TEXT _forkretiret(SB), $0
IRETL
+/*
+ * This is merely _strayintr optimised to vector
+ * to syscall() without going through trap().
+ */
+TEXT _syscallintr(SB), $0
+ PUSHL $VectorSYSCALL /* trap type */
+
+ PUSHL DS
+ PUSHL ES
+ PUSHL FS
+ PUSHL GS
+ PUSHAL
+ MOVL $(KDSEL), AX
+ MOVW AX, DS
+ MOVW AX, ES
+
+ MOVL $syscall(SB), AX
+
+ PUSHL SP /* Ureg* argument to syscall */
+ PUSHL $forkret(SB) /* return pc */
+ JMP *AX
+
TEXT vectortable(SB), $0
CALL _strayintr(SB); BYTE $0x00 /* divide error */
CALL _strayintr(SB); BYTE $0x01 /* debug exception */
CALL _strayintr(SB); BYTE $0x10 /* coprocessor error */
CALL _strayintrx(SB); BYTE $0x11 /* alignment check */
CALL _strayintr(SB); BYTE $0x12 /* machine check */
- CALL _strayintr(SB); BYTE $0x13
+ CALL _strayintr(SB); BYTE $0x13 /* simd error */
CALL _strayintr(SB); BYTE $0x14
CALL _strayintr(SB); BYTE $0x15
CALL _strayintr(SB); BYTE $0x16