Init IOAPIC nad LAPICs

This commit is contained in:
2025-08-21 00:47:58 +02:00
parent 3f6df79885
commit 9d8849a425
25 changed files with 801 additions and 306 deletions

View File

@ -1,24 +1,59 @@
#include <stddef.h>
#include <stdint.h>
#include "uacpi/uacpi.h"
#include "uacpi/utilities.h"
#include "hal/hal.h"
#include "kprintf.h"
#include "dlmalloc/malloc.h"
#include "compiler/attr.h"
#include "acpi.h"
#include "assert.h"
#include "util/util.h"
#include "bootinfo/bootinfo.h"
#include "uacpi/uacpi.h"
#define PREINIT_BUFFER_SIZE 0x1000
// uACPI
struct acpi_madt *MADT;
void uacpi_kernel_log(uacpi_log_level lvl, const uacpi_char *s) {
char *t = NULL;
switch (lvl) {
case UACPI_LOG_INFO: t = "Info"; break;
case UACPI_LOG_WARN: t = "Warn"; break;
case UACPI_LOG_DEBUG: t = "Dbg"; break;
case UACPI_LOG_ERROR: t = "Err"; break;
case UACPI_LOG_TRACE: t = "Trc"; break;
}
LOG("uACPI", "%s %s", t, s);
}
void uacpi_kernel_unmap(void *addr, uacpi_size len) {
// .
}
void *uacpi_kernel_map(uacpi_phys_addr addr, uacpi_size len) {
return (void *)(BOOT_INFO.hhdm_off + addr);
}
uacpi_status uacpi_kernel_get_rsdp(uacpi_phys_addr *out) {
*out = BOOT_INFO.rsdp;
return UACPI_STATUS_OK;
}
void acpi_init(void) {
uacpi_status ret;
uacpi_status r;
void *preinit_buffer = dlmalloc(PREINIT_BUFFER_SIZE);
ret = uacpi_setup_early_table_access(preinit_buffer, PREINIT_BUFFER_SIZE);
if (uacpi_unlikely_error(ret)) {
ERR("acpi", "init err %s\n", uacpi_status_to_string(ret));
size_t tmpbufsize = 0x1000;
void *tmpbuf = dlmalloc(tmpbufsize);
if (tmpbuf == NULL) {
ERR("hal", "could not allocate uACPI tmp buf\n");
hal_hang();
}
r = uacpi_setup_early_table_access(tmpbuf, tmpbufsize);
if (uacpi_unlikely_error(r)) {
ERR("hal", "uACPI init early table failed\n");
hal_hang();
}
LOG("hal", "acpi init\n");
}
/* uint32_t acpi_remapirq(uint32_t irq) { */
/* } */

View File

@ -1,10 +1,9 @@
#ifndef HAL_ACPI_H_
#define HAL_ACPI_H_
#include "uacpi/uacpi.h"
extern struct acpi_madt *MADT;
#include <stdint.h>
void acpi_init(void);
uint32_t acpi_remapirq(uint32_t irq);
#endif // HAL_ACPI_H_

179
kernel/hal/x86_64/apic.c Normal file
View File

@ -0,0 +1,179 @@
#include <stdint.h>
#include <stddef.h>
#include "apic.h"
#include "uacpi/tables.h"
#include "uacpi/acpi.h"
#include "kprintf.h"
#include "hal/hal.h"
#include "dlmalloc/malloc.h"
#include "bootinfo/bootinfo.h"
#include "assert.h"
#include "util/util.h"
#include "cpu.h"
#include "util/mmio.h"
#define IOAPIC_IOREGSEL 0x00
#define IOAPIC_IOWIN 0x10
#define IOAPIC_IOAPICID 0x00
#define IOAPIC_IOAPICVER 0x01
#define IOAPIC_IOAPICARB 0x02
#define IOAPIC_IOREDTBL 0x10
#define LAPIC_ID 0x0020
#define LAPIC_VER 0x0030
#define LAPIC_TPR 0x0080
#define LAPIC_APR 0x0090
#define LAPIC_PPR 0x00A0
#define LAPIC_EOI 0x00B0
#define LAPIC_RRD 0x00C0
#define LAPIC_LDR 0x00D0
#define LAPIC_DFR 0x00E0
#define LAPIC_SVR 0x00F0
#define LAPIC_ISR 0x0100
#define LAPIC_TMR 0x0180
#define LAPIC_IRR 0x0200
#define LAPIC_ESR 0x0280
#define LAPIC_ICRLO 0x0300
#define LAPIC_ICRHI 0x0310
#define LAPIC_TIMER 0x0320
#define LAPIC_THERMAL 0x0330
#define LAPIC_PERF 0x0340
#define LAPIC_LINT0 0x0350
#define LAPIC_LINT1 0x0360
#define LAPIC_ERROR 0x0370
#define LAPIC_TICR 0x0380
#define LAPIC_TCCR 0x0390
#define LAPIC_TDCR 0x03E0
#define ICR_FIXED 0x00000000
#define ICR_LOWEST 0x00000100
#define ICR_SMI 0x00000200
#define ICR_NMI 0x00000400
#define ICR_INIT 0x00000500
#define ICR_STARTUP 0x00000600
#define ICR_PHYS 0x00000000
#define ICR_LOGC 0x00000800
#define ICR_IDLE 0x00000000
#define ICR_SEND_PENDING 0x00001000
#define ICR_DEASSERT 0x00000000
#define ICR_ASSERT 0x00004000
#define ICR_EDGE 0x00000000
#define ICR_LEVEL 0x00008000
#define ICR_NO_SHORTHAND 0x00000000
#define ICR_SELF 0x00040000
#define ICR_ALL_INC_SELF 0x00080000
#define ICR_ALL_EXCL_SELF 0x000C0000
#define ICR_DEST_SHIFT 24
typedef struct LApic {
struct LApic *next;
uint8_t id;
} LApic;
struct acpi_madt *MADT = NULL;
uint8_t *IOAPIC;
uint8_t *LAPIC;
LApic *LAPICS = NULL;
void ioapic_write(uint8_t *base, uint8_t reg, uint32_t data) {
mmiowrite32(base + IOAPIC_IOREGSEL, reg);
mmiowrite32(base + IOAPIC_IOWIN, data);
}
uint32_t ioapic_read(uint8_t *base, uint8_t reg) {
mmiowrite32(base + IOAPIC_IOREGSEL, reg);
return mmioread32(base + IOAPIC_IOWIN);
}
void ioapic_setentry(uint8_t *base, uint8_t idx, uint64_t data) {
ioapic_write(base, IOAPIC_IOREDTBL + idx * 2, (uint32_t) data);
ioapic_write(base, IOAPIC_IOREDTBL + idx * 2 + 1, (uint32_t) (data >> 32));
}
void ioapic_init(void) {
uint32_t x = ioapic_read(IOAPIC, IOAPIC_IOAPICVER);
uint32_t count = ((x >> 16) & 0xff) + 1;
LOG("hal", "IOAPIC pins = %d\n", count);
for (uint32_t i = 0; i < count; i++) {
ioapic_setentry(IOAPIC, i, 1 << 16);
}
}
uint32_t lapic_read(uint32_t reg) {
return mmioread32(LAPIC + reg);
}
void lapic_write(uint32_t reg, uint32_t data) {
mmiowrite32(LAPIC + reg, data);
}
void lapic_init(void) {
lapic_write(LAPIC_TPR, 0);
lapic_write(LAPIC_DFR, 0xffffffff);
lapic_write(LAPIC_LDR, 0x01000000);
lapic_write(LAPIC_SVR, 0x100 | 0xff);
}
uint32_t lapic_getid(void) {
return lapic_read(LAPIC_ID) >> 24;
}
void lapic_sendinit(uint32_t id) {
lapic_write(LAPIC_ICRHI, id << ICR_DEST_SHIFT);
lapic_write(LAPIC_ICRLO, ICR_INIT | ICR_PHYS | ICR_ASSERT | ICR_EDGE | ICR_NO_SHORTHAND);
while (lapic_read(LAPIC_ICRLO) & ICR_SEND_PENDING);
}
void lapic_sendstartup(uint32_t id, uint32_t vec) {
lapic_write(LAPIC_ICRHI, id << ICR_DEST_SHIFT);
lapic_write(LAPIC_ICRLO, vec | ICR_STARTUP | ICR_PHYS | ICR_ASSERT | ICR_EDGE | ICR_NO_SHORTHAND);
while (lapic_read(LAPIC_ICRLO) & ICR_SEND_PENDING);
}
void apic_init(void) {
uacpi_status r;
uacpi_table madt;
r = uacpi_table_find_by_signature("APIC", &madt);
if (r != UACPI_STATUS_OK) {
ERR("hal", "could not find MADT\n");
hal_hang();
}
MADT = madt.ptr;
LAPIC = (uint8_t *)(MADT->local_interrupt_controller_address + BOOT_INFO.hhdm_off);
uint64_t cur = (uint64_t)&MADT->entries;
uint64_t end = cur + MADT->hdr.length;
while (cur < end) {
struct acpi_entry_hdr *ent = (struct acpi_entry_hdr *)cur;
if (ent->type == ACPI_MADT_ENTRY_TYPE_IOAPIC) {
struct acpi_madt_ioapic *ioapic = (struct acpi_madt_ioapic *)ent;
IOAPIC = (uint8_t *)(ioapic->address + BOOT_INFO.hhdm_off);
LOG("hal", "IOAPIC p=%p v=%p id=%d gsi=%d\n", ioapic->address, IOAPIC, ioapic->id, ioapic->gsi_base);
} else if (ent->type == ACPI_MADT_ENTRY_TYPE_LAPIC) {
struct acpi_madt_lapic *lapic = (struct acpi_madt_lapic *)ent;
LApic *new = dlmalloc(sizeof(*new));
ASSERT("hal", new != NULL, "out of memory\n");
new->id = lapic->id;
LL_APPEND(LAPICS, new);
LOG("hal", "LAPIC id=%d\n", lapic->id);
} else if (ent->type == ACPI_MADT_ENTRY_TYPE_LAPIC_ADDRESS_OVERRIDE) {
struct acpi_madt_lapic_address_override *override= (struct acpi_madt_lapic_address_override *)ent;
uint8_t *prev = LAPIC;
LAPIC = (uint8_t *)(override->address + BOOT_INFO.hhdm_off);
LOG("hal", "LAPIC override %p -> %p (v)\n", prev, LAPIC);
}
cur += ent->length;
}
lapic_init();
ioapic_init();
}

6
kernel/hal/x86_64/apic.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef HAL_APIC_H_
#define HAL_APIC_H_
void apic_init(void);
#endif // HAL_APIC_H_

View File

@ -5,7 +5,9 @@
#include "serial.h"
#include "gdt.h"
#include "acpi.h"
#include "isr.h"
#include "intr.h"
#include "pic.h"
#include "apic.h"
void hal_init(void) {
if (!serial_init()) {
@ -22,7 +24,9 @@ __attribute__((noreturn)) void hal_hang(void) {
}
void hal_init_withmalloc(void) {
/* acpi_init(); */
isr_init();
acpi_init();
pic_init();
apic_init();
intr_init();
}

View File

@ -1,9 +0,0 @@
.global hal_intr_enable
hal_intr_enable:
sti
ret
.global hal_intr_disable
hal_intr_disable:
cli
ret

183
kernel/hal/x86_64/intr.c Normal file
View File

@ -0,0 +1,183 @@
#include <stddef.h>
#include <stdint.h>
#include "intr.h"
#include "io.h"
#include "gdt.h"
#include "hal/hal.h"
#include "kprintf.h"
#include "compiler/attr.h"
void hal_intr_disable(void) {
asm volatile("cli");
}
void hal_intr_enable(void) {
asm volatile("sti");
}
typedef struct {
uint16_t intrlow;
uint16_t kernelcs;
uint8_t ist;
uint8_t attrs;
uint16_t intrmid;
uint32_t intrhigh;
uint32_t resv;
} PACKED IdtGate;
typedef struct {
uint16_t limit;
uint64_t base;
} PACKED Idt;
#define ENTRIES 256
ALIGNED(0x10) static IdtGate idtgates[ENTRIES] = {0};
static Idt idt = {0};
void idt_setentry(int i, uint64_t handler, uint8_t ist, uint8_t flags) {
idtgates[i].intrlow = handler & 0xffff;
idtgates[i].kernelcs = KCODE;
idtgates[i].ist = ist;
idtgates[i].attrs = flags;
idtgates[i].intrmid = (handler >> 16) & 0xFFFF;
idtgates[i].intrhigh = (handler >> 32) & 0xFFFFFFFF;
idtgates[i].resv = 0;
}
void idt_init(void) {
idt.base = (uint64_t)&idtgates;
idt.limit = ENTRIES * sizeof(IdtGate) - 1;
asm volatile("lidt %0" :: "m"(idt) : "memory");
LOG("hal", "idt init\n");
}
typedef struct {
uint64_t r15;
uint64_t r14;
uint64_t r13;
uint64_t r12;
uint64_t r11;
uint64_t r10;
uint64_t r9;
uint64_t r8;
uint64_t rsi;
uint64_t rdi;
uint64_t rbp;
uint64_t rdx;
uint64_t rcx;
uint64_t rbx;
uint64_t rax;
} PACKED CpuRegs;
typedef struct {
uint64_t cr8;
uint64_t cr4;
uint64_t cr3;
uint64_t cr2;
uint64_t cr0;
} PACKED CpuCtrlRegs;
typedef struct {
CpuCtrlRegs ctrl;
CpuRegs regs;
uint64_t trapnum;
uint64_t errnum;
uint64_t rip;
uint64_t cs;
uint64_t rflags;
uint64_t rsp;
uint64_t ss;
} PACKED IntrStackFrame;
extern void *ISR_REDIRTABLE[];
static const char *exceptions[] = {
"#DE", "#DB", "NMI",
"#BP", "#OF", "#BR",
"#UD", "#NM", "#DF",
"CSO", "#TS", "#NP",
"#SS", "#GP", "#PF",
"RES", "#MF", "#AC",
"#MC", "#XM", "#VE",
"#CP",
};
extern void intr_vec0(void);
extern void intr_vec1(void);
extern void intr_vec2(void);
extern void intr_vec3(void);
extern void intr_vec4(void);
extern void intr_vec5(void);
extern void intr_vec6(void);
extern void intr_vec7(void);
extern void intr_vec8(void);
extern void intr_vec10(void);
extern void intr_vec11(void);
extern void intr_vec12(void);
extern void intr_vec13(void);
extern void intr_vec14(void);
extern void intr_vec16(void);
extern void intr_vec17(void);
extern void intr_vec18(void);
extern void intr_vec19(void);
extern void intr_vec20(void);
extern void intr_vec21(void);
extern void intr_vec32(void);
extern void intr_vec33(void);
extern void intr_vec39(void);
void intr_init(void) {
idt_setentry(0, (uint64_t)&intr_vec0, 0, 0x8E);
idt_setentry(1, (uint64_t)&intr_vec1, 0, 0x8E);
idt_setentry(2, (uint64_t)&intr_vec2, 2, 0x8E);
idt_setentry(3, (uint64_t)&intr_vec3, 0, 0x8E);
idt_setentry(4, (uint64_t)&intr_vec4, 0, 0x8E);
idt_setentry(5, (uint64_t)&intr_vec5, 0, 0x8E);
idt_setentry(6, (uint64_t)&intr_vec6, 0, 0x8E);
idt_setentry(7, (uint64_t)&intr_vec7, 0, 0x8E);
idt_setentry(8, (uint64_t)&intr_vec8, 1, 0x8E);
idt_setentry(10, (uint64_t)&intr_vec10, 0, 0x8E);
idt_setentry(11, (uint64_t)&intr_vec11, 0, 0x8E);
idt_setentry(12, (uint64_t)&intr_vec12, 0, 0x8E);
idt_setentry(13, (uint64_t)&intr_vec13, 0, 0x8E);
idt_setentry(14, (uint64_t)&intr_vec14, 0, 0x8E);
idt_setentry(16, (uint64_t)&intr_vec16, 0, 0x8E);
idt_setentry(17, (uint64_t)&intr_vec17, 0, 0x8E);
idt_setentry(18, (uint64_t)&intr_vec18, 0, 0x8E);
idt_setentry(19, (uint64_t)&intr_vec19, 0, 0x8E);
idt_setentry(20, (uint64_t)&intr_vec20, 0, 0x8E);
idt_setentry(21, (uint64_t)&intr_vec21, 0, 0x8E);
idt_setentry(32, (uint64_t)&intr_vec32, 0, 0x8E);
idt_setentry(33, (uint64_t)&intr_vec33, 0, 0x8E);
idt_setentry(39, (uint64_t)&intr_vec39, 0, 0x8E);
idt_init();
}
void intr_dumpframe(IntrStackFrame *frame) {
kprintf("r15=%016lx r14=%016lx r13=%016lx r12=%016lx\n"
"r11=%016lx r10=%016lx r9 =%016lx r8 =%016lx\n"
"rsi=%016lx rdi=%016lx rbp=%016lx rdx=%016lx\n"
"rcx=%016lx rbx=%016lx rax=%016lx\n"
"cr8=%016lx cr4=%016lx cr3=%016lx cr2=%016lx\n"
"cr0=%016lx rip=%016lx cs =%016lx rfl=%016lx\n"
"rsp=%016lx ss =%016lx trp=%016lx err=%016lx\n",
frame->regs.r15, frame->regs.r14, frame->regs.r13, frame->regs.r12,
frame->regs.r11, frame->regs.r10, frame->regs.r9, frame->regs.r8,
frame->regs.rsi, frame->regs.rdi, frame->regs.rbp, frame->regs.rdx,
frame->regs.rcx, frame->regs.rbx, frame->regs.rax,
frame->ctrl.cr8, frame->ctrl.cr4, frame->ctrl.cr3,
frame->ctrl.cr2, frame->ctrl.cr0, frame->rip, frame->cs, frame->rflags,
frame->rsp, frame->ss, frame->trapnum, frame->errnum
);
}
void intr_handleintr(IntrStackFrame *frame) {
hal_intr_disable();
ERR("ERROR", "%s, 0x%lX\n", exceptions[frame->trapnum], frame->errnum);
intr_dumpframe(frame);
hal_hang();
}

8
kernel/hal/x86_64/intr.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef HAL_INTR_H_
#define HAL_INTR_H_
#define INTR_IRQBASE 0x20
void intr_init(void);
#endif // HAL_INTR_H_

View File

@ -1,28 +1,28 @@
.extern isr_handleintr
.extern intr_handleintr
.global isr_vec0
.global isr_vec1
.global isr_vec2
.global isr_vec3
.global isr_vec4
.global isr_vec5
.global isr_vec6
.global isr_vec7
.global isr_vec8
.global isr_vec10
.global isr_vec11
.global isr_vec12
.global isr_vec13
.global isr_vec14
.global isr_vec16
.global isr_vec17
.global isr_vec18
.global isr_vec19
.global isr_vec20
.global isr_vec21
.global isr_vec32
.global isr_vec33
.global isr_vec39
.global intr_vec0
.global intr_vec1
.global intr_vec2
.global intr_vec3
.global intr_vec4
.global intr_vec5
.global intr_vec6
.global intr_vec7
.global intr_vec8
.global intr_vec10
.global intr_vec11
.global intr_vec12
.global intr_vec13
.global intr_vec14
.global intr_vec16
.global intr_vec17
.global intr_vec18
.global intr_vec19
.global intr_vec20
.global intr_vec21
.global intr_vec32
.global intr_vec33
.global intr_vec39
.macro _PUSHAQ
push %rax
@ -99,77 +99,77 @@
.macro _vecintr_bodygen
cld
mov %rsp, %rdi
call isr_handleintr
call intr_handleintr
_vecintr_restore
iretq
.endm
isr_vec0:
intr_vec0:
_vecintr_plain_save 0, 0
_vecintr_bodygen
isr_vec1:
intr_vec1:
_vecintr_plain_save 1, 0
_vecintr_bodygen
isr_vec2:
intr_vec2:
_vecintr_plain_save 2, 0
_vecintr_bodygen
isr_vec3:
intr_vec3:
_vecintr_plain_save 3, 0
_vecintr_bodygen
isr_vec4:
intr_vec4:
_vecintr_plain_save 4, 0
_vecintr_bodygen
isr_vec5:
intr_vec5:
_vecintr_plain_save 5, 0
_vecintr_bodygen
isr_vec6:
intr_vec6:
_vecintr_plain_save 6, 0
_vecintr_bodygen
isr_vec7:
intr_vec7:
_vecintr_plain_save 7, 0
_vecintr_bodygen
isr_vec8:
intr_vec8:
_vecintr_errorcode_present_save 8
_vecintr_bodygen
isr_vec10:
intr_vec10:
_vecintr_errorcode_present_save 10
_vecintr_bodygen
isr_vec11:
intr_vec11:
_vecintr_errorcode_present_save 11
_vecintr_bodygen
isr_vec12:
intr_vec12:
_vecintr_errorcode_present_save 12
_vecintr_bodygen
isr_vec13:
intr_vec13:
_vecintr_errorcode_present_save 13
_vecintr_bodygen
isr_vec14:
intr_vec14:
_vecintr_errorcode_present_save 14
_vecintr_bodygen
isr_vec16:
intr_vec16:
_vecintr_plain_save 16, 0
_vecintr_bodygen
isr_vec17:
intr_vec17:
_vecintr_errorcode_present_save 17
_vecintr_bodygen
isr_vec18:
intr_vec18:
_vecintr_plain_save 18, 0
_vecintr_bodygen
isr_vec19:
intr_vec19:
_vecintr_plain_save 19, 0
_vecintr_bodygen
isr_vec20:
intr_vec20:
_vecintr_plain_save 20, 0
_vecintr_bodygen
isr_vec21:
intr_vec21:
_vecintr_errorcode_present_save 21
_vecintr_bodygen
isr_vec32:
intr_vec32:
_vecintr_plain_save 32, 0
_vecintr_bodygen
isr_vec33:
intr_vec33:
_vecintr_plain_save 33, 0
_vecintr_bodygen
isr_vec39:
intr_vec39:
_vecintr_plain_save 39, 0
_vecintr_bodygen

View File

@ -1,176 +0,0 @@
#include <stddef.h>
#include <stdint.h>
#include "isr.h"
#include "io.h"
#include "gdt.h"
#include "hal/hal.h"
#include "kprintf.h"
#include "compiler/attr.h"
typedef struct {
uint16_t isrlow;
uint16_t kernelcs;
uint8_t ist;
uint8_t attrs;
uint16_t isrmid;
uint32_t isrhigh;
uint32_t resv;
} PACKED IdtGate;
typedef struct {
uint16_t limit;
uint64_t base;
} PACKED Idt;
#define ENTRIES 256
ALIGNED(0x10) static IdtGate idtgates[ENTRIES] = {0};
static Idt idt = {0};
void idt_setentry(int i, uint64_t handler, uint8_t ist, uint8_t flags) {
idtgates[i].isrlow = handler & 0xffff;
idtgates[i].kernelcs = KCODE;
idtgates[i].ist = ist;
idtgates[i].attrs = flags;
idtgates[i].isrmid = (handler >> 16) & 0xFFFF;
idtgates[i].isrhigh = (handler >> 32) & 0xFFFFFFFF;
idtgates[i].resv = 0;
}
void idt_init(void) {
idt.base = (uint64_t)&idtgates;
idt.limit = ENTRIES * sizeof(IdtGate) - 1;
asm volatile("lidt %0" :: "m"(idt) : "memory");
LOG("idt", "idt init\n");
}
typedef struct {
uint64_t r15;
uint64_t r14;
uint64_t r13;
uint64_t r12;
uint64_t r11;
uint64_t r10;
uint64_t r9;
uint64_t r8;
uint64_t rsi;
uint64_t rdi;
uint64_t rbp;
uint64_t rdx;
uint64_t rcx;
uint64_t rbx;
uint64_t rax;
} PACKED CpuRegs;
typedef struct {
uint64_t cr8;
uint64_t cr4;
uint64_t cr3;
uint64_t cr2;
uint64_t cr0;
} PACKED CpuCtrlRegs;
typedef struct {
CpuCtrlRegs ctrl;
CpuRegs regs;
uint64_t trapnum;
uint64_t errnum;
uint64_t rip;
uint64_t cs;
uint64_t rflags;
uint64_t rsp;
uint64_t ss;
} PACKED IntrStackFrame;
extern void *ISR_REDIRTABLE[];
static const char *exceptions[] = {
"#DE", "#DB", "NMI",
"#BP", "#OF", "#BR",
"#UD", "#NM", "#DF",
"CSO", "#TS", "#NP",
"#SS", "#GP", "#PF",
"RES", "#MF", "#AC",
"#MC", "#XM", "#VE",
"#CP",
};
extern void isr_vec0(void);
extern void isr_vec1(void);
extern void isr_vec2(void);
extern void isr_vec3(void);
extern void isr_vec4(void);
extern void isr_vec5(void);
extern void isr_vec6(void);
extern void isr_vec7(void);
extern void isr_vec8(void);
extern void isr_vec10(void);
extern void isr_vec11(void);
extern void isr_vec12(void);
extern void isr_vec13(void);
extern void isr_vec14(void);
extern void isr_vec16(void);
extern void isr_vec17(void);
extern void isr_vec18(void);
extern void isr_vec19(void);
extern void isr_vec20(void);
extern void isr_vec21(void);
extern void isr_vec32(void);
extern void isr_vec33(void);
extern void isr_vec39(void);
void isr_init(void) {
idt_setentry(0, (uint64_t)&isr_vec0, 0, 0x8E);
idt_setentry(1, (uint64_t)&isr_vec1, 0, 0x8E);
idt_setentry(2, (uint64_t)&isr_vec2, 2, 0x8E);
idt_setentry(3, (uint64_t)&isr_vec3, 0, 0x8E);
idt_setentry(4, (uint64_t)&isr_vec4, 0, 0x8E);
idt_setentry(5, (uint64_t)&isr_vec5, 0, 0x8E);
idt_setentry(6, (uint64_t)&isr_vec6, 0, 0x8E);
idt_setentry(7, (uint64_t)&isr_vec7, 0, 0x8E);
idt_setentry(8, (uint64_t)&isr_vec8, 1, 0x8E);
idt_setentry(10, (uint64_t)&isr_vec10, 0, 0x8E);
idt_setentry(11, (uint64_t)&isr_vec11, 0, 0x8E);
idt_setentry(12, (uint64_t)&isr_vec12, 0, 0x8E);
idt_setentry(13, (uint64_t)&isr_vec13, 0, 0x8E);
idt_setentry(14, (uint64_t)&isr_vec14, 0, 0x8E);
idt_setentry(16, (uint64_t)&isr_vec16, 0, 0x8E);
idt_setentry(17, (uint64_t)&isr_vec17, 0, 0x8E);
idt_setentry(18, (uint64_t)&isr_vec18, 0, 0x8E);
idt_setentry(19, (uint64_t)&isr_vec19, 0, 0x8E);
idt_setentry(20, (uint64_t)&isr_vec20, 0, 0x8E);
idt_setentry(21, (uint64_t)&isr_vec21, 0, 0x8E);
idt_setentry(32, (uint64_t)&isr_vec32, 0, 0x8E);
idt_setentry(33, (uint64_t)&isr_vec33, 0, 0x8E);
idt_setentry(39, (uint64_t)&isr_vec39, 0, 0x8E);
idt_init();
}
void isr_dumpframe(IntrStackFrame *frame) {
kprintf("r15=%016llx r14=%016llx r13=%016llx r12=%016llx\n"
"r11=%016llx r10=%016llx r9 =%016llx r8 =%016llx\n"
"rsi=%016llx rdi=%016llx rbp=%016llx rdx=%016llx\n"
"rcx=%016llx rbx=%016llx rax=%016llx\n"
"cr8=%016llx cr4=%016llx cr3=%016llx cr2=%016llx\n"
"cr0=%016llx rip=%016llx cs =%016llx rfl=%016llx\n"
"rsp=%016llx ss =%016llx trp=%016llx err=%016llx\n",
frame->regs.r15, frame->regs.r14, frame->regs.r13, frame->regs.r12,
frame->regs.r11, frame->regs.r10, frame->regs.r9, frame->regs.r8,
frame->regs.rsi, frame->regs.rdi, frame->regs.rbp, frame->regs.rdx,
frame->regs.rcx, frame->regs.rbx, frame->regs.rax,
frame->ctrl.cr8, frame->ctrl.cr4, frame->ctrl.cr3,
frame->ctrl.cr2, frame->ctrl.cr0, frame->rip, frame->cs, frame->rflags,
frame->rsp, frame->ss, frame->trapnum, frame->errnum
);
}
void isr_handleintr(IntrStackFrame *frame) {
hal_intr_disable();
ERR("ERROR", "%s, 0x%X\n", exceptions[frame->trapnum], frame->errnum);
isr_dumpframe(frame);
hal_hang();
}

View File

@ -1,6 +0,0 @@
#ifndef HAL_ISR_H_
#define HAL_ISR_H_
void isr_init(void);
#endif // HAL_ISR_H_

22
kernel/hal/x86_64/pic.c Normal file
View File

@ -0,0 +1,22 @@
#include <stddef.h>
#include <stdint.h>
#include "pic.h"
#include "io.h"
#include "intr.h"
void pic_init(void) {
io_out8(PIC1_CMD, ICW1_INIT | ICW1_ICW4);
io_out8(PIC2_CMD, ICW1_INIT | ICW1_ICW4);
io_out8(PIC1_DATA, INTR_IRQBASE);
io_out8(PIC2_DATA, INTR_IRQBASE+8);
io_out8(PIC1_DATA, 4);
io_out8(PIC2_DATA, 2);
io_out8(PIC1_DATA, ICW4_8086);
io_out8(PIC2_DATA, ICW4_8086);
io_out8(PIC1_DATA, 0xff);
io_out8(PIC2_DATA, 0xff);
}

23
kernel/hal/x86_64/pic.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef HAL_PIC_H_
#define HAL_PIC_H_
#define PIC1_CMD 0x0020
#define PIC1_DATA 0x0021
#define PIC2_CMD 0x00A0
#define PIC2_DATA 0x00A1
#define ICW1_ICW4 0x01
#define ICW1_SINGLE 0x02
#define ICW1_ADI 0x04
#define ICW1_LTIM 0x08
#define ICW1_INIT 0x10
#define ICW4_8086 0x01
#define ICW4_AUTO 0x02
#define ICW4_BUFSLAVE 0x04
#define ICW4_BUFMASTER 0x0C
#define ICW4_SFNM 0x10
void pic_init(void);
#endif // HAL_PIC_H_

View File

@ -1,45 +0,0 @@
#include "uacpi/uacpi.h"
#include "dlmalloc/malloc.h"
#include "bootinfo/bootinfo.h"
#include "hal/x86_64/io.h"
#include "kprintf.h"
#include "compiler/builtins.h"
void *uacpi_kernel_alloc(uacpi_size size) {
return dlmalloc(size);
}
void uacpi_kernel_free(void *ptr) {
return dlfree(ptr);
}
void uacpi_kernel_log(uacpi_log_level lvl, const uacpi_char *s) {
char *t;
switch (lvl) {
case UACPI_LOG_DEBUG: t = "Debug"; break;
case UACPI_LOG_TRACE: t = "Trace"; break;
case UACPI_LOG_INFO: t = "Info"; break;
case UACPI_LOG_WARN: t = "Warn"; break;
case UACPI_LOG_ERROR: t = "Error"; break;
default:
unreachable();
break;
}
LOG("uACPI", "[%s] %s", t, s);
}
void *uacpi_kernel_map(uacpi_phys_addr addr, uacpi_size len) {
(void)len;
return (void *)(BOOT_INFO.hhdm_off + addr);
}
void uacpi_kernel_unmap(void *addr, uacpi_size len) {
(void)addr;
(void)len;
}
uacpi_status uacpi_kernel_get_rsdp(uacpi_phys_addr *out) {
*out = BOOT_INFO.rsdp;
return UACPI_STATUS_OK;
}

View File

@ -374,11 +374,12 @@ If you want to contribute:
| [ilobilix](https://github.com/ilobilo/ilobilix) | Yet another monolithic Linux clone wannabe. Currently under a rewrite | 8,703,286 | AMD Ryzen 9 9950X3D |
| [Crescent2](https://github.com/Qwinci/crescent2) | An NT driver compatible kernel and userspace | 6,818,418 | Intel Core i5-13600K |
| [davix](https://github.com/dbstream/davix) | Yet another unix-like by some bored nerd | 6,364,623 | Intel Core i7-13700K |
| [Ironclad](https://ironclad-os.org) | Formally verified, hard real-time capable kernel written in SPARK and Ada | 6,196,937 | Intel Core i9-13900KS |
| [Managarm](https://github.com/managarm/managarm) | Pragmatic microkernel-based OS with fully asynchronous I/O | 5,618,646 | Intel Core i7-14700K |
| [ChronOS](https://github.com/BUGO07/chronos) | Another basic hobby os held together by duct tape, made in rust | 5,416,703 | Intel Core Ultra 7 265KF |
| [pmOS](https://gitlab.com/mishakov/pmos) | Microkernel-based operating system written from scratch with uACPI running in userspace | 5,354,445 | AMD Ryzen 9 5900X |
| [menix](https://github.com/menix-os/menix) | A minimal and expandable Unix-like operating system | 5,239,043 | Intel Core Ultra 7 265KF |
| [Ironclad](https://ironclad.nongnu.org) | Formally verified, hard real-time capable kernel written in SPARK and Ada | 4,802,816 | Intel Core i9-13900KS |
| [Orange](https://github.com/cpplover0/orange) | Unix-like x86_64 OS with some microkernel features | 4,204,053 | AMD Ryzen 5 3600 |
| [Astral](https://github.com/mathewnd/astral) | Operating system written in C which aims be POSIX-compliant | 4,189,189 | Intel Core i5-13600K |
| [Keyronex](https://github.com/Keyronex/Keyronex) | Layered kernel with fundamentally asynchronous I/O and working set model-based memory management | 4,013,691 | AMD Ryzen 5800X |
| [Orange](https://github.com/cppLover0/Orange) | x86_64 Unix-like OS | 2,377,330 | AMD Ryzen 5 3600 |
@ -387,6 +388,7 @@ If you want to contribute:
| [ElysiumOS](https://github.com/imwux/elysium-os) | Hybrid Unix-like kernel | 1,737,654 | AMD Ryzen 7 5800X3D |
| [imaginarium](https://github.com/Khitiara/imaginarium) | Ziggy osdev experiments inspired by the NT kernel (using the zig general purpose allocator) | 1,504,436 | AMD Ryzen 7 3700X |
| [BadgerOS](https://github.com/badgeteam/BadgerOS) | A monolithic lightweight UNIX clone | 1,018,518 | AMD Ryzen 5 3600 |
| [Retro Rocket](https://github.com/brainboxdotcc/retro-rocket) | A BASIC _powered_ 64-bit SMP multitasking OS | 441,329 | Intel Xeon E5-2680 |
| [Hyra](https://github.com/sigsegv7/Hyra) | Monolithic UNIX-like OS by [OSMORA.ORG](https://osmora.org) | 199,873 | Intel Core i3-3220 |
## License

View File

@ -9,6 +9,8 @@ extern "C" {
// Forward-declared to avoid including the entire acpi.h here
struct acpi_fadt;
struct acpi_entry_hdr;
struct acpi_sdt_hdr;
typedef struct uacpi_table_identifiers {
uacpi_object_name signature;
@ -136,6 +138,30 @@ uacpi_status uacpi_set_table_installation_handler(
uacpi_table_installation_handler handler
);
typedef uacpi_iteration_decision (*uacpi_subtable_iteration_callback)
(uacpi_handle, struct acpi_entry_hdr*);
/*
* Iterate every subtable of a table such as MADT or SRAT.
*
* 'hdr' is the pointer to the main table, 'hdr_size' is the number of bytes in
* the table before the beginning of the subtable records. 'cb' is the callback
* invoked for each subtable with the 'user' context pointer passed for every
* invocation.
*
* Example usage:
* uacpi_table tbl;
*
* uacpi_table_find_by_signature(ACPI_MADT_SIGNATURE, &tbl);
* uacpi_for_each_subtable(
* tbl.hdr, sizeof(struct acpi_madt), parse_madt, NULL
* );
*/
uacpi_status uacpi_for_each_subtable(
struct acpi_sdt_hdr *hdr, size_t hdr_size,
uacpi_subtable_iteration_callback cb, void *user
);
#ifdef __cplusplus
}
#endif

View File

@ -29,7 +29,13 @@ typedef enum uacpi_iteration_decision {
UACPI_ITERATION_DECISION_CONTINUE = 0,
UACPI_ITERATION_DECISION_BREAK,
// Only applicable for uacpi_namespace_for_each_child
/*
* Ignore all of the children of the current node and proceed directly to
* its peer nodes.
*
* Only applicable for API that interacts with the AML namespace such as
* uacpi_namespace_for_each_child, uacpi_find_deivces, etc.
*/
UACPI_ITERATION_DECISION_NEXT_PEER,
} uacpi_iteration_decision;

View File

@ -6,7 +6,7 @@
#include <uacpi/namespace.h>
#define UACPI_MAJOR 3
#define UACPI_MINOR 0
#define UACPI_MINOR 1
#define UACPI_PATCH 0
#ifdef UACPI_REDUCED_HARDWARE

View File

@ -1398,3 +1398,52 @@ uacpi_status uacpi_table_fadt(struct acpi_fadt **out_fadt)
*out_fadt = &g_uacpi_rt_ctx.fadt;
return UACPI_STATUS_OK;
}
uacpi_status uacpi_for_each_subtable(
struct acpi_sdt_hdr *hdr, size_t hdr_size,
uacpi_subtable_iteration_callback cb, void *user
)
{
void *cursor;
size_t bytes_left;
cursor = UACPI_PTR_ADD(hdr, hdr_size);
bytes_left = hdr->length - hdr_size;
if (uacpi_unlikely(bytes_left > hdr->length))
return UACPI_STATUS_INVALID_TABLE_LENGTH;
while (bytes_left > sizeof(struct acpi_entry_hdr)) {
struct acpi_entry_hdr *subtable_hdr = cursor;
if (uacpi_unlikely(subtable_hdr->length > bytes_left ||
subtable_hdr->length < sizeof(*subtable_hdr))) {
uacpi_error(
"corrupted '%.4s' subtable length: %u (%zu bytes left)\n",
hdr->signature, subtable_hdr->length, bytes_left
);
return UACPI_STATUS_INVALID_TABLE_LENGTH;
}
switch (cb(user, subtable_hdr)) {
case UACPI_ITERATION_DECISION_CONTINUE:
break;
case UACPI_ITERATION_DECISION_BREAK:
return UACPI_STATUS_OK;
default:
return UACPI_STATUS_INVALID_ARGUMENT;
}
cursor = UACPI_PTR_ADD(cursor, subtable_hdr->length);
bytes_left -= subtable_hdr->length;
}
if (uacpi_unlikely(bytes_left != 0)) {
uacpi_warn(
"found %zu stray bytes in table '%.4s'\n",
bytes_left, hdr->signature
);
}
return UACPI_STATUS_OK;
}

View File

@ -464,6 +464,7 @@ def main() -> int:
bare_cases: List[TestCase] = [
BarebonesTestCase("basic-operation"),
BarebonesTestCase("table-installation"),
BarebonesTestCase("foreach-subtable"),
]
with TestHeaderFooter("Barebones Mode Tests"):

View File

@ -54,6 +54,33 @@ static uint8_t test_mcfg[] = {
0x00, 0x00, 0x00, 0x00
};
/*
* 4 Local APICs [0, 1, 2, 3]
* 2 IOAPICs [4, 5]
* 2 ISOs [0->2, 9->9]
* 4 NMIs [0, 1, 2, 3]
*/
static uint8_t test_apic[] = {
0x41, 0x50, 0x49, 0x43, 0x90, 0x00, 0x00, 0x00,
0x03, 0x1a, 0x48, 0x50, 0x51, 0x4f, 0x45, 0x4d,
0x53, 0x4c, 0x49, 0x43, 0x2d, 0x4d, 0x50, 0x43,
0x01, 0x00, 0x00, 0x00, 0x48, 0x50, 0x20, 0x20,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0xfe,
0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x01,
0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x02, 0x02,
0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x03, 0x03,
0x01, 0x00, 0x00, 0x00, 0x01, 0x0c, 0x04, 0x00,
0x00, 0x00, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00,
0x01, 0x0c, 0x05, 0x00, 0x00, 0x10, 0xc0, 0xfe,
0x18, 0x00, 0x00, 0x00, 0x02, 0x0a, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0a,
0x00, 0x09, 0x09, 0x00, 0x00, 0x00, 0x0f, 0x00,
0x04, 0x06, 0x00, 0x05, 0x00, 0x01, 0x04, 0x06,
0x01, 0x05, 0x00, 0x01, 0x04, 0x06, 0x02, 0x05,
0x00, 0x01, 0x04, 0x06, 0x03, 0x05, 0x00, 0x01
};
static void ensure_signature_is(const char *signature, uacpi_table tbl)
{
if (strncmp(tbl.hdr->signature, signature, 4) == 0)
@ -105,12 +132,123 @@ static void test_table_installation(void)
uacpi_table_unref(&tbl);
}
static uacpi_iteration_decision check_madt(
uacpi_handle user, struct acpi_entry_hdr *hdr
)
{
size_t *idx = user;
struct acpi_madt_lapic *lapic;
struct acpi_madt_ioapic *ioapic;
struct acpi_madt_interrupt_source_override *iso;
struct acpi_madt_lapic_nmi *nmi;
switch (*idx) {
case 0:
case 1:
case 2:
case 3:
if (hdr->type != ACPI_MADT_ENTRY_TYPE_LAPIC)
goto out_unexpected;
lapic = (struct acpi_madt_lapic*)hdr;
if (lapic->id != *idx)
error("unexpected LAPIC id %d (idx %d)\n", lapic->id, *idx);
break;
case 4:
case 5:
if (hdr->type != ACPI_MADT_ENTRY_TYPE_IOAPIC)
goto out_unexpected;
ioapic = (struct acpi_madt_ioapic*)hdr;
if (ioapic->id != *idx)
error("unexpected IOAPIC id %d (idx %d)\n", ioapic->id, *idx);
break;
case 6:
case 7:
if (hdr->type != ACPI_MADT_ENTRY_TYPE_INTERRUPT_SOURCE_OVERRIDE)
goto out_unexpected;
iso = (struct acpi_madt_interrupt_source_override*)hdr;
if ((*idx == 6 && iso->source != 0) ||
(*idx == 7 && iso->source != 9))
error("unexpected ISO source %d (idx %d)\n", iso->source, *idx);
break;
case 8:
case 9:
case 10:
case 11:
if (hdr->type != ACPI_MADT_ENTRY_TYPE_LAPIC_NMI)
goto out_unexpected;
nmi = (struct acpi_madt_lapic_nmi*)hdr;
if (nmi->uid != (*idx - 8))
error("unexpected LAPIC NMI uid %d (idx %d)\n", nmi->uid, *idx);
break;
default:
goto out_unexpected;
}
(*idx)++;
return UACPI_ITERATION_DECISION_CONTINUE;
out_unexpected:
error("unexpected MADT entry type %d (idx = %zu)\n", hdr->type, *idx);
return UACPI_ITERATION_DECISION_BREAK;
}
#define CHECK_SUBTEST_FAILED \
if (st != UACPI_STATUS_INVALID_TABLE_LENGTH) \
error("unexpected status %s\n", uacpi_status_to_string(st));
#define CHECK_SUBTEST_SUCCEEDED \
if (idx != 12) \
error("invalid number of iterations: %zu\n", idx);
#define FOREACH_SUBTEST(check_cond) \
idx = 0; \
st = uacpi_for_each_subtable( \
tbl.hdr, sizeof(struct acpi_madt), check_madt, &idx \
); \
check_cond; \
static void test_foreach_subtable(void)
{
uacpi_status st;
uacpi_table tbl;
size_t idx = 0;
st = uacpi_table_install(test_apic, &tbl);
ensure_ok_status(st);
ensure_signature_is(ACPI_MADT_SIGNATURE, tbl);
uacpi_table_unref(&tbl);
FOREACH_SUBTEST(CHECK_SUBTEST_SUCCEEDED);
// Make the size slightly larger, make sure we don't crash
test_apic[4] += 1;
FOREACH_SUBTEST(CHECK_SUBTEST_SUCCEEDED);
// Change the size to 1 byte and make sure we don't crash
test_apic[4] = 1;
FOREACH_SUBTEST(CHECK_SUBTEST_FAILED);
// Cutoff subtable
test_apic[4] = sizeof(struct acpi_madt) + sizeof(struct acpi_entry_hdr) + 1;
FOREACH_SUBTEST(CHECK_SUBTEST_FAILED);
test_apic[4] = sizeof(test_apic);
// Out-of-bounds subtable
test_apic[sizeof(test_apic) - 5]++;
FOREACH_SUBTEST(CHECK_SUBTEST_FAILED);
// all pass
test_apic[sizeof(test_apic) - 5]--;
uacpi_table_unref(&tbl);
}
static struct {
const char *name;
void (*func)(void);
} test_cases[] = {
{ "basic-operation", test_basic_operation },
{ "table-installation", test_table_installation },
{ "foreach-subtable", test_foreach_subtable },
};
static arg_spec_t TEST_CASE_ARG = ARG_POS("test-case", "name of the test case");

View File

@ -20,6 +20,8 @@ NORETURN static inline void error(const char *format, ...)
{
va_list args;
fflush(stdout);
fprintf(stderr, "unexpected error: ");
va_start(args, format);
vfprintf(stderr, format, args);