Initial commit

This commit is contained in:
2021-10-10 14:39:17 +08:00
commit d25da95e1e
135 changed files with 19184 additions and 0 deletions

194
interrupt/handler.asm.S Normal file
View File

@ -0,0 +1,194 @@
format elf64
; sysvx64call void interrupt_Handler(a, b, c, d, e, f)
extrn interrupt_Handler
; sysvx64call void interrupt_Handler128(a, b, c, d, e, f)
; Input: rax(syscall opcode)
extrn interrupt_Handler128
extrn io_WriteConsoleASCII
public interrupt_Int0
public interrupt_Int1
public interrupt_Int2
public interrupt_Int3
public interrupt_Int4
public interrupt_Int5
public interrupt_Int6
public interrupt_Int7
public interrupt_Int8
public interrupt_Int9
public interrupt_Int10
public interrupt_Int11
public interrupt_Int12
public interrupt_Int13
public interrupt_Int14
public interrupt_Int15
public interrupt_Int16
public interrupt_Int17
public interrupt_Int18
public interrupt_Int19
public interrupt_Int20
public interrupt_Int21
public interrupt_Int22
public interrupt_Int23
public interrupt_Int24
public interrupt_Int25
public interrupt_Int26
public interrupt_Int27
public interrupt_Int28
public interrupt_Int29
public interrupt_Int30
public interrupt_Int31
public interrupt_Int128
section '.text' executable
macro inth op1 {
push rdi
mov rdi, op1
push rsi
push rdx
mov rdx, [rsp+24]
push rcx
push r8
push r9
push r10
push r11
push rax
call interrupt_Handler
pop rax
pop r11
pop r10
pop r9
pop r8
pop rcx
pop rdx
pop rsi
pop rdi
iretq
}
macro inth_err op1 {
push rsi
push rdi
mov rdi, op1
mov esi, [rsp+16]
push rdx
mov rdx, [rsp+32]
push rcx
push r8
push r9
push r10
push r11
push rax
call interrupt_Handler
pop rax
pop r11
pop r10
pop r9
pop r8
pop rcx
pop rdx
pop rdi
pop rsi
add rsp, 8 ; pop the error code
iretq
}
interrupt_Int0: ; does not return
inth 0
interrupt_Int1:
inth 1
interrupt_Int2:
inth 2
interrupt_Int3:
inth 3
interrupt_Int4:
inth 4
interrupt_Int5:
inth 5
interrupt_Int6:
inth 6
interrupt_Int7:
inth 7
interrupt_Int8:
inth 8
interrupt_Int9:
inth 9
interrupt_Int10:
inth_err 10
interrupt_Int11:
inth_err 11
interrupt_Int12:
inth_err 12
interrupt_Int13:
inth_err 13
interrupt_Int14:
inth_err 14
interrupt_Int15:
inth 15
interrupt_Int16:
inth 16
interrupt_Int17:
inth_err 17
interrupt_Int18:
inth 18
interrupt_Int19:
inth 19
interrupt_Int20:
inth 20
interrupt_Int21:
inth_err 21
interrupt_Int22:
inth 22
interrupt_Int23:
inth 23
interrupt_Int24:
inth 24
interrupt_Int25:
inth 25
interrupt_Int26:
inth 26
interrupt_Int27:
inth 27
interrupt_Int28:
inth 28
interrupt_Int29:
inth 29
interrupt_Int30:
inth 30
interrupt_Int31:
inth 31
interrupt_Int128:
;sub rsp, 32
;mov rcx, interrupt_string
;call io_WriteConsoleASCII
;add rsp, 32
;iretq
; no need to save the registers
;push rax
;push rdi
;push rsi
;push rdx
;push rcx
;push r8
;push r9
;push r10
;push r11
call interrupt_Handler128
;pop r11
;pop r10
;pop r9
;pop r8
;pop rcx
;pop rdx
;pop rsi
;pop rdi
;pop rax
iretq

52
interrupt/handler.c Normal file
View File

