Trying to fix the boot2.asm second stage bootloader

This commit is contained in:
Gregory Kenneth Bowne 2024-02-09 16:36:16 -08:00
parent 19b61da1af
commit 8e7cdce87d
5 changed files with 195 additions and 116 deletions

BIN
.vscode/browse.vc.db vendored

Binary file not shown.

Binary file not shown.

2
.vscode/launch.json vendored
View File

@ -8,7 +8,7 @@
"name": "gcc-8 - Build and debug active file Level 1", "name": "gcc-8 - Build and debug active file Level 1",
"type": "cppdbg", "type": "cppdbg",
"request": "launch", "request": "launch",
"program": "${fileDirname}/${fileBasenameNoExtension}", "program": "/home/gbowne1/Documents/ClassicOS/build/ClassicOS",
"args": [], "args": [],
"stopAtEntry": false, "stopAtEntry": false,
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",

View File

@ -1,43 +1,124 @@
[BITS 16] [BITS 16]
[ORG 0x0000] [ORG 0x0000]
start: start:
MOV AX, CS ; Initialize stack
MOV DS, AX MOV AX, 0x0000 ; Set up a segment for the stack
MOV SS, AX MOV SS, AX
MOV SP, 0xFFFF MOV SP, 0xFFFF ; Stack grows downwards from the top of the segment
MOV SI, msg ; Copy boot sector data to a safe location
JMP println mCopyBootSector
JMP $ ; Load the kernel
CALL load_kernel
RET 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
init_pm:
; Update segment registers here
; ...
RET
println:
.next_char:
LODSB
OR AL, AL
JZ .stop
MOV AH, 0x0E enable_a20:
MOV BH, 0x00 ; Enable A20 gate
MOV BL, 0x07 cli ; Disable interrupts to prevent interference
INT 0x10 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
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, 0x02 ; New output port data with A20 enabled
out 0x60, al ; Write new output port data
call a20wait ; Wait for the keyboard controller to be ready
sti ; Re-enable interrupts
ret
JMP .next_char ; Wait for keyboard controller to be ready
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
.stop: ; Enter kernel space and jump to the kernel entry point
MOV AH, 0x03 ; AH = 0x03 (Get Cursor Position and Shape) JMP 0x1000:0x0000
XOR BH, BH ; BH = 0x00 (Video Page Number)
INT 0x10 ; Call video interrupt
INC DH ; Code to set up flat memory model for protected mode
; This involves setting up the segment registers with selectors
; that point to descriptors in the GDT that define a flat memory model
; ...
MOV AH, 0x02 ; Set cursor position ; Jump to the kernel entry point
XOR BH, BH ; Page number JMP 0x1000:0x0000 ; Assuming the kernel is loaded at 0x1000:0x0000
XOR DL, DL ; Column (start from 0)
INT 0x10 ; Call video interrupt
RET
msg db "Second stage loaded, and Gbowne1 stinks.", 0
; 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
; Setup disk parameters
; ... (set CH, CL, DH, DL for LBA, set DX for drive number)
; Calculate load address for kernel
; ... (set ES:BX to the target memory address)
; Read sectors from disk into memory
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

View File

