Skip to content

Commit

Permalink
apic: add apic timer
Browse files Browse the repository at this point in the history
Add APIC LVT timer

Signed-off-by: Daniele Ahmed <ahmeddan amazon   com; >
  • Loading branch information
82marbag authored and wipawel committed Nov 15, 2020
1 parent 5d27384 commit d9731ff
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 6 deletions.
58 changes: 58 additions & 0 deletions arch/x86/apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,16 @@
*/
#include <apic.h>
#include <console.h>
#include <drivers/pit.h>
#include <ktf.h>
#include <lib.h>
#include <percpu.h>
#include <processor.h>
#include <traps.h>

static apic_mode_t apic_mode = APIC_MODE_UNKNOWN;
static volatile uint64_t ticks = 0;
static bool apic_timer_enabled;

static const char *apic_mode_names[] = {
/* clang-format off */
Expand Down Expand Up @@ -155,3 +159,57 @@ void init_apic(unsigned int cpu, apic_mode_t mode) {
spiv.apic_enable = 1;
apic_write(APIC_SPIV, spiv.reg);
}

void init_apic_timer(void) {
ASSERT(apic_get_mode() >= APIC_MODE_XAPIC);
uint32_t min_ticks = _U32(-1);
int i;

apic_lvt_timer_t timer;
printk("Initializing local APIC timer\n");

/* Spend 1s calibrating the timer, 10 iterations of 100ms each */
for (i = 0; i < 10; ++i) {
/* Set the counter to the max value (0xFFFFFFFF) */
apic_write(APIC_TMR_DCR, APIC_TIMER_DIVIDE_BY_16);
apic_write(APIC_TMR_ICR, _U32(-1));

/* One shot mode to see how many ticks over 100ms */
timer.timer_mode = APIC_LVT_TIMER_ONE_SHOT;
apic_write(APIC_LVT_TIMER, timer.reg);

/* Sleep for 100ms to calibrate, count the ticks */
pit_sleep(100);

/* Calibrate */
uint32_t elapsed_ticks = (_U32(-1) - apic_read(APIC_TMR_CCR)) / 100;
min_ticks = min(min_ticks, elapsed_ticks);
}

/* Interrupt every min_ticks ticks */
apic_write(APIC_TMR_DCR, APIC_TIMER_DIVIDE_BY_16);
apic_write(APIC_TMR_ICR, min_ticks);

/* Switch to periodic mode */
timer.vector = APIC_TIMER_IRQ_OFFSET;
timer.timer_mode = APIC_LVT_TIMER_PERIODIC;
apic_write(APIC_LVT_TIMER, timer.reg);

apic_timer_enabled = true;
pit_disable();
}

bool is_apic_timer_enabled(void) { return apic_timer_enabled; }

void apic_timer_interrupt_handler(void) {
++ticks;
apic_EOI();
}

void apic_timer_sleep(uint64_t ms) {
BUG_ON(!is_apic_timer_enabled());
uint64_t end = ticks + ms;
while (ticks < end) {
cpu_relax();
}
}
1 change: 1 addition & 0 deletions arch/x86/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ END_FUNC(handle_exception)
interrupt_handler pit pit_interrupt_handler
interrupt_handler uart uart_interrupt_handler
interrupt_handler keyboard keyboard_interrupt_handler
interrupt_handler apic_timer apic_timer_interrupt_handler

ENTRY(usermode_call_asm)
/* FIXME: Add 32-bit support */
Expand Down
4 changes: 4 additions & 0 deletions arch/x86/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
* (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 <apic.h>
#include <console.h>
#include <drivers/keyboard.h>
#include <drivers/pit.h>
Expand All @@ -42,6 +43,7 @@
extern void asm_interrupt_handler_uart(void);
extern void asm_interrupt_handler_pit(void);
extern void asm_interrupt_handler_keyboard(void);
extern void asm_interrupt_handler_apic_timer(void);

static void ret2kern_handler(void) {
/* clang-format off */
Expand Down Expand Up @@ -164,6 +166,8 @@ void init_traps(unsigned int cpu) {
_ul(asm_interrupt_handler_pit), GATE_DPL0, GATE_PRESENT, 0);
set_intr_gate(&percpu->idt[KEYBOARD_PORT1_IRQ0_OFFSET], __KERN_CS,
_ul(asm_interrupt_handler_keyboard), GATE_DPL0, GATE_PRESENT, 0);
set_intr_gate(&percpu->idt[APIC_TIMER_IRQ_OFFSET], __KERN_CS,
_ul(asm_interrupt_handler_apic_timer), GATE_DPL0, GATE_PRESENT, 0);

barrier();
lidt(&percpu->idt_ptr);
Expand Down
3 changes: 2 additions & 1 deletion common/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,9 @@ void __noreturn __text_init kernel_start(uint32_t multiboot_magic,
/* Initialize console input */
uart_input_init(get_bsp_cpu_id());

/* Initialize Programmable Interrupt Timer */
/* Initialize timers */
init_pit(get_bsp_cpu_id());
init_apic_timer();

/* Initialize keyboard */
init_keyboard(get_bsp_cpu_id());
Expand Down
18 changes: 13 additions & 5 deletions include/arch/x86/apic.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,14 @@
#ifndef KTF_APIC_H
#define KTF_APIC_H

#include <drivers/pic.h>
#include <ktf.h>
#include <lib.h>
#include <page.h>

#define APIC_IRQ_BASE PIC_IRQ_END_OFFSET
#define APIC_TIMER_IRQ_OFFSET (APIC_IRQ_BASE + 0x00)

#define MSR_X2APIC_REGS 0x800U

#ifndef __ASSEMBLY__
Expand Down Expand Up @@ -83,7 +87,7 @@ enum xapic_regs {
APIC_LVT_LINT1 = 0x360, /* LVT LINT1 Register */
APIC_LVT_ERROR = 0x370, /* LVT Error Register */
APIC_TMR_ICR = 0x380, /* Timer Initial Count Register */
APIC_TMR_CCR = 0x380, /* Timer Current Count Register */
APIC_TMR_CCR = 0x390, /* Timer Current Count Register */

APIC_TMR_DCR = 0x3e0, /* Timer Divide Configuration Register */

Expand Down Expand Up @@ -304,12 +308,12 @@ typedef union apic_esr apic_esr_t;

enum apic_timer_divide {
APIC_TIMER_DIVIDE_BY_2 = 0x00,
APIC_TIMER_DIVIDE_BY_4 = 0x08,
APIC_TIMER_DIVIDE_BY_4 = 0x01,
APIC_TIMER_DIVIDE_BY_8 = 0x02,
APIC_TIMER_DIVIDE_BY_16 = 0x0a,
APIC_TIMER_DIVIDE_BY_32 = 0x01,
APIC_TIMER_DIVIDE_BY_16 = 0x03,
APIC_TIMER_DIVIDE_BY_32 = 0x08,
APIC_TIMER_DIVIDE_BY_64 = 0x09,
APIC_TIMER_DIVIDE_BY_128 = 0x03,
APIC_TIMER_DIVIDE_BY_128 = 0x0a,
APIC_TIMER_DIVIDE_BY_1 = 0x0b,
};
typedef enum apic_timer_divide apic_timer_divide_t;
Expand Down Expand Up @@ -457,6 +461,10 @@ extern void init_apic(unsigned int cpu, apic_mode_t mode);
extern apic_icr_t apic_icr_read(void);
extern void apic_icr_write(const apic_icr_t *icr);

extern void init_apic_timer(void);
extern void apic_timer_sleep(uint64_t ms);
extern bool is_apic_timer_enabled(void);

/* Static declarations */

static inline xapic_regs_t xapic_reg(x2apic_regs_t reg) {
Expand Down

0 comments on commit d9731ff

Please sign in to comment.