; TODO finish converting this to a text file that looks like the PDF...

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; ASSUMPTIONS:
;
; 1. The bottom 64K of memory is ram, and can be used for
; scratch space by this module.
;
; 2. The system has sufficient free usable ram to copy the
; initial GDT, IDT, and TSS
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; configuration data - must match with build definition

CS_BASE EQU 0FFFF0000H
; CS_BASE is the linear address of the segment STARTUP_CODE
; - this is specified in the build language file

RAM_START EQU 400H
; RAM_START is the start of free, usable ram in the linear
; memory space. The GDT, IDT, and initial TSS will be
; copied above this space, and a small data segment will be
; discarded at this linear address. The 32-bit word at
; RAM_START will contain the linear address of the first
; free byte above the copied tables - this may be useful if
; a memory manager is used.

TSS_INDEX EQU 10
; TSS_INDEX is the index of the TSS of the first task to
; run after startup

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; ------------------------- STRUCTURES and EQU ---------------
; structures for system data

; TSS structure
TASK_STATE STRUC
    link DW ?
    link_h DW ?
    ESP0 DD ?
    SS0 DW ?
    SS0_h DW ?
    ESP1 DD ?
    SS1 DW ?
    SS1_h DW ?
    ESP2 DD ?
    SS2 DW ?
    SS2_h DW ?
    CR3_reg DD ?
    EIP_reg DD ?
    EFLAGS_regDD ?
    EAX_reg DD ?
    ECX_reg DD ?
    EDX_reg DD ?
    EBX_reg DD ?
    ESP_reg DD ?
    EBP_reg DD ?
    ESI_reg DD ?
    EDI_reg DD ?
    ES_reg DW ?
    ES_h DW ?
    CS_reg DW ?
    CS_h DW ?
    SS_reg DW ?
    SS_h DW ?
    DS_reg DW ?
    DS_h DW ?
    FS_reg DW ?
    FS_h DW ?
    GS_reg DW ?
    GS_h DW ?
    LDT_reg DW ?
    LDT_h DW ?
    TRAP_reg DW ?
    IO_map_baseDW ?
TASK_STATE ENDS

; basic structure of a descriptor
DESC STRUC
    lim_0_15 DW ?
    bas_0_15 DW ?
    bas_16_23 DB ?
    access DB ?
    gran DB ?
    bas_24_31 DB ?
DESC ENDS

; structure for use with LGDT and LIDT instructions
TABLE_REG STRUC
table_lim DW ?
table_linearDD ?
TABLE_REG
ENDS
; offset of GDT and IDT descriptors in builder generated GDT
GDT_DESC_OFF
EQU 1*SIZE(DESC)
IDT_DESC_OFF
EQU 2*SIZE(DESC)
; equates for building temporary GDT in RAM
LINEAR_SEL
EQU
1*SIZE (DESC)
LINEAR_PROTO_LO
EQU
00000FFFFH ; LINEAR_ALIAS
LINEAR_PROTO_HI
EQU
000CF9200H
; Protection Enable Bit in CR0
PE_BIT EQU 1B
; ------------------------------------------------------------
; ------------------------- DATA SEGMENT----------------------
; Initially, this data segment starts at linear 0, according
; to the processor’s power-up state.
STARTUP_DATA
SEGMENT RW
free_mem_linear_base
LABEL
DWORD
TEMP_GDT
LABEL
BYTE ; must be first in segment
TEMP_GDT_NULL_DESC
DESC
<>
TEMP_GDT_LINEAR_DESC DESC
<>
; scratch areas for LGDT and
LIDT instructions
TEMP_GDT_SCRATCH TABLE_REG
<>
APP_GDT_RAM
TABLE_REG
<>
APP_IDT_RAM
TABLE_REG
<>
; align end_data
fill
DW
?
; last thing in this segment - should be on a dword boundary
end_data
LABEL
BYTE
STARTUP_DATA
ENDS
; ------------------------------------------------------------
; ------------------------- CODE SEGMENT----------------------
STARTUP_CODE SEGMENT ER PUBLIC USE16
; filled in by builder
PUBLIC GDT_EPROM
GDT_EPROM
TABLE_REG
<>
; filled in by builder
PUBLIC IDT_EPROM
IDT_EPROM
TABLE_REG
<>
; entry point into startup code - the bootstrap will vector
; here with a near JMP generated by the builder.
This
; label must be in the top 64K of linear memory.
PUBLIC
STARTUP
STARTUP:
; DS,ES address the bottom 64K of flat linear memory
ASSUME DS:STARTUP_DATA, ES:STARTUP_DATA
; See Figure 9-4
; load GDTR with temporary GDT
LEA
EBX,TEMP_GDT ; build the TEMP_GDT in low ram,
MOV
DWORD PTR [EBX],0
; where we can address
MOV
DWORD PTR [EBX]+4,0
MOV
DWORD PTR [EBX]+8, LINEAR_PROTO_LO
MOV
DWORD PTR [EBX]+12, LINEAR_PROTO_HI
MOV
TEMP_GDT_scratch.table_linear,EBX
MOV
TEMP_GDT_scratch.table_lim,15
DB 66H; execute a 32 bit LGDT
LGDT
TEMP_GDT_scratch
; enter protected mode
MOV
EBX,CR0
OR
EBX,PE_BIT
MOV
CR0,EBX
; clear prefetch queue
JMP
CLEAR_LABEL
CLEAR_LABEL:
; make DS and ES address 4G of linear memory
MOV
CX,LINEAR_SEL
MOV
DS,CX
MOV
ES,CX
; do board specific initialization
;
;
; ......
;
; See Figure 9-5
; copy EPROM GDT to ram at:
;
RAM_START + size (STARTUP_DATA)
MOV
EAX,RAM_START
ADD
EAX,OFFSET (end_data)
MOV
EBX,RAM_START
MOV
ECX, CS_BASE
ADD
ECX, OFFSET (GDT_EPROM)
MOV
ESI, [ECX].table_linear
MOV
EDI,EAX
MOVZX
ECX, [ECX].table_lim
MOV
APP_GDT_ram[EBX].table_lim,CX
INC
ECX
MOV
EDX,EAX
MOV
APP_GDT_ram[EBX].table_linear,EAX
ADD
EAX,ECX
REP MOVS
BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
; fixup
GDT base in descriptor
MOV
ECX,EDX
MOV
[EDX].bas_0_15+GDT_DESC_OFF,CX
ROR
ECX,16