@ -1,85 +1,83 @@
#include "cpu.h" #include "cpu.h"
// Function to read a 32-bit value from a CPU register // Function to read a 32-bit value from a CPU register
uint32_t read_register(uint8_t reg) uint32_t read_register(uint8_t reg) {
{ uint32_t value;
uint32_t value; __asm__ volatile("mov %0, %%" : "+r"(value) : "c"(reg));
__asm__ volatile("mov %0, %%" + reg : "=r"(value)); return value;
return value; }
}
// Function to write a 32-bit value to a CPU register
// Function to write a 32-bit value to a CPU register void write_register(uint8_t reg, uint32_t value) {
void write_register(uint8_t reg, uint32_t value) __asm__ volatile("mov %0, %%" : : "c"(reg), "r"(value));
{ }
__asm__ volatile("mov %0, %%" + reg : : "r"(value));
} // Function to read the value of the CR0 register
uint32_t read_cr0()
// Function to read the value of the CR0 register {
uint32_t read_cr0() uint32_t value;
{ __asm__ volatile("mov %%cr0, %0" : "=r"(value));
uint32_t value; return value;
__asm__ volatile("mov %%cr0, %0" : "=r"(value)); }
return value;
} // Function to write a value to the CR0 register
void write_cr0(uint32_t value)
// Function to write a value to the CR0 register {
void write_cr0(uint32_t value) __asm__ volatile("mov %0, %%cr0" : : "r"(value));
{ }
__asm__ volatile("mov %0, %%cr0" : : "r"(value));
} // Function to switch from real mode to protected mode
void switch_to_protected_mode()
// Function to switch from real mode to protected mode {
void switch_to_protected_mode() uint32_t cr0 = read_cr0();
{ cr0 |= 0x1; // Set the PE bit to switch to protected mode
uint32_t cr0 = read_cr0(); write_cr0(cr0);
cr0 |= 0x1; // Set the PE bit to switch to protected mode }
write_cr0(cr0);
} // Write a byte to a port
void outb(uint16_t port, uint8_t value)
// Write a byte to a port {
void outb(uint16_t port, uint8_t value) __asm__ volatile ("outb %0, %1" : : "a"(value), "Nd"(port));
{ }
__asm__ volatile ("outb %0, %1" : : "a"(value), "Nd"(port));
} // Read a byte from a port
uint8_t inb(uint16_t port)
// Read a byte from a port {
uint8_t inb(uint16_t port) uint8_t value;
{ __asm__ volatile ("inb %1, %0" : "=a"(value) : "Nd"(port));
uint8_t value; return value;
__asm__ volatile ("inb %1, %0" : "=a"(value) : "Nd"(port)); }
return value;
} // Write a word to a port
void outw(uint16_t port, uint16_t value)
// Write a word to a port {
void outw(uint16_t port, uint16_t value) __asm__ volatile ("outw %0, %1" : : "a"(value), "Nd"(port));
{ }
__asm__ volatile ("outw %0, %1" : : "a"(value), "Nd"(port));
} // Read a word from a port
uint16_t inw(uint16_t port)
// Read a word from a port {
uint16_t inw(uint16_t port) uint16_t value;
{ __asm__ volatile ("inw %1, %0" : "=a"(value) : "Nd"(port));
uint16_t value; return value;
__asm__ volatile ("inw %1, %0" : "=a"(value) : "Nd"(port)); }
return value;
} // Write a double word to a port
void outl(uint16_t port, uint32_t value)
// Write a double word to a port {
void outl(uint16_t port, uint32_t value) __asm__ volatile ("outl %0, %1" : : "a"(value), "Nd"(port));
{ }
__asm__ volatile ("outl %0, %1" : : "a"(value), "Nd"(port));
} // Read a double word from a port
uint32_t inl(uint16_t port)
// Read a double word from a port {
uint32_t inl(uint16_t port) uint32_t value;
{ __asm__ volatile ("inl %1, %0" : "=a"(value) : "Nd"(port));
uint32_t value; return value;
__asm__ volatile ("inl %1, %0" : "=a"(value) : "Nd"(port)); }
return value;
} // Execute the CPUID instruction
void cpuid(uint32_t code, uint32_t *a, uint32_t *d)
// Execute the CPUID instruction {
void cpuid(uint32_t code, uint32_t *a, uint32_t *d) __asm__ volatile ("cpuid" : "=a"(*a), "=d"(*d) : "a"(code) : "ecx", "ebx");
{ }
__asm__ volatile ("cpuid" : "=a"(*a), "=d"(*d) : "a"(code) : "ecx", "ebx");
}