@ -0,0 +1,52 @@
#include "interrupt.h"
#include "../runtime/panic_assert.h"
const char *interrupt_Descriptions[] = {
"Divide Error Execption",
"Debug Exception",
"NMI Interrupt",
"Breakpoint Exception",
"Overflow Exception",
"BOUND Range Exceeded Exception",
"Invalid Opcode Exception",
"Device Not Available Exception",
"Double Fault Exception",
"Coprocessor Segment Overrun",
"Invalid TSS Exception",
"Segment Not Present",
"Stack Fault Exception",
"General Protection Exception",
"Page-Fault Exception",
"Interrupt 15",
"x87 FPU Floating-Point Error",
"Alignment Check Exception",
"Machine-Check Exception",
"SIMD Floating-Point Exception",
"Interrupt 20",
"Control Protection Exception",
"Interrupt 22",
"Interrupt 23",
"Interrupt 24",
"Interrupt 25",
"Interrupt 26",
"Interrupt 27",
"Interrupt 28",
"Interrupt 29",
"Interrupt 30",
"Interrupt 31",
};
SYSV_ABI void interrupt_Handler(int vec, int errcode, uint64_t rip, int c, int d, int e) {
io_Printf("Panic: INT %02xh: %s, err=%d(0x%02x), rip=%llx\n", vec, interrupt_Descriptions[vec], errcode, errcode, rip);
__Panic_HaltSystem();
}
// handler for INT 80h
SYSV_ABI void interrupt_Handler128(int a, int b, int c, int d, int e, int f) {
int opcode;
asm volatile("mov %%eax, %0"
: "=rm"(opcode)); // read the opcode
io_Printf("INT 80h: EAX(opcode)=%d, abcdef=[%d,%d,%d,%d,%d,%d]\n", opcode, a, b, c, d, e, f);
}

38
interrupt/handlers.h Normal file
View File

@ -0,0 +1,38 @@
#pragma once
// the functions are not to be called, but to be taken address and put into IDT
void interrupt_Int0();
void interrupt_Int1();
void interrupt_Int2();
void interrupt_Int3();
void interrupt_Int4();
void interrupt_Int5();
void interrupt_Int6();
void interrupt_Int7();
void interrupt_Int8();
void interrupt_Int9();
void interrupt_Int10();
void interrupt_Int11();
void interrupt_Int12();
void interrupt_Int13();
void interrupt_Int14();
void interrupt_Int15();
void interrupt_Int16();
void interrupt_Int17();
void interrupt_Int18();
void interrupt_Int19();
void interrupt_Int20();
void interrupt_Int21();
void interrupt_Int22();
void interrupt_Int23();
void interrupt_Int24();
void interrupt_Int25();
void interrupt_Int26();
void interrupt_Int27();
void interrupt_Int28();
void interrupt_Int29();
void interrupt_Int30();
void interrupt_Int31();
void interrupt_Int128();

118
interrupt/init.c Normal file
View File

