Large rewrites & struggles

This commit is contained in:
Curle 2022-02-17 02:03:05 +00:00
parent 06134ebcd9
commit acda33948e
Signed by: TheCurle
GPG Key ID: 5942F13718443F79
48 changed files with 3828 additions and 2561 deletions

View File

@ -15,37 +15,39 @@ project(chroma)
SET(src_files
${CMAKE_SOURCE_DIR}/src/kernel.cpp
${CMAKE_SOURCE_DIR}/src/video/draw.c
${CMAKE_SOURCE_DIR}/src/video/draw.cpp
${CMAKE_SOURCE_DIR}/src/video/print.cpp
${CMAKE_SOURCE_DIR}/src/system/cpu.c
${CMAKE_SOURCE_DIR}/src/system/rw.c
${CMAKE_SOURCE_DIR}/src/system/serial.c
${CMAKE_SOURCE_DIR}/src/system/pci.c
${CMAKE_SOURCE_DIR}/src/system/memory/stack.c
${CMAKE_SOURCE_DIR}/src/system/memory/paging.c
${CMAKE_SOURCE_DIR}/src/system/memory/abstract_allocator.c
${CMAKE_SOURCE_DIR}/src/system/memory/liballoc.c
${CMAKE_SOURCE_DIR}/src/system/cpu.cpp
${CMAKE_SOURCE_DIR}/src/system/core.cpp
${CMAKE_SOURCE_DIR}/src/system/rw.cpp
${CMAKE_SOURCE_DIR}/src/system/serial.cpp
${CMAKE_SOURCE_DIR}/src/system/pci.cpp
${CMAKE_SOURCE_DIR}/src/system/acpi/MADT.cpp
${CMAKE_SOURCE_DIR}/src/system/acpi/RSDP.cpp
${CMAKE_SOURCE_DIR}/src/system/memory/paging.cpp
${CMAKE_SOURCE_DIR}/src/system/memory/abstract_allocator.cpp
${CMAKE_SOURCE_DIR}/src/system/memory/liballoc.cpp
${CMAKE_SOURCE_DIR}/src/system/memory/physmem.c
${CMAKE_SOURCE_DIR}/src/drivers/keyboard.c
${CMAKE_SOURCE_DIR}/src/drivers/elf.c
${CMAKE_SOURCE_DIR}/src/system/process/process.cpp
${CMAKE_SOURCE_DIR}/src/drivers/elf.cpp
${CMAKE_SOURCE_DIR}/src/drivers/devices/devices.cpp
${CMAKE_SOURCE_DIR}/src/drivers/devices/input/keyboard.cpp
${CMAKE_SOURCE_DIR}/src/drivers/devices/io/apic.cpp
${CMAKE_SOURCE_DIR}/src/drivers/devices/storage/ata.cpp
)
SET(lib_files
${CMAKE_SOURCE_DIR}/src/lainlib/list/basic_list.c
${CMAKE_SOURCE_DIR}/src/lainlib/mutex/ticketlock.c
${CMAKE_SOURCE_DIR}/src/lainlib/list/basic_list.cpp
${CMAKE_SOURCE_DIR}/src/lainlib/mutex/ticketlock.cpp
${CMAKE_SOURCE_DIR}/src/lainlib/compression/lzgmini.c
${CMAKE_SOURCE_DIR}/src/lainlib/string/str.c
${CMAKE_SOURCE_DIR}/src/lainlib/string/str.cpp
${CMAKE_SOURCE_DIR}/src/editor/EditorMain.cpp
)
include_directories("inc" "D:/mingw/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++" "D:/mingw/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32")
SET(src_no_sse
${CMAKE_SOURCE_DIR}/src/system/interrupts.c
${CMAKE_SOURCE_DIR}/src/system/interrupts.cpp
)
SET(src_preamble
@ -68,5 +70,5 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
add_executable(kernel)
target_sources(kernel PUBLIC ${src_preamble} PUBLIC ${src_files} PUBLIC ${src_no_sse} PUBLIC ${lib_files} PUBLIC ${src_epilogue})
target_compile_options(kernel PRIVATE -ffreestanding -O0 -Wall -Wextra -Wall -Werror -fPIC -fno-exceptions -fno-omit-frame-pointer -mno-red-zone -fno-stack-protector -ggdb3)
target_compile_options(kernel PRIVATE -ffreestanding -O0 -Wall -Wextra -Wall -Werror -fPIC -fno-exceptions -fno-omit-frame-pointer -mno-red-zone -fno-stack-protector -fno-rtti -ggdb3)
target_link_options(kernel PRIVATE -T ${CMAKE_SOURCE_DIR}/linker.ld -ffreestanding -O2 -nostdlib -nostartfiles -lgcc)

View File

@ -0,0 +1,3 @@
Start testing: Feb 17 01:48 GMT Standard Time
----------------------------------------------------------
End testing: Feb 17 01:48 GMT Standard Time

BIN
chroma.iso Normal file

Binary file not shown.

Binary file not shown.

View File

@ -15,10 +15,11 @@ namespace Device {
// The internal typemap of devices used in Chroma.
enum DeviceType : uint32_t {
STORAGE = 0,
KEYBOARD = 1,
NETWORK = 2,
UNKNOWN = 0xFFFFFFFF
STORAGE = 0, // Stores data.
INTERNAL = 1, // PCI, APIC, AHCI.
INTERFACE = 2, // Peripherals and I/O
NETWORK = 3, // NIC.
UNKNOWN = 0xFFFFFFFF // Unsupported.
};
// The base class that all devices extend from.
@ -81,6 +82,35 @@ namespace Device {
};
// The base class for every device that uses port or MMIO to communicate.
class IODevice : public GenericDevice {
public:
// Pre-use setup.
virtual void Init() = 0;
// This is an internal register device.
DeviceType GetType() const final {
return DeviceType::INTERNAL;
}
// Provided for utility checks.
static DeviceType GetRootType() {
return DeviceType::INTERNAL;
}
// Read data from a given port.
virtual uint32_t ReadRegister(uint32_t Register) = 0;
// Write data into a given port.
virtual void WriteRegister(uint32_t Register, uint32_t Data) = 0;
// Read data from the given address.
virtual uint32_t ReadIO(size_t Base, uint32_t Register) = 0;
// Write data into the given address.
virtual void WriteIO(size_t Base, uint32_t Register, uint32_t Data) = 0;
};
// Add a device pointer to the managed list.
void RegisterDevice(GenericDevice* Dev);

115
inc/driver/io/apic.h Normal file
View File

@ -0,0 +1,115 @@
#pragma once
#include <driver/generic/device.h>
#include <kernel/system/acpi/madt.h>
/************************
*** Team Kitty, 2021 ***
*** Chroma ***
***********************/
namespace Device {
/**
* Contains the driver definition for the Advanced Programmable Interrupt Controller - APIC.
* Each processor core contains at least one APIC, and they have a unique identifier,
* so they can be used to identify cores along with producing timed interrupts.
*
* However, this is only possible because this driver is loaded once per system.
* This is a singleton class.
*
* The primary functionality of the APIC is to send an interrupt to the given core after the specified time is up.
*/
class APIC : public IODevice {
private:
// Metadata of IOAPICs.
struct IOAPICMeta {
uint8_t Version;
uint8_t Reserved;
uint8_t MaxRedirect;
uint8_t Reserved2;
};
// The address in physical memory that refers to this device.
void* Address;
// Whether this APIC driver is ready for processing.
bool Ready = false;
ACPI::MADT::IOAPICEntry** IOAPICs;
ACPI::MADT::ISOEntry** ISOs;
IOAPICMeta* Meta;
// The internal implementation of Set. Handles raw redirects at the hardware level.
void SetInternal(uint8_t Vector, uint32_t TargetGSI, uint16_t Flags, int Core, int Status);
public:
APIC();
// The register locations of the APIC device.
enum Registers {
LAPIC_ID = 0x20, // ID of the APIC
EOI = 0xB0, // Acknowledge
SIVR = 0xF0, // Spurious Interrupt Vector Register
ICR1 = 0x300, // Interrupt Command Register Lower
ICR2 = 0x310, // Interrupt Command Register Higher
LVT = 0x320, // Local Vector Table
LINT1 = 0x350, // Local Interrupt ID
LINT2 = 0x360, // Local Interrupt ID
TIMER_DIVISOR = 0x3E0, // Frequency divisor for the timer.
TIMER_INIT = 0x380, // Initializer for the timer.
TIMER_CURRENT = 0x390, // Current "tick count" of the timer.
};
// The instance of this singleton class.
static APIC* driver;
const char* GetName() const override {
return "APIC";
}
// Dump all available information to the log (or to stdout eventually)
void LogDump();
// Move all structs and internal handlers to a new address.
void Move(size_t NewAddress);
// Prepare the APICs for use.
void Init() override;
// Load all data the APICs need.
void LoadInterruptSystem();
// Set the APICs ready for use.
void Enable();
// Check whether the APICs are ready for use.
bool IsReady();
// Prepare a core for use with interrupts.
void PreinitializeCore(int Core);
// Set a core as available to use interrupts.
void InitializeCore(int Core, size_t EntryPoint);
// Check what core ID is currently running.
int GetCurrentCore();
uint32_t ReadRegister(uint32_t Register) override;
void WriteRegister(uint32_t Register, uint32_t Data) override;
uint32_t ReadIO(size_t Base, uint32_t Register) override;
void WriteIO(size_t Base, uint32_t Register, uint32_t Data) override;
// Send a specified interrupt to another core.
void SendInterCoreInterrupt(int Core, uint32_t Interrupt);
// Tell the APIC that the interrupt is acknowledged. EOI = End Of Interrupt.
void SendEOI();
// Tell the APIC that the specified IRQ should come to this core.
void Set(int Core, uint8_t IRQ, int status);
// Write data into an inter-core interrupt.
void WriteICI(size_t Data);
// Check what the maximum allowed interrupt redirect is.
uint32_t GetMaxRedirect(uint32_t APIC);
};
};

View File

@ -4,6 +4,8 @@
*** Chroma ***
***********************/
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
@ -11,8 +13,10 @@ extern "C" {
/*
;* Memory map
;* 0h - 600h reserved for the system
* V----------- CAN REMOVE -----------V
;* 600h - 800h stage1 (MBR/VBR, boot.bin)
;* 800h - 6C00h stage2 (this)
* ----------- CAN REMOVE -----------
;* 6C00h - 7C00h stack (7000h - 700Fh SMP trampoline code)
;* 8000h - 9000h bootboot structure
;* 9000h - A000h environment
@ -111,7 +115,7 @@ typedef struct {
uint8_t protocol; /* 1, static addresses, see PROTOCOL_* and LOADER_* above */
uint8_t fb_type; /* framebuffer type, see FB_* above */
uint16_t numcores; /* number of processor cores */
uint16_t bspid; /* Bootsrap processor ID (Local APIC Id on x86_64) */
uint16_t bspid; /* Bootstrap processor ID (Local APIC Id on x86_64) */
int16_t timezone; /* in minutes -1440..1440 */
uint8_t datetime[8]; /* in BCD yyyymmddhhiiss UTC (independent to timezone) */
uint64_t initrd_ptr; /* ramdisk image position and size */

View File

@ -24,7 +24,10 @@ extern "C" {
#include <kernel/system/io.h>
#include <kernel/system/memory.h>
#include <kernel/system/pci.h>
#include <kernel/system/stack.h>
#ifdef __cplusplus
#include <kernel/system/core.hpp>
#endif
#include <lainlib/lainlib.h>
#include <lainlib/ethernet/e1000/e1000.h>

15
inc/kernel/constants.hpp Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#include <stdint.h>
/************************
*** Team Kitty, 2021 ***
*** Chroma ***
***********************/
namespace Constants {
namespace Core {
const size_t STACK_SIZE = 65536;
const size_t MAX_CORES = 12;
}
}

View File

@ -0,0 +1,104 @@
#pragma once
#include <stdint.h>
#include <kernel/system/acpi/rsdt.h>
/************************
*** Team Kitty, 2021 ***
*** Chroma ***
***********************/
namespace ACPI {
// Multiple APIC Descriptor Table. Enumerates every available APIC.
class MADT {
private:
void* Address = 0;
public:
// The type of a table entry.
enum Type {
LAPIC = 0,
IOAPIC = 1,
ISO = 2,
NMI = 4,
LAPIC_OVERRIDE = 5
};
// The header to a MADT Table Entry.
struct RecordTableEntry {
uint8_t Type; // The Type Enum value that represents this entry.
uint8_t Length; // The length in bytes of this entry.
} __attribute__((packed));
// The data of a Local APIC table Entry.
struct LAPICEntry {
RecordTableEntry Header;
uint8_t Core; // The Core ID where the Local APIC is stored
uint8_t APIC; // The ID of the APIC for the above Core ID.
uint32_t Flags; // Capability flags for the APIC.
} __attribute__((packed));
// The data of an IO (global) APIC table entry.
struct IOAPICEntry {
RecordTableEntry Header;
uint8_t APIC; // The ID of the global APIC.
uint8_t Unused;
uint32_t Address; // The Base address of the MMIO port of the APIC.
uint32_t GSI; // Global System Interrupt number.
} __attribute__((packed));
// The data of an Interrupt Source Override entry - allows interrupt redirection.
struct ISOEntry {
RecordTableEntry Header;
uint8_t Bus;
uint8_t IRQ;
uint32_t Interrupt;
uint16_t Flags;
} __attribute__((packed));
// The data of a Non-Maskable Interrupt source entry.
struct NMIEntry {
RecordTableEntry Header;
uint8_t Core;
uint16_t Flags;
uint8_t LocalInterrupt;
} __attribute__((packed));
// The data of a Local APIC Override Entry.
struct LocalOverrideEntry {
RecordTableEntry Header;
uint8_t Reserved;
size_t Address; // The 64 bit address of the Local APIC.
} __attribute__((packed));
struct MADTHeader {
ACPIHeader Header;
uint32_t LocalAPIC;
uint32_t Flags;
RecordTableEntry Table[];
} __attribute__((packed));
/***************************************
***************************************
***************************************/
static MADT* instance;
MADTHeader* Header = 0;
size_t LocalAPICBase = 0;
MADT();
void LogDump();
void Initialize();
// Get the byte of the end of the table.
size_t GetEndOfTable();
// Get all of the entries in the table, as an array.
RecordTableEntry* GetTableEntries();
// Get an array of pointers to IOAPIC entries. Should only be one.
IOAPICEntry** GetIOApicEntries();
// Get an array of pointers to ISO entries.
ISOEntry** GetISOEntries();
};
}

View File

@ -0,0 +1,77 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
/************************
*** Team Kitty, 2021 ***
*** Chroma ***
***********************/
namespace ACPI {
// The header of all System Descriptor Tables in the ACPI system.
struct ACPIHeader {
char Signature[4];
uint32_t Length;
uint8_t Revision;
uint8_t Checksum;
char OEMID[6];
char OEMTableID[8];
uint32_t OEMRevision;
uint32_t CreatorID;
uint32_t CreatorRevision;
} __attribute__((packed));
// Root System Description Pointer table container.
class RSDP {
public:
// Header of RSDP Version 1 entries.
struct DescriptorV1 {
char Signature[8];
uint8_t Checksum;
char OEM[6];
uint8_t Revision;
uint32_t RSDT;
} __attribute__((packed));
// Header of RSDP Version 2 entries.
struct DescriptorV2 {
DescriptorV1 Header;
uint32_t Length;
size_t XSDT;
uint8_t Checksum;
uint8_t Reserved[3];
} __attribute__((packed));
// RSDP Entries themselves.
struct RSDT {
ACPIHeader Header;
uint32_t* OtherSDTs;
} __attribute__((packed));
RSDP();
static RSDP* instance;
// Find the RSDP pointer in memory.
void* GetRSDP();
// Find the Fixed ACPI Descriptor (FADT) in memory.
void* GetFACP(RSDT* Root);
// Prepare virtual mapping of the RSDT
void PagingInit();
// Prepare the RSDT for reading.
__attribute__((unused)) void Init(size_t RSDP);
// Find the table with the specified name.
void* FindEntry(const char* Name);
// Dump all available information to the system log.
void LogDump();
private:
size_t Version = 0;
DescriptorV2* Descriptor;
RSDT* Table;
};
}

View File

@ -0,0 +1,80 @@
#pragma once
#include <kernel/constants.hpp>
#include <kernel/system/descriptors.h>
#include <kernel/system/memory.h>
#include <stddef.h>
#include <stdint.h>
/************************
*** Team Kitty, 2021 ***
*** Chroma ***
***********************/
/**
* The relevant information contained within a stack trace - each call consists of the
* contained information. By navigating the RBP until the base is found, a full backwards call stack can be determined.
*/
struct StackFrame {
StackFrame* rbp;
size_t rip;
};
/**
* Contains the definitions required to define and manage a single physical processing core.
* These include; active GDT and IDT, TSS segments, saved stacks for execution and syscalls.
* There are some utility functions for saving and loading extended registers, as well as
* for identifying individual Cores in a running system.
*
*/
class Core {
public:
Core() {}
Core(size_t LAPIC, size_t ID);
size_t ID;
size_t LocalAPIC;
address_space_t* AddressSpace;
uint8_t* SyscallStack;
size_t StackAddress;
uint8_t StackData[Constants::Core::STACK_SIZE];
IDT CoreIDT;
GDT CoreGDT;
TSS64 CoreTSS;
void LoadExtraRegisters(uint8_t* Data);
void SaveExtraRegisters(uint8_t* Data);
void StackTrace(size_t Cycles);
static Core* GetCurrent() {
size_t CoreID = 0;
__asm__ __volatile__("mov %0, %%fs\n" : "=r"(CoreID) : :);
return &Processors[CoreID];
}
static Core* GetCore(int ID) { return &Processors[ID]; }
static void Init();
private:
static Core Processors[];
// Initialization vectors for all new cores.
// Numbers derived from boot.h space.
// Specifically, the bootloader ROM.
enum Initialization {
PAGETABLES = 0x600,
STARTUP = 0x620,
STACK = 0x670,
GDT = 0x680,
IDT = 0x690
};
void Bootstrap();
void SetupData(size_t ID);
} __attribute__((packed));

View File

@ -77,6 +77,16 @@ typedef struct __attribute__((packed)) {
uint16_t IOMap;
} TSS64;
typedef struct __attribute__((packed)) {
uint16_t Length;
size_t Address;
} GDT;
typedef struct __attribute__((packed)) {
uint16_t Length;
size_t Address;
} IDT;
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -37,9 +37,9 @@ extern IRQHandler IRQ_Handlers[16];
void InstallIRQ(int IRQ, void (*Handler)(INTERRUPT_FRAME* Frame));
void IRQ_Common(INTERRUPT_FRAME* Frame, size_t Interupt);
void ISR_Common(INTERRUPT_FRAME* Frame, size_t Interrupt);
void ISR_Error_Common(INTERRUPT_FRAME* Frame, size_t ErrorCode, size_t Exception);
__attribute__((no_caller_saved_registers)) void IRQ_Common(INTERRUPT_FRAME* Frame, size_t Interupt);
__attribute__((no_caller_saved_registers)) void ISR_Common(INTERRUPT_FRAME* Frame, size_t Interrupt);
__attribute__((no_caller_saved_registers)) void ISR_Error_Common(INTERRUPT_FRAME* Frame, size_t ErrorCode, size_t Exception);
void RemapIRQControllers();

View File

@ -132,6 +132,8 @@ extern "C" {
#define STACK_TOP 0xFFFFFFFFFFFFF000ull // The start of the highest stack
#define MEM_CEILING 0xFFFFFFFFFFFFFFFFull // The top of the stack in the map
#define CORE_BOOTSTRAP 0x0000000000001000ull // The physical location of the core bootstrapping function.
#define USER_REGION 0x00007FFFFFFFFFFFull // Not needed yet, but we're higher half so we might as well be thorough
#define KERNEL_STACK_REGION 0xFFFFE00000000000ull // Kernel Stack Space

View File

@ -16,6 +16,8 @@ extern "C" {
* required to compatibly access the PCI bus,
* as well as set up new PCI devices, PCI bridges, and manipulate
* the connections of PCI lanes.
*
* TODO: Refactor for consistent naming style
*/
#define PCI_CONFIG_ADDRESS 0xCF8

View File

@ -77,7 +77,7 @@ class Process {
size_t UniquePID; // Globally Unique ID.
size_t KernelPID; // If in kernel space, the PID.
size_t ParentPID; // If this process was forked, the parent's PID.
size_t ParentPID; // If this process was forked, the parent's PID. Otherwise, the kernel.
char Name[128];
size_t Entry; // The entry point. Move execution here to start the process.
@ -104,7 +104,8 @@ class Process {
};
Process(const char* ProcessName, size_t KPID, size_t UPID, size_t EntryPoint, bool Userspace)
: UniquePID(UPID), KernelPID(KPID), Entry(EntryPoint), ORS(false), LastMessage(0), User(Userspace), Sleeping(0) {
: User(Userspace), UniquePID(UPID), KernelPID(KPID), Entry(EntryPoint), ORS(false), Sleeping(0),
LastMessage(0) {
memcpy((void*) ProcessName, Name, strlen(Name) + 1);
};
@ -136,6 +137,7 @@ class Process {
}
size_t* AllocateProcessSpace(size_t Bytes);
size_t FreeProcessSpace(size_t* Address, size_t Bytes);
bool OwnsAddress(size_t* Address, size_t Bytes);
@ -158,6 +160,7 @@ class Process {
void SetCore(size_t CoreID) { Core = CoreID; };
void IncreaseSleep(size_t Interval) { Sleeping += Interval; };
void DecreaseSleep(size_t Interval) { Sleeping -= Interval; };
/*************************************************************/
@ -167,6 +170,7 @@ class Process {
const char* GetName() const { return Name; };
size_t GetPID() const { return UniquePID; };
size_t GetKPID() const { return KernelPID; };
size_t GetParent() const { return ParentPID; };
@ -175,7 +179,9 @@ class Process {
bool IsValid() const { return KernelPID != 0; };
bool IsUsed() const { return (State != ProcessState::PROCESS_AVAILABLE && State != ProcessState::PROCESS_CRASH && State != ProcessState::PROCESS_REAP) && IsValid(); };
bool IsUsed() const { return (State != ProcessState::PROCESS_AVAILABLE && State != ProcessState::PROCESS_CRASH &&
State != ProcessState::PROCESS_REAP) && IsValid();
};
bool IsSleeping() const { return Sleeping; };
@ -190,13 +196,16 @@ class Process {
size_t GetCore() const { return Core; };
bool IsUserspace() { return User; };
bool IsSystem() { return System; };
/*************************************************************/
static Process* FromName(const char* name);
static Process* FromPID(size_t PID);
static Process* Current();
static void SetCurrent(Process* Target);
@ -216,22 +225,29 @@ class ProcessManagement {
uint32_t CoreCount = 1;
ProcessManagement();
static ProcessManagement* instance();
void Wait();
void Initialize();
void InitialiseCore(size_t APIC, size_t ID);
void NotifyAllCores();
void DumpProcess(size_t PID);
void LockProcess(size_t PID);
void UnlockProcess(size_t PID);
static void Sleep(size_t Count);
void Sleep(size_t Count, size_t PID);
static void Kill(int Code);
void Kill(size_t PID, int Code);
bool CheckLocked(size_t PID);
@ -240,10 +256,15 @@ class ProcessManagement {
// TODO: Process*
size_t SwitchContext(INTERRUPT_FRAME* CurrentFrame);
void MapThreadMemory(size_t from, size_t to, size_t length);
void InitProcess(function_t EntryPoint, size_t argc, char** argv);
void InitKernelProcess(function_t EntryPoint);
void InitProcessPagetable(bool Userspace);
void InitProcessArch();
size_t HandleRequest(size_t CPU);

View File

@ -1,24 +0,0 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <stdint.h>
/************************
*** Team Kitty, 2020 ***
*** Chroma ***
***********************/
typedef struct stackframe {
struct stackframe* rbp;
size_t rip;
} stackframe_t;
void StackTrace(size_t cycles);
#ifdef __cplusplus
}
#endif

View File

@ -43,7 +43,7 @@ typedef struct {
extern PRINTINFO PrintInfo;
void DrawPixel(size_t x, size_t y);
void FillScreen();
void FillScreen(uint32_t color);
void SetForegroundColor(uint32_t color);
uint32_t GetForegroundColor();

View File

@ -30,7 +30,8 @@ void Device::RegisterDevice(Device::GenericDevice* Device) {
DevicesArray[CurrentDevice] = Device;
Device->DeviceID = CurrentDevice;
CurrentDevice++;
SerialPrintf("[DEVICE] Registered device %d called %s of type %s\r\n", CurrentDevice - 1, Device->GetName(), DeviceNames[Device->GetType()]);
SerialPrintf("[DEVICE] Registered device %d called %s of type %s\r\n", CurrentDevice - 1, Device->GetName(),
DeviceNames[Device->GetType()]);
}
// Retrieve a device pointer from the managed list.

View File

@ -122,9 +122,9 @@ void UpdateKeyboard(uint8_t msg) {
}
KeyboardData data = (KeyboardData) {
.Scancode = msg,
.Pressed = msg > 0x80 && msg < 0xD8 ? false : true,
.Char = msg > 0x80 && msg < 0xD8 ? keys[msg - 0x80] : keys[msg]
.Char = msg > 0x80 && msg < 0xD8 ? keys[msg - 0x80] : keys[msg],
.Scancode = static_cast<char>(msg),
.Pressed = !(msg > 0x80 && msg < 0xD8),
};
void (* Handler)(KeyboardData data);

View File

@ -0,0 +1,139 @@
#include <driver/io/apic.h>
#include <kernel/system/acpi/madt.h>
#include <kernel/system/io.h>
#include <kernel/system/memory.h>
/************************
*** Team Kitty, 2021 ***
*** Chroma ***
***********************/
//TODO: remove
#define UNUSED(x) (void)x
// All of these functions are in the Device namespace.
using namespace Device;
Device::APIC* APIC::driver;
APIC::APIC() {
Ready = false;
driver = this;
}
void APIC::WriteIO(size_t Base, uint32_t Register, uint32_t Data) {
// MMIO - Set the base to the register we want to write into,
// 16 bytes higher the data we want to write, and the hardware does the rest.
*((volatile uint32_t*) Base) = Register;
*((volatile uint32_t*) (Base + 16)) = Data;
}
uint32_t APIC::ReadIO(size_t Base, uint32_t Register) {
// MMIO- Set the base to the register we want to read.
// The data we want will be put 16 bytes higher.
*((volatile uint32_t*) Base) = Register;
return *((volatile uint32_t*) (Base + 16));
}
uint32_t APIC::ReadRegister(uint32_t Register) {
return *((volatile uint32_t*) ((size_t*) Address + Register));
}
void APIC::WriteRegister(uint32_t Register, uint32_t Data) {
*((volatile uint32_t*) ((size_t*) Address + Register)) = Data;
}
void APIC::Enable() {
// Set the correct bits in the SIVR register. The APIC will be enabled.
WriteRegister(Registers::SIVR, ReadRegister(Registers::SIVR) | 0x1FF);
}
void APIC::SendEOI() {
WriteRegister(Registers::EOI, 0);
}
bool APIC::IsReady() {
return Ready;
}
void APIC::Init() {
SerialPrintf("[ACPI] Enabling APICs...");
Address = (void*) ACPI::MADT::instance->LocalAPICBase;
// TODO: Check whether the identity mapping covers this address
if (Address == nullptr) {
SerialPrintf("[ACPI] Unable to locate APICs.");
for (;;) { }
}
// Write "Local APIC Enabled" to the APIC Control Register.
WriteModelSpecificRegister(0x1B, (ReadModelSpecificRegister(0x1B) | 0x800) & ~(1 << 10));
Enable();
// Disable PIC1 and 2
WritePort(0x21, 0xFF, 1);
WritePort(0xA1, 0xFF, 1);
SerialPrintf("[ACPI] Enabling Global APIC..");
IOAPICs = ACPI::MADT::instance->GetIOApicEntries();
SerialPrintf("[ACPI] Enabling Interrupt Source Overrides..");
ISOs = ACPI::MADT::instance->GetISOEntries();
Ready = true;
}
uint32_t APIC::GetMaxRedirect(uint32_t ID) {
size_t address = (IOAPICs[ID]->Address);
uint32_t raw = (ReadIO(address, 0x1));
IOAPICMeta* table = (IOAPICMeta * ) & raw;
return table->MaxRedirect;
}
int APIC::GetCurrentCore() {
return ReadRegister(Registers::LAPIC_ID) >> 24;
}
void APIC::PreinitializeCore(int Core) {
WriteRegister(Registers::ICR2, Core << 24);
WriteRegister(Registers::ICR1, 0x500);
}
void APIC::InitializeCore(int Core, size_t EntryPoint) {
WriteRegister(Registers::ICR2, Core << 24);
WriteRegister(Registers::ICR1, 0x600 | ((uint32_t) (EntryPoint / PAGE_SIZE)));
}
void APIC::SetInternal(uint8_t Vector, uint32_t GSI, uint16_t Flags, int Core, int Status) {
UNUSED(Core);
size_t temp = Vector;
int64_t target = -1;
for (size_t i = 0; IOAPICs[i] != 0x0; i++)
if (IOAPICs[i]->GSI <= GSI)
if (IOAPICs[i]->GSI + GetMaxRedirect(i) > GSI) {
target = i;
continue;
}
if (target == -1) {
SerialPrintf("[APIC] No ISO found when setting up redirect.");
return;
}
if (Flags & 2)
temp |= (1 << 13);
if (Flags & 8)
temp |= (1 << 15);
if (!Status)
temp |= (1 << 16);
// TODO
}

View File

@ -22,7 +22,8 @@ extern size_t KernelLocation;
int ParseKernelHeader(size_t InitrdPtr) {
int flag = 0;
SerialPrintf("[ boot] Searching for kernel... Constants start at 0x%p / 0x%p\r\n", ((size_t) (&_kernel_text_start) - KernelAddr) + InitrdPtr, (size_t) (&_kernel_text_start));
SerialPrintf("[ boot] Searching for kernel... Constants start at 0x%p / 0x%p\r\n",
((size_t) (&_kernel_text_start) - KernelAddr) + InitrdPtr, (size_t) (&_kernel_text_start));
// We stop at the constants in the kernel, otherwise we'll read the constant ELF64MAGIC which is stored inside the kernel...
size_t headerLoc = 0;
@ -47,7 +48,8 @@ int ParseKernelHeader(size_t InitrdPtr) {
uint16_t EntryPoint1 = FIXENDIAN16(*((volatile uint16_t*) (headerLoc + ELFENTRY_OFF + 2)));
uint16_t EntryPoint2 = FIXENDIAN16(*((volatile uint16_t*) (headerLoc + ELFENTRY_OFF + 4)));
uint16_t EntryPoint3 = FIXENDIAN16(*((volatile uint16_t*) (headerLoc + ELFENTRY_OFF + 6)));
size_t EntryPoint = ((size_t) EntryPoint0 << 48) | ((size_t) EntryPoint1 << 32) | ((size_t) EntryPoint2 << 16) | ((size_t) EntryPoint3);
size_t EntryPoint = ((size_t) EntryPoint0 << 48) | ((size_t) EntryPoint1 << 32) | ((size_t) EntryPoint2 << 16) |
((size_t) EntryPoint3);
/* At this point, EntryPoint is a little-endian 64 bit integer. That means we have to fix its endianness in order to read it */
SerialPrintf("[ boot] Fixing entry point from 0x%p to 0x%p\r\n", EntryPoint, FIXENDIAN64(EntryPoint));
@ -71,8 +73,6 @@ int ParseKernelHeader(size_t InitrdPtr) {
FIXENDIAN16(MachineType));
if (EntryPoint == (size_t) (&_kernel_text_start)) {
SerialPrintf("[ boot] Header at 0x%p matches kernel header.\r\n", headerLoc);
flag = 1;

View File

@ -28,7 +28,7 @@ void Editor::StartEditor(int callbackID) {
layout.TextBoxX = (layout.ScreenWidth - layout.TextBoxWidth) / 2;
SetForegroundColor(0x000084);
FillScreen();
FillScreen(0x000084);
SetForegroundColor(0x00BBBBBB);
DrawFilledRect(0, 0, PrintInfo.screenWidth, layout.HeaderHeight);

138
src/global/core.s Normal file
View File

@ -0,0 +1,138 @@
;************************
;*** Team Kitty, 2021 ***
;*** Chroma ***
;************************
; Initial startup routines for new cores.
; New cores start in 16 bit real mode.
; Because of this, this is the only necessary assembler file in the OS.
; First, bring them up to Protected and Long mode.
; Then enable all necessary auxiliary features.
; Pass off to the CPP code to handle the heavy work, we just want the core running.
[bits 16]
BASE equ 0x1000
global stack
extern initcpu
extern coreidt
extern coregdt
global startCore
startCore:
cli
mov ax, 0x0
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
o32 lgdt [gdt_protected - startCore + BASE]
mov eax, cr0
or al, 0x1
mov cr0, eax
jmp 0x8:(startCore32 - startCore + BASE)
[bits 32]
section .text
startCore32:
mov bx, 0x10
mov ds, bx
mov es, bx
mov ss, bx
mov eax, dword [0xa000] ; Load bootloader tables into the new core
mov cr3, eax
mov eax, cr4 ; Enable PAE
or eax, 1 << 5
or eax, 1 << 7
mov cr4, eax
mov ecx, 0xc0000080
rdmsr
or eax, 1 << 8 ; Enable LME
wrmsr
mov eax, cr0
or eax, 1 << 31
mov cr0, eax
lgdt [gdt_long - startCore + BASE]
jmp 8:(startCore64 - startCore + BASE)
[bits 64]
startCore64:
mov ax, 0x10
mov ds, ax
mov es, ax
mov ss, ax
mov ax, 0x0 ; These will contain core information later on
mov fs, ax
mov gs, ax
lgdt [coregdt]
lidt [coreidt]
mov rbp, 0
push 0
popf
mov rax, qword leave
jmp leave
leave:
push rbp
mov rax, cr0
btr eax, 2
bts eax, 1
mov cr0, rax
mov rax, cr4
bts eax, 9
bts eax, 10
mov cr4, rax
call initcpu
align 16
gdt_long:
dw gdt_long_end - gdt_long_start - 1 ; gdt length
dq gdt_long_start - startCore + BASE ; address of the gdt
align 16
gdt_long_start:
dq 0
dq 0x00AF98000000FFFF
dq 0x00CF92000000FFFF
gdt_long_end:
align 16
gdt_protected:
dw gdt_protected_end - gdt_protected_start - 1 ; gdt length
dd gdt_protected_start - startCore + BASE ; address of the gdt
align 16
gdt_protected_start:
dq 0
dq 0x00CF9A000000FFFF
dq 0x00CF92000000FFFF
gdt_protected_end:
align 16
idt_protected:
dw 0
dd 0
dd 0
align 16
global endCore
endCore:

View File

@ -36,26 +36,32 @@ char* InternalBuffer;
#ifdef __cplusplus
}
#endif
/**
* C++ code! Scary!
* This is a temporary measure to experiment with the Editor system.
*/
int Main(void) {
extern "C" int Main(void) {
KernelAddressSpace.Lock.NextTicket = 0;
KernelAddressSpace.Lock.NowServing = 0;
KernelAddressSpace.PML4 = nullptr;
SerialPrintf("\r\n[ boot] Booting Chroma..\r\n");
SerialPrintf("[ boot] Bootloader data structure at 0x%p\r\n", (size_t) &bootldr);
SerialPrintf("[ boot] Kernel loaded at 0x%p, ends at 0x%p, is %d bytes long.\r\n", KernelAddr, KernelEnd, KernelEnd - KernelAddr);
SerialPrintf("[ boot] Framebuffer at 0x%p / 0x%p, is %dx%d, 0x%x bytes long.\r\n", bootldr.fb_ptr, (size_t) &fb, bootldr.fb_width, bootldr.fb_height, bootldr.fb_size);
SerialPrintf("[ boot] Initrd is physically at 0x%p, and is %d bytes long.\r\n", bootldr.initrd_ptr, bootldr.initrd_size);
SerialPrintf("[ boot] Kernel loaded at 0x%p, ends at 0x%p, is %d bytes long.\r\n", KernelAddr, KernelEnd,
KernelEnd - KernelAddr);
SerialPrintf("[ boot] Framebuffer at 0x%p / 0x%p, is %dx%d, 0x%x bytes long.\r\n", bootldr.fb_ptr, (size_t) &fb,
bootldr.fb_width, bootldr.fb_height, bootldr.fb_size);
SerialPrintf("[ boot] Initrd is physically at 0x%p, and is %d bytes long.\r\n", bootldr.initrd_ptr,
bootldr.initrd_size);
SerialPrintf("[ boot] Initrd's header is 0x%p\r\n", FIXENDIAN32(*((volatile uint32_t*) (bootldr.initrd_ptr))));
ParseKernelHeader(bootldr.initrd_ptr);
SerialPrintf("[ boot] The bootloader has put the paging tables at 0x%p.\r\n", ReadControlRegister(3));
SerialPrintf("[ boot] Removing bootloader code.\r\n");
memset((void*) 0x600, 0, 0x6600);
ListMemoryMap();
@ -89,7 +95,7 @@ int Main(void) {
return 0;
}
void PrintPressedChar(KeyboardData data) {
extern "C" void PrintPressedChar(KeyboardData data) {
if (!KernelLoaded) return;
if (data.Pressed) {
@ -100,7 +106,7 @@ void PrintPressedChar(KeyboardData data) {
}
}
void TrackInternalBuffer(KeyboardData data) {
extern "C" void TrackInternalBuffer(KeyboardData data) {
if (!data.Pressed) return;
bool tentative = false;
@ -135,11 +141,14 @@ void TrackInternalBuffer(KeyboardData data) {
}
}
void SomethingWentWrong(const char* Message) {
extern "C" void SomethingWentWrong(const char* Message) {
SerialPrintf("Assertion failed! %s\r\n", Message);
//for(;;){}
for(;;){}
}
void Exit(int ExitCode) {
extern "C" void __cxa_pure_virtual() { SomethingWentWrong("Pure Virtual Method Called"); }
extern "C" void Exit(int ExitCode) {
SerialPrintf("Kernel stopped with code %x\r\n", ExitCode);
}

View File

@ -22,8 +22,8 @@ void ListRemove(list_entry_t* Entry) {
Entry->Next->Previous = Entry->Previous;
Entry->Previous->Next = Entry->Next;
Entry->Previous = (void*)0xDEADull;
Entry->Next = (void*)0xBEEFull;
Entry->Previous = static_cast<list_entry*>((void*) 0xDEADull);
Entry->Next = static_cast<list_entry*>((void*) 0xBEEFull);
}
bool ListIsEmpty(list_entry_t* Head) {

74
src/system/acpi/MADT.cpp Normal file
View File

@ -0,0 +1,74 @@
#include <kernel/system/acpi/madt.h>
#include <kernel/chroma.h>
/************************
*** Team Kitty, 2021 ***
*** Chroma ***
***********************/
using namespace ACPI;
ACPI::MADT* MADT::instance;
MADT::MADT() {
instance = this;
}
size_t MADT::GetEndOfTable() {
return ((size_t) &Header->Header) + Header->Header.Length;
}
void MADT::Initialize() {
SerialPrintf("[ACPI] Loading Multiple APIC Descriptor Tables..");
Address = ACPI::RSDP::instance->FindEntry("APIC");
Header = reinterpret_cast<MADTHeader*>(Address);
LocalAPICBase = Header->LocalAPIC;
// TODO: Check whether the Base is identity mapped
}
MADT::IOAPICEntry** MADT::GetIOApicEntries() {
MADT::RecordTableEntry* table;
table = Header->Table;
auto** entries = (MADT::IOAPICEntry**) kmalloc(255);
size_t count = 0;
while ((size_t) table < GetEndOfTable()) {
table = (MADT::RecordTableEntry*) (((size_t) table) + table->Length);
if (table->Type == MADT::Type::IOAPIC) {
MADT::IOAPICEntry* io_apic = reinterpret_cast<MADT::IOAPICEntry*>(table);
entries[count] = (MADT::IOAPICEntry*) ((size_t) io_apic);
count++;
}
}
entries[count] = 0;
return entries;
}
MADT::ISOEntry** MADT::GetISOEntries() {
MADT::RecordTableEntry* table = Header->Table;
auto** entries = (MADT::ISOEntry**) kmalloc(255);
size_t count = 0;
while ((size_t) table < GetEndOfTable()) {
table = (MADT::RecordTableEntry*) (((size_t) table) + table->Length);
if (table->Type == MADT::Type::ISO) {
MADT::ISOEntry* io_apic = reinterpret_cast<MADT::ISOEntry*>(table);
entries[count] = (MADT::ISOEntry*) ((size_t) io_apic);
count++;
}
}
entries[count] = 0;
return entries;
}
MADT::RecordTableEntry* MADT::GetTableEntries() {
return Header->Table;
}

87
src/system/acpi/RSDP.cpp Normal file
View File

@ -0,0 +1,87 @@
#include <kernel/system/acpi/rsdt.h>
#include <kernel/chroma.h>
/************************
*** Team Kitty, 2021 ***
*** Chroma ***
***********************/
using namespace ACPI;
ACPI::RSDP* RSDP::instance;
void* RSDP::GetRSDP() {
// Search physical memory (via the direct region) for the "RSD PTR " magic string.
// TODO: this is extremely slow!
for (size_t i = TO_DIRECT(0x80000); i < TO_DIRECT(0x100000); i += 16) {
if (i == TO_DIRECT(0xA0000)) {
i = TO_DIRECT(0xE0000 - 16);
continue;
}
if (strcmp((char*) i, "RSD PTR ")) {
return (void*) i;
}
}
return nullptr;
}
RSDP::RSDP() {
instance = this;
Table = (RSDT*) 0;
Descriptor = (DescriptorV2*) 0;
}
void* RSDP::FindEntry(const char* Name) {
// Take the pointer to the RSD Table from the Direct region.
auto* table = reinterpret_cast<RSDP::RSDT*>(TO_DIRECT(Descriptor->Header.RSDT));
size_t entries = (table->Header.Length - sizeof(table->Header)) / 4;
// For each entry: if valid, search for the specified name.
for (size_t i = 0; i < entries; i++) {
if (table->OtherSDTs[i] == 0x0)
continue;
ACPIHeader* header = reinterpret_cast<ACPIHeader*>(table->OtherSDTs[i]);
if (strcmp(header->Signature, Name))
return (void*) header;
}
return nullptr;
}
void* RSDP::GetFACP(RSDT* Root) {
UNUSED(Root);
return FindEntry("FACP");
}
void RSDP::Init(size_t RSDP) {
UNUSED(RSDP);
SerialPrintf("[ACPI] Loading ACPI subsystem..");
Descriptor = (DescriptorV2*) GetRSDP();
Table = (RSDT *) TO_DIRECT(Descriptor->Header.RSDT);
SerialPrintf("[RSDP] Dumping RSDT..");
auto* table = reinterpret_cast<RSDP::RSDT*>(TO_DIRECT(Descriptor->Header.RSDT));
size_t entries = (table->Header.Length - sizeof(table->Header)) / 4;
// For each entry: if valid, search for the specified name.
for (size_t i = 0; i < entries; i++) {
if (table->OtherSDTs[i] == 0x0)
continue;
ACPIHeader* header = reinterpret_cast<ACPIHeader*>(table->OtherSDTs[i]);
SerialPrintf("[RSDP] Entry %d: Signature %.4s, OEM %.6s\n", i, header->Signature, header->OEMID);
}
}
void RSDP::PagingInit() {
// TODO: check whether the identity mapping makes this necessary.
}

134
src/system/core.cpp Normal file
View File

@ -0,0 +1,134 @@
#include <kernel/chroma.h>
#include <kernel/system/acpi/madt.h>
#include <driver/io/apic.h>
/************************
*** Team Kitty, 2021 ***
*** Chroma ***
***********************/
extern size_t startCore;
extern size_t endCore;
int Cores = 0;
volatile bool Ready = false;
Core Core::Processors[Constants::Core::MAX_CORES];
TSS64 Tasks[Constants::Core::MAX_CORES];
ACPI::MADT::LAPICEntry* LAPICs[Constants::Core::MAX_CORES];
extern "C" void initcpu() {
// Init APIC
WriteModelSpecificRegister(0x1B, (ReadModelSpecificRegister(0x1B) | 0x800) & ~(1 << 10));
Device::APIC::driver->Enable();
__asm__ __volatile__("mov %%fs, %0" : : "r" (Device::APIC::driver->GetCurrentCore()) : );
SerialPrintf("[CORE] Core %d ready.\r\n", Device::APIC::driver->GetCurrentCore());
// TODO: New GDT
__asm__ __volatile__("cli");
Ready = true;
__asm__ __volatile__("sti");
for (;;) { }
}
Core::Core(size_t APIC, size_t ID) {
Device::APIC::driver->PreinitializeCore(APIC);
GetCore(ID)->LocalAPIC = APIC;
Bootstrap();
SetupData(ID);
Device::APIC::driver->InitializeCore(APIC, CORE_BOOTSTRAP);
while (Ready != true) {
__asm__ ("nop");
}
Ready = false;
}
void Core::Init() {
using namespace ACPI;
Ready = false;
SerialPrintf("[CORE] Enabling Multiprocessing\n");
memset(Tasks, 0, Constants::Core::MAX_CORES * sizeof(TSS64));
for (size_t i = 0; i < Constants::Core::MAX_CORES; i++)
LAPICs[i] = nullptr;
// Parse MADT for cores
MADT::RecordTableEntry* table = MADT::instance->GetTableEntries();
Cores = 0;
// While there are more entries in the table..
while ((size_t) table < MADT::instance->GetEndOfTable()) {
// Move to the next entry (by skipping the length of the current entry)
table = (MADT::RecordTableEntry*) (((size_t) table) + table->Length);
// Check for a LAPIC record (which indicates a unique physical core)
if (table->Type == MADT::Type::LAPIC) {
// Find the data for the LAPIC with a reinterpret
MADT::LAPICEntry* lapic = reinterpret_cast<MADT::LAPICEntry*>(table);
// Set the current ID
LAPICs[Cores] = lapic;
// Tell the core that its' LAPIC is the current id
Core::GetCore(Cores)->LocalAPIC = lapic->APIC;
// Move to the next core if there is one.
Cores++;
}
}
SerialPrintf("[CORE] Found %d cores.\n", Cores);
if (Cores > 1)
SerialPrintf("[CORE] Bringing up other cores.\n");
// For each non-bootstrap core, initialize the necessary data and populate the array.
for (int i = 0; i < Cores; i++) {
SerialPrintf("[CORE] Enabling core %d.\n", i);
if (Device::APIC::driver->GetCurrentCore() != LAPICs[i]->Core)
Processors[i] = Core(LAPICs[i]->APIC, LAPICs[i]->Core);
}
}
void Core::Bootstrap() {
size_t coreStarterLen = endCore - startCore;
for (size_t i = 0; i < coreStarterLen + 2; i += PAGE_SIZE)
MapVirtualPage(AddressSpace, CORE_BOOTSTRAP + i, CORE_BOOTSTRAP + i, 0);
memcpy((void*) CORE_BOOTSTRAP, &startCore, coreStarterLen);
}
void Core::SetupData(size_t Core) {
// Write page tables
GetCore(Core)->AddressSpace->PML4 = GetCurrent()->AddressSpace->PML4;
*((size_t*) Initialization::PAGETABLES) = (size_t) GetCore(Core)->AddressSpace->PML4;
// Prepare stack
memset(GetCore(Core)->StackData, 0, Constants::Core::STACK_SIZE);
*((size_t*) Initialization::STACK) = (size_t) GetCore(Core)->StackData + Constants::Core::STACK_SIZE;
// GDT = 0x680
// IDT = 0x690
__asm__ __volatile__("sgdt (0x680)\n sidt (0x690)");
// Set startup address
*((size_t*) Initialization::STARTUP) = (size_t) &initcpu;
}
void Core::StackTrace(size_t Cycles) {
StackFrame* stack;
__asm__ __volatile__ ("mov %%rbp, %[dest]" : [dest] "=r"(stack) : :);
SerialPrintf("[Trace] Beginning stack trace. RBP is currently 0x%p\r\n", stack);
for (size_t frame = 0; stack != 0 && frame < Cycles; ++frame) {
SerialPrintf("[Trace] (%d) 0x%p: 0x%p \r\n", frame, stack->rbp, stack->rip);
stack = stack->rbp;
}
SerialPrintf("[Trace] Stack trace over.\r\n");
}

View File

@ -44,9 +44,9 @@ __attribute__((aligned(64))) static volatile size_t InitGDT[5] = {
0
};
__attribute__((aligned(64))) static volatile TSS64 TSSEntries = {0};
__attribute__((aligned(64))) static volatile TSS64 TSSEntries;
__attribute__((aligned(64))) static volatile IDT_GATE IDTEntries[256] = {0};
__attribute__((aligned(64))) static volatile IDT_GATE IDTEntries[256];
static void RefreshCS() {
@ -111,7 +111,7 @@ void PrepareCPU() {
*/
void SetupInitialGDT() {
DESC_TBL GDTData = {0};
DESC_TBL GDTData;
size_t TSSBase = (uint64_t) (&TSSEntries);
uint16_t TSSLower = (uint16_t) TSSBase;
@ -203,7 +203,7 @@ static void SetISRBP(size_t ISRNum, size_t ISRAddr) {
}
void SetupIDT() {
DESC_TBL IDTData = {0};
DESC_TBL IDTData;
IDTData.Limit = (sizeof(IDT_GATE) * 256) - 1;
IDTData.Base = (size_t) &IDTEntries;

View File

@ -1,468 +0,0 @@
#include <kernel/chroma.h>
#include <kernel/video/draw.h>
#include <kernel/system/interrupts.h>
#include <stdbool.h>
/************************
*** Team Kitty, 2020 ***
*** Chroma ***
***********************/
#ifdef __cplusplus
extern "C" {
#endif
/* This file contains all of the ISR and IRQ
* (Interrupt Service Request) functions.
*
* As they use the GCC interrupt attribute,
* this file must be compiled without red-
* zone protection, thus all of these
* functions are in their own file to
* accomodate this.
*
* Additionally, the kernel now has SSE/AVX support.
* So this file and this file *alone* must be compiled with
* -mgeneral-regs-only
*
* Calling a function like so:
*
* __attribute__((interrupt)) isr1(registers_t* frame) {}
*
* allows the function to be used to serve
* interrupts - GCC compiles it under unique
* conditions, as it preserves the state of
* the processor and stack between execution,
* as well as using the IRET instruction to
* return to the middle of the previous function.
*
* There is also a version of the interrupt
* attribute which allows for error handlers,
* these having a size_t input as an error code.
*/
const char* ExceptionStrings[] = {
"Division by Zero",
"Debug",
"Non Maskable Interrupt",
"Breakpoint",
"Into Detected Overflow",
"Out of Bounds",
"Invalid Opcode",
"No Coprocessor",
"Double Fault",
"Coprocessor Segment Overrun",
"Bad TSS",
"Segment Not Present",
"Stack Fault",
"General Protection Fault",
"Page Fault",
"Unknown Interrupt",
"Coprocessor Fault",
"Alignment Check",
"Machine Check",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved"
};
typedef void (*IRQHandler)(INTERRUPT_FRAME* Frame);
IRQHandler IRQ_Handlers[16] = {
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
typedef unsigned long long int uword_t;
/* All of the ISR routines call this function for now.
! This function is NOT leaf, and it might clobber the stack.
! Be careful!
*/
void ISR_Common(INTERRUPT_FRAME* Frame, size_t Exception) {
UNUSED(Frame);
/* Only the first 32 ISR/IRQs are reserved for exceptions by the CPU. We can handle up to 512 interrupts total, though. */
if(Exception < 32) {
SetForegroundColor(0x0000FF00);
FillScreen();
/* ExceptionStrings is an array of c-strings defined in kernel.h */
SerialPrintf("[ ISR] %s exception!\r\n", ExceptionStrings[Exception]);
}
}
/* The common handler for exceptions that throw error codes, which give us useful insight
into what went wrong. In pure Curle style, though, we just ignore the error code. */
void ISR_Error_Common(INTERRUPT_FRAME* Frame, size_t ErrorCode, size_t Exception) {
UNUSED(Frame);
if(Exception < 32) {
SetForegroundColor(0x0000FF00);
FillScreen();
SerialPrintf("[ ISR] ISR Error %d raised, EC %d!\r\n", Exception, ErrorCode);
SerialPrintf("[ ISR] %s exception!\r\n", ExceptionStrings[Exception]);
while(true) {}
}
}
/* Likewise, this function is common to all IRQ handlers. It calls the assigned routine,
which was set up earlier by irq_install.*/
void IRQ_Common(INTERRUPT_FRAME* Frame, size_t Interrupt) {
// First we need to define a function pointer..
void (*Handler)(INTERRUPT_FRAME* Frame);
/* We set all uninitialized routines to 0, so the if(handler) check here allows us to
safely tell whether we've actually got something for this IRQ. */
Handler = IRQ_Handlers[Interrupt];
// If there's something there,
if(Handler) {
SerialPrintf("[ IRQ] IRQ %d raised!\r\n", Interrupt);
// Call the handler.
Handler(Frame);
}
/* The Slave PIC must be told it's been read in order to receive another 8+ IRQ. */
if(Interrupt > 7)
WritePort(0xA0, 0x20, 1);
/* In either case, we tell the Master PIC it's been read to receive any IRQ. */
WritePort(0x20, 0x20, 1);
}
/* However, in order to actually be able to receive IRQs, we need to remap the PICs. */
void RemapIRQControllers() {
/* 0x20 is the Master PIC,
0xA0 is the Slave PIC. */
WritePort(0x20, 0x11, 1);
WritePort(0xA0, 0x11, 1);
WritePort(0x21, 0x20, 1);
WritePort(0xA1, 0x28, 1);
WritePort(0x21, 0x04, 1);
WritePort(0xA1, 0x02, 1);
WritePort(0x21, 0x01, 1);
WritePort(0xA1, 0x01, 1);
WritePort(0x21, 0x0, 1);
WritePort(0xA1, 0x0, 1);
}
/* In order to actually handle the IRQs, though, we need to tell the kernel *where* the handlers are. */
/* A simple wrapper that adds a function pointer to the IRQ array. */
void InstallIRQ(int IRQ, void (*Handler)(INTERRUPT_FRAME* Frame)) {
IRQ_Handlers[IRQ] = Handler;
}
/* A simple wrapper that unlinks a function pointer, rendering the IRQ unused. */
void UninstallIRQHandler(int IRQ) {
IRQ_Handlers[IRQ] = NULL; // 0 is used in the common check to make sure that the function is callable.
// This removes this IRQ from that check, ergo the function will no longer be called.
}
void EmptyIRQ(INTERRUPT_FRAME* frame) {
UNUSED(frame);
// Flash the borders green, then back to blue
SetForegroundColor(0x0000FF00);
for(size_t y = 0; y < bootldr.fb_height; y++) {
for(size_t x = 0; x < 20; x++) {
DrawPixel(x, y);
}
for(size_t x = (bootldr.fb_width - 20); x < bootldr.fb_width; x++) {
DrawPixel(x, y);
}
}
for(size_t x = 0; x < bootldr.fb_width; x++) {
for(size_t y = 0; y < 20; y++) {
DrawPixel(x, y);
}
for(size_t y = (bootldr.fb_height - 20); y < bootldr.fb_height; y++) {
DrawPixel(x, y);
}
}
for(size_t i = 0; i < 100000; i++) {}
SetForegroundColor(0x000000FF);
for(size_t y = 0; y < bootldr.fb_height; y++) {
for(size_t x = 0; x < 20; x++) {
DrawPixel(x, y);
}
for(size_t x = (bootldr.fb_width - 20); x < bootldr.fb_width; x++) {
DrawPixel(x, y);
}
}
for(size_t x = 0; x < bootldr.fb_width; x++) {
for(size_t y = 0; y < 20; y++) {
DrawPixel(x, y);
}
for(size_t y = (bootldr.fb_height - 20); y < bootldr.fb_height; y++) {
DrawPixel(x, y);
}
}
}
static void KeyboardCallback(INTERRUPT_FRAME* frame) {
UNUSED(frame);
uint8_t msg = ReadPort(0x60, 1);
UpdateKeyboard(msg);
WaitFor8042();
}
void InitInterrupts() {
size_t RFLAGS = ReadControlRegister('f');
if(!(RFLAGS & (1 << 9))) {
WriteControlRegister('f', RFLAGS | (1 << 9));
}
InstallIRQ(1, &KeyboardCallback);
Send8042(0xF002);
__asm__ __volatile__("sti");
}
/* The interrupt numbers, their meanings, and
* special information is laid out below:
*
* 0 - Divide by Zero
* 1 - Debug
* 2 - Non-Maskable
* 3 - Breakpoint
* 4 - Into Detected Overflow
* 5 - Out of Bounds
* 6 - Invalid Opcode
* 7 - No Coprocessor
* 8 - Double Fault * (With Error)
* 9 - Coprocessor Segment Overrun
* 10 - Bad TSS * (With Error)
* 11 - Segment Not Present * (With Error)
* 12 - Stack Fault * (With Error)
* 13 - General Protection Fault * (With Error)
* 14 - Page Fault * (With Error)
* 15 - Unknown Interrupt
* 16 - Coprocessor Fault
* 17 - Alignment Check
* 18 - Machine Check
* 19 to 31 - Reserved
*/
__attribute__((interrupt)) void ISR0Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 0);
}
__attribute__((interrupt)) void ISR1Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 1);
}
__attribute__((interrupt)) void ISR2Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 2);
}
__attribute__((interrupt)) void ISR3Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 3);
}
__attribute__((interrupt)) void ISR4Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 4);
}
__attribute__((interrupt)) void ISR5Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 5);
}
__attribute__((interrupt)) void ISR6Handler(INTERRUPT_FRAME* Frame) {
__asm__ __volatile__("sti");
SerialPrintf("[FAULT] Invalid Opcode!\n");
size_t retAddr = 0;
size_t opcodeAddr = Frame->rip;
__asm__ __volatile__("popq %%rax\n\t" "pushq %%rax": "=a" (retAddr) : :);
SerialPrintf("[FAULT] Opcode is at 0x%x, called from 0x%p\r\n", opcodeAddr, retAddr);
Printf("Invalid Opcode: 0x%p\n", opcodeAddr);
StackTrace(15);
for(;;) {}
}
__attribute__((interrupt)) void ISR7Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 7);
}
__attribute__((interrupt)) void ISR8Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
ISR_Error_Common(Frame, ErrorCode, 8);
}
__attribute__((interrupt)) void ISR9Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 9);
}
__attribute__((interrupt)) void ISR10Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
ISR_Error_Common(Frame, ErrorCode, 10);
}
__attribute__((interrupt)) void ISR11Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
ISR_Error_Common(Frame, ErrorCode, 11);
}
__attribute__((interrupt)) void ISR12Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
ISR_Error_Common(Frame, ErrorCode, 12);
}
__attribute__((interrupt)) void ISR13Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
SerialPrintf("\r\n\n[ GPF] RIP: 0x%p, CS: 0x%x, FLAGS: 0x%p, RSP: 0x%x, SS: 0x%x\r\n", Frame->rip, Frame->cs, Frame->rflags, Frame->rsp, Frame->ss);
StackTrace(6);
ISR_Error_Common(Frame, ErrorCode, 13); // General Protection
}
__attribute__((interrupt)) void ISR14Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
__asm__ __volatile__("sti");
SerialPrintf("\r\n\n\n[FAULT] Page fault! Caused by {\r\n");
//size_t FaultAddr = ReadControlRegister(2);
uint8_t FaultPres = ErrorCode & 0x1;
uint8_t FaultRW = ErrorCode & 0x2;
uint8_t FaultUser = ErrorCode & 0x4;
uint8_t FaultReserved = ErrorCode & 0x8;
uint8_t FaultInst = ErrorCode & 0x10;
if(!FaultPres) SerialPrintf("[FAULT] Accessed a page that isn't present.\r\n");
if(FaultRW || FaultUser) SerialPrintf("[FAULT] Accessed a Read-Only page.\r\n");
if(FaultReserved) SerialPrintf("[FAULT] Overwrote reserved bits.\r\n");
if(FaultInst) SerialPrintf("[FAULT] \"Instruction Fetch\"");
SerialPrintf("[FAULT] } at address\n[FAULT] 0x%p\r\n\n", ReadControlRegister(2));
StackTrace(6);
ISR_Error_Common(Frame, ErrorCode, 14); // Page Fault
}
__attribute__((interrupt)) void ISR15Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 15);
}
__attribute__((interrupt)) void ISR16Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 16);
}
__attribute__((interrupt)) void ISR17Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
ISR_Error_Common(Frame, ErrorCode, 17);
}
__attribute__((interrupt)) void ISR18Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 18);
}
__attribute__((interrupt)) void ISR19Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 19);
}
__attribute__((interrupt)) void ISR20Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 20);
}
__attribute__((interrupt)) void ISR21Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 21);
}
__attribute__((interrupt)) void ISR22Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 22);
}
__attribute__((interrupt)) void ISR23Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 23);
}
__attribute__((interrupt)) void ISR24Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 24);
}
__attribute__((interrupt)) void ISR25Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 25);
}
__attribute__((interrupt)) void ISR26Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 26);
}
__attribute__((interrupt)) void ISR27Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 27);
}
__attribute__((interrupt)) void ISR28Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 28);
}
__attribute__((interrupt)) void ISR29Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 29);
}
__attribute__((interrupt)) void ISR30Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
ISR_Error_Common(Frame, ErrorCode, 30);
}
__attribute__((interrupt)) void ISR31Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 31);
}
__attribute__((interrupt)) void ReservedISRHandler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 33); // if < 32, isn't handled.
// Effectively disables this ISR.
}
__attribute__((interrupt)) void IRQ0Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 0);
}
__attribute__((interrupt)) void IRQ1Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 1); // Keyboard handler
}
__attribute__((interrupt)) void IRQ2Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 2);
}
__attribute__((interrupt)) void IRQ3Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 3);
}
__attribute__((interrupt)) void IRQ4Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 4);
}
__attribute__((interrupt)) void IRQ5Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 5);
}
__attribute__((interrupt)) void IRQ6Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 6);
}
__attribute__((interrupt)) void IRQ7Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 7);
}
__attribute__((interrupt)) void IRQ8Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 8);
}
__attribute__((interrupt)) void IRQ9Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 9);
}
__attribute__((interrupt)) void IRQ10Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 10);
}
__attribute__((interrupt)) void IRQ11Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 11);
}
__attribute__((interrupt)) void IRQ12Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 12);
}
__attribute__((interrupt)) void IRQ13Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 13);
}
__attribute__((interrupt)) void IRQ14Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 14);
}
__attribute__((interrupt)) void IRQ15Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 15);
}
#ifdef __cplusplus
}
#endif

