; 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