LOTS MORE LOGGING. which is great, of course.
This commit is contained in:
parent
0cc3900e88
commit
b4484e951d
@ -15,7 +15,7 @@ ASFLAGS :=
|
|||||||
LDFLAGS := -T$(MOON_DIR)/moon.ld -nostdlib -lgcc -Wl,--build-id=none -z max-page-size=0x1000
|
LDFLAGS := -T$(MOON_DIR)/moon.ld -nostdlib -lgcc -Wl,--build-id=none -z max-page-size=0x1000
|
||||||
|
|
||||||
ifneq ($(MOON_BUILD_STABLE), 1)
|
ifneq ($(MOON_BUILD_STABLE), 1)
|
||||||
CFLAGS := ${CFLAGS} -D_MOON_SUFFIX="$(shell git rev-parse --short HEAD)"
|
CFLAGS := ${CFLAGS} -D_MOON_SUFFIX=-$(shell git rev-parse --short HEAD)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(MOON_BUILD_DEBUG), 1)
|
ifeq ($(MOON_BUILD_DEBUG), 1)
|
||||||
|
@ -17,5 +17,9 @@ namespace ACPI
|
|||||||
|
|
||||||
SDTHeader* GetRSDTOrXSDT();
|
SDTHeader* GetRSDTOrXSDT();
|
||||||
|
|
||||||
|
bool ValidateRSDTOrXSDT(SDTHeader* rootSDT);
|
||||||
|
|
||||||
|
bool IsXSDT(SDTHeader* rootSDT);
|
||||||
|
|
||||||
void* FindTable(SDTHeader* rootSDT, const char* signature);
|
void* FindTable(SDTHeader* rootSDT, const char* signature);
|
||||||
}
|
}
|
@ -15,7 +15,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef _MOON_SUFFIX
|
#ifndef _MOON_SUFFIX
|
||||||
#define MOON_SUFFIX "stable"
|
#define MOON_SUFFIX ""
|
||||||
#else
|
#else
|
||||||
#define MOON_SUFFIX STRINGIZE_VALUE_OF(_MOON_SUFFIX)
|
#define MOON_SUFFIX STRINGIZE_VALUE_OF(_MOON_SUFFIX)
|
||||||
#endif
|
#endif
|
@ -6,6 +6,7 @@ namespace CPU
|
|||||||
{
|
{
|
||||||
const char* get_vendor_string();
|
const char* get_vendor_string();
|
||||||
const char* get_brand_string();
|
const char* get_brand_string();
|
||||||
|
void log_cpu_information();
|
||||||
uint64_t get_feature_bitmask();
|
uint64_t get_feature_bitmask();
|
||||||
uint64_t get_initial_apic_id();
|
uint64_t get_initial_apic_id();
|
||||||
bool has_feature(CPU::Features);
|
bool has_feature(CPU::Features);
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "render/BBRenderer.h"
|
|
||||||
#include "render/Color.h"
|
|
||||||
|
|
||||||
namespace Debug
|
|
||||||
{
|
|
||||||
|
|
||||||
struct DebugStatus
|
|
||||||
{
|
|
||||||
static DebugStatus* the();
|
|
||||||
|
|
||||||
void Init();
|
|
||||||
void ThrowException(int exception);
|
|
||||||
void StartBootStage(Color stage);
|
|
||||||
void PassBootStage(Color stage);
|
|
||||||
void FailBootStage();
|
|
||||||
void DebugTick();
|
|
||||||
void DebugKey(char key);
|
|
||||||
|
|
||||||
private:
|
|
||||||
int x = 0;
|
|
||||||
int y = 0;
|
|
||||||
|
|
||||||
int errx = 0;
|
|
||||||
int erry = 30;
|
|
||||||
|
|
||||||
BBRenderer renderer;
|
|
||||||
|
|
||||||
static DebugStatus s_main;
|
|
||||||
};
|
|
||||||
}
|
|
@ -7,7 +7,9 @@ namespace KernelMemoryManager
|
|||||||
void release_mapping(void* mapping);
|
void release_mapping(void* mapping);
|
||||||
|
|
||||||
void* get_unaligned_mapping(void* physicalAddress);
|
void* get_unaligned_mapping(void* physicalAddress);
|
||||||
|
void* get_unaligned_mappings(void* physicalAddress, uint64_t count);
|
||||||
void release_unaligned_mapping(void* mapping);
|
void release_unaligned_mapping(void* mapping);
|
||||||
|
void release_unaligned_mappings(void* mapping, uint64_t count);
|
||||||
|
|
||||||
void* get_page();
|
void* get_page();
|
||||||
void* get_pages(uint64_t count);
|
void* get_pages(uint64_t count);
|
||||||
|
6
kernel/include/memory/MemoryMap.h
Normal file
6
kernel/include/memory/MemoryMap.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Memory
|
||||||
|
{
|
||||||
|
void walk_memory_map();
|
||||||
|
}
|
@ -1,6 +1,9 @@
|
|||||||
|
#define MODULE "acpi/rsdt"
|
||||||
|
|
||||||
#include "acpi/RSDT.h"
|
#include "acpi/RSDT.h"
|
||||||
#include "bootboot.h"
|
#include "bootboot.h"
|
||||||
#include "log/Address.h"
|
#include "log/Address.h"
|
||||||
|
#include "log/Log.h"
|
||||||
#include "memory/KernelMemoryManager.h"
|
#include "memory/KernelMemoryManager.h"
|
||||||
#include "std/stdio.h"
|
#include "std/stdio.h"
|
||||||
#include "std/string.h"
|
#include "std/string.h"
|
||||||
@ -9,25 +12,93 @@ extern BOOTBOOT bootboot;
|
|||||||
|
|
||||||
ACPI::SDTHeader* ACPI::GetRSDTOrXSDT()
|
ACPI::SDTHeader* ACPI::GetRSDTOrXSDT()
|
||||||
{
|
{
|
||||||
return (SDTHeader*)bootboot.arch.x86_64.acpi_ptr;
|
static void* cache = nullptr;
|
||||||
|
if (cache) return (SDTHeader*)cache;
|
||||||
|
kinfoln("First time accessing the RSDT/XSDT, mapping it into memory");
|
||||||
|
void* physical = (void*)bootboot.arch.x86_64.acpi_ptr;
|
||||||
|
uint64_t offset = (uint64_t)physical % 4096;
|
||||||
|
kinfoln("RSDT/XSDT physical address: %lx", (uint64_t)physical);
|
||||||
|
cache = KernelMemoryManager::get_unaligned_mapping(physical);
|
||||||
|
uint64_t numPages = 1;
|
||||||
|
while ((offset + ((SDTHeader*)cache)->Length) > (numPages * 4096))
|
||||||
|
{
|
||||||
|
kinfoln("RSDT/XSDT extends beyond the mapped page, mapping one more page");
|
||||||
|
KernelMemoryManager::release_unaligned_mappings(cache, numPages);
|
||||||
|
numPages++;
|
||||||
|
cache = KernelMemoryManager::get_unaligned_mappings(cache, numPages);
|
||||||
|
}
|
||||||
|
kinfoln("Mapped RSDT/XSDT to virtual address %lx, uses %ld pages", (uint64_t)cache, numPages);
|
||||||
|
SDTHeader* result = (SDTHeader*)cache;
|
||||||
|
char OEMID[7];
|
||||||
|
memcpy(OEMID, result->OEMID, 6);
|
||||||
|
OEMID[6] = 0;
|
||||||
|
kinfoln("OEMID: %s", OEMID);
|
||||||
|
char OEMTableID[9];
|
||||||
|
memcpy(OEMTableID, result->OEMTableID, 8);
|
||||||
|
OEMTableID[8] = 0;
|
||||||
|
kinfoln("OEMTableID: %s", OEMTableID);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ACPI::ValidateRSDTOrXSDT(ACPI::SDTHeader* rootSDT)
|
||||||
|
{
|
||||||
|
if (!ValidateSDTHeader(rootSDT)) return false;
|
||||||
|
if (strncmp(rootSDT->Signature, "XSDT", 4) == 0) return true;
|
||||||
|
if (strncmp(rootSDT->Signature, "RSDT", 4) == 0) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ACPI::IsXSDT(ACPI::SDTHeader* rootSDT)
|
||||||
|
{
|
||||||
|
return strncmp(rootSDT->Signature, "XSDT", 4) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* ACPI::FindTable(ACPI::SDTHeader* rootSDT, const char* signature)
|
void* ACPI::FindTable(ACPI::SDTHeader* rootSDT, const char* signature)
|
||||||
{
|
{
|
||||||
bool isXSDT = (strncmp(rootSDT->Signature, "XSDT", 4) == 0);
|
bool isXSDT = (strncmp(rootSDT->Signature, "XSDT", 4) == 0);
|
||||||
int entries = (rootSDT->Length - sizeof(SDTHeader)) / (isXSDT ? 8 : 4);
|
int entries = (rootSDT->Length - sizeof(SDTHeader)) / (isXSDT ? 8 : 4);
|
||||||
|
kinfoln("Searching for table %s in the %s at %lx (table contains %d entries)", signature, isXSDT ? "XSDT" : "RSDT",
|
||||||
|
(uint64_t)rootSDT, entries);
|
||||||
|
|
||||||
for (int i = 0; i < entries; i++)
|
for (int i = 0; i < entries; i++)
|
||||||
{
|
{
|
||||||
|
kinfoln("Testing for table %s in entry %d", signature, i);
|
||||||
SDTHeader* h;
|
SDTHeader* h;
|
||||||
if (isXSDT) h = (SDTHeader*)((XSDT*)rootSDT)->PointerToOtherSDT[i];
|
if (isXSDT)
|
||||||
|
{
|
||||||
|
uint64_t reversedAddress = (uint64_t)((XSDT*)rootSDT)->PointerToOtherSDT[i];
|
||||||
|
uint64_t correctAddress = reversedAddress >> 32 | reversedAddress << 32;
|
||||||
|
h = (SDTHeader*)correctAddress;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
uint32_t entry = ((RSDT*)rootSDT)->PointerToOtherSDT[i];
|
uint32_t entry = ((RSDT*)rootSDT)->PointerToOtherSDT[i];
|
||||||
h = (SDTHeader*)(uint64_t)entry;
|
h = (SDTHeader*)(uint64_t)entry;
|
||||||
}
|
}
|
||||||
|
if (!h)
|
||||||
|
{
|
||||||
|
kinfoln("Entry points to null");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
kinfoln("Physical address of entry: %lx", (uint64_t)h);
|
||||||
SDTHeader* realHeader = (SDTHeader*)KernelMemoryManager::get_unaligned_mapping(h);
|
SDTHeader* realHeader = (SDTHeader*)KernelMemoryManager::get_unaligned_mapping(h);
|
||||||
if (strncmp(h->Signature, signature, 4) == 0) return (void*)h;
|
kinfoln("Mapped entry to virtual address %lx", (uint64_t)realHeader);
|
||||||
|
if (!ValidateSDTHeader(realHeader))
|
||||||
|
{
|
||||||
|
kinfoln("Header is not valid, skipping this entry");
|
||||||
|
KernelMemoryManager::release_unaligned_mapping(realHeader);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
char tableSignature[5];
|
||||||
|
memcpy(tableSignature, h->Signature, 4);
|
||||||
|
tableSignature[4] = 0;
|
||||||
|
kinfoln("Comparing target signature (%s) to signature of entry (%s)", signature, tableSignature);
|
||||||
|
if (strncmp(h->Signature, signature, 4) == 0)
|
||||||
|
{
|
||||||
|
kinfoln("Found table %s", signature);
|
||||||
|
return (void*)realHeader;
|
||||||
|
}
|
||||||
|
kinfoln("Signatures do not match, unmapping entry and continuing");
|
||||||
KernelMemoryManager::release_unaligned_mapping(realHeader);
|
KernelMemoryManager::release_unaligned_mapping(realHeader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
|
#define MODULE "cpuid"
|
||||||
|
|
||||||
#include "cpu/CPU.h"
|
#include "cpu/CPU.h"
|
||||||
|
#include "log/Log.h"
|
||||||
#include <cpuid.h>
|
#include <cpuid.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@ -80,3 +83,9 @@ uint64_t CPU::get_initial_apic_id()
|
|||||||
__get_cpuid(1, &unused, &ebx, &unused, &unused);
|
__get_cpuid(1, &unused, &ebx, &unused, &unused);
|
||||||
return ebx >> 24;
|
return ebx >> 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CPU::log_cpu_information()
|
||||||
|
{
|
||||||
|
kinfoln("CPU vendor: %s", get_vendor_string());
|
||||||
|
kinfoln("CPU brand: %s", get_brand_string());
|
||||||
|
}
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
#include "debug.h"
|
|
||||||
#include "assert.h"
|
|
||||||
#include "scheduling/PIT.h"
|
|
||||||
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
|
||||||
|
|
||||||
namespace Debug
|
|
||||||
{
|
|
||||||
DebugStatus DebugStatus::s_main;
|
|
||||||
|
|
||||||
void DebugStatus::Init()
|
|
||||||
{
|
|
||||||
ASSERT(renderer.init());
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebugStatus::StartBootStage(Color stage)
|
|
||||||
{
|
|
||||||
renderer.paint_rect(x, y, 10, 10, stage);
|
|
||||||
y += 11;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebugStatus::PassBootStage(Color stage)
|
|
||||||
{
|
|
||||||
renderer.paint_rect(x, y, 10, 10, stage);
|
|
||||||
y -= 11;
|
|
||||||
x += 11;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebugStatus::FailBootStage()
|
|
||||||
{
|
|
||||||
renderer.paint_rect(x, y, 10, 10, Color::Red);
|
|
||||||
y -= 11;
|
|
||||||
x += 11;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebugStatus::DebugTick()
|
|
||||||
{
|
|
||||||
uint8_t blue = (PIT::ms_since_boot / 10) % 255;
|
|
||||||
renderer.paint_rect(0, 200, 10, 10, Color{blue, 0x00, 0x00, 0xFF});
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebugStatus::DebugKey(char key)
|
|
||||||
{
|
|
||||||
renderer.paint_rect(0, 215, 10, 10, Color{0x00, (uint8_t)key, 0x00, 0xFF});
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebugStatus::ThrowException(int exception)
|
|
||||||
{
|
|
||||||
uint8_t red = (uint8_t)(exception * 8);
|
|
||||||
renderer.paint_rect(errx, erry, 10, 10, Color{0x00, 0x00, red, 0xFF});
|
|
||||||
errx += 11;
|
|
||||||
}
|
|
||||||
|
|
||||||
DebugStatus* DebugStatus::the()
|
|
||||||
{
|
|
||||||
return &s_main;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma GCC diagnostic pop
|
|
@ -1,4 +1,7 @@
|
|||||||
|
#define MODULE "gdt"
|
||||||
|
|
||||||
#include "gdt/GDT.h"
|
#include "gdt/GDT.h"
|
||||||
|
#include "log/Log.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
struct GDTR
|
struct GDTR
|
||||||
@ -39,5 +42,6 @@ void GDT::load()
|
|||||||
static GDTR gdtr;
|
static GDTR gdtr;
|
||||||
gdtr.offset = (uint64_t)&internal_gdt;
|
gdtr.offset = (uint64_t)&internal_gdt;
|
||||||
gdtr.size = sizeof(InternalGDT);
|
gdtr.size = sizeof(InternalGDT);
|
||||||
|
kinfoln("Loading GDT at offset %lx, size %d", gdtr.offset, gdtr.size);
|
||||||
load_gdt(&gdtr);
|
load_gdt(&gdtr);
|
||||||
}
|
}
|
@ -1,4 +1,3 @@
|
|||||||
#include "debug.h"
|
|
||||||
#include "interrupts/IRQ.h"
|
#include "interrupts/IRQ.h"
|
||||||
#include "interrupts/SavedContext.h"
|
#include "interrupts/SavedContext.h"
|
||||||
#include "panic/hang.h"
|
#include "panic/hang.h"
|
||||||
@ -6,7 +5,6 @@
|
|||||||
|
|
||||||
extern "C" void common_handler(SavedContext* context)
|
extern "C" void common_handler(SavedContext* context)
|
||||||
{
|
{
|
||||||
if (context->number < 0x20) { Debug::DebugStatus::the()->ThrowException(context->number); }
|
|
||||||
if (context->number == 13)
|
if (context->number == 13)
|
||||||
{
|
{
|
||||||
printf("General protection fault at %zx, %ld, %ld, %zx, %ld, %zx\n", context->rip, context->cs, context->ss,
|
printf("General protection fault at %zx, %ld, %ld, %zx, %ld, %zx\n", context->rip, context->cs, context->ss,
|
||||||
@ -15,7 +13,7 @@ extern "C" void common_handler(SavedContext* context)
|
|||||||
}
|
}
|
||||||
if (context->number == 14)
|
if (context->number == 14)
|
||||||
{
|
{
|
||||||
printf("Page fault at 0x%zx\n", context->rip);
|
printf("Page fault (RIP 0x%lx), while trying to access %lx\n", context->rip, context->cr2);
|
||||||
hang();
|
hang();
|
||||||
}
|
}
|
||||||
if (context->number >= 0x20 && context->number < 0x30) { IRQ::interrupt_handler(context); }
|
if (context->number >= 0x20 && context->number < 0x30) { IRQ::interrupt_handler(context); }
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
|
#define MODULE "idt"
|
||||||
|
|
||||||
#include "interrupts/IDT.h"
|
#include "interrupts/IDT.h"
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
|
#include "log/Log.h"
|
||||||
|
|
||||||
struct IDTEntry
|
struct IDTEntry
|
||||||
{
|
{
|
||||||
@ -47,5 +50,6 @@ void IDT::load()
|
|||||||
{
|
{
|
||||||
idtr.limit = 0x0FFF;
|
idtr.limit = 0x0FFF;
|
||||||
idtr.offset = (uint64_t)entries;
|
idtr.offset = (uint64_t)entries;
|
||||||
|
kinfoln("Loading IDT at offset %lx, limit %d", idtr.offset, idtr.limit);
|
||||||
asm("lidt %0" : : "m"(idtr));
|
asm("lidt %0" : : "m"(idtr));
|
||||||
}
|
}
|
@ -1,5 +1,4 @@
|
|||||||
#include "interrupts/IRQ.h"
|
#include "interrupts/IRQ.h"
|
||||||
#include "debug.h"
|
|
||||||
#include "io/IO.h"
|
#include "io/IO.h"
|
||||||
#include "io/PIC.h"
|
#include "io/PIC.h"
|
||||||
#include "scheduling/PIT.h"
|
#include "scheduling/PIT.h"
|
||||||
@ -9,13 +8,9 @@ void IRQ::interrupt_handler(SavedContext* context)
|
|||||||
{
|
{
|
||||||
switch (context->irq_number)
|
switch (context->irq_number)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0: PIT::tick(); break;
|
||||||
PIT::tick();
|
|
||||||
Debug::DebugStatus::the()->DebugTick();
|
|
||||||
break;
|
|
||||||
case 1: {
|
case 1: {
|
||||||
volatile unsigned char scancode = IO::inb(0x60);
|
[[maybe_unused]] volatile unsigned char scancode = IO::inb(0x60);
|
||||||
Debug::DebugStatus::the()->DebugKey(scancode);
|
|
||||||
printf("Keyboard key pressed, seconds since boot: %ld\n", PIT::ms_since_boot / 1000);
|
printf("Keyboard key pressed, seconds since boot: %ld\n", PIT::ms_since_boot / 1000);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "interrupts/Install.h"
|
#include "interrupts/Install.h"
|
||||||
#include "interrupts/IDT.h"
|
#include "interrupts/IDT.h"
|
||||||
|
#include "log/Log.h"
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
@ -53,6 +54,7 @@ extern "C"
|
|||||||
|
|
||||||
void Interrupts::install()
|
void Interrupts::install()
|
||||||
{
|
{
|
||||||
|
kinfoln("Installing handler stubs for exceptions (ISRs 0-31)");
|
||||||
INSTALL_TRAP(0);
|
INSTALL_TRAP(0);
|
||||||
INSTALL_TRAP(1);
|
INSTALL_TRAP(1);
|
||||||
INSTALL_TRAP(2);
|
INSTALL_TRAP(2);
|
||||||
@ -85,6 +87,7 @@ void Interrupts::install()
|
|||||||
INSTALL_TRAP(29);
|
INSTALL_TRAP(29);
|
||||||
INSTALL_TRAP(30);
|
INSTALL_TRAP(30);
|
||||||
INSTALL_UNUSED(31);
|
INSTALL_UNUSED(31);
|
||||||
|
kinfoln("Installing handler stubs for IRQs (ISRs 32-47)");
|
||||||
INSTALL_ISR(32);
|
INSTALL_ISR(32);
|
||||||
INSTALL_ISR(33);
|
INSTALL_ISR(33);
|
||||||
INSTALL_ISR(34);
|
INSTALL_ISR(34);
|
||||||
@ -101,6 +104,8 @@ void Interrupts::install()
|
|||||||
INSTALL_ISR(45);
|
INSTALL_ISR(45);
|
||||||
INSTALL_ISR(46);
|
INSTALL_ISR(46);
|
||||||
INSTALL_ISR(47);
|
INSTALL_ISR(47);
|
||||||
|
kinfoln("Installing handler stub for software interrupt 48");
|
||||||
INSTALL_ISR(48);
|
INSTALL_ISR(48);
|
||||||
|
kinfoln("Installing unused handler stubs for the rest of the IDT");
|
||||||
for (int i = 49; i < 256; i++) { INSTALL_UNUSED(i); }
|
for (int i = 49; i < 256; i++) { INSTALL_UNUSED(i); }
|
||||||
}
|
}
|
@ -1,5 +1,8 @@
|
|||||||
|
#define MODULE "pic"
|
||||||
|
|
||||||
#include "io/PIC.h"
|
#include "io/PIC.h"
|
||||||
#include "io/IO.h"
|
#include "io/IO.h"
|
||||||
|
#include "log/Log.h"
|
||||||
|
|
||||||
#define PIC1_COMMAND 0x20
|
#define PIC1_COMMAND 0x20
|
||||||
#define PIC1_DATA 0x21
|
#define PIC1_DATA 0x21
|
||||||
@ -13,6 +16,7 @@
|
|||||||
|
|
||||||
void PIC::remap()
|
void PIC::remap()
|
||||||
{
|
{
|
||||||
|
kinfoln("Remapping PIC");
|
||||||
uint8_t a1, a2;
|
uint8_t a1, a2;
|
||||||
|
|
||||||
a1 = IO::inb(PIC1_DATA);
|
a1 = IO::inb(PIC1_DATA);
|
||||||
@ -25,8 +29,10 @@ void PIC::remap()
|
|||||||
IO::outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
|
IO::outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
|
||||||
IO::delay();
|
IO::delay();
|
||||||
|
|
||||||
|
kinfoln("Remapping master PIC to ISRs 32-39");
|
||||||
IO::outb(PIC1_DATA, 0x20);
|
IO::outb(PIC1_DATA, 0x20);
|
||||||
IO::delay();
|
IO::delay();
|
||||||
|
kinfoln("Remapping slave PIC to ISRs 40-47");
|
||||||
IO::outb(PIC2_DATA, 0x28);
|
IO::outb(PIC2_DATA, 0x28);
|
||||||
IO::delay();
|
IO::delay();
|
||||||
|
|
||||||
@ -47,11 +53,13 @@ void PIC::remap()
|
|||||||
|
|
||||||
void PIC::enable_master(uint8_t mask)
|
void PIC::enable_master(uint8_t mask)
|
||||||
{
|
{
|
||||||
|
kinfoln("Setting mask of master PIC to 0x%x", mask);
|
||||||
IO::outb(PIC1_DATA, mask);
|
IO::outb(PIC1_DATA, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PIC::enable_slave(uint8_t mask)
|
void PIC::enable_slave(uint8_t mask)
|
||||||
{
|
{
|
||||||
|
kinfoln("Setting mask of slave PIC to 0x%x", mask);
|
||||||
IO::outb(PIC2_DATA, mask);
|
IO::outb(PIC2_DATA, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "log/Log.h"
|
#include "log/Log.h"
|
||||||
#include "io/Serial.h"
|
#include "io/Serial.h"
|
||||||
|
#include "scheduling/PIT.h"
|
||||||
#include "std/stdio.h"
|
#include "std/stdio.h"
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
@ -8,6 +9,7 @@ void KernelLog::log(const char* function, LogLevel level, const char* message, .
|
|||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, message);
|
va_start(ap, message);
|
||||||
Serial::reset_color();
|
Serial::reset_color();
|
||||||
|
printf("[%ld.%ld] ", PIT::ms_since_boot / 1000, PIT::ms_since_boot % 1000);
|
||||||
Serial::print(function);
|
Serial::print(function);
|
||||||
Serial::print(": ");
|
Serial::print(": ");
|
||||||
switch (level)
|
switch (level)
|
||||||
@ -26,6 +28,7 @@ void KernelLog::logln(const char* function, LogLevel level, const char* message,
|
|||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, message);
|
va_start(ap, message);
|
||||||
Serial::reset_color();
|
Serial::reset_color();
|
||||||
|
printf("[%ld.%ld] ", PIT::ms_since_boot / 1000, PIT::ms_since_boot % 1000);
|
||||||
Serial::print(function);
|
Serial::print(function);
|
||||||
Serial::print(": ");
|
Serial::print(": ");
|
||||||
switch (level)
|
switch (level)
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
#include "bootboot.h"
|
#include "bootboot.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "cpu/CPU.h"
|
#include "cpu/CPU.h"
|
||||||
#include "debug.h"
|
|
||||||
#include "gdt/GDT.h"
|
#include "gdt/GDT.h"
|
||||||
#include "init/Init.h"
|
#include "init/Init.h"
|
||||||
#include "init/InitRD.h"
|
#include "init/InitRD.h"
|
||||||
@ -19,9 +18,10 @@
|
|||||||
#include "memory/KernelHeap.h"
|
#include "memory/KernelHeap.h"
|
||||||
#include "memory/KernelMemoryManager.h"
|
#include "memory/KernelMemoryManager.h"
|
||||||
#include "memory/Memory.h"
|
#include "memory/Memory.h"
|
||||||
|
#include "memory/MemoryMap.h"
|
||||||
#include "memory/RangeAllocator.h"
|
#include "memory/RangeAllocator.h"
|
||||||
#include "panic/hang.h"
|
#include "panic/hang.h"
|
||||||
#include "power/shutdown.h"
|
#include "power/reboot.h"
|
||||||
#include "render/BBRenderer.h"
|
#include "render/BBRenderer.h"
|
||||||
#include "render/Draw.h"
|
#include "render/Draw.h"
|
||||||
#include "render/TextRenderer.h"
|
#include "render/TextRenderer.h"
|
||||||
@ -36,117 +36,44 @@ extern "C" void _start()
|
|||||||
{
|
{
|
||||||
Init::check_magic();
|
Init::check_magic();
|
||||||
Init::disable_smp(); // Put all other cores except the bootstrap one in an infinite loop
|
Init::disable_smp(); // Put all other cores except the bootstrap one in an infinite loop
|
||||||
Debug::DebugStatus::the()->Init();
|
|
||||||
Debug::DebugStatus::the()->StartBootStage(Color::White);
|
|
||||||
Init::early_init();
|
Init::early_init();
|
||||||
Debug::DebugStatus::the()->PassBootStage(Color::White);
|
|
||||||
|
|
||||||
kinfoln("Starting Moon %d.%d-%s", MOON_MAJOR, MOON_MINOR, MOON_SUFFIX);
|
kinfoln("Starting Moon %d.%d%s", MOON_MAJOR, MOON_MINOR, MOON_SUFFIX);
|
||||||
|
|
||||||
|
CPU::log_cpu_information();
|
||||||
|
|
||||||
|
Memory::walk_memory_map();
|
||||||
|
|
||||||
Debug::DebugStatus::the()->StartBootStage(Color::Gray);
|
|
||||||
GDT::load();
|
GDT::load();
|
||||||
Debug::DebugStatus::the()->PassBootStage(Color::Gray);
|
|
||||||
|
|
||||||
kinfoln("Loaded GDT");
|
kinfoln("Loaded GDT");
|
||||||
|
|
||||||
Debug::DebugStatus::the()->StartBootStage(Color::Cyan);
|
|
||||||
Interrupts::install();
|
Interrupts::install();
|
||||||
Debug::DebugStatus::the()->PassBootStage(Color::Cyan);
|
|
||||||
|
|
||||||
Debug::DebugStatus::the()->StartBootStage(Color::Blue);
|
|
||||||
IDT::load();
|
IDT::load();
|
||||||
Debug::DebugStatus::the()->PassBootStage(Color::Blue);
|
|
||||||
|
|
||||||
kinfoln("Loaded IDT");
|
kinfoln("Loaded IDT");
|
||||||
|
|
||||||
Debug::DebugStatus::the()->StartBootStage(Color::Green);
|
|
||||||
PIC::remap();
|
PIC::remap();
|
||||||
PIC::enable_master(0b11111100); // enable keyboard and PIT
|
PIC::enable_master(0b11111100); // enable keyboard and PIT
|
||||||
PIC::enable_slave(0b11111111);
|
PIC::enable_slave(0b11111111);
|
||||||
Debug::DebugStatus::the()->PassBootStage(Color::Green);
|
|
||||||
|
|
||||||
kinfoln("Prepared PIC");
|
kinfoln("Prepared PIC");
|
||||||
|
|
||||||
Debug::DebugStatus::the()->StartBootStage(Color::Magenta);
|
PIT::initialize(1000); // 1000 times per second, 1 time per millisecond
|
||||||
PIT::initialize(100); // 100 times per second
|
|
||||||
Debug::DebugStatus::the()->PassBootStage(Color::Magenta);
|
|
||||||
|
|
||||||
kinfoln("Prepared PIT");
|
kinfoln("Prepared PIT");
|
||||||
|
|
||||||
Debug::DebugStatus::the()->StartBootStage(Color::Yellow);
|
|
||||||
Interrupts::enable();
|
Interrupts::enable();
|
||||||
Debug::DebugStatus::the()->PassBootStage(Color::Yellow);
|
|
||||||
|
|
||||||
kinfoln("Interrupts enabled");
|
kinfoln("Interrupts enabled");
|
||||||
|
|
||||||
Debug::DebugStatus::the()->StartBootStage(Color{0x33, 0x33, 0x00, 0xFF});
|
ACPI::SDTHeader* rootSDT = ACPI::GetRSDTOrXSDT();
|
||||||
ACPI::SDTHeader* rootSDT = (ACPI::SDTHeader*)KernelMemoryManager::get_unaligned_mapping(ACPI::GetRSDTOrXSDT());
|
bool isXSDT = ACPI::IsXSDT(rootSDT);
|
||||||
bool isXSDT = false;
|
if (!ACPI::ValidateRSDTOrXSDT(rootSDT)) kerrorln("Invalid %s", isXSDT ? "XSDT" : "RSDT");
|
||||||
if (strncmp(rootSDT->Signature, "XSDT", 4) != 0)
|
|
||||||
{
|
|
||||||
if (strncmp(rootSDT->Signature, "RSDT", 4) != 0)
|
|
||||||
{
|
|
||||||
kerrorln("Invalid RootSDT signature");
|
|
||||||
Debug::DebugStatus::the()->FailBootStage();
|
|
||||||
while (1) halt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
isXSDT = true;
|
|
||||||
if (ACPI::ValidateSDTHeader(rootSDT))
|
|
||||||
{
|
|
||||||
kinfoln("%s: 0x%lx", isXSDT ? "XSDT is valid" : "RSDT is valid", (uint64_t)rootSDT);
|
|
||||||
Debug::DebugStatus::the()->PassBootStage(Color{0x33, 0x33, 0x00, 0xFF});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
kinfoln(isXSDT ? "Invalid XSDT :(" : "Invalid RSDT :(");
|
|
||||||
Debug::DebugStatus::the()->FailBootStage();
|
|
||||||
while (1) halt();
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug::DebugStatus::the()->StartBootStage(Color{0x00, 0x66, 0xCC, 0xFF});
|
|
||||||
ACPI::SDTHeader* fadt = (ACPI::SDTHeader*)ACPI::FindTable(rootSDT, "FACP");
|
|
||||||
if (!fadt)
|
|
||||||
{
|
|
||||||
kerrorln("FADT not found");
|
|
||||||
Debug::DebugStatus::the()->FailBootStage();
|
|
||||||
while (1) halt();
|
|
||||||
}
|
|
||||||
if (strncmp(fadt->Signature, "FACP", 4) != 0)
|
|
||||||
{
|
|
||||||
kerrorln("Invalid FADT signature");
|
|
||||||
Debug::DebugStatus::the()->FailBootStage();
|
|
||||||
while (1) halt();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (ACPI::ValidateSDTHeader(fadt))
|
|
||||||
{
|
|
||||||
kinfoln("FADT is valid");
|
|
||||||
Debug::DebugStatus::the()->PassBootStage(Color{0x00, 0x66, 0xCC, 0xFF});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
kinfoln("Invalid FADT :(");
|
|
||||||
Debug::DebugStatus::the()->FailBootStage();
|
|
||||||
while (1) halt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ACPI::SDTHeader* madt = (ACPI::SDTHeader*)ACPI::FindTable(rootSDT, "APIC");
|
|
||||||
if (!madt)
|
|
||||||
{
|
|
||||||
kerrorln("MADT not found");
|
|
||||||
while (1) halt();
|
|
||||||
}
|
|
||||||
|
|
||||||
KernelMemoryManager::release_unaligned_mapping(rootSDT);
|
|
||||||
|
|
||||||
sleep(2500);
|
sleep(2500);
|
||||||
shutdown();
|
reboot();
|
||||||
|
|
||||||
while (1) halt();
|
while (1) halt();
|
||||||
loop:
|
|
||||||
goto loop;
|
|
||||||
}
|
}
|
@ -19,12 +19,29 @@ void* KernelMemoryManager::get_unaligned_mapping(void* physicalAddress)
|
|||||||
return (void*)(virtualAddress + offset);
|
return (void*)(virtualAddress + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* KernelMemoryManager::get_unaligned_mappings(void* physicalAddress, uint64_t count)
|
||||||
|
{
|
||||||
|
uint64_t offset = (uint64_t)physicalAddress % 4096;
|
||||||
|
uint64_t virtualAddress = KernelHeap::request_virtual_pages(count);
|
||||||
|
for (uint64_t i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
kernelVMM.map(virtualAddress + (i * 4096), ((uint64_t)physicalAddress - offset) + (i * 4096));
|
||||||
|
}
|
||||||
|
return (void*)(virtualAddress + offset);
|
||||||
|
}
|
||||||
|
|
||||||
void KernelMemoryManager::release_unaligned_mapping(void* mapping)
|
void KernelMemoryManager::release_unaligned_mapping(void* mapping)
|
||||||
{
|
{
|
||||||
uint64_t offset = (uint64_t)mapping % 4096;
|
uint64_t offset = (uint64_t)mapping % 4096;
|
||||||
kernelVMM.unmap((uint64_t)mapping - offset);
|
kernelVMM.unmap((uint64_t)mapping - offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KernelMemoryManager::release_unaligned_mappings(void* mapping, uint64_t count)
|
||||||
|
{
|
||||||
|
uint64_t offset = (uint64_t)mapping % 4096;
|
||||||
|
for (uint64_t i = 0; i < count; i++) { kernelVMM.unmap(((uint64_t)mapping - offset) + (i * 4096)); }
|
||||||
|
}
|
||||||
|
|
||||||
void KernelMemoryManager::release_mapping(void* mapping)
|
void KernelMemoryManager::release_mapping(void* mapping)
|
||||||
{
|
{
|
||||||
kernelVMM.unmap((uint64_t)mapping);
|
kernelVMM.unmap((uint64_t)mapping);
|
||||||
|
37
kernel/src/memory/MemoryMap.cpp
Normal file
37
kernel/src/memory/MemoryMap.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#define MODULE "mmap"
|
||||||
|
|
||||||
|
#include "memory/MemoryMap.h"
|
||||||
|
#include "bootboot.h"
|
||||||
|
#include "log/Log.h"
|
||||||
|
|
||||||
|
extern BOOTBOOT bootboot;
|
||||||
|
|
||||||
|
void Memory::walk_memory_map()
|
||||||
|
{
|
||||||
|
MMapEnt* ptr = &bootboot.mmap;
|
||||||
|
uint64_t mmap_entries = (bootboot.size - 128) / 16;
|
||||||
|
for (uint64_t i = 0; i < mmap_entries; i++)
|
||||||
|
{
|
||||||
|
switch (MMapEnt_Type(ptr))
|
||||||
|
{
|
||||||
|
case MMAP_USED:
|
||||||
|
kinfoln("Used memory region starting at %lx, ends at %lx, size %lx", MMapEnt_Ptr(ptr),
|
||||||
|
MMapEnt_Ptr(ptr) + MMapEnt_Size(ptr) - 1, MMapEnt_Size(ptr));
|
||||||
|
break;
|
||||||
|
case MMAP_ACPI:
|
||||||
|
kinfoln("ACPI memory region starting at %lx, ends at %lx, size %lx", MMapEnt_Ptr(ptr),
|
||||||
|
MMapEnt_Ptr(ptr) + MMapEnt_Size(ptr) - 1, MMapEnt_Size(ptr));
|
||||||
|
break;
|
||||||
|
case MMAP_MMIO:
|
||||||
|
kinfoln("MMIO memory region starting at %lx, ends at %lx, size %lx", MMapEnt_Ptr(ptr),
|
||||||
|
MMapEnt_Ptr(ptr) + MMapEnt_Size(ptr) - 1, MMapEnt_Size(ptr));
|
||||||
|
break;
|
||||||
|
case MMAP_FREE:
|
||||||
|
kinfoln("Free memory region starting at %lx, ends at %lx, size %lx", MMapEnt_Ptr(ptr),
|
||||||
|
MMapEnt_Ptr(ptr) + MMapEnt_Size(ptr) - 1, MMapEnt_Size(ptr));
|
||||||
|
break;
|
||||||
|
default: kinfoln("Invalid memory map entry"); break;
|
||||||
|
}
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
}
|
@ -30,18 +30,22 @@ void RangeAllocator::init_from_mmap()
|
|||||||
bitmap_addr = (char*)biggest_chunk;
|
bitmap_addr = (char*)biggest_chunk;
|
||||||
ASSERT((total_mem / 4096 / 8) < biggest_chunk_size);
|
ASSERT((total_mem / 4096 / 8) < biggest_chunk_size);
|
||||||
bitmap_size = total_mem / 4096 / 8 + 1;
|
bitmap_size = total_mem / 4096 / 8 + 1;
|
||||||
memset(bitmap_addr, 0, bitmap_size);
|
memset(bitmap_addr, 0xFF, bitmap_size);
|
||||||
|
|
||||||
free_mem = total_mem;
|
|
||||||
|
|
||||||
lock_pages(bitmap_addr, bitmap_size / 4096 + 1);
|
|
||||||
|
|
||||||
ptr = &bootboot.mmap;
|
ptr = &bootboot.mmap;
|
||||||
for (uint64_t i = 0; i < mmap_entries; i++)
|
for (uint64_t i = 0; i < mmap_entries; i++)
|
||||||
{
|
{
|
||||||
if (!MMapEnt_IsFree(ptr)) { reserve_pages((void*)MMapEnt_Ptr(ptr), MMapEnt_Size(ptr) / 4096); }
|
uint64_t index = MMapEnt_Ptr(ptr) / 4096;
|
||||||
|
if (!MMapEnt_IsFree(ptr)) { reserved_mem += 4096; }
|
||||||
|
else
|
||||||
|
{
|
||||||
|
free_mem += 4096;
|
||||||
|
bitmap_set(index, false);
|
||||||
|
}
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lock_pages(bitmap_addr, bitmap_size / 4096 + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RangeAllocator::bitmap_read(uint64_t index)
|
bool RangeAllocator::bitmap_read(uint64_t index)
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#define MODULE "power"
|
||||||
|
|
||||||
#include "power/reboot.h"
|
#include "power/reboot.h"
|
||||||
#include "acpi/FADT.h"
|
#include "acpi/FADT.h"
|
||||||
#include "acpi/RSDT.h"
|
#include "acpi/RSDT.h"
|
||||||
@ -11,20 +13,53 @@
|
|||||||
|
|
||||||
static void try_acpi_reboot()
|
static void try_acpi_reboot()
|
||||||
{
|
{
|
||||||
|
kinfoln("Fetching pointer to RSDT/XSDT");
|
||||||
ACPI::SDTHeader* rootSDT = ACPI::GetRSDTOrXSDT();
|
ACPI::SDTHeader* rootSDT = ACPI::GetRSDTOrXSDT();
|
||||||
if (!rootSDT) return;
|
if (!rootSDT)
|
||||||
if (!ACPI::ValidateSDTHeader(rootSDT)) return;
|
{
|
||||||
if (strncmp(rootSDT->Signature, "RSDT", 4) != 0 && strncmp(rootSDT->Signature, "XSDT", 4) != 0) return;
|
kinfoln("The pointer to the RSDT/XSDT is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!ACPI::ValidateSDTHeader(rootSDT))
|
||||||
|
{
|
||||||
|
kinfoln("The RSDT/XSDT has an invalid header");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (strncmp(rootSDT->Signature, "RSDT", 4) != 0 && strncmp(rootSDT->Signature, "XSDT", 4) != 0)
|
||||||
|
{
|
||||||
|
kinfoln("The RSDT/XSDT's signature is not RSDT or XSDT");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
kinfoln("Searching for FACP");
|
||||||
ACPI::FADT* fadt = (ACPI::FADT*)ACPI::FindTable(rootSDT, "FACP");
|
ACPI::FADT* fadt = (ACPI::FADT*)ACPI::FindTable(rootSDT, "FACP");
|
||||||
if (!fadt) return;
|
if (!fadt)
|
||||||
if (!ACPI::ValidateSDTHeader(&fadt->header)) return;
|
{
|
||||||
if (!(fadt->Flags & 1 << 10)) return;
|
kinfoln("Unable to find the FADT");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (fadt->header.Revision < 2)
|
||||||
|
{
|
||||||
|
kinfoln("ACPI revision is too low (%d), ACPI Reset is only implemented in ACPI 2.0+", fadt->header.Revision);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!(fadt->Flags & 1 << 10))
|
||||||
|
{
|
||||||
|
kinfoln("This system does not support ACPI Reset");
|
||||||
|
return;
|
||||||
|
}
|
||||||
switch (fadt->ResetReg.AddressSpace)
|
switch (fadt->ResetReg.AddressSpace)
|
||||||
{
|
{
|
||||||
case ACPI::SystemIO: IO::outb(fadt->ResetReg.Address, fadt->ResetValue); break;
|
case ACPI::SystemIO:
|
||||||
case ACPI::GeneralPurposeIO: IO::outb(fadt->ResetReg.Address, fadt->ResetValue); break;
|
kinfoln("Attempting reboot via IO");
|
||||||
default: return;
|
IO::outb(fadt->ResetReg.Address, fadt->ResetValue);
|
||||||
|
break;
|
||||||
|
case ACPI::GeneralPurposeIO:
|
||||||
|
kinfoln("Attempting reboot via IO");
|
||||||
|
IO::outb(fadt->ResetReg.Address, fadt->ResetValue);
|
||||||
|
break;
|
||||||
|
default: kinfoln("This method of rebooting via ACPI is not yet implemented"); return;
|
||||||
}
|
}
|
||||||
|
kinfoln("Tried to reboot, but apparently did nothing");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void try_kbd_reboot()
|
static void try_kbd_reboot()
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#define MODULE "power"
|
||||||
|
|
||||||
#include "power/shutdown.h"
|
#include "power/shutdown.h"
|
||||||
#include "io/IO.h"
|
#include "io/IO.h"
|
||||||
#include "log/Log.h"
|
#include "log/Log.h"
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
|
#define MODULE "pit"
|
||||||
|
|
||||||
#include "scheduling/PIT.h"
|
#include "scheduling/PIT.h"
|
||||||
#include "io/IO.h"
|
#include "io/IO.h"
|
||||||
|
#include "log/Log.h"
|
||||||
|
|
||||||
#define PIT_CHANNEL_0_PORT 0x40
|
#define PIT_CHANNEL_0_PORT 0x40
|
||||||
|
|
||||||
@ -9,6 +12,7 @@ uint16_t divisor = 65535;
|
|||||||
void PIT::initialize(uint64_t frequency)
|
void PIT::initialize(uint64_t frequency)
|
||||||
{
|
{
|
||||||
divisor = base_frequency / frequency;
|
divisor = base_frequency / frequency;
|
||||||
|
kinfoln("Configuring PIT to use divisor %d (will tick %lu times per second)", divisor, frequency);
|
||||||
if (divisor < 100) divisor = 100;
|
if (divisor < 100) divisor = 100;
|
||||||
IO::outb(PIT_CHANNEL_0_PORT, (uint8_t)(divisor & 0xFF));
|
IO::outb(PIT_CHANNEL_0_PORT, (uint8_t)(divisor & 0xFF));
|
||||||
IO::delay();
|
IO::delay();
|
||||||
|
Loading…
Reference in New Issue
Block a user