mirror of
https://github.com/gbowne1/ClassicOS.git
synced 2025-10-13 05:05:07 -07:00
fixing the keyboard and bootloader so that its 2 stage again
This commit is contained in:
@@ -1,67 +1,230 @@
|
|||||||
|
; ==============================================================================
|
||||||
|
; boot.asm - First Stage Bootloader (CHS Based)
|
||||||
|
; ==============================================================================
|
||||||
|
|
||||||
[BITS 16]
|
[BITS 16]
|
||||||
[ORG 0x7C00]
|
[ORG 0x7C00]
|
||||||
|
|
||||||
start:
|
start:
|
||||||
cli
|
cli ; Disable interrupts
|
||||||
|
|
||||||
|
mov [bootdev], dl ; Save boot device number (from BIOS in DL)
|
||||||
|
|
||||||
|
; Setup stack safely below EBDA area (choose 0x0000:0x7A00)
|
||||||
|
xor ax, ax ; AX = 0
|
||||||
|
mov ss, ax ; Stack segment = 0x0000
|
||||||
|
mov sp, 0x7A00 ; Stack offset = 0x7A00
|
||||||
|
|
||||||
|
; Initialize DS, ES for zero-based segments
|
||||||
xor ax, ax
|
xor ax, ax
|
||||||
mov ds, ax
|
mov ds, ax
|
||||||
mov es, ax
|
mov es, ax
|
||||||
mov ss, ax
|
|
||||||
mov sp, 0x7C00
|
|
||||||
|
|
||||||
|
; Load second-stage bootloader (boot1.asm) to 0x7E00
|
||||||
|
mov si, 0x7E00 ; Destination offset (ES already zero, so physical 0x7E00)
|
||||||
|
mov al, 1 ; Number of sectors to read (adjust if needed)
|
||||||
|
mov cl, 1 ; Starting sector (CHS - sector number, 1-based)
|
||||||
|
call read_chs
|
||||||
|
jc disk_error ; Jump if carry set (read error)
|
||||||
|
|
||||||
|
; Load kernel to 0x100000 (1 MB)
|
||||||
|
mov si, 0x0000 ; Destination offset
|
||||||
|
mov ax, 0x1000 ; ES = 0x1000 (0x1000:0x0000 = 1 MB)
|
||||||
|
mov es, ax
|
||||||
|
xor bx, bx
|
||||||
|
mov al, 16 ; Number of sectors for kernel (example)
|
||||||
|
mov cl, 2 ; Starting sector (adjust as per your disk layout)
|
||||||
|
call read_chs
|
||||||
|
jc disk_error
|
||||||
|
|
||||||
|
; Memory Validation: Verify checksum of second stage bootloader
|
||||||
|
mov si, 0x7E00 ; Start of second stage
|
||||||
|
mov cx, 512 ; Size in bytes (adjust if more sectors loaded)
|
||||||
|
call verify_checksum
|
||||||
|
jc disk_error ; Jump if checksum fails
|
||||||
|
|
||||||
|
; Enable A20 line
|
||||||
call enable_a20
|
call enable_a20
|
||||||
|
jc a20_error ; Jump if A20 enable fails
|
||||||
|
|
||||||
|
; Setup Global Descriptor Table
|
||||||
call setup_gdt
|
call setup_gdt
|
||||||
|
|
||||||
|
; Switch to protected mode and jump to second stage at 0x08:0x7E00
|
||||||
call switch_to_pm
|
call switch_to_pm
|
||||||
|
|
||||||
; ----------------------
|
disk_error:
|
||||||
; A20 Gate Enable (Fast method)
|
mov si, disk_error_msg
|
||||||
|
call print_string_16
|
||||||
|
jmp halt
|
||||||
|
|
||||||
|
a20_error:
|
||||||
|
mov si, a20_error_msg
|
||||||
|
call print_string_16
|
||||||
|
jmp halt
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------
|
||||||
|
; Verify Checksum Routine
|
||||||
|
; Uses SI = start address, CX = byte count
|
||||||
|
; Simple XOR checksum over bytes, expects result 0
|
||||||
|
|
||||||
|
verify_checksum:
|
||||||
|
push ax
|
||||||
|
push bx
|
||||||
|
push di
|
||||||
|
mov di, si
|
||||||
|
xor al, al
|
||||||
|
xor bx, bx
|
||||||
|
|
||||||
|
.verify_loop:
|
||||||
|
lodsb
|
||||||
|
xor bl, al
|
||||||
|
loop .verify_loop
|
||||||
|
|
||||||
|
test bl, bl
|
||||||
|
jz .checksum_ok
|
||||||
|
stc ; Set carry on checksum error
|
||||||
|
jmp .done
|
||||||
|
|
||||||
|
.checksum_ok:
|
||||||
|
clc ; Clear carry on success
|
||||||
|
|
||||||
|
.done:
|
||||||
|
pop di
|
||||||
|
pop bx
|
||||||
|
pop ax
|
||||||
|
ret
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------
|
||||||
|
; CHS Disk Read Routine
|
||||||
|
; AL = number of sectors
|
||||||
|
; CL = starting sector (1-based)
|
||||||
|
; SI = destination offset (Segment:ES already set)
|
||||||
|
read_chs:
|
||||||
|
pusha
|
||||||
|
push dx
|
||||||
|
mov cx, 5
|
||||||
|
.retry:
|
||||||
|
mov ah, 0x02 ; BIOS read sector
|
||||||
|
mov dl, [bootdev] ; Drive number
|
||||||
|
int 0x13
|
||||||
|
|
||||||
|
jc .error ; Carry flag set = error
|
||||||
|
pop dx
|
||||||
|
popa
|
||||||
|
ret
|
||||||
|
|
||||||
|
.error:
|
||||||
|
dec cx
|
||||||
|
jz disk_error
|
||||||
|
xor ah, ah
|
||||||
|
int 0x13
|
||||||
|
jmp .retry
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------
|
||||||
enable_a20:
|
enable_a20:
|
||||||
|
; Fast A20 gate method
|
||||||
in al, 0x92
|
in al, 0x92
|
||||||
or al, 0x02
|
or al, 0x02
|
||||||
out 0x92, al
|
out 0x92, al
|
||||||
|
; Fallback method (keyboard controller)
|
||||||
|
jc .fallbackenable_a20:
|
||||||
|
; Fast A20 method
|
||||||
|
in al, 0x92
|
||||||
|
or al, 0x02
|
||||||
|
and al, 0xFE ; Clear bit 0 to avoid fast A20 issues on some systems
|
||||||
|
out 0x92, al
|
||||||
|
; Verify A20
|
||||||
|
call check_a20
|
||||||
|
jnc .done
|
||||||
|
; Fallback method
|
||||||
|
mov al, 0xAD
|
||||||
|
out 0x64, al
|
||||||
|
; ... (rest of keyboard controller code)
|
||||||
|
.done:
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; ----------------------
|
check_a20:
|
||||||
; Set up a minimal GDT
|
in al, 0x64 ; Read keyboard controller status
|
||||||
|
test al, 0x02 ; Check if input buffer is full
|
||||||
|
jnz check_a20 ; Wait until empty
|
||||||
|
|
||||||
|
mov al, 0xD0 ; Command: read output port
|
||||||
|
out 0x64, al
|
||||||
|
|
||||||
|
.wait_output:
|
||||||
|
in al, 0x60 ; Read output port value
|
||||||
|
test al, 0x02 ; Check A20 gate bit (bit 1)
|
||||||
|
jnz .a20_enabled ; If set, A20 enabled
|
||||||
|
|
||||||
|
xor al, al ; Clear carry to indicate failure
|
||||||
|
stc ; Set carry for failure, jc will jump
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
.a20_enabled:
|
||||||
|
clc ; Clear carry flag to indicate success
|
||||||
|
ret
|
||||||
|
|
||||||
|
.fallback:
|
||||||
|
mov al, 0xAD
|
||||||
|
out 0x64, al
|
||||||
|
mov al, 0xD0
|
||||||
|
out 0x64, al
|
||||||
|
in al, 0x60
|
||||||
|
or al, 0x02
|
||||||
|
mov al, 0xD1
|
||||||
|
out 0x64, al
|
||||||
|
mov al, 0xAE
|
||||||
|
out 0x64, al
|
||||||
|
ret
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------
|
||||||
gdt_start:
|
gdt_start:
|
||||||
dq 0x0000000000000000 ; null descriptor
|
dq 0x0000000000000000 ; Null descriptor
|
||||||
dq 0x00CF9A000000FFFF ; code segment descriptor
|
dq 0x00CF9A000000FFFF ; 32-bit code segment (selector 0x08)
|
||||||
dq 0x00CF92000000FFFF ; data segment descriptor
|
dq 0x00CF92000000FFFF ; 32-bit data segment (selector 0x10)
|
||||||
|
dq 0x00009A000000FFFF ; 16-bit code segment for real mode (selector 0x18)
|
||||||
|
|
||||||
gdt_descriptor:
|
gdt_descriptor:
|
||||||
dw gdt_end - gdt_start - 1 ; size of GDT
|
dw gdt_end - gdt_start - 1
|
||||||
dd gdt_start ; address of GDT
|
dd gdt_start
|
||||||
|
|
||||||
gdt_end:
|
gdt_end:
|
||||||
|
|
||||||
setup_gdt:
|
setup_gdt:
|
||||||
lgdt [gdt_descriptor]
|
lgdt [gdt_descriptor]
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; ----------------------
|
; ----------------------------------------------------------------
|
||||||
; Switch to Protected Mode
|
|
||||||
switch_to_pm:
|
switch_to_pm:
|
||||||
cli
|
cli
|
||||||
mov eax, cr0
|
mov eax, cr0
|
||||||
or eax, 1
|
or eax, 1
|
||||||
mov cr0, eax
|
mov cr0, eax
|
||||||
jmp 0x08:protected_mode_entry
|
jmp 0x08:0x7E00
|
||||||
; ----------------------
|
|
||||||
; 32-bit Protected Mode Entry Point
|
|
||||||
[BITS 32]
|
|
||||||
protected_mode_entry:
|
|
||||||
mov ax, 0x10 ; data segment selector
|
|
||||||
mov ds, ax
|
|
||||||
mov es, ax
|
|
||||||
mov fs, ax
|
|
||||||
mov gs, ax
|
|
||||||
mov ss, ax
|
|
||||||
mov esp, 0x90000
|
|
||||||
|
|
||||||
; Kernel is assumed to be loaded at 0x100000
|
; ----------------------------------------------------------------
|
||||||
jmp 0x08:0x100000
|
print_string_16:
|
||||||
|
.loop:
|
||||||
|
lodsb
|
||||||
|
or al, al
|
||||||
|
jz .done
|
||||||
|
mov ah, 0x0E
|
||||||
|
int 0x10
|
||||||
|
jmp .loop
|
||||||
|
.done:
|
||||||
|
ret
|
||||||
|
|
||||||
|
disk_error_msg db "Disk error!", 0
|
||||||
|
a20_error_msg db "A20 error!", 0
|
||||||
|
|
||||||
|
halt:
|
||||||
|
cli
|
||||||
|
hlt
|
||||||
|
|
||||||
|
bootdev db 0
|
||||||
|
sectors_per_track dw 63
|
||||||
|
heads_per_cylinder dw 255
|
||||||
|
|
||||||
; ----------------------
|
|
||||||
; Boot signature
|
|
||||||
times 510 - ($ - $$) db 0
|
times 510 - ($ - $$) db 0
|
||||||
dw 0xAA55
|
dw 0xAA55
|
||||||
|
Binary file not shown.
182
bootloader/boot1.asm
Normal file
182
bootloader/boot1.asm
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
; ==============================================================================
|
||||||
|
; boot1.asm - Second Stage Bootloader (Fixed Real Mode Transition)
|
||||||
|
; ==============================================================================
|
||||||
|
|
||||||
|
[BITS 32]
|
||||||
|
global _start
|
||||||
|
extern kmain
|
||||||
|
|
||||||
|
_start:
|
||||||
|
; Set up segments
|
||||||
|
mov ax, 0x10
|
||||||
|
mov ds, ax
|
||||||
|
mov es, ax
|
||||||
|
mov fs, ax
|
||||||
|
mov gs, ax
|
||||||
|
mov ss, ax
|
||||||
|
|
||||||
|
; Stack (must be identity-mapped)
|
||||||
|
mov esp, 0x90000
|
||||||
|
|
||||||
|
; CPU Feature Detection: check CPUID support
|
||||||
|
pushfd ; Save flags
|
||||||
|
pop eax
|
||||||
|
mov ecx, eax
|
||||||
|
xor eax, 1 << 21 ; Flip ID bit
|
||||||
|
push eax
|
||||||
|
popfd
|
||||||
|
pushfd
|
||||||
|
pop eax
|
||||||
|
xor eax, ecx
|
||||||
|
jz .no_cpuid ; CPUID unsupported if no change
|
||||||
|
|
||||||
|
; CPUID supported, verify features
|
||||||
|
mov eax, 1
|
||||||
|
cpuid
|
||||||
|
; Check for paging support (bit 31 of edx)
|
||||||
|
test edx, 1 << 31
|
||||||
|
jz .no_paging_support
|
||||||
|
|
||||||
|
; Additional CPU feature checks could be added here
|
||||||
|
|
||||||
|
jmp .cpuid_check_done
|
||||||
|
|
||||||
|
.no_cpuid:
|
||||||
|
mov si, no_cpuid_msg
|
||||||
|
call print_string_16
|
||||||
|
jmp halt
|
||||||
|
|
||||||
|
.no_paging_support:
|
||||||
|
mov si, no_paging_msg
|
||||||
|
call print_string_16
|
||||||
|
jmp halt
|
||||||
|
|
||||||
|
.cpuid_check_done:
|
||||||
|
|
||||||
|
; Temporarily switch back to real mode
|
||||||
|
cli
|
||||||
|
mov eax, cr0
|
||||||
|
and eax, 0x7FFFFFFE ; Clear PE & PG bits
|
||||||
|
mov cr0, eax
|
||||||
|
jmp 0x18:real_mode_entry
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------
|
||||||
|
[BITS 16]
|
||||||
|
real_mode_entry:
|
||||||
|
; Real mode for BIOS access (E820, VESA)
|
||||||
|
xor ax, ax
|
||||||
|
mov es, ax
|
||||||
|
|
||||||
|
; VESA call
|
||||||
|
mov di, VbeControllerInfo
|
||||||
|
mov ax, 0x4F00
|
||||||
|
int 0x10
|
||||||
|
jc vesa_error
|
||||||
|
|
||||||
|
; E820 memory map
|
||||||
|
xor ebx, ebx
|
||||||
|
mov edx, 0x534D4150
|
||||||
|
mov di, MemoryMapBuffer
|
||||||
|
mov [MemoryMapEntries], dword 0
|
||||||
|
|
||||||
|
.e820_loop:
|
||||||
|
mov eax, 0xE820
|
||||||
|
mov ecx, 24
|
||||||
|
int 0x15
|
||||||
|
jc e820_error
|
||||||
|
add di, 24
|
||||||
|
inc dword [MemoryMapEntries]
|
||||||
|
test ebx, ebx
|
||||||
|
jnz .e820_loop
|
||||||
|
jmp .e820_done
|
||||||
|
|
||||||
|
e820_error:
|
||||||
|
mov si, e820_error_msg
|
||||||
|
call print_string_16
|
||||||
|
jmp halt
|
||||||
|
|
||||||
|
vesa_error:
|
||||||
|
mov si, vesa_error_msg
|
||||||
|
call print_string_16
|
||||||
|
|
||||||
|
; Fallback: set VGA text mode 3 and continue
|
||||||
|
mov ah, 0x00 ; BIOS Set Video Mode function
|
||||||
|
mov al, 0x03 ; VGA 80x25 text mode
|
||||||
|
int 0x10
|
||||||
|
|
||||||
|
; Clear screen
|
||||||
|
mov ah, 0x06 ; Scroll up function
|
||||||
|
mov al, 0 ; Clear entire screen
|
||||||
|
mov bh, 0x07 ; Text attribute (gray on black)
|
||||||
|
mov cx, 0 ; Upper-left corner
|
||||||
|
mov dx, 0x184F ; Lower-right corner
|
||||||
|
int 0x10
|
||||||
|
|
||||||
|
jmp .e820_done ; Continue booting without VESA graphics
|
||||||
|
|
||||||
|
.e820_done:
|
||||||
|
; Back to protected mode
|
||||||
|
cli
|
||||||
|
mov eax, cr0
|
||||||
|
or eax, 1
|
||||||
|
mov cr0, eax
|
||||||
|
jmp 0x08:protected_entry
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------
|
||||||
|
print_string_16:
|
||||||
|
.loop:
|
||||||
|
lodsb
|
||||||
|
or al, al
|
||||||
|
jz .done
|
||||||
|
mov ah, 0x0E
|
||||||
|
int 0x10
|
||||||
|
jmp .loop
|
||||||
|
.done:
|
||||||
|
ret
|
||||||
|
|
||||||
|
e820_error_msg db "E820 Failed!", 0
|
||||||
|
vesa_error_msg db "VESA Failed!", 0
|
||||||
|
no_cpuid_msg db "No CPUID support detected!", 0
|
||||||
|
no_paging_msg db "CPU lacks paging support!", 0
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------
|
||||||
|
[BITS 32]
|
||||||
|
protected_entry:
|
||||||
|
; Paging setup
|
||||||
|
xor eax, eax
|
||||||
|
mov edi, page_directory
|
||||||
|
mov ecx, 1024
|
||||||
|
rep stosd
|
||||||
|
mov edi, page_table
|
||||||
|
rep stosd
|
||||||
|
|
||||||
|
mov dword [page_directory], page_table | 0x3
|
||||||
|
mov ecx, 1024
|
||||||
|
mov edi, page_table
|
||||||
|
mov eax, 0x00000003
|
||||||
|
.fill_pages:
|
||||||
|
mov [edi], eax
|
||||||
|
add eax, 0x1000
|
||||||
|
add edi, 4
|
||||||
|
loop .fill_pages
|
||||||
|
|
||||||
|
mov eax, page_directory
|
||||||
|
mov cr3, eax
|
||||||
|
mov eax, cr0
|
||||||
|
or eax, 0x80000000
|
||||||
|
mov cr0, eax
|
||||||
|
|
||||||
|
jmp kmain
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------
|
||||||
|
; Data buffers and variables must be appropriately defined in your data section
|
||||||
|
MemoryMapBuffer times 128 db 0 ; 128*24 bytes reserved for E820 memory map (adjust size as needed)
|
||||||
|
MemoryMapEntries dd 0
|
||||||
|
VbeControllerInfo times 512 db 0 ; Buffer for VESA controller info (adjust size as needed)
|
||||||
|
|
||||||
|
; Define page directory and page table aligned as needed (in your data section)
|
||||||
|
align 4096
|
||||||
|
page_directory times 1024 dd 0
|
||||||
|
align 4096
|
||||||
|
page_table times 1024 dd 0
|
||||||
|
|
@@ -1,10 +1,9 @@
|
|||||||
ENTRY(start)
|
ENTRY(kmain)
|
||||||
|
|
||||||
SECTIONS {
|
SECTIONS {
|
||||||
. = 1M;
|
. = 1M;
|
||||||
|
|
||||||
.text : {
|
.text : {
|
||||||
*(.multiboot)
|
|
||||||
*(.text*)
|
*(.text*)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -20,34 +20,40 @@ static const char scancode_map[128] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Interrupt handler for IRQ1
|
// Interrupt handler for IRQ1
|
||||||
void keyboard_callback() {
|
void keyboard_callback(void) {
|
||||||
uint8_t scancode = inb(KEYBOARD_DATA_PORT);
|
uint8_t scancode = inb(0x60);
|
||||||
|
|
||||||
// Ignore key releases (scancodes with high bit set)
|
// Only handle key press (ignore key release)
|
||||||
if (scancode & 0x80)
|
if (!(scancode & 0x80)) {
|
||||||
return;
|
char c = scancode_map[scancode];
|
||||||
|
if (c && buffer_index < sizeof(key_buffer) - 1) {
|
||||||
char c = scancode_map[scancode];
|
key_buffer[buffer_index++] = c;
|
||||||
if (c && buffer_index < sizeof(key_buffer) - 1) {
|
terminal_putchar(c);
|
||||||
key_buffer[buffer_index++] = c;
|
}
|
||||||
terminal_putchar(c); // Echo to terminal (optional)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send End of Interrupt (EOI) to the PIC
|
||||||
|
outb(0x20, 0x20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void keyboard_init() {
|
void keyboard_init() {
|
||||||
register_interrupt_handler(33, keyboard_callback); // IRQ1 = int 33 (0x21)
|
register_interrupt_handler(33, keyboard_callback); // IRQ1 = int 33 (0x21)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blocking read (returns one char)
|
// Blocking read (returns one char)
|
||||||
char keyboard_get_char() {
|
char keyboard_get_char() {
|
||||||
while (buffer_index == 0);
|
while (buffer_index == 0); // Busy wait
|
||||||
char c = key_buffer[0];
|
|
||||||
|
|
||||||
// Shift buffer left
|
char c;
|
||||||
|
__asm__ __volatile__("cli");
|
||||||
|
c = key_buffer[0];
|
||||||
for (uint8_t i = 1; i < buffer_index; i++) {
|
for (uint8_t i = 1; i < buffer_index; i++) {
|
||||||
key_buffer[i - 1] = key_buffer[i];
|
key_buffer[i - 1] = key_buffer[i];
|
||||||
}
|
}
|
||||||
buffer_index--;
|
buffer_index--;
|
||||||
|
__asm__ __volatile__("sti");
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
#include "kmalloc.h"
|
#include "kmalloc.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "keyboard.h"
|
||||||
|
|
||||||
#define LPT1 0x378
|
#define LPT1 0x378
|
||||||
|
|
||||||
@@ -54,6 +55,10 @@ void kmain(void) {
|
|||||||
timer_init(100); // 100 Hz (10 ms interval)
|
timer_init(100); // 100 Hz (10 ms interval)
|
||||||
serial_write("Timer initialized.\n");
|
serial_write("Timer initialized.\n");
|
||||||
|
|
||||||
|
terminal_write("Initializing keyboard...\n");
|
||||||
|
keyboard_init();
|
||||||
|
serial_write("Keyboard initialized.\n");
|
||||||
|
|
||||||
terminal_write("Getting memory map...\n");
|
terminal_write("Getting memory map...\n");
|
||||||
memory_map_entry_t mmap[32];
|
memory_map_entry_t mmap[32];
|
||||||
uint32_t mmap_size = get_memory_map(mmap, 32);
|
uint32_t mmap_size = get_memory_map(mmap, 32);
|
||||||
|
@@ -4,17 +4,20 @@
|
|||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
#include "stdio.h"
|
#include "stdio.h"
|
||||||
|
|
||||||
static uint32_t tick = 0;
|
static volatile uint32_t tick = 0;
|
||||||
|
|
||||||
void timer_callback(void) {
|
void timer_callback(void) {
|
||||||
tick++;
|
tick++;
|
||||||
|
|
||||||
// Print every 100 ticks for debugging purposes
|
|
||||||
if (tick % 100 == 0) {
|
if (tick % 100 == 0) {
|
||||||
char tick_msg[50];
|
char buf[16];
|
||||||
snprintf(tick_msg, sizeof(tick_msg), "Tick count: %u\n", tick);
|
itoa(tick, buf, 10);
|
||||||
terminal_write(tick_msg);
|
terminal_write("Tick count: ");
|
||||||
|
terminal_write(buf);
|
||||||
|
terminal_write("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
outb(0x20, 0x20); // EOI to PIC
|
||||||
}
|
}
|
||||||
|
|
||||||
void timer_init(uint32_t frequency) {
|
void timer_init(uint32_t frequency) {
|
||||||
@@ -29,4 +32,4 @@ void timer_init(uint32_t frequency) {
|
|||||||
|
|
||||||
uint32_t timer_get_ticks(void) {
|
uint32_t timer_get_ticks(void) {
|
||||||
return tick;
|
return tick;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user