1

Final pre-release

This commit is contained in:
2023-03-02 17:29:30 +01:00
parent 01b1be0629
commit 3f02dfd309
47 changed files with 4803 additions and 1836 deletions

View File

@ -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

View File

@ -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
View 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);
}

View File

@ -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);

View File

@ -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();
}
}

View File

@ -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
}

View File

@ -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");
}

View File

@ -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
}
}

View File

@ -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
View File

@ -0,0 +1,5 @@
void IoApic::allow(GlobalSystemInterrupt gsi) {
REDTBLEntry redtblEntry = readREDTBL(gsi);
redtblEntry.isMasked = false;
writeREDTBL(gsi, redtblEntry);
}

View File

@ -1,6 +1,6 @@
struct IrqOverride {
InterruptRequest source;
GlobalSystemInterrupt target;
InterruptRequest source;
GlobalSystemInterrupt target;
REDTBLEntry::PinPolarity polarity;
REDTBLEntry::TriggerMode trigger;
};

View File

@ -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
View 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
}

View File

@ -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
}

View File

@ -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();
}