[LinksOS CVS Commit]linksos/boot/x86 strap.asm,NONE,1.1
Status: Inactive
Brought to you by:
terencevs
|
From: <ke...@to...> - 2003-01-03 20:35:40
|
Update of /cvsroot/linksos/linksos/boot/x86 In directory router-internal.tossell.net:/tmp/cvs-serv17143 Added Files: strap.asm Log Message: Title: strap.asm Changes: added bootstrap code to this directory (from main/) Effects: Portability dude a=kennyt --- NEW FILE: strap.asm --- ;----------------------------------------------------------------------------- ; filename: strap.asm ; creation date: unknown ; author: Charles Banas ; Edited by Kye Lewis (kye...@us...) ; version: 0.02 ;----------------------------------------------------------------------------- ; revision history: ; 12/22/2002 - 1136 MST - Charles Banas ; prepared for CVS commit. added comments. ; 20021229 - 0738GMT - Kye Lewis (kye...@us...) ; Changed so the file links and compiles on NASM correctly ; Changed BITS 16 to BITS 32, and fixed 3 other lines. ;----------------------------------------------------------------------------- ; description: ; this file provides the ability for the kernel to boot with a ; minimal bootloader that does not provide A20 or p-mode support. ;----------------------------------------------------------------------------- ;[BITS 16] [BITS 32] [SECTION .text] [GLOBAL _start] ; this part is meant for compatibility with the standard BeFS bootloader. ; the BeFS bootloader loads the kernel image at 1000h:0000h and jumps to ; 1000h:0200h. the DOS-compatible bootloader i use jumps to 1000h:0000h. jmp _start times (0x1fd) nop ;---------------------------- ; _start function ;---------------------------- ; default symbol name used by the linker _start: mov ax,0x1000 mov ds,ax mov es,ax mov fs,ax mov gs,ax cli mov ax,0x9000 mov ss,ax mov sp,ax sti mov si,[booting] call _disp_str call _set_a20 ; call _check_a20 jnc a20_good ; alternately, using the _check_a20 code, jz must be used. call _a20_dump a20_good: call _check_mem xor ebx,ebx mov bx,cs shl ebx,4 mov eax,ebx lea eax,[ebx] ; jmp $ mov [gdt2 + 2],ax ; set descriptor base address=EAX mov [gdt3 + 2],ax shr eax,16 mov [gdt2 + 4],al mov [gdt3 + 4],al mov [gdt2 + 7],ah mov [gdt3 + 7],ah lea eax,[ebx + gdt] ; point gdt_ptr to the gdt mov [gdt_ptr + 2],eax ; EAX=linear address of gdt push dword 0 ; zero EFLAGS (interrupts off, popfd ; IOPL=0, NT bit=0) lgdt [gdt_ptr] mov eax,cr0 or al,1 mov cr0,eax mov si,[pmodeswitch] call _disp_str jmp SYS_CODE_SEL:do_pm ;---------------------------- ; _a20_dump function ;---------------------------- ; dumps because a20 is not set _a20_dump: mov si,[a20fail] call _disp_str ; xor ax,ax ; int 0x16 ; int 0x19 ret ; for now. it's a pain to test on Bochs when a20 never enables. ; besides, using a BIOS function works on all tested machines. ;---------------------------- ; _disp_str function ;---------------------------- ; input: ; ds:si location of string to print ; clobbers: ; ax, bx ;---------------------------- ; default "print string" function for use before pmode _disp_str: lodsb or al,al jz done_str mov ah,0x0E ; mov bx,0x7 db 0xBB, 0x07, 0x00 ; why not "mov bx, 0x7" you ask? try it for yourself using int 0x10 ; NASM 0.98.35. then disassemble. then look. closely. jmp _disp_str done_str: ret ;---------------------------- ; _set_a20 function ;---------------------------- ; sets the a20 line to make all memory available ; right now, ONLY BIOS code is used. should this start failing, i will rewrite ; the code to try alternate methods. *DOES NOT WORK ON BOCHS.* in fact, none of ; this code does. but, the BIOS code works on most tested systems, so i have ; rather high hopes. ; ignore the messiness. _set_a20: ; push si ; push ax mov ax,2401h int 15h ; jnc saf3 ; in al,92h ; or ah,ah ; jne saf1 ; BIOS bug: do NOT clear b1 if it's already clear ; test al,02h ; je saf3 ; and al,0FDh ; jmp short saf2 ;saf1: ; BIOS bug: do NOT set b1 if it's already set ; test al,02h ; jne saf3 ; or al,02h ;saf2: ; out 92h,al ;saf3: ; pop ax ; pop si ret ;---------------------------- ; _check_a20 function ;---------------------------- ; output: ; ZF 1 if a20 off, 0 if on. ;---------------------------- ; verifies a20 status ;_check_a20: ; mov ax,2402h ; int 15h ; jnc check_done ; ; push ax ; push ds ; push es ; xor ax,ax ; mov ds,ax ; dec ax ; mov es,ax ; ; mov ax,[es:10h] ; read word at FFFF:0010 (1 meg) ; not ax ; 1's complement ; push word [0] ; save word at 0000:0000 (0) ; mov [0],ax ; word at 0 = ~(word at 1 meg) ; mov ax,[0] ; read it back ; cmp ax,[es:10h] ; fail if word at 0 == word at 1 meg ; pop word [0] ; pop es ; pop ds ; pop ax ; ;check_done: ; ret ; if ZF=1, the A20 gate is NOT enabled ;---------------------------- ; _check_mem function ;---------------------------- ; uses BIOS calls to get memory size - falls back to manual scans if needbe. ; i've elected to not use INT15h, AH=88h because of its severe limitations. ; i'll implement a manual scan only if the need arises. i don't expect this ; to be executed on ancient machines, so the need for antiquated methods may ; not even arise. we'll see. i need to print the contents of "_availmem" ; very soon, though. in the kernel init maybe? _check_mem: mem1: ;------- INT 15h AX=E801h xor eax,eax mov ax,0xe801 int 15h jc mem2 cmp ax,0xe801 je mem2 shl ebx,8 add eax,ebx mov [_availmem],eax jmp mem_done mem2: ;------- INT 15h AH=8Ah xor eax,eax xor edx,edx mov ah,0x8A int 15h cmp eax,0x0 jz mem3 shl edx,16 or eax,edx mov [_availmem],eax jmp mem_done mem3: ;------- alternate method mem_done: ret [SECTION .data] ; strings booting: db 'Initializing LinksOS kernel...',0xd,0xa,0x0 a20fail: db 'Failed setting A20!',0xd,0xa,0x0 pmodeswitch: db 'Switching to protected mode...',0xd,0xa,0x0 pmodefail: db 'P-mode failed!',0xd,0xa,0x0 _availmem: dd 0 ; to be filled with amount of memory available in K [GLOBAL _availmem] ; null descriptor gdt: dw 0 ; limit 15:0 dw 0 ; base 15:0 db 0 ; base 23:16 db 0 ; type db 0 ; limit 19:16, flags db 0 ; base 31:24 ; linear data segment descriptor LINEAR_SEL equ $-gdt dw 0xFFFF ; limit 0xFFFFF (1 meg? 4 gig?) dw 0 ; base for this one is always 0 db 0 db 0x92 ; present,ring 0,data,expand-up,writable db 0xCF ; page-granular (4 gig limit), 32-bit db 0 ; code segment descriptor SYS_CODE_SEL equ $-gdt gdt2: dw 0xFFFF dw 0 ; (base gets set above) db 0 db 0x9A ; present,ring 0,code,non-conforming,readable db 0xCF db 0 ; data segment descriptor SYS_DATA_SEL equ $-gdt gdt3: dw 0xFFFF dw 0 ; (base gets set above) db 0 db 0x92 ; present,ring 0,data,expand-up,writable db 0xCF db 0 gdt_end: gdt_ptr: dw gdt_end - gdt - 1 ; GDT limit dd gdt ; linear, physical address of GDT ;--------------- ; Protected-mode segment ;--------------- do_pm: mov ax,SYS_DATA_SEL ; now in 32-bit pmode mov ds,eax ; EAX works, one byte smaller :) mov ss,eax nop mov es,eax mov fs,eax mov gs,eax xor eax,eax ; zero top 16 bits of ESP mov ax,sp mov esp,eax ;[EXTERN _main] ; call _main ; call C code jmp $ ; freeze ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; time to link to C code now! ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |