Interrupts dont work and I dont know why

This commit is contained in:
c0repwn3r 2022-05-09 09:45:06 -04:00
commit dacf0315f3
Signed by: core
GPG Key ID: FDBF740DADDCEECF
59 changed files with 1531 additions and 0 deletions

56
Makefile Normal file
View File

@ -0,0 +1,56 @@
# $@ = target file
# $< = first dependency
# $^ = all dependencies
GDB = gdb
C_FILES = $(shell find src/ -type f -name '*.c')
CO_FILES = $(patsubst src/%.c, obj/%.o, $(C_FILES))
ASM_FILES = $(shell find src/kernel/ -type f -name '*.asm')
AO_FILES = $(patsubst src/kernel/%.asm, obj/kernel/%.o, $(ASM_FILES))
ABIN_FILES = $(patsubst src/%.asm, bin/%.bin, $(ASM_FILES))
os-image.bin: bin/boot.bin bin/kernel.bin
cat $^ > $@
bin/boot.bin: src/boot/boot.asm bin/kernel.bin .FORCE
sed -i.orig "s@CH_REPLACE_BOOTSECTORCOUNT@$(shell ./getinblocks.py $(shell du -b "bin/kernel.bin" | cut -f 1))@g" src/boot/kernel.asm
nasm -Isrc/boot/ $< -f bin -o $@
mv src/boot/kernel.asm.orig src/boot/kernel.asm
.FORCE:
bin/kernel.bin: obj/kernel/entry.o ${CO_FILES} ${AO_FILES}
i386-elf-ld -o $@ -Ttext 0x1000 $^ --oformat binary
kernel.elf: obj/kernel/entry.o ${CO_FILES} ${AO_FILES}
i386-elf-ld -o $@ -Ttext 0x1000 $^
run: clean os-image.bin
qemu-system-x86_64 -hdd os-image.bin
debug: clean os-image.bin kernel.elf
qemu-system-x86_64 -s -S -hdd os-image.bin &
${GDB} os-image.bin -ex "symbol-file kernel.elf" -ex "target remote localhost:1234"
obj/%.o: src/%.c
mkdir -p "$(@D)"
i386-elf-gcc -g -ffreestanding -c $< -o $@
obj/%.o: src/%.asm
mkdir -p "$(@D)"
nasm -f elf $< -o $@
bin/%.bin: src/%.asm
mkdir -p "$(@D)"
nasm -f bin $< -o $@
clean:
find obj -type f -name '*.o' -exec rm {} +
find obj -type f -name '*.bin' -exec rm {} +
find bin -type f -name '*.o' -exec rm {} +
find bin -type f -name '*.bin' -exec rm {} +
find . -type f -name '*.dis' -exec rm {} +
rm -f kernel.elf

BIN
bin/boot.bin Normal file

Binary file not shown.

BIN
bin/kernel.bin Executable file

Binary file not shown.

4
getinblocks.py Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/python3
import sys, math
intg = int(sys.argv[1])
print(int(math.ceil(intg/512)), end='')

BIN
obj/kernel/entry.o Normal file

Binary file not shown.

BIN
obj/kernel/kernel.o Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
obj/kernel/print.o Normal file

Binary file not shown.

BIN
obj/kernel/strings.o Normal file

Binary file not shown.

BIN
obj/kernel/util.o Normal file

Binary file not shown.

28
old_src/16bit/boot.asm Normal file
View File

@ -0,0 +1,28 @@
[org 0x7c00]
mov bx, HELLO
call print
call print_nl
mov bx, GOODBYE
call print
call print_nl
mov dx, 0x12fe
call print_hex
jmp $
%include "print.asm"
%include "print_hex.asm"
; data
HELLO:
db 'Hello, world!', 0
GOODBYE:
db 'Bye bye!', 0
times 510-($-$$) db 0
dw 0xaa55

40
old_src/16bit/disk.asm Normal file
View File

@ -0,0 +1,40 @@
; load 'dh' sectors from drive 'dl' into ES:BX
disk_load:
pusha
push dx ; save dx to stack for later use, as it needs to be overwritten
mov ah, 0x02 ; ah: int 0x13 function. 0x02 = 'read'
mov al, dh ; al: number of sectors to read (0x01 .. 0x80)
mov cl, 0x02 ; cl: sector (0x01 .. 0x11). 0x01 is boot sector, 0x02 is first 'avaliable' sector
mov ch, 0x00 ; ch: cylinder (0x0 .. 0x3FF, upper 2 bits in 'cl')
; dl: drive number. caller sets it as param and gets it from bios
; 0 = floppy, 1 = floppy2, 0x80 = hdd, 0x81 = hdd2
mov dh, 0x00 ; dh: head number (0x0 .. 0xF)
; [es:bx] pointer to buf where data is stored
; caller sets it up, and is standard location for int 13h
int 13h
jc disk_error ; if error (in carry)
pop dx
cmp al, dh ; al is # of sectors read. compare it
jne sectors_error
popa
ret
disk_error:
mov bx, DISK_ERROR
call print
call print_nl
mov dh, ah ; ah = error code, dl = disk drive that caused error
call print_hex
sectors_error:
mov bx, SECTORS_ERROR
call print
disk_loop:
jmp $
DISK_ERROR: db "Disk read error", 0
SECTORS_ERROR: db "Incorrect number of sectors read", 0