515
src/system/interrupts.cpp Normal file
View File

@ -0,0 +1,515 @@
#include <kernel/chroma.h>
#include <kernel/video/draw.h>
#include <kernel/system/interrupts.h>
#include <stdbool.h>
/************************
*** Team Kitty, 2020 ***
*** Chroma ***
***********************/
#ifdef __cplusplus
extern "C" {
#endif
/* This file contains all of the ISR and IRQ
* (Interrupt Service Request) functions.
*
* As they use the GCC interrupt attribute,
* this file must be compiled without red-
* zone protection, thus all of these
* functions are in their own file to
* accomodate this.
*
* Additionally, the kernel now has SSE/AVX support.
* So this file and this file *alone* must be compiled with
* -mgeneral-regs-only
*
* Calling a function like so:
*
* __attribute__((interrupt)) isr1(registers_t* frame) {}
*
* allows the function to be used to serve
* interrupts - GCC compiles it under unique
* conditions, as it preserves the state of
* the processor and stack between execution,
* as well as using the IRET instruction to
* return to the middle of the previous function.
*
* There is also a version of the interrupt
* attribute which allows for error handlers,
* these having a size_t input as an error code.
*/
const char* ExceptionStrings[] = {
"Division by Zero",
"Debug",
"Non Maskable Interrupt",
"Breakpoint",
"Into Detected Overflow",
"Out of Bounds",
"Invalid Opcode",
"No Coprocessor",
"Double Fault",
"Coprocessor Segment Overrun",
"Bad TSS",
"Segment Not Present",
"Stack Fault",
"General Protection Fault",
"Page Fault",
"Unknown Interrupt",
"Coprocessor Fault",
"Alignment Check",
"Machine Check",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved"
};
typedef void (* IRQHandler)(INTERRUPT_FRAME* Frame);
IRQHandler IRQ_Handlers[16] = {
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
typedef unsigned long long int uword_t;
/* All of the ISR routines call this function for now.
! This function is NOT leaf, and it might clobber the stack.
! Be careful!
*/
__attribute__((no_caller_saved_registers)) void ISR_Common(INTERRUPT_FRAME* Frame, size_t Exception) {
UNUSED(Frame);
/* Only the first 32 ISR/IRQs are reserved for exceptions by the CPU. We can handle up to 512 interrupts total, though. */
if (Exception < 32) {
SetForegroundColor(0x0000FF00);
FillScreen(0x0000FF00);
/* ExceptionStrings is an array of c-strings defined in kernel.h */
SerialPrintf("[ ISR] %s exception!\r\n", ExceptionStrings[Exception]);
}
}
/* The common handler for exceptions that throw error codes, which give us useful insight
into what went wrong. In pure Curle style, though, we just ignore the error code. */
void ISR_Error_Common(INTERRUPT_FRAME* Frame, size_t ErrorCode, size_t Exception) {
UNUSED(Frame);
if (Exception < 32) {
SetForegroundColor(0x0000FF00);
FillScreen(0x0000FF00);
SerialPrintf("[ ISR] ISR Error %d raised, EC %d!\r\n", Exception, ErrorCode);
SerialPrintf("[ ISR] %s exception!\r\n", ExceptionStrings[Exception]);
while (true) { }
}
}
/* Likewise, this function is common to all IRQ handlers. It calls the assigned routine,
which was set up earlier by irq_install.*/
void IRQ_Common(INTERRUPT_FRAME* Frame, size_t Interrupt) {
// First we need to define a function pointer..
void (* Handler)(INTERRUPT_FRAME* Frame);
/* We set all uninitialized routines to 0, so the if(handler) check here allows us to
safely tell whether we've actually got something for this IRQ. */
Handler = IRQ_Handlers[Interrupt];
// If there's something there,
if (Handler) {
SerialPrintf("[ IRQ] IRQ %d raised!\r\n", Interrupt);
// Call the handler.
Handler(Frame);
}
/* The Slave PIC must be told it's been read in order to receive another 8+ IRQ. */
if (Interrupt > 7)
WritePort(0xA0, 0x20, 1);
/* In either case, we tell the Master PIC it's been read to receive any IRQ. */
WritePort(0x20, 0x20, 1);
}
/* However, in order to actually be able to receive IRQs, we need to remap the PICs. */
void RemapIRQControllers() {
/* 0x20 is the Master PIC,
0xA0 is the Slave PIC. */
WritePort(0x20, 0x11, 1);
WritePort(0xA0, 0x11, 1);
WritePort(0x21, 0x20, 1);
WritePort(0xA1, 0x28, 1);
WritePort(0x21, 0x04, 1);
WritePort(0xA1, 0x02, 1);
WritePort(0x21, 0x01, 1);
WritePort(0xA1, 0x01, 1);
WritePort(0x21, 0x0, 1);
WritePort(0xA1, 0x0, 1);
}
/* In order to actually handle the IRQs, though, we need to tell the kernel *where* the handlers are. */
/* A simple wrapper that adds a function pointer to the IRQ array. */
void InstallIRQ(int IRQ, void (* Handler)(INTERRUPT_FRAME* Frame)) {
IRQ_Handlers[IRQ] = Handler;
}
/* A simple wrapper that unlinks a function pointer, rendering the IRQ unused. */
void UninstallIRQHandler(int IRQ) {
IRQ_Handlers[IRQ] = NULL; // 0 is used in the common check to make sure that the function is callable.
// This removes this IRQ from that check, ergo the function will no longer be called.
}
void EmptyIRQ(INTERRUPT_FRAME* frame) {
UNUSED(frame);
// Flash the borders green, then back to blue
SetForegroundColor(0x0000FF00);
for (size_t y = 0; y < bootldr.fb_height; y++) {
for (size_t x = 0; x < 20; x++) {
DrawPixel(x, y);
}
for (size_t x = (bootldr.fb_width - 20); x < bootldr.fb_width; x++) {
DrawPixel(x, y);
}
}
for (size_t x = 0; x < bootldr.fb_width; x++) {
for (size_t y = 0; y < 20; y++) {
DrawPixel(x, y);
}
for (size_t y = (bootldr.fb_height - 20); y < bootldr.fb_height; y++) {
DrawPixel(x, y);
}
}
for (size_t i = 0; i < 100000; i++) { }
SetForegroundColor(0x000000FF);
for (size_t y = 0; y < bootldr.fb_height; y++) {
for (size_t x = 0; x < 20; x++) {
DrawPixel(x, y);
}
for (size_t x = (bootldr.fb_width - 20); x < bootldr.fb_width; x++) {
DrawPixel(x, y);
}
}
for (size_t x = 0; x < bootldr.fb_width; x++) {
for (size_t y = 0; y < 20; y++) {
DrawPixel(x, y);
}
for (size_t y = (bootldr.fb_height - 20); y < bootldr.fb_height; y++) {
DrawPixel(x, y);
}
}
}
static void KeyboardCallback(INTERRUPT_FRAME* frame) {
UNUSED(frame);
uint8_t msg = ReadPort(0x60, 1);
UpdateKeyboard(msg);
WaitFor8042();
}
void InitInterrupts() {
size_t RFLAGS = ReadControlRegister('f');
if (!(RFLAGS & (1 << 9))) {
WriteControlRegister('f', RFLAGS | (1 << 9));
}
InstallIRQ(1, &KeyboardCallback);
Send8042(0xF002);
__asm__ __volatile__("sti");
}
/* The interrupt numbers, their meanings, and
* special information is laid out below:
*
* 0 - Divide by Zero
* 1 - Debug
* 2 - Non-Maskable
* 3 - Breakpoint
* 4 - Into Detected Overflow
* 5 - Out of Bounds
* 6 - Invalid Opcode
* 7 - No Coprocessor
* 8 - Double Fault * (With Error)
* 9 - Coprocessor Segment Overrun
* 10 - Bad TSS * (With Error)
* 11 - Segment Not Present * (With Error)
* 12 - Stack Fault * (With Error)
* 13 - General Protection Fault * (With Error)
* 14 - Page Fault * (With Error)
* 15 - Unknown Interrupt
* 16 - Coprocessor Fault
* 17 - Alignment Check
* 18 - Machine Check
* 19 to 31 - Reserved
*/
__attribute__((interrupt)) void ISR0Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 0);
}
__attribute__((interrupt)) void ISR1Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 1);
}
__attribute__((interrupt)) void ISR2Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 2);
}
__attribute__((interrupt)) void ISR3Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 3);
}
__attribute__((interrupt)) void ISR4Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 4);
}
__attribute__((interrupt)) void ISR5Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 5);
}
__attribute__((interrupt)) void ISR6Handler(INTERRUPT_FRAME* Frame) {
__asm__ __volatile__("sti");
SerialPrintf("[FAULT] Invalid Opcode!\n");
size_t retAddr = 0;
size_t opcodeAddr = Frame->rip;
__asm__ __volatile__("popq %%rax\n\t" "pushq %%rax": "=a" (retAddr) : :);
SerialPrintf("[FAULT] Opcode is at 0x%x, called from 0x%p\r\n", opcodeAddr, retAddr);
Printf("Invalid Opcode: 0x%p\n", opcodeAddr);
Core::GetCurrent()->StackTrace(15);
for (;;) { }
}
__attribute__((interrupt)) void ISR7Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 7);
}
__attribute__((interrupt)) void ISR8Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
ISR_Error_Common(Frame, ErrorCode, 8);
}
__attribute__((interrupt)) void ISR9Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 9);
}
__attribute__((interrupt)) void ISR10Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
ISR_Error_Common(Frame, ErrorCode, 10);
}
__attribute__((interrupt)) void ISR11Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
ISR_Error_Common(Frame, ErrorCode, 11);
}
__attribute__((interrupt)) void ISR12Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
ISR_Error_Common(Frame, ErrorCode, 12);
}
__attribute__((interrupt)) void ISR13Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
SerialPrintf("\r\n\n[ GPF] RIP: 0x%p, CS: 0x%x, FLAGS: 0x%p, RSP: 0x%x, SS: 0x%x\r\n", Frame->rip, Frame->cs,
Frame->rflags, Frame->rsp, Frame->ss);
Core::GetCurrent()->StackTrace(6);
ISR_Error_Common(Frame, ErrorCode, 13); // General Protection
}
__attribute__((interrupt)) void ISR14Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
__asm__ __volatile__("sti");
SerialPrintf("\r\n\n\n[FAULT] Page fault! Caused by {\r\n");
//size_t FaultAddr = ReadControlRegister(2);
uint8_t FaultPres = ErrorCode & 0x1;
uint8_t FaultRW = ErrorCode & 0x2;
uint8_t FaultUser = ErrorCode & 0x4;
uint8_t FaultReserved = ErrorCode & 0x8;
uint8_t FaultInst = ErrorCode & 0x10;
if (!FaultPres) SerialPrintf("[FAULT] Accessed a page that isn't present.\r\n");
if (FaultRW || FaultUser) SerialPrintf("[FAULT] Accessed a Read-Only page.\r\n");
if (FaultReserved) SerialPrintf("[FAULT] Overwrote reserved bits.\r\n");
if (FaultInst) SerialPrintf("[FAULT] \"Instruction Fetch\"");
SerialPrintf("[FAULT] } at address\n[FAULT] 0x%p\r\n\n", ReadControlRegister(2));
Core::GetCurrent()->StackTrace(6);
ISR_Error_Common(Frame, ErrorCode, 14); // Page Fault
}
__attribute__((interrupt)) void ISR15Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 15);
}
__attribute__((interrupt)) void ISR16Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 16);
}
__attribute__((interrupt)) void ISR17Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
ISR_Error_Common(Frame, ErrorCode, 17);
}
__attribute__((interrupt)) void ISR18Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 18);
}
__attribute__((interrupt)) void ISR19Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 19);
}
__attribute__((interrupt)) void ISR20Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 20);
}
__attribute__((interrupt)) void ISR21Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 21);
}
__attribute__((interrupt)) void ISR22Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 22);
}
__attribute__((interrupt)) void ISR23Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 23);
}
__attribute__((interrupt)) void ISR24Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 24);
}
__attribute__((interrupt)) void ISR25Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 25);
}
__attribute__((interrupt)) void ISR26Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 26);
}
__attribute__((interrupt)) void ISR27Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 27);
}
__attribute__((interrupt)) void ISR28Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 28);
}
__attribute__((interrupt)) void ISR29Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 29);
}
__attribute__((interrupt)) void ISR30Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
ISR_Error_Common(Frame, ErrorCode, 30);
}
__attribute__((interrupt)) void ISR31Handler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 31);
}
__attribute__((interrupt)) void ReservedISRHandler(INTERRUPT_FRAME* Frame) {
ISR_Common(Frame, 33); // if < 32, isn't handled.
// Effectively disables this ISR.
}
__attribute__((interrupt)) void IRQ0Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 0);
}
__attribute__((interrupt)) void IRQ1Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 1); // Keyboard handler
}
__attribute__((interrupt)) void IRQ2Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 2);
}
__attribute__((interrupt)) void IRQ3Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 3);
}
__attribute__((interrupt)) void IRQ4Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 4);
}
__attribute__((interrupt)) void IRQ5Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 5);
}
__attribute__((interrupt)) void IRQ6Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 6);
}
__attribute__((interrupt)) void IRQ7Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 7);
}
__attribute__((interrupt)) void IRQ8Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 8);
}
__attribute__((interrupt)) void IRQ9Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 9);
}
__attribute__((interrupt)) void IRQ10Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 10);
}
__attribute__((interrupt)) void IRQ11Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 11);
}
__attribute__((interrupt)) void IRQ12Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 12);
}
__attribute__((interrupt)) void IRQ13Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 13);
}
__attribute__((interrupt)) void IRQ14Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 14);
}
__attribute__((interrupt)) void IRQ15Handler(INTERRUPT_FRAME* Frame) {
IRQ_Common(Frame, 15);
}
#ifdef __cplusplus
}
#endif

