Created
October 31, 2015 18:27
-
-
Save Two9A/5ea7dbff87d41281e154 to your computer and use it in GitHub Desktop.
ph34rOS! I never got very far with this...
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;-------------------------------------------------------------------------- | |
; ph34rOS - Testing boot sector version 0.0.1h | |
; Changes from 0.0.1g - Removed Alias descriptor (No use for it) | |
; - Moved Stage2 load point to 7E00 | |
; - Assuming 386+ (It's a reasonable assumption) | |
; - Optimised debugging messages (I was bored) | |
; - Removed GetKey (No need, no need at all) | |
; - Moved procs into main code (no CALLs!) | |
;-------------------------------------------------------------------------- | |
[bits 16] ; 16-bit code | |
org 0 ; Code at start of sector | |
jmp ph34r_BOOT ; Jump over data | |
;-------------------------------------------------------------------------- | |
; The GDT, containing the PMode descriptors. Here we'll be using flat mode | |
; so the descriptors are limited to FFFFx4096. We provide one each for | |
; code and data, as well as the required dummy descriptor. | |
ph34r_BOOT_GDT: ; The GDT | |
dw 0x0030 ; Being cheeky and using | |
dw 0x7C03 ; the dummy descriptor as | |
dw 0x0000 ; storage for the GDTR | |
dw 0x0000 ; loading | |
ph34r_BOOT_GDT_CS: ; Descriptor 0008h | |
db 0xFF,0xFF,0x00,0x00 ; is the flat-mode code | |
db 0x00,0x9A,0xCF,0x00 ; (read-only, exec) | |
ph34r_BOOT_GDT_DS: ; Descriptor 0010h | |
db 0xFF,0xFF,0x00,0x00 ; is flat-mode data | |
db 0x00,0x92,0xCF,0x00 ; (read/write, nonexec) | |
; ph34rOS will comprehensively provide information on the current loading | |
; status (mainly for debugging), so here are some messages. | |
ph34r_BOOTMSG_Reboot db "Hit a key to re" | |
ph34r_BOOTMSG_Start db "boot: ",0 | |
ph34r_BOOTMSG_Read db "stg2" | |
ph34r_BOOTMSG_Dot db ".",0 | |
ph34r_BOOTMSG_SetA20 db "A20-",0 | |
ph34r_BOOTMSG_PMIn db "pmode",13,10,0 | |
;-------------------------------------------------------------------------- | |
; Another quite simple proc, Print will write a null-terminated message | |
; to the screen, using the VBIOS's teletype echo function. | |
ph34r_BOOT_Print: ; Print a message | |
lodsb ; Load in a byte | |
or al,al ; Test for zero | |
jz .Tend ; If zero, end | |
mov ah,0x0E ; Function 0Eh | |
mov bh,0x07 ; Page 0, Attribute 7 | |
int 0x10 ; BIOS Video Ine | |
jmp ph34r_BOOT_Print ; and Loop | |
.Tend: ; End of func | |
ret ; Return | |
;-------------------------------------------------------------------------- | |
; Everyone uses the vector at 000FFFF0 to reboot the PC, so that's what | |
; we'll do too. | |
ph34r_BOOT_Reboot: ; Reboot computer | |
mov si,ph34r_BOOTMSG_Reboot ; "Rebooting" | |
call ph34r_BOOT_Print ; Print it | |
xor ax,ax ; Wait for a key | |
int 0x16 ; BIOS Keyboard Int | |
db 0xEA ; FAR jmp | |
dw 0x0000 ; To the BIOS | |
dw 0xFFFF ; reset routine | |
;-------------------------------------------------------------------------- | |
ph34r_BOOT: ; Start of code | |
; The segments and stack start off in a random state, so we have to set | |
; them to something sane. We load the data I/O to the bootsector code, | |
; and set up a stack at the top of 640k. | |
mov ax,0x07C0 ; Segment | |
mov ds,ax ; for Source | |
mov es,ax ; and Destination | |
cli ; No interrupts, please | |
mov ax,0x9000 ; Segment | |
mov ss,ax ; for Stack | |
mov sp,0xFFFE ; Top of seg for stack start | |
sti ; Ints back | |
; The registers are sane now, so we can do all the normal things. So we | |
; set up the environment ready for the pmode switch. | |
mov si,ph34r_BOOTMSG_Start ; Start message | |
call ph34r_BOOT_Print ; Print it | |
; For the paging code, we need a list of valid memory locations. Instead | |
; of probing manually (we don't have space for that), we let the BIOS do | |
; it for us. | |
ph34r_BOOT_ProbeMem: ; Get a list of valid mem ranges | |
xor ax,ax ; Start of memory | |
mov es,ax ; For buffer | |
mov di,0x9000 ; Near the top of this seg | |
xor ebx,ebx ; 00000000 - Begin map read | |
mov cx,32 ; Get 32 memory lines | |
.PLoop: ; Loop the reading | |
push cx ; Save the loop counter | |
mov eax,0x0000E820 ; Read System Memory Map | |
mov ecx,0x00000014 ; Read 20 bytes at a time | |
mov edx,0x534D4150 ; 'SMAP' | |
int 0x15 ; Do the read | |
jc .PDone ; If error, we're done here | |
cmp eax,0x534D4150 ; Was the return 'SMAP'? | |
jnz .PDone ; If not, we're done | |
add di,20 ; Move along one record | |
pop cx ; Get the loop counter back | |
loop .PLoop ; And loop around | |
.PDone: ; All done | |
; The second stage is located right behind the bootsector on disk, so | |
; it must be loaded in. We load it just beyond the bootsector, at seg | |
; 0x07E0, ready for the jump. | |
ph34r_BOOT_Read: ; Read in the kernel | |
mov si,ph34r_BOOTMSG_Read ; "Reading" | |
call ph34r_BOOT_Print ; Print it | |
mov ax,0x07E0 ; Just after the | |
mov es,ax ; bootsector | |
xor bx,bx ; to write to | |
mov ax,2 ; Start sector 2 | |
mov cx,2 ; TWO sectors | |
; We'll read the sectors one by one, and retry each read up to 5 times if | |
; it fails. For the moment, floppy drive 0 is hardwired as the read drive. | |
.read: ; Start read | |
mov di,0x0005 ; Retry 5 times | |
.rloop: ; Reading loop | |
push ax ; Save | |
push bx ; parameter | |
push cx ; registers | |
mov cx,ax ; Sector/Track | |
mov ax,0x0201 ; Read a sector | |
xor dx,dx ; Head/Drive | |
int 0x13 ; Call BIOS disk | |
jnc .rsuccess ; Did it work? | |
xor ax,ax ; If not, reset | |
int 0x13 ; the disk system | |
dec di ; Count down retries | |
pop cx ; Get back | |
pop bx ; our saved | |
pop ax ; parameters | |
jnz .rloop ; Loop back | |
call ph34r_BOOT_Reboot ; If we get here, we're broke | |
.rsuccess: ; It worked | |
mov si,ph34r_BOOTMSG_Dot ; Print a dot for progress | |
call ph34r_BOOT_Print ; Do it | |
pop cx ; Get back | |
pop bx ; our saved | |
pop ax ; parameters | |
add bx,512 ; Move along in mem | |
inc ax ; And on disk | |
loop .read ; and loop back | |
; Address line A20 on the CPU is hooked to an AND gate, the other input | |
; being a line from the port on the keyboard controller. To access all | |
; our RAM, we need to set this line high. | |
ph34r_BOOT_SetA20: ; Set the A20 line | |
mov si,ph34r_BOOTMSG_SetA20 ; "Setting A20" | |
call ph34r_BOOT_Print ; Print it | |
xor cx,cx ; Reset loop counter | |
; We need to clear out the keyboard data buffer, then tell the KBC to | |
; send bytes out to its output port (command 0xD1). | |
.Clear1: ; Clearing keyboard buffer | |
in al,0x64 ; Read keyboard status | |
test al,0x02 ; Test 'buffer contents valid' | |
loopnz .Clear1 ; Loop until clear | |
mov al,0xD1 ; "Write to output port" | |
out 0x64,al ; Output command | |
; Now the KBC is waiting for data to send out its output wires. We tell | |
; it to set the line hooked to the A20 gate high (command 0xDF). | |
.Clear2: ; Clear buffer again | |
in al,0x64 ; Wait for | |
test al,0x02 ; keyboard buffer to | |
loopnz .Clear2 ; empty again | |
mov al,0xDF ; Set line hooked to A20 | |
out 0x60,al ; Out to KBC | |
; Now we hang around 25us for the command to complete. The 'delay' ports | |
; provide a handy waiting method. | |
mov cx,20 ; Delay for | |
.AWait: ; around 25usec | |
out 0xED,ax ; by using the | |
loop .AWait ; 'Delay' port | |
; Now we're ready for the switch. We don't have an IDT yet, so interrupts | |
; have to be turned off. After the switch, we jump across to the loaded | |
; stage 2, to clear out anything in the cpu's prefetch queue. | |
mov si,ph34r_BOOTMSG_PMIn ; "Entering pm" | |
call ph34r_BOOT_Print ; Print it | |
cli ; No ints please | |
; By default, the Interrupt Controller is programmed to stick some IRQ's | |
; low down in the IVT. In PMode, we need this space for exception handling, | |
; so it's time to reprogram the PIC. | |
ph34r_BOOT_InitPIC: ; Reinitialise the PIC | |
mov al,0x11 ; Cascaded PICs, ICW4 expected | |
out 0x20,al ; Send to PIC1 | |
out 0xA0,al ; And PIC2 | |
mov al,0x20 ; Starting at int 20h | |
out 0x21,al ; Write to PIC1 | |
mov al,0x28 ; A linear sequence of all 16 IRQs | |
out 0xA1,al ; Write to PIC2 | |
mov al,0x04 ; IRQ2 is hooked to a slavePIC | |
out 0x21,al ; Send to PIC1 | |
mov al,0x02 ; Slave is hooked to Master IRQ2 | |
out 0xA1,al ; Send to PIC2 | |
mov al,0x01 ; In an x86, manual EOI | |
out 0x21,al ; Write to PIC1 | |
out 0xA1,al ; and PIC2 | |
; And now we're good to go pmode. We do this in the standard way: Tell the | |
; CPU where the GDT is, flip the PE bit in control register 0, and jump to | |
; some 32-bit code. | |
lgdt [ph34r_BOOT_GDT] ; Set GDTR | |
mov eax,cr0 ; Read in status reg 0 | |
or al,1 ; Set PMode | |
mov cr0,eax ; Write in (now in PM!) | |
db 0xEA ; Far JMP down to stg2 | |
dw 0x7E00 ; (After the bootsector, | |
dw 0x0008 ; code descriptor) | |
;-------------------------------------------------------------------------- | |
; We need the sector to be a sector in size, and have the BIOS boot | |
; signature (55,AA) at position 510. | |
times 510-($-$$) db 0 ; Pad out sector | |
dw 0xAA55 ; BIOS Signature | |
;----EOS------------------------------------------------------------------- |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;-------------------------------------------------------------------------- | |
; ph34rOS Test Kernel, version 0.0.1c | |
; Changes from 0.0.1c - Added putHex | |
;-------------------------------------------------------------------------- | |
[bits 32] ; 32 bits! | |
[org 0x7E00] ; Where we loaded up | |
; And we're off! | |
ph34r_STG2_Code32: ; Start of code | |
mov ax,0x10 ; Load up the | |
mov ds,ax ; proper descriptor | |
mov es,ax ; for src and dest | |
mov ss,ax ; And the stack too | |
mov eax,0x0009FFFC ; Top of conventional RAM for stack | |
mov esp,eax ; Set it | |
mov edx,ph34r_STG2_Test ; Just a test message | |
call ph34r_STG2_print ; Print it out | |
mov ebx,0x00009000 | |
mov ecx,32 | |
.Outer: | |
push ecx | |
add ebx,7 | |
mov ecx,8 | |
.Loop1: | |
mov dl,[ebx] | |
call ph34r_STG2_putHex2 | |
dec ebx | |
loop .Loop1 | |
add ebx,16 | |
mov ecx,8 | |
.Loop2: | |
mov dl,[ebx] | |
call ph34r_STG2_putHex2 | |
dec ebx | |
loop .Loop2 | |
add ebx,12 | |
mov ecx,4 | |
.Loop3: | |
mov dl,[ebx] | |
call ph34r_STG2_putHex2 | |
dec ebx | |
loop .Loop3 | |
add ebx,5 | |
pop ecx | |
;mov dl,13 | |
;call ph34r_STG2_putch | |
;mov dl,10 | |
;call ph34r_STG2_putch | |
loop .Outer | |
hlt ; We'll stop now | |
ph34r_STG2_Test: db "Welcome to the next level.",13,10,0 | |
;-------------------------------------------------------------------------- | |
; Base console video driver routines. These assume startup into an 80x25 | |
; terminal, mapped at 0xB8000 (reasonable assumptions). | |
ph34r_STG2_CursX: db 0 ; Storage for the virtual | |
ph34r_STG2_CursY: db 0 ; cursor position | |
ph34r_STG2_RdCurs: ; Read the cursor position | |
push eax ; We're gonna be | |
push ebx ; changing these, | |
push ecx ; so it's probably | |
push edx ; wise to save them | |
xor eax,eax ; Wipe registers we'll | |
xor edx,edx ; be using later | |
xor ebx,ebx ; to be safe | |
mov dx,0x3D4 ; CRTC address port | |
mov al,0x0E ; Cursor Loc. High | |
out dx,al ; Write to CRTC address port | |
mov ecx,5 ; Delay for 5 reads | |
.Lp1: ; Start of delay loop | |
in al,dx ; Read in | |
dec ecx ; Move counter down | |
jnz .Lp1 ; and loop back | |
inc dx ; Move along to CRTC data | |
in al,dx ; Read in from CRTC data | |
mov bh,al ; Save for now | |
mov al,0x0F ; Cursor loc low | |
dec dx ; Back down to CRTC addr | |
out dx,al ; Write to CRTC addr | |
mov ecx,5 ; Delay for 5 reads | |
.Lp2: ; Start of delay loop | |
in al,dx ; Read in | |
dec ecx ; Move counter down | |
jnz .Lp2 ; and loop back | |
inc dx ; Up to CRTC data | |
in al,dx ; Read in low byte | |
mov bl,al ; Save it | |
mov eax,ebx ; Move over for DIV | |
xor edx,edx ; And XOR out the high dword | |
mov ebx,80 ; Divisor | |
div ebx ; Divide to find rows | |
mov [ph34r_STG2_CursX],dl ; Save remainder | |
mov [ph34r_STG2_CursY],al ; and quotient | |
pop edx ; Retrieve the | |
pop ecx ; values that we | |
pop ebx ; pushed on the | |
pop eax ; stack before | |
ret ; And return | |
;-------------------------------------------------------------------------- | |
ph34r_STG2_WrCurs: ; Move the cursor | |
push eax ; We're gonna be | |
push ebx ; changing these, | |
push ecx ; so it's probably | |
push edx ; wise to save them | |
xor ebx,ebx ; Clear out the | |
xor edx,edx ; regs we'll be using | |
mov bl,[ph34r_STG2_CursY] ; Load up the | |
mov dl,[ph34r_STG2_CursX] ; cursor pos | |
imul ebx,80 ; Mul up the rows | |
add ebx,edx ; And add on the cols | |
mov dx,0x3D4 ; CRTC address port | |
mov al,0x0E ; Cursor Loc. High | |
out dx,al ; Write to CRTC address port | |
mov ecx,5 ; Delay for 5 reads | |
.Lp1: ; Start of delay loop | |
in al,dx ; Read in | |
dec ecx ; Move counter down | |
jnz .Lp1 ; and loop back | |
inc dx ; Move along to CRTC data | |
mov al,bh ; Save high byte of pos | |
out dx,al ; Send it out | |
mov ecx,5 ; Delay for 5 reads | |
.Lp2: ; Start of delay loop | |
in al,dx ; Read in | |
dec ecx ; Move counter down | |
jnz .Lp2 ; and loop back | |
mov al,0x0F ; Cursor loc low | |
dec dx ; Back down to CRTC addr | |
out dx,al ; Write to CRTC addr | |
mov ecx,5 ; Delay for 5 reads | |
.Lp3: ; Start of delay loop | |
in al,dx ; Read in | |
dec ecx ; Move counter down | |
jnz .Lp3 ; and loop back | |
inc dx ; Up to CRTC data | |
mov al,bl ; Write low byte | |
out dx,al ; Do so | |
mov ecx,5 ; Delay for 5 reads | |
.Lp4: ; Start of delay loop | |
in al,dx ; Read in | |
dec ecx ; Move counter down | |
jnz .Lp4 ; and loop back | |
pop edx ; Retrieve the | |
pop ecx ; values that we | |
pop ebx ; pushed on the | |
pop eax ; stack before | |
ret ; And we're done | |
;-------------------------------------------------------------------------- | |
; Takes - DL = character to put | |
ph34r_STG2_putch: ; Put character on screen | |
push eax ; We're gonna be | |
push ebx ; changing these, | |
push ecx ; so it's probably | |
push edx ; wise to save them | |
call ph34r_STG2_RdCurs ; Read in cursor position | |
cmp dl,0x20 ; Is this an actual ASCII? | |
jb .nASCII ; If not, don't print it | |
mov bl,dl ; Save the char to write | |
xor eax,eax ; Clear out regs | |
xor edx,edx ; before use | |
mov al,[ph34r_STG2_CursY] ; Load up the | |
mov dl,[ph34r_STG2_CursX] ; cursor pos | |
imul eax,80 ; Mul up the rows | |
add eax,edx ; And add on the cols | |
shl eax,1 ; Shift for char/attr pair | |
mov edi,0x000B8000 ; Base of vidmem | |
add edi,eax ; Add our offset | |
mov al,bl ; Bring back char to write | |
mov ah,7 ; Default attr for now | |
stosw ; Put it on there | |
call ph34r_STG2_RdCurs ; Read in cursor pos | |
mov al,[ph34r_STG2_CursX] ; Load up cursor X | |
inc al ; Move along one | |
cmp al,80 ; Did we push beyond 79? | |
jb .CursOK ; If not, we're fine | |
xor eax,eax ; Position 0 | |
mov dl,[ph34r_STG2_CursY] ; Read in Y | |
inc dl ; Move down one | |
cmp dl,25 ; Did we scroll off? | |
jne .YCursOk ; If not, we're OK | |
dec dl ; Bring back to 24 | |
call ph34r_STG2_ScrlUp ; And move screen up | |
.YCursOk: ; All good on Y front | |
mov [ph34r_STG2_CursY],dl ; Save Y pos | |
.CursOK: ; Done repositioning | |
mov [ph34r_STG2_CursX],al ; Write out the X value | |
jmp .Exit ; Quit func | |
.nASCII: ; Done printing | |
cmp dl,10 ; Is this a LF? | |
jne .CRcheck ; If not, check for CR | |
mov al,[ph34r_STG2_CursY] ; Read in Y pos | |
inc al ; Move down | |
cmp al,25 ; Did we scroll off? | |
jne .nScrl ; If not, don't scroll | |
dec al ; Move back to 24 | |
call ph34r_STG2_ScrlUp ; And move the screen up | |
.nScrl: ; Done scrolling if any | |
mov [ph34r_STG2_CursY],al ; Save new pos | |
jmp .Exit ; And quit | |
.CRcheck: ; Check for a CR | |
cmp dl,13 ; Did we get a CR? | |
jne .Exit ; If not, we're done | |
xor eax,eax ; Move to start of line | |
mov [ph34r_STG2_CursX],al ; in X direction | |
.Exit: ; All done here | |
call ph34r_STG2_WrCurs ; Move cursor on screen | |
pop edx ; Retrieve the | |
pop ecx ; values that we | |
pop ebx ; pushed on the | |
pop eax ; stack before | |
ret ; and we're done | |
;-------------------------------------------------------------------------- | |
; Takes - EDX = Pointer to string | |
ph34r_STG2_print: ; Print an ASCIIZ string | |
push edx ; Save what we'll be modifying | |
push eax ; to the stack | |
mov eax,edx ; Make a copy of the pointer | |
.Lp: ; Main loop | |
mov dl,byte [eax] ; Read in a char | |
or dl,dl ; Is it 0? | |
jz .End ; If so, all done | |
call ph34r_STG2_putch ; Otherwise print it | |
inc eax ; Move along | |
jmp .Lp ; and loop back | |
.End: ; All done | |
pop eax ; From the stack | |
pop edx ; bring back the regs | |
ret ; and return | |
;-------------------------------------------------------------------------- | |
ph34r_STG2_ScrlUp: ; Scroll up one line | |
push ecx ; Save whatever regs | |
push esi ; we could be changing | |
push edi ; on the stack | |
push eax ; to be safe | |
mov ecx,960 ; For 960 dwords | |
mov esi,0x000B80A0 ; From one line down | |
mov edi,0x000B8000 ; to the top | |
rep movsd ; Block move | |
mov eax,0x07200720 ; Char 32, attr 7 | |
mov ecx,40 ; For 40 dwords | |
mov edi,0x000B8000+24*160 ; Bottom line | |
rep stosd ; Write out | |
pop eax ; Bring back | |
pop edi ; the regs we saved | |
pop esi ; on the stack | |
pop ecx ; beforehand | |
ret ; We're done | |
;-------------------------------------------------------------------------- | |
; Takes - DL = Nybble to write | |
ph34r_STG2_putHex: ; Print a 1-digit hex number | |
push edx ; Save the old value | |
and dl,0x0F ; Mask off to 1 nybble | |
add dl,48 ; Add on '0' | |
cmp dl,57 ; Is it above '9'? | |
jbe .Over ; If not, skip over this | |
add dl,7 ; Otherwise, move up to 'A-F' | |
.Over: ; We may have skipped to here | |
call ph34r_STG2_putch ; Print it | |
pop edx ; Restore it | |
ret ; All done | |
;-------------------------------------------------------------------------- | |
; Takes - DL = Double-digit hex to write | |
ph34r_STG2_putHex2: ; Print a 2-digit hex number | |
push edx ; Save the value | |
mov dh,dl ; Make a copy of the param | |
shr dl,4 ; Shift down the high nybble | |
call ph34r_STG2_putHex ; Print that | |
mov dl,dh ; Bring the copy back | |
call ph34r_STG2_putHex ; and print the low nybble | |
pop edx ; Restore edx | |
ret ; We're done here | |
;-------------------------------------------------------------------------- | |
; Takes - EDX = 8-digit hex to write | |
ph34r_STG2_putHex8: ; Print an 8-digit hex number | |
push edx ; Save the | |
push ecx ; current values | |
mov ecx,8 ; Loop 8 times | |
.Loop: ; Loop around | |
rol edx,4 ; Retrieve the right nybble | |
call ph34r_STG2_putHex ; and print it | |
loop .Loop ; Loop round | |
pop ecx ; Restore from stack | |
pop edx ; into the regs | |
ret ; and we're done | |
;-------------------------------------------------------------------------- | |
times 1024-($-$$) db 0 ; Pad out | |
;----EOF------------------------------------------------------------------- |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment