adding bootloader files from the issue in gittea

This commit is contained in:
Gregory Kenneth Bowne 2024-03-24 21:09:02 -07:00
parent a6f5bdb64c
commit f4c5d59d8e
5 changed files with 224 additions and 239 deletions

BIN
.vscode/browse.vc.db vendored

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,131 +1,166 @@
[BITS 16] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[ORG 0x7c00] ; Stage 1 bootloader for ClassicOS ;
; -------------------------------- ;
; Determines if it was loaded from ;
; a floppy disk or an hard disk ;
; drive, and then loads stage 2 ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;
; Assembler directives ;
;;;;;;;;;;;;;;;;;;;;;;;;
; tells the assembler that the program will be loaded at 0x7C00
; this is done by the BIOS
org 0x7C00
; we are targeting (x86) 16-bit real mode
bits 16
;;;;;;;;;;;;;;;;;
; Jump to start ;
;;;;;;;;;;;;;;;;;
jmp start
;;;;;;;;
; Data ;
;;;;;;;;
; fdd geometry & options
fddsamt db 8 ; how many sectors to load
fddretr db 5 ; max retries for fdd operations
fddcretr db 0 ; current retries left
; misc strings
welcome1 db "Welcome to the ClassicOS Stage 1 bootloader.", 13, 10, 0
disktype db "Drive type: ", 0
diskfdd db "FDD", 13, 10, 0
diskhdd db "HDD", 13, 10, 0
loaded db "Data loaded!", 13, 10, 0
; errors
fdderes db "FDD reset failed.", 13, 10, 0
fddeload db "FDD read failed.", 13, 10, 0
; storage
disknum db 0
;;;;;;;;;;;
; Program ;
;;;;;;;;;;;
start: start:
; Processor initialization (only stack segment register needed) xor ax, ax ; set up segment registers to segment 0 since
mov ss, 0x1000 ; Set stack segment register mov ds, ax ; our addresses are already relative to 0x7C00
mov sp, 0x7C00 ; Set stack pointer (SP) mov es, ax
mov ds, ss ; Set data segment register (DS)
; Identify boot device using BIOS calls mov [disknum], dl ; save disk number to memory
identify_drive:
mov ah, 0x0E ; Get Interrupt Vector for INT 13h (Disk Services)
int 0x80
cmp cl, 0x41 ; Check for floppy drive interrupt vector (example)
je is_floppy
cmp cl, 0x80 ; Check for hard disk interrupt vector (example)
je is_harddrive
; Handle invalid drive type (error handling)
; ...
is_floppy: mov ah, 0x01 ; set cursor shape
; Perform floppy disk access (assuming AH=0x02 for read sectors) mov cx, 0x0100 ; hide cursor by setting ch = 1 and cl = 0x00
mov ah, 0x02 ; Read sectors int 0x10 ; video interrupt
mov al, 1 ; Number of sectors to read (1)
; Set CH, CL, DH, DL for floppy based on your system configuration mov ah, 0x08 ; read page number into bh
; (Replace these values with appropriate settings for your floppy drive) int 0x10
mov ch, 0 ; Cylinder (example, adjust based on your floppy)
mov cl, 1 ; Sector number (example, adjust based on boot sector location)
mov dh, 0 ; Head number (example, typically 0 for single-sided floppies)
mov dl, 0x00 ; Drive number (0x00 for floppy drive A)
; Set ES:BX to the memory address where you want to store the read data mov si, welcome1 ; print welcome
mov es, 0x1000 ; Example segment (adjust as needed) call printstr
mov bx, 0x0 ; Memory offset within the segment (example)
mov si, disktype ; print first part of disk type
call printstr
mov dl, [disknum] ; restore disk number - should not be
; strictly necessary but you never know
and dl, 0x80 ; sets zf if disk is floppy
jz fddload
hddload:
mov si, diskhdd ; print disk type
call printstr
jmp halt ; not implemented!
fddload:
mov si, diskfdd ; print disk type
call printstr
fddload_onto_reset:
mov ah, [fddretr] ; load max retries in memory
mov [fddcretr], ah
fddload_reset:
mov si, fdderes ; load error message pointer
dec byte [fddcretr] ; decrement the retries counter
jz fddload_err ; if it is 0, we stop trying
mov ah, 0x00 ; otherwise, reset function (int 0x13)
int 0x13 int 0x13
jc error_floppy jc fddload_reset ; if jc (error), we try again
; Implement error handling (omitted here for brevity) fddload_onto_load:
; Process the read data from the floppy sector (load second stage bootloader, etc.) mov ah, [fddretr] ; reset retries counter
mov [fddcretr], ah
mov ax, 0x1000 ; need to stay within real mode limits
mov es, ax
fddload_load: ; loads 512*fddsamt bytes from sector 2 on.
mov si, fddeload
dec byte [fddcretr]
jz fddload_err
is_harddrive: mov dh, 0 ; head 0
mov ch, 0 ; cyl/track 0
mov cl, 2 ; start sector
mov bx, 0 ; memory location
mov al, [fddsamt] ; how many sectors to read
mov ah, 0x02 ; read function (int 0x13)
int 0x13
jc fddload_load ; if jc (error), we try again
cmp al, [fddsamt] ; also if al is not 1, we have a problem
jnz fddload_load
; Sample code (not guaranteed to work universally) fddload_done:
mov ah, 0x02 ; Set function for read sectors mov si, loaded ; we have successfully loaded the data
mov al, 0x01 ; Read one sector call printstr
; Set CH, CL, DH for desired sector location (e.g., first sector) jmp halt ; this will be jmp 0x1000:0x0000
mov dl, 0x80 ; Drive number (assuming drive A is boot device)
mov es, segment_address ; Set ES for buffer to store read data
mov bx, buffer_offset ; Set BX for offset within the buffer
int 13h ; Raise BIOS interrupt for disk read fddload_err:
call printstr ; print
jmp halt ; and die
; Check Carry flag for error handling ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
jc harddrive_not_found ; Jump if Carry flag is set (potential error) ; printstr routine, prints the string pointed by si using int 0x10 ;
; sets the direction flag to 0 ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
printstr:
cld ; clear df flag - lodsb increments si
printstr_loop:
lodsb ; load next character into al, increment si
or al, al ; sets zf if al is 0x00
jz printstr_end
mov ah, 0x0E ; teletype output (int 0x10)
int 0x10 ; print character
jmp printstr_loop
printstr_end:
ret ; return to caller address
; Hard drive likely present (further processing can occur)
; ... (rest of your bootloader code) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; halt routine - infinite loop ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
halt:
cli
jmp halt
harddrive_not_found: ;;;;;;;;;;;
; Handle error condition (missing drive or other issue) ; Padding ;
;;;;;;;;;;;
; $ is the address of the current line, $$ is the base address for
; this program.
; the expression is expanded to 510 - ($ - 0x7C00), or
; 510 + 0x7C00 - $, which is, in other words, the number of bytes
; before the address 510 + 0x7C00 (= 0x7DFD), where the 0xAA55
; signature shall be put.
times 510 - ($ - $$) db 0x00
; ... (error handling logic) ;;;;;;;;;;;;;;;;;;
; BIOS signature ;
memory_error: ;;;;;;;;;;;;;;;;;;
; ... (error handling or continue with limited memory) dw 0xAA55
; Second stage loading (simplified example)
; Here's an improved version of the load_second_stage section with the placeholder jump replaced by actual loading logic:
; Code snippet
load_second_stage:
; Calculate address of second stage bootloader (assuming offset from boot sector)
mov dx, 0x0000 ; Clear DX register for better calculation
add dx, sector_count ; Add number of sectors to skip (adjust as needed)
shl dx, 5 ; Multiply by sector size (512 bytes)
add dx, 0x7C00 ; Add boot sector address offset
; Read second stage bootloader from calculated address
mov ah, 0x02 ; Function for reading sectors
mov al, 1 ; Number of sectors to read (1 for second stage)
mov es, dx ; Set ES segment register to calculated address
mov bx, 0x0000 ; Set BX offset within the segment (example)
int 13h ; Raise BIOS interrupt for disk read
; Check Carry flag for error handling
jc memory_error ; Jump if Carry flag is set (potential error)
; Second stage likely loaded successfully, jump to it
jmp second_stage_address ; Direct jump to the defined address
error_floppy:
; Display a basic error message (optional)
mov ah, 0x0E ; BIOS video call for displaying text (educational purposes)
mov bh, 0x00 ; Set background color (black)
mov bl, 0x07 ; Set text color (white)
mov dx, error_floppy_message ; Address of error message string
int 0x10 ; BIOS video interrupt
; Halt the boot process (replace with a retry or more advanced error handling)
hlt ; Halt instruction
error_floppy_message db 'Floppy disk read error!', 0x0
memory_error:
; Check for available memory (replace with actual method)
; ... (e.g., call BIOS service for memory size or use a constant value)
cmp available_memory, memory_threshold ; Compare with minimum required memory
jb limited_memory_boot ; Jump if below threshold
; ... (standard error handling for other scenarios)
limited_memory_boot:
; Perform minimal setup for limited memory boot
; ... (disable non-essential features, adjust kernel parameters)
; Load and jump to second stage bootloader (potentially with adjustments)
; ... (modify loading logic if necessary)
; Define variables used for calculation (adjust as needed)
sector_count db 1 ; Number of sectors to skip before second stage (change if needed)
second_stage_address equ 0x8000 ; Replace with actual address of your second stage bootloader
available_memory equ 0x100000 ; Replace with actual memory size detection (1MB in this example)
memory_threshold equ 0x0A0000 ; Example minimum memory required (adjust based on needs)
; Padding and magic number (standard practice)
times 510-($-$$) db 0
dw 0xaa55

View File

@ -1,141 +1,91 @@
[BITS 16] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[ORG 0x0000] ; Stage 2 bootloader for ClassicOS ;
; -------------------------------- ;
; Loads the kernel, sets up tables, ;
; and transitions to protected mode ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;
; Assembler directives ;
;;;;;;;;;;;;;;;;;;;;;;;;
; tells the assembler that the program will be loaded at 0x8000
; this is done by the first stage bootloader
org 0x8000
; we are targeting (x86) 16-bit real mode
bits 16
;;;;;;;;;;;;;;;;;
; Jump to start ;
;;;;;;;;;;;;;;;;;
jmp start
;;;;;;;;
; Data ;
;;;;;;;;
; kernel file name
kername db "KERNEL.BIN", 0
;;;;;;;;;;;
; Program ;
;;;;;;;;;;;
start: start:
; Initialize stack xor ax, ax ; set up segment registers to segment 0 since
MOV AX, 0x0000 ; Set up a segment for the stack mov ds, ax ; our addresses are already relative to 0x8000
MOV SS, AX mov es, ax
MOV SP, 0xFFFF ; Stack grows downwards from the top of the segment
; Copy boot sector data to a safe location mov si, kername ; print kernel file name
call mCopyBootSector call printstr
; Load the kernel
CALL load_kernel
switch_to_protected_mode: ; Load the kernel into memory
CLI ; Disable interrupts ; ...
lgdt [gdt_descriptor] ; Load the global descriptor table
MOV EAX, CR0
OR EAX, 0x1 ; Set the PE (Protection Enable) bit
MOV CR0, EAX
; Far jump to flush CPU queue after changing to protected mode
JMP CODE_SEG:init_pm ; CODE_SEG is the segment selector for code segment in GDT
init_pm:
; Update segment registers here
; Set code segment register (CS) to point to code segment descriptor (selector 1)
mov ax, 0x0001
mov ds, ax ; Set data segment register (DS) to point to data segment descriptor (selector 2)
mov es, ax ; Set other segment registers (ES, SS, etc.) as needed
RET
enable_a20: ; Set up GDT, IDT, IVT
cli ; Disable interrupts to prevent interference ; ...
call a20wait ; Wait for the keyboard controller to be ready
mov al, 0xAD ; Command to disable keyboard
out 0x64, al ; Send command to keyboard controller command port
call a20wait ; Wait for the keyboard controller to be ready
mov al, 0xD0 ; Command to read output port
out 0x64, al ; Send command to keyboard controller command port
call a20wait ; Wait for the keyboard controller to be ready
in al, 0x60 ; Read current state of output port
or al, 0x02 ; Set A20 bit
out 0x64, al ; Send command to keyboard controller command port
call a20wait ; Wait for the keyboard controller to be ready
mov al, 0xD1 ; Command to write output port
out 0x64, al ; Send command to keyboard controller command port
call a20wait ; Wait for the keyboard controller to be ready
mov al, 0xAE ; Command to re-enable keyboard
out 0x64, al ; Send command to keyboard controller command port
sti ; Re-enable interrupts
ret
; Wait for keyboard controller to be ready ; Switch to protected mode
a20wait: ; ...
in al, 0x64 ; Read keyboard controller status port
test al, 0x02 ; Check if input buffer is full
jnz a20wait ; Wait until it's not full
ret
; Enter kernel space and jump to the kernel entry point ; Set up stack and start executing kernel's code
JMP 0x1000:0x0000 ; ...
; Code to set up flat memory model for protected mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; This involves setting up the segment registers with selectors ; printstr routine, prints the string pointed by si using int 0x10 ;
; that point to descriptors in the GDT that define a flat memory model ; sets the direction flag to 0 ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
printstr:
cld ; clear df flag - lodsb increments si
printstr_loop:
lodsb ; load next character into al, increment si
or al, al ; sets zf if al is 0x00
jz printstr_end
mov ah, 0x0E ; teletype output (int 0x10)
int 0x10 ; print character
jmp printstr_loop
printstr_end:
ret ; return to caller address
limit = 0x00CFFFFFh ; Define limit as a separate variable within gdt_struct ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; halt routine - infinite loop ;
; Placeholder instruction to satisfy NASM ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
dummy_instruction DB 0x90 ; NOP instruction as a placeholder halt:
gdt_struct:
base_addr equ 0x0000000
; Null descriptor (ignored)
dd base_addr, 0 ; Both values are zero for a null descriptor
; Code segment descriptor (flat memory model)
dd base_addr, limit
db 0x9A
db 0xCF
; Data segment descriptor (flat memory model)
dd base_addr, limit
db 0x92
db 0xCF
; Macro to copy boot sector data to a safe location
mCopyBootSector:
pusha ; Save all general-purpose registers
mov si, 0x7C00 ; Source address: where BIOS loads the boot sector
mov di, 0x6000 ; Destination address: safe memory area
mov cx, 512 ; Number of bytes to copy (size of boot sector)
cld ; Clear direction flag to increment SI and DI
copy_loop:
lodsb ; Load byte at address DS:SI into AL, increment SI
stosb ; Store byte from AL to address ES:DI, increment DI
loop copy_loop ; Decrement CX; if CX != 0, repeat loop
popa ; Restore all general-purpose registers
ret
; Subroutine to load the kernel
load_kernel:
; Disable interrupts
cli cli
jmp halt
; Setup disk parameters ;;;;;;;;;;;
; ... (set CH, CL, DH, DL for LBA, set DX for drive number) ; Padding ;
;;;;;;;;;;;
; $ is the address of the current line, $$ is the base address for
; this program.
; the expression is expanded to 510 - ($ - 0x8000), or
; 510 + 0x8000 - $, which is, in other words, the number of bytes
; before the address 510 + 0x8000 (= 0x80FD), where the 0xAA55
; signature shall be put.
times 510 - ($ - $$) db 0x00
; Calculate load address for kernel ;;;;;;;;;;;;;;;;;;
; ... (set ES:BX to the target memory address) ; BIOS signature ;
;;;;;;;;;;;;;;;;;;
; Read sectors from disk into memory dw 0xAA55
mov ah, 0x02 ; Read sectors function
mov al, 1 ; Number of sectors to read
int 0x13 ; BIOS disk services
; Check for read error
jc .disk_error ; Carry flag set means an error occurred
; Enable A20 line if necessary
; ... (implementation depends on your system)
; Jump to the kernel's entry point
jmp 0x1000:0x0000 ; Assuming the kernel is loaded at 0x1000:0x0000
.disk_error:
; Handle disk read error
; ... (display error message or halt)
hlt ; Halt the system
; Function or Subroutine to switch to protected mode
switch_to_protected_mode:
CLI ; Disable interrupts
LGDT [gdt_descriptor] ; Load the global descriptor table
MOV EAX, CR0
OR EAX, 0x1 ; Set the PE (Protection Enable) bit
MOV CR0, EAX
; Far jump to flush CPU queue after changing to protected mode
JMP CODE_SEG:init_pm ; CODE_SEG is the segment selector for code segment in GDT