View File

@ -80,7 +80,6 @@ alloc_decl int Alloc_FindLastOne_64(size_t size) {
#undef alloc_decl
/*********************************************
* T Y P E D E F I N I T I O N S
**********************************************/
@ -331,12 +330,16 @@ static void RemoveFreeBlock(allocator_control_t* Controller, block_header_t* Blo
}
}
static void InsertFreeBlock(allocator_control_t* Controller, block_header_t* NewBlock, int FirstLevel, int SecondLevel) {
static void
InsertFreeBlock(allocator_control_t* Controller, block_header_t* NewBlock, int FirstLevel, int SecondLevel) {
block_header_t* Current = Controller->Blocks[FirstLevel][SecondLevel];
ASSERT(Current, "InsertFreeBlock: Current Block is null!");
if (!Current) {
SerialPrintf("Extra info: \r\n\tFirst Level: %x Second Level: %x\r\nFirst Level bitmap: %x, Second Level bitmap: %x\r\n\tBlocks %x, BlocksAddress: %x", FirstLevel, SecondLevel, Controller->FirstLevel_Bitmap, Controller->SecondLevel_Bitmap, Controller->Blocks, Controller->Blocks[FirstLevel][SecondLevel]);
SerialPrintf(
"Extra info: \r\n\tFirst Level: %x Second Level: %x\r\nFirst Level bitmap: %x, Second Level bitmap: %x\r\n\tBlocks %x, BlocksAddress: %x",
FirstLevel, SecondLevel, Controller->FirstLevel_Bitmap, Controller->SecondLevel_Bitmap,
Controller->Blocks, Controller->Blocks[FirstLevel][SecondLevel]);
for (;;) { }
}
ASSERT(NewBlock, "InsertFreeBlock: New Block is null!");
@ -346,7 +349,8 @@ static void InsertFreeBlock(allocator_control_t* Controller, block_header_t* New
Current->LastFreeBlock = NewBlock;
ASSERT(WhereBlock(NewBlock) == AlignPointer(WhereBlock(NewBlock), ALIGN_SIZE), "InsertFreeBlock: Current block is not memory aligned!");
ASSERT(WhereBlock(NewBlock) == AlignPointer(WhereBlock(NewBlock), ALIGN_SIZE),
"InsertFreeBlock: Current block is not memory aligned!");
Controller->Blocks[FirstLevel][SecondLevel] = NewBlock;
Controller->FirstLevel_Bitmap |= (1U << FirstLevel);
@ -376,7 +380,8 @@ static block_header_t* SplitBlock(block_header_t* Block, size_t NewSize) {
const size_t RemainingSize = BlockSize(Block) - (NewSize + BLOCK_OVERHEAD);
ASSERT(WhereBlock(Overlap) == AlignPointer(WhereBlock(Overlap), ALIGN_SIZE), "SplitBlock: Requested size results in intermediary block which is not aligned!");
ASSERT(WhereBlock(Overlap) == AlignPointer(WhereBlock(Overlap), ALIGN_SIZE),
"SplitBlock: Requested size results in intermediary block which is not aligned!");
ASSERT(BlockSize(Block) == RemainingSize + NewSize + BLOCK_OVERHEAD, "SplitBlock: Maths error!");
@ -530,7 +535,6 @@ static void ConstructController(allocator_control_t* Controller) {
}
/***********************************************************************************
* H E A D E R ( A P I ) F U N C T I O N S
************************************************************************************/
@ -585,7 +589,9 @@ mempool_t AddPoolToAllocator(allocator_t Allocator, void* Address, size_t Size)
}
if (PoolBytes < BLOCK_MIN_SIZE || PoolBytes > BLOCK_MAX_SIZE) {
SerialPrintf("Memory manager error at [%s:%x]: Memory Size out of bounds: 0x%x-0x%x: 0x%x.\r\n", __FILE__, __LINE__, (unsigned int)(PoolOverhead + BLOCK_MIN_SIZE), (unsigned int)(PoolOverhead + BLOCK_MAX_SIZE) / 256, PoolBytes);
SerialPrintf("Memory manager error at [%s:%x]: Memory Size out of bounds: 0x%x-0x%x: 0x%x.\r\n", __FILE__,
__LINE__, (unsigned int) (PoolOverhead + BLOCK_MIN_SIZE),
(unsigned int) (PoolOverhead + BLOCK_MAX_SIZE) / 256, PoolBytes);
return 0;
}

View File

@ -1,867 +0,0 @@
#include <stdint.h>
#include <kernel/system/memory.h>
/** Durand's Amazing Super Duper Memory functions. */
#ifdef __cplusplus
extern "C" {
#endif
#define VERSION "1.1"
#define ALIGNMENT 16ul//4ul ///< This is the byte alignment that memory must be allocated on. IMPORTANT for GTK and other stuff.
#define ALIGN_TYPE char ///unsigned char[16] /// unsigned short
#define ALIGN_INFO sizeof(ALIGN_TYPE)*16 ///< Alignment information is stored right before the pointer. This is the number of bytes of information stored there.
#define USE_CASE1
#define USE_CASE2
#define USE_CASE3
#define USE_CASE4
#define USE_CASE5
extern address_space_t KernelAddressSpace;
/** This function is supposed to lock the memory data structures. It
* could be as simple as disabling interrupts or acquiring a spinlock.
* It's up to you to decide.
*
* \return 0 if the lock was acquired successfully. Anything else is
* failure.
*/
static int liballoc_lock() {
return TicketAttemptLock(&KernelAddressSpace.Lock) ? 0 : 1;
}
/** This function unlocks what was previously locked by the liballoc_lock
* function. If it disabled interrupts, it enables interrupts. If it
* had acquiried a spinlock, it releases the spinlock. etc.
*
*/
static void liballoc_unlock() {
TicketUnlock(&KernelAddressSpace.Lock);
}
/** This is the hook into the local system which allocates pages. It
* accepts an integer parameter which is the number of pages
* required. The page size was set up in the liballoc_init function.
*
* \return NULL if the pages were not allocated.
* \return A pointer to the allocated memory.
*/
static void* liballoc_alloc(size_t count) {
return (void*) PhysAllocateZeroMem(count * PAGE_SIZE);
}
/** This frees previously allocated memory. The void* parameter passed
* to the function is the exact same value returned from a previous
* liballoc_alloc call.
*
* The integer value is the number of pages to free.
*
* \return 0 if the memory was successfully freed.
*/
static int liballoc_free(void* ptr, size_t count) {
PhysFreeMem(ptr, count * PAGE_SIZE);
return 0;
}
/** This macro will conveniently align our pointer upwards */
#define ALIGN( ptr ) \
if ( ALIGNMENT > 1 ) \
{ \
uintptr_t diff; \
ptr = (void*)((uintptr_t)ptr + ALIGN_INFO); \
diff = (uintptr_t)ptr & (ALIGNMENT-1); \
if ( diff != 0 ) \
{ \
diff = ALIGNMENT - diff; \
ptr = (void*)((uintptr_t)ptr + diff); \
} \
*((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)) = \
diff + ALIGN_INFO; \
}
#define UNALIGN( ptr ) \
if ( ALIGNMENT > 1 ) \
{ \
uintptr_t diff = *((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)); \
if ( diff < (ALIGNMENT + ALIGN_INFO) ) \
{ \
ptr = (void*)((uintptr_t)ptr - diff); \
} \
}
#define LIBALLOC_MAGIC 0xc001c0de
#define LIBALLOC_DEAD 0xdeaddead
#if defined DEBUG || defined INFO
#include <stdio.h>
#include <stdlib.h>
#define FLUSH() fflush( stdout )
#endif
/** A structure found at the top of all system allocated
* memory blocks. It details the usage of the memory block.
*/
struct liballoc_major
{
struct liballoc_major *prev; ///< Linked list information.
struct liballoc_major *next; ///< Linked list information.
unsigned int pages; ///< The number of pages in the block.
unsigned int size; ///< The number of pages in the block.
unsigned int usage; ///< The number of bytes used in the block.
struct liballoc_minor *first; ///< A pointer to the first allocated memory in the block.
};
/** This is a structure found at the beginning of all
* sections in a major block which were allocated by a
* malloc, calloc, realloc call.
*/
struct liballoc_minor
{
struct liballoc_minor *prev; ///< Linked list information.
struct liballoc_minor *next; ///< Linked list information.
struct liballoc_major *block; ///< The owning block. A pointer to the major structure.
unsigned int magic; ///< A magic number to idenfity correctness.
unsigned int size; ///< The size of the memory allocated. Could be 1 byte or more.
unsigned int req_size; ///< The size of memory requested.
};
static struct liballoc_major *l_memRoot = NULL; ///< The root memory block acquired from the system.
static struct liballoc_major *l_bestBet = NULL; ///< The major with the most free memory.
static unsigned int l_pageSize = 4096; ///< The size of an individual page. Set up in liballoc_init.
static unsigned int l_pageCount = 16; ///< The number of pages to request per chunk. Set up in liballoc_init.
static unsigned long long l_allocated = 0; ///< Running total of allocated memory.
static unsigned long long l_inuse = 0; ///< Running total of used memory.
static long long l_warningCount = 0; ///< Number of warnings encountered
static long long l_errorCount = 0; ///< Number of actual errors
static long long l_possibleOverruns = 0; ///< Number of possible overruns
// *********** HELPER FUNCTIONS *******************************
static void *liballoc_memset(void* s, int c, size_t n)
{
unsigned int i;
for ( i = 0; i < n ; i++)
((char*)s)[i] = c;
return s;
}
static void* liballoc_memcpy(void* s1, const void* s2, size_t n)
{
char *cdest;
char *csrc;
unsigned int *ldest = (unsigned int*)s1;
unsigned int *lsrc = (unsigned int*)s2;
while ( n >= sizeof(unsigned int) )
{
*ldest++ = *lsrc++;
n -= sizeof(unsigned int);
}
cdest = (char*)ldest;
csrc = (char*)lsrc;
while ( n > 0 )
{
*cdest++ = *csrc++;
n -= 1;
}
return s1;
}
#if defined DEBUG || defined INFO
static void liballoc_dump()
{
#ifdef DEBUG
struct liballoc_major *maj = l_memRoot;
struct liballoc_minor *min = NULL;
#endif
printf( "liballoc: ------ Memory data ---------------\n");
printf( "liballoc: System memory allocated: %i bytes\n", l_allocated );
printf( "liballoc: Memory in used (malloc'ed): %i bytes\n", l_inuse );
printf( "liballoc: Warning count: %i\n", l_warningCount );
printf( "liballoc: Error count: %i\n", l_errorCount );
printf( "liballoc: Possible overruns: %i\n", l_possibleOverruns );
#ifdef DEBUG
while ( maj != NULL )
{
printf( "liballoc: %x: total = %i, used = %i\n",
maj,
maj->size,
maj->usage );
min = maj->first;
while ( min != NULL )
{
printf( "liballoc: %x: %i bytes\n",
min,
min->size );
min = min->next;
}
maj = maj->next;
}
#endif
FLUSH();
}
#endif
// ***************************************************************
static struct liballoc_major *allocate_new_page( unsigned int size )
{
unsigned int st;
struct liballoc_major *maj;
// This is how much space is required.
st = size + sizeof(struct liballoc_major);
st += sizeof(struct liballoc_minor);
// Perfect amount of space?
if ( (st % l_pageSize) == 0 )
st = st / (l_pageSize);
else
st = st / (l_pageSize) + 1;
// No, add the buffer.
// Make sure it's >= the minimum size.
if ( st < l_pageCount ) st = l_pageCount;
maj = (struct liballoc_major*)liballoc_alloc( st );
if ( maj == NULL )
{
l_warningCount += 1;
#if defined DEBUG || defined INFO
printf( "liballoc: WARNING: liballoc_alloc( %i ) return NULL\n", st );
FLUSH();
#endif
return NULL; // uh oh, we ran out of memory.
}
maj->prev = NULL;
maj->next = NULL;
maj->pages = st;
maj->size = st * l_pageSize;
maj->usage = sizeof(struct liballoc_major);
maj->first = NULL;
l_allocated += maj->size;
#ifdef DEBUG
printf( "liballoc: Resource allocated %x of %i pages (%i bytes) for %i size.\n", maj, st, maj->size, size );
printf( "liballoc: Total memory usage = %i KB\n", (int)((l_allocated / (1024))) );
FLUSH();
#endif
return maj;
}
void *PREFIX(malloc)(size_t req_size)
{
int startedBet = 0;
unsigned long long bestSize = 0;
void *p = NULL;
uintptr_t diff;
struct liballoc_major *maj;
struct liballoc_minor *min;
struct liballoc_minor *new_min;
unsigned long size = req_size;
// For alignment, we adjust size so there's enough space to align.
if ( ALIGNMENT > 1 )
{
size += ALIGNMENT + ALIGN_INFO;
}
// So, ideally, we really want an alignment of 0 or 1 in order
// to save space.
liballoc_lock();
if ( size == 0 )
{
l_warningCount += 1;
#if defined DEBUG || defined INFO
printf( "liballoc: WARNING: alloc( 0 ) called from %x\n",
__builtin_return_address(0) );
FLUSH();
#endif
liballoc_unlock();
return PREFIX(malloc)(1);
}
if ( l_memRoot == NULL )
{
#if defined DEBUG || defined INFO
#ifdef DEBUG
printf( "liballoc: initialization of liballoc " VERSION "\n" );
#endif
atexit( liballoc_dump );
FLUSH();
#endif
// This is the first time we are being used.
l_memRoot = allocate_new_page( size );
if ( l_memRoot == NULL )
{
liballoc_unlock();
#ifdef DEBUG
printf( "liballoc: initial l_memRoot initialization failed\n", p);
FLUSH();
#endif
return NULL;
}
#ifdef DEBUG
printf( "liballoc: set up first memory major %x\n", l_memRoot );
FLUSH();
#endif
}
#ifdef DEBUG
printf( "liballoc: %x PREFIX(malloc)( %i ): ",
__builtin_return_address(0),
size );
FLUSH();
#endif
// Now we need to bounce through every major and find enough space....
maj = l_memRoot;
startedBet = 0;
// Start at the best bet....
if ( l_bestBet != NULL )
{
bestSize = l_bestBet->size - l_bestBet->usage;
if ( bestSize > (size + sizeof(struct liballoc_minor)))
{
maj = l_bestBet;
startedBet = 1;
}
}
while ( maj != NULL )
{
diff = maj->size - maj->usage;
// free memory in the block
if ( bestSize < diff )
{
// Hmm.. this one has more memory then our bestBet. Remember!
l_bestBet = maj;
bestSize = diff;
}
#ifdef USE_CASE1
// CASE 1: There is not enough space in this major block.
if ( diff < (size + sizeof( struct liballoc_minor )) )
{
#ifdef DEBUG
printf( "CASE 1: Insufficient space in block %x\n", maj);
FLUSH();
#endif
// Another major block next to this one?
if ( maj->next != NULL )
{
maj = maj->next; // Hop to that one.
continue;
}
if ( startedBet == 1 ) // If we started at the best bet,
{ // let's start all over again.
maj = l_memRoot;
startedBet = 0;
continue;
}
// Create a new major block next to this one and...
maj->next = allocate_new_page( size ); // next one will be okay.
if ( maj->next == NULL ) break; // no more memory.
maj->next->prev = maj;
maj = maj->next;
// .. fall through to CASE 2 ..
}
#endif
#ifdef USE_CASE2
// CASE 2: It's a brand new block.
if ( maj->first == NULL )
{
maj->first = (struct liballoc_minor*)((uintptr_t)maj + sizeof(struct liballoc_major) );
maj->first->magic = LIBALLOC_MAGIC;
maj->first->prev = NULL;
maj->first->next = NULL;
maj->first->block = maj;
maj->first->size = size;
maj->first->req_size = req_size;
maj->usage += size + sizeof( struct liballoc_minor );
l_inuse += size;
p = (void*)((uintptr_t)(maj->first) + sizeof( struct liballoc_minor ));
ALIGN( p );
#ifdef DEBUG
printf( "CASE 2: returning %x\n", p);
FLUSH();
#endif
liballoc_unlock(); // release the lock
return p;
}
#endif
#ifdef USE_CASE3
// CASE 3: Block in use and enough space at the start of the block.
diff = (uintptr_t)(maj->first);
diff -= (uintptr_t)maj;
diff -= sizeof(struct liballoc_major);
if ( diff >= (size + sizeof(struct liballoc_minor)) )
{
// Yes, space in front. Squeeze in.
maj->first->prev = (struct liballoc_minor*)((uintptr_t)maj + sizeof(struct liballoc_major) );
maj->first->prev->next = maj->first;
maj->first = maj->first->prev;
maj->first->magic = LIBALLOC_MAGIC;
maj->first->prev = NULL;
maj->first->block = maj;
maj->first->size = size;
maj->first->req_size = req_size;
maj->usage += size + sizeof( struct liballoc_minor );
l_inuse += size;
p = (void*)((uintptr_t)(maj->first) + sizeof( struct liballoc_minor ));
ALIGN( p );
#ifdef DEBUG
printf( "CASE 3: returning %x\n", p);
FLUSH();
#endif
liballoc_unlock(); // release the lock
return p;
}
#endif
#ifdef USE_CASE4
// CASE 4: There is enough space in this block. But is it contiguous?
min = maj->first;
// Looping within the block now...
while ( min != NULL )
{
// CASE 4.1: End of minors in a block. Space from last and end?
if ( min->next == NULL )
{
// the rest of this block is free... is it big enough?
diff = (uintptr_t)(maj) + maj->size;
diff -= (uintptr_t)min;
diff -= sizeof( struct liballoc_minor );
diff -= min->size;
// minus already existing usage..
if ( diff >= (size + sizeof( struct liballoc_minor )) )
{
// yay....
min->next = (struct liballoc_minor*)((uintptr_t)min + sizeof( struct liballoc_minor ) + min->size);
min->next->prev = min;
min = min->next;
min->next = NULL;
min->magic = LIBALLOC_MAGIC;
min->block = maj;
min->size = size;
min->req_size = req_size;
maj->usage += size + sizeof( struct liballoc_minor );
l_inuse += size;
p = (void*)((uintptr_t)min + sizeof( struct liballoc_minor ));
ALIGN( p );
#ifdef DEBUG
printf( "CASE 4.1: returning %x\n", p);
FLUSH();
#endif
liballoc_unlock(); // release the lock
return p;
}
}
// CASE 4.2: Is there space between two minors?
if ( min->next != NULL )
{
// is the difference between here and next big enough?
diff = (uintptr_t)(min->next);
diff -= (uintptr_t)min;
diff -= sizeof( struct liballoc_minor );
diff -= min->size;
// minus our existing usage.
if ( diff >= (size + sizeof( struct liballoc_minor )) )
{
// yay......
new_min = (struct liballoc_minor*)((uintptr_t)min + sizeof( struct liballoc_minor ) + min->size);
new_min->magic = LIBALLOC_MAGIC;
new_min->next = min->next;
new_min->prev = min;
new_min->size = size;
new_min->req_size = req_size;
new_min->block = maj;
min->next->prev = new_min;
min->next = new_min;
maj->usage += size + sizeof( struct liballoc_minor );
l_inuse += size;
p = (void*)((uintptr_t)new_min + sizeof( struct liballoc_minor ));
ALIGN( p );
#ifdef DEBUG
printf( "CASE 4.2: returning %x\n", p);
FLUSH();
#endif
liballoc_unlock(); // release the lock
return p;
}
} // min->next != NULL
min = min->next;
} // while min != NULL ...
#endif
#ifdef USE_CASE5
// CASE 5: Block full! Ensure next block and loop.
if ( maj->next == NULL )
{
#ifdef DEBUG
printf( "CASE 5: block full\n");
FLUSH();
#endif
if ( startedBet == 1 )
{
maj = l_memRoot;
startedBet = 0;
continue;
}
// we've run out. we need more...
maj->next = allocate_new_page( size ); // next one guaranteed to be okay
if ( maj->next == NULL ) break; // uh oh, no more memory.....
maj->next->prev = maj;
}
#endif
maj = maj->next;
} // while (maj != NULL)
liballoc_unlock(); // release the lock
#ifdef DEBUG
printf( "All cases exhausted. No memory available.\n");
FLUSH();
#endif
#if defined DEBUG || defined INFO
printf( "liballoc: WARNING: PREFIX(malloc)( %i ) returning NULL.\n", size);
liballoc_dump();
FLUSH();
#endif
return NULL;
}
void PREFIX(free)(void *ptr)
{
struct liballoc_minor *min;
struct liballoc_major *maj;
if ( ptr == NULL )
{
l_warningCount += 1;
#if defined DEBUG || defined INFO
printf( "liballoc: WARNING: PREFIX(free)( NULL ) called from %x\n",
__builtin_return_address(0) );
FLUSH();
#endif
return;
}
UNALIGN( ptr );
liballoc_lock(); // lockit
min = (struct liballoc_minor*)((uintptr_t)ptr - sizeof( struct liballoc_minor ));
if ( min->magic != LIBALLOC_MAGIC )
{
l_errorCount += 1;
// Check for overrun errors. For all bytes of LIBALLOC_MAGIC
if (
((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF)) ||
((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF)) ||
((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF))
)
{
l_possibleOverruns += 1;
#if defined DEBUG || defined INFO
printf( "liballoc: ERROR: Possible 1-3 byte overrun for magic %x != %x\n",
min->magic,
LIBALLOC_MAGIC );
FLUSH();
#endif
}
if ( min->magic == LIBALLOC_DEAD )
{
#if defined DEBUG || defined INFO
printf( "liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n",
ptr,
__builtin_return_address(0) );
FLUSH();
#endif
}
else
{
#if defined DEBUG || defined INFO
printf( "liballoc: ERROR: Bad PREFIX(free)( %x ) called from %x\n",
ptr,
__builtin_return_address(0) );
FLUSH();
#endif
}
// being lied to...
liballoc_unlock(); // release the lock
return;
}
#ifdef DEBUG
printf( "liballoc: %x PREFIX(free)( %x ): ",
__builtin_return_address( 0 ),
ptr );
FLUSH();
#endif
maj = min->block;
l_inuse -= min->size;
maj->usage -= (min->size + sizeof( struct liballoc_minor ));
min->magic = LIBALLOC_DEAD; // No mojo.
if ( min->next != NULL ) min->next->prev = min->prev;
if ( min->prev != NULL ) min->prev->next = min->next;
if ( min->prev == NULL ) maj->first = min->next;
// Might empty the block. This was the first
// minor.
// We need to clean up after the majors now....
if ( maj->first == NULL ) // Block completely unused.
{
if ( l_memRoot == maj ) l_memRoot = maj->next;
if ( l_bestBet == maj ) l_bestBet = NULL;
if ( maj->prev != NULL ) maj->prev->next = maj->next;
if ( maj->next != NULL ) maj->next->prev = maj->prev;
l_allocated -= maj->size;
liballoc_free( maj, maj->pages );
}
else
{
if ( l_bestBet != NULL )
{
int bestSize = l_bestBet->size - l_bestBet->usage;
int majSize = maj->size - maj->usage;
if ( majSize > bestSize ) l_bestBet = maj;
}
}
#ifdef DEBUG
printf( "OK\n");
FLUSH();
#endif
liballoc_unlock(); // release the lock
}
void* PREFIX(calloc)(size_t nobj, size_t size)
{
int real_size;
void *p;
real_size = nobj * size;
p = PREFIX(malloc)( real_size );
liballoc_memset( p, 0, real_size );
return p;
}
void* PREFIX(realloc)(void *p, size_t size)
{
void *ptr;
struct liballoc_minor *min;
unsigned int real_size;
// Honour the case of size == 0 => free old and return NULL
if ( size == 0 )
{
PREFIX(free)( p );
return NULL;
}
// In the case of a NULL pointer, return a simple malloc.
if ( p == NULL ) return PREFIX(malloc)( size );
// Unalign the pointer if required.
ptr = p;
UNALIGN(ptr);
liballoc_lock(); // lockit
min = (struct liballoc_minor*)((uintptr_t)ptr - sizeof( struct liballoc_minor ));
// Ensure it is a valid structure.
if ( min->magic != LIBALLOC_MAGIC )
{
l_errorCount += 1;
// Check for overrun errors. For all bytes of LIBALLOC_MAGIC
if (
((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF)) ||
((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF)) ||
((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF))
)
{
l_possibleOverruns += 1;
#if defined DEBUG || defined INFO
printf( "liballoc: ERROR: Possible 1-3 byte overrun for magic %x != %x\n",
min->magic,
LIBALLOC_MAGIC );
FLUSH();
#endif
}
if ( min->magic == LIBALLOC_DEAD )
{
#if defined DEBUG || defined INFO
printf( "liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n",
ptr,
__builtin_return_address(0) );
FLUSH();
#endif
}
else
{
#if defined DEBUG || defined INFO
printf( "liballoc: ERROR: Bad PREFIX(free)( %x ) called from %x\n",
ptr,
__builtin_return_address(0) );
FLUSH();
#endif
}
// being lied to...
liballoc_unlock(); // release the lock
return NULL;
}
// Definitely a memory block.
real_size = min->req_size;
if ( real_size >= size )
{
min->req_size = size;
liballoc_unlock();
return p;
}
liballoc_unlock();
// If we got here then we're reallocating to a block bigger than us.
ptr = PREFIX(malloc)( size ); // We need to allocate new memory
liballoc_memcpy( ptr, p, real_size );
PREFIX(free)( p );
return ptr;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,827 @@
#include <stdint.h>
#include <kernel/system/memory.h>
/** Durand's Amazing Super Duper Memory functions. */
#ifdef __cplusplus
extern "C" {
#endif
#define VERSION "1.1"
#define ALIGNMENT 16ul//4ul ///< This is the byte alignment that memory must be allocated on. IMPORTANT for GTK and other stuff.
#define ALIGN_TYPE char ///unsigned char[16] /// unsigned short
#define ALIGN_INFO sizeof(ALIGN_TYPE)*16 ///< Alignment information is stored right before the pointer. This is the number of bytes of information stored there.
#define USE_CASE1
#define USE_CASE2
#define USE_CASE3
#define USE_CASE4
#define USE_CASE5
extern address_space_t KernelAddressSpace;
/** This function is supposed to lock the memory data structures. It
* could be as simple as disabling interrupts or acquiring a spinlock.
* It's up to you to decide.
*
* \return 0 if the lock was acquired successfully. Anything else is
* failure.
*/
static int liballoc_lock() {
return TicketAttemptLock(&KernelAddressSpace.Lock) ? 0 : 1;
}
/** This function unlocks what was previously locked by the liballoc_lock
* function. If it disabled interrupts, it enables interrupts. If it
* had acquiried a spinlock, it releases the spinlock. etc.
*
*/
static void liballoc_unlock() {
TicketUnlock(&KernelAddressSpace.Lock);
}
/** This is the hook into the local system which allocates pages. It
* accepts an integer parameter which is the number of pages
* required. The page size was set up in the liballoc_init function.
*
* \return NULL if the pages were not allocated.
* \return A pointer to the allocated memory.
*/
static void* liballoc_alloc(size_t count) {
return (void*) PhysAllocateZeroMem(count * PAGE_SIZE);
}
/** This frees previously allocated memory. The void* parameter passed
* to the function is the exact same value returned from a previous
* liballoc_alloc call.
*
* The integer value is the number of pages to free.
*
* \return 0 if the memory was successfully freed.
*/
static int liballoc_free(void* ptr, size_t count) {
PhysFreeMem(ptr, count * PAGE_SIZE);
return 0;
}
/** This macro will conveniently align our pointer upwards */
#define ALIGN(ptr) \
if ( ALIGNMENT > 1 ) \
{ \
uintptr_t diff; \
ptr = (void*)((uintptr_t)ptr + ALIGN_INFO); \
diff = (uintptr_t)ptr & (ALIGNMENT-1); \
if ( diff != 0 ) \
{ \
diff = ALIGNMENT - diff; \
ptr = (void*)((uintptr_t)ptr + diff); \
} \
*((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)) = \
diff + ALIGN_INFO; \
}
#define UNALIGN(ptr) \
if ( ALIGNMENT > 1 ) \
{ \
uintptr_t diff = *((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)); \
if ( diff < (ALIGNMENT + ALIGN_INFO) ) \
{ \
ptr = (void*)((uintptr_t)ptr - diff); \
} \
}
#define LIBALLOC_MAGIC 0xc001c0de
#define LIBALLOC_DEAD 0xdeaddead
#if defined DEBUG || defined INFO
#include <stdio.h>
#include <stdlib.h>
#define FLUSH() fflush( stdout )
#endif
/** A structure found at the top of all system allocated
* memory blocks. It details the usage of the memory block.
*/
struct liballoc_major {
struct liballoc_major* prev; ///< Linked list information.
struct liballoc_major* next; ///< Linked list information.
unsigned int pages; ///< The number of pages in the block.
unsigned int size; ///< The number of pages in the block.
unsigned int usage; ///< The number of bytes used in the block.
struct liballoc_minor* first; ///< A pointer to the first allocated memory in the block.
};
/** This is a structure found at the beginning of all
* sections in a major block which were allocated by a
* malloc, calloc, realloc call.
*/
struct liballoc_minor {
struct liballoc_minor* prev; ///< Linked list information.
struct liballoc_minor* next; ///< Linked list information.
struct liballoc_major* block; ///< The owning block. A pointer to the major structure.
unsigned int magic; ///< A magic number to idenfity correctness.
unsigned int size; ///< The size of the memory allocated. Could be 1 byte or more.
unsigned int req_size; ///< The size of memory requested.
};
static struct liballoc_major* l_memRoot = NULL; ///< The root memory block acquired from the system.
static struct liballoc_major* l_bestBet = NULL; ///< The major with the most free memory.
static unsigned int l_pageSize = 4096; ///< The size of an individual page. Set up in liballoc_init.
static unsigned int l_pageCount = 16; ///< The number of pages to request per chunk. Set up in liballoc_init.
static unsigned long long l_allocated = 0; ///< Running total of allocated memory.
static unsigned long long l_inuse = 0; ///< Running total of used memory.
static long long l_warningCount = 0; ///< Number of warnings encountered
static long long l_errorCount = 0; ///< Number of actual errors
static long long l_possibleOverruns = 0; ///< Number of possible overruns
// *********** HELPER FUNCTIONS *******************************
static void* liballoc_memset(void* s, int c, size_t n) {
unsigned int i;
for (i = 0; i < n; i++)
((char*) s)[i] = c;
return s;
}
static void* liballoc_memcpy(void* s1, const void* s2, size_t n) {
char* cdest;
char* csrc;
unsigned int* ldest = (unsigned int*) s1;
unsigned int* lsrc = (unsigned int*) s2;
while (n >= sizeof(unsigned int)) {
*ldest++ = *lsrc++;
n -= sizeof(unsigned int);
}
cdest = (char*) ldest;
csrc = (char*) lsrc;
while (n > 0) {
*cdest++ = *csrc++;
n -= 1;
}
return s1;
}
#if defined DEBUG || defined INFO
static void liballoc_dump()
{
#ifdef DEBUG
struct liballoc_major *maj = l_memRoot;
struct liballoc_minor *min = NULL;
#endif
printf( "liballoc: ------ Memory data ---------------\n");
printf( "liballoc: System memory allocated: %i bytes\n", l_allocated );
printf( "liballoc: Memory in used (malloc'ed): %i bytes\n", l_inuse );
printf( "liballoc: Warning count: %i\n", l_warningCount );
printf( "liballoc: Error count: %i\n", l_errorCount );
printf( "liballoc: Possible overruns: %i\n", l_possibleOverruns );
#ifdef DEBUG
while ( maj != NULL )
{
printf( "liballoc: %x: total = %i, used = %i\n",
maj,
maj->size,
maj->usage );
min = maj->first;
while ( min != NULL )
{
printf( "liballoc: %x: %i bytes\n",
min,
min->size );
min = min->next;
}
maj = maj->next;
}
#endif
FLUSH();
}
#endif
// ***************************************************************
static struct liballoc_major* allocate_new_page(unsigned int size) {
unsigned int st;
struct liballoc_major* maj;
// This is how much space is required.
st = size + sizeof(struct liballoc_major);
st += sizeof(struct liballoc_minor);
// Perfect amount of space?
if ((st % l_pageSize) == 0)
st = st / (l_pageSize);
else
st = st / (l_pageSize) + 1;
// No, add the buffer.
// Make sure it's >= the minimum size.
if (st < l_pageCount) st = l_pageCount;
maj = (struct liballoc_major*) liballoc_alloc(st);
if (maj == NULL) {
l_warningCount += 1;
#if defined DEBUG || defined INFO
printf( "liballoc: WARNING: liballoc_alloc( %i ) return NULL\n", st );
FLUSH();
#endif
return NULL; // uh oh, we ran out of memory.
}
maj->prev = NULL;
maj->next = NULL;
maj->pages = st;
maj->size = st * l_pageSize;
maj->usage = sizeof(struct liballoc_major);
maj->first = NULL;
l_allocated += maj->size;
#ifdef DEBUG
printf( "liballoc: Resource allocated %x of %i pages (%i bytes) for %i size.\n", maj, st, maj->size, size );
printf( "liballoc: Total memory usage = %i KB\n", (int)((l_allocated / (1024))) );
FLUSH();
#endif
return maj;
}
void* PREFIX(malloc)(size_t req_size) {
int startedBet = 0;
unsigned long long bestSize = 0;
void* p = NULL;
uintptr_t diff;
struct liballoc_major* maj;
struct liballoc_minor* min;
struct liballoc_minor* new_min;
unsigned long size = req_size;
// For alignment, we adjust size so there's enough space to align.
if (ALIGNMENT > 1) {
size += ALIGNMENT + ALIGN_INFO;
}
// So, ideally, we really want an alignment of 0 or 1 in order
// to save space.
liballoc_lock();
if (size == 0) {
l_warningCount += 1;
#if defined DEBUG || defined INFO
printf( "liballoc: WARNING: alloc( 0 ) called from %x\n",
__builtin_return_address(0) );
FLUSH();
#endif
liballoc_unlock();
return PREFIX(malloc)(1);
}
if (l_memRoot == NULL) {
#if defined DEBUG || defined INFO
#ifdef DEBUG
printf( "liballoc: initialization of liballoc " VERSION "\n" );
#endif
atexit( liballoc_dump );
FLUSH();
#endif
// This is the first time we are being used.
l_memRoot = allocate_new_page(size);
if (l_memRoot == NULL) {
liballoc_unlock();
#ifdef DEBUG
printf( "liballoc: initial l_memRoot initialization failed\n", p);
FLUSH();
#endif
return NULL;
}
#ifdef DEBUG
printf( "liballoc: set up first memory major %x\n", l_memRoot );
FLUSH();
#endif
}
#ifdef DEBUG
printf( "liballoc: %x PREFIX(malloc)( %i ): ",
__builtin_return_address(0),
size );
FLUSH();
#endif
// Now we need to bounce through every major and find enough space....
maj = l_memRoot;
startedBet = 0;
// Start at the best bet....
if (l_bestBet != NULL) {
bestSize = l_bestBet->size - l_bestBet->usage;
if (bestSize > (size + sizeof(struct liballoc_minor))) {
maj = l_bestBet;
startedBet = 1;
}
}
while (maj != NULL) {
diff = maj->size - maj->usage;
// free memory in the block
if (bestSize < diff) {
// Hmm.. this one has more memory then our bestBet. Remember!
l_bestBet = maj;
bestSize = diff;
}
#ifdef USE_CASE1
// CASE 1: There is not enough space in this major block.
if (diff < (size + sizeof(struct liballoc_minor))) {
#ifdef DEBUG
printf( "CASE 1: Insufficient space in block %x\n", maj);
FLUSH();
#endif
// Another major block next to this one?
if (maj->next != NULL) {
maj = maj->next; // Hop to that one.
continue;
}
if (startedBet == 1) // If we started at the best bet,
{ // let's start all over again.
maj = l_memRoot;
startedBet = 0;
continue;
}
// Create a new major block next to this one and...
maj->next = allocate_new_page(size); // next one will be okay.
if (maj->next == NULL) break; // no more memory.
maj->next->prev = maj;
maj = maj->next;
// .. fall through to CASE 2 ..
}
#endif
#ifdef USE_CASE2
// CASE 2: It's a brand new block.
if (maj->first == NULL) {
maj->first = (struct liballoc_minor*) ((uintptr_t) maj + sizeof(struct liballoc_major));
maj->first->magic = LIBALLOC_MAGIC;
maj->first->prev = NULL;
maj->first->next = NULL;
maj->first->block = maj;
maj->first->size = size;
maj->first->req_size = req_size;
maj->usage += size + sizeof(struct liballoc_minor);
l_inuse += size;
p = (void*) ((uintptr_t) (maj->first) + sizeof(struct liballoc_minor));
ALIGN(p);
#ifdef DEBUG
printf( "CASE 2: returning %x\n", p);
FLUSH();
#endif
liballoc_unlock(); // release the lock
return p;
}
#endif
#ifdef USE_CASE3
// CASE 3: Block in use and enough space at the start of the block.
diff = (uintptr_t) (maj->first);
diff -= (uintptr_t) maj;
diff -= sizeof(struct liballoc_major);
if (diff >= (size + sizeof(struct liballoc_minor))) {
// Yes, space in front. Squeeze in.
maj->first->prev = (struct liballoc_minor*) ((uintptr_t) maj + sizeof(struct liballoc_major));
maj->first->prev->next = maj->first;
maj->first = maj->first->prev;
maj->first->magic = LIBALLOC_MAGIC;
maj->first->prev = NULL;
maj->first->block = maj;
maj->first->size = size;
maj->first->req_size = req_size;
maj->usage += size + sizeof(struct liballoc_minor);
l_inuse += size;
p = (void*) ((uintptr_t) (maj->first) + sizeof(struct liballoc_minor));
ALIGN(p);
#ifdef DEBUG
printf( "CASE 3: returning %x\n", p);
FLUSH();
#endif
liballoc_unlock(); // release the lock
return p;
}
#endif
#ifdef USE_CASE4
// CASE 4: There is enough space in this block. But is it contiguous?
min = maj->first;
// Looping within the block now...
while (min != NULL) {
// CASE 4.1: End of minors in a block. Space from last and end?
if (min->next == NULL) {
// the rest of this block is free... is it big enough?
diff = (uintptr_t) (maj) + maj->size;
diff -= (uintptr_t) min;
diff -= sizeof(struct liballoc_minor);
diff -= min->size;
// minus already existing usage..
if (diff >= (size + sizeof(struct liballoc_minor))) {
// yay....
min->next = (struct liballoc_minor*) ((uintptr_t) min + sizeof(struct liballoc_minor) + min->size);
min->next->prev = min;
min = min->next;
min->next = NULL;
min->magic = LIBALLOC_MAGIC;
min->block = maj;
min->size = size;
min->req_size = req_size;
maj->usage += size + sizeof(struct liballoc_minor);
l_inuse += size;
p = (void*) ((uintptr_t) min + sizeof(struct liballoc_minor));
ALIGN(p);
#ifdef DEBUG
printf( "CASE 4.1: returning %x\n", p);
FLUSH();
#endif
liballoc_unlock(); // release the lock
return p;
}
}
// CASE 4.2: Is there space between two minors?
if (min->next != NULL) {
// is the difference between here and next big enough?
diff = (uintptr_t) (min->next);
diff -= (uintptr_t) min;
diff -= sizeof(struct liballoc_minor);
diff -= min->size;
// minus our existing usage.
if (diff >= (size + sizeof(struct liballoc_minor))) {
// yay......
new_min = (struct liballoc_minor*) ((uintptr_t) min + sizeof(struct liballoc_minor) + min->size);
new_min->magic = LIBALLOC_MAGIC;
new_min->next = min->next;
new_min->prev = min;
new_min->size = size;
new_min->req_size = req_size;
new_min->block = maj;
min->next->prev = new_min;
min->next = new_min;
maj->usage += size + sizeof(struct liballoc_minor);
l_inuse += size;
p = (void*) ((uintptr_t) new_min + sizeof(struct liballoc_minor));
ALIGN(p);
#ifdef DEBUG
printf( "CASE 4.2: returning %x\n", p);
FLUSH();
#endif
liballoc_unlock(); // release the lock
return p;
}
} // min->next != NULL
min = min->next;
} // while min != NULL ...
#endif
#ifdef USE_CASE5
// CASE 5: Block full! Ensure next block and loop.
if (maj->next == NULL) {
#ifdef DEBUG
printf( "CASE 5: block full\n");
FLUSH();
#endif
if (startedBet == 1) {
maj = l_memRoot;
startedBet = 0;
continue;
}
// we've run out. we need more...
maj->next = allocate_new_page(size); // next one guaranteed to be okay
if (maj->next == NULL) break; // uh oh, no more memory.....
maj->next->prev = maj;
}
#endif
maj = maj->next;
} // while (maj != NULL)
liballoc_unlock(); // release the lock
#ifdef DEBUG
printf( "All cases exhausted. No memory available.\n");
FLUSH();
#endif
#if defined DEBUG || defined INFO
printf( "liballoc: WARNING: PREFIX(malloc)( %i ) returning NULL.\n", size);
liballoc_dump();
FLUSH();
#endif
return NULL;
}
void PREFIX(free)(void* ptr) {
struct liballoc_minor* min;
struct liballoc_major* maj;
if (ptr == NULL) {
l_warningCount += 1;
#if defined DEBUG || defined INFO
printf( "liballoc: WARNING: PREFIX(free)( NULL ) called from %x\n",
__builtin_return_address(0) );
FLUSH();
#endif
return;
}
UNALIGN(ptr);
liballoc_lock(); // lockit
min = (struct liballoc_minor*) ((uintptr_t) ptr - sizeof(struct liballoc_minor));
if (min->magic != LIBALLOC_MAGIC) {
l_errorCount += 1;
// Check for overrun errors. For all bytes of LIBALLOC_MAGIC
if (
((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF)) ||
((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF)) ||
((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF))
) {
l_possibleOverruns += 1;
#if defined DEBUG || defined INFO
printf( "liballoc: ERROR: Possible 1-3 byte overrun for magic %x != %x\n",
min->magic,
LIBALLOC_MAGIC );
FLUSH();
#endif
}
if (min->magic == LIBALLOC_DEAD) {
#if defined DEBUG || defined INFO
printf( "liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n",
ptr,
__builtin_return_address(0) );
FLUSH();
#endif
} else {
#if defined DEBUG || defined INFO
printf( "liballoc: ERROR: Bad PREFIX(free)( %x ) called from %x\n",
ptr,
__builtin_return_address(0) );
FLUSH();
#endif
}
// being lied to...
liballoc_unlock(); // release the lock
return;
}
#ifdef DEBUG
printf( "liballoc: %x PREFIX(free)( %x ): ",
__builtin_return_address( 0 ),
ptr );
FLUSH();
#endif
maj = min->block;
l_inuse -= min->size;
maj->usage -= (min->size + sizeof(struct liballoc_minor));
min->magic = LIBALLOC_DEAD; // No mojo.
if (min->next != NULL) min->next->prev = min->prev;
if (min->prev != NULL) min->prev->next = min->next;
if (min->prev == NULL) maj->first = min->next;
// Might empty the block. This was the first
// minor.
// We need to clean up after the majors now....
if (maj->first == NULL) // Block completely unused.
{
if (l_memRoot == maj) l_memRoot = maj->next;
if (l_bestBet == maj) l_bestBet = NULL;
if (maj->prev != NULL) maj->prev->next = maj->next;
if (maj->next != NULL) maj->next->prev = maj->prev;
l_allocated -= maj->size;
liballoc_free(maj, maj->pages);
} else {
if (l_bestBet != NULL) {
int bestSize = l_bestBet->size - l_bestBet->usage;
int majSize = maj->size - maj->usage;
if (majSize > bestSize) l_bestBet = maj;
}
}
#ifdef DEBUG
printf( "OK\n");
FLUSH();
#endif
liballoc_unlock(); // release the lock
}
void* PREFIX(calloc)(size_t nobj, size_t size) {
int real_size;
void* p;
real_size = nobj * size;
p = PREFIX(malloc)(real_size);
liballoc_memset(p, 0, real_size);
return p;
}
void* PREFIX(realloc)(void* p, size_t size) {
void* ptr;
struct liballoc_minor* min;
unsigned int real_size;
// Honour the case of size == 0 => free old and return NULL
if (size == 0) {
PREFIX(free)(p);
return NULL;
}
// In the case of a NULL pointer, return a simple malloc.
if (p == NULL) return PREFIX(malloc)(size);
// Unalign the pointer if required.
ptr = p;
UNALIGN(ptr);
liballoc_lock(); // lockit
min = (struct liballoc_minor*) ((uintptr_t) ptr - sizeof(struct liballoc_minor));
// Ensure it is a valid structure.
if (min->magic != LIBALLOC_MAGIC) {
l_errorCount += 1;
// Check for overrun errors. For all bytes of LIBALLOC_MAGIC
if (
((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF)) ||
((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF)) ||
((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF))
) {
l_possibleOverruns += 1;
#if defined DEBUG || defined INFO
printf( "liballoc: ERROR: Possible 1-3 byte overrun for magic %x != %x\n",
min->magic,
LIBALLOC_MAGIC );
FLUSH();
#endif
}
if (min->magic == LIBALLOC_DEAD) {
#if defined DEBUG || defined INFO
printf( "liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n",
ptr,
__builtin_return_address(0) );
FLUSH();
#endif
} else {
#if defined DEBUG || defined INFO
printf( "liballoc: ERROR: Bad PREFIX(free)( %x ) called from %x\n",
ptr,
__builtin_return_address(0) );
FLUSH();
#endif
}
// being lied to...
liballoc_unlock(); // release the lock
return NULL;
}
// Definitely a memory block.
real_size = min->req_size;
if (real_size >= size) {
min->req_size = size;
liballoc_unlock();
return p;
}
liballoc_unlock();
// If we got here then we're reallocating to a block bigger than us.
ptr = PREFIX(malloc)(size); // We need to allocate new memory
liballoc_memcpy(ptr, p, real_size);
PREFIX(free)(p);
return ptr;
}
#ifdef __cplusplus
}
#endif
void operator delete(void* addr, unsigned long __attribute__((unused)) size) {
PREFIX(free)(addr);
}
void operator delete(void* addr) {
PREFIX(free)(addr);
}

View File

@ -34,21 +34,23 @@ size_t KernelLocation;
void InitPaging() {
KernelAddressSpace = (address_space_t) {
.Lock = {0},
.PML4 = PhysAllocateZeroMem(4096)
.Lock = {.NowServing = 0, .NextTicket = 0},
.PML4 = (size_t*) PhysAllocateZeroMem(4096)
};
address_space_t BootloaderAddressSpace = (address_space_t) {
.Lock = {0},
.Lock = {.NowServing = 0, .NextTicket = 0},
.PML4 = (size_t*) ReadControlRegister(3)
};
size_t AddressToFind = KernelAddr + 0x2000;
size_t BootldrAddress = 0x8000;
KernelLocation = DecodeVirtualAddressNoDirect(&BootloaderAddressSpace, AddressToFind);
SerialPrintf("[ Mem] Double check: Kernel physically starts at 0x%p (0x%p), ends at 0x%p.\r\n", KernelLocation, AddressToFind, KERNEL_END);
SerialPrintf("[ Mem] Double check: Kernel physically starts at 0x%p (0x%p), ends at 0x%p.\r\n", KernelLocation,
AddressToFind, KERNEL_END);
SerialPrintf("[ Mem] Identity mapping the entire 0x%p bytes of physical memory to 0x%p\r\n", FullMemorySize, (size_t) KernelAddressSpace.PML4);
SerialPrintf("[ Mem] Identity mapping the entire 0x%p bytes of physical memory to 0x%p\r\n", FullMemorySize,
(size_t) KernelAddressSpace.PML4);
for (size_t i = 0; i < (FullMemorySize / 4096); i++) {
size_t Addr = i * 4096;
@ -56,12 +58,14 @@ void InitPaging() {
MapVirtualPageNoDirect(&KernelAddressSpace, Addr, TO_DIRECT(Addr), DEFAULT_PAGE_FLAGS);
}
SerialPrintf("[ Mem] Mapping 0x%x bytes of bootloader structure, starting at 0x%p\r\n", bootldr.size, BootldrAddress);
SerialPrintf("[ Mem] Mapping 0x%x bytes of bootloader structure, starting at 0x%p\r\n", bootldr.size,
BootldrAddress);
for (size_t i = BootldrAddress; i < (BootldrAddress + bootldr.size); i += PAGE_SIZE)
MapVirtualPageNoDirect(&KernelAddressSpace, i, KERNEL_REGION + (i - BootldrAddress), 0x3);
// This allows the code to actually run
SerialPrintf("[ Mem] Mapping 0x%x bytes of kernel, starting at 0x%p\r\n", KERNEL_END - KERNEL_PHYSICAL, KERNEL_PHYSICAL);
SerialPrintf("[ Mem] Mapping 0x%x bytes of kernel, starting at 0x%p\r\n", KERNEL_END - KERNEL_PHYSICAL,
KERNEL_PHYSICAL);
for (size_t i = KERNEL_PHYSICAL; i < KERNEL_END; i += PAGE_SIZE)
MapVirtualPageNoDirect(&KernelAddressSpace, i, (i - KERNEL_PHYSICAL) + KERNEL_REGION + KERNEL_TEXT, 0x3);
@ -82,9 +86,12 @@ void InitPaging() {
SerialPrintf("[ Mem] Diagnostic: Querying existing page tables\r\n");
size_t KernelAddress = DecodeVirtualAddressNoDirect(&KernelAddressSpace, AddressToFind);
SerialPrintf("[ Mem] Diagnostic: Our pagetables put 0x%p at 0x%p + 0x%p.\r\n", AddressToFind, KernelAddress, AddressToFind & ~STACK_TOP);
SerialPrintf("[ Mem] Diagnostic: Existing pagetables put 0x%p at 0x%p + 0x%p.\r\n", AddressToFind, KERNEL_PHYSICAL, AddressToFind & ~STACK_TOP);
SerialPrintf("[ Mem] %s\r\n", KernelAddress == KERNEL_PHYSICAL ? "These match. Continuing." : "These do not match. Continuing with caution..");
SerialPrintf("[ Mem] Diagnostic: Our pagetables put 0x%p at 0x%p + 0x%p.\r\n", AddressToFind, KernelAddress,
AddressToFind & ~STACK_TOP);
SerialPrintf("[ Mem] Diagnostic: Existing pagetables put 0x%p at 0x%p + 0x%p.\r\n", AddressToFind, KERNEL_PHYSICAL,
AddressToFind & ~STACK_TOP);
SerialPrintf("[ Mem] %s\r\n", KernelAddress == KERNEL_PHYSICAL ? "These match. Continuing."
: "These do not match. Continuing with caution..");
SerialPrintf("[ Mem] Attempting to jump into our new pagetables: 0x%p\r\n", (size_t) KernelAddressSpace.PML4);
WriteControlRegister(3, (size_t) KernelAddressSpace.PML4 & STACK_TOP);
@ -302,7 +309,7 @@ size_t* CreateNewPageTable(address_space_t* AddressSpace) {
// Allocate the first page
size_t* NewPML4 = (size_t*) TO_DIRECT(PhysAllocateZeroMem(4096));
address_space_t TempAddressSpace = (address_space_t) {
.Lock = {0},
.Lock = {.NowServing = 0, .NextTicket = 0},
.PML4 = NewPML4
};

View File

@ -1,6 +1,7 @@
#include <kernel/chroma.h>
#include <lainlib/lainlib.h>
/************************
*** Team Kitty, 2020 ***
*** Chroma ***
@ -12,17 +13,12 @@ extern "C" {
/* This file contains functions for physical memory management.
*
* This is also called blocking, or block memory allocation.
* It mostly deals with the memory map handed to us by the bootloader.
* Physical Memory Management is performed with Buddy List allocators, which are one of the most performant systems available.
* They tend to be able to allocate physical pages with O(1) efficiency.
*
* It is useful in virtual memory management, because it allows us to map one block of physical memory to one page of virtual memory.
*
* Most of the processing here is done with a bitwise mapping of blocks to allocations, normally called a memory bitmap.
* See heap.h for the implementation.
*
* This file also contains memory manipulation functions, like memset and memcpy.
* //TODO: replace these functions with SSE2 equivalent.
* The implementation here is bespoke, and in need of documentation.
*
* TODO: Document this mess.
*/
@ -40,14 +36,14 @@ static buddy_t LowBuddy = {
.MaxOrder = 32,
.Base = (directptr_t) DIRECT_REGION,
.List = (directptr_t[32 - MIN_ORDER]) {0},
.Lock = {0},
.Lock = {.NowServing = 0, .NextTicket = 0},
};
static buddy_t HighBuddy = {
.MaxOrder = 64,
.Base = 0,
.List = (directptr_t[64 - MIN_ORDER]) {0},
.Lock = {0},
.Lock = {.NowServing = 0, .NextTicket = 0},
};
static size_t MemoryLength;
@ -123,7 +119,9 @@ static directptr_t BuddyAllocate(buddy_t* Buddy, size_t Size) {
if (InitialOrder >= Buddy->MaxOrder) {
SerialPrintf("Tried to allocate too much physical memory for buddy 0x%p\r\n", Buddy);
SerialPrintf("Buddy 0x%p has max order %d, but 0x%x bytes was requested.\r\nInitial Order: %d, Wanted Size: 0x%x\r\n", Buddy, Buddy->MaxOrder, Size, InitialOrder, WantedSize);
SerialPrintf(
"Buddy 0x%p has max order %d, but 0x%x bytes was requested.\r\nInitial Order: %d, Wanted Size: 0x%x\r\n",
Buddy, Buddy->MaxOrder, Size, InitialOrder, WantedSize);
return NULL;
}
@ -215,7 +213,8 @@ void ListMemoryMap() {
size_t page_to = AlignDownwards(entry_to, 0x1000);
if (page_from != 0 && page_to != 0) {
SerialPrintf("[ Mem] Adding the range 0x%p-0x%p to the physical memory manager!\r\n", page_from, page_to);
SerialPrintf("[ Mem] Adding the range 0x%p-0x%p to the physical memory manager!\r\n", page_from,
page_to);
AddRangeToPhysMem((void*) ((char*) (page_from)), page_to - page_from);
}
@ -231,7 +230,9 @@ void AddRangeToPhysMem(directptr_t Base, size_t Size) {
} else {
if ((size_t) Base < (size_t) LOWER_REGION) {
size_t difference = (size_t) LOWER_REGION - (size_t) Base;
SerialPrintf("[ Mem] Base is 0x%p bytes away from the threshold, allocating 0x%p-0x%p to lower memory..\r\n", difference, (size_t) Base, (size_t) Base + difference);
SerialPrintf(
"[ Mem] Base is 0x%p bytes away from the threshold, allocating 0x%p-0x%p to lower memory..\r\n",
difference, (size_t) Base, (size_t) Base + difference);
AddRangeToBuddy(&LowBuddy, Base, difference);
Base = (void*) LOWER_REGION;
Size = Size - difference;
@ -305,7 +306,7 @@ void PhysFreeMem(directptr_t Pointer, size_t Size) {
static _Atomic(uint16_t)* PageRefCount = NULL;
void PhysAllocatorInit() {
PageRefCount = PhysAllocateZeroMem(sizeof(uint16_t) * MemoryPages);
PageRefCount = (_Atomic(uint16_t)*) PhysAllocateZeroMem(sizeof(uint16_t) * MemoryPages);
}
directptr_t PhysAllocatePage() {

View File

@ -1,37 +0,0 @@
#include <kernel/chroma.h>
/************************
*** Team Kitty, 2020 ***
*** Chroma ***
***********************/
#ifdef __cplusplus
extern "C" {
#endif
/*
* This file aims to implement stack unwinding
* to trace faulty functions.
*
* I was in the middle of debugging a jump to null
* when i started creating this, so there will be a
* lot of functionality here left over from that
* initial goal, probably...
*
* //TODO: Rework this to allow unwinding function parameters on call.
*/
void StackTrace(size_t cycles) {
struct stackframe* stack;
__asm__ __volatile__ ("mov %%rbp, %[dest]" : [dest] "=r" (stack) : :);
SerialPrintf("[Trace] Beginning stack trace. RBP is currently 0x%p\r\n", stack);
for(size_t frame = 0; stack != 0 && frame < cycles; ++frame) {
SerialPrintf("[Trace] (%d) 0x%p: 0x%p \r\n", frame, stack->rbp, stack->rip);
stack = stack->rbp;
}
SerialPrintf("[Trace] Stack trace over.\r\n");
}
#ifdef __cplusplus
}
#endif

View File

@ -1,531 +0,0 @@
#include <kernel/chroma.h>
/************************
*** Team Kitty, 2020 ***
*** Chroma ***
***********************/
#ifdef __cplusplus
extern "C" {
#endif
/* This file contains functions for accessing the PCI bus,
* and devices contained wherein.
*
* It allows you to query the bus, as well as communicate with individual devices.
*
*/
pci_device_t** pci_root_devices = NULL;
pci_entry_t* pci_map = NULL;
//static uint32_t PCIReadConfig(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset);
//static const char* PCIGetDeviceName_Subclass(uint8_t DeviceClass, uint8_t Subclass, uint8_t ProgrammableInterface);
//static const char* PCIGetClassName(uint8_t DeviceClass);
void PCIEnumerate() {
uint8_t bus = 0, device = 0, function = 0;
uint32_t registerData;
uint16_t DeviceID, VendorID;
uint8_t ClassCode, subclass_code;
SerialPrintf("[ PCI] Started PCI Enumeration.");
SerialPrintf("\n[ PCI] PCI Scan result:\n[ PCI]");
do {
for (device = 0; device <= 31; device++) {
for(function = 0; function <= 7; function++) {
registerData = PCIReadConfig(bus, device, 0, 0xC); // Read BIST/Header/Latency/Cache Line register
uint8_t header = (uint8_t) ((registerData & 0x00FF0000) >> 24); // Header is lower byte of upper word, so mask it off and shift it down
uint8_t multifunction_bit = header & 0x80; // The multifunction bit is the highest bit of the header
registerData = PCIReadConfig(bus, device, function, 0); // Read the Vendor/Device ID register
VendorID = (uint16_t) (registerData & 0x0000FFFF); // Vendor ID is bottom word
DeviceID = (uint16_t) (registerData >> 16); // Device ID is top word
registerData = PCIReadConfig(bus, device, function, 8); // Read the Device Info register
ClassCode = (uint16_t)( registerData >> 24); // Device class is top byte, so shift them down
subclass_code = (uint16_t) ((registerData >> 16) & 0x00FF); // Device subclass is same as header - lower byte of higher word. Shift down and mask just like before.
uint8_t device_progif = (uint16_t) ((registerData & 0x0000FF00) >> 8); // Device Programming Interface is higher byte of lower word, so mask and shift
uint8_t device_revision = (uint16_t) (registerData & 0x000000FF); // Device revision is lower byte of whole double word. Just mask it.
/* 0xFFFF is not a valid Vendor ID. This serves as a sanity check.
* If this check is true, then nothing is logged and we continue for the next loop.
*/
if(VendorID != 0xFFFF) {
SerialPrintf("[ PCI]\n[ PCI]\t%x:%x:\n[ PCI]\t\tVendor: %x\n[ PCI]\t\tDevice: %x", bus, device, VendorID, DeviceID);
SerialPrintf("\n[ PCI]\t\tClass: %s\n[ PCI]\t\tDevice Type: %s\n[ PCI]\t\tRevision: %d\n", PCIGetClassName(ClassCode), PCIGetDeviceName_Subclass(ClassCode, subclass_code, device_progif), device_revision);
}
/* If the PCI Device header tells us that this is not a multifunction device,
* and we've already scanned function 0, then there is nothing else to see.
* Therefore, stop this loop and move onto device++
*/
if (multifunction_bit == 0)
break;
}
}
} while (++bus);
}
uint32_t PCIReadConfig(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset) {
uint32_t address;
uint32_t busLong = (uint32_t) bus;
uint32_t slotLong = (uint32_t) slot;
uint32_t functionLong = (uint32_t) function;
/* ---------------------------------------------------------------
* | 31 | 30 ... 24 | 23 ... 16 | 15 ... 11 | 10 ... 8 | 7 ... 0 |
* ---------------------------------------------------------------
* | EN | RESERVED | BUS NUM | DEVICE NO | FUNC NO | REG OFF |
* ---------------------------------------------------------------
*
* NOTE: REG OFF *must* have 0 last two bits (ie. & 0xFC)
*/
address = (uint32_t) (( busLong << 16 ) | ( slotLong << 11 ) |
( functionLong << 8 ) | ( offset & 0xFC) | ((uint32_t)0x80000000));
WritePort(0xCF8, address, 4);
return ReadPort(0xCFC, 4);
}
const char* PCIGetDeviceName_Subclass(uint8_t DeviceClass, uint8_t Subclass, uint8_t ProgrammableInterface) {
switch(DeviceClass) {
case 0x00: {
switch(Subclass) {
case 0x00: return "Non-VGA-Compatible device";
case 0x01: return "VGA-Compatible device";
default: return "Unknown Unclassified";
}
}
case 0x01: {
switch(Subclass) {
case 0x00: return "SCSI Bus Controller";
case 0x01: {
switch(ProgrammableInterface) {
case 0x00: return "ISA Compatibility Mode-only IDE Controller";
case 0x05: return "PCI Native Mode-only IDE Controller";
case 0x0A: return "ISA Compatibility Mode IDE Controller (supports PCI Native Mode)";
case 0x0F: return "PCI Native Mode IDE Controller (supports ISA Compatibility Mode)";
case 0x80: return "ISA Compatibilty Mode-only IDE Controller (supports Bus Mastering)";
case 0x85: return "PCI Native Mode-only IDE Controller (supports Bus Mastering)";
case 0x8A: return "ISA Compatibility Mode IDE Controller (supports PCI Native Mode & Bus Mastering)";
case 0x8F: return "PCI Native Mode IDE Controller (supports ISA Compatibiliy Mode & Bus Mastering)";
default: return "IDE Controller";
}
}
case 0x02: return "Floppy Disk Controller";
case 0x03: return "IPI Bus Controller";
case 0x04: return "RAID Controller";
case 0x05: {
switch(ProgrammableInterface) {
case 0x20: return "Single-DMA ATA Controller";
case 0x30: return "Chained-DMA ATA Controller";
default: return "ATA Controller";
}
}
case 0x06: {
switch(ProgrammableInterface) {
case 0x00: return "Vendor-Specific Interface SATA Controller";
case 0x01: return "AHCI 1.0 SATA Controller";
case 0x02: return "Serial Storage Bus SATA Controller";
default: return "Serial ATA Controller";
}
}
case 0x07: return "Serial Attached SCSI (SAS)";
case 0x08:{
switch(ProgrammableInterface) {
case 0x01: return "NVMHCI Memory Controller";
case 0x02: return "NVMe Memory Controller";
default: return "Non-Volatile Memory Controller";
}
}
case 0x80: return "Other";
default: return "Unknown Mass Storage Controller";
}
}
case 0x02: {
switch(Subclass) {
case 0x00: return "Ethernet Controller";
case 0x01: return "Token Ring Controller";
case 0x02: return "FDDI Controller";
case 0x03: return "ATM Controller";
case 0x04: return "ISDN Controller";
case 0x05: return "WorldFip Controller";
case 0x06: return "PICMG 2.14 Multi Computing";
case 0x07: return "Infiniband Controller";
case 0x08: return "Fabric Controller";
case 0x80: return "Other";
default: return "Unknown Network Controller";
}
}
case 0x03: {
switch(Subclass) {
case 0x00: {
switch(ProgrammableInterface) {
case 0x00: return "VGA Controller";
case 0x01: return "8514 VGA Controller";
default: return "VGA Compatible Controller";
}
}
case 0x01: return "XGA Controller";
case 0x02: return "3D Controller (Not VGA-Compatible)";
case 0x80: return "Other";
default: return "Unknown Display Controller";
}
}
case 0x04: {
switch(Subclass) {
case 0x00: return "Multimedia Video Controller";
case 0x01: return "Multimedia Audio Controller";
case 0x02: return "Computer Telephony Device";
case 0x03: return "Audio Device";
case 0x80: return "Other";
default: return "Unknown Multimedia Controller";
}
}
case 0x05: {
switch(Subclass) {
case 0x00: return "RAM Controller";
case 0x01: return "Flash Controller";
case 0x80: return "Other";
default: return "Unknown Memory Controller";
}
}
case 0x06: {
switch(Subclass) {
case 0x00: return "Host Bridge";
case 0x01: return "ISA Bridge";
case 0x02: return "EISA Bridge";
case 0x03: return "MCA Bridge";
case 0x04:
case 0x09:
return "PCI-to-PCI Bridge";
case 0x05: return "PCMCIA Bridge";
case 0x06: return "NuBus Bridge";
case 0x07: return "CardBus Bridge";
case 0x08: return "RACEway Bridge";
case 0x0A: return "InfiniBand-to-PCI Host Bridge";
case 0x80: return "Other";
default: return "Unknown Bridge Device";
}
}
case 0x07: {
switch(Subclass) {
case 0x00: {
switch(ProgrammableInterface) {
case 0x00: return "Serial Controller <8250>";
case 0x01: return "Serial controller <16450>";
case 0x02: return "Serial controller <16550>";
case 0x03: return "Serial controller <16650>";
case 0x04: return "Serial controller <16750>";
case 0x05: return "Serial controller <16850>";
case 0x06: return "Serial controller <16950>";
default: return "Serial Controller";
}
}
case 0x01: {
switch(ProgrammableInterface) {
case 0x00: return "Standard Parallel Port";
case 0x01: return "Bi-Directional Parallel Port";
case 0x02: return "ECP 1.X Compliant Parallel Port";
case 0x03: return "IEEE 1284 Parallel Controller";
case 0x04: return "IEE 1284 Parallel Target";
default: return "Parallel Controller";
}
}
case 0x02: return "Multiport Serial Controller";
case 0x03: {
switch(ProgrammableInterface) {
case 0x00: return "Generic Modem";
case 0x01: return "Hayes 16450 Compatible Modem";
case 0x02: return "Hayes 16550 Compatible Modem";
case 0x03: return "Hayes 16650 Compatible Modem";
case 0x04: return "Hayes 16750 Compatible Modem";
default: return "Modem";
}
}
case 0x04: return "IEEE 488.1/2 (GPIB) Controller";
case 0x05: return "Smart Card";
case 0x80: return "Other";
default: return "Unknown Simple Comms Controller";
}
}
case 0x08: {
switch(Subclass) {
case 0x00: {
switch(ProgrammableInterface) {
case 0x00: return "Generic 8259-Compatible PIC";
case 0x01: return "ISA-Compatible PIC";
case 0x02: return "EISA-Compatible PIC";
case 0x03: return "I/O APIC Interrupt Controller";
case 0x04: return "I/O(x) APIC Interrupt Controller";
default: return "PIC";
}
}
case 0x01: {
switch(ProgrammableInterface) {
case 0x00: return "Generic 8237-Compatible DMA Controller";
case 0x01: return "ISA-Compatible DMA Controller";
case 0x02: return "EISA-Compatible DMA Controller";
default: return "DMA Controller";
}
}
case 0x02: {
switch(ProgrammableInterface) {
case 0x00: return "Generic 8254-Compatible Timer";
case 0x01: return "ISA-Compatible Timer";
case 0x02: return "EISA-Compatible Timer";
case 0x03: return "HPET Timer";
default: return "Timer";
}
}
case 0x03: {
switch(ProgrammableInterface) {
case 0x00: return "Generic RTC Controller";
case 0x01: return "ISA-Compatible RTC Controller";
default: return "RTC Controller";
}
}
case 0x04: return "PCI Hot-Plug Controller";
case 0x05: return "SD Host Controller";
case 0x06: return "IOMMU";
case 0x80: return "Other";
default: return "Unknown Base System Peripheral";
}
}
case 0x09: {
switch(Subclass) {
case 0x00: return "Keyboard Controller";
case 0x01: return "Digitiser Pen";
case 0x02: return "Mouse Controller";
case 0x03: return "Scanner Controller";
case 0x04: {
switch(ProgrammableInterface) {
case 0x00: return "Generic Gameport Controller";
case 0x10: return "Extended Gameport Controller";
default: return "Gameport Controller";
}
}
case 0x80: return "Other";
default: return "Unknown Input Device Controller";
}
}
case 0x0A: {
switch(Subclass) {
case 0x00: return "Generic Docking Station";
case 0x80: return "Other";
default: return "Unknown Docking Station";
}
}
case 0x0B: {
switch(Subclass) {
case 0x00: return "386 Processor";
case 0x01: return "486 Processor";
case 0x02: return "Pentium Processor";
case 0x03: return "Pentium Pro Processor";
case 0x10: return "Alpha Processor";
case 0x20: return "PowerPC Processor";
case 0x30: return "MIPS Processor";
case 0x40: return "Co-Processor";
case 0x80: return "Other";
default: return "Unknown Processor";
}
}
case 0x0C: {
switch(Subclass) {
case 0x00: {
switch(ProgrammableInterface) {
case 0x00: return "Generic Firewire Controller";
case 0x10: return "OHCI Firewire Controller";
default: return "FireWire (IEEE 1394) Controller";
}
}
case 0x01: return "ACCESS Bus";
case 0x02: return "SSA";
case 0x03: {
switch(ProgrammableInterface) {
case 0x00: return "UHCI USB Controller";
case 0x10: return "OHCI USB Controller";
case 0x20: return "EHCI USB (2.0) Controller";
case 0x30: return "XHCI USB (3.0) Controller";
case 0x80: return "Unspecified USB Controller";
case 0xFE: return "USB Device (NOT a Controller)";
default: return "USB Controller";
}
}
case 0x04: return "Fibre Channel";
case 0x05: return "SMBus";
case 0x06: return "InfiniBand";
case 0x07: {
switch(ProgrammableInterface) {
case 0x00: return "SMIC IPMI Interface";
case 0x01: return "Keyboard Controller-Style IPMI Interface";
case 0x02: return "Block Transfer IPMI Interface";
default: return "IPMI Interface";
}
}
case 0x08: return "SERCOS Interface (IEC 61491)";
case 0x09: return "CANbus";
case 0x80: return "Other";
default: return "Unknown Serial Bus Controller";
}
}
case 0x0D: {
switch(Subclass) {
case 0x00: return "IRDA Compatible Controller";
case 0x01: return "Consumer IR Controller";
case 0x10: return "RF Controller";
case 0x11: return "Bluetooth Controller";
case 0x12: return "Broadband Controller";
case 0x20: return "Ethernet Controller (802.1a)";
case 0x21: return "Ethernet Controller (802.1b)";
case 0x80: return "Other";
default: return "Unknown Wireless Controller";
}
}
case 0x0E: {
switch(Subclass) {
case 0x00: return "I20";
default: return "Unknown Intelligent Controller";
}
}
case 0x0F: {
switch(Subclass) {
case 0x01: return "Satellite TV Controller";
case 0x02: return "Satellite Audio Controller";
case 0x03: return "Satellite Voice Controller";
case 0x04: return "Satellite Data Controller";
default: return "Unknown Satelllite Comms Controller";
}
}
case 0x10: {
switch(Subclass) {
case 0x00: return "Network & Computing Codec";
case 0x10: return "Entertainment Codec";
case 0x80: return "Other Codec";
default: return "Unknown Encryption Controller";
}
}
case 0x11: {
switch(Subclass) {
case 0x00: return "DPIO Modules";
case 0x01: return "Performance Counters";
case 0x10: return "Communication Synchronizer";
case 0x20: return "Signal Processing Management";
case 0x80: return "Other";
default: return "Unknown Signal Processing Controller";
}
}
case 0x12: return "Processing Accelerator";
case 0x13: return "Non-Essential Instrumentation";
case 0x14:
case 0x41: return "Reserved";
case 0x40: return "Co-Processor";
case 0xFF: return "Unassigned Class";
}
return "Invalid Device!";
}
const char* PCIGetClassName(uint8_t DeviceClass) {
switch(DeviceClass) {
case 0x00: return "Unclassified";
case 0x01: return "Mass Storage Controller";
case 0x02: return "Network Controller";
case 0x03: return "Display Controller";
case 0x04: return "Multimedia Controller";
case 0x05: return "Memory Controller";
case 0x06: return "Bridge Device";
case 0x07: return "Simple Communication Controller";
case 0x08: return "Base System Peripheral";
case 0x09: return "Input Device Controller";
case 0x0A: return "Docking Station";
case 0x0B: return "Processor";
case 0x0C: return "Serial Bus Controller";
case 0x0D: return "Wireless Controller";
case 0x0E: return "Intelligent Controller";
case 0x0F: return "Satellite Communication Controller";
case 0x10: return "Encryption Controller";
case 0x11: return "Signal Processing Controller";
case 0x12: return "Processing Accelerator";
case 0x13: return "Non-Essential Instrumentation";
case 0x14: return "Reserved";
case 0x40: return "Co-Processor";
case 0x41: return "Reserved";
case 0xFF: return "Unassigned Class";
default: return "Unknown Category";
}
return "Invalid device!";
}
#ifdef __cplusplus
}
#endif

757
src/system/pci.cpp Normal file
View File

@ -0,0 +1,757 @@
#include <kernel/chroma.h>
/************************
*** Team Kitty, 2020 ***
*** Chroma ***
***********************/
#ifdef __cplusplus
extern "C" {
#endif
/* This file contains functions for accessing the PCI bus,
* and devices contained wherein.
*
* It allows you to query the bus, as well as communicate with individual devices.
*
*/
pci_device_t** pci_root_devices = NULL;
pci_entry_t* pci_map = NULL;
//static uint32_t PCIReadConfig(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset);
//static const char* PCIGetDeviceName_Subclass(uint8_t DeviceClass, uint8_t Subclass, uint8_t ProgrammableInterface);
//static const char* PCIGetClassName(uint8_t DeviceClass);
void PCIEnumerate() {
uint8_t bus = 0, device = 0, function = 0;
uint32_t registerData;
uint16_t DeviceID, VendorID;
uint8_t ClassCode, subclass_code;
SerialPrintf("[ PCI] Started PCI Enumeration.");
SerialPrintf("\n[ PCI] PCI Scan result:\n[ PCI]");
do {
for (device = 0; device <= 31; device++) {
for (function = 0; function <= 7; function++) {
registerData = PCIReadConfig(bus, device, 0,
0xC); // Read BIST/Header/Latency/Cache Line register
uint8_t header = (uint8_t) ((registerData & 0x00FF0000)
>> 24); // Header is lower byte of upper word, so mask it off and shift it down
uint8_t multifunction_bit = header &
0x80; // The multifunction bit is the highest bit of the header
registerData = PCIReadConfig(bus, device, function,
0); // Read the Vendor/Device ID register
VendorID = (uint16_t) (registerData & 0x0000FFFF); // Vendor ID is bottom word
DeviceID = (uint16_t) (registerData >> 16); // Device ID is top word
registerData = PCIReadConfig(bus, device, function, 8); // Read the Device Info register
ClassCode = (uint16_t) (registerData
>> 24); // Device class is top byte, so shift them down
subclass_code = (uint16_t) ((registerData >> 16) &
0x00FF); // Device subclass is same as header - lower byte of higher word. Shift down and mask just like before.
uint8_t device_progif = (uint16_t) ((registerData & 0x0000FF00)
>> 8); // Device Programming Interface is higher byte of lower word, so mask and shift
uint8_t device_revision = (uint16_t) (registerData &
0x000000FF); // Device revision is lower byte of whole double word. Just mask it.
/* 0xFFFF is not a valid Vendor ID. This serves as a sanity check.
* If this check is true, then nothing is logged and we continue for the next loop.
*/
if (VendorID != 0xFFFF) {
SerialPrintf("[ PCI]\n[ PCI]\t%x:%x:\n[ PCI]\t\tVendor: %x\n[ PCI]\t\tDevice: %x", bus, device,
VendorID, DeviceID);
SerialPrintf("\n[ PCI]\t\tClass: %s\n[ PCI]\t\tDevice Type: %s\n[ PCI]\t\tRevision: %d\n",
PCIGetClassName(ClassCode),
PCIGetDeviceName_Subclass(ClassCode, subclass_code, device_progif), device_revision);
}
/* If the PCI Device header tells us that this is not a multifunction device,
* and we've already scanned function 0, then there is nothing else to see.
* Therefore, stop this loop and move onto device++
*/
if (multifunction_bit == 0)
break;
}
}
} while (++bus);
}
uint32_t PCIReadConfig(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset) {
uint32_t address;
uint32_t busLong = (uint32_t) bus;
uint32_t slotLong = (uint32_t) slot;
uint32_t functionLong = (uint32_t) function;
/* ---------------------------------------------------------------
* | 31 | 30 ... 24 | 23 ... 16 | 15 ... 11 | 10 ... 8 | 7 ... 0 |
* ---------------------------------------------------------------
* | EN | RESERVED | BUS NUM | DEVICE NO | FUNC NO | REG OFF |
* ---------------------------------------------------------------
*
* NOTE: REG OFF *must* have 0 last two bits (ie. & 0xFC)
*/
address = (uint32_t) ((busLong << 16) | (slotLong << 11) |
(functionLong << 8) | (offset & 0xFC) | ((uint32_t) 0x80000000));
WritePort(0xCF8, address, 4);
return ReadPort(0xCFC, 4);
}
const char* PCIGetDeviceName_Subclass(uint8_t DeviceClass, uint8_t Subclass, uint8_t ProgrammableInterface) {
switch (DeviceClass) {
case 0x00: {
switch (Subclass) {
case 0x00:
return "Non-VGA-Compatible device";
case 0x01:
return "VGA-Compatible device";
default:
return "Unknown Unclassified";
}
}
case 0x01: {
switch (Subclass) {
case 0x00:
return "SCSI Bus Controller";
case 0x01: {
switch (ProgrammableInterface) {
case 0x00:
return "ISA Compatibility Mode-only IDE Controller";
case 0x05:
return "PCI Native Mode-only IDE Controller";
case 0x0A:
return "ISA Compatibility Mode IDE Controller (supports PCI Native Mode)";
case 0x0F:
return "PCI Native Mode IDE Controller (supports ISA Compatibility Mode)";
case 0x80:
return "ISA Compatibilty Mode-only IDE Controller (supports Bus Mastering)";
case 0x85:
return "PCI Native Mode-only IDE Controller (supports Bus Mastering)";
case 0x8A:
return "ISA Compatibility Mode IDE Controller (supports PCI Native Mode & Bus Mastering)";
case 0x8F:
return "PCI Native Mode IDE Controller (supports ISA Compatibiliy Mode & Bus Mastering)";
default:
return "IDE Controller";
}
}
case 0x02:
return "Floppy Disk Controller";
case 0x03:
return "IPI Bus Controller";
case 0x04:
return "RAID Controller";
case 0x05: {
switch (ProgrammableInterface) {
case 0x20:
return "Single-DMA ATA Controller";
case 0x30:
return "Chained-DMA ATA Controller";
default:
return "ATA Controller";
}
}
case 0x06: {
switch (ProgrammableInterface) {
case 0x00:
return "Vendor-Specific Interface SATA Controller";
case 0x01:
return "AHCI 1.0 SATA Controller";
case 0x02:
return "Serial Storage Bus SATA Controller";
default:
return "Serial ATA Controller";
}
}
case 0x07:
return "Serial Attached SCSI (SAS)";
case 0x08: {
switch (ProgrammableInterface) {
case 0x01:
return "NVMHCI Memory Controller";
case 0x02:
return "NVMe Memory Controller";
default:
return "Non-Volatile Memory Controller";
}
}
case 0x80:
return "Other";
default:
return "Unknown Mass Storage Controller";
}
}
case 0x02: {
switch (Subclass) {
case 0x00:
return "Ethernet Controller";
case 0x01:
return "Token Ring Controller";
case 0x02:
return "FDDI Controller";
case 0x03:
return "ATM Controller";
case 0x04:
return "ISDN Controller";
case 0x05:
return "WorldFip Controller";
case 0x06:
return "PICMG 2.14 Multi Computing";
case 0x07:
return "Infiniband Controller";
case 0x08:
return "Fabric Controller";
case 0x80:
return "Other";
default:
return "Unknown Network Controller";
}
}
case 0x03: {
switch (Subclass) {
case 0x00: {
switch (ProgrammableInterface) {
case 0x00:
return "VGA Controller";
case 0x01:
return "8514 VGA Controller";
default:
return "VGA Compatible Controller";
}
}
case 0x01:
return "XGA Controller";
case 0x02:
return "3D Controller (Not VGA-Compatible)";
case 0x80:
return "Other";
default:
return "Unknown Display Controller";
}
}
case 0x04: {
switch (Subclass) {
case 0x00:
return "Multimedia Video Controller";
case 0x01:
return "Multimedia Audio Controller";
case 0x02:
return "Computer Telephony Device";
case 0x03:
return "Audio Device";
case 0x80:
return "Other";
default:
return "Unknown Multimedia Controller";
}
}
case 0x05: {
switch (Subclass) {
case 0x00:
return "RAM Controller";
case 0x01:
return "Flash Controller";
case 0x80:
return "Other";
default:
return "Unknown Memory Controller";
}
}
case 0x06: {
switch (Subclass) {
case 0x00:
return "Host Bridge";
case 0x01:
return "ISA Bridge";
case 0x02:
return "EISA Bridge";
case 0x03:
return "MCA Bridge";
case 0x04:
case 0x09:
return "PCI-to-PCI Bridge";
case 0x05:
return "PCMCIA Bridge";
case 0x06:
return "NuBus Bridge";
case 0x07:
return "CardBus Bridge";
case 0x08:
return "RACEway Bridge";
case 0x0A:
return "InfiniBand-to-PCI Host Bridge";
case 0x80:
return "Other";
default:
return "Unknown Bridge Device";
}
}
case 0x07: {
switch (Subclass) {
case 0x00: {
switch (ProgrammableInterface) {
case 0x00:
return "Serial Controller <8250>";
case 0x01:
return "Serial controller <16450>";
case 0x02:
return "Serial controller <16550>";
case 0x03:
return "Serial controller <16650>";
case 0x04:
return "Serial controller <16750>";
case 0x05:
return "Serial controller <16850>";
case 0x06:
return "Serial controller <16950>";
default:
return "Serial Controller";
}
}
case 0x01: {
switch (ProgrammableInterface) {
case 0x00:
return "Standard Parallel Port";
case 0x01:
return "Bi-Directional Parallel Port";
case 0x02:
return "ECP 1.X Compliant Parallel Port";
case 0x03:
return "IEEE 1284 Parallel Controller";
case 0x04:
return "IEE 1284 Parallel Target";
default:
return "Parallel Controller";
}
}
case 0x02:
return "Multiport Serial Controller";
case 0x03: {
switch (ProgrammableInterface) {
case 0x00:
return "Generic Modem";
case 0x01:
return "Hayes 16450 Compatible Modem";
case 0x02:
return "Hayes 16550 Compatible Modem";
case 0x03:
return "Hayes 16650 Compatible Modem";
case 0x04:
return "Hayes 16750 Compatible Modem";
default:
return "Modem";
}
}
case 0x04:
return "IEEE 488.1/2 (GPIB) Controller";
case 0x05:
return "Smart Card";
case 0x80:
return "Other";
default:
return "Unknown Simple Comms Controller";
}
}
case 0x08: {
switch (Subclass) {
case 0x00: {
switch (ProgrammableInterface) {
case 0x00:
return "Generic 8259-Compatible PIC";
case 0x01:
return "ISA-Compatible PIC";
case 0x02:
return "EISA-Compatible PIC";
case 0x03:
return "I/O APIC Interrupt Controller";
case 0x04:
return "I/O(x) APIC Interrupt Controller";
default:
return "PIC";
}
}
case 0x01: {
switch (ProgrammableInterface) {
case 0x00:
return "Generic 8237-Compatible DMA Controller";
case 0x01:
return "ISA-Compatible DMA Controller";
case 0x02:
return "EISA-Compatible DMA Controller";
default:
return "DMA Controller";
}
}
case 0x02: {
switch (ProgrammableInterface) {
case 0x00:
return "Generic 8254-Compatible Timer";
case 0x01:
return "ISA-Compatible Timer";
case 0x02:
return "EISA-Compatible Timer";
case 0x03:
return "HPET Timer";
default:
return "Timer";
}
}
case 0x03: {
switch (ProgrammableInterface) {
case 0x00:
return "Generic RTC Controller";
case 0x01:
return "ISA-Compatible RTC Controller";
default:
return "RTC Controller";
}
}
case 0x04:
return "PCI Hot-Plug Controller";
case 0x05:
return "SD Host Controller";
case 0x06:
return "IOMMU";
case 0x80:
return "Other";
default:
return "Unknown Base System Peripheral";
}
}
case 0x09: {
switch (Subclass) {
case 0x00:
return "Keyboard Controller";
case 0x01:
return "Digitiser Pen";
case 0x02:
return "Mouse Controller";
case 0x03:
return "Scanner Controller";
case 0x04: {
switch (ProgrammableInterface) {
case 0x00:
return "Generic Gameport Controller";
case 0x10:
return "Extended Gameport Controller";
default:
return "Gameport Controller";
}
}
case 0x80:
return "Other";
default:
return "Unknown Input Device Controller";
}
}
case 0x0A: {
switch (Subclass) {
case 0x00:
return "Generic Docking Station";
case 0x80:
return "Other";
default:
return "Unknown Docking Station";
}
}
case 0x0B: {
switch (Subclass) {
case 0x00:
return "386 Processor";
case 0x01:
return "486 Processor";
case 0x02:
return "Pentium Processor";
case 0x03:
return "Pentium Pro Processor";
case 0x10:
return "Alpha Processor";
case 0x20:
return "PowerPC Processor";
case 0x30:
return "MIPS Processor";
case 0x40:
return "Co-Processor";
case 0x80:
return "Other";
default:
return "Unknown Processor";
}
}
case 0x0C: {
switch (Subclass) {
case 0x00: {
switch (ProgrammableInterface) {
case 0x00:
return "Generic Firewire Controller";
case 0x10:
return "OHCI Firewire Controller";
default:
return "FireWire (IEEE 1394) Controller";
}
}
case 0x01:
return "ACCESS Bus";
case 0x02:
return "SSA";
case 0x03: {
switch (ProgrammableInterface) {
case 0x00:
return "UHCI USB Controller";
case 0x10:
return "OHCI USB Controller";
case 0x20:
return "EHCI USB (2.0) Controller";
case 0x30:
return "XHCI USB (3.0) Controller";
case 0x80:
return "Unspecified USB Controller";
case 0xFE:
return "USB Device (NOT a Controller)";
default:
return "USB Controller";
}
}
case 0x04:
return "Fibre Channel";
case 0x05:
return "SMBus";
case 0x06:
return "InfiniBand";
case 0x07: {
switch (ProgrammableInterface) {
case 0x00:
return "SMIC IPMI Interface";
case 0x01:
return "Keyboard Controller-Style IPMI Interface";
case 0x02:
return "Block Transfer IPMI Interface";
default:
return "IPMI Interface";
}
}
case 0x08:
return "SERCOS Interface (IEC 61491)";
case 0x09:
return "CANbus";
case 0x80:
return "Other";
default:
return "Unknown Serial Bus Controller";
}
}
case 0x0D: {
switch (Subclass) {
case 0x00:
return "IRDA Compatible Controller";
case 0x01:
return "Consumer IR Controller";
case 0x10:
return "RF Controller";
case 0x11:
return "Bluetooth Controller";
case 0x12:
return "Broadband Controller";
case 0x20:
return "Ethernet Controller (802.1a)";
case 0x21:
return "Ethernet Controller (802.1b)";
case 0x80:
return "Other";
default:
return "Unknown Wireless Controller";
}
}
case 0x0E: {
switch (Subclass) {
case 0x00:
return "I20";
default:
return "Unknown Intelligent Controller";
}
}
case 0x0F: {
switch (Subclass) {
case 0x01:
return "Satellite TV Controller";
case 0x02:
return "Satellite Audio Controller";
case 0x03:
return "Satellite Voice Controller";
case 0x04:
return "Satellite Data Controller";
default:
return "Unknown Satelllite Comms Controller";
}
}
case 0x10: {
switch (Subclass) {
case 0x00:
return "Network & Computing Codec";
case 0x10:
return "Entertainment Codec";
case 0x80:
return "Other Codec";
default:
return "Unknown Encryption Controller";
}
}
case 0x11: {
switch (Subclass) {
case 0x00:
return "DPIO Modules";
case 0x01:
return "Performance Counters";
case 0x10:
return "Communication Synchronizer";
case 0x20:
return "Signal Processing Management";
case 0x80:
return "Other";
default:
return "Unknown Signal Processing Controller";
}
}
case 0x12:
return "Processing Accelerator";
case 0x13:
return "Non-Essential Instrumentation";
case 0x14:
case 0x41:
return "Reserved";
case 0x40:
return "Co-Processor";
case 0xFF:
return "Unassigned Class";
}
return "Invalid Device!";
}
const char* PCIGetClassName(uint8_t DeviceClass) {
switch (DeviceClass) {
case 0x00:
return "Unclassified";
case 0x01:
return "Mass Storage Controller";
case 0x02:
return "Network Controller";
case 0x03:
return "Display Controller";
case 0x04:
return "Multimedia Controller";
case 0x05:
return "Memory Controller";
case 0x06:
return "Bridge Device";
case 0x07:
return "Simple Communication Controller";
case 0x08:
return "Base System Peripheral";
case 0x09:
return "Input Device Controller";
case 0x0A:
return "Docking Station";
case 0x0B:
return "Processor";
case 0x0C:
return "Serial Bus Controller";
case 0x0D:
return "Wireless Controller";
case 0x0E:
return "Intelligent Controller";
case 0x0F:
return "Satellite Communication Controller";
case 0x10:
return "Encryption Controller";
case 0x11:
return "Signal Processing Controller";
case 0x12:
return "Processing Accelerator";
case 0x13:
return "Non-Essential Instrumentation";
case 0x14:
return "Reserved";
case 0x40:
return "Co-Processor";
case 0x41:
return "Reserved";
case 0xFF:
return "Unassigned Class";
default:
return "Unknown Category";
}
return "Invalid device!";
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,27 @@
#include <kernel/chroma.h>
#include <kernel/system/process/process.h>
/************************
*** Team Kitty, 2021 ***
*** Chroma ***
***********************/
// An array of pointers to the header of each active process.
Process** processes;
// An array of pointers to the header of each process active on the current core.
Process* processesPerCore[MAX_CORES];
// A lock "counter". This can be increased and decreased at will.
// Positive values mean the process is being locked by another, zero and negative means it is active.
int locked = 0;
// Whether the current process is fully loaded into memory and ready to run.
bool loaded = false;
// A ticketlock that prevents two threads being created at the same time.
ticketlock_t creatorlock;
// A ticketlock that prevents two threads from being switched into at the same time.
ticketlock_t switcherlock;
// The PID of the next process to be created. The kernel is always 0.
size_t nextPID = 1;

View File

@ -207,7 +207,7 @@ size_t ReadXCS() {
}
DESC_TBL ReadGDT() {
DESC_TBL GDTData = {0};
DESC_TBL GDTData;
__asm__ __volatile__("sgdt %[dest]" : [dest] "=m"(GDTData) : :);
@ -220,7 +220,7 @@ void WriteGDT(DESC_TBL GDTData) {
}
DESC_TBL ReadIDT() {
DESC_TBL IDTData = {0};
DESC_TBL IDTData;
__asm__ __volatile__("sidt %[dest]" : [dest] "=m"(IDTData) : :);

View File

@ -20,7 +20,7 @@ extern "C" {
*/
PRINTINFO PrintInfo = {0};
PRINTINFO PrintInfo;
#define FONT bitfont_latin
@ -44,8 +44,10 @@ void InitPrint() {
PrintInfo.charsPerRow = bootldr.fb_width / (PrintInfo.charScale * PrintInfo.charWidth);
PrintInfo.rowsPerScrn = bootldr.fb_height / (PrintInfo.charScale * PrintInfo.charHeight);
SerialPrintf("[Print] A single character is %ux%u pixels.\r\n", PrintInfo.charScale * PrintInfo.charWidth, PrintInfo.charScale * PrintInfo.charHeight);
SerialPrintf("[Print] The screen is %ux%u, meaning you can fit %ux%u characters on screen.\r\n", bootldr.fb_width, bootldr.fb_height, PrintInfo.charsPerRow, PrintInfo.rowsPerScrn);
SerialPrintf("[Print] A single character is %ux%u pixels.\r\n", PrintInfo.charScale * PrintInfo.charWidth,
PrintInfo.charScale * PrintInfo.charHeight);
SerialPrintf("[Print] The screen is %ux%u, meaning you can fit %ux%u characters on screen.\r\n", bootldr.fb_width,
bootldr.fb_height, PrintInfo.charsPerRow, PrintInfo.rowsPerScrn);
WriteString("Testing print\n");
@ -87,9 +89,11 @@ static void DrawChar(const char character, size_t x, size_t y) {
for (uint32_t ScaleY = 0; ScaleY < PrintInfo.charScale; ScaleY++) { // Take care of the scale height
for (uint32_t ScaleX = 0; ScaleX < PrintInfo.charScale; ScaleX++) { // And the scale width
size_t offset = ((y * bootldr.fb_width + x) + // Calculate the offset from the framebuffer
PrintInfo.charScale * (Row * bootldr.fb_width + Bit) + // With the appropriate scale
PrintInfo.charScale * (Row * bootldr.fb_width + Bit) +
// With the appropriate scale
(ScaleY * bootldr.fb_width + ScaleX) + // In X and Y
PrintInfo.charScale * 1 * PrintInfo.charWidth) - 10; // With some offset to start at 0
PrintInfo.charScale * 1 * PrintInfo.charWidth) -
10; // With some offset to start at 0
// Check the bit in the bitmap, if it's solid..
if ((FONT[(int) character][Row * Y + X] >> (Bit & 0x7)) & 1) {
@ -110,11 +114,9 @@ inline void DrawPixel(size_t x, size_t y) {
}
void FillScreen(uint32_t color) {
uint32_t currentColor = GetForegroundColor();
for (uint32_t pixel = 0; pixel < bootldr.fb_width * bootldr.fb_height; pixel++) {
((uint32_t*) &fb)[pixel] = color;
}
SetForegroundColor(currentColor);
}
static void Newline() {
@ -226,7 +228,8 @@ void WriteStringWithFont(const char *inChar) {
offset += bootldr.fb_scanline;
}
inChar++; kx++;
inChar++;
kx++;
}
}

View File

@ -54,6 +54,10 @@ int SerialPrintf(const char* Format, ...) {
switch (*Format) {
case '.':
Limit = va_arg(Parameters, size_t);
[[fallthrough]];
case 'c': {
Format++;
@ -68,10 +72,7 @@ int SerialPrintf(const char* Format, ...) {
Format++;
const char* Str = va_arg(Parameters, char*);
size_t Len = strlen(Str);
if(Limit < Len)
return -1;
size_t Len = MIN(strlen(Str), Limit);
WriteSerialString(Str, Len);