Start cleaning up kernel assembly mixins & start ISR/interrupts
This commit is contained in:
parent
9e4aaa56ba
commit
9904ac83d8
4
Makefile
4
Makefile
@ -30,9 +30,9 @@ $(BUILD_DIR)/bootloader.bin: $(BOOTLOADER_DIR)/main16.asm
|
||||
cd $(BOOTLOADER_DIR); nasm -f bin -o ../../build/bootloader.bin main16.asm
|
||||
|
||||
# Builds the kernel entry object file
|
||||
$(BUILD_DIR)/kernel_entry.o: asm/boot.asm
|
||||
$(BUILD_DIR)/kernel_entry.o: asm/kasm.asm
|
||||
$(MKDIR_P) $(dir $@)
|
||||
nasm asm/boot.asm -f elf -o $@
|
||||
cd asm; nasm kasm.asm -f elf -o ../build/kernel_entry.o
|
||||
|
||||
# Build C++ sources
|
||||
$(BUILD_DIR)/%.cpp.o: %.cpp
|
||||
|
@ -5,4 +5,4 @@
|
||||
[extern main] ; going to call main in kernel.c
|
||||
|
||||
call main
|
||||
jmp $
|
||||
jmp $
|
||||
|
89
asm/idt.asm
Normal file
89
asm/idt.asm
Normal file
@ -0,0 +1,89 @@
|
||||
[bits 32]
|
||||
[extern isr_handler]
|
||||
|
||||
%macro ISR_NOERRORCODE 1 ; define a macro, taking one parameter
|
||||
[GLOBAL isr%1] ; %1 accesses the first parameter.
|
||||
isr%1:
|
||||
cli
|
||||
push byte 0
|
||||
push byte %1
|
||||
jmp isr_common_stub
|
||||
%endmacro
|
||||
|
||||
%macro ISR_ERRORCODE 1
|
||||
[GLOBAL isr%1]
|
||||
isr%1:
|
||||
cli
|
||||
push byte %1
|
||||
jmp isr_common_stub
|
||||
%endmacro
|
||||
|
||||
ISR_NOERRORCODE 0
|
||||
ISR_NOERRORCODE 1
|
||||
ISR_NOERRORCODE 2
|
||||
ISR_NOERRORCODE 3
|
||||
ISR_NOERRORCODE 4
|
||||
ISR_NOERRORCODE 5
|
||||
ISR_NOERRORCODE 6
|
||||
ISR_NOERRORCODE 7
|
||||
ISR_ERRORCODE 8
|
||||
ISR_NOERRORCODE 9
|
||||
ISR_ERRORCODE 10
|
||||
ISR_ERRORCODE 11
|
||||
ISR_ERRORCODE 12
|
||||
ISR_ERRORCODE 13
|
||||
ISR_ERRORCODE 14
|
||||
ISR_NOERRORCODE 15
|
||||
ISR_NOERRORCODE 16
|
||||
ISR_NOERRORCODE 17
|
||||
ISR_NOERRORCODE 18
|
||||
ISR_NOERRORCODE 19
|
||||
ISR_NOERRORCODE 20
|
||||
ISR_NOERRORCODE 21
|
||||
ISR_NOERRORCODE 22
|
||||
ISR_NOERRORCODE 23
|
||||
ISR_NOERRORCODE 24
|
||||
ISR_NOERRORCODE 25
|
||||
ISR_NOERRORCODE 26
|
||||
ISR_NOERRORCODE 27
|
||||
ISR_NOERRORCODE 28
|
||||
ISR_NOERRORCODE 29
|
||||
ISR_NOERRORCODE 30
|
||||
ISR_NOERRORCODE 31
|
||||
|
||||
; In isr.c
|
||||
[EXTERN isr_handler]
|
||||
|
||||
; This is our common ISR stub. It saves the processor state, sets
|
||||
; up for kernel mode segments, calls the C-level fault handler,
|
||||
; and finally restores the stack frame.
|
||||
isr_common_stub:
|
||||
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 ; load the kernel data segment descriptor
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
call isr_handler
|
||||
|
||||
pop eax ; reload the original data segment descriptor
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
popa ; Pops edi,esi,ebp...
|
||||
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
|
||||
|
||||
[GLOBAL idt_flush]
|
||||
idt_flush:
|
||||
mov eax, [esp + 4]
|
||||
lidt [eax]
|
||||
ret
|
5
asm/kasm.asm
Normal file
5
asm/kasm.asm
Normal file
@ -0,0 +1,5 @@
|
||||
; NOT part of the bootloader
|
||||
; this is the kernel entry code that calls main() in kernel.cpp
|
||||
|
||||
%include "boot.asm"
|
||||
%include "idt.asm"
|
61
src/cpu/idt.cpp
Normal file
61
src/cpu/idt.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
#include "idt.h"
|
||||
#include "../kernel/mem.h"
|
||||
#include "../drivers/vga.h"
|
||||
|
||||
void isr_handler(registers_t regs) {
|
||||
VGA vga;
|
||||
vga.print("Received interrupt!");
|
||||
}
|
||||
|
||||
static void init_idt() {
|
||||
idt_ptr.limit = sizeof(idt_entry_t) * 256 - 1;
|
||||
idt_ptr.base = (uint32_t) &idt_entries;
|
||||
|
||||
mem_set((uint8_t*) &idt_entries, 0, sizeof(idt_entry_t) * 256);
|
||||
|
||||
idt_set_gate(0, (uint32_t) isr0, 0x08, 0x8e);
|
||||
idt_set_gate(1, (uint32_t) isr1, 0x08, 0x8e);
|
||||
idt_set_gate(2, (uint32_t) isr2, 0x08, 0x8e);
|
||||
idt_set_gate(3, (uint32_t) isr3, 0x08, 0x8e);
|
||||
idt_set_gate(4, (uint32_t) isr4, 0x08, 0x8e);
|
||||
idt_set_gate(5, (uint32_t) isr5, 0x08, 0x8e);
|
||||
idt_set_gate(6, (uint32_t) isr6, 0x08, 0x8e);
|
||||
idt_set_gate(7, (uint32_t) isr7, 0x08, 0x8e);
|
||||
idt_set_gate(8, (uint32_t) isr8, 0x08, 0x8e);
|
||||
idt_set_gate(9, (uint32_t) isr9, 0x08, 0x8e);
|
||||
idt_set_gate(10, (uint32_t) isr10, 0x08, 0x8e);
|
||||
idt_set_gate(11, (uint32_t) isr11, 0x08, 0x8e);
|
||||
idt_set_gate(12, (uint32_t) isr12, 0x08, 0x8e);
|
||||
idt_set_gate(13, (uint32_t) isr13, 0x08, 0x8e);
|
||||
idt_set_gate(14, (uint32_t) isr14, 0x08, 0x8e);
|
||||
idt_set_gate(15, (uint32_t) isr15, 0x08, 0x8e);
|
||||
idt_set_gate(16, (uint32_t) isr16, 0x08, 0x8e);
|
||||
idt_set_gate(17, (uint32_t) isr17, 0x08, 0x8e);
|
||||
idt_set_gate(18, (uint32_t) isr18, 0x08, 0x8e);
|
||||
idt_set_gate(19, (uint32_t) isr19, 0x08, 0x8e);
|
||||
idt_set_gate(20, (uint32_t) isr20, 0x08, 0x8e);
|
||||
idt_set_gate(21, (uint32_t) isr21, 0x08, 0x8e);
|
||||
idt_set_gate(22, (uint32_t) isr22, 0x08, 0x8e);
|
||||
idt_set_gate(23, (uint32_t) isr23, 0x08, 0x8e);
|
||||
idt_set_gate(24, (uint32_t) isr24, 0x08, 0x8e);
|
||||
idt_set_gate(25, (uint32_t) isr25, 0x08, 0x8e);
|
||||
idt_set_gate(26, (uint32_t) isr26, 0x08, 0x8e);
|
||||
idt_set_gate(27, (uint32_t) isr27, 0x08, 0x8e);
|
||||
idt_set_gate(28, (uint32_t) isr28, 0x08, 0x8e);
|
||||
idt_set_gate(29, (uint32_t) isr29, 0x08, 0x8e);
|
||||
idt_set_gate(30, (uint32_t) isr30, 0x08, 0x8e);
|
||||
idt_set_gate(31, (uint32_t) isr31, 0x08, 0x8e);
|
||||
|
||||
idt_flush((uint32_t) &idt_ptr);
|
||||
}
|
||||
|
||||
static void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) {
|
||||
idt_entries[num].base_lo = base & 0xFFFF;
|
||||
idt_entries[num].base_hi = (base >> 16) & 0xFFFF;
|
||||
idt_entries[num].sel = sel;
|
||||
idt_entries[num].always0 = 0;
|
||||
|
||||
// We must uncomment the OR below when we get to using user-mode.
|
||||
// It sets the interrupt gate's privilege level to 3.
|
||||
idt_entries[num].flags = flags /* | 0x60 */;
|
||||
}
|
77
src/cpu/idt.h
Normal file
77
src/cpu/idt.h
Normal file
@ -0,0 +1,77 @@
|
||||
#ifndef KERNEL_CPU_IDT_H
|
||||
#define KERNEL_CPU_IDT_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
typedef struct registers
|
||||
{
|
||||
uint32_t ds; // Data segment selector
|
||||
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed by pusha.
|
||||
uint32_t int_no, err_code; // Interrupt number and error code (if applicable)
|
||||
uint32_t eip, cs, eflags, useresp, ss; // Pushed by the processor automatically.
|
||||
} registers_t;
|
||||
|
||||
void isr_handler(registers_t);
|
||||
|
||||
// A struct describing an interrupt gate.
|
||||
struct idt_entry_struct
|
||||
{
|
||||
uint16_t base_lo; // The lower 16 bits of the address to jump to when this interrupt fires.
|
||||
uint16_t sel; // Kernel segment selector.
|
||||
uint8_t always0; // This must always be zero.
|
||||
uint8_t flags; // More flags. See documentation.
|
||||
uint16_t base_hi; // The upper 16 bits of the address to jump to.
|
||||
} __attribute__((packed));
|
||||
typedef struct idt_entry_struct idt_entry_t;
|
||||
|
||||
// A struct describing a pointer to an array of interrupt handlers.
|
||||
// This is in a format suitable for giving to 'lidt'.
|
||||
struct idt_ptr_struct {
|
||||
uint16_t limit;
|
||||
uint32_t base; // The address of the first element in our idt_entry_t array.
|
||||
} __attribute__((packed));
|
||||
typedef struct idt_ptr_struct idt_ptr_t;
|
||||
|
||||
extern void idt_flush(uint32_t);
|
||||
|
||||
static void init_idt();
|
||||
static void idt_set_gate(uint8_t, uint32_t, uint16_t, uint8_t);
|
||||
|
||||
idt_entry_t idt_entries[256];
|
||||
idt_ptr_t idt_ptr;
|
||||
|
||||
// References to ASM ISR handlers
|
||||
extern void isr0();
|
||||
extern void isr1();
|
||||
extern void isr2();
|
||||
extern void isr3();
|
||||
extern void isr4();
|
||||
extern void isr5();
|
||||
extern void isr6();
|
||||
extern void isr7();
|
||||
extern void isr8();
|
||||
extern void isr9();
|
||||
extern void isr10();
|
||||
extern void isr11();
|
||||
extern void isr12();
|
||||
extern void isr13();
|
||||
extern void isr14();
|
||||
extern void isr15();
|
||||
extern void isr16();
|
||||
extern void isr17();
|
||||
extern void isr18();
|
||||
extern void isr19();
|
||||
extern void isr20();
|
||||
extern void isr21();
|
||||
extern void isr22();
|
||||
extern void isr23();
|
||||
extern void isr24();
|
||||
extern void isr25();
|
||||
extern void isr26();
|
||||
extern void isr27();
|
||||
extern void isr28();
|
||||
extern void isr29();
|
||||
extern void isr30();
|
||||
extern void isr31();
|
||||
|
||||
#endif //KERNEL_CPU_IDT_H
|
@ -2,12 +2,7 @@
|
||||
#define KERNEL_CPU_TYPES_H
|
||||
|
||||
// Non-semantic types specific to 32-bit Intel x86
|
||||
typedef unsigned int u32_t;
|
||||
typedef int i32_t;
|
||||
typedef unsigned short u16_t;
|
||||
typedef short i16_t;
|
||||
typedef unsigned char u8_t;
|
||||
typedef char i8_t;
|
||||
#include <stdint.h>
|
||||
|
||||
#define LOW16(address) (u16)((address) & 0xffff)
|
||||
#define HIGH16(address) (u16)(((address) >> 16) & 0xffff)
|
||||
|
@ -9,8 +9,8 @@
|
||||
* @param port
|
||||
* @return the read byte
|
||||
*/
|
||||
u8_t io_byte_in(u16_t port) {
|
||||
u8_t result;
|
||||
uint8_t io_byte_in(uint16_t port) {
|
||||
uint8_t result;
|
||||
__asm__("in %%dx, %%al" : "=a" (result) : "d" (port));
|
||||
return result;
|
||||
}
|
||||
@ -24,7 +24,7 @@ u8_t io_byte_in(u16_t port) {
|
||||
* @param port
|
||||
* @param data
|
||||
*/
|
||||
void io_byte_out(u16_t port, u8_t data) {
|
||||
void io_byte_out(uint16_t port, uint8_t data) {
|
||||
__asm__("out %%al, %%dx" : : "a" (data), "d" (port));
|
||||
}
|
||||
|
||||
@ -37,8 +37,8 @@ void io_byte_out(u16_t port, u8_t data) {
|
||||
* @param port
|
||||
* @return the read word
|
||||
*/
|
||||
u16_t io_word_in(u16_t port) {
|
||||
u16_t result;
|
||||
uint16_t io_word_in(uint16_t port) {
|
||||
uint16_t result;
|
||||
__asm__("in %%dx, %%ax" : "=a" (result) : "d" (port));
|
||||
return result;
|
||||
}
|
||||
@ -52,6 +52,6 @@ u16_t io_word_in(u16_t port) {
|
||||
* @param port
|
||||
* @param data
|
||||
*/
|
||||
void io_word_out(u16_t port, u16_t data) {
|
||||
void io_word_out(uint16_t port, uint16_t data) {
|
||||
__asm__("out %%ax, %%dx" : : "a" (data), "d" (port));
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef KERNEL_IO_H
|
||||
#define KERNEL_IO_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Wrapper function that reads a byte from the specified I/O port.
|
||||
*
|
||||
@ -10,7 +12,7 @@
|
||||
* @param port
|
||||
* @return the read byte
|
||||
*/
|
||||
u8_t io_byte_in(u16_t port);
|
||||
uint8_t io_byte_in(uint16_t port);
|
||||
|
||||
/**
|
||||
* Wrapper function that writes a byte to the specified I/O port.
|
||||
@ -21,7 +23,7 @@ u8_t io_byte_in(u16_t port);
|
||||
* @param port
|
||||
* @param data
|
||||
*/
|
||||
void io_byte_out(u16_t port, u8_t data);
|
||||
void io_byte_out(uint16_t port, uint8_t data);
|
||||
|
||||
/**
|
||||
* Wrapper function that reads a word from the specified I/O port.
|
||||
@ -32,7 +34,7 @@ void io_byte_out(u16_t port, u8_t data);
|
||||
* @param port
|
||||
* @return the read word
|
||||
*/
|
||||
u16_t io_word_in(u16_t port);
|
||||
uint16_t io_word_in(uint16_t port);
|
||||
|
||||
/**
|
||||
* Wrapper function that writes a word to the specified I/O port.
|
||||
@ -43,6 +45,6 @@ u16_t io_word_in(u16_t port);
|
||||
* @param port
|
||||
* @param data
|
||||
*/
|
||||
void io_word_out(u16_t port, u16_t data);
|
||||
void io_word_out(uint16_t port, uint16_t data);
|
||||
|
||||
#endif //KERNEL_IO_H
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include "util.h"
|
||||
|
||||
/**
|
||||
* Copy `num_bytes` many bytes from the `source` memory to the
|
||||
@ -7,8 +8,16 @@
|
||||
* @param destination
|
||||
* @param num_bytes
|
||||
*/
|
||||
void mem_copy(char* source, char* destination, int num_bytes) {
|
||||
void mem_copy(uint8_t* source, uint8_t* destination, int num_bytes) {
|
||||
for ( int i = 0; i < num_bytes; i += 1 ) {
|
||||
*(destination + i) = *(source + i);
|
||||
}
|
||||
}
|
||||
|
||||
void mem_set(uint8_t* destination, uint8_t value, uint32_t length) {
|
||||
uint8_t* temp = (uint8_t*) destination;
|
||||
while ( length != 0 ) {
|
||||
*temp++ = value;
|
||||
length -= 1;
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
#ifndef KERNEL_MEM_H
|
||||
#define KERNEL_MEM_H
|
||||
|
||||
void mem_copy(char* source, char* destination, int num_bytes);
|
||||
void mem_copy(uint8_t* source, uint8_t* destination, int num_bytes);
|
||||
|
||||
void mem_set(uint8_t* destination, uint8_t value, uint32_t length);
|
||||
|
||||
#endif //KERNEL_MEM_H
|
||||
|
Loading…
Reference in New Issue
Block a user