Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Local APIC timer #110

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions include/kernel/infrastructure/i686/drivers/asm/lapic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* Copyright (C) 2025 Philippe Aubertin.
* All rights reserved.

* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the author nor the names of other contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef JINUE_KERNEL_INFRASTRUCTURE_I686_DRIVERS_ASM_LAPIC_H
#define JINUE_KERNEL_INFRASTRUCTURE_I686_DRIVERS_ASM_LAPIC_H

#define APIC_REG_ID 0x20

#define APIC_REG_VERSION 0x30

#define APIC_REG_TPR 0x80

#define APIC_REG_APR 0x90

#define APIC_REG_PPR 0xa0

#define APIC_REG_EOI 0xb0

#define APIC_REG_RRD 0xc0

#define APIC_REG_LOGICAL_DEST 0xd0

#define APIC_REG_DEST_FORMAT 0xe0

#define APIC_REG_SPURIOUS_VECT 0xf0

#define APIC_REG_ISR 0x100

#define APIC_REG_TMR 0x180

#define APIC_REG_IRR 0x200

#define APIC_REG_ERROR_STATUS 0x280

#define APIC_REG_LVT_CMCI 0x2f0

#define APIC_REG_LVT_TIMER 0x320

#define APIC_REG_LVT_THERMAL 0x330

#define APIC_REG_LVT_PERF_MON 0x340

#define APIC_REG_LVT_LINT0 0x350

#define APIC_REG_LVT_LINT1 0x360

#define APIC_REG_LVT_ERROR 0x370

#define APIC_REG_INITIAL_COUNT 0x380

#define APIC_REG_CURRENT_COUNT 0x390

#define APIC_REG_DIVIDE_CONF 0x3e0


#define APIC_LVT_DELIVERY_FIXED 0

#define APIC_LVT_DELIVERY_SMI 0x200

#define APIC_LVT_DELIVERY_NMI 0x400

#define APIC_LVT_DELIVERY_INIT 0x600

#define APIC_LVT_DELIVERY_EXTINT 0x700


#define APIC_LVT_PENDING (1 << 12)

#define APIC_LVT_POLARITY_HIGH 0

#define APIC_LVT_POLARITY_LOW (1 << 13)

#define APIC_LVT_TRIGGER_EDGE 0

#define APIC_LVT_TRIGGER_LEVEL (1 << 15)

#define APIC_LVT_MASKED (1 << 16)

#define APIC_LVT_TIMER_ONE_SHOT 0

#define APIC_LVT_TIMER_PERIODIC (1 << 17)

#define APIC_LVT_TIMER_TSC_DEADLINE (2 << 17)


#define APIC_SVR_ENABLED 0

#define APIC_SVR_DISABLED (1 << 8)

#endif
41 changes: 41 additions & 0 deletions include/kernel/infrastructure/i686/drivers/lapic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2025 Philippe Aubertin.
* All rights reserved.

* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the author nor the names of other contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef JINUE_KERNEL_INFRASTRUCTURE_I686_DRIVERS_LAPIC_H
#define JINUE_KERNEL_INFRASTRUCTURE_I686_DRIVERS_LAPIC_H

#include <kernel/infrastructure/i686/drivers/asm/lapic.h>

void local_apic_init(void);

void local_apic_eoi(void);

#endif
8 changes: 8 additions & 0 deletions include/kernel/interface/i686/asm/idt.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,12 @@

#define IDT_PIC8259_BASE (IDT_LAST_EXCEPTION + 1)

#define IDT_APIC_TIMER 0xfe

/**
* spurious interrupt vector for local APIC
* Bits 3..0 must be 1 for compatibility with Pentium and P6 processors.
*/
#define IDT_APIC_SPURIOUS 0xff

#endif
1 change: 1 addition & 0 deletions kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ sources.kernel.c = \
domain/services/scheduler.c \
domain/config.c \
infrastructure/acpi/acpi.c \
infrastructure/i686/drivers/lapic.c \
infrastructure/i686/drivers/pic8259.c \
infrastructure/i686/drivers/pit8253.c \
infrastructure/i686/drivers/uart16550a.c \
Expand Down
107 changes: 107 additions & 0 deletions kernel/infrastructure/i686/drivers/lapic.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Copyright (C) 2025 Philippe Aubertin.
* All rights reserved.

* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the author nor the names of other contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <jinue/shared/asm/mman.h>
#include <kernel/application/asm/ticks.h>
#include <kernel/domain/services/mman.h>
#include <kernel/infrastructure/i686/drivers/lapic.h>
#include <kernel/infrastructure/i686/cpuinfo.h>
#include <kernel/interface/i686/asm/idt.h>
#include <kernel/types.h>
#include <stdbool.h>