View File

@ -0,0 +1,28 @@
[org 0x7c00]
mov bp, 0x8000 ; set stack somewhere far away
mov sp, bp
mov bx, 0x9000 ; es:bx = 0x0000:0x9000 = 0x09000
mov dh, 2 ; read 2 sectors
; bios sets dl for disk number
call disk_load
mov dx, [0x9000] ; get first loaded word, 0xdada
call print_hex
call print_nl
mov dx, [0x9000 + 512] ; first word from second loaded sector, 0xface
call print_hex
jmp $
%include "print.asm"
%include "print_hex.asm"
%include "disk.asm"
times 510 - ($-$$) db 0
dw 0xaa55
; boot sector passed, now its sector 2
times 256 dw 0xdada ; sector 2
times 256 dw 0xface ; sector 3

View File

@ -0,0 +1,26 @@
mov ah, 0x0e
mov al, [the_secret]
int 0x10 ; shouldnt work
mov bx, 0x7c0 ; segment is automatically << 4
mov ds, bx ; set data segment offset to 0x7c0
; all memory references will be offset by ds implicitly
mov al, [the_secret]
int 0x10
mov al, [es:the_secret]
int 0x10
mov bx, 0x7c0
mov es, bx
mov al, [es:the_secret]
int 0x10
jmp $
the_secret:
db "X"
times 510 - ($-$$) db 0
dw 0xaa55

31
old_src/32bit_gdt.asm Normal file
View File

@ -0,0 +1,31 @@
gdt_start: ; use labels to compute sizes and jumps
; gdt starts with 8 byte null
dd 0x0
dd 0x0
; GDT for code segment, base = 0x00000000, length = 0xfffff
gdt_code:
dw 0xffff ; segment length
dw 0x0 ; segment base
db 0x0 ; segment base
db 10011010b ; flags
db 11001111b ; flags + segment length
db 0x0 ; segment base
; GDT for data segment
gdt_data:
dw 0xffff
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_start - 1 ; size, always 1 less than what it actually is
dd gdt_start ; address
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start

22
old_src/32bit_jump.asm Normal file
View File

@ -0,0 +1,22 @@
[bits 16]
enter_protected:
cli ; Disable interrupts
lgdt [gdt_descriptor] ; load the GDT
mov eax, cr0
or eax, 0x1 ; set 32-bit mode bit
mov cr0, eax
jmp CODE_SEG:init_protected ; far jump into a different segment
[bits 32]
init_protected: ; now in 32bit
mov ax, DATA_SEG ; update segment registers
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ebp, 0x90000 ; update stack to top of free space
mov esp, ebp
call BEGIN_PROTECTED ; call known label with useful code

27
old_src/32bit_main.asm Normal file
View File

@ -0,0 +1,27 @@
[org 0x7c00] ; bootloader offset
mov bp, 0x9000 ; set stack
mov sp, bp
mov bx, MSG_REAL_MODE
call print ; will be written after bios messages
call enter_protected
jmp $ ; will never really be executed
%include "print.asm"
%include "32bit_gdt.asm"
%include "32bit_print.asm"
%include "32bit_jump.asm"
[bits 32]
BEGIN_PROTECTED: ; 32bit entry
mov ebx, MSG_PROT_MODE
call print_string_pm ; Will be written in top left
jmp $
MSG_REAL_MODE db "Welcome! Started in 16-bit protected mode"
MSG_PROT_MODE db "Hello, world! 32-bit mode initialized successfully"
; bootsector
times 510-($-$$) db 0
dw 0xaa55

26
old_src/32bit_print.asm Normal file
View File

@ -0,0 +1,26 @@
[bits 32]
; defining constants
VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f ; color byte
print_string_pm:
pusha
mov edx, VIDEO_MEMORY
print_string_pm_loop:
mov al, [ebx] ; [ebx] is address of char
mov ah, WHITE_ON_BLACK
cmp al, 0 ; is end of string?
je print_string_pm_done
mov [edx], ax ; store char + attribute in video memory
add ebx, 1 ; next char
add edx, 2 ; next video memory position
jmp print_string_pm_loop
print_string_pm_done:
popa
ret

3
old_src/function.c Normal file
View File

@ -0,0 +1,3 @@
int my_function() {
return 0xbaba;
}

7
old_src/functioncalls.c Normal file
View File

@ -0,0 +1,7 @@
void caller() {
my_func(0xdede);
}
int my_func(int arg) {
return arg;
}

View File

@ -0,0 +1,5 @@
loop:
jmp loop
times 510-($-$$) db 0
dw 0xaa55

View File

@ -0,0 +1,18 @@
mov ah, 0x0e ; enable TTY
mov al, 'H'
int 0x10
mov al, 'e'
int 0x10
mov al, 'l'
int 0x10
int 0x10
mov al, 'o'
int 0x10
mov al, '!'
int 0x10
jmp $
times 510 - ($-$$) db 0
dw 0xaa55