; PAGE 4 TODO remove later.

MOV
[EDX].bas_16_23+GDT_DESC_OFF,CL
[EDX].bas_24_31+GDT_DESC_OFF,CH
; copy EPROM IDT to ram at:
; RAM_START+size(STARTUP_DATA)+SIZE (EPROM GDT)
MOV
 ECX, CS_BASE
ADD
 ECX, OFFSET (IDT_EPROM)
MOV
 ESI, [ECX].table_linear
MOV
 EDI,EAX
MOVZX
 ECX, [ECX].table_lim
MOV
 APP_IDT_ram[EBX].table_lim,CX
INC
 ECX
MOV
 APP_IDT_ram[EBX].table_linear,EAX
MOV
 EBX,EAX
ADD
 EAX,ECX
REP MOVS
 BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
MOV
ROR
MOV
MOV
MOV
LGDT
LIDT
REPMOV
MOV
MOV
MOV
MOV
MOV
ROL
MOV
MOV
LSL
INC
MOV
ADD
MOVS
MOV
ROL
MOV
MOV
ROL
;save start
MOV
; fixup IDT pointer in GDT
[EDX].bas_0_15+IDT_DESC_OFF,BX
EBX,16
[EDX].bas_16_23+IDT_DESC_OFF,BL
[EDX].bas_24_31+IDT_DESC_OFF,BH
; load GDTR and IDTR
EBX,RAM_START
DB
 66H
 ; execute a 32 bit LGDT
APP_GDT_ram[EBX]
DB
 66H
 ; execute a 32 bit LIDT
APP_IDT_ram[EBX]
; move the TSS
EDI,EAX
EBX,TSS_INDEX*SIZE(DESC)
ECX,GDT_DESC_OFF ;build linear address for TSS
GS,CX
DH,GS:[EBX].bas_24_31
DL,GS:[EBX].bas_16_23
EDX,16
DX,GS:[EBX].bas_0_15
ESI,EDX
ECX,EBX
ECX
EDX,EAX
EAX,ECX
BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
; fixup TSS pointer
GS:[EBX].bas_0_15,DX
EDX,16
GS:[EBX].bas_24_31,DH
GS:[EBX].bas_16_23,DL
EDX,16
of free ram at linear location RAMSTART
free_mem_linear_base+RAM_START,EAX


;assume no LDT used in the initial task - if necessary,
;code to move the LDT could be added, and should resemble
;that used to move the TSS
; load task register
LTR
BX
; No task switch, only descriptor loading
; See Figure 9-6
; load minimal set of registers necessary to simulate task
; switch
MOV
AX,[EDX].SS_reg
; start loading registers
MOV
EDI,[EDX].ESP_reg
MOV
SS,AX
MOV
ESP,EDI
; stack now valid
PUSH
DWORD PTR [EDX].EFLAGS_reg
PUSH
DWORD PTR [EDX].CS_reg
PUSH
DWORD PTR [EDX].EIP_reg
MOV
AX,[EDX].DS_reg
MOV
BX,[EDX].ES_reg
MOV
DS,AX
; DS and ES no longer linear memory
MOV
ES,BX
; simulate far jump to initial task
IRETD
STARTUP_CODE ENDS
END STARTUP, DS:STARTUP_DATA, SS:STARTUP_DATA