static void *mmio_addr;

static void set_register(int offset, uint32_t value) {
uint32_t *reg = (uint32_t *)((addr_t)mmio_addr + offset);
*reg = value;
}

static void set_divider(int divider) {
uint32_t value;

switch(divider) {
case 128:
value = 0xa;
break;
case 64:
value = 9;
break;
case 32:
value = 8;
break;
case 16:
value = 3;
break;
case 8:
value = 2;
break;
case 4:
value = 1;
break;
case 2:
value = 0;
break;
case 1:
default:
value = 0xb;
}

set_register(APIC_REG_DIVIDE_CONF, value);
}

void local_apic_init(void) {
if(!cpu_has_feature(CPUINFO_FEATURE_LOCAL_APIC)) {
return;
}

// TODO figure out address from firmware table or MSR
// TODO some APICs are controlled through MSRs instead of MMIO?
// TODO ensure caheability attributes are appropriate (MTRRs?)
mmio_addr = map_in_kernel(0xfee00000, 4096, JINUE_PROT_READ | JINUE_PROT_WRITE);

/* TODO get frequency from CPUID and/or MSRs and/or calibrate
*
* This is QEMU's hardcoded frequency */
const uint32_t clock_freq_hz = 1000000000;
const uint32_t initial_count = (clock_freq_hz / TICKS_PER_SECOND) - 1;

/* Configure and start timer. */
set_divider(1);
set_register(APIC_REG_INITIAL_COUNT, initial_count);

set_register(APIC_REG_LVT_TIMER, APIC_LVT_TIMER_PERIODIC | IDT_APIC_TIMER);
set_register(APIC_REG_SPURIOUS_VECT, APIC_SVR_ENABLED | IDT_APIC_SPURIOUS);
}

void local_apic_eoi(void) {
set_register(APIC_REG_EOI, 0);
}
1 change: 0 additions & 1 deletion kernel/infrastructure/i686/drivers/pit8253.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
#include <kernel/infrastructure/i686/drivers/iodelay.h>
#include <kernel/infrastructure/i686/drivers/pit8253.h>
#include <kernel/infrastructure/i686/isa/io.h>
#include <kernel/infrastructure/i686/isa/io.h>
#include <kernel/utils/utils.h>

void pit8253_init(void) {
Expand Down
9 changes: 8 additions & 1 deletion kernel/infrastructure/i686/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <kernel/domain/services/mman.h>
#include <kernel/domain/services/panic.h>
#include <kernel/infrastructure/i686/asm/msr.h>
#include <kernel/infrastructure/i686/drivers/lapic.h>
#include <kernel/infrastructure/i686/drivers/pic8259.h>
#include <kernel/infrastructure/i686/drivers/pit8253.h>
#include <kernel/infrastructure/i686/drivers/uart16550a.h>
Expand Down Expand Up @@ -386,7 +387,13 @@ void machine_init(const config_t *config) {
* Interrupts are disabled during initialization so the CPU won't actually
* be interrupted until the first user space thread starts. */
pit8253_init();
pic8259_unmask(IRQ_TIMER);

if(!cpu_has_feature(CPUINFO_FEATURE_LOCAL_APIC)) {
pic8259_unmask(IRQ_TIMER);
}

/* Initializa local APIC, including local APIC timer. */
local_apic_init();

/* choose a system call implementation */
select_syscall_implementation();
Expand Down
6 changes: 6 additions & 0 deletions kernel/interface/i686/interrupts.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <kernel/application/interrupts.h>
#include <kernel/domain/services/logging.h>
#include <kernel/domain/services/panic.h>
#include <kernel/infrastructure/i686/drivers/lapic.h>
#include <kernel/infrastructure/i686/drivers/pic8259.h>
#include <kernel/infrastructure/i686/isa/regs.h>
#include <kernel/interface/i686/asm/exceptions.h>
Expand Down Expand Up @@ -82,6 +83,11 @@ void handle_interrupt(trapframe_t *trapframe) {

if(ivt <= IDT_LAST_EXCEPTION) {
handle_exception(ivt, trapframe->eip, trapframe->errcode);
} else if(ivt == IDT_APIC_TIMER) {
tick_interrupt();
local_apic_eoi();
} else if(ivt == IDT_APIC_SPURIOUS) {
spurious_interrupt();
} else if(ivt >= IDT_PIC8259_BASE && ivt < IDT_PIC8259_BASE + PIC8259_IRQ_COUNT) {
handle_hardware_interrupt(ivt);
} else {
Expand Down
Loading