feat/kernel: APIC (LAPIC / IOAPIC) and PIT
This commit is contained in:
parent
cdceef1da7
commit
9fcac766f6
10 changed files with 350 additions and 11 deletions
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -20,6 +20,7 @@
|
||||||
"serial.h": "c",
|
"serial.h": "c",
|
||||||
"kpanic.h": "c",
|
"kpanic.h": "c",
|
||||||
"smp.h": "c",
|
"smp.h": "c",
|
||||||
"string_view": "c"
|
"string_view": "c",
|
||||||
|
"lapic.h": "c"
|
||||||
}
|
}
|
||||||
}
|
}
|
1
credits.txt
Normal file
1
credits.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
- Thanks to Raph and https://github.com/SILD-Project/soaplin for most APIC related code
|
|
@ -5,6 +5,11 @@
|
||||||
#include <arch/cpu.h>
|
#include <arch/cpu.h>
|
||||||
#include <util/log.h>
|
#include <util/log.h>
|
||||||
#include <sys/kpanic.h>
|
#include <sys/kpanic.h>
|
||||||
|
#include <sys/lapic.h>
|
||||||
|
#include <arch/smp.h>
|
||||||
|
#include <sys/lapic.h>
|
||||||
|
#include <sys/ioapic.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
struct idt_entry __attribute__((aligned(16))) idt_descriptor[256] = {0};
|
struct idt_entry __attribute__((aligned(16))) idt_descriptor[256] = {0};
|
||||||
idt_intr_handler real_handlers[256] = {0};
|
idt_intr_handler real_handlers[256] = {0};
|
||||||
|
@ -58,6 +63,8 @@ int idt_register_handler(size_t vector, idt_intr_handler handler)
|
||||||
if (real_handlers[vector] != idt_default_interrupt_handler)
|
if (real_handlers[vector] != idt_default_interrupt_handler)
|
||||||
{
|
{
|
||||||
real_handlers[vector] = handler;
|
real_handlers[vector] = handler;
|
||||||
|
if (vector <= 14)
|
||||||
|
ioapic_redirect_irq(bootstrap_lapic_id, vector + 32, vector, false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -20,6 +20,9 @@
|
||||||
#include <sys/acpi.h>
|
#include <sys/acpi.h>
|
||||||
#include <sys/acpi/madt.h>
|
#include <sys/acpi/madt.h>
|
||||||
#include <arch/smp.h>
|
#include <arch/smp.h>
|
||||||
|
#include <sys/lapic.h>
|
||||||
|
#include <sys/ioapic.h>
|
||||||
|
#include <sys/pit.h>
|
||||||
|
|
||||||
__attribute__((used, section(".limine_requests"))) static volatile LIMINE_BASE_REVISION(3);
|
__attribute__((used, section(".limine_requests"))) static volatile LIMINE_BASE_REVISION(3);
|
||||||
__attribute__((used, section(".limine_requests"))) static volatile struct limine_memmap_request memmap_request = {
|
__attribute__((used, section(".limine_requests"))) static volatile struct limine_memmap_request memmap_request = {
|
||||||
|
@ -58,6 +61,12 @@ struct limine_mp_response *mp_response = NULL;
|
||||||
struct flanterm_context *ft_ctx = NULL;
|
struct flanterm_context *ft_ctx = NULL;
|
||||||
#endif // FLANTERM_SUPPORT
|
#endif // FLANTERM_SUPPORT
|
||||||
|
|
||||||
|
void tick(struct register_ctx *)
|
||||||
|
{
|
||||||
|
log_early("tick");
|
||||||
|
lapic_eoi();
|
||||||
|
}
|
||||||
|
|
||||||
void emk_entry(void)
|
void emk_entry(void)
|
||||||
{
|
{
|
||||||
__asm__ volatile("movq %%rsp, %0" : "=r"(kstack_top));
|
__asm__ volatile("movq %%rsp, %0" : "=r"(kstack_top));
|
||||||
|
@ -168,15 +177,6 @@ void emk_entry(void)
|
||||||
kfree(c);
|
kfree(c);
|
||||||
log_early("Initialized kernel heap");
|
log_early("Initialized kernel heap");
|
||||||
|
|
||||||
/* Setup SMP */
|
|
||||||
if (!mp_request.response)
|
|
||||||
{
|
|
||||||
kpanic(NULL, "Failed to get MP request");
|
|
||||||
}
|
|
||||||
|
|
||||||
mp_response = mp_request.response;
|
|
||||||
smp_init();
|
|
||||||
|
|
||||||
/* Setup ACPI and APIC */
|
/* Setup ACPI and APIC */
|
||||||
rsdp_response = rsdp_request.response;
|
rsdp_response = rsdp_request.response;
|
||||||
if (!rsdp_response)
|
if (!rsdp_response)
|
||||||
|
@ -188,7 +188,24 @@ void emk_entry(void)
|
||||||
|
|
||||||
/* Setup MADT */
|
/* Setup MADT */
|
||||||
madt_init();
|
madt_init();
|
||||||
log_early("Initialized APIC");
|
ioapic_init();
|
||||||
|
log_early("Initialized IOAPIC");
|
||||||
|
lapic_init();
|
||||||
|
log_early("Initialized LAPIC");
|
||||||
|
|
||||||
|
/* Setup timer */
|
||||||
|
pit_init(tick);
|
||||||
|
log_early("Initialized Timer");
|
||||||
|
|
||||||
|
/* Setup SMP */
|
||||||
|
if (!mp_request.response)
|
||||||
|
{
|
||||||
|
kpanic(NULL, "Failed to get MP request");
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_response = mp_request.response;
|
||||||
|
smp_init();
|
||||||
|
log_early("Initialized SMP");
|
||||||
|
|
||||||
hlt();
|
hlt();
|
||||||
}
|
}
|
128
kernel/src/sys/ioapic.c
Normal file
128
kernel/src/sys/ioapic.c
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
/* EMK 1.0 Copyright (c) 2025 Piraterna */
|
||||||
|
#include <sys/ioapic.h>
|
||||||
|
#include <boot/emk.h>
|
||||||
|
|
||||||
|
void ioapic_init()
|
||||||
|
{
|
||||||
|
acpi_madt_ioapic_t *ioapic = madt_ioapic_list[0];
|
||||||
|
|
||||||
|
uint32_t val = ioapic_read(ioapic, IOAPIC_VER);
|
||||||
|
uint32_t count = ((val >> 16) & 0xFF);
|
||||||
|
|
||||||
|
if ((ioapic_read(ioapic, 0) >> 24) != ioapic->ioapic_id)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i <= count; ++i)
|
||||||
|
{
|
||||||
|
ioapic_write(ioapic, IOAPIC_REDTBL + 2 * i, 0x00010000 | (32 + i));
|
||||||
|
ioapic_write(ioapic, IOAPIC_REDTBL + 2 * i + 1, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ioapic_write(acpi_madt_ioapic_t *ioapic, uint8_t reg, uint32_t val)
|
||||||
|
{
|
||||||
|
*((volatile uint32_t *)(HIGHER_HALF(ioapic->ioapic_addr) + IOAPIC_REGSEL)) =
|
||||||
|
reg;
|
||||||
|
*((volatile uint32_t *)(HIGHER_HALF(ioapic->ioapic_addr) + IOAPIC_IOWIN)) = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ioapic_read(acpi_madt_ioapic_t *ioapic, uint8_t reg)
|
||||||
|
{
|
||||||
|
*((volatile uint32_t *)(HIGHER_HALF(ioapic->ioapic_addr) + IOAPIC_REGSEL)) =
|
||||||
|
reg;
|
||||||
|
return *(
|
||||||
|
(volatile uint32_t *)(HIGHER_HALF(ioapic->ioapic_addr) + IOAPIC_IOWIN));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ioapic_set_entry(acpi_madt_ioapic_t *ioapic, uint8_t idx, uint64_t data)
|
||||||
|
{
|
||||||
|
ioapic_write(ioapic, (uint8_t)(IOAPIC_REDTBL + idx * 2), (uint32_t)data);
|
||||||
|
ioapic_write(ioapic, (uint8_t)(IOAPIC_REDTBL + idx * 2 + 1),
|
||||||
|
(uint32_t)(data >> 32));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t ioapic_gsi_count(acpi_madt_ioapic_t *ioapic)
|
||||||
|
{
|
||||||
|
return (ioapic_read(ioapic, 1) & 0xff0000) >> 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
acpi_madt_ioapic_t *ioapic_get_gsi(uint32_t gsi)
|
||||||
|
{
|
||||||
|
for (uint64_t i = 0; i < madt_iso_len; i++)
|
||||||
|
{
|
||||||
|
acpi_madt_ioapic_t *ioapic = madt_ioapic_list[i];
|
||||||
|
if (ioapic->gsi_base <= gsi &&
|
||||||
|
ioapic->gsi_base + ioapic_gsi_count(ioapic) > gsi)
|
||||||
|
return ioapic;
|
||||||
|
}
|
||||||
|
return (acpi_madt_ioapic_t *)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ioapic_redirect_gsi(uint32_t lapic_id, uint8_t vec, uint32_t gsi,
|
||||||
|
uint16_t flags, bool mask)
|
||||||
|
{
|
||||||
|
acpi_madt_ioapic_t *ioapic = ioapic_get_gsi(gsi);
|
||||||
|
|
||||||
|
uint64_t redirect = vec;
|
||||||
|
|
||||||
|
if ((flags & (1 << 1)) != 0)
|
||||||
|
{
|
||||||
|
redirect |= (1 << 13);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flags & (1 << 3)) != 0)
|
||||||
|
{
|
||||||
|
redirect |= (1 << 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mask)
|
||||||
|
redirect |= (1 << 16);
|
||||||
|
else
|
||||||
|
redirect &= ~(1 << 16);
|
||||||
|
|
||||||
|
redirect |= (uint64_t)lapic_id << 56;
|
||||||
|
|
||||||
|
uint32_t redir_table = (gsi - ioapic->gsi_base) * 2 + 16;
|
||||||
|
ioapic_write(ioapic, redir_table, (uint32_t)redirect);
|
||||||
|
ioapic_write(ioapic, redir_table + 1, (uint32_t)(redirect >> 32));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ioapic_redirect_irq(uint32_t lapic_id, uint8_t vec, uint8_t irq,
|
||||||
|
bool mask)
|
||||||
|
{
|
||||||
|
uint8_t idx = 0;
|
||||||
|
acpi_madt_ioapic_src_ovr_t *iso = (acpi_madt_ioapic_src_ovr_t *)0;
|
||||||
|
|
||||||
|
while (idx < madt_iso_len)
|
||||||
|
{
|
||||||
|
iso = madt_iso_list[idx];
|
||||||
|
if (iso->irq_source == irq)
|
||||||
|
{
|
||||||
|
ioapic_redirect_gsi(lapic_id, vec, iso->gsi, iso->flags, mask);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ioapic_redirect_gsi(lapic_id, vec, irq, 0, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ioapic_get_redirect_irq(uint8_t irq)
|
||||||
|
{
|
||||||
|
uint8_t idx = 0;
|
||||||
|
acpi_madt_ioapic_src_ovr_t *iso;
|
||||||
|
|
||||||
|
while (idx < madt_iso_len)
|
||||||
|
{
|
||||||
|
iso = madt_iso_list[idx];
|
||||||
|
if (iso->irq_source == irq)
|
||||||
|
{
|
||||||
|
return iso->gsi;
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return irq;
|
||||||
|
}
|
30
kernel/src/sys/ioapic.h
Normal file
30
kernel/src/sys/ioapic.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/* EMK 1.0 Copyright (c) 2025 Piraterna */
|
||||||
|
#ifndef IOAPIC_H
|
||||||
|
#define IOAPIC_H
|
||||||
|
|
||||||
|
// Credits: https://github.com/SILD-Project/soaplin/blob/main/kernel/src/dev/ioapic.h
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <sys/acpi.h>
|
||||||
|
#include <sys/acpi/madt.h>
|
||||||
|
|
||||||
|
#define IOAPIC_REGSEL 0x0
|
||||||
|
#define IOAPIC_IOWIN 0x10
|
||||||
|
|
||||||
|
#define IOAPIC_ID 0x0
|
||||||
|
#define IOAPIC_VER 0x01
|
||||||
|
#define IOAPIC_ARB 0x02
|
||||||
|
#define IOAPIC_REDTBL 0x10
|
||||||
|
|
||||||
|
void ioapic_write(acpi_madt_ioapic_t *ioapic, uint8_t reg, uint32_t val);
|
||||||
|
uint32_t ioapic_read(acpi_madt_ioapic_t *ioapic, uint8_t reg);
|
||||||
|
|
||||||
|
void ioapic_redirect_irq(uint32_t lapic_id, uint8_t vec, uint8_t irq,
|
||||||
|
bool mask);
|
||||||
|
uint32_t ioapic_get_redirect_irq(uint8_t irq);
|
||||||
|
|
||||||
|
void ioapic_set_entry(acpi_madt_ioapic_t *ioapic, uint8_t idx, uint64_t data);
|
||||||
|
|
||||||
|
void ioapic_init();
|
||||||
|
|
||||||
|
#endif // IOAPIC_H
|
66
kernel/src/sys/lapic.c
Normal file
66
kernel/src/sys/lapic.c
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/* EMK 1.0 Copyright (c) 2025 Piraterna */
|
||||||
|
#include <sys/lapic.h>
|
||||||
|
#include <boot/emk.h>
|
||||||
|
|
||||||
|
uint64_t apic_ticks = 0;
|
||||||
|
|
||||||
|
void lapic_init()
|
||||||
|
{
|
||||||
|
lapic_write(0xf0, 0x1ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lapic_stop_timer()
|
||||||
|
{
|
||||||
|
lapic_write(LAPIC_TIMER_INITCNT, 0);
|
||||||
|
lapic_write(LAPIC_TIMER_LVT, LAPIC_TIMER_DISABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lapic_oneshot(uint8_t vec, uint64_t ms)
|
||||||
|
{
|
||||||
|
lapic_stop_timer();
|
||||||
|
lapic_write(LAPIC_TIMER_DIV, 0);
|
||||||
|
lapic_write(LAPIC_TIMER_LVT, vec);
|
||||||
|
lapic_write(LAPIC_TIMER_INITCNT, apic_ticks * ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lapic_calibrate_timer()
|
||||||
|
{
|
||||||
|
lapic_stop_timer();
|
||||||
|
lapic_write(LAPIC_TIMER_DIV, 0);
|
||||||
|
lapic_write(LAPIC_TIMER_LVT, (1 << 16) | 0xff);
|
||||||
|
lapic_write(LAPIC_TIMER_INITCNT, 0xFFFFFFFF);
|
||||||
|
lapic_write(LAPIC_TIMER_LVT, LAPIC_TIMER_DISABLE);
|
||||||
|
uint32_t ticks = 0xFFFFFFFF - lapic_read(LAPIC_TIMER_CURCNT);
|
||||||
|
apic_ticks = ticks;
|
||||||
|
lapic_stop_timer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void lapic_write(uint32_t reg, uint32_t val)
|
||||||
|
{
|
||||||
|
*((volatile uint32_t *)(HIGHER_HALF(0xfee00000) + reg)) = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t lapic_read(uint32_t reg)
|
||||||
|
{
|
||||||
|
return *((volatile uint32_t *)(HIGHER_HALF(0xfee00000) + reg));
|
||||||
|
}
|
||||||
|
|
||||||
|
void lapic_eoi() { lapic_write((uint8_t)0xb0, 0x0); }
|
||||||
|
|
||||||
|
void lapic_ipi(uint32_t id, uint8_t dat)
|
||||||
|
{
|
||||||
|
lapic_write(LAPIC_ICRHI, id << LAPIC_ICDESTSHIFT);
|
||||||
|
lapic_write(LAPIC_ICRLO, dat);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lapic_send_all_int(uint32_t id, uint32_t vec)
|
||||||
|
{
|
||||||
|
lapic_ipi(id, vec | LAPIC_ICRAIS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lapic_send_others_int(uint32_t id, uint32_t vec)
|
||||||
|
{
|
||||||
|
lapic_ipi(id, vec | LAPIC_ICRAES);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t lapic_get_id() { return lapic_read(0x0020) >> LAPIC_ICDESTSHIFT; }
|
56
kernel/src/sys/lapic.h
Normal file
56
kernel/src/sys/lapic.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/* EMK 1.0 Copyright (c) 2025 Piraterna */
|
||||||
|
#ifndef LAPIC_H
|
||||||
|
#define LAPIC_H
|
||||||
|
|
||||||
|
// Credits: https://github.com/SILD-Project/soaplin/blob/main/kernel/src/dev/lapic.h
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define LAPIC_PPR 0x00a0
|
||||||
|
|
||||||
|
#define LAPIC_ICRLO 0x0300
|
||||||
|
#define LAPIC_ICRHI 0x0310
|
||||||
|
|
||||||
|
#define LAPIC_ICINI 0x0500
|
||||||
|
#define LAPIC_ICSTR 0x0600
|
||||||
|
|
||||||
|
#define LAPIC_ICEDGE 0x0000
|
||||||
|
|
||||||
|
#define LAPIC_ICPEND 0x00001000
|
||||||
|
#define LAPIC_ICPHYS 0x00000000
|
||||||
|
#define LAPIC_ICASSR 0x00004000
|
||||||
|
#define LAPIC_ICSHRTHND 0x00000000
|
||||||
|
#define LAPIC_ICDESTSHIFT 24
|
||||||
|
|
||||||
|
#define LAPIC_ICRAIS 0x00080000
|
||||||
|
#define LAPIC_ICRAES 0x000c0000
|
||||||
|
|
||||||
|
// Timer
|
||||||
|
#define LAPIC_TIMER_DIV 0x3E0
|
||||||
|
#define LAPIC_TIMER_INITCNT 0x380
|
||||||
|
#define LAPIC_TIMER_LVT 0x320
|
||||||
|
#define LAPIC_TIMER_DISABLE 0x10000
|
||||||
|
#define LAPIC_TIMER_CURCNT 0x390
|
||||||
|
#define LAPIC_TIMER_PERIODIC 0x20000
|
||||||
|
|
||||||
|
void lapic_init();
|
||||||
|
|
||||||
|
void lapic_stop_timer();
|
||||||
|
void lapic_oneshot(uint8_t vec, uint64_t ms);
|
||||||
|
void lapic_calibrate_timer();
|
||||||
|
|
||||||
|
void lapic_write(uint32_t reg, uint32_t val);
|
||||||
|
uint32_t lapic_read(uint32_t reg);
|
||||||
|
|
||||||
|
void lapic_eoi();
|
||||||
|
|
||||||
|
void lapic_ipi(uint32_t id, uint8_t dat);
|
||||||
|
|
||||||
|
void lapic_send_all_int(uint32_t id, uint32_t vec);
|
||||||
|
void lapic_send_others_int(uint32_t id, uint32_t vec);
|
||||||
|
|
||||||
|
void lapic_init_cpu(uint32_t id);
|
||||||
|
void lapic_start_cpu(uint32_t id, uint32_t vec);
|
||||||
|
uint32_t lapic_get_id();
|
||||||
|
|
||||||
|
#endif // LAPIC_H
|
24
kernel/src/sys/pit.c
Normal file
24
kernel/src/sys/pit.c
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/* EMK 1.0 Copyright (c) 2025 Piraterna */
|
||||||
|
#include <sys/pit.h>
|
||||||
|
#include <arch/io.h>
|
||||||
|
#include <sys/lapic.h>
|
||||||
|
|
||||||
|
void (*pit_callback)(struct register_ctx *ctx) = NULL;
|
||||||
|
|
||||||
|
void pit_handler(struct register_ctx *frame)
|
||||||
|
{
|
||||||
|
if (pit_callback)
|
||||||
|
pit_callback(frame);
|
||||||
|
lapic_eoi();
|
||||||
|
}
|
||||||
|
|
||||||
|
void pit_init(void (*callback)(struct register_ctx *ctx))
|
||||||
|
{
|
||||||
|
if (callback)
|
||||||
|
pit_callback = callback;
|
||||||
|
outb(0x43, 0x36);
|
||||||
|
idt_register_handler(IDT_IRQ_BASE + 0, pit_handler);
|
||||||
|
uint16_t divisor = 5966; // ~200Hz
|
||||||
|
outb(0x40, divisor & 0xFF);
|
||||||
|
outb(0x40, (divisor >> 8) & 0xFF);
|
||||||
|
}
|
9
kernel/src/sys/pit.h
Normal file
9
kernel/src/sys/pit.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
/* EMK 1.0 Copyright (c) 2025 Piraterna */
|
||||||
|
#ifndef PIT_H
|
||||||
|
#define PIT_H
|
||||||
|
|
||||||
|
#include <arch/idt.h>
|
||||||
|
|
||||||
|
void pit_init(void (*callback)(struct register_ctx *ctx));
|
||||||
|
|
||||||
|
#endif // PIT_H
|
Loading…
Add table
Add a link
Reference in a new issue