/*
* Memory and machine-specific definitions.  Used in C and assembler.
*/

/*
* Sizes
*/
#define BI2BY           8                       /* bits per byte */
#define BI2WD           32                      /* bits per word */
#define BY2WD           4                       /* bytes per word */
#define BY2PG           4096                    /* bytes per page */
#define WD2PG           (BY2PG/BY2WD)           /* words per page */
#define PGSHIFT         12                      /* log(BY2PG) */
#define PGROUND(s)      (((s)+(BY2PG-1))&~(BY2PG-1))

#define MAXMACH         1                       /* max # cpus system can run */

/*
* Time
*/
#define HZ              (20)                    /* clock frequency */
#define MS2HZ           (1000/HZ)               /* millisec per clock tick */
#define TK2SEC(t)       ((t)/HZ)                /* ticks to seconds */
#define TK2MS(t)        ((((ulong)(t))*1000)/HZ)        /* ticks to milliseconds */
#define MS2TK(t)        ((((ulong)(t))*HZ)/1000)        /* milliseconds to ticks */

/*
* Fundamental addresses
*/

/*
*  Address spaces
*
*  User is at 0-2GB
*  Kernel is at 2GB-4GB
*
*  To avoid an extra page map, both the user stack (USTKTOP) and
*  the temporary user stack (TSTKTOP) should be in the the same
*  4 meg.
*/
#define UZERO           0                       /* base of user address space */
#define UTZERO          (UZERO+BY2PG)           /* first address in user text */
#define KZERO           0x80000000              /* base of kernel address space */
#define KTZERO          KZERO                   /* first address in kernel text */
#define USERADDR        0xC0000000              /* struct User */
#define UREGADDR        (USERADDR+BY2PG-4*19)
#define TSTKTOP         USERADDR                /* end of new stack in sysexec */
#define TSTKSIZ 10
#define USTKTOP         (TSTKTOP-TSTKSIZ*BY2PG) /* byte just beyond user stack */
#define USTKSIZE        (16*1024*1024 - TSTKSIZ*BY2PG)  /* size of user stack */
#define ROMBIOS         (KZERO|0xF0000)

#define MACHSIZE        4096

#define isphys(x) (((ulong)x)&KZERO)

/*
*  known 80386 segments (in GDT) and their selectors
*/
#define NULLSEG 0       /* null segment */
#define KDSEG   1       /* kernel data/stack */
#define KESEG   2       /* kernel executable */
#define UDSEG   3       /* user data/stack */
#define UESEG   4       /* user executable */
#define TSSSEG  5       /* task segment */

#define SELGDT  (0<<3)  /* selector is in gdt */
#define SELLDT  (1<<3)  /* selector is in ldt */

#define SELECTOR(i, t, p)       (((i)<<3) | (t) | (p))

#define NULLSEL SELECTOR(NULLSEG, SELGDT, 0)
#define KESEL   SELECTOR(KESEG, SELGDT, 0)
#define KDSEL   SELECTOR(KDSEG, SELGDT, 0)
#define UESEL   SELECTOR(UESEG, SELGDT, 3)
#define UDSEL   SELECTOR(UDSEG, SELGDT, 3)
#define TSSSEL  SELECTOR(TSSSEG, SELGDT, 0)

/*
*  fields in segment descriptors
*/
#define SEGDATA (0x10<<8)       /* data/stack segment */
#define SEGEXEC (0x18<<8)       /* executable segment */
#define SEGTSS  (0x9<<8)        /* TSS segment */
#define SEGCG   (0x0C<<8)       /* call gate */
#define SEGIG   (0x0E<<8)       /* interrupt gate */
#define SEGTG   (0x0F<<8)       /* task gate */
#define SEGTYPE (0x1F<<8)

#define SEGP    (1<<15)         /* segment present */
#define SEGPL(x) ((x)<<13)      /* priority level */
#define SEGB    (1<<22)         /* granularity 1==4k (for expand-down) */
#define SEGG    (1<<23)         /* granularity 1==4k (for other) */
#define SEGE    (1<<10)         /* expand down */
#define SEGW    (1<<9)          /* writable (for data/stack) */
#define SEGR    (1<<9)          /* readable (for code) */
#define SEGD    (1<<22)         /* default 1==32bit (for code) */

/*
*  virtual MMU
*/
#define PTEMAPMEM       (1024*1024)     /* ??? */
#define SEGMAPSIZE      16              /* ??? */
#define PTEPERTAB       (PTEMAPMEM/BY2PG)       /* ??? */
#define PPN(x)          ((x)&~(BY2PG-1))

/*
*  physical MMU
*/
#define PTEVALID        (1<<0)
#define PTEUNCACHED     0               /* everything is uncached */
#define PTEWRITE        (1<<1)
#define PTERONLY        (0<<1)
#define PTEKERNEL       (0<<2)
#define PTEUSER         (1<<2)

/*
*  flag register bits that we care about
*/
#define IFLAG   0x200

#define OP16    BYTE    $0x66

/*
*      about to walk all over ms/dos - turn off interrupts
*/
TEXT    origin(SB),$0

       CLI

