128 lines
3.2 KiB
C
128 lines
3.2 KiB
C
/*
|
|
* LAPIC
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <kassert.h>
|
|
|
|
#include "amd64.h"
|
|
#include "amd64op.h"
|
|
#include "trap.h"
|
|
|
|
#define CPUID_FLAG_APIC 0x100
|
|
|
|
#define IA32_APIC_BASE_MSR 0x1B
|
|
#define IA32_APIC_BASE_MSR_BSP 0x100
|
|
#define IA32_APIC_BASE_MSR_ENABLE 0x800
|
|
|
|
#define LAPIC_ID 0x0020 /* CPU ID */
|
|
#define LAPIC_VERSION 0x0030 /* Version */
|
|
#define LAPIC_TPR 0x0080 /* Task Priority Register */
|
|
#define LAPIC_EOI 0x00B0 /* End of Interrupt */
|
|
#define LAPIC_SIV 0x00F0 /* Spurious Interrupt Vector */
|
|
#define LAPIC_SIV_ENABLE 0x100
|
|
|
|
#define LAPIC_ESR 0x0280 /* Error Status Register */
|
|
#define LAPIC_LVT_CMCI 0x02F0 /* LVT CMCI */
|
|
#define LAPIC_LVT_TIMER 0x0320 /* LVT Timer */
|
|
#define LAPIC_LVT_TIMER_ONESHOT 0x00000000
|
|
#define LAPIC_LVT_TIMER_PERIODIC 0x00020000
|
|
#define LAPIC_LVT_TIMER_TSCDEADLINE 0x00040000
|
|
#define LAPIC_LVT_THERMAL 0x0330 /* LVT Thermal Sensor */
|
|
#define LAPIC_LVT_PMCR 0x0340 /* LVT Performance Monitoring Counter */
|
|
#define LAPIC_LVT_LINT0 0x0350 /* LVT LINT0 */
|
|
#define LAPIC_LVT_LINT1 0x0360 /* LVT LINT1 */
|
|
#define LAPIC_LVT_ERROR 0x0370 /* LVT Error */
|
|
#define LAPIC_LVT_FLAG_MASKED 0x00010000 /* Masked */
|
|
|
|
#define LAPIC_TICR 0x0380 /* Timer Initial Count Register */
|
|
#define LAPIC_TCCR 0x0390 /* Timer Currnet Count Register */
|
|
#define LAPIC_TDCR 0x03E0 /* Time Divide Configuration Register */
|
|
#define LAPIC_TDCR_X1 0x000B /* Divide counts by 1 */
|
|
|
|
static uint32_t *
|
|
LAPIC_GetBase()
|
|
{
|
|
uint64_t base = rdmsr(IA32_APIC_BASE_MSR) & 0xFFFFFFFFFFFFF000ULL;
|
|
|
|
return (uint32_t *)base;
|
|
}
|
|
|
|
uint32_t
|
|
LAPIC_Read(uint16_t reg)
|
|
{
|
|
uint32_t volatile *lapic = (uint32_t volatile *) LAPIC_GetBase();
|
|
|
|
return lapic[reg >> 2];
|
|
}
|
|
|
|
void
|
|
LAPIC_Write(uint16_t reg, uint32_t val)
|
|
{
|
|
uint32_t volatile *lapic = (uint32_t volatile *)LAPIC_GetBase();
|
|
|
|
lapic[reg >> 2] = val;
|
|
lapic[LAPIC_ID >> 2];
|
|
}
|
|
|
|
uint32_t
|
|
LAPIC_CPU()
|
|
{
|
|
return LAPIC_Read(LAPIC_ID) >> 24;
|
|
}
|
|
|
|
void
|
|
LAPIC_SendEOI()
|
|
{
|
|
LAPIC_Write(LAPIC_EOI, 0);
|
|
}
|
|
|
|
void
|
|
LAPIC_Periodic(uint64_t rate)
|
|
{
|
|
LAPIC_Write(LAPIC_TDCR, LAPIC_TDCR_X1);
|
|
LAPIC_Write(LAPIC_LVT_TIMER, LAPIC_LVT_TIMER_PERIODIC | T_IRQ_TIMER);
|
|
LAPIC_Write(LAPIC_TICR, rate);
|
|
}
|
|
|
|
void
|
|
LAPIC_Init()
|
|
{
|
|
uint32_t edx;
|
|
uint64_t base;
|
|
|
|
cpuid(1, NULL, NULL, NULL, &edx);
|
|
if ((edx & CPUID_FLAG_APIC) == 0)
|
|
Panic("APIC is required!\n");
|
|
|
|
// Enable LAPIC
|
|
base = rdmsr(IA32_APIC_BASE_MSR);
|
|
wrmsr(IA32_APIC_BASE_MSR, base | IA32_APIC_BASE_MSR_ENABLE);
|
|
|
|
kprintf("LAPIC: CPU %d found at 0x%016llx\n", LAPIC_CPU(), base);
|
|
|
|
// Enable interrupts
|
|
LAPIC_Write(LAPIC_SIV, LAPIC_SIV_ENABLE | T_IRQ_SPURIOUS);
|
|
|
|
// Clear any remaining errors
|
|
LAPIC_Write(LAPIC_ESR, 0);
|
|
|
|
// Enable error and thermal interrupts
|
|
LAPIC_Write(LAPIC_LVT_ERROR, T_IRQ_ERROR);
|
|
LAPIC_Write(LAPIC_LVT_THERMAL, T_IRQ_THERMAL);
|
|
|
|
// Disable LINT0/1, PMC
|
|
LAPIC_Write(LAPIC_LVT_LINT0, LAPIC_LVT_FLAG_MASKED);
|
|
LAPIC_Write(LAPIC_LVT_LINT1, LAPIC_LVT_FLAG_MASKED);
|
|
LAPIC_Write(LAPIC_LVT_PMCR, LAPIC_LVT_FLAG_MASKED);
|
|
|
|
LAPIC_Periodic(10000000);
|
|
|
|
LAPIC_SendEOI();
|
|
|
|
LAPIC_Write(LAPIC_TPR, 0);
|
|
}
|
|
|
|
|
|
|