feat: implement PCI subsystem and integrate uACPI support
See previous commit Signed-off-by: kaguya <vpshinomiya@protonmail.com>
This commit is contained in:
@@ -11,6 +11,8 @@ set(KIRKOS_VERSION_STRING
|
||||
"${VERSION}.${PATCHLEVEL}.${SUBLEVEL}${EXTRAVERSION}"
|
||||
)
|
||||
|
||||
include(${CMAKE_SOURCE_DIR}/libs/uacpi/uacpi.cmake)
|
||||
|
||||
message(STATUS "Building KirkOS version: ${KIRKOS_VERSION_STRING}")
|
||||
|
||||
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
|
||||
@@ -31,7 +33,14 @@ set(EXT2_ROOT "${CMAKE_SOURCE_DIR}/ext2_root")
|
||||
|
||||
add_executable(KirkOS ${KIRKOS_SOURCES})
|
||||
|
||||
target_sources(KirkOS PRIVATE
|
||||
${UACPI_SOURCES}
|
||||
${CMAKE_SOURCE_DIR}/libs/uacpi/source/kernel_api.c
|
||||
)
|
||||
|
||||
target_include_directories(KirkOS PRIVATE
|
||||
${UACPI_INCLUDES}
|
||||
)
|
||||
|
||||
target_compile_definitions(KirkOS PRIVATE
|
||||
KIRKOS_VERSION="${KIRKOS_VERSION_STRING}"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "pic.h"
|
||||
#include "io.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define PIC1_COMMAND_PORT 0x20
|
||||
#define PIC1_DATA_PORT 0x21
|
||||
|
||||
@@ -51,12 +51,13 @@ void x86_64_IRQ_Initialize(void)
|
||||
|
||||
log_info(MODULE, "Found %s PIC.", g_Driver->Name);
|
||||
g_Driver->Initialize(PIC_REMAP_OFFSET, PIC_REMAP_OFFSET + 8, false);
|
||||
|
||||
|
||||
// register ISR handlers for each of the 16 irq lines
|
||||
for (int i = 0; i < 16; i++)
|
||||
x86_64_ISR_RegisterHandler(PIC_REMAP_OFFSET + i, x86_64_IRQ_Handler);
|
||||
|
||||
x86_64_EnableInterrupts();
|
||||
g_Driver->Unmask(0);
|
||||
}
|
||||
|
||||
void x86_64_IRQ_RegisterHandler(int irq, IRQHandler handler)
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
#include "pci.h"
|
||||
#include "arch/x86_64/io.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define PCI_CFG_ADDR 0x0CF8
|
||||
#define PCI_CFG_DATA 0x0CFC
|
||||
|
||||
static uint32_t pci_pack_addr(pci_address_t addr, uint16_t offset)
|
||||
{
|
||||
return (1u << 31) |
|
||||
((uint32_t)addr.bus << 16) |
|
||||
((uint32_t)addr.device << 11) |
|
||||
((uint32_t)addr.function << 8) |
|
||||
(offset & 0xFCu);
|
||||
}
|
||||
|
||||
uint8_t pci_read8(pci_address_t addr, uint16_t offset)
|
||||
{
|
||||
x86_64_outl(PCI_CFG_ADDR, pci_pack_addr(addr, offset));
|
||||
return (uint8_t)(x86_64_inl(PCI_CFG_DATA) >> ((offset & 3) * 8));
|
||||
}
|
||||
|
||||
uint16_t pci_read16(pci_address_t addr, uint16_t offset)
|
||||
{
|
||||
x86_64_outl(PCI_CFG_ADDR, pci_pack_addr(addr, offset));
|
||||
return (uint16_t)(x86_64_inl(PCI_CFG_DATA) >> ((offset & 2) * 8));
|
||||
}
|
||||
|
||||
uint32_t pci_read32(pci_address_t addr, uint16_t offset)
|
||||
{
|
||||
x86_64_outl(PCI_CFG_ADDR, pci_pack_addr(addr, offset));
|
||||
return x86_64_inl(PCI_CFG_DATA);
|
||||
}
|
||||
|
||||
void pci_write8(pci_address_t addr, uint16_t offset, uint8_t val)
|
||||
{
|
||||
uint32_t tmp = pci_read32(addr, offset & ~3u);
|
||||
uint8_t shift = (offset & 3) * 8;
|
||||
tmp = (tmp & ~(0xFFu << shift)) | ((uint32_t)val << shift);
|
||||
x86_64_outl(PCI_CFG_ADDR, pci_pack_addr(addr, offset));
|
||||
x86_64_outl(PCI_CFG_DATA, tmp);
|
||||
}
|
||||
|
||||
void pci_write16(pci_address_t addr, uint16_t offset, uint16_t val)
|
||||
{
|
||||
uint32_t tmp = pci_read32(addr, offset & ~3u);
|
||||
uint8_t shift = (offset & 2) * 8;
|
||||
tmp = (tmp & ~(0xFFFFu << shift)) | ((uint32_t)val << shift);
|
||||
x86_64_outl(PCI_CFG_ADDR, pci_pack_addr(addr, offset));
|
||||
x86_64_outl(PCI_CFG_DATA, tmp);
|
||||
}
|
||||
|
||||
void pci_write32(pci_address_t addr, uint16_t offset, uint32_t val)
|
||||
{
|
||||
x86_64_outl(PCI_CFG_ADDR, pci_pack_addr(addr, offset));
|
||||
x86_64_outl(PCI_CFG_DATA, val);
|
||||
}
|
||||
|
||||
static void pci_read_bars(pci_device_t* dev)
|
||||
{
|
||||
for (int i = 0; i < 6; i++) {
|
||||
uint16_t off = 0x10 + i * 4;
|
||||
dev->bar[i] = pci_read32(dev->addr, off);
|
||||
// If it's a 64-bit BAR we skip the next one (simple version)
|
||||
if ((dev->bar[i] & 0x7) == 0x4)
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void pci_init(void)
|
||||
{
|
||||
printf("[PCI] Scanning bus 0...\n");
|
||||
pci_print_all();
|
||||
}
|
||||
|
||||
void pci_print_all(void)
|
||||
{
|
||||
for (uint8_t bus = 0; bus < 1; bus++) { // start with bus 0 only
|
||||
for (uint8_t dev = 0; dev < 32; dev++) {
|
||||
for (uint8_t func = 0; func < 8; func++) {
|
||||
pci_address_t addr = {bus, dev, func};
|
||||
|
||||
uint16_t vendor = pci_read16(addr, 0x00);
|
||||
if (vendor == 0xFFFF) {
|
||||
if (func == 0) break; // no device
|
||||
continue;
|
||||
}
|
||||
|
||||
uint16_t device_id = pci_read16(addr, 0x02);
|
||||
uint16_t class_sub = pci_read16(addr, 0x0A);
|
||||
uint8_t prog_if = pci_read8 (addr, 0x09);
|
||||
uint8_t revision = pci_read8 (addr, 0x08);
|
||||
|
||||
pci_device_t d = {
|
||||
.addr = addr,
|
||||
.vendor_id = vendor,
|
||||
.device_id = device_id,
|
||||
.class_code = class_sub,
|
||||
.prog_if = prog_if,
|
||||
.revision = revision,
|
||||
};
|
||||
pci_read_bars(&d);
|
||||
|
||||
printf("[PCI] %02x:%02x.%x %04x:%04x class %04x rev %02x\n",
|
||||
bus, dev, func, vendor, device_id, class_sub, revision);
|
||||
|
||||
if (func == 0 && (pci_read8(addr, 0x0E) & 0x80) == 0)
|
||||
break; // not multifunction
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool pci_find_hda(pci_device_t* out_dev)
|
||||
{
|
||||
// Same scan as above, but stop at first HDA device
|
||||
for (uint8_t bus = 0; bus < 1; bus++) {
|
||||
for (uint8_t dev = 0; dev < 32; dev++) {
|
||||
for (uint8_t func = 0; func < 8; func++) {
|
||||
pci_address_t addr = {bus, dev, func};
|
||||
uint16_t vendor = pci_read16(addr, 0x00);
|
||||
if (vendor == 0xFFFF) continue;
|
||||
|
||||
uint16_t class_sub = pci_read16(addr, 0x0A);
|
||||
if (class_sub == (PCI_CLASS_AUDIO << 8) | PCI_SUBCLASS_HDA) {
|
||||
out_dev->addr = addr;
|
||||
out_dev->vendor_id = vendor;
|
||||
out_dev->device_id = pci_read16(addr, 0x02);
|
||||
out_dev->class_code = class_sub;
|
||||
pci_read_bars(out_dev);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
uint8_t bus;
|
||||
uint8_t device;
|
||||
uint8_t function;
|
||||
} pci_address_t;
|
||||
|
||||
typedef struct {
|
||||
pci_address_t addr;
|
||||
uint16_t vendor_id;
|
||||
uint16_t device_id;
|
||||
uint16_t class_code; // (class << 8) | subclass
|
||||
uint8_t prog_if;
|
||||
uint8_t revision;
|
||||
uint32_t bar[6];
|
||||
bool is_multifunction;
|
||||
} pci_device_t;
|
||||
|
||||
#define PCI_CLASS_AUDIO 0x04
|
||||
#define PCI_SUBCLASS_HDA 0x03
|
||||
|
||||
// Read/write config space (re-uses your existing uACPI PCI code)
|
||||
uint8_t pci_read8 (pci_address_t addr, uint16_t offset);
|
||||
uint16_t pci_read16(pci_address_t addr, uint16_t offset);
|
||||
uint32_t pci_read32(pci_address_t addr, uint16_t offset);
|
||||
|
||||
void pci_write8 (pci_address_t addr, uint16_t offset, uint8_t val);
|
||||
void pci_write16(pci_address_t addr, uint16_t offset, uint16_t val);
|
||||
void pci_write32(pci_address_t addr, uint16_t offset, uint32_t val);
|
||||
|
||||
// Scan and print all PCI devices
|
||||
void pci_init(void);
|
||||
void pci_print_all(void);
|
||||
|
||||
// Find first HDA controller (returns true if found)
|
||||
bool pci_find_hda(pci_device_t* out_dev);
|
||||
@@ -0,0 +1,69 @@
|
||||
#include "pit.h"
|
||||
#include "irq.h"
|
||||
#include "io.h"
|
||||
#include <stdint.h>
|
||||
#include "stdio.h"
|
||||
#include "e9.h"
|
||||
#include "limine.h"
|
||||
|
||||
__attribute__((used, section(".limine_requests")))
|
||||
volatile struct limine_date_at_boot_request boot_request = {
|
||||
.id = LIMINE_DATE_AT_BOOT_REQUEST_ID,
|
||||
.revision = 6,
|
||||
};
|
||||
|
||||
#define PIT_BASE_FREQUENCY 1193182
|
||||
|
||||
#define PIT_COMMAND_PORT 0x43
|
||||
#define PIT_CHANNEL0_PORT 0x40
|
||||
|
||||
volatile uint64_t g_Ticks = 0;
|
||||
volatile uint64_t ticks = 0;
|
||||
uint64_t g_Unixseconds = 0;
|
||||
|
||||
/* ========================= */
|
||||
/* IRQ0 Handler (Timer Tick) */
|
||||
/* ========================= */
|
||||
void PIT_IRQ_Handler(Registers* regs)
|
||||
{
|
||||
(void)regs;
|
||||
g_Ticks++;
|
||||
ticks++;
|
||||
if (ticks >= 1000) {
|
||||
g_Unixseconds++;
|
||||
ticks = 0;
|
||||
}
|
||||
|
||||
|
||||
// You can add scheduler / time logic here later
|
||||
}
|
||||
|
||||
/* ========================= */
|
||||
/* Initialize PIT */
|
||||
/* ========================= */
|
||||
void x86_64_PIT_Initialize(uint32_t frequency)
|
||||
{
|
||||
uint16_t divisor = (uint16_t)(PIT_BASE_FREQUENCY / frequency);
|
||||
|
||||
printf("PIT divisor = %u\n", divisor);
|
||||
// Send command byte:
|
||||
// Channel 0 | lobyte/hibyte | mode 3 (square wave) | binary
|
||||
x86_64_outb(PIT_COMMAND_PORT, 0x36);
|
||||
|
||||
// Send divisor (low byte then high byte)
|
||||
x86_64_outb(PIT_CHANNEL0_PORT, divisor & 0xFF);
|
||||
x86_64_outb(PIT_CHANNEL0_PORT, (divisor >> 8) & 0xFF);
|
||||
|
||||
g_Unixseconds = boot_request.response->timestamp;
|
||||
|
||||
// Register IRQ0 handler (IRQ0 = timer)
|
||||
x86_64_IRQ_RegisterHandler(0, PIT_IRQ_Handler);
|
||||
}
|
||||
|
||||
/* ========================= */
|
||||
/* Get tick count */
|
||||
/* ========================= */
|
||||
uint64_t PIT_GetTicks(void)
|
||||
{
|
||||
return g_Ticks;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "irq.h"
|
||||
#include "io.h"
|
||||
#include <stdint.h>
|
||||
#include "stdio.h"
|
||||
#include "e9.h"
|
||||
|
||||
extern volatile uint64_t g_Ticks;
|
||||
extern uint64_t g_Unixseconds;
|
||||
|
||||
void x86_64_PIT_Initialize(uint32_t frequency);
|
||||
uint64_t PIT_GetTicks(void);
|
||||
void PIT_IRQ_Handler(Registers* regs);
|
||||
+119
-9
@@ -19,6 +19,13 @@
|
||||
#include "arch/x86_64/usermode.h"
|
||||
#include "syscall/syscall.h"
|
||||
#include "fs/vfs.h"
|
||||
#include "time/time.h"
|
||||
#include "arch/x86_64/pit.h"
|
||||
#include <uacpi/uacpi.h>
|
||||
#include <uacpi/event.h>
|
||||
#include <uacpi/sleep.h>
|
||||
#include "arch/x86_64/pci.h"
|
||||
|
||||
|
||||
uintptr_t g_hhdm_offset;
|
||||
#define CPU_STACK_SIZE (64 * 1024)
|
||||
@@ -47,6 +54,13 @@ static volatile struct limine_memmap_request memmap_request = {
|
||||
.revision = 6
|
||||
};
|
||||
|
||||
__attribute__((used, section(".limine_requests")))
|
||||
static volatile struct limine_rsdp_request rsdp_request = {
|
||||
.id = LIMINE_RSDP_REQUEST_ID,
|
||||
.revision = 6
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
__attribute__((used, section(".limine_requests")))
|
||||
@@ -82,7 +96,34 @@ static void hcf(void) {
|
||||
}
|
||||
}
|
||||
|
||||
extern struct kernel_pagemap;
|
||||
uint64_t g_rsdp_phys;
|
||||
|
||||
void shutdown(void) {
|
||||
uacpi_status ret2 = uacpi_prepare_for_sleep_state(UACPI_SLEEP_STATE_S5);
|
||||
if (uacpi_unlikely_error(ret2)) {
|
||||
printf("failed to prepare for sleep: %s", uacpi_status_to_string(ret2));
|
||||
}
|
||||
|
||||
ret2 = uacpi_enter_sleep_state(UACPI_SLEEP_STATE_S5);
|
||||
if (uacpi_unlikely_error(ret2)) {
|
||||
printf("failed to enter sleep: %s", uacpi_status_to_string(ret2));
|
||||
}
|
||||
}
|
||||
|
||||
static uacpi_interrupt_ret handle_power_button(uacpi_handle ctx) {
|
||||
/*
|
||||
* Shut down right here using the helper we have defined above.
|
||||
*
|
||||
* Note that it's generally terrible practice to run any AML from
|
||||
* an interrupt handler, as it's allowed to allocate, map, sleep,
|
||||
* stall, acquire mutexes, etc. So, if possible in your kernel,
|
||||
* instead schedule the shutdown callback to be run in a normal
|
||||
* preemptible context later.
|
||||
*/
|
||||
shutdown();
|
||||
return UACPI_INTERRUPT_HANDLED;
|
||||
}
|
||||
|
||||
// The following will be our kernel's entry point.
|
||||
// If renaming kmain() to something else, make sure to change the
|
||||
@@ -104,9 +145,13 @@ void kmain(void) {
|
||||
|
||||
struct limine_memmap_response *memmap_response = memmap_request.response;
|
||||
|
||||
struct limine_rsdp_response *rsdp_response = rsdp_request.response;
|
||||
|
||||
g_rsdp_phys = (uint64_t)rsdp_response->address - MEM_PHYS_OFFSET;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (!memmap_response) {
|
||||
hcf();
|
||||
@@ -117,6 +162,7 @@ void kmain(void) {
|
||||
fb_width = framebuffer->width;
|
||||
fb_height = framebuffer->height;
|
||||
fb_pitch = framebuffer->pitch / 4;
|
||||
|
||||
|
||||
|
||||
printf("Hello, Kernel!\n");
|
||||
@@ -135,23 +181,29 @@ void kmain(void) {
|
||||
|
||||
|
||||
|
||||
/*uint32_t msr_lo, msr_hi;
|
||||
uint32_t msr_lo, msr_hi;
|
||||
asm volatile("rdmsr" : "=a"(msr_lo), "=d"(msr_hi) : "c"(0x1B));
|
||||
msr_lo &= ~(1 << 11);
|
||||
asm volatile("wrmsr" : : "a"(msr_lo), "d"(msr_hi), "c"(0x1B));*/
|
||||
printf("init pmm");
|
||||
asm volatile("wrmsr" : : "a"(msr_lo), "d"(msr_hi), "c"(0x1B));
|
||||
printf("rsdp: 0x%x\n", g_rsdp_phys);
|
||||
printf("init pmm\n");
|
||||
pmm_init(memmap_response->entries, memmap_response->entry_count);
|
||||
printf("init slab");
|
||||
printf("init slab\n");
|
||||
slab_init();
|
||||
printf("init vmm");
|
||||
printf("init vmm\n");
|
||||
vmm_init(memmap_response->entries, memmap_response->entry_count);
|
||||
|
||||
printf("init gdt");
|
||||
x86_64_GDT_Initialize();
|
||||
x86_64_IDT_Initialize();
|
||||
x86_64_ISR_Initialize();
|
||||
x86_64_IRQ_Initialize();
|
||||
x86_64_EnableInterrupts();
|
||||
//lapic_timer_start(100);
|
||||
x86_64_PIT_Initialize(1000);
|
||||
asm volatile("sti");
|
||||
calibrate_tsc();
|
||||
|
||||
|
||||
//while (1) asm volatile("hlt");
|
||||
|
||||
ata_init();
|
||||
ata_identify();
|
||||
@@ -327,10 +379,68 @@ void kmain(void) {
|
||||
printf("\nKirkOS %s\n", KIRKOS_VERSION);
|
||||
|
||||
x86_64_EnableInterrupts();
|
||||
syscall_init();
|
||||
start_userspace();
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Start with this as the first step of the initialization. This loads all
|
||||
* tables, brings the event subsystem online, and enters ACPI mode. We pass
|
||||
* in 0 as the flags as we don't want to override any default behavior for now.
|
||||
*/
|
||||
uacpi_status ret = uacpi_initialize(0);
|
||||
if (uacpi_unlikely_error(ret)) {
|
||||
printf("uacpi_initialize error: %s", uacpi_status_to_string(ret));
|
||||
}
|
||||
|
||||
/*
|
||||
* Load the AML namespace. This feeds DSDT and all SSDTs to the interpreter
|
||||
* for execution.
|
||||
*/
|
||||
ret = uacpi_namespace_load();
|
||||
if (uacpi_unlikely_error(ret)) {
|
||||
printf("uacpi_namespace_load error: %s", uacpi_status_to_string(ret));
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the namespace. This calls all necessary _STA/_INI AML methods,
|
||||
* as well as _REG for registered operation region handlers.
|
||||
*/
|
||||
ret = uacpi_namespace_initialize();
|
||||
if (uacpi_unlikely_error(ret)) {
|
||||
printf("uacpi_namespace_initialize error: %s", uacpi_status_to_string(ret));
|
||||
}
|
||||
|
||||
/*
|
||||
* Tell uACPI that we have marked all GPEs we wanted for wake (even though we haven't
|
||||
* actually marked any, as we have no power management support right now). This is
|
||||
* needed to let uACPI enable all unmarked GPEs that have a corresponding AML handler.
|
||||
* These handlers are used by the firmware to dynamically execute AML code at runtime
|
||||
* to e.g. react to thermal events or device hotplug.
|
||||
*/
|
||||
ret = uacpi_finalize_gpe_initialization();
|
||||
if (uacpi_unlikely_error(ret)) {
|
||||
printf("uACPI GPE initialization error: %s", uacpi_status_to_string(ret));
|
||||
}
|
||||
|
||||
|
||||
pci_init();
|
||||
|
||||
pci_device_t hda;
|
||||
if (pci_find_hda(&hda)) {
|
||||
printf("[PCI] Found HDA controller at %02x:%02x.%x %04x:%04x\n",
|
||||
hda.addr.bus, hda.addr.device, hda.addr.function,
|
||||
hda.vendor_id, hda.device_id);
|
||||
// BAR0 is usually at hda.bar[0] & ~0xF (MMIO)
|
||||
} else {
|
||||
printf("[PCI] No HDA controller found!\n");
|
||||
}
|
||||
|
||||
|
||||
//syscall_init();
|
||||
//start_userspace();
|
||||
printf("tst");
|
||||
|
||||
|
||||
// We're done, just hang...
|
||||
hcf();
|
||||
}
|
||||
+35
-7
@@ -279,17 +279,45 @@ level4:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// spinlock_drop(&pagemap->lock);
|
||||
spinlock_drop(&pagemap->lock);
|
||||
return &pml1[pml1_entry];
|
||||
}
|
||||
|
||||
|
||||
uint64_t vmm_virt_to_phys(struct pagemap *pagemap, uint64_t virt) {
|
||||
spinlock_acquire_or_wait(&pagemap->lock);
|
||||
uint64_t *pte = vmm_virt_to_pte(pagemap, virt, false);
|
||||
spinlock_drop(&pagemap->lock);
|
||||
if (pte == NULL || (((*pte) & ~0xffffffffff000) & 1) == 0)
|
||||
return INVALID_PHYS;
|
||||
spinlock_acquire_or_wait(&pagemap->lock);
|
||||
|
||||
return ((*pte) & 0xffffffffff000);
|
||||
size_t pml4_entry = (virt & ((uint64_t)0x1FF << 39)) >> 39;
|
||||
size_t pml3_entry = (virt & ((uint64_t)0x1FF << 30)) >> 30;
|
||||
size_t pml2_entry = (virt & ((uint64_t)0x1FF << 21)) >> 21;
|
||||
size_t pml1_entry = (virt & ((uint64_t)0x1FF << 12)) >> 12;
|
||||
|
||||
uint64_t *pml4 = pagemap->top_level;
|
||||
|
||||
uint64_t *pml3 = get_next_level(pml4, pml4_entry, false);
|
||||
if (!pml3) goto fail;
|
||||
|
||||
uint64_t *pml2 = get_next_level(pml3, pml3_entry, false);
|
||||
if (!pml2) goto fail;
|
||||
|
||||
// Check for 2MiB huge page (PS bit = bit 7)
|
||||
if (pml2[pml2_entry] & (1 << 7)) {
|
||||
uint64_t phys = (pml2[pml2_entry] & ~0x1FFFFFULL) // 2MiB-aligned base
|
||||
+ (virt & 0x1FFFFFULL); // + offset within 2MiB
|
||||
spinlock_drop(&pagemap->lock);
|
||||
return phys;
|
||||
}
|
||||
|
||||
uint64_t *pml1 = get_next_level(pml2, pml2_entry, false);
|
||||
if (!pml1 || !(pml1[pml1_entry] & 1)) goto fail;
|
||||
|
||||
uint64_t phys = (pml1[pml1_entry] & 0x000ffffffffff000ULL)
|
||||
+ (virt & 0xFFFULL);
|
||||
spinlock_drop(&pagemap->lock);
|
||||
return phys;
|
||||
|
||||
fail:
|
||||
spinlock_drop(&pagemap->lock);
|
||||
printf("Invalid Phys!\n");
|
||||
return INVALID_PHYS;
|
||||
}
|
||||
+283
-49
@@ -5,6 +5,8 @@
|
||||
#include "video/render.h"
|
||||
#include "arch/x86_64/e9.h"
|
||||
#include "mp/spinlock.h"
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
|
||||
static const uint32_t g_LogSeverityColors[] =
|
||||
{
|
||||
@@ -17,7 +19,26 @@ static const uint32_t g_LogSeverityColors[] =
|
||||
|
||||
static spinlock_t s_printf_lock = SPINLOCK_INIT;
|
||||
|
||||
typedef struct {
|
||||
char* buf;
|
||||
size_t size;
|
||||
size_t pos;
|
||||
} snprintf_ctx_t;
|
||||
|
||||
static void buf_putc(snprintf_ctx_t* ctx, char c)
|
||||
{
|
||||
if (ctx->pos + 1 < ctx->size) {
|
||||
ctx->buf[ctx->pos] = c;
|
||||
}
|
||||
ctx->pos++;
|
||||
}
|
||||
|
||||
static void buf_puts(snprintf_ctx_t* ctx, const char* str)
|
||||
{
|
||||
while (*str) {
|
||||
buf_putc(ctx, *str++);
|
||||
}
|
||||
}
|
||||
|
||||
void fputc(char c)
|
||||
{
|
||||
@@ -38,7 +59,7 @@ void fputs_colored(const char* str, uint32_t color) {
|
||||
|
||||
const char g_HexChars[] = "0123456789abcdef";
|
||||
|
||||
void fprintf_unsigned(uint64_t number, int radix)
|
||||
static void buf_print_unsigned(snprintf_ctx_t* ctx, uint64_t number, int radix, int width, int zero_pad)
|
||||
{
|
||||
char buffer[32];
|
||||
int pos = 0;
|
||||
@@ -48,73 +69,286 @@ void fprintf_unsigned(uint64_t number, int radix)
|
||||
number /= radix;
|
||||
} while (number > 0);
|
||||
|
||||
while (--pos >= 0) fputc(buffer[pos]);
|
||||
// Apply zero-padding / width
|
||||
if (zero_pad) {
|
||||
while (pos < width)
|
||||
buffer[pos++] = '0';
|
||||
}
|
||||
|
||||
while (--pos >= 0)
|
||||
buf_putc(ctx, buffer[pos]);
|
||||
}
|
||||
|
||||
void fprintf_signed(int64_t number, int radix)
|
||||
static void buf_print_signed(snprintf_ctx_t* ctx, int64_t number, int radix, int width, int zero_pad)
|
||||
{
|
||||
if (number < 0) {
|
||||
fputc('-');
|
||||
fprintf_unsigned(-number, radix);
|
||||
buf_putc(ctx, '-');
|
||||
buf_print_unsigned(ctx, (uint64_t)(-number), radix, width, zero_pad);
|
||||
} else {
|
||||
fprintf_unsigned(number, radix);
|
||||
buf_print_unsigned(ctx, (uint64_t)number, radix, width, zero_pad);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int snprintf(char* buf, size_t size, const char* fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int ret = vsnprintf(buf, size, fmt, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void fprintf_unsigned(uint64_t number, int radix, int width, int zero_pad)
|
||||
{
|
||||
char buffer[32];
|
||||
int pos = 0;
|
||||
|
||||
do {
|
||||
buffer[pos++] = g_HexChars[number % radix];
|
||||
number /= radix;
|
||||
} while (number > 0);
|
||||
|
||||
if (zero_pad) {
|
||||
while (pos < width)
|
||||
buffer[pos++] = '0';
|
||||
}
|
||||
|
||||
while (--pos >= 0)
|
||||
fputc(buffer[pos]);
|
||||
}
|
||||
|
||||
static void fprintf_signed(int64_t number, int radix, int width, int zero_pad)
|
||||
{
|
||||
if (number < 0) {
|
||||
fputc('-');
|
||||
fprintf_unsigned((uint64_t)(-number), radix, width, zero_pad);
|
||||
} else {
|
||||
fprintf_unsigned((uint64_t)number, radix, width, zero_pad);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void vfprintf(const char* fmt, va_list args)
|
||||
{
|
||||
int state = 0; // normal
|
||||
int length = 0; // default
|
||||
int radix = 10;
|
||||
bool sign = false;
|
||||
bool number = false;
|
||||
|
||||
while (*fmt) {
|
||||
switch (state) {
|
||||
case 0: // normal
|
||||
if (*fmt == '%') state = 1;
|
||||
else fputc(*fmt);
|
||||
break;
|
||||
if (*fmt != '%') {
|
||||
fputc(*fmt++);
|
||||
continue;
|
||||
}
|
||||
fmt++; // skip %
|
||||
|
||||
case 1: // length
|
||||
if (*fmt == 'l') { length = 3; state = 4; }
|
||||
else if (*fmt == 'h') { length = 2; state = 4; }
|
||||
else goto spec;
|
||||
break;
|
||||
|
||||
case 4: // spec
|
||||
spec:
|
||||
switch (*fmt) {
|
||||
case 'c': fputc((char)va_arg(args,int)); break;
|
||||
case 's': fputs(va_arg(args,const char*)); break;
|
||||
case 'd':
|
||||
case 'i': sign = true; number = true; radix = 10; break;
|
||||
case 'u': sign = false; number = true; radix = 10; break;
|
||||
case 'x':
|
||||
case 'X': sign = false; number = true; radix = 16; break;
|
||||
case 'p': number = true; sign = false; radix = 16; break;
|
||||
case 'o': sign = false; number = true; radix = 8; break;
|
||||
case '%': fputc('%'); break;
|
||||
}
|
||||
|
||||
if (number) {
|
||||
if (sign) fprintf_signed(va_arg(args,long), radix);
|
||||
else fprintf_unsigned(va_arg(args,unsigned long), radix);
|
||||
}
|
||||
|
||||
state = 0;
|
||||
length = 0;
|
||||
number = false;
|
||||
sign = false;
|
||||
break;
|
||||
/* flags */
|
||||
int zero_pad = 0;
|
||||
if (*fmt == '0') {
|
||||
zero_pad = 1;
|
||||
fmt++;
|
||||
}
|
||||
|
||||
fmt++;
|
||||
/* width */
|
||||
int width = 0;
|
||||
while (*fmt >= '0' && *fmt <= '9') {
|
||||
width = width * 10 + (*fmt++ - '0');
|
||||
}
|
||||
|
||||
/* precision */
|
||||
int precision = -1;
|
||||
if (*fmt == '.') {
|
||||
fmt++;
|
||||
precision = 0;
|
||||
while (*fmt >= '0' && *fmt <= '9') {
|
||||
precision = precision * 10 + (*fmt++ - '0');
|
||||
}
|
||||
}
|
||||
|
||||
/* length modifier */
|
||||
int is_long_long = 0;
|
||||
if (*fmt == 'l') {
|
||||
fmt++;
|
||||
if (*fmt == 'l') {
|
||||
is_long_long = 1;
|
||||
fmt++;
|
||||
}
|
||||
} else if (*fmt == 'z') { // %zu, %zx
|
||||
is_long_long = 1;
|
||||
fmt++;
|
||||
} else if (*fmt == 'h') {
|
||||
fmt++; // ignore h/hh
|
||||
}
|
||||
|
||||
/* specifier */
|
||||
switch (*fmt++) {
|
||||
case 'c':
|
||||
fputc((char)va_arg(args, int));
|
||||
break;
|
||||
|
||||
case 's': {
|
||||
const char* s = va_arg(args, const char*);
|
||||
if (!s) s = "(null)";
|
||||
if (precision >= 0) {
|
||||
while (*s && precision--) fputc(*s++);
|
||||
} else {
|
||||
fputs(s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'd':
|
||||
case 'i':
|
||||
if (is_long_long)
|
||||
fprintf_signed(va_arg(args, long long), 10, width, zero_pad);
|
||||
else
|
||||
fprintf_signed(va_arg(args, long), 10, width, zero_pad);
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
if (is_long_long)
|
||||
fprintf_unsigned(va_arg(args, unsigned long long), 10, width, zero_pad);
|
||||
else
|
||||
fprintf_unsigned(va_arg(args, unsigned long), 10, width, zero_pad);
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
case 'X':
|
||||
if (is_long_long)
|
||||
fprintf_unsigned(va_arg(args, unsigned long long), 16, width, zero_pad);
|
||||
else
|
||||
fprintf_unsigned(va_arg(args, unsigned long), 16, width, zero_pad);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
fputs("0x");
|
||||
fprintf_unsigned(va_arg(args, uint64_t), 16, 16, 1); // always full 64-bit
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
if (is_long_long)
|
||||
fprintf_unsigned(va_arg(args, unsigned long long), 8, width, zero_pad);
|
||||
else
|
||||
fprintf_unsigned(va_arg(args, unsigned long), 8, width, zero_pad);
|
||||
break;
|
||||
|
||||
case '%':
|
||||
fputc('%');
|
||||
break;
|
||||
|
||||
default:
|
||||
fputc('%');
|
||||
fputc(*(fmt - 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int vsnprintf(char* buf, size_t size, const char* fmt, va_list args)
|
||||
{
|
||||
snprintf_ctx_t ctx = { .buf = buf, .size = size, .pos = 0 };
|
||||
|
||||
while (*fmt) {
|
||||
if (*fmt != '%') {
|
||||
buf_putc(&ctx, *fmt++);
|
||||
continue;
|
||||
}
|
||||
fmt++;
|
||||
|
||||
int zero_pad = 0;
|
||||
if (*fmt == '0') { zero_pad = 1; fmt++; }
|
||||
|
||||
int width = 0;
|
||||
while (*fmt >= '0' && *fmt <= '9') {
|
||||
width = width * 10 + (*fmt++ - '0');
|
||||
}
|
||||
|
||||
int precision = -1;
|
||||
if (*fmt == '.') {
|
||||
fmt++;
|
||||
precision = 0;
|
||||
while (*fmt >= '0' && *fmt <= '9') {
|
||||
precision = precision * 10 + (*fmt++ - '0');
|
||||
}
|
||||
}
|
||||
|
||||
int is_long_long = 0;
|
||||
if (*fmt == 'l') {
|
||||
fmt++;
|
||||
if (*fmt == 'l') { is_long_long = 1; fmt++; }
|
||||
} else if (*fmt == 'z') {
|
||||
is_long_long = 1;
|
||||
fmt++;
|
||||
} else if (*fmt == 'h') {
|
||||
fmt++;
|
||||
}
|
||||
|
||||
switch (*fmt++) {
|
||||
case 'c':
|
||||
buf_putc(&ctx, (char)va_arg(args, int));
|
||||
break;
|
||||
|
||||
case 's': {
|
||||
const char* s = va_arg(args, const char*);
|
||||
if (!s) s = "(null)";
|
||||
int max = (precision >= 0) ? precision : INT_MAX;
|
||||
while (*s && max--) buf_putc(&ctx, *s++);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'd':
|
||||
case 'i':
|
||||
if (is_long_long)
|
||||
buf_print_signed(&ctx, va_arg(args, long long), 10, width, zero_pad);
|
||||
else
|
||||
buf_print_signed(&ctx, va_arg(args, long), 10, width, zero_pad);
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
if (is_long_long)
|
||||
buf_print_unsigned(&ctx, va_arg(args, unsigned long long), 10, width, zero_pad);
|
||||
else
|
||||
buf_print_unsigned(&ctx, va_arg(args, unsigned long), 10, width, zero_pad);
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
case 'X':
|
||||
if (is_long_long)
|
||||
buf_print_unsigned(&ctx, va_arg(args, unsigned long long), 16, width, zero_pad);
|
||||
else
|
||||
buf_print_unsigned(&ctx, va_arg(args, unsigned long), 16, width, zero_pad);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
buf_puts(&ctx, "0x");
|
||||
buf_print_unsigned(&ctx, va_arg(args, uint64_t), 16, 16, 1);
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
if (is_long_long)
|
||||
buf_print_unsigned(&ctx, va_arg(args, unsigned long long), 8, width, zero_pad);
|
||||
else
|
||||
buf_print_unsigned(&ctx, va_arg(args, unsigned long), 8, width, zero_pad);
|
||||
break;
|
||||
|
||||
case '%':
|
||||
buf_putc(&ctx, '%');
|
||||
break;
|
||||
|
||||
default:
|
||||
buf_putc(&ctx, '%');
|
||||
buf_putc(&ctx, *(fmt - 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.size > 0) {
|
||||
if (ctx.pos < ctx.size)
|
||||
ctx.buf[ctx.pos] = '\0';
|
||||
else
|
||||
ctx.buf[ctx.size - 1] = '\0';
|
||||
}
|
||||
|
||||
return (int)ctx.pos;
|
||||
}
|
||||
|
||||
void printf(const char* fmt, ...)
|
||||
{
|
||||
uint64_t flags;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
void printf(const char* fmt, ...);
|
||||
void fputs(const char* str);
|
||||
@@ -8,3 +9,5 @@ void fputc(char c);
|
||||
void vfprintf(const char* fmt, va_list args);
|
||||
void fprintf(const char* fmt, ...);
|
||||
void fputs_colored(const char* str, uint32_t color);
|
||||
int snprintf(char* buf, size_t size, const char* fmt, ...);
|
||||
int vsnprintf(char* buf, size_t size, const char* fmt, va_list args);
|
||||
@@ -100,6 +100,19 @@ char* strcat(char* dst, const char* src)
|
||||
return origDst;
|
||||
}
|
||||
|
||||
size_t strnlen(const char* str, size_t maxlen)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
||||
if (!str)
|
||||
return 0;
|
||||
|
||||
while (len < maxlen && str[len])
|
||||
++len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
char* strncpy(char* dst, const char* src, size_t n)
|
||||
{
|
||||
char* origDst = dst;
|
||||
|
||||
+2
-1
@@ -9,4 +9,5 @@ char* strncpy(char* dst, const char* src, size_t n);
|
||||
char* strcat(char* dst, const char* src);
|
||||
int strncmp(const char* a, const char* b, size_t n);
|
||||
wchar_t* utf16_to_codepoint(wchar_t* string, int* codepoint);
|
||||
char* codepoint_to_utf8(int codepoint, char* stringOutput);
|
||||
char* codepoint_to_utf8(int codepoint, char* stringOutput);
|
||||
size_t strnlen(const char* str, size_t maxlen);
|
||||
@@ -0,0 +1,50 @@
|
||||
#include <stdint.h>
|
||||
#include "arch/x86_64/pit.h"
|
||||
#include "arch/x86_64/io.h"
|
||||
#include "stdio.h"
|
||||
#include "time.h"
|
||||
|
||||
extern uint64_t PIT_GetTicks(void);
|
||||
|
||||
volatile uint64_t tsc_cycles_per_us = 0;
|
||||
|
||||
uint64_t rdtsc(void)
|
||||
{
|
||||
uint32_t lo, hi;
|
||||
__asm__ volatile ("rdtsc" : "=a"(lo), "=d"(hi));
|
||||
return ((uint64_t)hi << 32) | lo;
|
||||
}
|
||||
|
||||
|
||||
void calibrate_tsc(void)
|
||||
{
|
||||
// Use a stable PIT rate for calibration
|
||||
const uint32_t pit_freq = 1000; // 100 Hz = 10ms per tick
|
||||
const uint32_t calibration_ticks = 1000; // 1 second total
|
||||
|
||||
|
||||
|
||||
// Wait for PIT to stabilize
|
||||
uint64_t start_ticks = PIT_GetTicks();
|
||||
while (PIT_GetTicks() == start_ticks)
|
||||
;
|
||||
|
||||
uint64_t start_tsc = rdtsc();
|
||||
uint64_t target_ticks = start_ticks + calibration_ticks;
|
||||
|
||||
// Wait for known number of PIT ticks
|
||||
while (PIT_GetTicks() < target_ticks)
|
||||
;
|
||||
|
||||
uint64_t end_tsc = rdtsc();
|
||||
|
||||
// Compute elapsed time
|
||||
uint64_t tsc_delta = end_tsc - start_tsc;
|
||||
|
||||
// 100 ticks at 100 Hz = 1 second = 1,000,000 microseconds
|
||||
uint64_t elapsed_us = 1000000ULL;
|
||||
|
||||
tsc_cycles_per_us = tsc_delta / elapsed_us;
|
||||
|
||||
printf("TSC calibration complete: %lu cycles/us\n", tsc_cycles_per_us);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#include <stdint.h>
|
||||
#include "arch/x86_64/pit.h"
|
||||
#include "arch/x86_64/io.h"
|
||||
#include "stdio.h"
|
||||
|
||||
uint64_t rdtsc(void);
|
||||
|
||||
|
||||
|
||||
void calibrate_tsc(void);
|
||||
Reference in New Issue
Block a user