#include "mem.h"
#define OP16 BYTE $0x66
#define NOP XCHGL AX,AX
#define CPUID BYTE $0x0F; BYTE $0xA2 /* CPUID, argument in AX */
#define WRMSR BYTE $0x0F; BYTE $0x30 /* WRMSR, argument in AX/DX (lo/hi) */
#define RDMSR BYTE $0x0F; BYTE $0x32 /* RDMSR, result in AX/DX (lo/hi) */
#define RDTSC BYTE $0x0F; BYTE $0x31
#define DELAY BYTE $0xEB; BYTE $0x00 /* JMP .+2 */
/*
* Macros for calculating offsets within the page directory base
* and page tables. Note that these are assembler-specific hence
* the '<<2'.
*/
#define PDO(a) (((((a))>>22) & 0x03FF)<<2)
#define PTO(a) (((((a))>>12) & 0x03FF)<<2)
TEXT origin(SB),$0
CLI
/*
* Clear BSS
*/
LEAL edata-KZERO(SB),SI
MOVL SI,DI
ADDL $4,DI
MOVL $0,AX
MOVL AX,(SI)
LEAL end-KZERO(SB),CX
SUBL DI,CX
SHRL $2,CX
CLD; REP; MOVSL
/*
* make a bottom level page table page that maps the first
* 4 meg of physical memory
*/
LEAL tpt-KZERO(SB),AX /* get phys addr of temporary page table */
ADDL $(BY2PG-1),AX /* must be page alligned */
ANDL $(~(BY2PG-1)),AX /* ... */
MOVL $1024,CX /* pte's per page */
MOVL $(((1024-1)<<PGSHIFT)|PTEVALID|PTEKERNEL|PTEWRITE),BX
setpte:
MOVL BX,-4(AX)(CX*4)
SUBL $(1<<PGSHIFT),BX
LOOP setpte
/*
* make a top level page table page that maps the first
* 4 meg of memory to 0 thru 4meg and to KZERO thru KZERO+4meg
*/
MOVL AX,BX
ADDL $BY2PG,AX
ADDL $(PTEVALID|PTEKERNEL|PTEWRITE),BX
MOVL BX,0(AX)
MOVL BX,(PDO(KZERO))(AX)
/*
* point processor to top level page & turn on paging & make
* supervisor obey the R/W bit in the page map
*/
MOVL AX,CR3
DELAY
MOVL CR0,AX
ORL $0x80010000,AX /* PG|WP */
ANDL $~0x6000000A,AX /* ~(CD|NW|TS|MP) */
MOVL AX,CR0
/*
* use a jump to an absolute location to get the PC into
* KZERO.
*/
LEAL tokzero(SB),AX
JMP* AX
TEXT tokzero(SB),$0
/*
* stack and mach
*/
MOVL $mach0(SB),SP
MOVL SP,m(SB)
MOVL $0,0(SP)
ADDL $(MACHSIZE-4),SP /* start stack under machine struct */
MOVL $0, u(SB)
/*
* clear flags
*/
MOVL $0,AX
PUSHL AX
POPFL
CALL main(SB)
loop:
JMP loop
GLOBL mach0+0(SB), $MACHSIZE
GLOBL u(SB), $4
GLOBL m(SB), $4
GLOBL tpt(SB), $(BY2PG*3)
/*
* gdt to get us to 32-bit/segmented/unpaged mode
*/
TEXT tgdt(SB),$0
/* null descriptor */
LONG $0
LONG $0
/* data segment descriptor for 4 gigabytes (PL 0) */
LONG $(0xFFFF)
LONG $(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW)
/* exec segment descriptor for 4 gigabytes (PL 0) */
LONG $(0xFFFF)
LONG $(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR)
/*
* pointer to initial gdt
*/
TEXT tgdtptr(SB),$0
WORD $(3*8)
LONG $tgdt-KZERO(SB)
/*
* input a byte
*/
TEXT inb(SB),$0
MOVL p+0(FP),DX
XORL AX,AX
INB
RET
/*
* input a string of bytes from a port
*/
TEXT insb(SB),$0
MOVL p+0(FP),DX
MOVL a+4(FP),DI
MOVL c+8(FP),CX
CLD; REP; INSB
RET
/*
* output a byte
*/
TEXT outb(SB),$0
MOVL p+0(FP),DX
MOVL b+4(FP),AX
OUTB
RET
/*
* output a string of bytes to a port
*/
TEXT outsb(SB),$0
MOVL p+0(FP),DX
MOVL a+4(FP),SI
MOVL c+8(FP),CX
CLD; REP; OUTSB
RET
/*
* input a short from a port
*/
TEXT ins(SB), $0
MOVL p+0(FP), DX
XORL AX, AX
OP16; INL
RET
/*
* input a string of shorts from a port
*/
TEXT inss(SB),$0
MOVL p+0(FP),DX
MOVL a+4(FP),DI
MOVL c+8(FP),CX
CLD; REP; OP16; INSL
RET
/*
* input a long from a port
*/
TEXT inl(SB), $0
MOVL p+0(FP), DX
XORL AX, AX
INL
RET
/*
* input a string of longs from a port
*/
TEXT insl(SB),$0
MOVL p+0(FP),DX
MOVL a+4(FP),DI
MOVL c+8(FP),CX
CLD; REP; INSL
RET
/*
* output a short to a port
*/
TEXT outs(SB), $0
MOVL p+0(FP), DX
MOVL s+4(FP), AX
OP16; OUTL
RET
/*
* output a string of shorts to a port
*/
TEXT outss(SB),$0
MOVL p+0(FP),DX
MOVL a+4(FP),SI
MOVL c+8(FP),CX
CLD; REP; OP16; OUTSL
RET
/*
* output a long to a port
*/
TEXT outl(SB), $0
MOVL p+0(FP), DX
MOVL s+4(FP), AX
OUTL
RET
/*
* output a string of longs to a port
*/
TEXT outsl(SB),$0
MOVL p+0(FP),DX
MOVL a+4(FP),SI
MOVL c+8(FP),CX
CLD; REP; OUTSL
RET
/*
* test and set
*/
TEXT tas(SB),$0
MOVL $0xdeadead,AX
MOVL l+0(FP),BX
XCHGL AX,(BX)
RET
TEXT sfence(SB), $0
BYTE $0x0f
BYTE $0xae
BYTE $0xf8
RET
TEXT lfence(SB), $0
BYTE $0x0f
BYTE $0xae
BYTE $0xe8
RET
TEXT mfence(SB), $0
BYTE $0x0f
BYTE $0xae
BYTE $0xf0
RET
TEXT mb386(SB), $0
POPL AX /* return PC */
PUSHFL
PUSHL CS
PUSHL AX
IRETL
TEXT mb586(SB), $0
XORL AX, AX
CPUID
RET
/*
* routines to load/read various system registers
*/
GLOBL idtptr(SB),$6
TEXT putidt(SB),$0 /* interrupt descriptor table */
MOVL t+0(FP),AX
MOVL AX,idtptr+2(SB)
MOVL l+4(FP),AX
MOVW AX,idtptr(SB)
MOVL idtptr(SB),IDTR
RET
GLOBL gdtptr(SB),$6
TEXT putgdt(SB),$0 /* global descriptor table */
MOVL t+0(FP),AX
MOVL AX,gdtptr+2(SB)
MOVL l+4(FP),AX
MOVW AX,gdtptr(SB)
MOVL gdtptr(SB),GDTR
RET
TEXT putcr3(SB),$0 /* top level page table pointer */
MOVL t+0(FP),AX
MOVL AX,CR3
RET
TEXT getcr3(SB),$0
MOVL CR3, AX
RET
TEXT getcr4(SB), $0 /* CR4 - extensions */
MOVL CR4, AX
RET
TEXT putcr4(SB), $0
MOVL cr4+0(FP), AX
MOVL AX, CR4
RET
TEXT puttr(SB),$0 /* task register */
MOVL t+0(FP),AX
MOVW AX,TASK
RET
TEXT getcr0(SB),$0 /* coprocessor bits */
MOVL CR0,AX
RET
TEXT getcr2(SB),$0 /* fault address */
MOVL CR2,AX
RET
/*
* special traps
*/
TEXT intr0(SB),$0
PUSHL $0
PUSHL $0
JMP intrcommon
TEXT intr1(SB),$0
PUSHL $0
PUSHL $1
JMP intrcommon
TEXT intr2(SB),$0
PUSHL $0
PUSHL $2
JMP intrcommon
TEXT intr3(SB),$0
PUSHL $0
PUSHL $3
JMP intrcommon
TEXT intr4(SB),$0
PUSHL $0
PUSHL $4
JMP intrcommon
TEXT intr5(SB),$0
PUSHL $0
PUSHL $5
JMP intrcommon
TEXT intr6(SB),$0
PUSHL $0
PUSHL $6
JMP intrcommon
TEXT intr7(SB),$0
PUSHL $0
PUSHL $7
JMP intrcommon
TEXT intr8(SB),$0
PUSHL $8
JMP intrscommon
TEXT intr9(SB),$0
PUSHL $0
PUSHL $9
JMP intrcommon
TEXT intr10(SB),$0
PUSHL $10
JMP intrscommon
TEXT intr11(SB),$0
PUSHL $11
JMP intrscommon
TEXT intr12(SB),$0
PUSHL $12
JMP intrscommon
TEXT intr13(SB),$0
PUSHL $13
JMP intrscommon
TEXT intr14(SB),$0
PUSHL $14
JMP intrscommon
TEXT intr15(SB),$0
PUSHL $0
PUSHL $15
JMP intrcommon
TEXT intr16(SB),$0
PUSHL $0
PUSHL $16
JMP intrcommon
TEXT intr24(SB),$0
PUSHL $0
PUSHL $24
JMP intrcommon
TEXT intr25(SB),$0
PUSHL $0
PUSHL $25
JMP intrcommon
TEXT intr26(SB),$0
PUSHL $0
PUSHL $26
JMP intrcommon
TEXT intr27(SB),$0
PUSHL $0
PUSHL $27
JMP intrcommon
TEXT intr28(SB),$0
PUSHL $0
PUSHL $28
JMP intrcommon
TEXT intr29(SB),$0
PUSHL $0
PUSHL $29
JMP intrcommon
TEXT intr30(SB),$0
PUSHL $0
PUSHL $30
JMP intrcommon
TEXT intr31(SB),$0
PUSHL $0
PUSHL $31
JMP intrcommon
TEXT intr32(SB),$0
PUSHL $0
PUSHL $32
JMP intrcommon
TEXT intr33(SB),$0
PUSHL $0
PUSHL $33
JMP intrcommon
TEXT intr34(SB),$0
PUSHL $0
PUSHL $34
JMP intrcommon
TEXT intr35(SB),$0
PUSHL $0
PUSHL $35
JMP intrcommon
TEXT intr36(SB),$0
PUSHL $0
PUSHL $36
JMP intrcommon
TEXT intr37(SB),$0
PUSHL $0
PUSHL $37
JMP intrcommon
TEXT intr38(SB),$0
PUSHL $0
PUSHL $38
JMP intrcommon
TEXT intr39(SB),$0
PUSHL $0
PUSHL $39
JMP intrcommon
TEXT intr64(SB),$0
PUSHL $0
PUSHL $64
JMP intrcommon
TEXT intrbad(SB),$0
PUSHL $0
PUSHL $0x1ff
JMP intrcommon
intrcommon:
PUSHL DS
PUSHL ES
PUSHL FS
PUSHL GS
PUSHAL
MOVL $(KDSEL),AX
MOVW AX,DS
MOVW AX,ES
LEAL 0(SP),AX
PUSHL AX
CALL trap(SB)
POPL AX
POPAL
NOP
POPL GS
POPL FS
POPL ES
POPL DS
NOP
ADDL $8,SP /* error code and trap type */
IRETL
intrscommon:
PUSHL DS
PUSHL ES
PUSHL FS
PUSHL GS
PUSHAL
MOVL $(KDSEL),AX
MOVW AX,DS
MOVW AX,ES
LEAL 0(SP),AX
PUSHL AX
CALL trap(SB)
POPL AX
POPAL
NOP
POPL GS
POPL FS
POPL ES
POPL DS
NOP
ADDL $8,SP /* error code and trap type */
IRETL
/*
* interrupt level is interrupts on or off
*/
TEXT spllo(SB),$0
PUSHFL
POPL AX
STI
RET
TEXT splhi(SB),$0
PUSHFL
POPL AX
CLI
RET
TEXT splx(SB),$0
MOVL s+0(FP),AX
PUSHL AX
POPFL
RET
TEXT getstatus(SB),$0
PUSHFL
POPL AX
RET
TEXT _cycles(SB), $0 /* time stamp counter; cycles since power up */
RDTSC
MOVL vlong+0(FP), CX /* &vlong */
MOVL AX, 0(CX) /* lo */
MOVL DX, 4(CX) /* hi */
RET
TEXT rdmsr(SB), $0 /* model-specific register */
MOVL index+0(FP), CX
RDMSR
MOVL vlong+4(FP), CX /* &vlong */
MOVL AX, (CX) /* lo */
MOVL DX, 4(CX) /* hi */
RET
TEXT wrmsr(SB), $0
MOVL index+0(FP), CX
MOVL lo+4(FP), AX
MOVL hi+8(FP), DX
WRMSR
RET
/*
* Try to determine the CPU type which requires fiddling with EFLAGS.
* If the Id bit can be toggled then the CPUID instruciton can be used
* to determine CPU identity and features. First have to check if it's
* 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(id[], &ax, &dx);
*/
TEXT cpuid(SB), $0
MOVL $0x240000, AX
PUSHL AX
POPFL /* set Id|Ac */
PUSHFL
POPL BX /* retrieve value */
MOVL $0, AX
PUSHL AX
POPFL /* clear Id|Ac, EFLAGS initialised */
PUSHFL
POPL AX /* retrieve value */
XORL BX, AX
TESTL $0x040000, AX /* Ac */
JZ _cpu386 /* can't set this bit on 386 */
TESTL $0x200000, AX /* Id */
JZ _cpu486 /* can't toggle this bit on some 486 */
MOVL $0, AX
CPUID
MOVL id+0(FP), BP
MOVL BX, 0(BP) /* "Genu" "Auth" "Cyri" */
MOVL DX, 4(BP) /* "ineI" "enti" "xIns" */
MOVL CX, 8(BP) /* "ntel" "cAMD" "tead" */
MOVL $1, AX
CPUID
JMP _cpuid
_cpu486:
MOVL $0x400, AX
MOVL $0, DX
JMP _cpuid
_cpu386:
MOVL $0x300, AX
MOVL $0, DX
_cpuid:
MOVL ax+4(FP), BP
MOVL AX, 0(BP)
MOVL dx+8(FP), BP
MOVL DX, 0(BP)
RET
/*
* basic timing loop to determine CPU frequency
*/
TEXT aamloop(SB),$0
MOVL c+0(FP),CX
aaml1:
AAM
LOOP aaml1
RET
/*
* do nothing whatsoever till interrupt happens
*/
TEXT idle(SB),$0
HLT
RET
/*
* label consists of a stack pointer and a PC
*/
TEXT gotolabel(SB),$0
MOVL l+0(FP),AX
MOVL 4(AX),SP /* restore sp */
MOVL 0(AX),AX /* put return pc on the stack */
MOVL AX,0(SP)
MOVL $1,AX /* return 1 */
RET
TEXT setlabel(SB),$0
MOVL l+0(FP),AX
MOVL SP,4(AX) /* store sp */
MOVL 0(SP),BX /* store return pc */
MOVL BX,0(AX)
MOVL $0,AX /* return 0 */
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
#define FPON\
MOVL CR0,AX;\
ANDL $~0x4,AX /* EM=0 */;\
MOVL AX,CR0
TEXT fpinit(SB),$0 /* turn on & init the floating point */
FPON
FINIT
WAIT
PUSHW $0x033E
FLDCW 0(SP) /* ignore underflow/precision, signal others */
POPW AX
WAIT
RET
TEXT famd+0(SB), $4
PUSHFL
CLI /* spl hi */
FMOVL b+4(FP), F0
FADDF a+0(FP), F0
FMOVL c+8(FP), F0
FMULDP F0, F1
FMOVL d+12(FP), F0
FDIVDP F0, F1
FMOVFP F0, .safe-4(SP)
MOVL .safe-4(SP), AX
POPFL /* splx */
RET
TEXT fdf+0(SB), $4
PUSHFL
CLI /* spl hi */
FMOVL b+4(FP), F0
FDIVRF a+0(FP), F0
FMOVLP F0, .safe-4(SP)
MOVL .safe-4(SP), AX
POPFL /* splx */
RET
|