mirror of
https://github.com/Fennix-Project/Kernel.git
synced 2025-07-11 15:29:18 +00:00
Added APIC & SMP stub
This commit is contained in:
@ -7,7 +7,7 @@ namespace ACPI
|
||||
{
|
||||
MADT::MADT(ACPI::MADTHeader *madt)
|
||||
{
|
||||
LAPICAddr = (LAPIC *)(uintptr_t)madt->LocalControllerAddress;
|
||||
LAPICAddress = (LAPIC *)(uintptr_t)madt->LocalControllerAddress;
|
||||
for (uint8_t *ptr = (uint8_t *)(madt->Entries);
|
||||
(uintptr_t)(ptr) < (uintptr_t)(madt) + madt->Header.Length;
|
||||
ptr += *(ptr + 1))
|
||||
@ -27,8 +27,8 @@ namespace ACPI
|
||||
case 1:
|
||||
{
|
||||
ioapic.push_back((MADTIOApic *)ptr);
|
||||
trace("I/O APIC %#llx (Address %#llx) found.", ioapic.back()->APICID, ioapic.back()->addr);
|
||||
Memory::Virtual().Map((void *)(uintptr_t)ioapic.back()->addr, (void *)(uintptr_t)ioapic.back()->addr, Memory::PTFlag::RW | Memory::PTFlag::PCD); // Make sure that the address is mapped.
|
||||
trace("I/O APIC %#llx (Address %#llx) found.", ioapic.back()->APICID, ioapic.back()->Address);
|
||||
Memory::Virtual().Map((void *)(uintptr_t)ioapic.back()->Address, (void *)(uintptr_t)ioapic.back()->Address, Memory::PTFlag::RW | Memory::PTFlag::PCD); // Make sure that the address is mapped.
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
@ -48,12 +48,12 @@ namespace ACPI
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
LAPICAddr = (LAPIC *)ptr;
|
||||
trace("APIC found at %#llx", LAPICAddr);
|
||||
LAPICAddress = (LAPIC *)ptr;
|
||||
trace("APIC found at %#llx", LAPICAddress);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Memory::Virtual().Map((void *)LAPICAddr, (void *)LAPICAddr, Memory::PTFlag::RW | Memory::PTFlag::PCD); // I should map more than one page?
|
||||
Memory::Virtual().Map((void *)LAPICAddress, (void *)LAPICAddress, Memory::PTFlag::RW | Memory::PTFlag::PCD); // I should map more than one page?
|
||||
}
|
||||
trace("Total CPU cores: %d", CPUCores);
|
||||
}
|
||||
|
@ -199,8 +199,8 @@ namespace ACPI
|
||||
struct APICHeader Header;
|
||||
uint8_t APICID;
|
||||
uint8_t reserved;
|
||||
uint32_t addr;
|
||||
uint32_t gsib;
|
||||
uint32_t Address;
|
||||
uint32_t GSIBase;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct MADTIso
|
||||
@ -239,7 +239,7 @@ namespace ACPI
|
||||
Vector<MADTIso *> iso;
|
||||
Vector<MADTNmi *> nmi;
|
||||
Vector<LocalAPIC *> lapic;
|
||||
struct LAPIC *LAPICAddr;
|
||||
struct LAPIC *LAPICAddress;
|
||||
uint8_t CPUCores;
|
||||
|
||||
MADT(ACPI::MADTHeader *madt);
|
||||
|
@ -0,0 +1,202 @@
|
||||
#include "apic.hpp"
|
||||
|
||||
#include <cpu.hpp>
|
||||
#include <smp.hpp>
|
||||
|
||||
#include "../../../kernel.h"
|
||||
#include "../acpi.hpp"
|
||||
|
||||
namespace APIC
|
||||
{
|
||||
enum IOAPICRegisters
|
||||
{
|
||||
GetIOAPICVersion = 0x1
|
||||
};
|
||||
|
||||
enum IOAPICFlags
|
||||
{
|
||||
ActiveHighLow = 2,
|
||||
EdgeLevel = 8
|
||||
};
|
||||
|
||||
struct IOAPICVersion
|
||||
{
|
||||
uint8_t Version;
|
||||
uint8_t Reserved;
|
||||
uint8_t MaximumRedirectionEntry;
|
||||
uint8_t Reserved2;
|
||||
};
|
||||
|
||||
// headache
|
||||
// https://www.amd.com/system/files/TechDocs/24593.pdf
|
||||
// https://www.naic.edu/~phil/software/intel/318148.pdf
|
||||
|
||||
uint32_t APIC::Read(uint32_t Register)
|
||||
{
|
||||
// Too repetitive
|
||||
if (Register != APIC_EOI &&
|
||||
Register != APIC_ID &&
|
||||
Register != APIC_TIMER &&
|
||||
Register != APIC_TDCR &&
|
||||
Register != APIC_TICR &&
|
||||
Register != APIC_TCCR)
|
||||
debug("APIC::Read(%#lx)", Register);
|
||||
if (x2APICSupported)
|
||||
{
|
||||
if (Register != APIC_ICRHI)
|
||||
return CPU::x64::rdmsr((Register >> 4) + 0x800);
|
||||
else
|
||||
return CPU::x64::rdmsr(0x30 + 0x800);
|
||||
}
|
||||
else
|
||||
return *((volatile uint32_t *)((uintptr_t)((ACPI::MADT *)PowerManager->GetMADT())->LAPICAddress + Register));
|
||||
}
|
||||
|
||||
void APIC::Write(uint32_t Register, uint32_t Value)
|
||||
{
|
||||
// Too repetitive
|
||||
if (Register != APIC_EOI &&
|
||||
Register != APIC_TIMER &&
|
||||
Register != APIC_TDCR &&
|
||||
Register != APIC_TICR &&
|
||||
Register != APIC_TCCR)
|
||||
debug("APIC::Write(%#lx, %#lx)", Register, Value);
|
||||
if (x2APICSupported)
|
||||
{
|
||||
if (Register != APIC_ICRHI)
|
||||
CPU::x64::wrmsr((Register >> 4) + 0x800, Value);
|
||||
else
|
||||
CPU::x64::wrmsr(CPU::x64::MSR_X2APIC_ICR, Value);
|
||||
}
|
||||
else
|
||||
*((volatile uint32_t *)(((uintptr_t)((ACPI::MADT *)PowerManager->GetMADT())->LAPICAddress) + Register)) = Value;
|
||||
}
|
||||
|
||||
void APIC::IOWrite(uint64_t Base, uint32_t Register, uint32_t Value)
|
||||
{
|
||||
debug("APIC::IOWrite(%#lx, %#lx, %#lx)", Base, Register, Value);
|
||||
*((volatile uint32_t *)(((uintptr_t)Base))) = Register;
|
||||
*((volatile uint32_t *)(((uintptr_t)Base + 16))) = Value;
|
||||
}
|
||||
|
||||
uint32_t APIC::IORead(uint64_t Base, uint32_t Register)
|
||||
{
|
||||
debug("APIC::IORead(%#lx, %#lx)", Base, Register);
|
||||
*((volatile uint32_t *)(((uintptr_t)Base))) = Register;
|
||||
return *((volatile uint32_t *)(((uintptr_t)Base + 16)));
|
||||
}
|
||||
|
||||
void APIC::EOI() { this->Write(APIC_EOI, 0); }
|
||||
|
||||
void APIC::RedirectIRQs(int CPU)
|
||||
{
|
||||
debug("Redirecting IRQs...");
|
||||
for (int i = 0; i < 16; i++)
|
||||
this->RedirectIRQ(CPU, i, 1);
|
||||
debug("Redirecting IRQs completed.");
|
||||
}
|
||||
|
||||
void APIC::IPI(uint8_t CPU, uint32_t InterruptNumber)
|
||||
{
|
||||
if (x2APICSupported)
|
||||
{
|
||||
CPU::x64::wrmsr(CPU::x64::MSR_X2APIC_ICR, ((uint64_t)CPU) << 32 | InterruptNumber);
|
||||
}
|
||||
else
|
||||
{
|
||||
InterruptNumber = (1 << 14) | InterruptNumber;
|
||||
this->Write(APIC_ICRHI, (CPU << 24));
|
||||
this->Write(APIC_ICRLO, InterruptNumber);
|
||||
}
|
||||
}
|
||||
|
||||
void APIC::OneShot(uint32_t Vector, uint64_t Miliseconds)
|
||||
{
|
||||
int apic_timer_ticks = 0;
|
||||
fixme("APIC::OneShot(%#lx, %#lx)", Vector, Miliseconds);
|
||||
this->Write(APIC_TDCR, 0x03);
|
||||
this->Write(APIC_TIMER, (APIC::APIC::APICRegisters::APIC_ONESHOT | Vector));
|
||||
this->Write(APIC_TICR, apic_timer_ticks * Miliseconds);
|
||||
}
|
||||
|
||||
uint32_t APIC::IOGetMaxRedirect(uint32_t APICID)
|
||||
{
|
||||
uint32_t TableAddress = (this->IORead((((ACPI::MADT *)PowerManager->GetMADT())->ioapic[APICID]->Address), GetIOAPICVersion));
|
||||
return ((IOAPICVersion *)&TableAddress)->MaximumRedirectionEntry;
|
||||
}
|
||||
|
||||
void APIC::RawRedirectIRQ(uint8_t Vector, uint32_t GSI, uint16_t Flags, int CPU, int Status)
|
||||
{
|
||||
uint64_t Value = Vector;
|
||||
|
||||
int64_t IOAPICTarget = -1;
|
||||
for (uint64_t i = 0; ((ACPI::MADT *)PowerManager->GetMADT())->ioapic[i] != 0; i++)
|
||||
if (((ACPI::MADT *)PowerManager->GetMADT())->ioapic[i]->GSIBase <= GSI)
|
||||
if (((ACPI::MADT *)PowerManager->GetMADT())->ioapic[i]->GSIBase + IOGetMaxRedirect(i) > GSI)
|
||||
{
|
||||
IOAPICTarget = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (IOAPICTarget == -1)
|
||||
{
|
||||
error("No ISO table found for I/O APIC");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Flags & ActiveHighLow)
|
||||
Value |= (1 << 13);
|
||||
|
||||
if (Flags & EdgeLevel)
|
||||
Value |= (1 << 15);
|
||||
|
||||
if (!Status)
|
||||
Value |= (1 << 16);
|
||||
|
||||
Value |= (((uintptr_t)GetCPU(CPU)->Data->LAPIC.APICId) << 56);
|
||||
uint32_t IORegister = (GSI - ((ACPI::MADT *)PowerManager->GetMADT())->ioapic[IOAPICTarget]->GSIBase) * 2 + 16;
|
||||
|
||||
this->IOWrite(((ACPI::MADT *)PowerManager->GetMADT())->ioapic[IOAPICTarget]->Address, IORegister, (uint32_t)Value);
|
||||
this->IOWrite(((ACPI::MADT *)PowerManager->GetMADT())->ioapic[IOAPICTarget]->Address, IORegister + 1, (uint32_t)(Value >> 32));
|
||||
}
|
||||
|
||||
void APIC::RedirectIRQ(int CPU, uint8_t IRQ, int Status)
|
||||
{
|
||||
for (uint64_t i = 0; i < ((ACPI::MADT *)PowerManager->GetMADT())->iso.size(); i++)
|
||||
if (((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->IRQSource == IRQ)
|
||||
{
|
||||
debug("[ISO %d] Mapping to source IRQ%#d GSI:%#lx on CPU %d",
|
||||
i, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->IRQSource, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->GSI, CPU);
|
||||
|
||||
this->RawRedirectIRQ(((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->IRQSource + 0x20, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->GSI, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->Flags, CPU, Status);
|
||||
return;
|
||||
}
|
||||
debug("Mapping IRQ%d on CPU %d", IRQ, CPU);
|
||||
this->RawRedirectIRQ(IRQ + 0x20, IRQ, 0, CPU, Status);
|
||||
}
|
||||
|
||||
APIC::APIC()
|
||||
{
|
||||
uint32_t rcx;
|
||||
CPU::x64::cpuid(1, 0, 0, &rcx, 0);
|
||||
if (rcx & CPU::x64::CPUID_FEAT_RCX_x2APIC)
|
||||
{
|
||||
// this->x2APICSupported = true;
|
||||
warn("x2APIC not supported yet.");
|
||||
// CPU::x64::wrmsr(CPU::x64::MSR_APIC_BASE, (CPU::x64::rdmsr(CPU::x64::MSR_APIC_BASE) | (1 << 11)) & ~(1 << 10));
|
||||
CPU::x64::wrmsr(CPU::x64::MSR_APIC_BASE, CPU::x64::rdmsr(CPU::x64::MSR_APIC_BASE) | (1 << 11));
|
||||
}
|
||||
else
|
||||
{
|
||||
CPU::x64::wrmsr(CPU::x64::MSR_APIC_BASE, CPU::x64::rdmsr(CPU::x64::MSR_APIC_BASE) | (1 << 11));
|
||||
}
|
||||
trace("APIC Address: %#lx", CPU::x64::rdmsr(CPU::x64::MSR_APIC_BASE));
|
||||
|
||||
this->Write(APIC_TPR, 0x0);
|
||||
this->Write(APIC_SVR, this->Read(APIC_SVR) | 0x100); // 0x1FF or 0x100 ? on https://wiki.osdev.org/APIC is 0x100
|
||||
}
|
||||
|
||||
APIC::~APIC()
|
||||
{
|
||||
}
|
||||
}
|
113
Architecture/amd64/cpu/SMPTrampoline.asm
Normal file
113
Architecture/amd64/cpu/SMPTrampoline.asm
Normal file
@ -0,0 +1,113 @@
|
||||
[bits 16]
|
||||
TRAMPOLINE_BASE equ 0x2000
|
||||
|
||||
extern StartCPU
|
||||
global _trampoline_start
|
||||
_trampoline_start:
|
||||
cli
|
||||
mov ax, 0x0
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
mov ss, ax
|
||||
o32 lgdt [ProtectedMode_gdtr - _trampoline_start + TRAMPOLINE_BASE]
|
||||
mov eax, cr0
|
||||
or al, 0x1
|
||||
mov cr0, eax
|
||||
jmp 0x8:(Trampoline32 - _trampoline_start + TRAMPOLINE_BASE)
|
||||
|
||||
[bits 32]
|
||||
section .text
|
||||
Trampoline32:
|
||||
mov bx, 0x10
|
||||
mov ds, bx
|
||||
mov es, bx
|
||||
mov ss, bx
|
||||
mov eax, dword [0x500]
|
||||
mov cr3, eax
|
||||
mov eax, cr4
|
||||
or eax, 1 << 5 ; Set the PAE-bit, which is the 6th bit (bit 5).
|
||||
or eax, 1 << 7
|
||||
mov cr4, eax
|
||||
mov ecx, 0xc0000080
|
||||
rdmsr
|
||||
or eax,1 << 8 ; LME
|
||||
wrmsr
|
||||
mov eax, cr0
|
||||
or eax, 1 << 31
|
||||
mov cr0, eax
|
||||
lgdt [LongMode_gdtr - _trampoline_start + TRAMPOLINE_BASE]
|
||||
jmp 0x8:(Trampoline64 - _trampoline_start + TRAMPOLINE_BASE)
|
||||
|
||||
[bits 64]
|
||||
Trampoline64:
|
||||
mov ax, 0x10
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov ss, ax
|
||||
mov ax, 0x0
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
lgdt [0x580]
|
||||
lidt [0x590]
|
||||
mov rsp, [0x570]
|
||||
mov rbp, 0x0 ; Terminate stack traces here.
|
||||
; Reset RFLAGS.
|
||||
push 0x0
|
||||
popf
|
||||
mov rax, qword vcode64
|
||||
call vcode64
|
||||
|
||||
vcode64:
|
||||
push rbp
|
||||
; Set up SSE
|
||||
mov rax, cr0
|
||||
; btr eax, 2
|
||||
; bts eax, 1
|
||||
; mov cr0, rax
|
||||
mov rax, cr4
|
||||
bts eax, 9
|
||||
bts eax, 10
|
||||
mov cr4, rax
|
||||
mov rax, qword TrampolineExit
|
||||
call rax
|
||||
|
||||
align 16
|
||||
LongMode_gdtr:
|
||||
dw LongModeGDTEnd - LongModeGDTStart - 1
|
||||
dq LongModeGDTStart - _trampoline_start + TRAMPOLINE_BASE
|
||||
|
||||
align 16
|
||||
LongModeGDTStart:
|
||||
dq 0 ; NULL segment
|
||||
dq 0x00AF98000000FFFF ; Code segment
|
||||
dq 0x00CF92000000FFFF ; Data segment
|
||||
LongModeGDTEnd:
|
||||
|
||||
align 16
|
||||
ProtectedMode_gdtr:
|
||||
dw ProtectedModeGDTEnd - ProtectedModeGDTStart - 1
|
||||
dd ProtectedModeGDTStart - _trampoline_start + TRAMPOLINE_BASE
|
||||
|
||||
align 16
|
||||
ProtectedModeGDTStart:
|
||||
dq 0 ; NULL segment
|
||||
dq 0x00CF9A000000FFFF ; Code segment
|
||||
dq 0x00CF92000000FFFF ; Data segment
|
||||
ProtectedModeGDTEnd:
|
||||
|
||||
align 16
|
||||
ProtectedMode_idtr:
|
||||
dw 0
|
||||
dd 0
|
||||
dd 0
|
||||
align 16
|
||||
|
||||
global _trampoline_end
|
||||
_trampoline_end:
|
||||
|
||||
TrampolineExit:
|
||||
call StartCPU
|
||||
|
||||
times 512 - ($-$$) db 0
|
26
Architecture/amd64/cpu/SymmetricMultiprocessing.cpp
Normal file
26
Architecture/amd64/cpu/SymmetricMultiprocessing.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#include <smp.hpp>
|
||||
|
||||
#include <cpu.hpp>
|
||||
|
||||
#include "../../../kernel.h"
|
||||
|
||||
extern "C" uint64_t _trampoline_start, _trampoline_end;
|
||||
|
||||
#define TRAMPOLINE_START 0x2000
|
||||
|
||||
enum SMPTrampolineAddress
|
||||
{
|
||||
PAGE_TABLE = 0x500,
|
||||
START_ADDR = 0x520,
|
||||
STACK = 0x570,
|
||||
GDT = 0x580,
|
||||
IDT = 0x590,
|
||||
};
|
||||
|
||||
volatile bool CPUEnabled = false;
|
||||
|
||||
extern "C" void StartCPU()
|
||||
{
|
||||
CPUEnabled = true;
|
||||
CPU::Stop();
|
||||
}
|
64
Architecture/amd64/cpu/apic.hpp
Normal file
64
Architecture/amd64/cpu/apic.hpp
Normal file
@ -0,0 +1,64 @@
|
||||
#ifndef __FENNIX_KERNEL_APIC_H__
|
||||
#define __FENNIX_KERNEL_APIC_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
namespace APIC
|
||||
{
|
||||
class APIC
|
||||
{
|
||||
private:
|
||||
bool x2APICSupported = false;
|
||||
|
||||
public:
|
||||
enum APICRegisters
|
||||
{
|
||||
APIC_ONESHOT = (0 << 17), // LVT One-Shot Mode (for Timer)
|
||||
APIC_PERIODIC = (1 << 17), // LVT Periodic Mode (for Timer)
|
||||
APIC_TSC_DEADLINE = (2 << 17), // LVT Timer/sDeadline (for Timer)
|
||||
// source from: https://github.com/pdoane/osdev/blob/master/intr/local_apic.c
|
||||
APIC_ID = 0x20, // Local APIC ID
|
||||
APIC_VER = 0x30, // Local APIC Version
|
||||
APIC_TPR = 0x80, // Task Priority
|
||||
APIC_APR = 0x90, // Arbitration Priority
|
||||
APIC_PPR = 0xa0, // Processor Priority
|
||||
APIC_EOI = 0xb0, // EOI
|
||||
APIC_RRD = 0xc0, // Remote Read
|
||||
APIC_LDR = 0xd0, // Logical Destination
|
||||
APIC_DFR = 0xe0, // Destination Format
|
||||
APIC_SVR = 0xf0, // Spurious Interrupt Vector
|
||||
APIC_ISR = 0x100, // In-Service (8 registers)
|
||||
APIC_TMR = 0x180, // Trigger Mode (8 registers)
|
||||
APIC_IRR = 0x200, // Interrupt Request (8 registers)
|
||||
APIC_ESR = 0x280, // Error Status
|
||||
APIC_ICRLO = 0x300, // Interrupt Command
|
||||
APIC_ICRHI = 0x310, // Interrupt Command [63:32]
|
||||
APIC_TIMER = 0x320, // LVT Timer
|
||||
APIC_THERMAL = 0x330, // LVT Thermal Sensor
|
||||
APIC_PERF = 0x340, // LVT Performance Counter
|
||||
APIC_LINT0 = 0x350, // LVT LINT0
|
||||
APIC_LINT1 = 0x360, // LVT LINT1
|
||||
APIC_ERROR = 0x370, // LVT Error
|
||||
APIC_TICR = 0x380, // Initial Count (for Timer)
|
||||
APIC_TCCR = 0x390, // Current Count (for Timer)
|
||||
APIC_TDCR = 0x3e0, // Divide Configuration (for Timer)
|
||||
};
|
||||
|
||||
uint32_t Read(uint32_t Register);
|
||||
void Write(uint32_t Register, uint32_t Value);
|
||||
void IOWrite(uint64_t Base, uint32_t Register, uint32_t Value);
|
||||
uint32_t IORead(uint64_t Base, uint32_t Register);
|
||||
void EOI();
|
||||
void RedirectIRQs(int CPU = 0);
|
||||
void IPI(uint8_t CPU, uint32_t InterruptNumber);
|
||||
void OneShot(uint32_t Vector, uint64_t Miliseconds);
|
||||
bool APICSupported();
|
||||
uint32_t IOGetMaxRedirect(uint32_t APICID);
|
||||
void RawRedirectIRQ(uint8_t Vector, uint32_t GSI, uint16_t Flags, int CPU, int Status);
|
||||
void RedirectIRQ(int CPU, uint8_t IRQ, int Status);
|
||||
APIC();
|
||||
~APIC();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // !__FENNIX_KERNEL_APIC_H__
|
Reference in New Issue
Block a user