View File

@ -0,0 +1,27 @@
mov ah, 0x0e ; enable TTY
mov al, "1"
int 0x10
mov al, the_secret
int 0x10
mov al, "2"
int 0x10
mov al, [the_secret]
int 0x10
mov al, "3"
int 0x10
mov bx, the_secret
add bx, 0x7c00
mov al, [bx]
int 0x10
jmp $ ; infinite loop
the_secret:
; store 0x58 'X' right before zeropad
db "X"
times 510-($-$$) db 0
dw 0xaa55

View File

View File

@ -0,0 +1,38 @@
mov ah, 0x0e ; tty mode
mov bp, 0x8000 ; far away from 0x7c00, want to avoid overwriting ourself
mov sp, bp ; if stack empty, sp points to bp
push 'A'
push 'B'
push 'C'
; stack grows downwards
mov al, [0x7ffe] ; 0x8000 - 2
int 0x10
; you can only access stack top now
mov al, [0x8000]
int 0x10
; recover chars with pop
; you can onoly pop words, so you need an aux register to manipulate the lower byte
pop bx
mov al, bl
int 0x10
pop bx
mov al, bl
int 0x10
pop bx
mov al, bl
int 0x10
; pop'd stack is garbage now
mov al, [0x8000]
int 0x10
jmp $
times 510-($-$$) db 0
dw 0xaa55

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

33
old_src/print.asm Normal file
View File

@ -0,0 +1,33 @@
print:
pusha
; logic being implemented here:
; while ( string[i] != 0 ) { print string[i]; i++ }
start:
mov al, [bx]
cmp al, 0 ; check if al (byte we are printing) is a 0 (null byte)
je done ; if so, jump to done
; print with BIOS help
mov ah, 0x0e
int 0x10 ; char already in al
add bx, 1 ; increment pointer
jmp start ; repeat
done:
popa
ret
print_nl:
pusha
mov ah, 0x0e
mov al, 0x0a ; newline char
int 0x10
mov al, 0x0d ; carriage return
int 0x10
popa
ret

38
old_src/print_hex.asm Normal file
View File

@ -0,0 +1,38 @@
; data in dx
print_hex:
pusha
mov cx, 0 ; index var
hex_loop:
cmp cx, 4 ; loop 4 times
je end
; 1) convert last char of 'dx' to ascii
mov ax, dx ; ax is working register
and ax, 0x000f ; 0x1234 -> 0x0004
add al, 0x30 ; add 0x30 to N to convert it to ascii "n"
cmp al, 0x39 ; if > 9, add extra 8 to represent a-f
jle step2
add al, 7 ; A is ascii 64 instead of 58, 65-58 = 7
step2:
; 2) get correct pos of string to place char
; bx <- base address + string length - index
mov bx, HEX_OUT + 5
sub bx, cx ; cx: index
mov [bx], al ; copy ascii char on al to pos pointed by bx
ror dx, 4 ; 1234 - 4123 - 3412 - 2341 - 1234
add cx, 1
jmp hex_loop
end:
mov bx, HEX_OUT
call print
popa
ret
HEX_OUT:
db '0x0000', 0 ; reserve memory for string

BIN
os-image.bin Normal file

Binary file not shown.

39
src/boot/boot.asm Normal file
View File

@ -0,0 +1,39 @@
[org 0x7c00]
KERNEL_OFFSET equ 0x1000 ; Same one used while linking!
mov [BOOT_DRIVE], dl ; BIOS sets boot drive to 'dl' for us
mov bp, 0x9000
mov sp, bp
mov bx, MSG_REAL_MODE
call print
call print_nl
call load_kernel
call enable_protected
jmp $ ; never executed
%include "output/print.asm"
%include "output/print_hex.asm"
%include "disk/disk.asm"
%include "protected/gdt.asm"
%include "output/vga-print.asm"
%include "protected/protected-switch.asm"
%include "kernel.asm"
[bits 32]
BEGIN_PROTECTED:
mov ebx, MSG_PROT_MODE
call print_string_pm
call KERNEL_OFFSET ; give control to kernel
jmp $ ; infinite loop if kernel returns control to us
BOOT_DRIVE db 0
MSG_REAL_MODE db "llb: started, preparing protected mode initialization", 0
MSG_PROT_MODE db "llb: loaded protected mode successfully, jumping to llb2", 0
MSG_LOAD_KERNEL db "llb: loading kernel into memory at 0x1000", 0
times 510 - ($-$$) db 0
dw 0xaa55

40
src/boot/disk/disk.asm Normal file
View File

