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}"
|
"${VERSION}.${PATCHLEVEL}.${SUBLEVEL}${EXTRAVERSION}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
include(${CMAKE_SOURCE_DIR}/libs/uacpi/uacpi.cmake)
|
||||||
|
|
||||||
message(STATUS "Building KirkOS version: ${KIRKOS_VERSION_STRING}")
|
message(STATUS "Building KirkOS version: ${KIRKOS_VERSION_STRING}")
|
||||||
|
|
||||||
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
|
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})
|
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
|
target_compile_definitions(KirkOS PRIVATE
|
||||||
KIRKOS_VERSION="${KIRKOS_VERSION_STRING}"
|
KIRKOS_VERSION="${KIRKOS_VERSION_STRING}"
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#include "pic.h"
|
#include "pic.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define PIC1_COMMAND_PORT 0x20
|
#define PIC1_COMMAND_PORT 0x20
|
||||||
#define PIC1_DATA_PORT 0x21
|
#define PIC1_DATA_PORT 0x21
|
||||||
|
|||||||
@@ -52,11 +52,12 @@ void x86_64_IRQ_Initialize(void)
|
|||||||
log_info(MODULE, "Found %s PIC.", g_Driver->Name);
|
log_info(MODULE, "Found %s PIC.", g_Driver->Name);
|
||||||
g_Driver->Initialize(PIC_REMAP_OFFSET, PIC_REMAP_OFFSET + 8, false);
|
g_Driver->Initialize(PIC_REMAP_OFFSET, PIC_REMAP_OFFSET + 8, false);
|
||||||
|
|
||||||
|
|
||||||
// register ISR handlers for each of the 16 irq lines
|
// register ISR handlers for each of the 16 irq lines
|
||||||
for (int i = 0; i < 16; i++)
|
for (int i = 0; i < 16; i++)
|
||||||
x86_64_ISR_RegisterHandler(PIC_REMAP_OFFSET + i, x86_64_IRQ_Handler);
|
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)
|
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 "arch/x86_64/usermode.h"
|
||||||
#include "syscall/syscall.h"
|
#include "syscall/syscall.h"
|
||||||
#include "fs/vfs.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;
|
uintptr_t g_hhdm_offset;
|
||||||
#define CPU_STACK_SIZE (64 * 1024)
|
#define CPU_STACK_SIZE (64 * 1024)
|
||||||
@@ -47,6 +54,13 @@ static volatile struct limine_memmap_request memmap_request = {
|
|||||||
.revision = 6
|
.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")))
|
__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.
|
// The following will be our kernel's entry point.
|
||||||
// If renaming kmain() to something else, make sure to change the
|
// If renaming kmain() to something else, make sure to change the
|
||||||
@@ -104,6 +145,10 @@ void kmain(void) {
|
|||||||
|
|
||||||
struct limine_memmap_response *memmap_response = memmap_request.response;
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -119,6 +164,7 @@ void kmain(void) {
|
|||||||
fb_pitch = framebuffer->pitch / 4;
|
fb_pitch = framebuffer->pitch / 4;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
printf("Hello, Kernel!\n");
|
printf("Hello, Kernel!\n");
|
||||||
printf("Number: %d\n", 1234);
|
printf("Number: %d\n", 1234);
|
||||||
printf("Hex: %x\n", 0xBEEF);
|
printf("Hex: %x\n", 0xBEEF);
|
||||||
@@ -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));
|
asm volatile("rdmsr" : "=a"(msr_lo), "=d"(msr_hi) : "c"(0x1B));
|
||||||
msr_lo &= ~(1 << 11);
|
msr_lo &= ~(1 << 11);
|
||||||
asm volatile("wrmsr" : : "a"(msr_lo), "d"(msr_hi), "c"(0x1B));*/
|
asm volatile("wrmsr" : : "a"(msr_lo), "d"(msr_hi), "c"(0x1B));
|
||||||
printf("init pmm");
|
printf("rsdp: 0x%x\n", g_rsdp_phys);
|
||||||
|
printf("init pmm\n");
|
||||||
pmm_init(memmap_response->entries, memmap_response->entry_count);
|
pmm_init(memmap_response->entries, memmap_response->entry_count);
|
||||||
printf("init slab");
|
printf("init slab\n");
|
||||||
slab_init();
|
slab_init();
|
||||||
printf("init vmm");
|
printf("init vmm\n");
|
||||||
vmm_init(memmap_response->entries, memmap_response->entry_count);
|
vmm_init(memmap_response->entries, memmap_response->entry_count);
|
||||||
|
|
||||||
printf("init gdt");
|
printf("init gdt");
|
||||||
x86_64_GDT_Initialize();
|
x86_64_GDT_Initialize();
|
||||||
x86_64_IDT_Initialize();
|
x86_64_IDT_Initialize();
|
||||||
x86_64_ISR_Initialize();
|
x86_64_ISR_Initialize();
|
||||||
x86_64_IRQ_Initialize();
|
x86_64_IRQ_Initialize();
|
||||||
x86_64_EnableInterrupts();
|
x86_64_PIT_Initialize(1000);
|
||||||
//lapic_timer_start(100);
|
asm volatile("sti");
|
||||||
|
calibrate_tsc();
|
||||||
|
|
||||||
|
|
||||||
|
//while (1) asm volatile("hlt");
|
||||||
|
|
||||||
ata_init();
|
ata_init();
|
||||||
ata_identify();
|
ata_identify();
|
||||||
@@ -327,10 +379,68 @@ void kmain(void) {
|
|||||||
printf("\nKirkOS %s\n", KIRKOS_VERSION);
|
printf("\nKirkOS %s\n", KIRKOS_VERSION);
|
||||||
|
|
||||||
x86_64_EnableInterrupts();
|
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");
|
printf("tst");
|
||||||
|
|
||||||
|
|
||||||
// We're done, just hang...
|
// We're done, just hang...
|
||||||
hcf();
|
hcf();
|
||||||
}
|
}
|
||||||
+34
-6
@@ -279,17 +279,45 @@ level4:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// spinlock_drop(&pagemap->lock);
|
spinlock_drop(&pagemap->lock);
|
||||||
return &pml1[pml1_entry];
|
return &pml1[pml1_entry];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint64_t vmm_virt_to_phys(struct pagemap *pagemap, uint64_t virt) {
|
uint64_t vmm_virt_to_phys(struct pagemap *pagemap, uint64_t virt) {
|
||||||
spinlock_acquire_or_wait(&pagemap->lock);
|
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;
|
|
||||||
|
|
||||||
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 "video/render.h"
|
||||||
#include "arch/x86_64/e9.h"
|
#include "arch/x86_64/e9.h"
|
||||||
#include "mp/spinlock.h"
|
#include "mp/spinlock.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
static const uint32_t g_LogSeverityColors[] =
|
static const uint32_t g_LogSeverityColors[] =
|
||||||
{
|
{
|
||||||
@@ -17,7 +19,26 @@ static const uint32_t g_LogSeverityColors[] =
|
|||||||
|
|
||||||
static spinlock_t s_printf_lock = SPINLOCK_INIT;
|
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)
|
void fputc(char c)
|
||||||
{
|
{
|
||||||
@@ -38,7 +59,7 @@ void fputs_colored(const char* str, uint32_t color) {
|
|||||||
|
|
||||||
const char g_HexChars[] = "0123456789abcdef";
|
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];
|
char buffer[32];
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
@@ -48,71 +69,284 @@ void fprintf_unsigned(uint64_t number, int radix)
|
|||||||
number /= radix;
|
number /= radix;
|
||||||
} while (number > 0);
|
} while (number > 0);
|
||||||
|
|
||||||
while (--pos >= 0) fputc(buffer[pos]);
|
// Apply zero-padding / width
|
||||||
|
if (zero_pad) {
|
||||||
|
while (pos < width)
|
||||||
|
buffer[pos++] = '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
void fprintf_signed(int64_t number, int radix)
|
while (--pos >= 0)
|
||||||
|
buf_putc(ctx, buffer[pos]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void buf_print_signed(snprintf_ctx_t* ctx, int64_t number, int radix, int width, int zero_pad)
|
||||||
|
{
|
||||||
|
if (number < 0) {
|
||||||
|
buf_putc(ctx, '-');
|
||||||
|
buf_print_unsigned(ctx, (uint64_t)(-number), radix, width, zero_pad);
|
||||||
|
} else {
|
||||||
|
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) {
|
if (number < 0) {
|
||||||
fputc('-');
|
fputc('-');
|
||||||
fprintf_unsigned(-number, radix);
|
fprintf_unsigned((uint64_t)(-number), radix, width, zero_pad);
|
||||||
} else {
|
} else {
|
||||||
fprintf_unsigned(number, radix);
|
fprintf_unsigned((uint64_t)number, radix, width, zero_pad);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void vfprintf(const char* fmt, va_list args)
|
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) {
|
while (*fmt) {
|
||||||
switch (state) {
|
if (*fmt != '%') {
|
||||||
case 0: // normal
|
fputc(*fmt++);
|
||||||
if (*fmt == '%') state = 1;
|
continue;
|
||||||
else fputc(*fmt);
|
|
||||||
break;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
fmt++; // skip %
|
||||||
|
|
||||||
|
/* 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, ...)
|
void printf(const char* fmt, ...)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
void printf(const char* fmt, ...);
|
void printf(const char* fmt, ...);
|
||||||
void fputs(const char* str);
|
void fputs(const char* str);
|
||||||
@@ -8,3 +9,5 @@ void fputc(char c);
|
|||||||
void vfprintf(const char* fmt, va_list args);
|
void vfprintf(const char* fmt, va_list args);
|
||||||
void fprintf(const char* fmt, ...);
|
void fprintf(const char* fmt, ...);
|
||||||
void fputs_colored(const char* str, uint32_t color);
|
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;
|
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* strncpy(char* dst, const char* src, size_t n)
|
||||||
{
|
{
|
||||||
char* origDst = dst;
|
char* origDst = dst;
|
||||||
|
|||||||
@@ -10,3 +10,4 @@ char* strcat(char* dst, const char* src);
|
|||||||
int strncmp(const char* a, const char* b, size_t n);
|
int strncmp(const char* a, const char* b, size_t n);
|
||||||
wchar_t* utf16_to_codepoint(wchar_t* string, int* codepoint);
|
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