[Stage1] Complete IDT implementation

[Stage1] Add IRQ remapping
[Stage1] Handle IRQ0 gracefully
[Stage1] Add error output functions
This commit is contained in:
John Stefanelli 2023-01-18 17:11:28 +01:00
parent 17a18e4f91
commit dad4ff6a34
Signed by: jstefanelli
GPG key ID: 60EDE2437640D2AA
13 changed files with 261 additions and 89 deletions

View file

@ -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;

View file

@ -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;
}

View file

@ -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)

View file

@ -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
View 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
View 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

View file

@ -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

View file

@ -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,11 +28,11 @@ 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
RET ; return
LIDT [main_idt_ptr] ; load idt with SP+4
RET ; return
; void enable_interrupts()
global enable_interrupts

View file

@ -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
View 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
View 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);
}

View file

@ -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;
}

View file

@ -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;
}