feat: further kernel power and power optimizations
This commit is contained in:
@@ -14,6 +14,8 @@ using namespace Kt;
|
||||
namespace Hal {
|
||||
namespace LocalApic {
|
||||
static volatile uint32_t* g_apicBase = nullptr;
|
||||
static constexpr uint32_t ICR_DELIVERY_STATUS = (1 << 12);
|
||||
static constexpr uint32_t ICR_LEVEL_ASSERT = (1 << 14);
|
||||
|
||||
static inline uint64_t ReadMSR(uint32_t msr) {
|
||||
uint32_t lo, hi;
|
||||
@@ -113,6 +115,21 @@ namespace Hal {
|
||||
WriteRegister(REG_EOI, 0);
|
||||
}
|
||||
|
||||
void SendFixedIpi(uint32_t apicId, uint8_t vector) {
|
||||
if (g_apicBase == nullptr) return;
|
||||
|
||||
while (ReadRegister(REG_ICR_LOW) & ICR_DELIVERY_STATUS) {
|
||||
asm volatile("pause");
|
||||
}
|
||||
|
||||
WriteRegister(REG_ICR_HIGH, apicId << 24);
|
||||
WriteRegister(REG_ICR_LOW, (uint32_t)vector | ICR_LEVEL_ASSERT);
|
||||
|
||||
while (ReadRegister(REG_ICR_LOW) & ICR_DELIVERY_STATUS) {
|
||||
asm volatile("pause");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t GetId() {
|
||||
return (ReadRegister(REG_ID) >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace Hal {
|
||||
void Reinitialize();
|
||||
|
||||
void SendEOI();
|
||||
void SendFixedIpi(uint32_t apicId, uint8_t vector);
|
||||
uint32_t GetId();
|
||||
|
||||
uint32_t ReadRegister(uint32_t reg);
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace Hal {
|
||||
constexpr uint8_t IRQ_MOUSE = 12;
|
||||
constexpr uint8_t IRQ_ATA1 = 14;
|
||||
constexpr uint8_t IRQ_ATA2 = 15;
|
||||
constexpr uint8_t IRQ_RESCHEDULE = 47;
|
||||
|
||||
// Register a handler for the given IRQ number (0-47)
|
||||
void RegisterIrqHandler(uint8_t irq, IrqHandler handler);
|
||||
|
||||
@@ -31,6 +31,19 @@ namespace Hal {
|
||||
asm volatile("mwait" :: "a"(0x00), "c"(0));
|
||||
}
|
||||
|
||||
// Atomic idle entry for paths that have already disabled interrupts.
|
||||
// Keeping STI immediately adjacent to HLT/MWAIT avoids the classic race
|
||||
// where an IRQ is handled between enabling interrupts and entering idle,
|
||||
// after which the CPU sleeps until the next timer deadline.
|
||||
inline void HaltWithInterruptsDisabled() {
|
||||
asm volatile("sti\n\thlt\n\tcli" ::: "memory");
|
||||
}
|
||||
|
||||
inline void IdleWaitWithInterruptsDisabled(volatile uint64_t* monitorAddr) {
|
||||
asm volatile("monitor" :: "a"(monitorAddr), "c"(0), "d"(0) : "memory");
|
||||
asm volatile("sti\n\tmwait\n\tcli" :: "a"(0x00), "c"(0) : "memory");
|
||||
}
|
||||
|
||||
inline void EnableSSE() {
|
||||
uint64_t cr0;
|
||||
asm volatile("mov %%cr0, %0" : "=r"(cr0));
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "SmpBoot.hpp"
|
||||
#include <ACPI/CpuIdle.hpp>
|
||||
#include <Hal/Apic/Apic.hpp>
|
||||
#include <Hal/Apic/Interrupts.hpp>
|
||||
#include <Hal/IDT.hpp>
|
||||
@@ -212,16 +213,9 @@ namespace Smp {
|
||||
// --- Enable interrupts and enter idle loop ---
|
||||
asm volatile("sti");
|
||||
|
||||
// Use MWAIT for deeper C-states if available, otherwise HLT.
|
||||
static volatile uint64_t s_idleMonitor = 0;
|
||||
if (cpu->hasMwait) {
|
||||
for (;;) {
|
||||
Hal::IdleWait(&s_idleMonitor);
|
||||
}
|
||||
} else {
|
||||
for (;;) {
|
||||
asm volatile("hlt");
|
||||
}
|
||||
for (;;) {
|
||||
Hal::CpuIdle::Wait(10, cpu->hasMwait, &s_idleMonitor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user