Skip to content

Commit

Permalink
x86: LAPIC timer
Browse files Browse the repository at this point in the history
  • Loading branch information
marv7000 committed Nov 27, 2024
1 parent f5685d6 commit f605130
Show file tree
Hide file tree
Showing 6 changed files with 17 additions and 121 deletions.
2 changes: 1 addition & 1 deletion include/menix/util/log.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
#endif

#define kmesg(fmt, ...) \
kmesg_direct("[%5zu.%06zu] " fmt, (clock_get_elapsed() / 1000000000), ((clock_get_elapsed() / 1000) % 100000), \
kmesg_direct("[%5zu.%06zu] " fmt, (clock_get_elapsed() / 1000000000), ((clock_get_elapsed() / 1000) % 1000000), \
##__VA_ARGS__)

// Print a message to the kernel log.
Expand Down
6 changes: 0 additions & 6 deletions kernel/arch/riscv64/system/arch.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,6 @@ void arch_early_init(BootInfo* info)
boot_info = info;
}

void arch_init(BootInfo* info)
{
fw_init(info);
asm_interrupt_enable();
}

void arch_shutdown(BootInfo* info)
{
arch_stop(info);
Expand Down
120 changes: 12 additions & 108 deletions kernel/arch/x86_64/system/apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <menix/system/acpi/madt.h>
#include <menix/system/arch.h>
#include <menix/system/sch/scheduler.h>
#include <menix/system/time/clock.h>

#include <apic.h>
#include <io.h>
Expand All @@ -32,82 +33,11 @@ void pic_disable()
arch_x86_write8(PIC2_DATA_PORT, 0x01); // ICW4: Set the PIC to operate in 8086/88 mode.
arch_x86_write8(PIC2_DATA_PORT, 0xFF); // Mask all interrupts.
}

static u32 ioapic_read(PhysAddr ioapic_address, usize reg)
{
mmio_write16(pm_get_phys_base() + ioapic_address, reg & 0xFF);
return mmio_read16(pm_get_phys_base() + ioapic_address + 16);
}

static void ioapic_write(PhysAddr ioapic_address, usize reg, u32 data)
{
mmio_write16(pm_get_phys_base() + ioapic_address, reg & 0xFF);
mmio_write16(pm_get_phys_base() + ioapic_address + 16, data);
}

static MadtIoApic* get_ioapic_by_gsi(i32 gsi)
{
for (usize i = 0; i < madt_ioapic_list.length; i++)
{
MadtIoApic* ioapic = madt_ioapic_list.items[i];
if (ioapic->gsi_base <= gsi &&
ioapic->gsi_base + ((ioapic_read(ioapic->ioapic_addr, 1) & 0xFF0000) >> 16) > gsi)
return ioapic;
}

return NULL;
}

static void ioapic_redirect_gsi(u32 gsi, u8 vec, u16 flags)
{
// Get I/O APIC address of the GSI
usize io_apic = get_ioapic_by_gsi(gsi)->ioapic_addr;

u32 low_index = 0x10 + (gsi - get_ioapic_by_gsi(gsi)->gsi_base) * 2;
u32 high_index = low_index + 1;

u32 high = ioapic_read(io_apic, high_index);

// Set APIC ID
high &= ~0xFF000000;
high |= ioapic_read(io_apic, 0) << 24;
ioapic_write(io_apic, high_index, high);

u32 low = ioapic_read(io_apic, low_index);

low &= ~(1 << 16);
low &= ~(1 << 11);
low &= ~0x700;
low &= ~0xFF;
low |= vec;

if (flags & 2)
low |= 1 << 13;

if (flags & 8)
low |= 1 << 15;

ioapic_write(io_apic, low_index, low);
}

static inline u32 reg_to_x2apic(u32 reg)
{
return ((reg == 0x310) ? 0x30 : (reg >> 4)) + 0x800;
}

void apic_redirect_irq(u32 irq, u8 interrupt)
{
for (u32 i = 0; i < madt_iso_list.length; i++)
{
if (madt_iso_list.items[i]->irq_source == irq)
{
ioapic_redirect_gsi(madt_iso_list.items[i]->gsi, interrupt, madt_iso_list.items[i]->flags);
return;
}
}
ioapic_redirect_gsi(irq, interrupt, 0);
}

u32 lapic_read(u32 reg)
{
if (has_x2apic)
Expand All @@ -124,33 +54,6 @@ void lapic_write(u32 reg, u32 value)
mmio_write16(pm_get_phys_base() + lapic_addr + reg, value);
}

static void lapic_set_nmi(u8 vec, u8 current_processor_id, u8 processor_id, u16 flags, u8 lint)
{
// A value of 0xFF means all the processors
if (processor_id != 0xFF)
{
if (current_processor_id != processor_id)
return;
}

// Set to raise in vector number "vec" and set NMI flag
u32 nmi = 0x400 | vec;

// Set to active low if needed
if (flags & 2)
nmi |= 1 << 13;

// Set to level triggered if needed
if (flags & 8)
nmi |= 1 << 15;

// Use the proper LINT register
if (lint == 0)
lapic_write(0x350, nmi);
else if (lint == 1)
lapic_write(0x360, nmi);
}

void lapic_init(usize cpu_id)
{
u64 apic_msr = asm_rdmsr(0x1B);
Expand All @@ -164,6 +67,11 @@ void lapic_init(usize cpu_id)
has_x2apic = true;
apic_msr |= 1 << 10;
}
else
{
// TODO
return;
}

asm_wrmsr(0x1B, apic_msr);

Expand All @@ -176,34 +84,30 @@ void lapic_init(usize cpu_id)
lapic_write(0xD0, lapic_read(0x20));
}

