; protected mode startup for XMS and RAW modes
; copyright Rossi Gianluca [ranger@racine.ra.it]
; V0.6 sept 07 1997
;
; FIXME: cr4 may be != 0 after pmode switch
;
;
BITS 16
SEGMENT CONST
EXTERN map_memory_and_getcr3 ; function
EXTERN cmdl_pages ; word
EXTERN cmdl_debug ; byte
EXTERN cmdl_text ; byte
EXTERN cmdl_fname ; string
EXTERN cmdl_kernel ; string
EXTERN _dos_mem
EXTERN driver_code ; word
EXTERN kernel_buffer
EXTERN prefixseg
; temp tss buffer
TSS times 103 db 0
ss_sp dd 0
; xms driver entry point
xms_drv
xms_o dw 0
xms_s dw 0
; XMS block address
mem_addr
mem_lo dw 0
mem_hi dw 0
; XMS handle
handle dw 0
; 4K align offset for mem_addr
mem_ofs4k dd 0
; loaded program entry point far ptr
far_jmp_ptr
far_jmp_eip dd 0
far_jmp_cs dw 40h
; IDT
idt_limit dw 0
idt_addr dd 0
; GDT
gdt_limit dw (10*8)-1
gdt_addr dd 0
;-- table
gdt_0 dd 0 ; NULL
dd 0
gdt_8 dd 0 ; reserved for VCPI
dd 0
gdt_10 dd 0 ; reserved for VCPI
dd 0
gdt_18 dd 0 ; reserved for VCPI
dd 0
; code 16 bit
gdt_20 dw 0xffff
dw 0
db 0
db 9ah
dw 0
; data 16 bit
gdt_28 dw 0xffff
dw 0
db 0
db 92h
dw 0
; stub_stat (point to kernel_buffer)
gdt_30 dw 255
dw 0
db 0
db 92h
db 0
db 0
; kdata 32 (4G,W+,B+)
gdt_38 dw 0xffff
dw 0
db 0
db 92h
db 0xcf
db 0
; kcode 32 (4G,R+,D+)
gdt_40 dw 0xffff
dw 0
db 0
db 9ah
db 0xcf
db 0
; temp TSS
gdt_48 dw 103
dw 0
db 0
db 89h
db 0
db 0
SEGMENT CODE
;
; check for XMS
;
global XMS_check
XMS_check:
push es
xor eax,eax
mov es,ax
cmp dword [es:2fh*4],eax
jz .ret_false
mov ah,43h
int 2fh
cmp al,80h
jnz .ret_false
mov ax,4310h
int 2fh
mov [xms_s],es
mov [xms_o],bx
smsw ax
and ax,1
setz al
jmp .ret
.ret_false:
xor ax,ax
.ret
pop es
ret
;
; initialize XMS
;
global XMS_init
XMS_init:
; enable A20
mov ah,3
call far [xms_drv]
dec ax
jnz .err
cmp word [cmdl_pages],0
jnz .go
; alloc all free XMS memory
mov ah,8h
call far [xms_drv]
test bl,80h
jnz .err
shr ax,2
sub ax,2
mov [cmdl_pages],ax
.go
; alloc memory
mov ah,9h
mov dx,[cmdl_pages]
inc dx
shl dx,2
call far [xms_drv]
dec ax
jnz .err
mov word [handle],dx
; lock
mov ah,0ch
call far [xms_drv]
dec ax
jnz .err
mov word [mem_lo],bx
mov word [mem_hi],dx
mov eax,[mem_addr]
add eax,0xfff
and eax,0xfffff000
sub eax,[mem_addr]
mov [mem_ofs4k],eax
xor ax,ax
inc ax
ret
.err:
mov bh,0
mov word [driver_code],bx
xor ax,ax
ret
;
; free XMS resources
;
global XMS_clean
XMS_clean:
mov dx,word [handle]
test dx,dx
jz .nofree
; unlock & free
mov ah,0dh
call far [xms_drv]
mov ah,0ah
call far [xms_drv]
.nofree:
mov ah,04h
call far [xms_drv]
retf
global XMS_move
;
; dword [bp+12] = vaddr (dest)
; dword [bp+8] = from
; word [bp+6] = size
; struct [bp-16] (XMS struct)
; dw[bp-16] = count
; w [bp-12] = sh
; dw[bp-10] = soff
; w [bp-6] = dh
; dw[bp-4] = doff
XMS_move:
push bp
mov bp,sp
sub sp,16
mov eax,[bp+12] ; vaddr
add eax,[mem_ofs4k] ; 4k alignement
mov [bp-4],eax
mov ax,[handle]
mov [bp-6],ax ; dest handle
mov eax,[bp+8]
mov [bp-10],eax ; from
mov word [bp-12],0 ; source handle (0 = base)
mov ax,word [bp+6] ; size
add ax,1
and al,0feh
movzx eax,ax
mov dword [bp-16],eax
mov si,sp
push ds
pop es
push ss
pop ds
mov ah,0bh
call far [es:xms_drv]
push es
pop ds
dec ax
jnz .err
mov ax,1
jmp .ret
.err:
xor ax,ax
xor bh,bh
mov [driver_code],bx
.ret
add sp,16
pop bp
retf 10
%macro SET_BASE 1
mov [%1+2],ax
shr eax,16
mov [%1+4],al
mov [%1+7],ah
%endm
global RAW_switch
global XMS_switch
XMS_switch:
RAW_switch:
movzx esp,sp
mov eax,[esp+4] ; eip
mov [far_jmp_eip],eax
push bp
mov [ss_sp],sp
mov [ss_sp+2],ss
; set descriptors base
mov ax,cs
movzx eax,ax
shl eax,4
SET_BASE gdt_20
mov ax,ds
shl eax,4
mov [gdt_addr],eax
SET_BASE gdt_28
mov ax,TSS
add eax,[gdt_addr]
SET_BASE gdt_48
mov ax,kernel_buffer
add eax,[gdt_addr]
SET_BASE gdt_30
mov ax,gdt_0 ; 16 bit linkers dont like _
add [gdt_addr],eax ; _ add dword [*],gdt_0
mov eax,[mem_addr]
add eax,[mem_ofs4k]
mov [kernel_buffer + 4], eax
push eax
call map_memory_and_getcr3 ; memory mapping
movzx eax,ax
shl eax,4
mov cr3,eax ; cr3 in now ignored
; disable all flags (especially IF)
push dword 0
popfd
; now make ss == ds
mov ax,ss
movzx eax,ax
shl eax,4
movzx esp,sp
add esp,eax
;-- start pmode
lidt [idt_limit]
lgdt [gdt_limit]
mov eax,1
mov cr0,eax
jmp word 20h:.load_pmcs
.load_pmcs
mov ax,28h
mov gs,ax ; gs=data
mov ax,30h
mov fs,ax ; fs=stub
mov ax,38h
mov ss,ax
mov ds,ax ; DS&ES&SS CHANGED !!! BASE 0
mov es,ax
mov ax,48h
ltr ax
xor ax,ax
lldt ax
mov eax,80000001h
mov cr0,eax ; enable paging, cr3 already loaded
jmp .flush_tlb
.flush_tlb
and esp,0xFFFFFFF8 ; 8 byte stack align
call far dword [gs:far_jmp_ptr]
mov bx,ax
mov eax,1
mov cr0,eax
jmp .flush_tlb2
.flush_tlb2
xor eax,eax
mov dr6,eax
mov dr7,eax
mov cr3,eax
mov cr2,eax
mov ax,28h
mov ds,ax
mov es,ax
mov gs,ax
mov fs,ax
mov ss,ax
mov word [idt_limit], 1023
mov dword [idt_addr], 0
lidt [idt_limit]
xor eax,eax
mov cr0,eax
jmp far .load_rmcs
.load_rmcs
mov ax,SEG idt_limit ; carica DS
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax
lss sp,[ss_sp]
movzx esp,sp
movzx ebp,bp
sti
mov ax,bx
pop bp
ret 4
; ofs 0: 'V0'
; 2: header size
; 4: kernel base
; 8: # pages
; 10: cmdl_kernel
; 74: flags [0:debug,1:text]
global kernel_buf_setup
kernel_buf_setup:
push ds
pop es
mov di,kernel_buffer
xor ax,ax
mov cx,128
rep stosw
; set header
mov word [kernel_buffer],'V0'
mov word [kernel_buffer+2],252 ; 256 - 2 word
; # pages
mov ax,[cmdl_pages]
mov [kernel_buffer+8],ax
; set cmdl_kernel field
mov di,kernel_buffer+10
mov si,cmdl_kernel+1
mov cl,[si-1]
mov ch,0
rep movsb
; set flags field
mov si,kernel_buffer+74
xor ax,ax
mov bx,ax
mov [si],ax
cmp [cmdl_debug],ax
setne bl
or [si],bx
cmp [cmdl_text],ax
setne bl
shl bl,1
or [si],bx
mov ax,[prefixseg]
mov [si+2],ax
mov eax,[_dos_mem]
mov [si+4],eax
ret