@ -0,0 +1,40 @@
; load 'dh' sectors from drive 'dl' into ES:BX
disk_load:
pusha
push dx ; save dx to stack for later use, as it needs to be overwritten
mov ah, 0x02 ; ah: int 0x13 function. 0x02 = 'read'
mov al, dh ; al: number of sectors to read (0x01 .. 0x80)
mov cl, 0x02 ; cl: sector (0x01 .. 0x11). 0x01 is boot sector, 0x02 is first 'avaliable' sector
mov ch, 0x00 ; ch: cylinder (0x0 .. 0x3FF, upper 2 bits in 'cl')
; dl: drive number. caller sets it as param and gets it from bios
; 0 = floppy, 1 = floppy2, 0x80 = hdd, 0x81 = hdd2
mov dh, 0x00 ; dh: head number (0x0 .. 0xF)
; [es:bx] pointer to buf where data is stored
; caller sets it up, and is standard location for int 13h
int 13h
jc disk_error ; if error (in carry)
pop dx
cmp al, dh ; al is # of sectors read. compare it
jne sectors_error
popa
ret
disk_error:
mov bx, DISK_ERROR
call print
call print_nl
mov dh, ah ; ah = error code, dl = disk drive that caused error
call print_hex
sectors_error:
mov bx, SECTORS_ERROR
call print
disk_loop:
jmp $
DISK_ERROR: db "Disk read error", 0
SECTORS_ERROR: db "Incorrect number of sectors read", 0

11
src/boot/kernel.asm Normal file
View File

@ -0,0 +1,11 @@
[bits 16]
load_kernel:
mov bx, MSG_LOAD_KERNEL
call print
call print_nl
mov bx, KERNEL_OFFSET ; Read from disk and store at 0x1000
mov dh, CH_REPLACE_BOOTSECTORCOUNT ; Populated with kernel sector count at build (see makefile)
mov dl, [BOOT_DRIVE]
call disk_load
ret

33
src/boot/output/print.asm Normal file
View File

@ -0,0 +1,33 @@
print:
pusha
; logic being implemented here:
; while ( string[i] != 0 ) { print string[i]; i++ }
start:
mov al, [bx]
cmp al, 0 ; check if al (byte we are printing) is a 0 (null byte)
je done ; if so, jump to done
; print with BIOS help
mov ah, 0x0e
int 0x10 ; char already in al
add bx, 1 ; increment pointer
jmp start ; repeat
done:
popa
ret
print_nl:
pusha
mov ah, 0x0e
mov al, 0x0a ; newline char
int 0x10
mov al, 0x0d ; carriage return
int 0x10
popa
ret

View File

@ -0,0 +1,38 @@
; data in dx
print_hex:
pusha
mov cx, 0 ; index var
hex_loop:
cmp cx, 4 ; loop 4 times
je end
; 1) convert last char of 'dx' to ascii
mov ax, dx ; ax is working register
and ax, 0x000f ; 0x1234 -> 0x0004
add al, 0x30 ; add 0x30 to N to convert it to ascii "n"
cmp al, 0x39 ; if > 9, add extra 8 to represent a-f
jle step2
add al, 7 ; A is ascii 64 instead of 58, 65-58 = 7
step2:
; 2) get correct pos of string to place char
; bx <- base address + string length - index
mov bx, HEX_OUT + 5
sub bx, cx ; cx: index
mov [bx], al ; copy ascii char on al to pos pointed by bx
ror dx, 4 ; 1234 - 4123 - 3412 - 2341 - 1234
add cx, 1
jmp hex_loop
end:
mov bx, HEX_OUT
call print
popa
ret
HEX_OUT:
db '0x0000', 0 ; reserve memory for string

View File

@ -0,0 +1,26 @@
[bits 32]
; defining constants
VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f ; color byte
print_string_pm:
pusha
mov edx, VIDEO_MEMORY
print_string_pm_loop:
mov al, [ebx] ; [ebx] is address of char
mov ah, WHITE_ON_BLACK
cmp al, 0 ; is end of string?
je print_string_pm_done
mov [edx], ax ; store char + attribute in video memory
add ebx, 1 ; next char
add edx, 2 ; next video memory position
jmp print_string_pm_loop
print_string_pm_done:
popa
ret

View File

@ -0,0 +1,31 @@
gdt_start: ; use labels to compute sizes and jumps
; gdt starts with 8 byte null
dd 0x0
dd 0x0
; GDT for code segment, base = 0x00000000, length = 0xfffff
gdt_code:
dw 0xffff ; segment length
dw 0x0 ; segment base
db 0x0 ; segment base
db 10011010b ; flags
db 11001111b ; flags + segment length
db 0x0 ; segment base
; GDT for data segment
gdt_data:
dw 0xffff
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_start - 1 ; size, always 1 less than what it actually is
dd gdt_start ; address
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start

View File

@ -0,0 +1,24 @@
[bits 16]
enable_protected:
cli ; Disable interrupts
lgdt [gdt_descriptor] ; load the GDT
mov eax, cr0
or eax, 0x1 ; set 32-bit mode bit
mov cr0, eax
jmp CODE_SEG:init_protected ; far jump into a different segment
[bits 32]
init_protected: ; now in 32bit
mov ax, DATA_SEG ; update segment registers
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
; wipe registers clean
mov ebp, 0x90000 ; update stack to top of free space
mov esp, ebp
call BEGIN_PROTECTED ; call known label with useful code

4
src/kernel/entry.asm Normal file
View File

