diff --git a/README.md b/README.md index 9742eed..29c11d6 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,7 @@ ninja runmin - [x] LAPIC - [x] IOAPIC - [x] RTC + - [x] TSC (usable delay(), finally!) - Generic - [x] PCI - [x] ISA diff --git a/arch/x86_64/cpu/Cpu.h b/arch/x86_64/cpu/Cpu.h index 69d7c7c..9fac60e 100644 --- a/arch/x86_64/cpu/Cpu.h +++ b/arch/x86_64/cpu/Cpu.h @@ -54,10 +54,6 @@ static inline uint64_t __attribute__((always_inline)) rdtsc(void) { return ((uint64_t)hi << 32) | lo; } -static inline void __attribute__((always_inline)) delay(uint64_t cycles) { - while (cycles--) __asm__ volatile ("nop"); -} - void DumpRegisters(RegistersDumpT* dump); void PrintRegisters(const RegistersDumpT* dump); diff --git a/drivers/ACPI.c b/drivers/ACPI.c new file mode 100644 index 0000000..a04eefe --- /dev/null +++ b/drivers/ACPI.c @@ -0,0 +1,208 @@ +#include "ACPI.h" +#include "Console.h" +#include "Io.h" +#include "MemOps.h" +#include "StringOps.h" +#include "VMem.h" +#include "TSC.h" + +static ACPIFADT* g_fadt = NULL; +static bool g_acpi_initialized = false; + +// Find RSDP in BIOS memory areas +static ACPIRSDPv1* FindRSDP(void) { + // Search in EBDA (Extended BIOS Data Area) + uint16_t ebda = 0; + if (VMemGetPhysAddr(0x40E) != 0) { + ebda = *(uint16_t*)0x40E; + } + if (ebda) { + uint8_t* ebda_ptr = (uint8_t*)(ebda << 4); + for (uint32_t i = 0; i < 1024; i += 16) { + if (FastMemcmp(ebda_ptr + i, ACPI_RSDP_SIG, 8) == 0) { + return (ACPIRSDPv1*)(ebda_ptr + i); + } + } + } + + // Search in BIOS ROM area (0xE0000-0xFFFFF) + for (uint32_t addr = 0xE0000; addr < 0x100000; addr += 16) { + if (FastMemcmp((void*)addr, ACPI_RSDP_SIG, 8) == 0) { + return (ACPIRSDPv1*)addr; + } + } + + return NULL; +} + +// Validate ACPI table checksum +static bool ValidateChecksum(void* table, uint32_t length) { + uint8_t sum = 0; + uint8_t* bytes = (uint8_t*)table; + for (uint32_t i = 0; i < length; i++) { + sum += bytes[i]; + } + return sum == 0; +} + +// Map ACPI table to virtual memory +static void* MapACPITable(uint32_t phys_addr, uint32_t size) { + // Align to page boundaries + uint32_t aligned_addr = phys_addr & ~0xFFF; + uint32_t offset = phys_addr - aligned_addr; + uint32_t aligned_size = ((size + offset + 0xFFF) & ~0xFFF); + + void* virt_addr = VMemAlloc(aligned_size); + if (!virt_addr) return NULL; + + if (VMemUnmap((uint64_t)virt_addr, aligned_size) != VMEM_SUCCESS) { + VMemFree(virt_addr, aligned_size); + return NULL; + } + + if (VMemMapMMIO((uint64_t)virt_addr, aligned_addr, aligned_size, PAGE_WRITABLE | PAGE_NOCACHE) != VMEM_SUCCESS) { + VMemFree(virt_addr, aligned_size); + return NULL; + } + + return (uint8_t*)virt_addr + offset; +} + +bool ACPIInit(void) { + PrintKernel("ACPI: Initializing ACPI subsystem...\n"); + + // Find RSDP + ACPIRSDPv1* rsdp = FindRSDP(); + if (!rsdp) { + PrintKernelError("ACPI: RSDP not found\n"); + return false; + } + + PrintKernel("ACPI: Found RSDP at 0x"); + PrintKernelHex((uint64_t)rsdp); + PrintKernel("\n"); + + // Validate RSDP checksum + if (!ValidateChecksum(rsdp, sizeof(ACPIRSDPv1))) { + PrintKernelError("ACPI: Invalid RSDP checksum\n"); + return false; + } + + ACPIRSDT* rsdt = (ACPIRSDT*)MapACPITable(rsdp->rsdt_address, + sizeof(ACPISDTHeader)); + if (!rsdt) { + PrintKernelError("ACPI: Failed to map RSDT\n"); + return false; + } + // Validate RSDT signature + if (FastMemcmp(rsdt->header.signature, ACPI_RSDT_SIG, 4) != 0) { + PrintKernelError("ACPI: Invalid RSDT signature\n"); + // Clean up the initial header‐only mapping + VMemUnmap((uint64_t)rsdt - (rsdp->rsdt_address & 0xFFF), + ((sizeof(ACPISDTHeader) + (rsdp->rsdt_address & 0xFFF) + 0xFFF) + & ~0xFFF)); + return false; + } + // Remap with the full table length + uint32_t rsdt_size = rsdt->header.length; + // Remember the old header mapping so we can free it afterward + void* old_rsdt = rsdt; + uint32_t old_offset = rsdp->rsdt_address & 0xFFF; + rsdt = (ACPIRSDT*)MapACPITable(rsdp->rsdt_address, rsdt_size); + // Now unmap the temporary header‐only region + VMemUnmap((uint64_t)old_rsdt - old_offset, + ((sizeof(ACPISDTHeader) + old_offset + 0xFFF) & ~0xFFF)); + + PrintKernel("ACPI: RSDT mapped, length="); + PrintKernelInt(rsdt_size); + PrintKernel("\n"); + + // Find FADT + uint32_t entries = (rsdt_size - sizeof(ACPISDTHeader)) / 4; + for (uint32_t i = 0; i < entries; i++) { + ACPISDTHeader* header = (ACPISDTHeader*)MapACPITable( + rsdt->table_pointers[i], + sizeof(ACPISDTHeader) + ); + if (!header) continue; + + bool is_fadt = FastMemcmp(header->signature, ACPI_FADT_SIG, 4) == 0; + uint32_t table_length = header->length; + uint32_t header_offset = rsdt->table_pointers[i] & 0xFFF; + + // Unmap the header mapping now that we've inspected it + VMemUnmap( + (uint64_t)header - header_offset, + ( (sizeof(ACPISDTHeader) + header_offset + 0xFFF) & ~0xFFF ) + ); + + if (is_fadt) { + PrintKernel("ACPI: Found FADT\n"); + g_fadt = (ACPIFADT*)MapACPITable( + rsdt->table_pointers[i], + table_length + ); + break; + } + } + + PrintKernelError("ACPI: FADT not found or invalid\n"); + return false; +} + +void ACPIShutdown(void) { + if (!g_acpi_initialized || !g_fadt) { + PrintKernel("ACPI: Shutdown not available, using fallback\n"); + outw(0x604, 0x2000); + return; + } + + PrintKernel("ACPI: Initiating shutdown...\n"); + + // Enable ACPI mode if needed + if (g_fadt->smi_command_port && g_fadt->acpi_enable) { + PrintKernel("ACPI: Enabling ACPI mode via SMI\n"); + outb(g_fadt->smi_command_port, g_fadt->acpi_enable); + } + + // Try multiple shutdown methods + uint16_t shutdown_values[] = {0x2000, 0x3C00, 0x1400, 0x0000}; + + for (int i = 0; i < 4; i++) { + PrintKernel("ACPI: Trying shutdown value 0x"); + PrintKernelHex(shutdown_values[i]); + PrintKernel(" on port 0x"); + PrintKernelHex(g_fadt->pm1a_control_block); + PrintKernel("\n"); + + outw(g_fadt->pm1a_control_block, shutdown_values[i]); + + // Wait a bit + delay(10); + } + + // Fallback methods + PrintKernel("ACPI: Trying QEMU shutdown\n"); + outw(0x604, 0x2000); + + PrintKernel("ACPI: Trying Bochs shutdown\n"); + outw(0xB004, 0x2000); + + PrintKernelError("ACPI: All shutdown methods failed\n"); +} + +void ACPIReboot(void) { + PrintKernel("ACPI: Initiating reboot...\n"); + + // Try keyboard controller reset + outb(0x64, 0xFE); + + PrintKernel("ACPI: falling back to triple faulting...\n"); + + struct { + uint16_t limit; + uint64_t base; + } __attribute__((packed)) invalid_idt = { 0, 0 }; + __asm__ volatile("lidt %0; int $0x03" :: "m"(invalid_idt)); + __builtin_unreachable(); +} \ No newline at end of file diff --git a/drivers/ACPI.h b/drivers/ACPI.h new file mode 100644 index 0000000..da00da1 --- /dev/null +++ b/drivers/ACPI.h @@ -0,0 +1,85 @@ +#pragma once +#include "stdint.h" +#include "stdbool.h" + +// ACPI Table signatures +#define ACPI_RSDP_SIG "RSD PTR " +#define ACPI_RSDT_SIG "RSDT" +#define ACPI_FADT_SIG "FACP" + +// ACPI structures +typedef struct { + char signature[8]; + uint8_t checksum; + char oem_id[6]; + uint8_t revision; + uint32_t rsdt_address; +} __attribute__((packed)) ACPIRSDPv1; + +typedef struct { + char signature[4]; + uint32_t length; + uint8_t revision; + uint8_t checksum; + char oem_id[6]; + char oem_table_id[8]; + uint32_t oem_revision; + uint32_t creator_id; + uint32_t creator_revision; +} __attribute__((packed)) ACPISDTHeader; + +typedef struct { + ACPISDTHeader header; + uint32_t table_pointers[]; +} __attribute__((packed)) ACPIRSDT; + +typedef struct { + ACPISDTHeader header; + uint32_t firmware_ctrl; + uint32_t dsdt; + uint8_t reserved; + uint8_t preferred_pm_profile; + uint16_t sci_interrupt; + uint32_t smi_command_port; + uint8_t acpi_enable; + uint8_t acpi_disable; + uint8_t s4bios_req; + uint8_t pstate_control; + uint32_t pm1a_event_block; + uint32_t pm1b_event_block; + uint32_t pm1a_control_block; + uint32_t pm1b_control_block; + uint32_t pm2_control_block; + uint32_t pm_timer_block; + uint32_t gpe0_block; + uint32_t gpe1_block; + uint8_t pm1_event_length; + uint8_t pm1_control_length; + uint8_t pm2_control_length; + uint8_t pm_timer_length; + uint8_t gpe0_length; + uint8_t gpe1_length; + uint8_t gpe1_base; + uint8_t cstate_control; + uint16_t worst_c2_latency; + uint16_t worst_c3_latency; + uint16_t flush_size; + uint16_t flush_stride; + uint8_t duty_offset; + uint8_t duty_width; + uint8_t day_alarm; + uint8_t month_alarm; + uint8_t century; + uint16_t boot_architecture_flags; + uint8_t reserved2; + uint32_t flags; +} __attribute__((packed)) ACPIFADT; + +// Power management defines +#define ACPI_SLP_TYP_MASK 0x1C00 +#define ACPI_SLP_EN 0x2000 + +// Function declarations +bool ACPIInit(void); +void ACPIShutdown(void); +void ACPIReboot(void); \ No newline at end of file diff --git a/drivers/APIC.c b/drivers/APIC.c index 3a12709..c7f50d8 100644 --- a/drivers/APIC.c +++ b/drivers/APIC.c @@ -40,11 +40,13 @@ #define IOAPIC_DEFAULT_PHYS_ADDR 0xFEC00000 #define LAPIC_LVT_TIMER_SCALE_FACTOR 1 // --- Global Variables --- -static volatile uint32_t* s_lapic_base = NULL; +volatile uint32_t* s_lapic_base = NULL; static volatile uint32_t* s_ioapic_base = NULL; static uint32_t s_apic_timer_freq_hz = 1000; // Default to 1KHz volatile uint32_t s_apic_timer_ticks = 0; volatile uint32_t APIC_HZ = 250; +uint32_t s_apic_bus_freq = 0; // Cached bus frequency, non static for TSC.c access +static bool s_calibrated = false; // Calibration flag // --- Forward Declarations --- static void lapic_write(uint32_t reg, uint32_t value); @@ -186,51 +188,54 @@ void ApicTimerSetFrequency(uint32_t frequency_hz) { s_apic_timer_freq_hz = frequency_hz; APIC_HZ = frequency_hz; - // 1. Configure PIT channel 2 for square wave mode (mode 3) at 100Hz - outb(PIT_COMMAND, 0xB6); // Channel 2, LSB/MSB, mode 3 - uint16_t divisor = 11932; // 1193180 / 100 - outb(PIT_CHANNEL_2, divisor & 0xFF); - outb(PIT_CHANNEL_2, (divisor >> 8) & 0xFF); - - // 2. Enable PC speaker to connect PIT channel 2 output - uint8_t speaker_reg = inb(PC_SPEAKER_PORT); - outb(PC_SPEAKER_PORT, speaker_reg | 0x01); - - // 3. Set APIC timer to one-shot mode with max initial count - lapic_write(LAPIC_LVT_TIMER, 32 | (0b00 << 17)); // Vector 32, one-shot mode - lapic_write(LAPIC_TIMER_INIT_COUNT, 0xFFFFFFFF); - - // 4. Wait for a rising edge on PIT channel 2 output - while ((inb(PC_SPEAKER_PORT) & 0x20) != 0); - while ((inb(PC_SPEAKER_PORT) & 0x20) == 0); - - // 5. Read the APIC timer count - uint32_t start_count = lapic_read(LAPIC_TIMER_CUR_COUNT); - - // 6. Wait for the next rising edge - while ((inb(PC_SPEAKER_PORT) & 0x20) != 0); - while ((inb(PC_SPEAKER_PORT) & 0x20) == 0); - - // 7. Read the APIC timer count again - uint32_t end_count = lapic_read(LAPIC_TIMER_CUR_COUNT); - - // 8. Stop the PIT and APIC timer - outb(PC_SPEAKER_PORT, speaker_reg); // Restore speaker port - lapic_write(LAPIC_LVT_TIMER, 1 << 16); // Mask the timer - - // 9. Calculate the number of ticks in 10ms (100 Hz) - uint32_t ticks_in_10ms = start_count - end_count; - - // 10. Calculate the APIC timer frequency (with divider) - uint32_t bus_freq = ticks_in_10ms * 100; - lapic_write(LAPIC_TIMER_DIV, 0x3); // Divide by 16 - uint32_t apic_freq = bus_freq / 16; - - // 11. Calculate the required initial count for the desired frequency - uint32_t initial_count = apic_freq / frequency_hz; - - // --- Set APIC Timer to Periodic Mode --- - lapic_write(LAPIC_LVT_TIMER, 32 | (0b01 << 17)); // Vector 32, periodic mode + // Only calibrate once to avoid expensive operations + if (!s_calibrated) { + // Set divider first + lapic_write(LAPIC_TIMER_DIV, 0xB); // Divide by 1 (no division) + + // Configure PIT for calibration + outb(PIT_COMMAND, 0xB6); + uint16_t divisor = 11932; // 100Hz + outb(PIT_CHANNEL_2, divisor & 0xFF); + outb(PIT_CHANNEL_2, (divisor >> 8) & 0xFF); + + uint8_t speaker_reg = inb(PC_SPEAKER_PORT); + outb(PC_SPEAKER_PORT, speaker_reg | 0x01); + + // One-shot calibration + lapic_write(LAPIC_LVT_TIMER, 32 | (0b00 << 17)); + lapic_write(LAPIC_TIMER_INIT_COUNT, 0xFFFFFFFF); + + // Wait with timeout + uint32_t timeout = 100000; + while ((inb(PC_SPEAKER_PORT) & 0x20) != 0 && --timeout); + while ((inb(PC_SPEAKER_PORT) & 0x20) == 0 && --timeout); + + uint32_t start_count = lapic_read(LAPIC_TIMER_CUR_COUNT); + + timeout = 100000; + while ((inb(PC_SPEAKER_PORT) & 0x20) != 0 && --timeout); + while ((inb(PC_SPEAKER_PORT) & 0x20) == 0 && --timeout); + + uint32_t end_count = lapic_read(LAPIC_TIMER_CUR_COUNT); + + outb(PC_SPEAKER_PORT, speaker_reg); + lapic_write(LAPIC_LVT_TIMER, 1 << 16); + + if (timeout > 0) { + uint32_t ticks_per_10ms = start_count - end_count; + s_apic_bus_freq = ticks_per_10ms * 100; + s_calibrated = true; + // PrintKernelF("APIC: Calibrated - ticks/10ms=%u, bus_freq=%u Hz\n", ticks_per_10ms, s_apic_bus_freq); + } else { + s_apic_bus_freq = 100000000; // Fallback: 100MHz + PrintKernelWarning("APIC: Calibration timeout, using fallback frequency\n"); + } + } + + uint32_t initial_count = s_apic_bus_freq / frequency_hz; + // PrintKernelF("APIC: Setting timer - freq=%u Hz, bus_freq=%u, initial_count=%u\n", frequency_hz, s_apic_bus_freq, initial_count); + lapic_write(LAPIC_LVT_TIMER, 32 | (0b01 << 17)); // Periodic mode lapic_write(LAPIC_TIMER_INIT_COUNT, initial_count); } diff --git a/drivers/PCI/PCI.c b/drivers/PCI/PCI.c index 8c8c5da..93336ab 100644 --- a/drivers/PCI/PCI.c +++ b/drivers/PCI/PCI.c @@ -1,7 +1,7 @@ #include "PCI/PCI.h" #include "Console.h" #include "Io.h" -#include "Cpu.h" +#include "TSC.h" #include "stdbool.h" #include "stdint.h" #include "virtio/Virtio.h" diff --git a/drivers/RTC/Rtc.c b/drivers/RTC/Rtc.c index e0ebd2b..d0c6ddf 100644 --- a/drivers/RTC/Rtc.c +++ b/drivers/RTC/Rtc.c @@ -128,4 +128,65 @@ void RtcSetTime(const RtcDateTime *dateTime) { // Re-enable updates and NMI Rtc_WriteRegister(RTC_STATUS_B, statusB); Rtc_WriteRegister(RTC_CMOS_ADDRESS, RTC_STATUS_B); // Re-enable NMI +} + +// Days in each month (non-leap year) +static const uint16_t days_in_month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +static bool is_leap_year(uint16_t year) { + return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); +} + +uint64_t RtcGetUnixTime(void) { + RtcDateTime dt; + RtcReadTime(&dt); + + // Calculate days since Unix epoch (1970-01-01) + uint64_t days = 0; + + // Add days for complete years + for (uint16_t y = 1970; y < dt.year; y++) { + days += is_leap_year(y) ? 366 : 365; + } + + // Add days for complete months in current year + for (uint8_t m = 1; m < dt.month; m++) { + days += days_in_month[m - 1]; + if (m == 2 && is_leap_year(dt.year)) days++; // February in leap year + } + + // Add remaining days + days += dt.day - 1; + + // Convert to seconds and add time + return days * 86400 + dt.hour * 3600 + dt.minute * 60 + dt.second; +} + +void RtcSetUnixTime(uint64_t unix_time) { + RtcDateTime dt; + + // Extract time components + dt.second = unix_time % 60; + unix_time /= 60; + dt.minute = unix_time % 60; + unix_time /= 60; + dt.hour = unix_time % 24; + uint64_t days = unix_time / 24; + + // Calculate year + dt.year = 1970; + while (days >= (is_leap_year(dt.year) ? 366 : 365)) { + days -= is_leap_year(dt.year) ? 366 : 365; + dt.year++; + } + + // Calculate month and day + dt.month = 1; + while (days >= days_in_month[dt.month - 1] + (dt.month == 2 && is_leap_year(dt.year) ? 1 : 0)) { + days -= days_in_month[dt.month - 1] + (dt.month == 2 && is_leap_year(dt.year) ? 1 : 0); + dt.month++; + } + dt.day = days + 1; + + RtcSetTime(&dt); } \ No newline at end of file diff --git a/drivers/RTC/Rtc.h b/drivers/RTC/Rtc.h index 8977ae8..5f0925e 100644 --- a/drivers/RTC/Rtc.h +++ b/drivers/RTC/Rtc.h @@ -20,4 +20,8 @@ void RtcSetTime(const rtc_time_t *dateTime); uint8_t Rtc_BinaryToBcd(uint8_t binary); int Rtc_BcdToBinary(uint8_t bcd); +// Unix timestamp functions +uint64_t RtcGetUnixTime(void); +void RtcSetUnixTime(uint64_t unix_time); + #endif // VOIDFRAME_RTC_H diff --git a/drivers/TSC.c b/drivers/TSC.c new file mode 100644 index 0000000..4f5381b --- /dev/null +++ b/drivers/TSC.c @@ -0,0 +1,58 @@ +#include "TSC.h" +#include "Cpu.h" +#include "Console.h" + +uint64_t tsc_freq_hz = 0; +static bool tsc_calibrated = false; + +void TSCInit(void) { + // Calibrate TSC frequency using APIC timer + extern volatile uint32_t APIC_HZ; + extern uint32_t s_apic_bus_freq; + + if (APIC_HZ == 0) { + tsc_freq_hz = 3000000000ULL; // Fallback: 3GHz + tsc_calibrated = true; // no-op fix + PrintKernelWarning("TSC: Using fallback frequency\n"); + return; + } + + // Use 10ms calibration period + uint64_t start_tsc = rdtsc(); + uint32_t calibration_ticks = s_apic_bus_freq / 100; // 10 ms worth of APIC ticks + + // Wait using APIC timer current count + extern volatile uint32_t* s_lapic_base; + uint32_t target = s_lapic_base[0x390/4] - calibration_ticks; + while (s_lapic_base[0x390/4] > target); + + uint64_t end_tsc = rdtsc(); + tsc_freq_hz = (end_tsc - start_tsc) * 100; // Scale to 1 second + tsc_calibrated = true; + + PrintKernelF("TSC: Calibrated frequency: %llu Hz\n", tsc_freq_hz); +} + +void delay_us(uint32_t microseconds) { + if (!tsc_calibrated) return; + + uint64_t start = rdtsc(); + uint64_t ticks = (tsc_freq_hz * microseconds) / 1000000; + + while ((rdtsc() - start) < ticks); +} + + +void delay(uint32_t milliseconds) { + uint64_t us = (uint64_t)milliseconds * 1000ULL; + if (us > UINT32_MAX) us = UINT32_MAX; // clamp to API + delay_us((uint32_t)us); +} +void delay_s(uint32_t seconds) { + if (seconds > UINT32_MAX / 1000U) seconds = UINT32_MAX / 1000U; + delay(seconds * 1000U); +} + +uint64_t TSCGetFrequency(void) { + return tsc_freq_hz; +} \ No newline at end of file diff --git a/drivers/TSC.h b/drivers/TSC.h new file mode 100644 index 0000000..a8ec14b --- /dev/null +++ b/drivers/TSC.h @@ -0,0 +1,10 @@ +#pragma once +#include "stdint.h" + +void TSCInit(void); + +void delay_us(uint32_t microseconds); +void delay(uint32_t milliseconds); +void delay_s(uint32_t seconds); + +uint64_t TSCGetFrequency(void); \ No newline at end of file diff --git a/drivers/ethernet/intel/E1000.c b/drivers/ethernet/intel/E1000.c index b3ed100..5caabc8 100644 --- a/drivers/ethernet/intel/E1000.c +++ b/drivers/ethernet/intel/E1000.c @@ -2,7 +2,7 @@ #include "../interface/Arp.h" #include "../interface/Ip.h" #include "Console.h" -#include "Cpu.h" +#include "TSC.h" #include "Io.h" #include "KernelHeap.h" #include "MemOps.h" diff --git a/drivers/sound/Generic.c b/drivers/sound/Generic.c index 24b4920..d22eefb 100644 --- a/drivers/sound/Generic.c +++ b/drivers/sound/Generic.c @@ -1,6 +1,6 @@ #include "Generic.h" #include "Console.h" -#include "Cpu.h" +#include "TSC.h" #include "Io.h" static int pc_speaker_initialized = 0; diff --git a/drivers/sound/SB16.c b/drivers/sound/SB16.c index 1ae20e3..f5114fa 100644 --- a/drivers/sound/SB16.c +++ b/drivers/sound/SB16.c @@ -1,6 +1,6 @@ #include "SB16.h" #include "Io.h" -#include "Cpu.h" +#include "TSC.h" #include "stdint.h" int SB16_Probe(uint16_t io_base) { diff --git a/drivers/storage/AHCI.c b/drivers/storage/AHCI.c index 39abbb2..9529b34 100644 --- a/drivers/storage/AHCI.c +++ b/drivers/storage/AHCI.c @@ -1,6 +1,6 @@ #include "AHCI.h" #include "Console.h" -#include "Cpu.h" +#include "TSC.h" #include "KernelHeap.h" #include "MemOps.h" #include "VMem.h" @@ -48,7 +48,7 @@ static int AHCI_StopPort(int port) { while (timeout-- > 0) { cmd = AHCI_ReadPortReg(port, AHCI_PORT_CMD); if (!(cmd & AHCI_PORT_CMD_CR)) break; - delay(1000); + delay(500); } // Clear FRE bit @@ -61,7 +61,7 @@ static int AHCI_StopPort(int port) { while (timeout-- > 0) { cmd = AHCI_ReadPortReg(port, AHCI_PORT_CMD); if (!(cmd & AHCI_PORT_CMD_FR)) break; - delay(1000); + delay(500); } return (timeout > 0) ? 0 : -1; @@ -160,7 +160,7 @@ static int AHCI_SendCommand(int port, uint8_t command, uint64_t lba, uint16_t co while (timeout-- > 0) { uint32_t tfd = AHCI_ReadPortReg(port, AHCI_PORT_TFD); if (!(tfd & 0x88)) break; // BSY and DRQ clear - delay(1000); + delay(500); } if (timeout <= 0) return -1; @@ -197,11 +197,11 @@ static int AHCI_SendCommand(int port, uint8_t command, uint64_t lba, uint16_t co AHCI_WritePortReg(port, AHCI_PORT_CI, 1); // Wait for completion - timeout = 5000; + timeout = 500; while (timeout-- > 0) { uint32_t ci = AHCI_ReadPortReg(port, AHCI_PORT_CI); if (!(ci & 1)) break; - delay(1000); + delay(50); } if (timeout <= 0) { diff --git a/drivers/xHCI/xHCI.c b/drivers/xHCI/xHCI.c index 8329633..6ce0657 100644 --- a/drivers/xHCI/xHCI.c +++ b/drivers/xHCI/xHCI.c @@ -2,7 +2,7 @@ #include "../../mm/MemOps.h" #include "../../mm/VMem.h" #include "Console.h" -#include "Cpu.h" +#include "TSC.h" // 5.4 - Operational Registers #define XHCI_OP_USBCMD 0x00 // USB Command Register diff --git a/fs/EXT/Ext2.c b/fs/EXT/Ext2.c index aa0f60e..e4f6347 100644 --- a/fs/EXT/Ext2.c +++ b/fs/EXT/Ext2.c @@ -8,6 +8,7 @@ #include "../../mm/MemOps.h" #include "../VFS.h" #include "FileSystem.h" +#include "Rtc.h" #define EXT2_SUPERBLOCK_OFFSET 1024 #define EXT2_MAGIC 0xEF53 @@ -1047,7 +1048,7 @@ int Ext2Delete(const char* path) { // TODO: Handle indirect blocks // Mark inode as deleted - inode.i_dtime = 0; // TODO: Get current time + inode.i_dtime = RtcGetUnixTime(); inode.i_links_count = 0; if (Ext2WriteInode(inode_num, &inode) != 0) { WriteUnlock(&volume.lock); diff --git a/kernel/core/Kernel.c b/kernel/core/Kernel.c index 6324a3b..0c839e7 100644 --- a/kernel/core/Kernel.c +++ b/kernel/core/Kernel.c @@ -35,6 +35,8 @@ #include "storage/AHCI.h" #include "xHCI/xHCI.h" #include "FileSystem.h" +#include "TSC.h" +#include "ACPI.h" void KernelMainHigherHalf(void); #define KERNEL_STACK_SIZE (16 * 1024) // 16KB stack @@ -632,9 +634,26 @@ static InitResultT PXS2(void) { // Initialize APIC PrintKernel("Info: Installing APIC...\n"); - if (!ApicInstall()) PANIC("Failed to initialize APIC"); + if (!ApicInstall()) +#ifndef VF_CONFIG_PANIC_OVERRIDE + PANIC("Failed to initialize APIC"); +#else + PrintKernelError("Failed to initialize APIC\n"); +#endif + ApicTimerInstall(250); PrintKernelSuccess("System: APIC Installed\n"); + + // Initialize TSC for precise delays + TSCInit(); + PrintKernelSuccess("System: TSC initialized\n"); + + // Initialize ACPI for power management + if (ACPIInit()) { + PrintKernelSuccess("System: ACPI initialized\n"); + } else { + PrintKernelWarning("System: ACPI initialization failed\n"); + } #ifdef VF_CONFIG_ENFORCE_MEMORY_PROTECTION PrintKernel("Info: Final memory health check...\n"); diff --git a/kernel/etc/Shell.c b/kernel/etc/Shell.c index 36d9fd3..911bb0f 100644 --- a/kernel/etc/Shell.c +++ b/kernel/etc/Shell.c @@ -2,6 +2,7 @@ #include "../../drivers/ethernet/interface/Icmp.h" #include "6502/6502.h" +#include "ACPI.h" #include "APIC.h" #include "Cerberus.h" #include "Console.h" @@ -182,6 +183,7 @@ static const HelpEntry system_cmds[] = { {"stacksize", "Show stack usage"}, {"lscpu", "List CPU features"}, {"snoozer ", "Snooze messages from PrintKernel"}, + {"acpi sd/rb", "Shutdown (sd) or reboot (rb) via ACPI"}, }; static const HelpEntry file_cmds[] = { @@ -1138,6 +1140,25 @@ static void SnoozeHandler(const char* args) { } KernelFree(status); } + +static void ACPIHandler(const char* args) { + char* status = GetArg(args, 1); + if (!status) { + PrintKernel("Usage: acpi sd/rb\n"); + return; + } + if (FastStrCmp(status, "sd") == 0) { + ACPIShutdown(); + } else if (FastStrCmp(status, "rb") == 0) { + ACPIReboot(); + } else { + PrintKernel("Usage: acpi sd/rb\n"); + KernelFree(status); + return; + } + KernelFree(status); +} + static const ShellCommand commands[] = {\ {"help", HelpHandler}, {"ps", PSHandler}, @@ -1188,6 +1209,7 @@ static const ShellCommand commands[] = {\ {"post", POSTHandler}, {"ping", PingHandler}, {"snooze", SnoozeHandler}, + {"acpi", ACPIHandler}, }; void ExecuteCommand(const char* cmd) { diff --git a/meson.build b/meson.build index 7f7d765..2809126 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,5 @@ project('voidframe', 'c', 'cpp', version : '0.0.2-development3', - meson_version : '>=1.4.0', default_options : [ 'c_std=c11', 'cpp_std=c++17', @@ -201,6 +200,8 @@ fs_sources = files([ # Driver sources driver_sources = files([ 'drivers/APIC.c', + 'drivers/TSC.c', + 'drivers/ACPI.c', 'drivers/Serial.c', 'drivers/PS2.c', 'drivers/Ide.c', @@ -406,13 +407,13 @@ iso = custom_target( run_target('run', command : [ qemu_system_x86_64, - '-cpu', 'max', + '-cpu', 'host', '-vga', 'vmware', '-enable-kvm', '-cdrom', iso.full_path(), '-debugcon', 'file:bootstrap.log', '-serial', 'stdio', - '-no-reboot', '-no-shutdown', +# '-no-reboot', '-no-shutdown', '-m', '4G', '-drive', 'file=VoidFrameDisk.img,if=ide', '-drive', 'file=SataDisk.img,if=none,id=sata0',