@ -0,0 +1,118 @@
#include "interrupt.h"
#include "handlers.h"
#include "../memory/memory.h"
#include "../runtime/stdio.h"
#include "../runtime/panic_assert.h"
#include "testcode.h"
interrupt_DescriptorTableReference *interrupt_IDTR, *interrupt_GDTR;
bool interrupt_Enabled;
/*
SYSV_ABI void interrupt_MapHandler(void *handler, int interrupt) {
//io_Printf("interrupt_MapHandler: handler %llx, int %d\n", handler, interrupt);
uint64_t *base = (uint64_t *)(KERNEL_IDT_MAPPING + interrupt * 16ull);
uint64_t b = 0;
b |= (uint64_t)handler & 0xFFFFull; // Offset[15:0], 15:0
b |= (uint64_t)GDT_EXEC_SELECTOR << 16; // Segment Selector, 31:16
b |= IDT_TYPE_32_INTERRUPT_GATE; // Type = 32-bit Interrupt Gate, 44:40
b |= IDT_RING0; // Ring 0, 46:45
b |= IDT_PRESENT; // Present, 47
b |= ((uint64_t)handler & 0xFFFF0000ull) << 32; // Offset[31:16], 63:48
*base = b;
*(base + 1) = (uint64_t)handler >> 32;
}
*/
// defined in assembly
SYSV_ABI void interrupt_MapHandler(void *handler, int interrupt);
void interrupt_Init() {
assert(sizeof(interrupt_DescriptorTableReference) == 10 && "GDTR/IDTR size must be 10 bytes");
assert(offsetof(interrupt_DescriptorTableReference, base) == 2 && "GDTR/IDTR must be packed");
assert(KERNEL_IDTR_MAPPING % 4 == 0 && "IDTR not aligned to 4-byte");
assert(KERNEL_GDTR_MAPPING % 4 == 0 && "GDTR not aligned to 4-byte");
// allocate GDTR
io_WriteConsoleASCII("interrupt_Init() calling\n");
interrupt_GDTR = (interrupt_DescriptorTableReference *)KERNEL_GDTR_MAPPING;
interrupt_GDTR->length = 4 * GDT_SIZE_BYTES - 1;
interrupt_GDTR->base = (void *)KERNEL_GDT_MAPPING;
io_WriteConsoleASCII("GDTR Written\n");
// set the 2 dummy gdts
uint64_t *gdt = (uint64_t *)KERNEL_GDT_MAPPING;
gdt[0] = 0;
gdt[1] = GDT_EXEC;
gdt[2] = GDT_DATA;
gdt[3] = GDT_EXEC_RING3;
gdt[4] = GDT_DATA_RING3;
io_WriteConsoleASCII("GDT Installed\n");
interrupt_LoadGDT(interrupt_GDTR); // set it!
io_WriteConsoleASCII("GDT OK\n");
//interrupt_Testcode();
io_WriteConsoleASCII("Testcode OK\n");
// allocate IDTR
//interrupt_IDTR = kMalloc(sizeof(interrupt_DescriptorTableReference));
interrupt_IDTR = (interrupt_DescriptorTableReference *)KERNEL_IDTR_MAPPING;
interrupt_IDTR->length = KERNEL_IDT_SIZE - 1;
interrupt_IDTR->base = (void *)KERNEL_IDT_MAPPING;
io_WriteConsoleASCII("IDT Written\n");
interrupt_MapHandler(interrupt_Int0, 0);
interrupt_MapHandler(interrupt_Int1, 1);
interrupt_MapHandler(interrupt_Int2, 2);
interrupt_MapHandler(interrupt_Int3, 3);
interrupt_MapHandler(interrupt_Int4, 4);
interrupt_MapHandler(interrupt_Int5, 5);
interrupt_MapHandler(interrupt_Int6, 6);
interrupt_MapHandler(interrupt_Int7, 7);
interrupt_MapHandler(interrupt_Int8, 8);
interrupt_MapHandler(interrupt_Int9, 9);
interrupt_MapHandler(interrupt_Int10, 10);
interrupt_MapHandler(interrupt_Int11, 11);
interrupt_MapHandler(interrupt_Int12, 12);
interrupt_MapHandler(interrupt_Int13, 13);
interrupt_MapHandler(interrupt_Int14, 14);
interrupt_MapHandler(interrupt_Int15, 15);
interrupt_MapHandler(interrupt_Int16, 16);
interrupt_MapHandler(interrupt_Int17, 17);
interrupt_MapHandler(interrupt_Int18, 18);
interrupt_MapHandler(interrupt_Int19, 19);
interrupt_MapHandler(interrupt_Int20, 20);
interrupt_MapHandler(interrupt_Int21, 21);
interrupt_MapHandler(interrupt_Int22, 22);
interrupt_MapHandler(interrupt_Int23, 23);
interrupt_MapHandler(interrupt_Int24, 24);
interrupt_MapHandler(interrupt_Int25, 25);
interrupt_MapHandler(interrupt_Int26, 26);
interrupt_MapHandler(interrupt_Int27, 27);
interrupt_MapHandler(interrupt_Int28, 28);
interrupt_MapHandler(interrupt_Int29, 29);
interrupt_MapHandler(interrupt_Int30, 30);
interrupt_MapHandler(interrupt_Int31, 31);
interrupt_MapHandler(interrupt_Int128, 128);
io_WriteConsoleASCII("IDT Installed\n");
interrupt_LoadIDT(interrupt_IDTR); // set it!
io_WriteConsoleASCII("IDT OK\n");
interrupt_Enabled = true;
asm volatile("sti");
interrupt_ReloadSegments();
io_WriteConsoleASCII("Segment Registers Reloaded\n");
}