@ -0,0 +1,4 @@
[bits 32]
[extern main] ; define callpoint, must have same name as kernel.c entrypoint
call main ; jump to fun, linker will figure out where it is
jmp $

65
src/kernel/kernel.c Normal file
View File

@ -0,0 +1,65 @@
#include "./platform/drivers/ports.h"
#include "print.h"
#include "./platform/types.h"
#include "./platform/interrupts/idt.h"
#include "./platform/interrupts/isr.h"
void dummy_test_entrypoint() {}
void kernel_welcome() {
print_str("Welcome to ");
print_set_color(PRINT_COLOR_CYAN, PRINT_COLOR_BLACK);
print_str("Shade");
print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK);
print_str("!\n");
print_str("shadeOS kernel version ");
print_set_color(PRINT_COLOR_YELLOW, PRINT_COLOR_BLACK);
print_str("0.2.2");
print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK);
print_newline();
print_str("Running on ");
print_set_color(PRINT_COLOR_YELLOW, PRINT_COLOR_BLACK);
print_str("shade-development");
print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK);
print_newline();
}
// kMain
void main() {
// Initialize screen buffer
struct Char* buffer = (struct Char*) 0xb8000;
clear_all(); // Clear screen
set_cursor_pos(0, 0); // Set cursor position
print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK); // Set print color
// welcome messages
kernel_msg_ok("Initialized display successfully\n");
kernel_welcome();
print_str("Copyright (c) e3team 2022. All rights reserved.\n");
print_str("This program is provided \"as-is\" and no express or implied warranty is provided.\n");
print_str("The full license can be found at /sys/LICENCE on this system or ./LICENCE in the source tree.\n");
print_str("Initializing interrupts...\n");
isr_setup();
kernel_msg_ok("isr setup done\n");
// Test interrupts
__asm__ __volatile__("int $2");
kernel_msg_ok("int 2 not failed");
__asm__ __volatile__("int $3");
__asm__ __volatile__("int $2");
__asm__ __volatile__("int $3");
__asm__ __volatile__("int $2");
__asm__ __volatile__("int $3");
kernel_msg_ok("interrupt test completed\n");
}

View File

@ -0,0 +1,26 @@
/*
* Read 1 byte from specified port
*/
unsigned char port_byte_in(unsigned short port) {
unsigned char result;
// source and dest are backwards.
// "=a (result)" set the C variable to the value of register e'a'x
// '"d" (port) map the C variable port into e'd'x register
__asm__("in %%dx, %%al" : "=a" (result) : "d" (port));
}
void port_byte_out(unsigned short port, unsigned char data) {
// both regs are C vars, nothing is returned, so no '=' in asm syntax
// comma because two vars in input area and none in return area
__asm__("out %%al, %%dx" : : "a" (data), "d" (port));
}
unsigned short port_word_in(unsigned short port) {
unsigned short result;
__asm__("in %%dx, %%ax" : "=a" (result) : "d" (port));
return result;
}
void port_word_out(unsigned short port, unsigned short data) {
__asm__("out %%ax, %%dx" : : "a" (data), "d" (port));
}

View File

@ -0,0 +1,4 @@
unsigned char port_byte_in(unsigned short port);
void port_byte_out(unsigned short port, unsigned char data);
unsigned short port_word_in(unsigned short port);
void port_word_out(unsigned short port, unsigned short data);

View File

@ -0,0 +1,20 @@
#include "idt.h"
#include "../../util.h"
idt_gate_t idt[IDT_ENTRIES];
idt_pointer_t idt_ptr;
void idt_set_gate(int n, u32 handler_addr) {
idt[n].low_offset = low16(handler_addr);
idt[n].sel = KERNEL_CS;
idt[n].reserved = 0;
idt[n].flags = 0x8E;
idt[n].high_offset = high16(handler_addr);
}
void idt_set() {
idt_ptr.base = (u32) &idt;
idt_ptr.limit = IDT_ENTRIES * sizeof(idt_gate_t) - 1;
/* Don't make the mistake of loading &idt -- always load &idt_reg */
__asm__ __volatile__("lidtl (%0)" : : "r" (&idt_ptr));
}

View File

@ -0,0 +1,27 @@
#ifndef IDT_H
#define IDT_H
#include "../types.h"
#define KERNEL_CS 0x08
#define IDT_ENTRIES 256
// An entry in the IDT
typedef struct {
u16 low_offset; // Low 16 bits of handler address
u16 sel; // Kernel code segment selector
u8 reserved; // Always zero
u8 flags; // x xx x xxxx, Present, ring, type, 1110 = "32bit int gate"
u16 high_offset; // High 16 bits of handler address
} __attribute__((packed)) idt_gate_t;
// The IDT itself
typedef struct {
u16 limit;
u32 base;
} __attribute__((packed)) idt_pointer_t;
void idt_set_gate(int n, u32 handler_addr);
void idt_set();
#endif

View File

