[Stage1] Complete IDT implementation
[Stage1] Add IRQ remapping [Stage1] Handle IRQ0 gracefully [Stage1] Add error output functions
This commit is contained in:
parent
17a18e4f91
commit
dad4ff6a34
13 changed files with 261 additions and 89 deletions
|
|
@ -52,6 +52,11 @@ int main(int argc, char** argv) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (kernel == NULL) {
|
||||
fprintf(stderr, "Failed to open kernel file\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
LFFileHandle image_handle = libhost_create_handle(image);
|
||||
|
||||
LFControlBlock fat;
|
||||
|
|
|
|||
|
|
@ -85,6 +85,11 @@ os_bool libfat_write_fat_cluster(LFControlBlock* fat, os_u32 cluster_id, os_u32
|
|||
fat->handle.seek(second_fat_cluster_offset, LIBFAT_SEEK_ORIGIN, fat->handle.user_data);
|
||||
fat->handle.write(sizeof(os_u32), (void*)&cluster_value, fat->handle.user_data);
|
||||
|
||||
if (fat->first_loaded_cluster <= cluster_id && (fat->first_loaded_cluster + fat->loaded_fat_cluster_amount) > cluster_id) {
|
||||
os_u32 cluster_offset = cluster_id - fat->first_loaded_cluster;
|
||||
fat->loaded_fat_segment[cluster_offset] = cluster_value;
|
||||
}
|
||||
|
||||
return OS_TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -113,7 +118,7 @@ os_u32 libfat_write_cluster(LFControlBlock* fat, os_u32 cluster, void* buffer, o
|
|||
os_u32 cluster_size = fat->header.base.bytes_per_sector * fat->header.base.sectors_per_cluster;
|
||||
os_u32 data_offset = (fat->header.base.reserved_sectors + (fat->header.sectors_per_fat_32 * fat->header.base.number_of_fats)) * fat->header.base.bytes_per_sector;
|
||||
|
||||
if (offset_in_cluster + buffer_size >= cluster_size) {
|
||||
if (offset_in_cluster + buffer_size > cluster_size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -596,7 +601,7 @@ os_u32 libfat_write(LFFile* f, void* buffer, os_u32 buffer_size) {
|
|||
f->in_cluster_position = 0;
|
||||
os_u32 next = libfat_read_cluster(f->fat, f->current_cluster);
|
||||
if (next >= FAT_LAST_CLUSTER_32_2) {
|
||||
next = libfat_add_cluster_to_chain(f->fat, next);
|
||||
next = libfat_add_cluster_to_chain(f->fat, f->current_cluster);
|
||||
}
|
||||
f->current_cluster = next;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
add_executable(stage1 stage1.c screen.c include/interrupts.h interrupts.c interrupt_utils.asm)
|
||||
add_executable(stage1 stage1.c screen.c include/interrupts.h interrupts.c interrupt_utils.asm include/io.h io.asm include/pic_8259.h pic_8259.c)
|
||||
target_compile_options(stage1 PUBLIC "$<$<COMPILE_LANGUAGE:C>:-ffreestanding>")
|
||||
set_target_properties(stage1 PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld)
|
||||
target_link_options(stage1 PRIVATE -T${CMAKE_CURRENT_SOURCE_DIR}/linker.ld)
|
||||
|
|
|
|||
|
|
@ -1,43 +1,9 @@
|
|||
#ifndef OS3_INTERRUPTS_H
|
||||
#define OS3_INTERRUPTS_H
|
||||
|
||||
#include "datatypes.h"
|
||||
#include "packing.h"
|
||||
#include "screen.h"
|
||||
extern void setup_interrupts();
|
||||
|
||||
OS_PACK_START
|
||||
typedef struct __idt_attributes {
|
||||
os_u8 gate_type: 4;
|
||||
os_u8 empty : 1;
|
||||
os_u8 dpl : 2;
|
||||
os_u8 present: 1;
|
||||
} OS_PACK_MID idt_attributes;
|
||||
OS_PACK_END
|
||||
|
||||
#define IDT_GATE_TYPE_TASK 0x5
|
||||
#define IDT_GATE_TYPE_INTERRUPT_16 0x6
|
||||
#define IDT_GATE_TYPE_TRAP_16 0x7
|
||||
#define IDT_GATE_TYPE_INTERRUPT_32 0xE
|
||||
#define IDT_GATE_TYPE_TRAP_32 0xF
|
||||
|
||||
OS_PACK_START
|
||||
typedef struct __idt_entry {
|
||||
os_u16 isr_low;
|
||||
os_u16 kernel_gdt_code_segment;
|
||||
os_u8 reserved;
|
||||
//idt_attributes attributes;
|
||||
os_u8 attributes;
|
||||
os_u16 isr_high;
|
||||
} OS_PACK_MID idt_entry;
|
||||
OS_PACK_END
|
||||
|
||||
OS_PACK_START
|
||||
typedef struct __idt_ptr {
|
||||
os_u16 limit;
|
||||
os_u32 base;
|
||||
} OS_PACK_MID idt_ptr;
|
||||
OS_PACK_END
|
||||
|
||||
extern void fill_idt();
|
||||
// Defined in interrupt_utils.asm
|
||||
extern void enable_interrupts();
|
||||
|
||||
#endif //OS3_INTERRUPTS_H
|
||||
|
|
|
|||
18
stage1/include/io.h
Normal file
18
stage1/include/io.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// Created by John Stefanelli on 18/01/23.
|
||||
//
|
||||
|
||||
#ifndef OS3_IO_H
|
||||
#define OS3_IO_H
|
||||
|
||||
#include "datatypes.h"
|
||||
|
||||
extern void outb(os_u16 port, os_u8 data);
|
||||
extern void outw(os_u16 port, os_u16 data);
|
||||
extern void outd(os_u16 port, os_u32 data);
|
||||
|
||||
extern os_u8 inb(os_u16 port);
|
||||
extern os_u16 inw(os_u16 port);
|
||||
extern os_u32 ind(os_u16 port);
|
||||
|
||||
#endif //OS3_IO_H
|
||||
13
stage1/include/pic_8259.h
Normal file
13
stage1/include/pic_8259.h
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
//
|
||||
// Created by John Stefanelli on 18/01/23.
|
||||
//
|
||||
|
||||
#ifndef OS3_PIC_8259_H
|
||||
#define OS3_PIC_8259_H
|
||||
|
||||
#include "datatypes.h"
|
||||
|
||||
extern void pic_sendEOI(os_u8 irq);
|
||||
extern void setup_pic();
|
||||
|
||||
#endif //OS3_PIC_8259_H
|
||||
|
|
@ -3,8 +3,11 @@
|
|||
|
||||
#include "datatypes.h"
|
||||
|
||||
extern void write_string(const char*, int);
|
||||
extern void clear_screen();
|
||||
extern void write_number(os_u32 number);
|
||||
extern void screen_write_string(const char* str, int length);
|
||||
extern void screen_write_error(const char* str, int length);
|
||||
extern void screen_clear();
|
||||
extern void screen_write_number(os_u32 number);
|
||||
extern void screen_write_number_error(os_u32 number);
|
||||
extern void screen_set_pos(int x, int y);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,10 +1,14 @@
|
|||
; list of 256 void* to call when the corresponding interrupt is received
|
||||
extern interrupt_service_list, generic_exception
|
||||
extern interrupt_service_list
|
||||
; IDTR structure
|
||||
extern main_idt_ptr
|
||||
|
||||
%macro interrupt_service_routine 1
|
||||
isr_stub_%+%1:
|
||||
;CALL interrupt_service_list + (%1*4)
|
||||
CALL generic_exception
|
||||
MOV EAX, i ; load interrupt number
|
||||
PUSH EAX ; push parameter "interrupt number"
|
||||
CALL [interrupt_service_list + (%1*4)] ; call interrupt subroutine
|
||||
ADD ESP, 4 ; clear parameters
|
||||
IRET
|
||||
%endmacro
|
||||
|
||||
|
|
@ -24,10 +28,10 @@ interrupt_service_table:
|
|||
%assign i i+1
|
||||
%endrep
|
||||
|
||||
; void load_idt(void* idt_ptr)
|
||||
; void load_idt()
|
||||
global load_idt
|
||||
load_idt:
|
||||
LIDT [ESP+4] ; load idt with SP+4
|
||||
LIDT [main_idt_ptr] ; load idt with SP+4
|
||||
RET ; return
|
||||
|
||||
; void enable_interrupts()
|
||||
|
|
|
|||
|
|
@ -1,56 +1,91 @@
|
|||
#include "include/interrupts.h"
|
||||
#include "datatypes.h"
|
||||
#include "packing.h"
|
||||
#include "include/screen.h"
|
||||
#include "include/pic_8259.h"
|
||||
|
||||
#define EFFECTIVE_INTERRUPT_AMOUNT 32
|
||||
OS_PACK_START
|
||||
typedef struct __idt_attributes {
|
||||
os_u8 gate_type: 4;
|
||||
os_u8 empty : 1;
|
||||
os_u8 dpl : 2;
|
||||
os_u8 present: 1;
|
||||
} OS_PACK_MID idt_attributes;
|
||||
OS_PACK_END
|
||||
|
||||
#define IDT_GATE_TYPE_TASK 0x5
|
||||
#define IDT_GATE_TYPE_INTERRUPT_16 0x6
|
||||
#define IDT_GATE_TYPE_TRAP_16 0x7
|
||||
#define IDT_GATE_TYPE_INTERRUPT_32 0xE
|
||||
#define IDT_GATE_TYPE_TRAP_32 0xF
|
||||
|
||||
OS_PACK_START
|
||||
typedef struct __idt_entry {
|
||||
os_u16 isr_low;
|
||||
os_u16 kernel_gdt_code_segment;
|
||||
os_u8 reserved;
|
||||
idt_attributes attributes;
|
||||
//os_u8 attributes;
|
||||
os_u16 isr_high;
|
||||
} OS_PACK_MID idt_entry;
|
||||
OS_PACK_END
|
||||
|
||||
OS_PACK_START
|
||||
typedef struct __idt_ptr {
|
||||
os_u16 limit;
|
||||
os_u32 base;
|
||||
} OS_PACK_MID idt_ptr;
|
||||
OS_PACK_END
|
||||
|
||||
|
||||
#define EFFECTIVE_INTERRUPT_AMOUNT 256
|
||||
|
||||
__attribute__((aligned(0x10)))
|
||||
idt_entry main_idt[EFFECTIVE_INTERRUPT_AMOUNT];
|
||||
idt_ptr main_idt_ptr;
|
||||
volatile void* interrupt_service_list[EFFECTIVE_INTERRUPT_AMOUNT];
|
||||
|
||||
void generic_exception() {
|
||||
//clear_screen();
|
||||
write_string("Exception received: ", 0);
|
||||
write_number(0);
|
||||
write_string("\n", 0);
|
||||
__asm__("cli; hlt;");
|
||||
void generic_exception(os_u32 interrupt_id) {
|
||||
//screen_clear();
|
||||
screen_set_pos(0, 0);
|
||||
screen_write_error("Exception received: ", 0);
|
||||
screen_write_number_error(interrupt_id);
|
||||
screen_write_string("\n", 0);
|
||||
while(1) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void handle_irq0(os_u32) {
|
||||
pic_sendEOI(0);
|
||||
}
|
||||
|
||||
/* The following is defined in interrupt_utils.asm */
|
||||
extern void* interrupt_service_table[];
|
||||
extern void load_idt(void* idtr_ptr);
|
||||
extern void enable_interrupts();
|
||||
extern void load_idt();
|
||||
/* --- */
|
||||
|
||||
void fill_idt() {
|
||||
void setup_interrupts() {
|
||||
|
||||
main_idt_ptr.base = (os_u32) &main_idt[0];
|
||||
main_idt_ptr.limit = ((os_u16) (sizeof(idt_entry) * EFFECTIVE_INTERRUPT_AMOUNT)) - 1;
|
||||
os_u32 val = (os_u32) interrupt_service_table[0];
|
||||
write_string("ISR address: ", 0);
|
||||
write_number(val);
|
||||
write_string("\n", 1);
|
||||
for (int i = 0; i < EFFECTIVE_INTERRUPT_AMOUNT; i++) {
|
||||
|
||||
//os_u32 val = (os_u32) interrupt_service_table[0];
|
||||
os_u32 val = (os_u32) &generic_exception;
|
||||
os_u32 val = (os_u32) interrupt_service_table[i];
|
||||
//os_u32 val = (os_u32) &generic_exception;
|
||||
main_idt[i].isr_low = (os_u16)(val & 0xFFFF);
|
||||
main_idt[i].isr_high = (os_u16)(val >> 16);
|
||||
main_idt[i].kernel_gdt_code_segment = 0x08;
|
||||
main_idt[i].reserved = 0;
|
||||
/*
|
||||
|
||||
main_idt[i].attributes.present = 1;
|
||||
main_idt[i].attributes.gate_type = IDT_GATE_TYPE_INTERRUPT_32;
|
||||
main_idt[i].attributes.empty = 0;
|
||||
main_idt[i].attributes.dpl = i == 0x49 ? 3 : 0;
|
||||
*/
|
||||
main_idt[i].attributes = 0x8e;
|
||||
|
||||
interrupt_service_list[i] = (void*)&generic_exception;
|
||||
}
|
||||
interrupt_service_list[32] = (void*)&handle_irq0;
|
||||
|
||||
load_idt((void*)&main_idt_ptr);
|
||||
enable_interrupts();
|
||||
load_idt();
|
||||
}
|
||||
50
stage1/io.asm
Normal file
50
stage1/io.asm
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
|
||||
section .text
|
||||
|
||||
; void outb(os_u16 port, os_u8 data);
|
||||
global outb
|
||||
outb:
|
||||
MOV EDX, [ESP + 4] ; load parameter 'port'
|
||||
MOV EAX, [ESP + 8] ; load parameter 'data'
|
||||
OUT DX, AL ; output byte in AL to port in DX
|
||||
RET ; return
|
||||
|
||||
; void outw(os_u16 port, os_u16 data)
|
||||
global outw
|
||||
outw:
|
||||
MOV EDX, [ESP + 4] ; load parameter 'port'
|
||||
MOV EAX, [ESP + 8] ; load parameter 'data'
|
||||
OUT DX, AX ; output word in AX to port in DX
|
||||
RET ; return
|
||||
|
||||
; void outd(os_u16 port, os_u32 data)
|
||||
global outd
|
||||
outd:
|
||||
MOV EDX, [ESP + 4] ; load parameter 'port'
|
||||
MOV EAX, [ESP + 8] ; load parameter 'data'
|
||||
OUT DX, EAX ; output double word in EAX to port in DX
|
||||
RET ; return
|
||||
|
||||
; os_u8 inb(os_u16 port)
|
||||
global inb
|
||||
inb:
|
||||
MOV EDX, [ESP + 4] ; load parameter 'port'
|
||||
XOR EAX, EAX ; reset EAX
|
||||
IN AL, DX ; read byte from port 'DX'
|
||||
RET ; return
|
||||
|
||||
; os_u16 inw(os_u16 port)
|
||||
global inw
|
||||
inw:
|
||||
MOV EDX, [ESP + 4] ; load parameter 'port'
|
||||
XOR EAX, EAX ; reset EAX
|
||||
IN AX, DX ; read word from port 'DX'
|
||||
RET ; return
|
||||
|
||||
; os_u32 ind(os_u16 port)
|
||||
global ind
|
||||
ind:
|
||||
MOV EDX, [ESP + 4] ; load parameter 'port'
|
||||
XOR EAX, EAX ; reset EAX
|
||||
IN EAX, DX ; read double word from port 'DX'
|
||||
RET ; return
|
||||
50
stage1/pic_8259.c
Normal file
50
stage1/pic_8259.c
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#include "include/pic_8259.h"
|
||||
#include "include/io.h"
|
||||
|
||||
#define PIC0 0x20
|
||||
#define PIC1 0xA0
|
||||
#define PIC0_COMMAND (PIC0)
|
||||
#define PIC0_DATA (PIC0 + 1)
|
||||
#define PIC1_COMMAND (PIC1)
|
||||
#define PIC1_DATA (PIC1 + 1)
|
||||
|
||||
#define PIC_EOI 0x20 //PIC end-of-interrupt command
|
||||
|
||||
#define ICW1_ICW4 0x01 /* ICW4 (not) needed */
|
||||
#define ICW1_SINGLE 0x02 /* Single (cascade) mode */
|
||||
#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */
|
||||
#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */
|
||||
#define ICW1_INIT 0x10 /* Initialization - required! */
|
||||
|
||||
#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */
|
||||
#define ICW4_AUTO 0x02 /* Auto (normal) EOI */
|
||||
#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */
|
||||
#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */
|
||||
#define ICW4_SFNM 0x10 /* Special fully nested (not) */
|
||||
|
||||
void pic_sendEOI(os_u8 irq) {
|
||||
if (irq >= 8) {
|
||||
outb(PIC1_COMMAND, PIC_EOI);
|
||||
}
|
||||
|
||||
outb(PIC0_COMMAND, PIC_EOI);
|
||||
}
|
||||
|
||||
void setup_pic() {
|
||||
os_u8 a1, a2;
|
||||
|
||||
a1 = inb(PIC0_DATA); // save current interrupt masks
|
||||
a2 = inb(PIC1_DATA);
|
||||
|
||||
outb(PIC0_COMMAND, ICW1_INIT | ICW1_ICW4); //Start init sequence in cascade mode
|
||||
outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4);
|
||||
outb(PIC0_DATA, 0x20); // 0x20: Offset of IRQ 0
|
||||
outb(PIC1_DATA, 0x28); // 0x28: Offset of IRQ 8
|
||||
outb(PIC0_DATA, 4); //Master PIC should handle cascade at IRQ 2
|
||||
outb(PIC1_DATA, 2); //Salve PIC should handle cascade identity '2'
|
||||
outb(PIC0_DATA, ICW4_8086); //Set master to 8086 mode
|
||||
outb(PIC1_DATA, ICW4_8086); //Set slave to 8086 mode
|
||||
|
||||
outb(PIC0_DATA, a1); //restore interrupt masks
|
||||
outb(PIC1_DATA, a2);
|
||||
}
|
||||
|
|
@ -1,18 +1,17 @@
|
|||
#include "include/screen.h"
|
||||
#include "../os3_common/datatypes.h"
|
||||
#include "../os3_common/packing.h"
|
||||
#include "include/screen.h"
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
void write_character(char c) {
|
||||
os_u16 color_byte = 0x0A;
|
||||
void write_character(char c, os_u8 color) {
|
||||
os_u16* vram = (os_u16*) 0xB8000;
|
||||
os_u16* cursor_pos = vram + ((y * 80) + x);
|
||||
*cursor_pos = c | (color_byte << 8);
|
||||
*cursor_pos = c | (color << 8);
|
||||
}
|
||||
|
||||
void write_string(const char* str, int max_len) {
|
||||
void screen_write(const char* str, int max_len, os_u8 color) {
|
||||
int i = 0;
|
||||
do {
|
||||
char c = *str;
|
||||
|
|
@ -22,7 +21,7 @@ void write_string(const char* str, int max_len) {
|
|||
|
||||
if (c == '\n') {
|
||||
if (y == 24) {
|
||||
clear_screen();
|
||||
screen_clear();
|
||||
}
|
||||
y = (y + 1) % 25;
|
||||
x = 0;
|
||||
|
|
@ -30,11 +29,11 @@ void write_string(const char* str, int max_len) {
|
|||
continue;
|
||||
}
|
||||
|
||||
write_character(c);
|
||||
write_character(c, color);
|
||||
x++;
|
||||
if (x >= 80) {
|
||||
if (y == 24) {
|
||||
clear_screen();
|
||||
screen_clear();
|
||||
}
|
||||
y = (y + 1) % 25;
|
||||
x = 0;
|
||||
|
|
@ -44,7 +43,15 @@ void write_string(const char* str, int max_len) {
|
|||
} while(i < max_len || max_len == 0);
|
||||
}
|
||||
|
||||
void clear_screen() {
|
||||
void screen_write_string(const char* str, int length) {
|
||||
screen_write(str, length, 0x0A);
|
||||
}
|
||||
|
||||
void screen_write_error(const char* str, int length) {
|
||||
screen_write(str, length, 0x0C);
|
||||
}
|
||||
|
||||
void screen_clear() {
|
||||
os_u16* ptr = (os_u16*) 0xB8000;
|
||||
for (int y = 0; y < 25; y++) {
|
||||
for (int x = 0; x < 80; x++) {
|
||||
|
|
@ -56,7 +63,7 @@ void clear_screen() {
|
|||
y = 0;
|
||||
}
|
||||
|
||||
void write_number(os_u32 number) {
|
||||
void screen_write_number_impl(os_u32 number, os_u8 color) {
|
||||
char buffer[32];
|
||||
char buffer_2[32];
|
||||
|
||||
|
|
@ -79,5 +86,18 @@ void write_number(os_u32 number) {
|
|||
i--;
|
||||
}
|
||||
|
||||
write_string(buffer_2, 0);
|
||||
screen_write(buffer_2, 0, color);
|
||||
}
|
||||
|
||||
void screen_write_number(os_u32 number) {
|
||||
screen_write_number_impl(number, 0x0A);
|
||||
}
|
||||
|
||||
void screen_write_number_error(os_u32 number) {
|
||||
screen_write_number_impl(number, 0x0C);
|
||||
}
|
||||
|
||||
void screen_set_pos(int nx, int ny) {
|
||||
x = nx;
|
||||
y = ny;
|
||||
}
|
||||
|
|
@ -2,17 +2,20 @@
|
|||
#include "../os3_common/packing.h"
|
||||
#include "include/screen.h"
|
||||
#include "include/interrupts.h"
|
||||
#include "include/pic_8259.h"
|
||||
|
||||
int main() {
|
||||
clear_screen();
|
||||
write_string("OS3 Booted into stage 1!\n", 0);
|
||||
write_string("Looking for stage 2....\n", 0);
|
||||
fill_idt();
|
||||
os_u32 i = 0;
|
||||
screen_clear();
|
||||
screen_write_string("OS3 Booted into stage 1!\n", 0);
|
||||
screen_write_string("Looking for stage 2....\n", 0);
|
||||
setup_interrupts();
|
||||
|
||||
setup_pic();
|
||||
|
||||
enable_interrupts();
|
||||
|
||||
while(1) {
|
||||
write_number(i++);
|
||||
write_string("\n", 0);
|
||||
};
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue