Initial commit
This commit is contained in:
commit
cbc51f523e
125 changed files with 34817 additions and 0 deletions
137
src/hal/apic.c
Normal file
137
src/hal/apic.c
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
#include "../sys/acpi.h"
|
||||
#include "../drivers/pmt.h"
|
||||
#include "smp.h"
|
||||
#include "timer.h"
|
||||
#include "ioapic.h"
|
||||
#include <lock.h>
|
||||
#include <stdio.h>
|
||||
#include <SFB25.h>
|
||||
#include <cpuid.h> // GCC specific
|
||||
|
||||
#define LAPIC_ID_REG 0x020
|
||||
#define LAPIC_EOI_REG 0x0B0
|
||||
#define LAPIC_SPURIOUS_REG 0x0F0
|
||||
#define LAPIC_ERR_REG 0x280
|
||||
|
||||
#define LAPIC_LINT0_REG 0x350
|
||||
#define LAPIC_LINT1_REG 0x360
|
||||
|
||||
#define LAPIC_ICR_REG 0x300
|
||||
|
||||
#define LAPIC_LVT_TIMER_REG 0x320
|
||||
#define LAPIC_TIMER_INITIAL_CNT_REG 0x380
|
||||
#define LAPIC_TIMER_CURRENT_CNT_REG 0x390
|
||||
#define LAPIC_TIMER_DIVIDER_REG 0x3E0
|
||||
|
||||
#define LAPIC_TIMER_MASK (1 << 16)
|
||||
#define LAPIC_TIMER_UNMASK 0xFFFEFFFF
|
||||
|
||||
#define LAPIC_TIMER_PERIODIC (1 << 17)
|
||||
#define LAPIC_TIMER_VECTOR 69
|
||||
|
||||
|
||||
extern madt_t *madt;
|
||||
extern uint64_t hhdmoffset;
|
||||
|
||||
uint64_t lapic_address = 0;
|
||||
uint64_t timer_speed_us = 0;
|
||||
|
||||
void lapic_write_reg(uint32_t reg, uint32_t data){
|
||||
*((uint32_t*)(lapic_address+reg)) = data;
|
||||
}
|
||||
|
||||
uint32_t lapic_read_reg(uint32_t reg){
|
||||
return(*((uint32_t*)(lapic_address+reg)));
|
||||
}
|
||||
|
||||
/* Assumes single-threaded*/
|
||||
void apic_sleep(uint64_t ms){
|
||||
uint64_t lapic_timer_ticks = get_cpu_struct()->lapic_timer_ticks;
|
||||
uint64_t curcnt = get_cpu_struct()->lapic_timer_ticks;
|
||||
while (lapic_timer_ticks - curcnt < ms) {
|
||||
lapic_timer_ticks = get_cpu_struct()->lapic_timer_ticks;
|
||||
}
|
||||
}
|
||||
|
||||
atomic_flag lapic_timer_flag = ATOMIC_FLAG_INIT;
|
||||
void lapic_timer_init(int us){
|
||||
acquire_lock(&lapic_timer_flag);
|
||||
/* Stop the APIC timer */
|
||||
lapic_write_reg(LAPIC_TIMER_INITIAL_CNT_REG, 0);
|
||||
|
||||
/* Set the divisor to 16 */
|
||||
lapic_write_reg(LAPIC_TIMER_DIVIDER_REG, 0b11);
|
||||
|
||||
/* Set the intial count to max */
|
||||
lapic_write_reg(LAPIC_TIMER_INITIAL_CNT_REG, 0xffffffff);
|
||||
|
||||
/* Call a delay function based on the available timer */
|
||||
pmt_delay(us);
|
||||
|
||||
/* Mask the timer (prevents interrupts) */
|
||||
lapic_write_reg(LAPIC_LVT_TIMER_REG, LAPIC_TIMER_MASK);
|
||||
|
||||
/* Determine the inital count to be used for a delay set by `timer_speed_us` */
|
||||
uint32_t calibration = 0xffffffff - lapic_read_reg(LAPIC_TIMER_CURRENT_CNT_REG);
|
||||
|
||||
/* Set the timer interrupt vector and put the timer into periodic mode */
|
||||
lapic_write_reg(LAPIC_LVT_TIMER_REG, LAPIC_TIMER_VECTOR | LAPIC_TIMER_PERIODIC);
|
||||
|
||||
/* Set the inital count to the calibration */
|
||||
lapic_write_reg(LAPIC_TIMER_INITIAL_CNT_REG, calibration);
|
||||
|
||||
free_lock(&lapic_timer_flag);
|
||||
|
||||
}
|
||||
|
||||
void apic_init(void){
|
||||
asm("cli");
|
||||
|
||||
lapic_address = madt->lic_address + hhdmoffset;
|
||||
|
||||
lapic_ao_t *lapic_ao = (lapic_ao_t*) find_ics(0x5); // Local APIC Address Override
|
||||
|
||||
/* If there is a lapic address override present then use that instead */
|
||||
if(lapic_ao){
|
||||
/* Check that the field isnt 0 */
|
||||
if(lapic_ao->lapic_address != 0){
|
||||
lapic_address = lapic_ao->lapic_address + hhdmoffset;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable the lapic and set the spurious interrupt vector to 0xFF */
|
||||
lapic_write_reg(LAPIC_SPURIOUS_REG, 0x1FF);
|
||||
|
||||
/* Initialize the IOAPIC */
|
||||
ioapic_init();
|
||||
|
||||
/* Start the timers for calibration of the APIC timer */
|
||||
timer_init();
|
||||
|
||||
/* Start the APIC timer with 10ms timer */
|
||||
lapic_timer_init(10000);
|
||||
|
||||
asm("sti");
|
||||
}
|
||||
|
||||
void ap_apic_init(){
|
||||
asm("cli");
|
||||
/* Enable the lapic and set the spurious interrupt vector to 0xFF */
|
||||
lapic_write_reg(LAPIC_SPURIOUS_REG, 0x1FF);
|
||||
|
||||
/* Start the APIC timer */
|
||||
lapic_timer_init(10000);
|
||||
|
||||
asm("sti");
|
||||
}
|
||||
|
||||
void apic_timer_handler(){
|
||||
lapic_write_reg(LAPIC_EOI_REG, 0);
|
||||
if(get_cpu_struct_initialized()){
|
||||
get_cpu_struct()->lapic_timer_ticks++;
|
||||
}
|
||||
}
|
||||
|
||||
void apic_send_ipi(uint8_t dest_field, uint8_t dest_shorthand, uint8_t trigger, uint8_t level, uint8_t status, uint8_t destination, uint8_t delivery_mode, uint8_t vector){
|
||||
|
||||
}
|
||||
4
src/hal/apic.h
Normal file
4
src/hal/apic.h
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
void apic_init(void);
|
||||
void ap_apic_init();
|
||||
void apic_sleep(int ms);
|
||||
34
src/hal/gdt.asm
Normal file
34
src/hal/gdt.asm
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
[bits 64]
|
||||
|
||||
default rel
|
||||
|
||||
extern gdtr
|
||||
|
||||
global s_load_gdt
|
||||
|
||||
s_load_gdt:
|
||||
|
||||
lgdt [gdtr]
|
||||
|
||||
; move kernel data offset into data registers
|
||||
mov ax, 0x10
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov ss, ax
|
||||
|
||||
; zero the optional data registers
|
||||
xor ax, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
; pop the return instruction pointer from the stack
|
||||
pop rax
|
||||
|
||||
; first push the segment selector we will far return to (0x08 is the code segment)
|
||||
push 0x08
|
||||
|
||||
; then push the return instruction pointer
|
||||
push rax
|
||||
|
||||
; and finally far return
|
||||
retfq
|
||||
33
src/hal/gdt.c
Normal file
33
src/hal/gdt.c
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#include "gdt.h"
|
||||
#include <stdio.h>
|
||||
|
||||
gdt_descriptor gdt[5] = {0};
|
||||
|
||||
gdt_register gdtr = {sizeof(gdt)-1, (uint64_t)(&gdt)};
|
||||
|
||||
extern void s_load_gdt();
|
||||
|
||||
void gdt_set_entry(int num, unsigned long long base, unsigned long long limit, unsigned char access, unsigned char granularity){
|
||||
// descriptor base access
|
||||
gdt[num].base_low = (base & 0xFFFF);
|
||||
gdt[num].base_middle = (base >> 16) & 0xFF;
|
||||
gdt[num].base_high = (base >> 24) & 0xFF;
|
||||
|
||||
// descriptor limits
|
||||
gdt[num].limit_low = (limit & 0xFFFF);
|
||||
gdt[num].granularity = ((limit >> 16) & 0x0F);
|
||||
|
||||
// granularity and access flag
|
||||
gdt[num].granularity |= (granularity & 0xF) << 4;
|
||||
gdt[num].access = access;
|
||||
}
|
||||
|
||||
void set_gdt(void){
|
||||
gdt_set_entry(0, 0, 0, 0, 0); // null segment offset 0x00
|
||||
gdt_set_entry(1, 0, 0xFFFFF, 0x9A, 0xA); // kernel code offset 0x08
|
||||
gdt_set_entry(2, 0, 0xFFFFF, 0x92, 0xA); // kernel data offset 0x10
|
||||
gdt_set_entry(3, 0, 0xFFFFF, 0xFA, 0xA); // userspace code offset 0x18
|
||||
gdt_set_entry(4, 0, 0xFFFFF, 0xF2, 0xA); // userspace data offset 0x20
|
||||
s_load_gdt();
|
||||
|
||||
}
|
||||
17
src/hal/gdt.h
Normal file
17
src/hal/gdt.h
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#include <stdint.h>
|
||||
|
||||
typedef struct gdt_descriptor {
|
||||
uint16_t limit_low;
|
||||
uint16_t base_low;
|
||||
uint8_t base_middle;
|
||||
uint8_t access;
|
||||
uint8_t granularity;
|
||||
uint8_t base_high;
|
||||
} __attribute((packed)) gdt_descriptor;
|
||||
|
||||
typedef struct gdt_register {
|
||||
uint16_t limit;
|
||||
uint64_t base_address;
|
||||
} __attribute((packed)) gdt_register;
|
||||
|
||||
void set_gdt(void);
|
||||
330
src/hal/idt.asm
Normal file
330
src/hal/idt.asm
Normal file
|
|
@ -0,0 +1,330 @@
|
|||
default rel
|
||||
|
||||
extern interrupt_handler
|
||||
|
||||
extern idtr
|
||||
|
||||
global s_isr0
|
||||
global s_isr1
|
||||
global s_isr2
|
||||
global s_isr3
|
||||
global s_isr4
|
||||
global s_isr5
|
||||
global s_isr6
|
||||
global s_isr7
|
||||
global s_isr8
|
||||
global s_isr9
|
||||
global s_isr10
|
||||
global s_isr11
|
||||
global s_isr12
|
||||
global s_isr13
|
||||
global s_isr14
|
||||
global s_isr15
|
||||
global s_isr16
|
||||
global s_isr17
|
||||
global s_isr18
|
||||
global s_isr19
|
||||
global s_isr20
|
||||
global s_isr21
|
||||
global s_isr22
|
||||
global s_isr23
|
||||
global s_isr24
|
||||
global s_isr25
|
||||
global s_isr26
|
||||
global s_isr27
|
||||
global s_isr28
|
||||
global s_isr29
|
||||
global s_isr30
|
||||
global s_isr31
|
||||
|
||||
global s_isr44
|
||||
|
||||
global s_isr69
|
||||
|
||||
global s_isr70
|
||||
|
||||
global s_isr255
|
||||
|
||||
global s_load_idt
|
||||
|
||||
s_isr0:
|
||||
;
|
||||
push qword 0 ; dummy
|
||||
push qword 0 ; isr num
|
||||
jmp isr_handler
|
||||
|
||||
s_isr1:
|
||||
|
||||
push qword 0 ; dummy
|
||||
push qword 1 ; isr num
|
||||
jmp isr_handler
|
||||
|
||||
s_isr2:
|
||||
|
||||
push qword 0 ; dummy
|
||||
push qword 2 ; isr num
|
||||
jmp isr_handler
|
||||
|
||||
s_isr3:
|
||||
|
||||
push qword 0 ; dummy
|
||||
push qword 3 ; isr num
|
||||
jmp isr_handler
|
||||
|
||||
s_isr4:
|
||||
|
||||
push qword 0 ; dummy
|
||||
push qword 4 ; isr num
|
||||
jmp isr_handler
|
||||
|
||||
s_isr5:
|
||||
|
||||
push qword 0 ; dummy
|
||||
push qword 5 ; isr num
|
||||
jmp isr_handler
|
||||
|
||||
s_isr6:
|
||||
|
||||
push qword 0 ; dummy
|
||||
push qword 6 ; isr num
|
||||
jmp isr_handler
|
||||
|
||||
s_isr7:
|
||||
|
||||
push qword 0 ; dummy
|
||||
push qword 7 ; isr num
|
||||
jmp isr_handler
|
||||
|
||||
s_isr8:
|
||||
|
||||
; dont push dummy as it already pushes one
|
||||
push qword 8 ; isr num
|
||||
jmp isr_handler
|
||||
|
||||
s_isr9:
|
||||
|
||||
push qword 0 ; dummy
|
||||
push qword 9 ; isr num
|
||||
jmp isr_handler
|
||||
|
||||
s_isr10:
|
||||
|
||||
; dont push dummy as it already pushes one
|
||||
push qword 10 ; isr num
|
||||
jmp isr_handler
|
||||
|
||||
s_isr11:
|
||||
|
||||
; dont push dummy as it already pushes one
|
||||
push qword 11 ; isr num
|
||||
jmp isr_handler
|
||||
|
||||
s_isr12:
|
||||
|
||||
; dont push dummy as it already pushes one
|
||||
push qword 12 ; isr num
|
||||
jmp isr_handler
|
||||
|
||||
s_isr13:
|
||||
|
||||
; dont push dummy as it already pushes one
|
||||
push qword 13 ; isr num
|
||||
jmp isr_handler
|
||||
|
||||
s_isr14:
|
||||
|
||||
; dont push dummy as it already pushes one
|
||||
push qword 14 ; isr num
|
||||
jmp isr_handler
|
||||
|
||||
s_isr15:
|
||||
|
||||
push qword 0 ; dummy
|
||||
push qword 15 ; isr num
|
||||
jmp isr_handler
|
||||
|
||||
s_isr16:
|
||||
|
||||
push qword 0 ; dummy
|
||||
push qword 16 ; isr num
|
||||
jmp isr_handler
|
||||
|
||||
s_isr17:
|
||||
|
||||
push qword 0 ; dummy
|
||||
push qword 17 ; isr num
|
||||
jmp isr_handler
|
||||
|
||||
s_isr18:
|
||||
|
||||
push qword 0 ; dummy
|
||||
push qword 18 ; isr num
|
||||
jmp isr_handler
|
||||
|
||||
; 19: Reserved
|
||||
s_isr19:
|
||||
|
||||
push qword 0
|
||||
push qword 19
|
||||
jmp isr_handler
|
||||
|
||||
; 20: Reserved
|
||||
s_isr20:
|
||||
|
||||
push qword 0
|
||||
push qword 20
|
||||
jmp isr_handler
|
||||
|
||||
; 21: Reserved
|
||||
s_isr21:
|
||||
|
||||
push qword 0
|
||||
push qword 21
|
||||
jmp isr_handler
|
||||
|
||||
; 22: Reserved
|
||||
s_isr22:
|
||||
|
||||
push qword 0
|
||||
push qword 22
|
||||
jmp isr_handler
|
||||
|
||||
; 23: Reserved
|
||||
s_isr23:
|
||||
|
||||
push qword 0
|
||||
push qword 23
|
||||
jmp isr_handler
|
||||
|
||||
; 24: Reserved
|
||||
s_isr24:
|
||||
|
||||
push qword 0
|
||||
push qword 24
|
||||
jmp isr_handler
|
||||
|
||||
; 25: Reserved
|
||||
s_isr25:
|
||||
|
||||
push qword 0
|
||||
push qword 25
|
||||
jmp isr_handler
|
||||
|
||||
; 26: Reserved
|
||||
s_isr26:
|
||||
|
||||
push qword 0
|
||||
push qword 26
|
||||
jmp isr_handler
|
||||
|
||||
; 27: Reserved
|
||||
s_isr27:
|
||||
|
||||
push qword 0
|
||||
push qword 27
|
||||
jmp isr_handler
|
||||
|
||||
; 28: Reserved
|
||||
s_isr28:
|
||||
|
||||
push qword 0
|
||||
push qword 28
|
||||
jmp isr_handler
|
||||
|
||||
; 29: Reserved
|
||||
s_isr29:
|
||||
|
||||
push qword 0
|
||||
push qword 29
|
||||
jmp isr_handler
|
||||
|
||||
; 30: Reserved
|
||||
s_isr30:
|
||||
|
||||
push qword 0
|
||||
push qword 30
|
||||
jmp isr_handler
|
||||
|
||||
; 31: Reserved
|
||||
s_isr31:
|
||||
|
||||
push qword 0
|
||||
push qword 31
|
||||
jmp isr_handler
|
||||
|
||||
s_isr44:
|
||||
|
||||
push qword 0
|
||||
push qword 44
|
||||
jmp isr_handler
|
||||
|
||||
; 69 - APIC timer
|
||||
s_isr69:
|
||||
|
||||
push qword 0
|
||||
push qword 69
|
||||
jmp isr_handler
|
||||
|
||||
; 70 - Kernel panic
|
||||
s_isr70:
|
||||
|
||||
push qword 0
|
||||
push qword 70
|
||||
jmp isr_handler
|
||||
|
||||
s_isr255:
|
||||
|
||||
push qword 0
|
||||
push qword 255
|
||||
jmp isr_handler
|
||||
|
||||
%macro pushaq 0
|
||||
push rax
|
||||
push rbx
|
||||
push rcx
|
||||
push rdx
|
||||
push rbp
|
||||
push rsi
|
||||
push rdi
|
||||
push r8
|
||||
push r9
|
||||
push r10
|
||||
push r11
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
|
||||
%endmacro
|
||||
|
||||
%macro popaq 0
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop r11
|
||||
pop r10
|
||||
pop r9
|
||||
pop r8
|
||||
pop rdi
|
||||
pop rsi
|
||||
pop rbp
|
||||
pop rdx
|
||||
pop rcx
|
||||
pop rbx
|
||||
pop rax
|
||||
%endmacro
|
||||
|
||||
isr_handler:
|
||||
pushaq
|
||||
mov rdi, rsp ; put stack frame as parameter for interrupt_handler
|
||||
call interrupt_handler
|
||||
popaq
|
||||
add rsp, 16 ; remove vector and error code from the stack
|
||||
iretq
|
||||
|
||||
s_load_idt:
|
||||
lidt [idtr]
|
||||
sti
|
||||
ret
|
||||
|
||||
230
src/hal/idt.c
Normal file
230
src/hal/idt.c
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
#include "idt.h"
|
||||
#include "error.h"
|
||||
#include "timer.h"
|
||||
#include <stdio.h>
|
||||
#include <lock.h>
|
||||
#include <SFB25.h>
|
||||
idt_descriptor idt[256] = {0};
|
||||
|
||||
idt_register idtr = {sizeof(idt)-1, (uint64_t)(&idt)};
|
||||
|
||||
/* Expand if needed */
|
||||
#define MAX_IRQ 256
|
||||
|
||||
/* IRQ structure list, eventually restructure to support IRQs on multiple cores */
|
||||
irq_t irq_list[MAX_IRQ] = {0};
|
||||
|
||||
extern void s_isr0();
|
||||
extern void s_isr1();
|
||||
extern void s_isr2();
|
||||
extern void s_isr3();
|
||||
extern void s_isr4();
|
||||
extern void s_isr5();
|
||||
extern void s_isr6();
|
||||
extern void s_isr7();
|
||||
extern void s_isr8();
|
||||
extern void s_isr9();
|
||||
extern void s_isr10();
|
||||
extern void s_isr11();
|
||||
extern void s_isr12();
|
||||
extern void s_isr13();
|
||||
extern void s_isr14();
|
||||
extern void s_isr15();
|
||||
extern void s_isr16();
|
||||
extern void s_isr17();
|
||||
extern void s_isr18();
|
||||
extern void s_isr19();
|
||||
extern void s_isr20();
|
||||
extern void s_isr21();
|
||||
extern void s_isr22();
|
||||
extern void s_isr23();
|
||||
extern void s_isr24();
|
||||
extern void s_isr25();
|
||||
extern void s_isr26();
|
||||
extern void s_isr27();
|
||||
extern void s_isr28();
|
||||
extern void s_isr29();
|
||||
extern void s_isr30();
|
||||
extern void s_isr31();
|
||||
|
||||
extern void s_isr44();
|
||||
|
||||
extern void s_isr69();
|
||||
extern void s_isr70();
|
||||
|
||||
extern void s_isr255();
|
||||
|
||||
extern void s_load_idt();
|
||||
|
||||
atomic_flag irq_register_lock = ATOMIC_FLAG_INIT;
|
||||
|
||||
/* Registers an IRQ with the specified vector. */
|
||||
kstatus register_irq_vector(uint8_t vector, void *base, uint8_t flags){
|
||||
acquire_lock(&irq_register_lock);
|
||||
|
||||
if(!irq_list[vector].in_use){
|
||||
free_lock(&irq_register_lock);
|
||||
return KERNEL_STATUS_ERROR;
|
||||
}
|
||||
|
||||
set_idt_descriptor(vector, base, flags);
|
||||
|
||||
irq_list[vector].base = base;
|
||||
irq_list[vector].in_use = true;
|
||||
|
||||
s_load_idt();
|
||||
|
||||
free_lock(&irq_register_lock);
|
||||
|
||||
return KERNEL_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Registers an IRQ and returns the vector */
|
||||
int register_irq(void *base, uint8_t flags){
|
||||
acquire_lock(&irq_register_lock);
|
||||
|
||||
for(size_t i = 0; i < MAX_IRQ; i++){
|
||||
if(!irq_list[i].in_use) {
|
||||
set_idt_descriptor(i, base, flags);
|
||||
irq_list[i].base = base;
|
||||
irq_list[i].in_use = true;
|
||||
free_lock(&irq_register_lock);
|
||||
s_load_idt();
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
free_lock(&irq_register_lock);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void set_idt_descriptor(uint8_t vector, void *base, uint8_t flags){
|
||||
idt[vector].offset_low = ((uint64_t)base & 0xffff);
|
||||
|
||||
idt[vector].segment_sel = 0x08; // kernel code segment
|
||||
|
||||
idt[vector].ist = 0;
|
||||
idt[vector].attributes = flags;
|
||||
|
||||
idt[vector].offset_high = ((uint64_t)base >> 16) & 0xffff;
|
||||
idt[vector].offset_higher = ((uint64_t)base >> 32) & 0xffffffff;
|
||||
|
||||
idt[vector].reserved = 0;
|
||||
}
|
||||
|
||||
void set_idt(void){
|
||||
|
||||
/* Set all the reserved vectors as used */
|
||||
for(size_t i = 0; i < 32; i++){
|
||||
irq_list[i].in_use = true;
|
||||
irq_list[i].base = NULL;
|
||||
}
|
||||
|
||||
set_idt_descriptor(0, s_isr0, 0x8E);
|
||||
set_idt_descriptor(1, s_isr1, 0x8E);
|
||||
set_idt_descriptor(2, s_isr2, 0x8E);
|
||||
set_idt_descriptor(3, s_isr3, 0x8E);
|
||||
set_idt_descriptor(4, s_isr4, 0x8E);
|
||||
set_idt_descriptor(5, s_isr5, 0x8E);
|
||||
set_idt_descriptor(6, s_isr6, 0x8E);
|
||||
set_idt_descriptor(7, s_isr7, 0x8E);
|
||||
set_idt_descriptor(8, s_isr8, 0x8E);
|
||||
set_idt_descriptor(9, s_isr9, 0x8E);
|
||||
set_idt_descriptor(10, s_isr10, 0x8E);
|
||||
set_idt_descriptor(11, s_isr11, 0x8E);
|
||||
set_idt_descriptor(12, s_isr12, 0x8E);
|
||||
set_idt_descriptor(13, s_isr13, 0x8E);
|
||||
set_idt_descriptor(14, s_isr14, 0x8E);
|
||||
set_idt_descriptor(15, s_isr15, 0x8E);
|
||||
set_idt_descriptor(16, s_isr16, 0x8E);
|
||||
set_idt_descriptor(17, s_isr17, 0x8E);
|
||||
set_idt_descriptor(18, s_isr18, 0x8E);
|
||||
set_idt_descriptor(19, s_isr19, 0x8E);
|
||||
set_idt_descriptor(20, s_isr20, 0x8E);
|
||||
set_idt_descriptor(21, s_isr21, 0x8E);
|
||||
set_idt_descriptor(22, s_isr22, 0x8E);
|
||||
set_idt_descriptor(23, s_isr23, 0x8E);
|
||||
set_idt_descriptor(24, s_isr24, 0x8E);
|
||||
set_idt_descriptor(25, s_isr25, 0x8E);
|
||||
set_idt_descriptor(26, s_isr26, 0x8E);
|
||||
set_idt_descriptor(27, s_isr27, 0x8E);
|
||||
set_idt_descriptor(28, s_isr28, 0x8E);
|
||||
set_idt_descriptor(29, s_isr29, 0x8E);
|
||||
set_idt_descriptor(30, s_isr30, 0x8E);
|
||||
set_idt_descriptor(31, s_isr31, 0x8E);
|
||||
|
||||
set_idt_descriptor(44, 0, 0x8E);
|
||||
set_idt_descriptor(69, s_isr69, 0x8E);
|
||||
set_idt_descriptor(70, s_isr70, 0x8E);
|
||||
set_idt_descriptor(255, s_isr255, 0x8E);
|
||||
|
||||
s_load_idt();
|
||||
}
|
||||
|
||||
char *exception_messages[] =
|
||||
{
|
||||
"Division Error",
|
||||
"Debug",
|
||||
"Non Maskable Interrupt",
|
||||
"Breakpoint",
|
||||
"Into Detected Overflow",
|
||||
"Out of Bounds",
|
||||
"Invalid Opcode",
|
||||
"Device not available",
|
||||
|
||||
"Double Fault",
|
||||
"Coprocessor Segment Overrun",
|
||||
"Invalid TSS",
|
||||
"Segment Not Present",
|
||||
"Stack Fault",
|
||||
"General Protection Fault",
|
||||
"Page Fault",
|
||||
"x87 FPU Floating-point error",
|
||||
|
||||
"Alignment Check",
|
||||
"Machine Check",
|
||||
"SIMD Floating-point exception",
|
||||
"Virtualization exception",
|
||||
"Control Protection",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved"
|
||||
};
|
||||
|
||||
void interrupt_handler(interrupt_frame *r){
|
||||
|
||||
if(r->int_no < 32){
|
||||
kprintf("\nOh no! Received interrupt {d}, '{s}'. Below is the provided stack frame{n}{n}", r->int_no, exception_messages[r->int_no]);
|
||||
kprintf("error code 0x{xn}", r->err);
|
||||
kprintf("rax 0x{x} | rbx 0x{x} | rcx 0x{x} | rdx 0x{xn}", r->rax, r->rbx, r->rcx, r->rdx);
|
||||
kprintf("rdi 0x{x} | rsi 0x{x} | rbp 0x{xn}", r->rdi, r->rsi, r->rbp);
|
||||
kprintf("r8 0x{x} | r9 0x{x} | r10 0x{x} | r11 0x{x} | r12 0x{x} | r13 0x{x} | r14 0x{x} | r15 0x{xn}", r->r8, r->r9, r->r10, r->r11, r->r12, r->r13, r->r14, r->r15);
|
||||
kprintf("rip 0x{x} | cs 0x{x} | ss 0x{x} | rsp 0x{x} | rflags 0x{xn}", r->rip, r->cs, r->ss, r->rsp, r->rflags);
|
||||
kkill();
|
||||
for(;;);
|
||||
}
|
||||
|
||||
if(r->int_no == 255){
|
||||
kprintf("hey");
|
||||
}
|
||||
|
||||
if(r->int_no == 69){
|
||||
apic_timer_handler();
|
||||
}
|
||||
if(r->int_no == 70){
|
||||
for(;;){
|
||||
asm("cli;hlt");
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
37
src/hal/idt.h
Normal file
37
src/hal/idt.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#include "error.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct idt_descriptor {
|
||||
uint16_t offset_low;
|
||||
uint16_t segment_sel;
|
||||
uint8_t ist;
|
||||
uint8_t attributes;
|
||||
uint16_t offset_high;
|
||||
uint32_t offset_higher;
|
||||
uint32_t reserved;
|
||||
} __attribute((packed))idt_descriptor;
|
||||
|
||||
typedef struct idt_register {
|
||||
uint16_t limit;
|
||||
uint64_t base_address;
|
||||
} __attribute((packed)) idt_register;
|
||||
|
||||
typedef struct interrupt_frame {
|
||||
uint64_t r15, r14, r13, r12, r11, r10, r9, r8, rdi, rsi, rbp, rdx, rcx, rbx, rax;
|
||||
uint64_t int_no, err;
|
||||
uint64_t rip, cs, rflags, rsp, ss;
|
||||
} __attribute((packed)) interrupt_frame;
|
||||
|
||||
typedef struct irq_t {
|
||||
void *base;
|
||||
bool in_use;
|
||||
}irq_t;
|
||||
|
||||
void set_idt_descriptor(uint8_t vector, void *base, uint8_t flags);
|
||||
|
||||
kstatus register_irq_vector(uint8_t vector, void *base, uint8_t flags);
|
||||
|
||||
int register_irq(void *base, uint8_t flags);
|
||||
|
||||
void set_idt(void);
|
||||
62
src/hal/ioapic.c
Normal file
62
src/hal/ioapic.c
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <SFB25.h>
|
||||
#include "../sys/acpi.h"
|
||||
#include "error.h"
|
||||
|
||||
#define IOREGSEL 0x0
|
||||
#define IOWIN 0x10
|
||||
|
||||
#define IOAPICID 0x0
|
||||
#define IOAPICVER 0x1
|
||||
#define IOAPICARB 0x2
|
||||
#define IOREDTBL(x) (0x10 + (x * 2)) // 0-23 registers
|
||||
|
||||
extern uint64_t hhdmoffset;
|
||||
|
||||
extern madt_t *madt;
|
||||
|
||||
uint64_t ioapic_address;
|
||||
|
||||
void ioapic_write_reg(uint8_t reg, uint32_t data){
|
||||
/* First we load IOREGSEL with the register we want to access */
|
||||
*(uint32_t*)(ioapic_address + IOREGSEL) = (uint8_t) reg;
|
||||
|
||||
/* Then we write the data to the IOWIN register */
|
||||
*(uint32_t*)(ioapic_address + IOWIN) = (uint32_t) data;
|
||||
}
|
||||
|
||||
uint32_t ioapic_read_reg(uint8_t reg){
|
||||
*(uint32_t*)(ioapic_address + IOREGSEL) = reg;
|
||||
|
||||
return *(uint32_t*)(ioapic_address + IOWIN);
|
||||
}
|
||||
|
||||
void write_redir_entry(uint8_t reg, uint64_t data){
|
||||
/* First write lower 32-bits of the data to the specified IOREDTBL register */
|
||||
ioapic_write_reg(IOREDTBL(reg), (uint32_t)(data & 0xFFFFFFFF));
|
||||
|
||||
/* Then write the upper 32-bits */
|
||||
ioapic_write_reg(IOREDTBL(reg)+1, (uint32_t)(data >> 32));
|
||||
}
|
||||
|
||||
kstatus set_redir_entry(uint8_t pin, uint8_t vector, uint8_t delivery, uint8_t trigger, uint8_t destination_field, uint8_t destination_mode){
|
||||
uint64_t data = ((uint64_t)destination_field << 56) | (uint64_t)trigger << 15 | (uint64_t)destination_mode << 11 | (uint64_t)delivery << 8 | vector;
|
||||
write_redir_entry(pin, data);
|
||||
return KERNEL_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void ioapic_init(void){
|
||||
|
||||
ioapic_t *ioapic = (ioapic_t*) find_ics(0x1);
|
||||
|
||||
if(!ioapic){
|
||||
klog(LOG_ERROR, __func__, "IOAPIC ICS not found\n");
|
||||
kkill();
|
||||
}
|
||||
|
||||
ioapic_address = ioapic->ioapic_address + hhdmoffset;
|
||||
|
||||
}
|
||||
13
src/hal/ioapic.h
Normal file
13
src/hal/ioapic.h
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#include "error.h"
|
||||
#include <stdint.h>
|
||||
void ioapic_init(void);
|
||||
void write_redir_entry(uint8_t reg, uint64_t data);
|
||||
kstatus set_redir_entry(uint8_t pin, uint8_t vector, uint8_t delivery, uint8_t trigger, uint8_t destination_field, uint8_t destination_mode);
|
||||
|
||||
#define IOREGSEL 0x0
|
||||
#define IOWIN 0x10
|
||||
|
||||
#define IOAPICID 0x0
|
||||
#define IOAPICVER 0x1
|
||||
#define IOAPICARB 0x2
|
||||
#define IOREDTBL(x) (0x10 + (x * 2)) // 0-23 registers
|
||||
112
src/hal/smp.c
Normal file
112
src/hal/smp.c
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
#include <limine.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <SFB25.h>
|
||||
#include "gdt.h"
|
||||
#include "smp.h"
|
||||
#include "apic.h"
|
||||
#include "idt.h"
|
||||
#include "../mm/vmm.h"
|
||||
#include <lock.h>
|
||||
#include <io.h>
|
||||
#include <string.h>
|
||||
|
||||
static volatile struct limine_smp_request smp_request = {
|
||||
.id = LIMINE_SMP_REQUEST,
|
||||
.revision = 0,
|
||||
};
|
||||
|
||||
extern void s_load_idt();
|
||||
extern void s_load_gdt();
|
||||
extern uint64_t hhdmoffset;
|
||||
|
||||
/* Returns the CPU structure for this particular CPU */
|
||||
cpu_state *get_cpu_struct(){
|
||||
return (cpu_state*)rdmsr(GSBASE);
|
||||
}
|
||||
|
||||
uint64_t get_cpu_count(){
|
||||
return smp_request.response->cpu_count;
|
||||
}
|
||||
|
||||
bool get_cpu_struct_initialized(){
|
||||
if(rdmsr(GSBASE) < hhdmoffset){
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
atomic_flag ap_init_lock = ATOMIC_FLAG_INIT;
|
||||
|
||||
void ap_init(struct limine_smp_info *smp_info){
|
||||
|
||||
acquire_lock(&ap_init_lock);
|
||||
|
||||
/* Load the GDT */
|
||||
s_load_gdt();
|
||||
|
||||
/* Load the IDT */
|
||||
s_load_idt();
|
||||
|
||||
/* Set the CR3 context */
|
||||
extern uint64_t *kernel_page_map;
|
||||
|
||||
vmm_set_ctx(kernel_page_map);
|
||||
|
||||
asm volatile(
|
||||
"movq %%cr3, %%rax\n\
|
||||
movq %%rax, %%cr3\n"
|
||||
: : : "rax"
|
||||
);
|
||||
|
||||
cpu_state *cpu_struct = (cpu_state*)kmalloc(sizeof(cpu_state));
|
||||
memset(cpu_struct, 0, sizeof(cpu_state));
|
||||
cpu_struct->lapic_id = smp_info->lapic_id;
|
||||
|
||||
wrmsr(KERNELGSBASE, (uint64_t)cpu_struct);
|
||||
wrmsr(GSBASE, (uint64_t)cpu_struct);
|
||||
|
||||
/* Initialize APIC & APIC timer */
|
||||
ap_apic_init();
|
||||
|
||||
free_lock(&ap_init_lock);
|
||||
|
||||
for(;;);
|
||||
|
||||
scheduler_init();
|
||||
}
|
||||
|
||||
void smp_init(){
|
||||
|
||||
if(!smp_request.response){
|
||||
klog(LOG_ERROR, __func__, "Failed to get SMP request");
|
||||
kkill();
|
||||
}
|
||||
|
||||
struct limine_smp_response *smp_response = smp_request.response;
|
||||
|
||||
kprintf("smp: {d} CPUs\n", smp_response->cpu_count);
|
||||
|
||||
for(uint64_t i = 0; i < smp_response->cpu_count; i++){
|
||||
/* Pointer to smp_info is passed in RDI by Limine, so no need to pass any arguments here */
|
||||
smp_response->cpus[i]->goto_address = &ap_init;
|
||||
}
|
||||
|
||||
/* -- Setup CPU structure for BSP -- */
|
||||
|
||||
/* Allocate CPU structure */
|
||||
cpu_state *cpu_struct = (cpu_state*)kmalloc(sizeof(cpu_state));
|
||||
cpu_struct->lapic_id = smp_response->cpus[0]->lapic_id;
|
||||
|
||||
wrmsr(KERNELGSBASE, (uint64_t)cpu_struct);
|
||||
wrmsr(GSBASE, (uint64_t)cpu_struct);
|
||||
|
||||
/* If one of the APs has halted, then halt the BSP */
|
||||
extern bool kernel_killed;
|
||||
if(kernel_killed == true){
|
||||
kkill();
|
||||
}
|
||||
|
||||
}
|
||||
23
src/hal/smp.h
Normal file
23
src/hal/smp.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "../scheduler/sched.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
#define GSBASE 0xC0000101
|
||||
#define KERNELGSBASE 0xC0000102
|
||||
|
||||
typedef struct cpu_state {
|
||||
uint32_t lapic_id;
|
||||
uint64_t lapic_timer_ticks;
|
||||
proc process_list[PROC_MAX];
|
||||
proc *current_process;
|
||||
uint16_t process_count;
|
||||
context scheduler_context;
|
||||
}__attribute((packed))cpu_state;
|
||||
|
||||
void smp_init();
|
||||
cpu_state *get_cpu_struct();
|
||||
uint64_t get_cpu_count();
|
||||
bool get_cpu_struct_initialized();
|
||||
|
||||
24
src/hal/timer.c
Normal file
24
src/hal/timer.c
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#include "../sys/acpi.h"
|
||||
#include "../hal/ioapic.h"
|
||||
#include "../hal/apic.h"
|
||||
#include "../drivers/pmt.h"
|
||||
#include "timer.h"
|
||||
#include <stdio.h>
|
||||
#include <SFB25.h>
|
||||
|
||||
/* Determines which timer will be used for calibration */
|
||||
int calibration_timer = -1;
|
||||
|
||||
void timer_init(void){
|
||||
if(pmt_init() == -1){
|
||||
klog(LOG_INFO, __func__, "PMT Timer not found, falling back");
|
||||
/* Fall back to PIT */
|
||||
}else{
|
||||
calibration_timer = PMT;
|
||||
}
|
||||
}
|
||||
|
||||
void sleep(int ms){
|
||||
/* Eventually fix this */
|
||||
apic_sleep(ms);
|
||||
}
|
||||
11
src/hal/timer.h
Normal file
11
src/hal/timer.h
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#include <stdint.h>
|
||||
|
||||
enum USABLE_TIMERS {
|
||||
HPET = 0,
|
||||
PMT,
|
||||
PIT,
|
||||
};
|
||||
|
||||
void timer_init(void);
|
||||
void apic_timer_handler(void);
|
||||
void sleep(int ms);
|
||||
77
src/hal/tsc.c
Normal file
77
src/hal/tsc.c
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#include <cpuid.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include "error.h"
|
||||
#include "../drivers/pmt.h"
|
||||
|
||||
uint32_t core_crystal_clock = 0;
|
||||
|
||||
void enable_tsc(){
|
||||
asm(".intel_syntax noprefix\n\
|
||||
mov rax, cr4\n\
|
||||
or rax, 0b10\n\
|
||||
mov cr4, rax\n\
|
||||
.att_syntax prefix");
|
||||
}
|
||||
|
||||
void disable_tsc(){
|
||||
asm(".intel_syntax noprefix\n\
|
||||
mov rax, cr4\n\
|
||||
and rax, 0xFFFFFFFFFFFFFFFD\n\
|
||||
mov cr4, rax\n\
|
||||
.att_syntax prefix");
|
||||
}
|
||||
|
||||
uint64_t read_tsc(){
|
||||
uint32_t eax, edx;
|
||||
asm("rdtsc" :"=a"(eax),"=d"(edx));
|
||||
return ((uint64_t)edx << 32 | eax);
|
||||
}
|
||||
|
||||
kstatus tsc_init(){
|
||||
|
||||
uint32_t edx, unused;
|
||||
|
||||
/* Check if there is an invariant TSC */
|
||||
__get_cpuid(0x80000007, &unused, &unused, &unused, &edx);
|
||||
|
||||
if((edx & (1 << 8)) == 0){
|
||||
return KERNEL_STATUS_ERROR;
|
||||
}
|
||||
|
||||
kprintf("tsc: Invariant TSC found\n");
|
||||
|
||||
/* Get the core crystal clock so we can determine TSC speed */
|
||||
__get_cpuid(0x15, &unused, &unused, &core_crystal_clock, &unused);
|
||||
|
||||
if(core_crystal_clock != 0){
|
||||
kprintf("cpuid 15h supported!\n");
|
||||
|
||||
/* Make it so that it ticks every millisecond */
|
||||
core_crystal_clock *= 1000;
|
||||
|
||||
}else{
|
||||
/* Calibrate using the PMT */
|
||||
enable_tsc();
|
||||
uint32_t read1 = read_tsc();
|
||||
pmt_delay(1000);
|
||||
uint32_t read2 = read_tsc();
|
||||
disable_tsc();
|
||||
core_crystal_clock = read2 - read1;
|
||||
}
|
||||
|
||||
kprintf("Core crystal clock: {d}\n", core_crystal_clock);
|
||||
|
||||
enable_tsc();
|
||||
|
||||
return KERNEL_STATUS_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
uint64_t tsc_get_timestamp(){
|
||||
if(core_crystal_clock == 0){
|
||||
return 0;
|
||||
}
|
||||
uint64_t read = read_tsc();
|
||||
return read / core_crystal_clock;
|
||||
}
|
||||
6
src/hal/tsc.h
Normal file
6
src/hal/tsc.h
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#include "error.h"
|
||||
#include <stdint.h>
|
||||
|
||||
kstatus tsc_init();
|
||||
|
||||
uint64_t tsc_get_timestamp();
|
||||
Loading…
Add table
Add a link
Reference in a new issue