#ifdef BOOT
/*
*      This part of l.s is used only in the boot kernel.
*      It assumes that we are in real address mode, i.e.,
*      that we look like an 8086.
*/
/*
*      relocate everything to a half meg and jump there
*      - looks wierd because it is being assembled by a 32 bit
*        assembler for a 16 bit world
*/
       MOVL    $0,BX
       INCL    BX
       SHLL    $15,BX
       MOVL    BX,CX
       MOVW    BX,ES
       MOVL    $0,SI
       MOVL    SI,DI
       CLD; REP; MOVSL
/*      JMPFAR  0X8000:$lowcore(SB) /**/
        BYTE   $0xEA
        WORD   $lowcore(SB)
        WORD   $0X8000

TEXT    lowcore(SB),$0

/*
*      now that we're in low core, update the DS
*/

       MOVW    BX,DS

/*
*      goto protected mode
*/
/*      MOVL    tgdtptr(SB),GDTR /**/
        BYTE   $0x0f
        BYTE   $0x01
        BYTE   $0x16
        WORD   $tgdtptr(SB)
       MOVL    CR0,AX
       ORL     $1,AX
       MOVL    AX,CR0

/*
*      clear prefetch queue (wierd code to avoid optimizations)
*/
       CLC
       JCC     flush
       MOVL    AX,AX
flush:

/*
*      set all segs
*/
/*      MOVW    $SELECTOR(1, SELGDT, 0),AX      /**/
        BYTE   $0xc7
        BYTE   $0xc0
        WORD   $SELECTOR(1, SELGDT, 0)
       MOVW    AX,DS
       MOVW    AX,SS
       MOVW    AX,ES
       MOVW    AX,FS
       MOVW    AX,GS

/*      JMPFAR  SELECTOR(2, SELGDT, 0):$mode32bit(SB) /**/
        BYTE   $0x66
        BYTE   $0xEA
        LONG   $mode32bit-KZERO(SB)
        WORD   $SELECTOR(2, SELGDT, 0)

TEXT    mode32bit(SB),$0

#endif BOOT

       /*
        * 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
        *  16 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    $(4*1024),CX            /* pte's per page */
       MOVL    $((((4*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
        *  16 meg of memory to 0 thru 16meg and to KZERO thru KZERO+16meg
        */
       MOVL    AX,BX
       ADDL    $(4*BY2PG),AX
       ADDL    $(PTEVALID|PTEKERNEL|PTEWRITE),BX
       MOVL    BX,0(AX)
       MOVL    BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+0)(AX)
       ADDL    $BY2PG,BX
       MOVL    BX,4(AX)
       MOVL    BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+4)(AX)
       ADDL    $BY2PG,BX
       MOVL    BX,8(AX)
       MOVL    BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+8)(AX)
       ADDL    $BY2PG,BX
       MOVL    BX,12(AX)
       MOVL    BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+12)(AX)

       /*
        *  point processor to top level page & turn on paging
        */
       MOVL    AX,CR3
       MOVL    CR0,AX
       ORL     $0X80000000,AX
       ANDL    $~(0x8|0x2),AX  /* TS=0, MP=0 */
       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*6)

/*
*  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

/*
*  output a byte
*/
TEXT    outb(SB),$0

       MOVL    p+0(FP),DX
       MOVL    b+4(FP),AX
       OUTB
       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

/*
*  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

/*
*  test and set
*/
TEXT    tas(SB),$0
       MOVL    $0xdeadead,AX
       MOVL    l+0(FP),BX
       XCHGL   AX,(BX)
       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    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

#define FPOFF\
       WAIT;\
       MOVL    CR0,AX;\
       ORL     $0x4,AX         /* EM=1 */;\
       MOVL    AX,CR0

#define FPON\
       MOVL    CR0,AX;\
       ANDL    $~0x4,AX        /* EM=0 */;\
       MOVL    AX,CR0

TEXT    fpoff(SB),$0            /* turn off floating point */
       FPOFF
       RET

TEXT    fpinit(SB),$0           /* turn on & init the floating point */
       FPON
       FINIT
       WAIT
       PUSHW   $0x0330
       FLDCW   0(SP)           /* ignore underflow/precision, signal others */
       POPW    AX
       WAIT
       RET

TEXT    fpsave(SB),$0           /* save floating point state and turn off */
       MOVL    p+0(FP),AX
       WAIT
       FSAVE   0(AX)
       FPOFF
       RET

TEXT    fprestore(SB),$0        /* turn on floating point and restore regs */
       FPON
       MOVL    p+0(FP),AX
       FRSTOR  0(AX)
       WAIT
       RET

TEXT    fpstatus(SB),$0         /* get floating point status */
       FSTSW   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   $16
       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
       POPL    GS
       POPL    FS
       POPL    ES
       POPL    DS
       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
       POPL    GS
       POPL    FS
       POPL    ES
       POPL    DS
       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

/*
*  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    0(AX),SP        /* restore sp */
       MOVL    4(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,0(AX)        /* store sp */
       MOVL    0(SP),BX        /* store return pc */
       MOVL    BX,4(AX)
       MOVL    $0,AX           /* return 0 */
       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 */
       PUSHL   $(USTKTOP)              /* old sp */
       PUSHFL                          /* 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

/*
*  set configuration register
*/
TEXT    config(SB),$0
       MOVL    l+0(FP),AX
       MOVL    $0x3F3,DX
       OUTB
       OUTB
       RET