Skip to content

Instantly share code, notes, and snippets.

@Two9A
Created October 31, 2015 18:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Two9A/5ea7dbff87d41281e154 to your computer and use it in GitHub Desktop.
Save Two9A/5ea7dbff87d41281e154 to your computer and use it in GitHub Desktop.
ph34rOS! I never got very far with this...
;--------------------------------------------------------------------------
; 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-------------------------------------------------------------------
;--------------------------------------------------------------------------
; 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