Pmsetup.inc
[ Return to Browse Source Page ]
; Pmsetup.inc:
;  Procedures for setting up protected mode.

build_idt:
push IDT_DSC
pop es
; first create a table of default interrupt entries
xor di,di
mov esi,(offset interrupt_table + 0A000h)
mov eax,(OS_Code*65536)
mov ax,[esi]
add esi,2
; Segment high, Offset low. Stores to dw offset,segment
mov cx,256*2
rep stosd
mov di,4
; eax = (offset 31...16) (flags) (0)
mov ax,[esi]
add esi,2
shl eax,16
mov ax,(10001110b*256)
; this is a register renaming nightmare, but it only executes once
mov cx,256
build_idt_loop1:
stosd
lea di,[di+4]
loop build_idt_loop1

xor di,di
mov cx,17
build_idt_loop2:
;0: low word = low offset
;4: hi word = hi offset
;in memory:
;0: lo ofset ??
;4: ??       hi offset
mov ax,[esi]
lea esi,[esi+2]
stosw
lea di,[di+2*2]
mov ax,[esi]
lea esi,[esi+2]
stosw
loop build_idt_loop2

mov bx,[esi]
lea esi,[esi+2]
mov ax,[esi]
lea esi,[esi+2]
mov cx,15
build_idt_loop3: ; the latter 16 faults are all reserved, and are all
mov es:[di],bx      ;  handled by the same proc.
lea di,[di+3*2]
stosw
dec cx
jnz build_idt_loop3

build_idt_read_table:
xor ax,ax
mov al,[esi]
mov di,ax
test ax,ax
jz build_idt_leave
inc esi
shl di,3
mov ax,[esi]
lea esi,[esi+2]
stosw
lea di,[di+2*2]
mov ax,[esi]
lea esi,[esi+2]
stosw
jmp build_idt_read_table

build_idt_leave:
ret


build_gdt:
mov ecx,070000h + (offset os_data_sz) + 15
;mov eax,(offset os_code_sz)
;mov ebx,(offset os_data_sz)
and cl,0F0h
;mov [os_code_limit],ax
mov [os_codestartshere],ecx
;mov [os_data_limit],bx
mov [os_code_offset],cx
shr ecx,8
;shr ebx,8
mov [os_code_midoffset],ch
;shr eax,8
;mov [os_data_hilimit],bh
;or ah,01000000b
;mov [os_code_hilimit],ah

mov ax,0100h ; 1000h = GDT Location
mov es,ax
xor di,di
;ds should already be set up to cs
mov si,offset gdt_data
mov cx,(GDT_DATA_LEN/4)
rep movsd

mov cx,(((1024*32)-GDT_DATA_LEN)/4)
xor eax,eax
rep stosd

; just zero the rest of the table. as long as the P bit is 0 it doesn't
;  really matter too much.
ret

gdt_data:
; invalid selector
dw (4096*8)-1
dd 01000h
db "Ed"

FLAT_DATA equ 8
; flat_data
dw 0FFFFh,0
db 0,010010010b,010001111b,0

OS_CODE equ (FLAT_DATA + 8)
; os_code -- (end of os_data) -> 8FFFFh
os_code_limit dw 0FFFFh;!0; will be patched
os_code_offset dw 0 ; offset lowoffset - this will be patched.
os_code_midoffset db 0h ; midoffset - this too will be patched
db 010011010b
os_code_hilimit db 01001111b;!01000000b ; 01001000b will be patched
db 0 ; highoffset

PDA equ (OS_CODE+8)
; os_data -- 500h->5FFh
dw 05FFh,0500h
db 0,010010010b,0,0

OS_DATA equ (PDA+8)
os_data_limit dw 0FFFFh;!0 ; limit. will be patched
dw 0 ; offset
db 07h,010010010b
os_data_hilimit db 00001111b;!00000000b ; contains limit, will be patched.
db 0

IDT_DSC equ (OS_DATA+8)
; IDT -- 800h->9FFh
dw 09FFh,0800h
db 0,10010010b,0,0

MALLOC_BFR equ (IDT_DSC+8)
; mem_buffer
dw 0AFFFh,0A000h
db 0,010010010b,0,0

OS_VRAM equ (MALLOC_BFR+8)
; os_vram - 0B8000h
dw ((80*25*2)-1),08000h
db 0Bh,010010010b,00000000b,0

OS_STACK equ (OS_VRAM + 8)
; stack for os when no task is loaded
dw (0C000h-1),0B000h
db 0,10010010b,0,0

BDA equ (OS_STACK + 8)
dw 4FFh,400h
db 0,11110000b,0,0

GDT_DSC equ (BDA + 8)
dw 9000h ; gdt_len
dw 1000h ; offset
db 0,10010010b,00000000b,0

GDT_DATA_LEN equ ($-gdt_data)


reloc_pic:
mov al,00010001b ; LTIM = 0 - edge triggering, SNGL = 0 - Cascaded
                ; IC4 = 1 - IC4 required
out 020h,al ; Begin Parent PIC Initialization
out 0A0h,al ; Begin Child PIC Initialization
mov dx,21h
mov al,020h ; Parent ICW2 = 20h: IRQ0 -> 20h
out dx,al
mov al,028h ; Child ICW2 = 28h: IRQ8 -> 28h
out 0A1h,al
mov al,0100b ; Parent ICW3 - Child PIC connected to IRQ2 (0100b = 1 << 2)
out dx,al
mov al,2 ; Child ICW3 - Child PIC ID (2)
out 0A1h,al
mov al,1 ; uPM = 1: Operate in 80x86 mode. AEOI=0: No automatic EOI
         ; M/S = 0: (ignored). BUF = 0: Non-buffered mode.
         ; SFNM = 0: No special fully nested mode.
; mask all ints via PIC.
; i'm leaving irq2 (cascade for PIC2) open so that doesn't come back
;  to haunt me when i try to write drivers for hardware >= Irq 8.
out dx,al
mov al,011111011b
out dx,al
or al,0100b
out 0A1h,al
; Note:
;  LittleOS writes 02h to ports 020h and 0A0h at this point. Why?
ret


enable_a20:
mov dx,064h
mov cx,offset a20_cmndwait
call cx ; unneeded?
mov al,0ADh ; Disable Keyboard
out dx,al
call cx
mov al,0D0h ; Read 8042 Output Port
out dx,al
a20_inputwait:
in al,dx
test al,1 ; waits until bit 1 (data ready) of port 64h is set.
jz a20_inputwait

in al,060h
or al,00000010b
mov bl,al
;call cx
mov al,0D1h ; Write 8042 Output Port
out dx,al
call cx
mov al,bl
out 60h,al
call cx
mov al,0AEh ; Enable Keyboard
out dx,al
;call cx    ;Call (a20_cmdwait) would be equivalent to just letting the
;ret        ; program execution roll of into the proc. i saved ~3 bytes.

push ds
xor ax,ax
mov es,ax
mov di,ax
mov ax,0FFFFh
mov ds,ax
mov si,010h
mov bx,es:[di]
mov bp,bx
a20_wait_until_enabled:
not bx
mov [si],bx
mov ax,es:[di]
xor ax,bx
jz a20_wait_until_enabled
mov [si],bp ; restore IVT entry (for v86 mode?)
pop ax
mov es,ax
mov ds,ax

a20_cmndwait:
in al,dx
test al,2 ; waits until bit 2 (input data) of port 64h is clear.
jnz a20_cmndwait ; when this is clear, the command has been processed
ret

os_codestartshere dd 0h


Download this file.


[ Return to Browse Source Page ]
Copyright 2000, Ed Pizzi