Final pre-release
This commit is contained in:
@ -5,12 +5,10 @@
|
||||
shr ebx, 0x18
|
||||
mov edi, ebx ; Now the ID is in EDI
|
||||
|
||||
; Load the prepared AP GDT
|
||||
; Load the AP's prepared GDT and TSS
|
||||
mov ebx, [boot_ap_gdts - boot_ap + startup_address]
|
||||
mov eax, [ebx + edi * 0x4]
|
||||
lgdt [eax]
|
||||
|
||||
; Load the TSS
|
||||
mov ax, 0x28
|
||||
ltr ax
|
||||
|
||||
|
||||
@ -1,10 +1,5 @@
|
||||
// These variables are located in the startup routine's TEXT section
|
||||
// and exported from smp_boot.asm.
|
||||
|
||||
// Use IDTR from the BSP
|
||||
// Recycle values from the BSP
|
||||
asm volatile("sidt %0" : "=m"(boot_ap_idtr));
|
||||
|
||||
// Use cr0, cr3 and cr4 from the BSP
|
||||
asm volatile("mov %%cr0, %%eax;" : "=a"(boot_ap_cr0));
|
||||
asm volatile("mov %%cr3, %%eax;" : "=a"(boot_ap_cr3));
|
||||
asm volatile("mov %%cr4, %%eax;" : "=a"(boot_ap_cr4));
|
||||
|
||||
35
code/apic_def.cpp
Normal file
35
code/apic_def.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
// Excerpt from the Apic class definition
|
||||
class Apic {
|
||||
public:
|
||||
// Enabling the APIC subsystem
|
||||
static bool isSupported();
|
||||
static bool isEnabled();
|
||||
static void enable();
|
||||
|
||||
// Enabling SMP
|
||||
static bool isSmpSupported();
|
||||
static void startupSmp();
|
||||
|
||||
// Controlling the current core's local APIC
|
||||
static void initializeCurrentLocalApic();
|
||||
static uint8_t getCpuCount();
|
||||
static LocalApic &getCurrentLocalApic();
|
||||
static void enableCurrentErrorHandler();
|
||||
|
||||
// Controlling the current core's APIC timer
|
||||
static bool isCurrentTimerRunning();
|
||||
static void startCurrentTimer();
|
||||
static ApicTimer &getCurrentTimer();
|
||||
|
||||
// Controlling the current core's interrupts
|
||||
static void allow(InterruptRequest interruptRequest);
|
||||
static void forbid(InterruptRequest interruptRequest);
|
||||
static bool status(InterruptRequest interruptRequest);
|
||||
static void sendEndOfInterrupt(InterruptVector vector);
|
||||
static bool isLocalInterrupt(InterruptVector vector);
|
||||
static bool isExternalInterrupt(InterruptVector vector);
|
||||
|
||||
// Tracking interrupt statistics
|
||||
static void mountVirtualFilesystemNodes();
|
||||
static void countInterrupt(InterruptVector vector);
|
||||
}
|
||||
@ -1,5 +1,4 @@
|
||||
void ApicErrorHandler::trigger(const InterruptFrame &frame) {
|
||||
// Write/read register: Write first, then read
|
||||
void ApicErrorHandler::trigger() {
|
||||
// Writing the ESR updates its contents and arms the interrupt again
|
||||
LocalApic::writeDoubleWord(LocalApic::ESR, 0);
|
||||
uint32_t errors = LocalApic::readDoubleWord(LocalApic::ESR);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Excerpt from the APIC timer interrupt handler
|
||||
// Excerpt from the ApicTimer interrupt handler
|
||||
void ApicTimer::trigger(const InterruptFrame &frame) {
|
||||
if (cpuId != LocalApic::getId()) {
|
||||
// Abort if the handler doesn't belong to the current CPU
|
||||
@ -7,4 +7,14 @@ void ApicTimer::trigger(const InterruptFrame &frame) {
|
||||
|
||||
// Increase the "core-local" time
|
||||
time.addNanoseconds(timerInterval * 1'000'000); // Interval is in milliseconds
|
||||
|
||||
// Only the BSP may continue
|
||||
if (cpuId != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Trigger preemption
|
||||
if (time.toMilliseconds() % yieldInterval == 0) {
|
||||
System::getService<SchedulerService>().yield();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
// Excerpt from the "InterruptDispatcher" class
|
||||
void InterruptDispatcher::assign(uint8_t slot, InterruptHandler &isr) {
|
||||
if (handler[slot] == nullptr) {
|
||||
handler[slot] = new Util::ArrayList<InterruptHandler*>;
|
||||
// Excerpt from the "assign" function
|
||||
void InterruptDispatcher::assign(InterruptVector vec, InterruptHandler &handler) {
|
||||
if (handlers[vec] == nullptr) {
|
||||
// Make space for multiple possible interrupt handlers
|
||||
handlers[vec] = new Util::ArrayList<InterruptHandler *>;
|
||||
}
|
||||
|
||||
handler[slot]->add(&isr); // Register an interrupt handler to an interrupt vector
|
||||
handlers[vec]->add(&handler); // Register a handler to a vector
|
||||
}
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
// Excerpt from the "dispatch" function
|
||||
interruptDepthWrapper.inc();
|
||||
interruptService.sendEndOfInterrupt(slot); // Signal interrupt servicing
|
||||
asm volatile("sti"); // Allow cascaded interrupts
|
||||
void InterruptDispatcher::dispatch(InterruptVector vec) {
|
||||
interruptService.sendEndOfInterrupt(vec); // Signal interrupt servicing
|
||||
asm volatile("sti"); // Allow cascaded interrupts
|
||||
|
||||
uint32_t size = handlerList->size();
|
||||
for (uint32_t i = 0; i < size; i++) {
|
||||
handlerList->get(i)->trigger(frame); // Call registered interrupt handlers
|
||||
}
|
||||
auto *handlerList = handlers[vec];
|
||||
for (uint32_t i = 0; i < handlerList->size(); i++) {
|
||||
handlerList->get(i)->trigger(); // Call registered interrupt handlers
|
||||
}
|
||||
|
||||
asm volatile("cli");
|
||||
interruptDepthWrapper.dec();
|
||||
asm volatile("cli");
|
||||
}
|
||||
@ -1,5 +1,7 @@
|
||||
// Excerpt from the "dispatch" function
|
||||
if (interruptService.checkSpuriousInterrupt(slot)) {
|
||||
spuriousCounterWrapper.inc();
|
||||
return; // Early return to skip the calling of any handlers
|
||||
void InterruptDispatcher::dispatch(InterruptVector vec) {
|
||||
if (interruptService.checkSpuriousInterrupt(slot)) {
|
||||
spuriousCounterWrapper.inc();
|
||||
return; // Early return to skip the calling of any handlers
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
// Excerpt from the "InterruptHandler" class definition
|
||||
// Excerpt from the "InterruptHandler" interface
|
||||
class InterruptHandler {
|
||||
public:
|
||||
virtual void plugin() = 0; // Register the handler
|
||||
virtual void trigger(const InterruptFrame &frame) = 0; // Handle an interrupt
|
||||
virtual void trigger(const InterruptFrame &frame) = 0; // Handle an interrupt
|
||||
};
|
||||
|
||||
5
code/ioapic_allow.cpp
Normal file
5
code/ioapic_allow.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
void IoApic::allow(GlobalSystemInterrupt gsi) {
|
||||
REDTBLEntry redtblEntry = readREDTBL(gsi);
|
||||
redtblEntry.isMasked = false;
|
||||
writeREDTBL(gsi, redtblEntry);
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
struct IrqOverride {
|
||||
InterruptRequest source;
|
||||
GlobalSystemInterrupt target;
|
||||
InterruptRequest source;
|
||||
GlobalSystemInterrupt target;
|
||||
REDTBLEntry::PinPolarity polarity;
|
||||
REDTBLEntry::TriggerMode trigger;
|
||||
};
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
void Pit::trigger(const InterruptFrame &frame) {
|
||||
void Pit::trigger() {
|
||||
time.addNanoseconds(timerInterval); // Increase system time
|
||||
|
||||
// Don't use PIT for scheduling when the APIC timer is enabled
|
||||
|
||||
12
code/pit_early_delay.cpp
Normal file
12
code/pit_early_delay.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
// Excerpt from the "earlyDelay" function
|
||||
void Pit::earlyDelay(uint16_t us) {
|
||||
uint32_t counter = (static_cast<double>(BASE_FREQUENCY) / 1'000'000) * us;
|
||||
|
||||
controlPort.writeByte(0b110000); // Channel 0, mode 0
|
||||
dataPort0.writeByte(static_cast<uint8_t>(counter & 0xFF)); // Low byte
|
||||
dataPort0.writeByte(static_cast<uint8_t>((counter >> 8) & 0xFF)); // High byte
|
||||
|
||||
do {
|
||||
controlPort.writeByte(0b11100010); // Readback channel 0
|
||||
} while (!(dataPort0.readByte() & (1 << 7))); // Bit 7 is the output pin state
|
||||
}
|
||||
@ -1,7 +1,8 @@
|
||||
// Excerpt from the "Pit" interrupt handler
|
||||
void Pit::trigger(const InterruptFrame &frame) {
|
||||
void Pit::trigger() {
|
||||
time.addNanoseconds(timerInterval); // Increase system time
|
||||
|
||||
// Trigger preemption
|
||||
if (time.toMilliseconds() % yieldInterval == 0) {
|
||||
System::getService<SchedulerService>().yield(); // Trigger preemption
|
||||
}
|
||||
|
||||
@ -1,9 +1,12 @@
|
||||
// Excerpt from System::initializeSystem(). Located before interrupts
|
||||
// are enabled and any devices have registered their handlers.
|
||||
if (Apic::isSupported()) {
|
||||
Apic::enable();
|
||||
// Excerpt from the "initializeSystem" function
|
||||
void System::initializeSystem() {
|
||||
if (Apic::isSupported()) {
|
||||
Apic::enable();
|
||||
|
||||
if (Apic::isSmpSupported()) {
|
||||
Apic::startupSmp();
|
||||
if (Apic::isSmpSupported()) {
|
||||
Apic::startupSmp();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Cpu::enableInterrupts();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user