mirror of
https://github.com/gbowne1/ClassicOS.git
synced 2024-11-21 22:06:51 -08:00
Trying to fix the boot2.asm second stage bootloader
This commit is contained in:
parent
19b61da1af
commit
8e7cdce87d
BIN
.vscode/browse.vc.db
vendored
BIN
.vscode/browse.vc.db
vendored
Binary file not shown.
BIN
.vscode/browse.vc.db-shm
vendored
BIN
.vscode/browse.vc.db-shm
vendored
Binary file not shown.
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@ -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}",
|
||||||
|
@ -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
|
168
src/cpu/cpu.c
168
src/cpu/cpu.c
@ -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");
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user