@ -0,0 +1,286 @@
; in isr.c
[extern isr_handler]
isr_common_stub:
; Save CPU state
pusha ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
mov ax, ds ; Lower 16-bits of eax = ds.
push eax ; save the data segment descriptor
mov ax, 0x10 ; kernel data segment descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
; Call C handler
call isr_handler
; Restore CPU state
pop eax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
popa
add esp, 8 ; Cleans up the pushed error code and pushed ISR number
sti
iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
; We don't get information about which interrupt was caller
; when the handler is run, so we will need to have a different handler
; for every interrupt.
; Furthermore, some interrupts push an error code onto the stack but others
; don't, so we will push a dummy error code for those which don't, so that
; we have a consistent stack for all of them.
; First make the ISRs global
global isr00
global isr01
global isr02
global isr03
global isr04
global isr05
global isr06
global isr07
global isr08
global isr09
global isr10
global isr11
global isr12
global isr13
global isr14
global isr15
global isr16
global isr17
global isr18
global isr19
global isr20
global isr21
global isr22
global isr23
global isr24
global isr25
global isr26
global isr27
global isr28
global isr29
global isr30
global isr31
; 0: Divide By Zero Exception
isr00:
cli
push byte 0
push byte 0
jmp isr_common_stub
; 1: Debug Exception
isr01:
cli
push byte 0
push byte 1
jmp isr_common_stub
; 2: Non Maskable Interrupt Exception
isr02:
cli
push byte 0
push byte 2
jmp isr_common_stub
; 3: Int 3 Exception
isr03:
cli
push byte 0
push byte 3
jmp isr_common_stub
; 4: INTO Exception
isr04:
cli
push byte 0
push byte 4
jmp isr_common_stub
; 5: Out of Bounds Exception
isr05:
cli
push byte 0
push byte 5
jmp isr_common_stub
; 6: Invalid Opcode Exception
isr06:
cli
push byte 0
push byte 6
jmp isr_common_stub
; 7: Coprocessor Not Available Exception
isr07:
cli
push byte 0
push byte 7
jmp isr_common_stub
; 8: Double Fault Exception (With Error Code!)
isr08:
cli
push byte 8
jmp isr_common_stub
; 9: Coprocessor Segment Overrun Exception
isr09:
cli
push byte 0
push byte 9
jmp isr_common_stub
; 10: Bad TSS Exception (With Error Code!)
isr10:
cli
push byte 10
jmp isr_common_stub
; 11: Segment Not Present Exception (With Error Code!)
isr11:
cli
push byte 11
jmp isr_common_stub
; 12: Stack Fault Exception (With Error Code!)
isr12:
cli
push byte 12
jmp isr_common_stub
; 13: General Protection Fault Exception (With Error Code!)
isr13:
cli
push byte 13
jmp isr_common_stub
; 14: Page Fault Exception (With Error Code!)
isr14:
cli
push byte 14
jmp isr_common_stub
; 15: Reserved Exception
isr15:
cli
push byte 0
push byte 15
jmp isr_common_stub
; 16: Floating Point Exception
isr16:
cli
push byte 0
push byte 16
jmp isr_common_stub
; 17: Alignment Check Exception
isr17:
cli
push byte 0
push byte 17
jmp isr_common_stub
; 18: Machine Check Exception
isr18:
cli
push byte 0
push byte 18
jmp isr_common_stub
; 19: Reserved
isr19:
cli
push byte 0
push byte 19
jmp isr_common_stub
; 20: Reserved
isr20:
cli
push byte 0
push byte 20
jmp isr_common_stub
; 21: Reserved
isr21:
cli
push byte 0
push byte 21
jmp isr_common_stub
; 22: Reserved
isr22:
cli
push byte 0
push byte 22
jmp isr_common_stub
; 23: Reserved
isr23:
cli
push byte 0
push byte 23
jmp isr_common_stub
; 24: Reserved
isr24:
cli
push byte 0
push byte 24
jmp isr_common_stub
; 25: Reserved
isr25:
cli
push byte 0
push byte 25
jmp isr_common_stub
; 26: Reserved
isr26:
cli
push byte 0
push byte 26
jmp isr_common_stub
; 27: Reserved
isr27:
cli
push byte 0
push byte 27
jmp isr_common_stub
; 28: Reserved
isr28:
cli
push byte 0
push byte 28
jmp isr_common_stub
; 29: Reserved
isr29:
cli
push byte 0
push byte 29
jmp isr_common_stub
; 30: Reserved
isr30:
cli
push byte 0
push byte 30
jmp isr_common_stub
; 31: Reserved
isr31:
cli
push byte 0
push byte 31
jmp isr_common_stub

View File