74
interrupt/interrupt.h Normal file
View File

@ -0,0 +1,74 @@
#pragma once
#include "../main.h"
#include "stdbool.h"
#ifdef __cplusplus
extern "C" {
#endif
#define GDT_SIZE_BYTES 4
#define GDT_EXEC 0x00AF9A000000FFFFull // Base=0, Limit=max, Access=Present|Ring0|TypeUser|Exec|Readable, Flag=GranularityPage|Long
#define GDT_DATA 0x00EF92000000FFFFull // Base=0, Limit=max, Access=Present|Ring0|TypeUser|Writable, Flag=GranularityPage|Size
#define GDT_EXEC_RING3 0x00AFFA000000FFFFull // Base=0, Limit=max, Access=Present|Ring3|TypeUser|Exec|Readable, Flag=GranularityPage|Long
#define GDT_DATA_RING3 0x00EFF2000000FFFFull // Base=0, Limit=max, Access=Present|Ring3|TypeUser|Writable, Flag=GranularityPage|Size
#define GDT_EXEC_SELECTOR 0x08 // SelectorIndex=1, TableIndicator=GDT(0), Privilege=Ring0
#define GDT_DATA_SELECTOR 0x10 // SelectorIndex=2, TableIndicator=GDT(0), Privilege=Ring0
#define GDT_EXEC_RING3_SELECTOR 0x1B // SelectorIndex=3, TableIndicator=GDT(0), Privilege=Ring3
#define GDT_DATA_RING3_SELECTOR 0x23 // SelectorIndex=4, TableIndicator=GDT(0), Privilege=Ring3
#define IDT_PRESENT (1ull << 47)
#define IDT_RING0 0
#define IDT_RING1 (1ull << 45)
#define IDT_RING2 (2ull << 45)
#define IDT_RING3 (3ull << 45)
#define IDT_TYPE_32_CALL_GATE (0x0Cull << 40)
#define IDT_TYPE_32_INTERRUPT_GATE (0x0Eull << 40)
#define IDT_TYPE_32_TRAP_GATE (0x0Full << 40)
typedef struct {
uint16_t length;
void * base;
} PACKED interrupt_DescriptorTableReference;
// address of IDTR and GDTR, allocated by kMalloc() and is never freed
extern interrupt_DescriptorTableReference *interrupt_IDTR, *interrupt_GDTR;
// true if Init() has been called and interrupt handling is on
extern bool interrupt_Enabled;
// initializes interrupt handling like IDT and a dummy GDT
void interrupt_Init();
SYSV_ABI void interrupt_MapHandler(void *handler, int interrupt);
// errorcode is 0 if nonexistent
//
// for IRQs, params are documented in assembly
SYSV_ABI void interrupt_Handler(int vec, int errcode, uint64_t rip, int c, int d, int e);
// defined in assembly
SYSV_ABI void interrupt_LoadGDT(void *gdtr);
SYSV_ABI void interrupt_LoadIDT(void *idtr);
SYSV_ABI void interrupt_ReloadSegments();
#define INTERRUPT_DISABLE \
uintptr_t __interrupt_flags; \
asm volatile("pushf\n\tcli\n\tpop %0" \
: "=r"(__interrupt_flags) \
: \
: "memory")
#define INTERRUPT_RESTORE \
asm volatile("push %0\n\tpopf" \
: \
: "rm"(__interrupt_flags) \
: "memory", "cc")
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,57 @@
format elf64
extrn io_WriteConsoleASCII
section '.rodata'
interrupt_string:
db "Interrupt Testcode", 0x0A, 0x00
section '.data' writable
align 4
idt:
rb 50*16
idtr:
dw (50*16)-1
dq idt
section '.text' executable
int_handler:
push rax
push rcx
push rdx
push r8
push r9
push r10
push r11
sub rsp, 32
mov rcx, interrupt_string
call io_WriteConsoleASCII
add rsp, 32
pop r11
pop r10
pop r9
pop r8
pop rdx
pop rcx
pop rax
iretq
public interrupt_Testcode
interrupt_Testcode:
lidt [idtr]
mov rax, int_handler
mov [idt+49*16], ax
mov word [idt+49*16+2], 0x08
mov word [idt+49*16+4], 0x8e00
shr rax, 16
mov [idt+49*16+6], ax
shr rax, 16
mov [idt+49*16+8], rax
int 49
ret

45
interrupt/load_gdt.S Normal file
View File

@ -0,0 +1,45 @@
format elf64
public interrupt_ReloadSegments
public interrupt_LoadGDT
public interrupt_LoadIDT
section '.text' executable
; sysvx64call void interrupt_LoadGDT(void* gdtr)
;
; Input: (void* rdi)
; Clobbers: none
interrupt_LoadGDT:
lgdt [rdi]
ret
; sysvx64call void interrupt_ReloadSegments()
;
; Clobbers: rax
interrupt_ReloadSegments:
mov eax, 0x10 ; my data segment
xor ax, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
;jmp 0x08:.flush
; as in https://forum.osdev.org/viewtopic.php?f=1&t=30739
; farjump does not work in long mode, you need to do a far return:
pop rax
push qword 0x08 ; my code segment
push rax
retfq
; sysvx64call void interrupt_LoadIDT(void* idtr)
;
; Input: (void* rdi)
; Clobbers: none
interrupt_LoadIDT:
lidt [rdi]
ret

25
interrupt/map_handler.S Normal file
View File

@ -0,0 +1,25 @@
format elf64
extrn io_WriteConsoleASCII
public interrupt_MapHandler
section '.text' executable
; sysvx64call void interrupt_MapHandler(uint64_t handler, int interrupt)
;
; Input: (uint64_t rdi, int rsi)
; Clobbers: rax, flags
interrupt_MapHandler:
mov rax, 0xFFFFFFFEC0000000 ; KERNEL_IDT_MAPPING
shl rsi, 4 ; rsi *= 16
add rsi, rax ; rsi += KERNEL_IDT_MAPPING
mov [rsi], di
mov word [rsi+2], 0x08 ; GDT_EXEC_SELECTOR (index=1)
mov word [rsi+4], 0x8e00
shr rdi, 16
mov [rsi+6], di
shr rdi, 16
mov [rsi+8], rdi
ret

18
interrupt/syscall.S Normal file
View File

@ -0,0 +1,18 @@
format elf64
public asm_Syscall as 'Syscall' ; syscall is a reserved token
section ".text" executable
; sysvx64call int Syscall(int syscall_id, int a,b,c,d,e,f)
asm_Syscall:
mov rax, rdi
mov rdi, rsi
mov rsi, rdx
mov rdx, rcx
mov rcx, r8
mov r8, r9
mov r9, [rsp+8]
int 0x80
ret

8
interrupt/syscall.h Normal file
View File

@ -0,0 +1,8 @@
#pragma once
#include "../main.h"
// this function is here, well, mostly just for fun.
//
// userspace in the far future should need this
SYSV_ABI long Syscall(int id, long a, long b, long c, long d, long e, long f);

6
interrupt/testcode.h Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include "../main.h"
SYSV_ABI void interrupt_Testcode();