// Set NMIs according to the MADT
for (usize i = 0; i < madt_nmi_list.length; i++)
{
MadtNmi* nmi = madt_nmi_list.items[i];
lapic_set_nmi(2, cpu_id, nmi->acpi_id, nmi->flags, nmi->lint);
}

// Set up APIC timer

// Tell APIC timer to divide by 16
lapic_write(0x3E0, 3);
// Set timer init counter to -1
lapic_write(0x380, 0xFFFFFFFF);

// TODO
// timer_sleep(10);
// See how much ticks pass in 10 milliseconds.
clock_wait(10 * 1000000);

// Stop the APIC timer
lapic_write(0x320, 0x10000);

// How much the APIC timer ticked in 10ms
apic_ticks_in_10ms = 0xFFFFFFFF - lapic_read(0x390);

// Make sure interrupts are off.
asm_interrupt_disable();

// Start timer as periodic on IRQ 0
lapic_write(0x320, INT_TIMER | 0x20000);
// With divider 16
lapic_write(0x3E0, 3);
lapic_write(0x380, apic_ticks_in_10ms / 10);
lapic_write(0x380, apic_ticks_in_10ms);
}

void apic_send_eoi()
Expand Down
3 changes: 1 addition & 2 deletions kernel/arch/x86_64/system/arch.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,7 @@ void arch_init_cpu(BootInfo* info, Cpu* cpu, Cpu* boot)
cpu->is_present = true;
atomic_fetch_add(&info->cpu_active, 1);

// TODO: Finish HPET impl for LAPIC calibration
// lapic_init(cpu->lapic_id);
lapic_init(cpu->lapic_id);

spin_unlock(&cpu_lock);

Expand Down
5 changes: 3 additions & 2 deletions kernel/arch/x86_64/system/arch.s
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ sch_x86_finalize:
.extern syscall_handler
.align 0x10
sc_syscall:
cli /* Disable interrupts. */
swapgs /* Change GS to kernel mode. */
movq %rsp, %gs:16 /* Save user stack to `Cpu.user_stack`. */
movq %gs:8, %rsp /* Restore kernel stack from `Cpu.kernel_stack`. */
Expand All @@ -86,7 +85,6 @@ sc_syscall:
add $0x18, %rsp /* Skip Context.error, Context.isr and Context.core fields. */
movq %gs:16, %rsp /* Load user stack from `Cpu.user_stack`. */
swapgs /* Change GS to user mode. */
sti /* Resume interrupts. */
sysretq /* Return to user mode */

/* Internal function called by one of the stubs. */
Expand All @@ -101,13 +99,15 @@ interrupt_internal:
pop_all_regs
add $0x18, %rsp /* Skip Context.error, Context.isr, and Context.core fields. */
swapgs_if_necessary /* Change GS back to user mode if we came from user mode. */
sti
iretq

/* Interrupt stub that pushes 0 as the error code. */
.macro interrupt_stub num
.global interrupt_\num
.align 0x10
interrupt_\num:
cli
swapgs_if_necessary /* Change GS to kernel mode if we're coming from user mode. */
pushq $0
pushq $\num
Expand All @@ -119,6 +119,7 @@ interrupt_\num:
.global interrupt_\num
.align 0x10
interrupt_\num:
cli
swapgs_if_necessary /* Change GS to kernel mode if we're coming from user mode. */
pushq $\num
jmp interrupt_internal
Expand Down
2 changes: 0 additions & 2 deletions kernel/arch/x86_64/system/gdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ void gdt_init()
{
// clang-format off

asm_interrupt_disable();
// Kernel Code
GDT_ENCODE(gdt_table.kernel_code,
0, 0xFFFFF,
Expand Down Expand Up @@ -60,7 +59,6 @@ void gdt_init()

gdt_reload();
tss_reload();
asm_interrupt_enable();
}

void gdt_reload()
Expand Down

0 comments on commit f605130

Please sign in to comment.