@ -0,0 +1,89 @@
#include "isr.h"
#include "idt.h"
#include "../../print.h"
#include "../../util.h"
void isr_setup() {
idt_set_gate(0, (u32)isr00);
idt_set_gate(1, (u32)isr01);
idt_set_gate(2, (u32)isr02);
idt_set_gate(3, (u32)isr03);
idt_set_gate(4, (u32)isr04);
idt_set_gate(5, (u32)isr05);
idt_set_gate(6, (u32)isr06);
idt_set_gate(7, (u32)isr07);
idt_set_gate(8, (u32)isr08);
idt_set_gate(9, (u32)isr09);
idt_set_gate(10, (u32)isr10);
idt_set_gate(11, (u32)isr11);
idt_set_gate(12, (u32)isr12);
idt_set_gate(13, (u32)isr13);
idt_set_gate(14, (u32)isr14);
idt_set_gate(15, (u32)isr15);
idt_set_gate(16, (u32)isr16);
idt_set_gate(17, (u32)isr17);
idt_set_gate(18, (u32)isr18);
idt_set_gate(19, (u32)isr19);
idt_set_gate(20, (u32)isr20);
idt_set_gate(21, (u32)isr21);
idt_set_gate(22, (u32)isr22);
idt_set_gate(23, (u32)isr23);
idt_set_gate(24, (u32)isr24);
idt_set_gate(25, (u32)isr25);
idt_set_gate(26, (u32)isr26);
idt_set_gate(27, (u32)isr27);
idt_set_gate(28, (u32)isr28);
idt_set_gate(29, (u32)isr29);
idt_set_gate(30, (u32)isr30);
idt_set_gate(31, (u32)isr31);
idt_set();
}
char *exception_messages[] = {
"Division By Zero",
"Debug",
"Non Maskable Interrupt",
"Breakpoint",
"Into Detected Overflow",
"Out of Bounds",
"Invalid Opcode",
"No Coprocessor",
"Double Fault",
"Coprocessor Segment Overrun",
"Bad TSS",
"Segment Not Present",
"Stack Fault",
"General Protection Fault",
"Page Fault",
"Unknown Interrupt",
"Coprocessor Fault",
"Alignment Check",
"Machine Check",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved"
};
void isr_handler(registers_t r) {
print_str("int: ");
char s[3];
int_to_ascii(r.int_no, s);
print_str(s);
print_str("\n");
print_str(exception_messages[r.int_no]);
print_str("\n");
}

View File

@ -0,0 +1,48 @@
#pragma once
#include "../types.h"
typedef struct {
u32 ds; // Data segment selector
u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed by pusha
u32 int_no, err_code; // Interrupt number and error code (if present)
u32 eip, cs, eflags, useresp, ss; // Pushed automatically by the CPU
} registers_t;
// CPU exception interrupts
// ^ - pushes error code
extern void isr00(); // Division by Zero
extern void isr01(); // Debug Exception
extern void isr02(); // Non Maskable Interrupt
extern void isr03(); // Breakpoint
extern void isr04(); // Into detected overflow?
extern void isr05(); // Out of Bounds
extern void isr06(); // Invalid opcode
extern void isr07(); // No coprocessor
extern void isr08(); //^ Double fault
extern void isr09(); // Coprocessor segment overrun
extern void isr10(); //^ Bad TSS
extern void isr11(); //^ Segment not present
extern void isr12(); //^ Stack fault
extern void isr13(); //^ General Protection Fault
extern void isr14(); //^ Page Fault
extern void isr15(); // Unknown Interrupt
extern void isr16(); // Coprocessor Fault
extern void isr17(); // Alignment check exception
extern void isr18(); // Machine check exception
extern void isr19(); // Reserved
extern void isr20(); // Reserved
extern void isr21(); // Reserved
extern void isr22(); // Reserved
extern void isr23(); // Reserved
extern void isr24(); // Reserved
extern void isr25(); // Reserved
extern void isr26(); // Reserved
extern void isr27(); // Reserved
extern void isr28(); // Reserved
extern void isr29(); // Reserved
extern void isr30(); // Reserved
extern void isr31(); // Reserved
void isr_setup();
void isr_handler(registers_t r);

View File

@ -0,0 +1,18 @@
#ifndef TYPES_H
#define TYPES_H
typedef unsigned int u32;
typedef int i32;
typedef unsigned short u16;
typedef short i16;
typedef unsigned char u8;
typedef char i8;
#define high16(i32) (i32 & 0xffff)
#define low16(i32) ((i32>>16) & 0xffff)
#define TRUE 1
#define FALSE 0
#define NULL 0
#endif

110
src/kernel/print.c Normal file
View File

@ -0,0 +1,110 @@
#include "print.h"
#include "./platform/drivers/ports.h"
int row = 0;
int col = 0;
char color = PRINT_COLOR_WHITE | PRINT_COLOR_BLACK << 4;
void clear_row(int row) {
struct Char* buffer = (struct Char*) 0xb8000;
struct Char empty = (struct Char) {
character: ' ',
color: color,
};
for (int x = 0; x < NUM_COLS; x++) {
buffer[x + NUM_COLS * row] = empty;
}
set_cursor_pos(col, row);
}
void clear_all() {
for (int i = 0; i < NUM_ROWS; i++) {
clear_row(i);
}
set_cursor_pos(col, row);
}
void print_newline() {
struct Char* buffer = (struct Char*) 0xb8000;
col = 0;
if (row < NUM_ROWS - 1) {
row++;
return;
}
for (int row = 1; row < NUM_ROWS; row++) {
for (int col = 0; col < NUM_COLS; col++) {
struct Char character = buffer[col + NUM_COLS * row];
buffer[col + NUM_COLS * (row - 1)] = character;
}
}
clear_row(NUM_COLS - 1);
set_cursor_pos(col, row);
}
void print_char(char character) {
struct Char* buffer = (struct Char*) 0xb8000;
if (character == '\n') {
print_newline();
return;
}
if (col > NUM_COLS) {
print_newline();
}
struct Char cr = (struct Char) {
character: character,
color: color,
};
buffer[col + NUM_COLS * row] = cr;
col++;
set_cursor_pos(col, row);
}
void print_str(char* str) {
for (int i = 0; 1; i++) {
char character = (char) str[i];
if (character == '\0') {
return;
}
print_char(character);
}
}
void print_set_color(char foreground, char background) {
color = foreground + (background << 4);
}
void set_cursor_pos(int col, int row) {
int offset = col + NUM_COLS * row;
port_byte_out(REG_SCREEN_CTRL, 14);
port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset >> 8));
port_byte_out(REG_SCREEN_CTRL, 15);
port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset & 0xff));
}
void kernel_msg_ok(char* msg) {
char ok_p1[] = "[ ";
char ok_p2[] = "OK ";
char ok_p3[] = "] ";
print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK);
print_str(ok_p1);
print_set_color(PRINT_COLOR_GREEN, PRINT_COLOR_BLACK);
print_str(ok_p2);
print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK);
print_str(ok_p3);
print_str(msg);
}

44
src/kernel/print.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef PRINT_H
#define PRINT_H
#define REG_SCREEN_CTRL 0x3d4
#define REG_SCREEN_DATA 0x3d5
enum {
PRINT_COLOR_BLACK = 0,
PRINT_COLOR_BLUE = 1,
PRINT_COLOR_GREEN = 2,
PRINT_COLOR_CYAN = 3,
PRINT_COLOR_RED = 4,
PRINT_COLOR_MAGENTA = 5,
PRINT_COLOR_BROWN = 6,
PRINT_COLOR_LIGHT_GRAY = 7,
PRINT_COLOR_DARK_GRAY = 8,
PRINT_COLOR_LIGHT_BLUE = 9,
PRINT_COLOR_LIGHT_GREEN = 10,
PRINT_COLOR_LIGHT_CYAN = 11,
PRINT_COLOR_LIGHT_RED = 12,
PRINT_COLOR_PINK = 13,
PRINT_COLOR_YELLOW = 14,
PRINT_COLOR_WHITE = 15,
};
const static int NUM_COLS = 80;
const static int NUM_ROWS = 25;
struct Char {
char character;
char color;
};
void clear_row(int row);
void clear_all();
void print_newline();
void print_char(char character);
void print_set_color(char foreground, char background);
void print_str(char* str);
void set_cursor_pos(int col, int row);
void kernel_msg_ok(char* msg);
#endif

48
src/kernel/strings.c Normal file
View File

@ -0,0 +1,48 @@
#include "strings.h"
#include "./platform/types.h"
void itoa(int n, char str[]) {
int i, sign;
if ((sign = n) < 0) n = -n;
i = 0;
do {
str[i++] = n % 10 + '0';
} while ((n /= 10) > 0);
if (sign < 0) str[i++] = '-';
str[i] = '\0';
strrev(str);
}
/* K&R */
void strrev(char s[]) {
int c, i, j;
for (i = 0, j = strlen(s)-1; i < j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
/* K&R */
int strlen(char s[]) {
int i = 0;
while (s[i] != '\0') ++i;
return i;
}
char* strcpy(char* strDest, const char* strSrc) {
if ( (strDest == NULL) || (strSrc == NULL) ) {
return NULL;
}
char* strDestCopy = strDest;
while ((*strDest++=*strSrc++)!='\0');
return strDestCopy;
}
char* strcnc(char* str1, char* str2) {
char* str_dest;
strcpy(str_dest, str1);
strcpy(str_dest, str2);
}

10
src/kernel/strings.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef STRINGS_H
#define STRINGS_H
void itoa(int n, char str[]);
void strrev(char s[]);
int strlen(char s[]);
char* strcpy(char* strDest, const char* strSrc);
char* strcnc(char* str1, char* str2);
#endif

25
src/kernel/util.c Normal file
View File

@ -0,0 +1,25 @@
#include "util.h"
void memcpy(char *source, char *dest, int nbytes) {
int i;
for (i = 0; i < nbytes; i++) {
*(dest + i) = *(source + i);
}
}
void memset(char *dest, char val, int len) {
char *temp = (char *)dest;
for(; len !=0; len--) *temp++ = val;
}
void int_to_ascii(int n, char str[]) {
int i, sign;
if ((sign = n) < 0) n = -n;
i = 0;
do {
str[i++] = n % 10 + '0';
} while ((n /= 10) > 0);
if (sign < 0) str[i++] = '-';
str[i] = '\0';
}

8
src/kernel/util.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef UTIL_H
#define UTIL_H
void memcpy(char *source, char *dest, int nbytes);
void memset(char *dest, char val, int len);
void int_to_ascii(int n, char str[]);
#endif