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

@ -14,51 +14,53 @@ SET(CMAKE_CROSSCOMPILING 1)
project(chroma)
SET(src_files
${CMAKE_SOURCE_DIR}/src/kernel.cpp
${CMAKE_SOURCE_DIR}/src/video/draw.c
${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/memory/physmem.c
${CMAKE_SOURCE_DIR}/src/drivers/keyboard.c
${CMAKE_SOURCE_DIR}/src/drivers/elf.c
${CMAKE_SOURCE_DIR}/src/drivers/devices/devices.cpp
${CMAKE_SOURCE_DIR}/src/drivers/devices/storage/ata.cpp
${CMAKE_SOURCE_DIR}/src/kernel.cpp
${CMAKE_SOURCE_DIR}/src/video/draw.cpp
${CMAKE_SOURCE_DIR}/src/video/print.cpp
${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/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/compression/lzgmini.c
${CMAKE_SOURCE_DIR}/src/lainlib/string/str.c
${CMAKE_SOURCE_DIR}/src/editor/EditorMain.cpp
${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.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
${CMAKE_SOURCE_DIR}/src/global/crt0.o
${CMAKE_SOURCE_DIR}/src/global/crti.o
${CMAKE_SOURCE_DIR}/src/global/crtbegin.o
${CMAKE_SOURCE_DIR}/src/global/crt0.o
${CMAKE_SOURCE_DIR}/src/global/crti.o
${CMAKE_SOURCE_DIR}/src/global/crtbegin.o
)
set(src_epilogue
${CMAKE_SOURCE_DIR}/src/global/crtend.o
${CMAKE_SOURCE_DIR}/src/global/crtn.o
${CMAKE_SOURCE_DIR}/src/assets/font.o
${CMAKE_SOURCE_DIR}/src/assets/zerosharp.o
${CMAKE_SOURCE_DIR}/src/global/crtend.o
${CMAKE_SOURCE_DIR}/src/global/crtn.o
${CMAKE_SOURCE_DIR}/src/assets/font.o
${CMAKE_SOURCE_DIR}/src/assets/zerosharp.o
)
set_property(SOURCE ${src_no_sse} PROPERTY COMPILE_FLAGS -mgeneral-regs-only)
@ -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

@ -14,7 +14,7 @@
#define MAX_PROCESSES 128
#define PROCESS_STACK 65535
typedef void (*function_t)();
typedef void (* function_t)();
/**
* @brief All the data a process needs.
@ -68,138 +68,147 @@ class Process {
address_space_t* AddressSpace;
};
private:
ProcessHeader Header;
ProcessState State;
private:
ProcessHeader Header;
ProcessState State;
bool User; // Is this process originated in userspace?
bool System; // Was this process started by the system (ie. not user interaction)
bool User; // Is this process originated in userspace?
bool System; // Was this process started by the system (ie. not user interaction)
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 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. Otherwise, the kernel.
char Name[128];
size_t Entry; // The entry point. Move execution here to start the process.
uint8_t Core;
char Name[128];
size_t Entry; // The entry point. Move execution here to start the process.
uint8_t Core;
bool ORS = false;
bool IsActive = false;
bool IsInterrupted = false; // True if an interrupt was fired while this process is active
bool ORS = false;
bool IsActive = false;
bool IsInterrupted = false; // True if an interrupt was fired while this process is active
uint8_t Signals[8]; // Interrupt / IRQ / Signal handlers.
uint8_t Sleeping; // 0 if active, else the process is waiting for something. TODO: remove this, use State?
uint8_t Signals[8]; // Interrupt / IRQ / Signal handlers.
uint8_t Sleeping; // 0 if active, else the process is waiting for something. TODO: remove this, use State?
ProcessMessage* Messages; // A queue of IPC messages.
size_t LastMessage; // The index of the current message.
ProcessMessage* Messages; // A queue of IPC messages.
size_t LastMessage; // The index of the current message.
uint8_t* ProcessMemory;
size_t ProcessMemorySize;
uint8_t* ProcessMemory;
size_t ProcessMemorySize;
// TODO: Stack Trace & MFS
// TODO: Stack Trace & MFS
public:
public:
Process(size_t KPID) : State(PROCESS_AVAILABLE), UniquePID(-1), KernelPID(KPID) {
};
Process(size_t KPID) : State(PROCESS_AVAILABLE), UniquePID(-1), KernelPID(KPID) {
};
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) {
Process(const char* ProcessName, size_t KPID, size_t UPID, size_t EntryPoint, bool Userspace)
: User(Userspace), UniquePID(UPID), KernelPID(KPID), Entry(EntryPoint), ORS(false), Sleeping(0),
LastMessage(0) {
memcpy((void*) ProcessName, Name, strlen(Name) + 1);
};
memcpy((void*) ProcessName, Name, strlen(Name) + 1);
};
Process(const Process &Instance) {
memcpy(this, &Instance, sizeof(Process));
};
Process(const Process &Instance) {
memcpy(this, &Instance, sizeof(Process));
};
Process& operator=(const Process &Instance) {
memcpy(this, &Instance, sizeof(Process));
return *this;
};
Process &operator =(const Process &Instance) {
memcpy(this, &Instance, sizeof(Process));
return *this;
};
/*************************************************************/
/*************************************************************/
void InitMemory();
void InitMemory();
void InitMessages();
void InitMessages();
void Kill() {
State = ProcessState::PROCESS_REAP;
Sleeping = -1;
};
void Kill() {
State = ProcessState::PROCESS_REAP;
Sleeping = -1;
};
void Destroy();
void Destroy();
void Rename(const char* NewName) {
memcpy(Name, NewName, strlen(Name) > strlen(NewName) ? strlen(Name) : strlen(NewName));
void Rename(const char* NewName) {
memcpy(Name, NewName, strlen(Name) > strlen(NewName) ? strlen(Name) : strlen(NewName));
}
size_t* AllocateProcessSpace(size_t Bytes);
size_t FreeProcessSpace(size_t* Address, size_t Bytes);
bool OwnsAddress(size_t* Address, size_t Bytes);
/*************************************************************/
void SetParent(size_t PID) { ParentPID = PID; };
void SetSystem(bool Status) {
System = Status;
if (System && User) {
// TODO: Log error.
}
};
size_t* AllocateProcessSpace(size_t Bytes);
size_t FreeProcessSpace(size_t* Address, size_t Bytes);
void SetState(ProcessState NewState) { State = NewState; };
bool OwnsAddress(size_t* Address, size_t Bytes);
void SetActive(bool NewState) { IsActive = NewState; };
/*************************************************************/
void SetCore(size_t CoreID) { Core = CoreID; };
void SetParent(size_t PID) { ParentPID = PID; };
void IncreaseSleep(size_t Interval) { Sleeping += Interval; };
void SetSystem(bool Status) {
System = Status;
if(System && User) {
// TODO: Log error.
}
};
void DecreaseSleep(size_t Interval) { Sleeping -= Interval; };
void SetState(ProcessState NewState) { State = NewState; };
/*************************************************************/
void SetActive(bool NewState) { IsActive = NewState; };
ProcessHeader* GetHeader() { return &Header; };
void SetCore(size_t CoreID) { Core = CoreID; };
const char* GetName() const { return Name; };
void IncreaseSleep(size_t Interval) { Sleeping += Interval; };
void DecreaseSleep(size_t Interval) { Sleeping -= Interval; };
size_t GetPID() const { return UniquePID; };
/*************************************************************/
size_t GetKPID() const { return KernelPID; };
ProcessHeader* GetHeader() { return &Header; };
size_t GetParent() const { return ParentPID; };
const char* GetName() const { return Name; };
ProcessState GetState() const { return State; };
size_t GetPID() const { return UniquePID; };
size_t GetKPID() const { return KernelPID; };
bool IsValid() const { return KernelPID != 0; };
size_t GetParent() const { return ParentPID; };
bool IsUsed() const { return (State != ProcessState::PROCESS_AVAILABLE && State != ProcessState::PROCESS_CRASH &&
State != ProcessState::PROCESS_REAP) && IsValid();
};
ProcessState GetState() const { return State; };
bool IsSleeping() const { return Sleeping; };
bool IsValid() const { return KernelPID != 0; };
size_t GetSleepCounter() const { return Sleeping; };
bool IsUsed() const { return (State != ProcessState::PROCESS_AVAILABLE && State != ProcessState::PROCESS_CRASH && State != ProcessState::PROCESS_REAP) && IsValid(); };
bool CanRun(const size_t CPU) const {
bool flag = !(ORS && !IsActive);
bool IsSleeping() const { return Sleeping; };
return State == ProcessState::PROCESS_WAITING && Core == CPU && KernelPID != 0 && flag && !IsSleeping();
};
size_t GetSleepCounter() const { return Sleeping; };
size_t GetCore() const { return Core; };
bool CanRun(const size_t CPU) const {
bool flag = !(ORS && !IsActive);
bool IsUserspace() { return User; };
return State == ProcessState::PROCESS_WAITING && Core == CPU && KernelPID != 0 && flag && !IsSleeping();
};
size_t GetCore() const { return Core; };
bool IsUserspace() { return User; };
bool IsSystem() { return System; };
bool IsSystem() { return System; };
/*************************************************************/
/*************************************************************/
static Process* FromName(const char* name);
static Process* FromPID(size_t PID);
static Process* Current();
static Process* FromName(const char* name);
static void SetCurrent(Process* Target);
static Process* FromPID(size_t PID);
static Process* Current();
static void SetCurrent(Process* Target);
};
@ -211,42 +220,54 @@ class Process {
* Stuff like switching tasks, sleeping, killing, etc.
*/
class ProcessManagement {
public:
TSS64 TSS[MAX_CORES];
uint32_t CoreCount = 1;
public:
TSS64 TSS[MAX_CORES];
uint32_t CoreCount = 1;
ProcessManagement();
static ProcessManagement* instance();
ProcessManagement();
void Wait();
void Initialize();
void InitialiseCore(size_t APIC, size_t ID);
static ProcessManagement* instance();
void NotifyAllCores();
void Wait();
void DumpProcess(size_t PID);
void LockProcess(size_t PID);
void UnlockProcess(size_t PID);
void Initialize();
static void Sleep(size_t Count);
void Sleep(size_t Count, size_t PID);
void InitialiseCore(size_t APIC, size_t ID);
static void Kill(int Code);
void Kill(size_t PID, int Code);
void NotifyAllCores();
bool CheckLocked(size_t PID);
void DumpProcess(size_t PID);
void GetStatus(size_t PID, int* ReturnVal, size_t* StatusVal);
void LockProcess(size_t PID);
// 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();
void UnlockProcess(size_t PID);
size_t HandleRequest(size_t CPU);
static void Sleep(size_t Count);
inline void yield() { __asm __volatile("int 100"); }
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);
void GetStatus(size_t PID, int* ReturnVal, size_t* StatusVal);
// 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);
inline void yield() { __asm __volatile("int 100"); }
};

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

@ -22,7 +22,7 @@ Device::GenericStorage* StorageDevicesArray[MAX_STORAGE_DEVICES];
size_t CurrentStorageDevice = 0;
// Internal storage. TODO: Make this not a pain to maintain
const char* DeviceNames[] = { "Storage", "Keyboard", "Networking" };
const char* DeviceNames[] = {"Storage", "Keyboard", "Networking"};
// Add a device pointer to the managed list.
@ -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.
@ -54,8 +55,8 @@ size_t Device::GetTotalDevices() { return CurrentDevice; }
template <typename T>
// Get the first registered instance of a specific type of device
T* Device::FindDevice() {
for(size_t i = 0; i < CurrentDevice; i++)
if(DevicesArray[i]->GetType() == T::GetRootType())
for (size_t i = 0; i < CurrentDevice; i++)
if (DevicesArray[i]->GetType() == T::GetRootType())
return static_cast<T*>(DevicesArray[i]);
SerialPrintf("[DEVICE] Warning: Unable to find a %s device.\r\n", DeviceNames[T::GetRootType()]);

View File

@ -23,59 +23,59 @@ extern "C" {
KBD_FLAGS KbdFlags;
char keys[128] = {
0, 27,
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
0,
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '#',
0,
'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/',
0,
'*', 0,
' ', 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0,
0,
0,
0,
0,
0,
'-',
0,
0,
0,
'+',
0,
0,
0,
0,
0,
0, 0, 0,
0,
0,
0,
0, 27,
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
0,
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '#',
0,
'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/',
0,
'*', 0,
' ', 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0,
0,
0,
0,
0,
0,
'-',
0,
0,
0,
'+',
0,
0,
0,
0,
0,
0, 0, 0,
0,
0,
0,
};
KeyboardCallback KeyboardCallbacks[16] = {
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
static int CurrentCallback = 0;
int SetupKBCallback(void (*Handler)(KeyboardData Frame)) {
int SetupKBCallback(void (* Handler)(KeyboardData Frame)) {
KeyboardCallbacks[CurrentCallback++] = Handler;
return CurrentCallback;
}
void UninstallKBCallback(int Number) {
KeyboardCallbacks[Number] = NULL; // 0 is used in the common check to make sure that the function is callable.
// This removes this callback from that check, ergo the function will no longer be called.
KeyboardCallbacks[Number] = NULL; // 0 is used in the common check to make sure that the function is callable.
// This removes this callback from that check, ergo the function will no longer be called.
}
void KbdEcho() {
if(!KbdFlags.EchoCount) {
if(!KbdFlags.Echo) {
if (!KbdFlags.EchoCount) {
if (!KbdFlags.Echo) {
Send8042(0xEE);
}
} else {
@ -87,7 +87,7 @@ void KbdEcho() {
void UpdateKeyboard(uint8_t msg) {
switch(msg) {
switch (msg) {
case 0x0:
KbdFlags.Error = 1;
//ResendBuffer();
@ -122,25 +122,25 @@ 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);
void (* Handler)(KeyboardData data);
for(size_t handlerNum = 0; handlerNum < 16; handlerNum++) {
Handler = KeyboardCallbacks[handlerNum];
if(Handler) {
Handler(data);
}
for (size_t handlerNum = 0; handlerNum < 16; handlerNum++) {
Handler = KeyboardCallbacks[handlerNum];
if (Handler) {
Handler(data);
}
}
}
void Send8042(size_t info) {
for(size_t i = 0; i < 8; i++) {
for (size_t i = 0; i < 8; i++) {
unsigned char chr = (unsigned char) info;
if(chr != 0) {
if (chr != 0) {
WritePort(0x60, chr, 1);
WaitFor8042();
}
@ -149,10 +149,10 @@ void Send8042(size_t info) {
void WaitFor8042() {
bool full = true;
while(full) {
full = ReadPort(0x64, 1) & 1;
}
bool full = true;
while (full) {
full = ReadPort(0x64, 1) & 1;
}
}
#ifdef __cplusplus

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,58 +22,58 @@ 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;
for(size_t i = InitrdPtr; i < ((size_t) (&_kernel_text_start) - KernelAddr) + InitrdPtr; i++) {
if(*((volatile uint32_t*)(i)) == ELF64MAGIC) {
for (size_t i = InitrdPtr; i < ((size_t) (&_kernel_text_start) - KernelAddr) + InitrdPtr; i++) {
if (*((volatile uint32_t*) (i)) == ELF64MAGIC) {
SerialPrintf("[ boot] Matched kernel header at 0x%p.\r\n", i);
headerLoc = i;
}
if(FIXENDIAN32(*((volatile uint32_t*)(i))) == ELF64MAGIC) {
if (FIXENDIAN32(*((volatile uint32_t*) (i))) == ELF64MAGIC) {
SerialPrintf("[ boot] Matched little-endian kernel header at 0x%p.\r\n", i);
headerLoc = i;
}
}
if(headerLoc) {
if (headerLoc) {
/* For whatever reason, reading a size_t here fails. The max that seems to work is uint16_t, so we read in the
* 64 bit address by constructing it from 4 individual reads.
* Note that these 4 reads are little endian, so we need to flip them around individually
*/
uint16_t EntryPoint0 = FIXENDIAN16(*((volatile uint16_t*)(headerLoc + ELFENTRY_OFF)));
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);
uint16_t EntryPoint0 = FIXENDIAN16(*((volatile uint16_t*) (headerLoc + ELFENTRY_OFF)));
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);
/* 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));
EntryPoint = FIXENDIAN64(EntryPoint);
/* Now we can continue as normal */
uint8_t HeaderClass = *((volatile uint8_t*)(headerLoc + ELF_IDENT_CLASS_OFF));
uint16_t ExecutableType = (uint16_t) *((volatile uint8_t*)(headerLoc + ELFTYPE_OFF));
uint16_t MachineType = (uint16_t) *((volatile uint8_t*)(headerLoc + ELFMACHINE_OFF));
uint8_t HeaderClass = *((volatile uint8_t*) (headerLoc + ELF_IDENT_CLASS_OFF));
uint16_t ExecutableType = (uint16_t) *((volatile uint8_t*) (headerLoc + ELFTYPE_OFF));
uint16_t MachineType = (uint16_t) *((volatile uint8_t*) (headerLoc + ELFMACHINE_OFF));
SerialPrintf(
"[ boot] ELF header at 0x%p.\r\n\tConsidering ELF with:\r\n\tBitness %d: %d\r\n\tEntry point 0x%p\r\n\tFile type %s : 0x%x\r\n\tArchitecture %s : 0x%x\r\n",
headerLoc,
HeaderClass == 2 ? 64 : 32,
HeaderClass,
EntryPoint,
ExecutableType == FIXENDIAN16(0x0200) ? "EXECUTABLE" : "OTHER",
"[ boot] ELF header at 0x%p.\r\n\tConsidering ELF with:\r\n\tBitness %d: %d\r\n\tEntry point 0x%p\r\n\tFile type %s : 0x%x\r\n\tArchitecture %s : 0x%x\r\n",
headerLoc,
HeaderClass == 2 ? 64 : 32,
HeaderClass,
EntryPoint,
ExecutableType == FIXENDIAN16(0x0200) ? "EXECUTABLE" : "OTHER",
FIXENDIAN16(ExecutableType),
MachineType == FIXENDIAN16(0x3E00) ? "AMD64" : "OTHER",
MachineType == FIXENDIAN16(0x3E00) ? "AMD64" : "OTHER",
FIXENDIAN16(MachineType));
if(EntryPoint == (size_t) (&_kernel_text_start)) {
if (EntryPoint == (size_t) (&_kernel_text_start)) {
SerialPrintf("[ boot] Header at 0x%p matches kernel header.\r\n", headerLoc);
flag = 1;
// At this point, we've found the right ELF64 executable!
@ -81,10 +81,10 @@ int ParseKernelHeader(size_t InitrdPtr) {
KernelLocation = headerLoc;
}
if(!flag) {
if (!flag) {
for(char i = 0; i < 64; i++) {
SerialPrintf("[ boot] Header dump part %x: 0x%x\r\n", i, *((volatile uint8_t*)(headerLoc + i)));
for (char i = 0; i < 64; i++) {
SerialPrintf("[ boot] Header dump part %x: 0x%x\r\n", i, *((volatile uint8_t*) (headerLoc + i)));
}
}
}

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;
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] Initrd's header is 0x%p\r\n", FIXENDIAN32(*((volatile uint32_t*)(bootldr.initrd_ptr))));
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();
@ -84,15 +90,15 @@ int Main(void) {
InternalBufferID = SetupKBCallback(&TrackInternalBuffer);
for (;;) {}
for (;;) { }
return 0;
}
void PrintPressedChar(KeyboardData data) {
if(!KernelLoaded) return;
extern "C" void PrintPressedChar(KeyboardData data) {
if (!KernelLoaded) return;
if(data.Pressed) {
if (data.Pressed) {
SerialPrintf("Key pressed: [\\%c (%x)]\r\n", data.Char, data.Scancode);
Printf("%c", data.Char);
} else {
@ -100,24 +106,24 @@ void PrintPressedChar(KeyboardData data) {
}
}
void TrackInternalBuffer(KeyboardData data) {
if(!data.Pressed) return;
extern "C" void TrackInternalBuffer(KeyboardData data) {
if (!data.Pressed) return;
bool tentative = false;
if(BufferLength > 4097) tentative = true;
if (BufferLength > 4097) tentative = true;
if(data.Char == '\b') {
if (data.Char == '\b') {
BufferLength--;
tentative = false;
}
if(data.Scancode == 0x1C) {
if (data.Scancode == 0x1C) {
InternalBuffer[BufferLength] = '\0'; // Null-terminate to make checking easier
if(strcmp(InternalBuffer, "editor")) {
if (strcmp(InternalBuffer, "editor")) {
UninstallKBCallback(InternalBufferID);
Editor editor;
editor.StartEditor(CharPrinterCallbackID);
} else if(strcmp(InternalBuffer, "zero")) {
} else if (strcmp(InternalBuffer, "zero")) {
int returnVal = sharp_entryPoint();
SerialPrintf("Sharp returned %d\r\n", returnVal);
} else {
@ -128,18 +134,21 @@ void TrackInternalBuffer(KeyboardData data) {
BufferLength = 0;
}
if(!tentative && data.Scancode <= 0x2c && data.Scancode != 0x1C) {
if (!tentative && data.Scancode <= 0x2c && data.Scancode != 0x1C) {
SerialPrintf("[ Kbd] Adding %c to the buffer.\r\n", data.Char);
InternalBuffer[BufferLength] = data.Char;
BufferLength++;
}
}
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

@ -28,7 +28,7 @@ extern "C" {
#define BP_STACK 4096
void InvalidatePage(size_t Page) {
__asm__ __volatile__("invlpg (%%eax)" : : "a" (Page) );
__asm__ __volatile__("invlpg (%%eax)" : : "a" (Page));
}
__attribute__((aligned(64))) static volatile unsigned char NMIStack[NMI_STACK] = {0};
@ -37,19 +37,19 @@ __attribute__((aligned(64))) static volatile unsigned char MCStack[MC_STACK] = {
__attribute__((aligned(64))) static volatile unsigned char BPStack[BP_STACK] = {0};
__attribute__((aligned(64))) static volatile size_t InitGDT[5] = {
0,
0x00af9a000000ffff,
0x00cf92000000ffff,
0x0080890000000067,
0
0,
0x00af9a000000ffff,
0x00cf92000000ffff,
0x0080890000000067,
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() {
__asm__ __volatile__ ("mov $16, %ax \n\t" // 16 = 0x10 = index 2 of GDT
"mov %ax, %ds \n\t" // Next few lines prepare the processor for the sudden change into the data segment
"mov %ax, %es \n\t" //
@ -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;
@ -122,10 +122,10 @@ void SetupInitialGDT() {
GDTData.Limit = sizeof(InitGDT) - 1;
GDTData.Base = (size_t) InitGDT;
( (TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]) )->BaseLow = TSSLower;
( (TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]) )->BaseMid1 = TSSMid1;
( (TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]) )->BaseMid2 = TSSMid2;
( (TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]) )->BaseHigh = TSSHigher;
((TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]))->BaseLow = TSSLower;
((TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]))->BaseMid1 = TSSMid1;
((TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]))->BaseMid2 = TSSMid2;
((TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]))->BaseHigh = TSSHigher;
WriteGDT(GDTData);
WriteTSR(3 << 3);
@ -203,44 +203,44 @@ 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;
//memset(&IDTEntries, 0, sizeof(IDT_GATE) * 256);
RemapIRQControllers();
RemapIRQControllers();
*(size_t*) (&TSSEntries.IST1) = (size_t) (NMIStack + NMI_STACK);
*(size_t*) (&TSSEntries.IST2) = (size_t) (DFStack + DF_STACK);
*(size_t*) (&TSSEntries.IST3) = (size_t) (MCStack + MC_STACK);
*(size_t*) (&TSSEntries.IST4) = (size_t) (BPStack + BP_STACK);
SetISR (0, (size_t) ISR0Handler);
SetISRBP (1, (size_t) ISR1Handler);
SetISRNMI (2, (size_t) ISR2Handler);
SetISRBP (3, (size_t) ISR3Handler);
SetISR (4, (size_t) ISR4Handler);
SetISR (5, (size_t) ISR5Handler);
SetISR (6, (size_t) ISR6Handler);
SetISR (7, (size_t) ISR7Handler);
SetISRDF (8, (size_t) ISR8Handler);
SetISR (9, (size_t) ISR9Handler);
SetISR (10, (size_t) ISR10Handler);
SetISR (11, (size_t) ISR11Handler);
SetISR (12, (size_t) ISR12Handler);
SetISR (13, (size_t) ISR13Handler);
SetISR (14, (size_t) ISR14Handler);
SetISR (15, (size_t) ISR15Handler);
SetISR (16, (size_t) ISR16Handler);
SetISR (17, (size_t) ISR17Handler);
SetISRMC (18, (size_t) ISR18Handler);
SetISR (19, (size_t) ISR19Handler);
SetISR (20, (size_t) ISR20Handler);
SetISR (30, (size_t) ISR30Handler);
SetISR(0, (size_t) ISR0Handler);
SetISRBP(1, (size_t) ISR1Handler);
SetISRNMI(2, (size_t) ISR2Handler);
SetISRBP(3, (size_t) ISR3Handler);
SetISR(4, (size_t) ISR4Handler);
SetISR(5, (size_t) ISR5Handler);
SetISR(6, (size_t) ISR6Handler);
SetISR(7, (size_t) ISR7Handler);
SetISRDF(8, (size_t) ISR8Handler);
SetISR(9, (size_t) ISR9Handler);
SetISR(10, (size_t) ISR10Handler);
SetISR(11, (size_t) ISR11Handler);
SetISR(12, (size_t) ISR12Handler);
SetISR(13, (size_t) ISR13Handler);
SetISR(14, (size_t) ISR14Handler);
SetISR(15, (size_t) ISR15Handler);
SetISR(16, (size_t) ISR16Handler);
SetISR(17, (size_t) ISR17Handler);
SetISRMC(18, (size_t) ISR18Handler);
SetISR(19, (size_t) ISR19Handler);
SetISR(20, (size_t) ISR20Handler);
SetISR(30, (size_t) ISR30Handler);
for(size_t i = 1; i < 11; i++) {
if(i != 9) {
for (size_t i = 1; i < 11; i++) {
if (i != 9) {
SetISR(i + 20, (size_t) ReservedISRHandler);
}
}

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

@ -49,9 +49,9 @@ extern void SomethingWentWrong(const char* Message);
*************************************************/
#ifdef _cplusplus
#define alloc_decl inline
#define alloc_decl inline
#else
#define alloc_decl static
#define alloc_decl static
#endif
@ -61,18 +61,18 @@ alloc_decl int Alloc_FindFirstOne(unsigned int word) {
alloc_decl int Alloc_FindLastOne(unsigned int word) {
const int bit = word ? 32 - __builtin_clz(word) : 0;
return bit -1;
return bit - 1;
}
alloc_decl int Alloc_FindLastOne_64(size_t size) {
int high = (int)(size >> 32);
int high = (int) (size >> 32);
int bits = 0;
if(high)
if (high)
bits = 32 + Alloc_FindLastOne(high);
else
bits = Alloc_FindLastOne((int)size & 0xFFFFFFFF);
bits = Alloc_FindLastOne((int) size & 0xFFFFFFFF);
return bits;
}
@ -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
**********************************************/
@ -113,7 +112,7 @@ typedef struct block_header_t {
struct block_header_t* NextFreeBlock;
struct block_header_t* LastFreeBlock;
} block_header_t ;
} block_header_t;
typedef struct allocator_control_t {
@ -225,12 +224,12 @@ size_t AlignDownwards(size_t Pointer, size_t Alignment) {
void* AlignPointer(const void* Pointer, size_t Alignment) {
const ptrdiff_t AlignedPointer =
((
CAST(ptrdiff_t, Pointer)
+ (Alignment - 1))
& ~(Alignment - 1)
);
const ptrdiff_t AlignedPointer =
((
CAST(ptrdiff_t, Pointer)
+ (Alignment - 1))
& ~(Alignment - 1)
);
ASSERT(((Alignment & (Alignment - 1)) == 0), "AlignPointer: Requested alignment not aligned!");
return CAST(void*, AlignedPointer);
@ -244,12 +243,12 @@ void* AlignPointer(const void* Pointer, size_t Alignment) {
static size_t AlignRequestSize(size_t Size, size_t Alignment) {
size_t Adjustment = 0;
if(Size) {
if (Size) {
const size_t Aligned = AlignUpwards(Size, Alignment);
if(Aligned < BLOCK_MAX_SIZE)
if (Aligned < BLOCK_MAX_SIZE)
Adjustment = MAX(Aligned, BLOCK_MIN_SIZE);
}
return Adjustment;
@ -258,7 +257,7 @@ static size_t AlignRequestSize(size_t Size, size_t Alignment) {
static void InsertMapping(size_t Size, int* FirstLevelIndex, int* SecondLevelIndex) {
int FirstLevel, SecondLevel;
if(Size < SMALL_BLOCK_SIZE) {
if (Size < SMALL_BLOCK_SIZE) {
FirstLevel = 0;
SecondLevel = CAST(int, Size) / (SMALL_BLOCK_SIZE / SL_INDEX_COUNT);
@ -274,7 +273,7 @@ static void InsertMapping(size_t Size, int* FirstLevelIndex, int* SecondLevelInd
}
static void RoundUpBlockSize(size_t Size, int* FirstLevelIndex, int* SecondLevelIndex) {
if(Size >= SMALL_BLOCK_SIZE) {
if (Size >= SMALL_BLOCK_SIZE) {
const size_t Rounded = (1 << (Alloc_FindLastOne_64(Size) - SL_LIMIT_LN)) - 1;
Size += Rounded;
}
@ -288,13 +287,13 @@ static block_header_t* FindSuitableBlock(allocator_control_t* Controller, int* F
unsigned int SLMap = Controller->SecondLevel_Bitmap[FirstLevel] & (~0U << SecondLevel);
if(!SLMap) {
if (!SLMap) {
const unsigned int FLMap = Controller->FirstLevel_Bitmap & (~0U << (FirstLevel + 1));
if(!FLMap)
if (!FLMap)
return 0;
FirstLevel = Alloc_FindFirstOne(FLMap);
*FirstLevelIndex = FirstLevel;
SLMap = Controller->SecondLevel_Bitmap[FirstLevel];
@ -318,27 +317,31 @@ static void RemoveFreeBlock(allocator_control_t* Controller, block_header_t* Blo
NextBlock->LastFreeBlock = PreviousBlock;
PreviousBlock->NextFreeBlock = NextBlock;
if(Controller->Blocks[FirstLevel][SecondLevel] == Block) {
if (Controller->Blocks[FirstLevel][SecondLevel] == Block) {
Controller->Blocks[FirstLevel][SecondLevel] = NextBlock;
if(NextBlock == &Controller->BlockNull) {
if (NextBlock == &Controller->BlockNull) {
Controller->SecondLevel_Bitmap[FirstLevel] &= ~(1U << SecondLevel);
if(!Controller->SecondLevel_Bitmap[FirstLevel]) {
if (!Controller->SecondLevel_Bitmap[FirstLevel]) {
Controller->FirstLevel_Bitmap &= ~(1U << FirstLevel);
}
}
}
}
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]);
for(;;){}
}
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]);
for (;;) { }
}
ASSERT(NewBlock, "InsertFreeBlock: New Block is null!");
NewBlock->NextFreeBlock = Current;
@ -346,10 +349,11 @@ 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);
Controller->FirstLevel_Bitmap |= (1U << FirstLevel);
Controller->SecondLevel_Bitmap[FirstLevel] |= (1U << SecondLevel);
}
@ -376,12 +380,13 @@ 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!");
BlockSetSize(Overlap, RemainingSize);
ASSERT(BlockSize(Overlap) >= BLOCK_MIN_SIZE, "SplitBlock: Requested size results in new block that is too small!");
BlockSetSize(Block, NewSize);
@ -401,7 +406,7 @@ static block_header_t* MergeBlockDown(block_header_t* Previous, block_header_t*
static block_header_t* MergeEmptyBlockDown(allocator_control_t* Controller, block_header_t* Block) {
if(BlockPrevIsFree(Block)) {
if (BlockPrevIsFree(Block)) {
block_header_t* Previous = BlockGetPrevious(Block);
ASSERT(Previous, "MergeEmptyBlockDown: Previous block is null!");
ASSERT(BlockIsFree(Previous), "MergeEmptyBlockDown: Previous block is free!");
@ -416,19 +421,19 @@ static block_header_t* MergeNextBlockDown(allocator_control_t* Controller, block
block_header_t* NextBlock = BlockGetNext(Block);
ASSERT(NextBlock, "MergeNextBlockDown: Next Block is null!");
if(BlockIsFree(NextBlock)) {
if (BlockIsFree(NextBlock)) {
ASSERT(!BlockIsLast(Block), "MergeNextBlockDown: Current block is the last block!");
RemoveBlock(Controller, NextBlock);
Block = MergeBlockDown(Block, NextBlock);
}
return Block;
}
static void TrimBlockFree(allocator_control_t* Controller, block_header_t* Block, size_t Size) {
ASSERT(BlockIsFree(Block), "TrimBlockFree: Current block is wholly free!");
if(CanBlockSplit(Block, Size)) {
if (CanBlockSplit(Block, Size)) {
block_header_t* RemainingBlock = SplitBlock(Block, Size);
BlockLinkToNext(Block);
@ -442,7 +447,7 @@ static void TrimBlockFree(allocator_control_t* Controller, block_header_t* Block
static void TrimBlockUsed(allocator_control_t* Controller, block_header_t* Block, size_t Size) {
ASSERT(!BlockIsFree(Block), "TrimBlockUsed: The current block is wholly used!");
if(CanBlockSplit(Block, Size)) {
if (CanBlockSplit(Block, Size)) {
block_header_t* RemainingBlock = SplitBlock(Block, Size);
@ -458,7 +463,7 @@ static void TrimBlockUsed(allocator_control_t* Controller, block_header_t* Block
static block_header_t* TrimBlockLeadingFree(allocator_control_t* Controller, block_header_t* Block, size_t Size) {
block_header_t* RemainingBlock = Block;
if(CanBlockSplit(Block, Size)) {
if (CanBlockSplit(Block, Size)) {
RemainingBlock = SplitBlock(Block, Size - BLOCK_OVERHEAD);
BlockSetPrevFree(RemainingBlock);
@ -476,17 +481,17 @@ static block_header_t* LocateFreeBlock(allocator_control_t* Controller, size_t S
block_header_t* Block = 0;
if(Size) {
if (Size) {
RoundUpBlockSize(Size, &FirstLevel, &SecondLevel);
if(FirstLevel < FL_INDEX_COUNT) {
if (FirstLevel < FL_INDEX_COUNT) {
Block = FindSuitableBlock(Controller, &FirstLevel, &SecondLevel);
}
}
if(Block) {
if (Block) {
ASSERT(BlockSize(Block) >= Size, "LocateFreeBlock: Found a block that is too small!");
RemoveFreeBlock(Controller, Block, FirstLevel, SecondLevel);
}
@ -497,7 +502,7 @@ static block_header_t* LocateFreeBlock(allocator_control_t* Controller, size_t S
static void* PrepareUsedBlock(allocator_control_t* Controller, block_header_t* Block, size_t Size) {
void* Pointer = 0;
if(Block){
if (Block) {
ASSERT(Size, "PrepareUsedBlock: Size is 0!");
TrimBlockFree(Controller, Block, Size);
BlockMarkUsed(Block);
@ -520,7 +525,7 @@ static void ConstructController(allocator_control_t* Controller) {
Controller->FirstLevel_Bitmap = 0;
for ( i = 0; i < FL_INDEX_COUNT; i++) {
for (i = 0; i < FL_INDEX_COUNT; i++) {
Controller->SecondLevel_Bitmap[i] = 0;
for (j = 0; j < SL_INDEX_COUNT; j++) {
@ -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
************************************************************************************/
@ -539,7 +543,7 @@ static void ConstructController(allocator_control_t* Controller) {
size_t AllocatorGetBlockSize(void* Memory) {
size_t Size = 0;
if(Memory) {
if (Memory) {
const block_header_t* Block = WhichBlock(Memory);
Size = BlockSize(Block);
}
@ -564,7 +568,7 @@ size_t AllocatorMaxBlockSize(void) {
}
size_t AllocatorPoolOverhead(void) {
return 2* BLOCK_OVERHEAD; // Free block + Sentinel block
return 2 * BLOCK_OVERHEAD; // Free block + Sentinel block
}
size_t AllocatorAllocateOverhead(void) {
@ -579,17 +583,19 @@ mempool_t AddPoolToAllocator(allocator_t Allocator, void* Address, size_t Size)
const size_t PoolOverhead = AllocatorPoolOverhead();
const size_t PoolBytes = AlignDownwards(Size - PoolOverhead, ALIGN_SIZE);
if(((ptrdiff_t) Address % ALIGN_SIZE) != 0) {
if (((ptrdiff_t) Address % ALIGN_SIZE) != 0) {
SerialPrintf("Memory manager error at [%s:%x]: Memory not properly aligned.\r\n", __FILE__, __LINE__);
return 0;
}
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);
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);
return 0;
}
Block = OffsetToBlock(Address, -(ptrdiff_t)BLOCK_OVERHEAD);
Block = OffsetToBlock(Address, -(ptrdiff_t) BLOCK_OVERHEAD);
BlockSetSize(Block, PoolBytes);
BlockSetFree(Block);
BlockSetPrevUsed(Block);
@ -602,11 +608,11 @@ mempool_t AddPoolToAllocator(allocator_t Allocator, void* Address, size_t Size)
BlockSetPrevFree(NextBlock);
return Address;
}
}
void RemovePoolFromAllocator(allocator_t Allocator, mempool_t Pool){
void RemovePoolFromAllocator(allocator_t Allocator, mempool_t Pool) {
allocator_control_t* Controller = CAST(allocator_control_t*, Allocator);
block_header_t* Block = OffsetToBlock(Pool, -(int)BLOCK_OVERHEAD);
block_header_t* Block = OffsetToBlock(Pool, -(int) BLOCK_OVERHEAD);
int FirstLevel = 0, SecondLevel = 0;
@ -619,32 +625,32 @@ void RemovePoolFromAllocator(allocator_t Allocator, mempool_t Pool){
}
int TestBuiltins() {
/* Verify ffs/fls work properly. */
int TestsFailed = 0;
TestsFailed += (Alloc_FindFirstOne(0) == -1) ? 0 : 0x1;
TestsFailed += (Alloc_FindLastOne(0) == -1) ? 0 : 0x2;
TestsFailed += (Alloc_FindFirstOne(1) == 0) ? 0 : 0x4;
TestsFailed += (Alloc_FindLastOne(1) == 0) ? 0 : 0x8;
TestsFailed += (Alloc_FindFirstOne(0x80000000) == 31) ? 0 : 0x10;
TestsFailed += (Alloc_FindFirstOne(0x80008000) == 15) ? 0 : 0x20;
TestsFailed += (Alloc_FindLastOne(0x80000008) == 31) ? 0 : 0x40;
TestsFailed += (Alloc_FindLastOne(0x7FFFFFFF) == 30) ? 0 : 0x80;
TestsFailed += (Alloc_FindLastOne_64(0x80000000) == 31) ? 0 : 0x100;
TestsFailed += (Alloc_FindLastOne_64(0x100000000) == 32) ? 0 : 0x200;
TestsFailed += (Alloc_FindLastOne_64(0xffffffffffffffff) == 63) ? 0 : 0x400;
/* Verify ffs/fls work properly. */
int TestsFailed = 0;
TestsFailed += (Alloc_FindFirstOne(0) == -1) ? 0 : 0x1;
TestsFailed += (Alloc_FindLastOne(0) == -1) ? 0 : 0x2;
TestsFailed += (Alloc_FindFirstOne(1) == 0) ? 0 : 0x4;
TestsFailed += (Alloc_FindLastOne(1) == 0) ? 0 : 0x8;
TestsFailed += (Alloc_FindFirstOne(0x80000000) == 31) ? 0 : 0x10;
TestsFailed += (Alloc_FindFirstOne(0x80008000) == 15) ? 0 : 0x20;
TestsFailed += (Alloc_FindLastOne(0x80000008) == 31) ? 0 : 0x40;
TestsFailed += (Alloc_FindLastOne(0x7FFFFFFF) == 30) ? 0 : 0x80;
if (TestsFailed) {
SerialPrintf("TestBuiltins: %x ffs/fls tests failed.\n", TestsFailed);
}
TestsFailed += (Alloc_FindLastOne_64(0x80000000) == 31) ? 0 : 0x100;
TestsFailed += (Alloc_FindLastOne_64(0x100000000) == 32) ? 0 : 0x200;
TestsFailed += (Alloc_FindLastOne_64(0xffffffffffffffff) == 63) ? 0 : 0x400;
return TestsFailed;
if (TestsFailed) {
SerialPrintf("TestBuiltins: %x ffs/fls tests failed.\n", TestsFailed);
}
return TestsFailed;
}
allocator_t CreateAllocator(void* Memory) {
if(TestBuiltins())
if (TestBuiltins())
return 0;
if (((ptrdiff_t) Memory % ALIGN_SIZE) != 0) {
SerialPrintf("Memory manager error at [%s:%x]: Memory not properly aligned.\r\n", __FILE__, __LINE__);
return 0;
@ -659,7 +665,7 @@ allocator_t CreateAllocator(void* Memory) {
allocator_t CreateAllocatorWithPool(void* Memory, size_t Bytes) {
allocator_t Allocator = CreateAllocator(Memory);
AddPoolToAllocator(Allocator, (char*)Memory + AllocatorSize(), Bytes - AllocatorSize());
AddPoolToAllocator(Allocator, (char*) Memory + AllocatorSize(), Bytes - AllocatorSize());
return Allocator;
}
@ -669,7 +675,7 @@ void DestroyAllocator(allocator_t Allocator) {
}
mempool_t GetPoolFromAllocator(allocator_t Allocator) {
return CAST(mempool_t, (char*)Allocator + AllocatorSize());
return CAST(mempool_t, (char*) Allocator + AllocatorSize());
}
/***********************************************************************************
@ -698,14 +704,14 @@ void* AllocatorMalign(allocator_t Allocator, size_t Alignment, size_t Size) {
ASSERT(sizeof(block_header_t) == BLOCK_MIN_SIZE + BLOCK_OVERHEAD, "AllocatorMalign: Maths error!");
if(Block) {
if (Block) {
void* Address = WhereBlock(Block);
void* AlignedAddress = AlignPointer(Address, Alignment);
size_t Gap = CAST(size_t, CAST(ptrdiff_t, AlignedAddress) - CAST(ptrdiff_t, Address));
if(Gap) {
if(Gap << MinimumGap) {
if (Gap) {
if (Gap << MinimumGap) {
const size_t GapRemaining = MinimumGap - Gap;
const size_t Offset = MAX(GapRemaining, Alignment);
const void* NextAlignedAddress = CAST(void*, CAST(ptrdiff_t, AlignedAddress) + Offset);
@ -726,7 +732,7 @@ void* AllocatorMalign(allocator_t Allocator, size_t Alignment, size_t Size) {
}
void AllocatorFree(allocator_t Allocator, void* Address) {
if(Address) {
if (Address) {
allocator_control_t* Controller = CAST(allocator_control_t*, Allocator);
block_header_t* Block = WhichBlock(Address);
ASSERT(!BlockIsFree(Block), "AllocatorFree: Attempting to free a freed block!");
@ -759,9 +765,9 @@ void* AllocatorRealloc(allocator_t Allocator, void* Address, size_t NewSize) {
void* Pointer = 0;
// Valid address, invalid size; free
if(Address && NewSize == 0)
if (Address && NewSize == 0)
AllocatorFree(Allocator, Address);
else if (!Address) // Invalid address; alloc
AllocatorMalloc(Allocator, NewSize);
@ -776,17 +782,17 @@ void* AllocatorRealloc(allocator_t Allocator, void* Address, size_t NewSize) {
ASSERT(!BlockIsFree(Block), "AllocatorRealloc: Requested block is not free!");
if(AdjustedSize > CurrentSize && (!BlockIsFree(NextBlock) || AdjustedSize > CombinedSize)) {
if (AdjustedSize > CurrentSize && (!BlockIsFree(NextBlock) || AdjustedSize > CombinedSize)) {
// We're going to need more room
Pointer = AllocatorMalloc(Allocator, NewSize);
if(Pointer) {
if (Pointer) {
const size_t MinimumSize = MIN(CurrentSize, NewSize);
memcpy(Pointer, Address, MinimumSize);
AllocatorFree(Allocator, Address);
}
} else {
if( AdjustedSize > CurrentSize) {
if (AdjustedSize > CurrentSize) {
MergeNextBlockDown(Controller, Block);
BlockMarkUsed(Block);
}

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,42 +34,46 @@ 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},
.PML4 = (size_t*) ReadControlRegister(3)
.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++) {
for (size_t i = 0; i < (FullMemorySize / 4096); i++) {
size_t Addr = i * 4096;
MapVirtualPageNoDirect(&KernelAddressSpace, Addr, Addr, DEFAULT_PAGE_FLAGS);
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);
for(size_t i = BootldrAddress; i < (BootldrAddress + bootldr.size); i += PAGE_SIZE)
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);
for(size_t i = KERNEL_PHYSICAL; i < KERNEL_END; i += PAGE_SIZE)
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);
// TODO: The above mapping loses the ELF header.
// This allows us to write to the screen
SerialPrintf("[ Mem] Mapping 0x%x bytes of framebuffer, starting at 0x%p\r\n", bootldr.fb_size, FB_PHYSICAL);
for(size_t i = FB_PHYSICAL; i < bootldr.fb_size + FB_PHYSICAL; i += PAGE_SIZE) {
for (size_t i = FB_PHYSICAL; i < bootldr.fb_size + FB_PHYSICAL; i += PAGE_SIZE) {
MapVirtualPageNoDirect(&KernelAddressSpace, i, i, 0x3); // FD000000 + (page)
MapVirtualPageNoDirect(&KernelAddressSpace, i, (i - FB_PHYSICAL) + FB_REGION, 0x3); // FFFFFFFFFC000000 + (page)
}
@ -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);
@ -127,19 +134,19 @@ size_t DecodeVirtualAddress(address_space_t* AddressSpace, size_t VirtualAddress
size_t PDP = PAGE_TABLES_GET_PDP(VirtualAddress);
size_t PDE = PAGE_TABLES_GET_PDE(VirtualAddress);
size_t PT = PAGE_TABLES_GET_PT(VirtualAddress);
size_t* PDPT_T, *PDE_T, *PT_T;
size_t* PDPT_T, * PDE_T, * PT_T;
if(AddressSpace->PML4[PDPT] & PRESENT_BIT)
if (AddressSpace->PML4[PDPT] & PRESENT_BIT)
PDPT_T = (size_t*) TO_DIRECT(AddressSpace->PML4[PDPT] & STACK_TOP);
else
return VirtualAddress;
if(PDPT_T[PDP] & PRESENT_BIT)
if (PDPT_T[PDP] & PRESENT_BIT)
PDE_T = (size_t*) TO_DIRECT(PDPT_T[PDP] & STACK_TOP);
else
return VirtualAddress;
if(PDE_T[PDE] & PRESENT_BIT)
if (PDE_T[PDE] & PRESENT_BIT)
PT_T = (size_t*) TO_DIRECT(PDE_T[PDE] & STACK_TOP);
else
return VirtualAddress;
@ -162,10 +169,10 @@ void MapVirtualPage(address_space_t* AddressSpace, size_t Physical, size_t Virtu
size_t PDP = PAGE_TABLES_GET_PDP(Virtual);
size_t PDE = PAGE_TABLES_GET_PDE(Virtual);
size_t PT = PAGE_TABLES_GET_PT(Virtual);
size_t* PDPT_T, *PDE_T, *PT_T;
size_t* PDPT_T, * PDE_T, * PT_T;
// Read the top level's bits. If it's marked as present..
if(AddressSpace->PML4[PDPT] & PRESENT_BIT)
if (AddressSpace->PML4[PDPT] & PRESENT_BIT)
// Set the variable for the next level. Mask off the lower 12 bits, shift it into the "direct region".
PDPT_T = (size_t*) TO_DIRECT(AddressSpace->PML4[PDPT] & STACK_TOP);
else {
@ -176,14 +183,14 @@ void MapVirtualPage(address_space_t* AddressSpace, size_t Physical, size_t Virtu
}
// The above repeats.
if(PDPT_T[PDP] & PRESENT_BIT)
if (PDPT_T[PDP] & PRESENT_BIT)
PDE_T = (size_t*) TO_DIRECT(PDPT_T[PDP] & STACK_TOP);
else {
PDE_T = (size_t*) TO_DIRECT(PhysAllocateZeroMem(4096));
PDPT_T[PDP] = FROM_DIRECT(PDE_T) | DEFAULT_PAGE_FLAGS;
}
if(PDE_T[PDE] & PRESENT_BIT)
if (PDE_T[PDE] & PRESENT_BIT)
PT_T = (size_t*) TO_DIRECT(PDE_T[PDE] & STACK_TOP);
else {
PT_T = (size_t*) TO_DIRECT(PhysAllocateZeroMem(4096));
@ -216,19 +223,19 @@ size_t DecodeVirtualAddressNoDirect(address_space_t* AddressSpace, size_t Virtua
size_t PDP = PAGE_TABLES_GET_PDP(VirtualAddress);
size_t PDE = PAGE_TABLES_GET_PDE(VirtualAddress);
size_t PT = PAGE_TABLES_GET_PT(VirtualAddress);
size_t* PDPT_T, *PDE_T, *PT_T;
size_t* PDPT_T, * PDE_T, * PT_T;
if(AddressSpace->PML4[PDPT] & PRESENT_BIT)
if (AddressSpace->PML4[PDPT] & PRESENT_BIT)
PDPT_T = (size_t*) (AddressSpace->PML4[PDPT] & STACK_TOP);
else
return VirtualAddress;
if(PDPT_T[PDP] & PRESENT_BIT)
if (PDPT_T[PDP] & PRESENT_BIT)
PDE_T = (size_t*) (PDPT_T[PDP] & STACK_TOP);
else
return VirtualAddress;
if(PDE_T[PDE] & PRESENT_BIT)
if (PDE_T[PDE] & PRESENT_BIT)
PT_T = (size_t*) (PDE_T[PDE] & STACK_TOP);
else
return VirtualAddress;
@ -254,10 +261,10 @@ void MapVirtualPageNoDirect(address_space_t* AddressSpace, size_t Physical, size
size_t PDP = PAGE_TABLES_GET_PDP(Virtual);
size_t PDE = PAGE_TABLES_GET_PDE(Virtual);
size_t PT = PAGE_TABLES_GET_PT(Virtual);
size_t* PDPT_T, *PDE_T, *PT_T;
size_t* PDPT_T, * PDE_T, * PT_T;
// Read the top level's bits. If it's marked as present..
if(AddressSpace->PML4[PDPT] & PRESENT_BIT)
if (AddressSpace->PML4[PDPT] & PRESENT_BIT)
// Set the variable for the next level. Mask off the lower 12 bits, shift it into the "direct region".
PDPT_T = (size_t*) (AddressSpace->PML4[PDPT] & STACK_TOP);
else {
@ -269,7 +276,7 @@ void MapVirtualPageNoDirect(address_space_t* AddressSpace, size_t Physical, size
// The above repeats.
if(PDPT_T[PDP] & PRESENT_BIT)
if (PDPT_T[PDP] & PRESENT_BIT)
PDE_T = (size_t*) (PDPT_T[PDP] & STACK_TOP);
else {
PDE_T = (size_t*) PhysAllocateZeroMem(4096);
@ -277,7 +284,7 @@ void MapVirtualPageNoDirect(address_space_t* AddressSpace, size_t Physical, size
}
if(PDE_T[PDE] & PRESENT_BIT)
if (PDE_T[PDE] & PRESENT_BIT)
PT_T = (size_t*) (PDE_T[PDE] & STACK_TOP);
else {
PT_T = (size_t*) PhysAllocateZeroMem(4096);
@ -302,20 +309,20 @@ 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},
.PML4 = NewPML4
.Lock = {.NowServing = 0, .NextTicket = 0},
.PML4 = NewPML4
};
// Initialize to zeros
for(size_t i = 0; i < 512; i++)
for (size_t i = 0; i < 512; i++)
NewPML4[i] = 0;
// Copy the current Address Space's higher half
for(size_t i = 255; i < 512; i++)
for (size_t i = 255; i < 512; i++)
NewPML4[i] = AddressSpace->PML4[i];
// Identity map the bottom two megabytes into the higher half
for(size_t i = 0; i < 8192; i++) {
for (size_t i = 0; i < 8192; i++) {
// Get page offset
size_t Addr = i * 4096;
// Identity map
@ -325,7 +332,7 @@ size_t* CreateNewPageTable(address_space_t* AddressSpace) {
}
// Identity map the next 4gb
for(size_t i = 8192; i < 0x100000; i++) {
for (size_t i = 8192; i < 0x100000; i++) {
size_t Addr = i * 4096;
MapVirtualPage(&TempAddressSpace, Addr, Addr, DEFAULT_PAGE_FLAGS);
}

View File

@ -1,6 +1,7 @@
#include <kernel/chroma.h>
#include <lainlib/lainlib.h>
/************************
*** Team Kitty, 2020 ***
*** Chroma ***
@ -12,21 +13,16 @@ 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.
*
* 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.
*
* 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.
*
* The implementation here is bespoke, and in need of documentation.
*
* TODO: Document this mess.
*/
#define MIN_ORDER 3
#define MIN_ORDER 3
#define PEEK(type, address) (*((volatile type*)(address)))
uint8_t* MemoryStart;
@ -37,17 +33,17 @@ size_t FreeMemorySize = 0;
size_t FullMemorySize = 0;
static buddy_t LowBuddy = {
.MaxOrder = 32,
.Base = (directptr_t) DIRECT_REGION,
.List = (directptr_t[32 - MIN_ORDER]) {0},
.Lock = {0},
.MaxOrder = 32,
.Base = (directptr_t) DIRECT_REGION,
.List = (directptr_t[32 - MIN_ORDER]) {0},
.Lock = {.NowServing = 0, .NextTicket = 0},
};
static buddy_t HighBuddy = {
.MaxOrder = 64,
.Base = 0,
.List = (directptr_t[64 - MIN_ORDER]) {0},
.Lock = {0},
.MaxOrder = 64,
.Base = 0,
.List = (directptr_t[64 - MIN_ORDER]) {0},
.Lock = {.NowServing = 0, .NextTicket = 0},
};
static size_t MemoryLength;
@ -68,12 +64,12 @@ static void AddToBuddyList(buddy_t* Buddy, directptr_t Address, size_t Order, bo
TicketAttemptLock(&Buddy->Lock);
if(!NewEntry && ListHead != 0) {
if (!NewEntry && ListHead != 0) {
directptr_t ListPrevious = 0;
while(true) {
if(CheckBuddies(Buddy, ListHead, Address, Size)) {
if(ListPrevious != 0) {
while (true) {
if (CheckBuddies(Buddy, ListHead, Address, Size)) {
if (ListPrevious != 0) {
PEEK(directptr_t, ListPrevious) = PEEK(directptr_t, ListHead);
} else
Buddy->List[Order - MIN_ORDER] = PEEK(directptr_t, ListHead);
@ -82,7 +78,7 @@ static void AddToBuddyList(buddy_t* Buddy, directptr_t Address, size_t Order, bo
break;
}
if(PEEK(directptr_t, ListHead) == 0) {
if (PEEK(directptr_t, ListHead) == 0) {
PEEK(directptr_t, ListHead) = Address;
break;
}
@ -91,7 +87,7 @@ static void AddToBuddyList(buddy_t* Buddy, directptr_t Address, size_t Order, bo
ListHead = PEEK(directptr_t, ListHead);
}
} else {
*((size_t*)(Address)) = (size_t) ListHead;
*((size_t*) (Address)) = (size_t) ListHead;
Buddy->List[Order - MIN_ORDER] = Address;
}
@ -99,15 +95,15 @@ static void AddToBuddyList(buddy_t* Buddy, directptr_t Address, size_t Order, bo
}
static void AddRangeToBuddy(buddy_t* Buddy, directptr_t Base, size_t Size) {
while(Size > (1ull << MIN_ORDER)) {
while (Size > (1ull << MIN_ORDER)) {
//SerialPrintf("New iteration. Current Size: 0x%x\r\n\t", Size);
for(int Order = Buddy->MaxOrder - 1; Order >= MIN_ORDER; Order--) {
for (int Order = Buddy->MaxOrder - 1; Order >= MIN_ORDER; Order--) {
//SerialPrintf("New Loop. Current Order: %d\r\n\t", Order);
if(Size >= (1ull << Order)) {
if (Size >= (1ull << Order)) {
//SerialPrintf("\tNew loop check passed.\r\n\t");
AddToBuddyList(Buddy, Base, Order, true);
//SerialPrintf("\tEntry added to current buddy. Moving onto memory operations..\r\n\t");
Base = (void*)((((char*)Base) + (1ull << Order)));
Base = (void*) ((((char*) Base) + (1ull << Order)));
Size -= 1ull << Order;
//SerialPrintf("\tMemory operations complete. Moving onto next iteration.\r\n");
break;
@ -121,9 +117,11 @@ static directptr_t BuddyAllocate(buddy_t* Buddy, size_t Size) {
size_t WantedSize = 1ull << InitialOrder;
if(InitialOrder >= Buddy->MaxOrder) {
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;
}
@ -131,9 +129,9 @@ static directptr_t BuddyAllocate(buddy_t* Buddy, size_t Size) {
//SerialPrintf("Searching for a valid order to allocate into. Condition: {\r\n\tOrder: %d,\r\n\tSize: 0x%x\r\n}\r\n\n", InitialOrder, WantedSize);
for(int Order = InitialOrder; Order < Buddy->MaxOrder; Order++) {
for (int Order = InitialOrder; Order < Buddy->MaxOrder; Order++) {
//SerialPrintf("\tCurrent Order: %d, Buddy entry: %x\r\n", Order, Buddy->List[Order - MIN_ORDER]);
if(Buddy->List[Order - MIN_ORDER] != 0) {
if (Buddy->List[Order - MIN_ORDER] != 0) {
//SerialPrintf("\tFound a valid Order!\r\n");
directptr_t Address = Buddy->List[Order - MIN_ORDER];
Buddy->List[Order - MIN_ORDER] = PEEK(directptr_t, Address);
@ -143,7 +141,7 @@ static directptr_t BuddyAllocate(buddy_t* Buddy, size_t Size) {
//SerialPrintf("\tAdding area - Address 0x%p, Size 0x%x\r\n\n", Address, FoundSize);
AddRangeToBuddy(Buddy, (void*)((size_t)Address + WantedSize), FoundSize - WantedSize);
AddRangeToBuddy(Buddy, (void*) ((size_t) Address + WantedSize), FoundSize - WantedSize);
//SerialPrintf("\tArea added!\r\n");
return Address;
@ -163,8 +161,8 @@ void InitMemoryManager() {
MMapEnt* MemMap = &bootldr.mmap;
while((size_t) MemMap < ((size_t) &bootldr) + bootldr.size) {
if(MMapEnt_IsFree(MemMap)) {
while ((size_t) MemMap < ((size_t) &bootldr) + bootldr.size) {
if (MMapEnt_IsFree(MemMap)) {
FreeMemorySize += MMapEnt_Size(MemMap);
}
FullMemorySize += MMapEnt_Size(MemMap);
@ -185,9 +183,9 @@ void ListMemoryMap() {
SerialPrintf("[ Mem] BIOS-Provided memory map:\r\n");
for(MMapEnt* MapEntry = &bootldr.mmap; (size_t)MapEntry < (size_t) &bootldr + bootldr.size; MapEntry++) {
for (MMapEnt* MapEntry = &bootldr.mmap; (size_t) MapEntry < (size_t) &bootldr + bootldr.size; MapEntry++) {
char EntryType[8] = {0};
switch(MMapEnt_Type(MapEntry)) {
switch (MMapEnt_Type(MapEntry)) {
case MMAP_FREE:
memcpy(EntryType, "FREE", 5);
break;
@ -206,17 +204,18 @@ void ListMemoryMap() {
size_t entry_to = MMapEnt_Ptr(MapEntry) + MMapEnt_Size(MapEntry);
if(entry_from != 0 && entry_to != 0)
if (entry_from != 0 && entry_to != 0)
SerialPrintf("[ Mem] 0x%p-0x%p %s\r\n", entry_from, entry_to, EntryType);
if(MMapEnt_Type(MapEntry) == MMAP_FREE) {
if (MMapEnt_Type(MapEntry) == MMAP_FREE) {
// We need to page align the inputs to the buddy lists.
size_t page_from = AlignUpwards(entry_from, 0x1000);
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);
AddRangeToPhysMem((void*)((char*)(page_from)), page_to - page_from);
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);
AddRangeToPhysMem((void*) ((char*) (page_from)), page_to - page_from);
}
}
@ -225,19 +224,21 @@ void ListMemoryMap() {
}
void AddRangeToPhysMem(directptr_t Base, size_t Size) {
if((size_t) Base + Size < (size_t) (LOWER_REGION)) {
if ((size_t) Base + Size < (size_t) (LOWER_REGION)) {
SerialPrintf("[ Mem] New range in lower memory: 0x%p, size 0x%x\r\n", Base, Size);
AddRangeToBuddy(&LowBuddy, Base, Size);
} else {
if((size_t) Base < (size_t) LOWER_REGION) {
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;
}
if(HighBuddy.Base == NULL) {
if (HighBuddy.Base == NULL) {
HighBuddy.Base = Base;
}
@ -245,8 +246,8 @@ void AddRangeToPhysMem(directptr_t Base, size_t Size) {
AddRangeToBuddy(&HighBuddy, Base, Size);
}
if(MemoryLength < AlignUpwards((size_t)Base + Size, PAGE_SIZE) / PAGE_SIZE) {
MemoryLength = AlignUpwards((size_t)Base + Size, PAGE_SIZE) / PAGE_SIZE;
if (MemoryLength < AlignUpwards((size_t) Base + Size, PAGE_SIZE) / PAGE_SIZE) {
MemoryLength = AlignUpwards((size_t) Base + Size, PAGE_SIZE) / PAGE_SIZE;
}
}
@ -260,12 +261,12 @@ directptr_t PhysAllocateLowMem(size_t Size) {
directptr_t PhysAllocateMem(size_t Size) {
directptr_t Pointer = NULL;
if(HighBuddy.Base == 0) {
if (HighBuddy.Base == 0) {
//SerialPrintf("Attempting allocation into high memory.\n");
Pointer = BuddyAllocate(&HighBuddy, Size);
}
if(Pointer == NULL) {
if (Pointer == NULL) {
//SerialPrintf("Attempting allocation into low memory.\n");
Pointer = BuddyAllocate(&LowBuddy, Size);
}
@ -293,7 +294,7 @@ void PhysFreeMem(directptr_t Pointer, size_t Size) {
buddy_t* Buddy;
if(Pointer < (void*)(LOWER_REGION /* + DIRECT_REGION */))
if (Pointer < (void*) (LOWER_REGION /* + DIRECT_REGION */))
Buddy = &LowBuddy;
else
Buddy = &HighBuddy;
@ -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() {
@ -319,7 +320,7 @@ void PhysRefPage(directptr_t Page) {
}
void PhysFreePage(directptr_t Page) {
if(--PageRefCount[(size_t)Page >> PAGE_SHIFT] == 0) {
if (--PageRefCount[(size_t) Page >> PAGE_SHIFT] == 0) {
PhysFreeMem(Page, PAGE_SIZE);
}
}
@ -328,7 +329,7 @@ void* memcpy(void* dest, void const* src, size_t len) {
unsigned char* dst = (unsigned char*) dest;
const unsigned char* source = (const unsigned char*) src;
for(size_t i = 0; i < len; i++) {
for (size_t i = 0; i < len; i++) {
dst[i] = source[i];
}
@ -338,8 +339,8 @@ void* memcpy(void* dest, void const* src, size_t len) {
void* memset(void* dst, int src, size_t len) {
unsigned char* buf = (unsigned char*) dst;
for(size_t i = 0; i < len; i++) {
buf[i] = (unsigned char) src;
for (size_t i = 0; i < len; i++) {
buf[i] = (unsigned char) src;
}
return dst;

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

@ -19,57 +19,57 @@ extern "C" {
uint32_t ReadPort(uint16_t Port, int Length) {
uint32_t Data = 0;
uint16_t Data16 = 0;
uint8_t Data8 = 0;
uint8_t Data8 = 0;
if(Length == 1) {
__asm__ __volatile__ ("inb %[address], %[value]" : [value] "=a" (Data8) : [address] "d" (Port) :);
if (Length == 1) {
__asm__ __volatile__ ("inb %[address], %[value]" : [value] "=a"(Data8) : [address] "d"(Port) :);
Data = (uint32_t) Data8;
} else if(Length == 2) {
__asm__ __volatile__ ("inw %[address], %[value]" : [value] "=a" (Data16) : [address] "d" (Port) :);
} else if (Length == 2) {
__asm__ __volatile__ ("inw %[address], %[value]" : [value] "=a"(Data16) : [address] "d"(Port) :);
Data = (uint32_t) Data16;
} else if(Length == 4)
__asm__ __volatile__ ("inl %[address], %[value]" : [value] "=a" (Data) : [address] "d" (Port) :);
} else if (Length == 4)
__asm__ __volatile__ ("inl %[address], %[value]" : [value] "=a"(Data) : [address] "d"(Port) :);
//else
//printf("Readport: Invalid length\r\n");
//printf("Readport: Invalid length\r\n");
return Data;
}
uint32_t WritePort(uint16_t Port, uint32_t Data, int Length) {
if(Length == 1)
__asm__ __volatile__ ("outb %[value], %[address]" : : [value] "a" ((uint8_t) Data), [address] "d" (Port) :);
else if(Length == 2)
__asm__ __volatile__ ("outw %[value], %[address]" : : [value] "a" ((uint16_t) Data), [address] "d" (Port) :);
else if(Length == 4)
__asm__ __volatile__ ("outl %[value], %[address]" : : [value] "a" (Data), [address] "d" (Port) :);
if (Length == 1)
__asm__ __volatile__ ("outb %[value], %[address]" : : [value] "a"((uint8_t) Data), [address] "d"(Port) :);
else if (Length == 2)
__asm__ __volatile__ ("outw %[value], %[address]" : : [value] "a"((uint16_t) Data), [address] "d"(Port) :);
else if (Length == 4)
__asm__ __volatile__ ("outl %[value], %[address]" : : [value] "a"(Data), [address] "d"(Port) :);
//else
//printf("WritePort: Invalid length.\r\n");
//printf("WritePort: Invalid length.\r\n");
return Data;
}
size_t ReadMMIO(size_t Address, int Length) {
if (Length == 1) {
return *((volatile uint8_t*)(Address));
return *((volatile uint8_t*) (Address));
} else if (Length == 2) {
return *((volatile uint16_t*)(Address));
return *((volatile uint16_t*) (Address));
} else if (Length == 4) {
return *((volatile uint32_t*)(Address));
return *((volatile uint32_t*) (Address));
} else {
return *((volatile size_t*)(Address));
return *((volatile size_t*) (Address));
}
}
void WriteMMIO(size_t Address, size_t Data, int Length) {
if(Length == 1) {
(*((volatile uint8_t*)(Address))) = ((uint8_t) Data);
if (Length == 1) {
(*((volatile uint8_t*) (Address))) = ((uint8_t) Data);
} else if (Length == 2) {
(*((volatile uint16_t*)(Address))) = ((uint16_t) Data);
(*((volatile uint16_t*) (Address))) = ((uint16_t) Data);
} else if (Length == 4) {
(*((volatile uint32_t*)(Address))) = ((uint32_t) Data);
(*((volatile uint32_t*) (Address))) = ((uint32_t) Data);
} else {
(*((volatile uint8_t*)(Address))) = (Data);
}
(*((volatile uint8_t*) (Address))) = (Data);
}
}
@ -94,26 +94,26 @@ size_t WriteModelSpecificRegister(size_t MSR, size_t Data) {
uint32_t ReadVexMXCSR() {
uint32_t Data;
__asm__ __volatile__ ("vstmxcsr %[dest]" : [dest] "=m" (Data) : :);
__asm__ __volatile__ ("vstmxcsr %[dest]" : [dest] "=m"(Data) : :);
return Data;
}
uint32_t WriteVexMXCSR(uint32_t Data) {
__asm__ __volatile__ ("vldmxcsr %[src]" : : [src] "m" (Data) :);
__asm__ __volatile__ ("vldmxcsr %[src]" : : [src] "m"(Data) :);
return Data;
}
uint32_t ReadMXCSR() {
uint32_t Data;
__asm__ __volatile__ ("stmxcsr %[dest]" : [dest] "=m" (Data) : :);
__asm__ __volatile__ ("stmxcsr %[dest]" : [dest] "=m"(Data) : :);
return Data;
}
uint32_t WriteMXCSR(uint32_t Data) {
__asm__ __volatile__ ("ldmxcsr %[src]" : : [src] "m" (Data) :);
__asm__ __volatile__ ("ldmxcsr %[src]" : : [src] "m"(Data) :);
return Data;
}
@ -121,30 +121,30 @@ size_t ReadControlRegister(int CRX) {
size_t Data;
switch(CRX) {
switch (CRX) {
case 0:
__asm__ __volatile__ ("mov %%cr0, %[dest]" : [dest] "=r" (Data) : :);
__asm__ __volatile__ ("mov %%cr0, %[dest]" : [dest] "=r"(Data) : :);
break;
case 1:
__asm__ __volatile__ ("mov %%cr1, %[dest]" : [dest] "=r" (Data) : :);
__asm__ __volatile__ ("mov %%cr1, %[dest]" : [dest] "=r"(Data) : :);
break;
case 2:
__asm__ __volatile__ ("mov %%cr2, %[dest]" : [dest] "=r" (Data) : :);
__asm__ __volatile__ ("mov %%cr2, %[dest]" : [dest] "=r"(Data) : :);
break;
case 3:
__asm__ __volatile__ ("mov %%cr3, %[dest]" : [dest] "=r" (Data) : :);
__asm__ __volatile__ ("mov %%cr3, %[dest]" : [dest] "=r"(Data) : :);
break;
case 4:
__asm__ __volatile__ ("mov %%cr4, %[dest]" : [dest] "=r" (Data) : :);
__asm__ __volatile__ ("mov %%cr4, %[dest]" : [dest] "=r"(Data) : :);
break;
case 8:
__asm__ __volatile__ ("mov %%cr8, %[dest]" : [dest] "=r" (Data) : :);
__asm__ __volatile__ ("mov %%cr8, %[dest]" : [dest] "=r"(Data) : :);
break;
case 'f':
__asm__ __volatile__ ("pushfq\n\t" "popq %[dest]" : [dest] "=r" (Data) : :);
__asm__ __volatile__ ("pushfq\n\t" "popq %[dest]" : [dest] "=r"(Data) : :);
break;
default:
SerialPrintf("invalid crx read %x\r\n",CRX);
SerialPrintf("invalid crx read %x\r\n", CRX);
Data = 0xdeadbeef;
break;
}
@ -153,27 +153,27 @@ size_t ReadControlRegister(int CRX) {
}
size_t WriteControlRegister(int CRX, size_t Data) {
switch(CRX) {
switch (CRX) {
case 0:
__asm__ __volatile__ ("movq %[dest], %%cr0" : : [dest] "r" (Data) : );
__asm__ __volatile__ ("movq %[dest], %%cr0" : : [dest] "r"(Data) : );
break;
case 1:
__asm__ __volatile__ ("movq %[dest], %%cr1" : : [dest] "r" (Data) : );
__asm__ __volatile__ ("movq %[dest], %%cr1" : : [dest] "r"(Data) : );
break;
case 2:
__asm__ __volatile__ ("movq %[dest], %%cr2" : : [dest] "r" (Data) : );
__asm__ __volatile__ ("movq %[dest], %%cr2" : : [dest] "r"(Data) : );
break;
case 3:
__asm__ __volatile__ ("movq %[dest], %%cr3" : : [dest] "r" (Data) : );
__asm__ __volatile__ ("movq %[dest], %%cr3" : : [dest] "r"(Data) : );
break;
case 4:
__asm__ __volatile__ ("movq %[dest], %%cr4" : : [dest] "r" (Data) : );
__asm__ __volatile__ ("movq %[dest], %%cr4" : : [dest] "r"(Data) : );
break;
case 8:
__asm__ __volatile__ ("movq %[dest], %%cr8" : : [dest] "r" (Data) : );
__asm__ __volatile__ ("movq %[dest], %%cr8" : : [dest] "r"(Data) : );
break;
case 'f':
__asm__ __volatile__ ("pushq %[dest]\n\t" "popfq" : : [dest] "r" (Data) : "cc");
__asm__ __volatile__ ("pushq %[dest]\n\t" "popfq" : : [dest] "r"(Data) : "cc");
break;
default:
break;
@ -192,8 +192,8 @@ size_t ReadExtendedControlRegister(size_t XCRX) {
//TODO: make this just have an assert as returning data for a write to catch
// errors that shoudlunt really happen doesent make alot of sense
size_t WriteExtendedControlRegister(size_t XCRX, size_t Data){
uint32_t DataLow = Data & 0x00000000ffffffff;
size_t WriteExtendedControlRegister(size_t XCRX, size_t Data) {
uint32_t DataLow = Data & 0x00000000ffffffff;
uint32_t DataHigh = (Data & 0xffffffff00000000) >> 32;
__asm__ __volatile__("xsetbv" : : "a" (DataLow), "c" (XCRX), "d" (DataHigh) :);
return Data;
@ -202,60 +202,60 @@ size_t WriteExtendedControlRegister(size_t XCRX, size_t Data){
size_t ReadXCS() {
size_t Data;
__asm__ __volatile__("mov %%cs, %[dest]" : [dest] "=r" (Data) : :);
__asm__ __volatile__("mov %%cs, %[dest]" : [dest] "=r"(Data) : :);
return Data;
}
DESC_TBL ReadGDT() {
DESC_TBL GDTData = {0};
DESC_TBL GDTData;
__asm__ __volatile__("sgdt %[dest]" : [dest] "=m" (GDTData) : :);
__asm__ __volatile__("sgdt %[dest]" : [dest] "=m"(GDTData) : :);
return GDTData;
}
void WriteGDT(DESC_TBL GDTData) {
__asm__ __volatile__("lgdt %[src]" : : [src] "m" (GDTData) :);
__asm__ __volatile__("lgdt %[src]" : : [src] "m"(GDTData) :);
}
DESC_TBL ReadIDT() {
DESC_TBL IDTData = {0};
DESC_TBL IDTData;
__asm__ __volatile__("sidt %[dest]" : [dest] "=m" (IDTData) : :);
__asm__ __volatile__("sidt %[dest]" : [dest] "=m"(IDTData) : :);
return IDTData;
}
void WriteIDT(DESC_TBL IDTData) {
__asm__ __volatile__("lidt %[src]" : : [src] "m" (IDTData) :);
__asm__ __volatile__("lidt %[src]" : : [src] "m"(IDTData) :);
}
uint16_t ReadLDT() {
uint16_t LDTData;
__asm__ __volatile__("sldt %[dest]" : [dest] "=m" (LDTData) : :);
__asm__ __volatile__("sldt %[dest]" : [dest] "=m"(LDTData) : :);
return LDTData;
}
void WriteLDT(uint16_t LDTData) {
__asm__ __volatile__("lldt %[src]" : : [src] "m" (LDTData) :);
__asm__ __volatile__("lldt %[src]" : : [src] "m"(LDTData) :);
}
uint16_t ReadTSR() {
uint16_t TSRData;
__asm__ __volatile__("str %[dest]" : [dest] "=m" (TSRData) : :);
__asm__ __volatile__("str %[dest]" : [dest] "=m"(TSRData) : :);
return TSRData;
}
void WriteTSR(uint16_t TSRData) {
__asm__ __volatile__("ltr %[src]" : : [src] "m" (TSRData) :);
__asm__ __volatile__("ltr %[src]" : : [src] "m"(TSRData) :);
}

View File

@ -41,12 +41,12 @@ int CheckSerial() {
}
void WriteSerialChar(const char chr) {
while(!(CheckSerial() & 0x20));
while (!(CheckSerial() & 0x20));
WritePort(COM1, chr, 1);
}
void WriteSerialString(const char* str, size_t len) {
for(size_t i = 0; i < len; i++) {
for (size_t i = 0; i < len; i++) {
WriteSerialChar(str[i]);
}
}

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");
@ -73,31 +75,33 @@ static void DrawChar(const char character, size_t x, size_t y) {
uint32_t Y = PrintInfo.charWidth >> 3, X = 0;
if((PrintInfo.charWidth & 0x7) != 0) {
if ((PrintInfo.charWidth & 0x7) != 0) {
Y++;
}
for(uint32_t Row = 0; Row < PrintInfo.charHeight; Row++) {
for(uint32_t Bit = 0; Bit < PrintInfo.charWidth; Bit++) {
if ( ((Bit & 0x7) == 0) && (Bit > 0)) {
for (uint32_t Row = 0; Row < PrintInfo.charHeight; Row++) {
for (uint32_t Bit = 0; Bit < PrintInfo.charWidth; Bit++) {
if (((Bit & 0x7) == 0) && (Bit > 0)) {
X++;
}
// This one is crazy. Stick with me.
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
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
(ScaleY * bootldr.fb_width + ScaleX) + // In X and Y
PrintInfo.charScale * 1 * PrintInfo.charWidth) - 10; // With some offset to start at 0
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
// Check the bit in the bitmap, if it's solid..
if((FONT[(int)character][Row * Y + X] >> (Bit & 0x7)) & 1) {
*(uint32_t* )(&fb + offset * 4) //use it to set the correct pixel on the screen
= PrintInfo.charFGColor; // In the set foreground color
if ((FONT[(int) character][Row * Y + X] >> (Bit & 0x7)) & 1) {
*(uint32_t*) (&fb + offset * 4) //use it to set the correct pixel on the screen
= PrintInfo.charFGColor; // In the set foreground color
} else { // otherwise,
*(uint32_t* )(&fb + offset * 4)
= PrintInfo.charBGColor; // set the background color.
*(uint32_t*) (&fb + offset * 4)
= PrintInfo.charBGColor; // set the background color.
}
}
}
@ -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;
for (uint32_t pixel = 0; pixel < bootldr.fb_width * bootldr.fb_height; pixel++) {
((uint32_t*) &fb)[pixel] = color;
}
SetForegroundColor(currentColor);
}
static void Newline() {
@ -123,10 +125,10 @@ static void Newline() {
}
static void ProgressCursorS(size_t Steps) {
if(PrintInfo.charPosX + Steps > PrintInfo.charsPerRow) {
if (PrintInfo.charPosX + Steps > PrintInfo.charsPerRow) {
PrintInfo.charPosX = 0;
size_t Rows = Steps / PrintInfo.charsPerRow;
if(PrintInfo.charPosY + Rows > PrintInfo.rowsPerScrn) {
if (PrintInfo.charPosY + Rows > PrintInfo.rowsPerScrn) {
size_t RowsLeft = PrintInfo.rowsPerScrn - PrintInfo.charPosY;
ProgressCursorS(RowsLeft + 1);
Newline();
@ -146,8 +148,8 @@ static void ProgressCursor() {
static void Backspace() {
SerialPrintf("Backspacing from %d to %d\r\n", PrintInfo.charPosX, PrintInfo.charPosX - 1);
if(PrintInfo.charPosX - 1 <= 0) {
if(PrintInfo.charPosY - 1 <= 0) {
if (PrintInfo.charPosX - 1 <= 0) {
if (PrintInfo.charPosY - 1 <= 0) {
PrintInfo.charPosY = 0;
} else {
PrintInfo.charPosY--;
@ -160,7 +162,7 @@ static void Backspace() {
void WriteChar(const char character) {
// TODO: Color codes!
switch(character) {
switch (character) {
case '\b':
Backspace();
DrawChar((char) 32, PrintInfo.charPosX, PrintInfo.charPosY);
@ -184,49 +186,50 @@ void WriteChar(const char character) {
}
void WriteString(const char* string) {
for(unsigned int i = 0; i < strlen(string); i++) {
for (unsigned int i = 0; i < strlen(string); i++) {
WriteChar(string[i]);
}
}
// ! Deprecated.
// TODO: Fix this to work with arbitrary length and offset.
void WriteStringWithFont(const char *inChar) {
psf_t *font = (psf_t*) &_binary_src_assets_font_psf_start;
void WriteStringWithFont(const char* inChar) {
psf_t* font = (psf_t*) &_binary_src_assets_font_psf_start;
unsigned int drawX, drawY, kx = 0, fontLine, bitMask, offset;
const unsigned int bytesPerLine = ( font -> glyphWidth + 7 ) / 8;
const unsigned int bytesPerLine = (font->glyphWidth + 7) / 8;
while(*inChar) {
unsigned char *glyph =
(unsigned char*) &_binary_src_assets_font_psf_start
+ font->headerSize
+ (*inChar > 0 && *inChar < (int)font->numGlyphs ? *inChar : 0) *
font->glyphSize;
while (*inChar) {
unsigned char* glyph =
(unsigned char*) &_binary_src_assets_font_psf_start
+ font->headerSize
+ (*inChar > 0 && *inChar < (int) font->numGlyphs ? *inChar : 0) *
font->glyphSize;
offset = (kx * (font->glyphWidth + 1) * 4);
for( drawY = 0; drawY < font->glyphHeight ; drawY++) {
for (drawY = 0; drawY < font->glyphHeight; drawY++) {
fontLine = offset;
bitMask = 1 << (font->glyphWidth - 1);
for( drawX = 0; drawX < font->glyphWidth; drawX++) {
for (drawX = 0; drawX < font->glyphWidth; drawX++) {
*((uint32_t*)((uint64_t) &fb + fontLine)) =
((int) *glyph) & (bitMask) ? 0xFFFFFF : 0;
*((uint32_t*) ((uint64_t) &fb + fontLine)) =
((int) *glyph) & (bitMask) ? 0xFFFFFF : 0;
bitMask >>= 1;
fontLine += 4;
}
*((uint32_t*)((uint64_t) &fb + fontLine)) = 0;
*((uint32_t*) ((uint64_t) &fb + fontLine)) = 0;
glyph += bytesPerLine;
offset += bootldr.fb_scanline;
}
inChar++; kx++;
inChar++;
kx++;
}
}
@ -276,14 +279,14 @@ void DrawLineInternal(size_t x0, size_t y0, size_t x1, size_t y1) {
for (; x0 <= x1; x0++) {
if (steep)
DrawPixel(y0, x0);
DrawPixel(y0, x0);
else
DrawPixel(x0, y0);
DrawPixel(x0, y0);
err -= dy;
if (err < 0) {
y0 += ystep;
err += dx;
y0 += ystep;
err += dx;
}
}
}
@ -384,7 +387,7 @@ void DrawLine(size_t x0, size_t y0, size_t x1, size_t y1) {
DrawVerticalLine(x0, y0, y1 - y0 + 1);
} else if (y0 == y1) {
if (x0 > x1)
_swap_size_t(x0, x1);
_swap_size_t(x0, x1);
DrawHorizontalLine(x0, y0, x1 - x0 + 1);
} else {
@ -449,22 +452,22 @@ void DrawLineCircleCorners(size_t centerX, size_t centerY, size_t radius, char c
ddF_x += 2;
f += ddF_x;
if(cornerMask & 0x4) {
if (cornerMask & 0x4) {
DrawPixel(centerX + x, centerY + y);
DrawPixel(centerX + y, centerY + x);
}
if(cornerMask & 0x2) {
if (cornerMask & 0x2) {
DrawPixel(centerX + x, centerY - y);
DrawPixel(centerX - y, centerY - x);
}
if(cornerMask & 0x8) {
if (cornerMask & 0x8) {
DrawPixel(centerX - y, centerY + x);
DrawPixel(centerX - x, centerY + y);
}
if(cornerMask & 0x1) {
if (cornerMask & 0x1) {
DrawPixel(centerX - y, centerY - x);
DrawPixel(centerX - x, centerY - y);
}

View File

@ -28,7 +28,7 @@ void NumToStr(char* Buffer, size_t Num, size_t Base) {
Buffer[i--] = 0;
for(j = 0; j < i; j++, i--) {
for (j = 0; j < i; j++, i--) {
Temp = Buffer[j];
Buffer[j] = Buffer[i];
Buffer[i] = Temp;
@ -45,15 +45,19 @@ int SerialPrintf(const char* Format, ...) {
char BufferStr[512] = {0};
while(*Format != '\0') {
while (*Format != '\0') {
size_t Limit = UINT64_MAX - CharsWritten;
if(*Format == '%') {
if(*(++Format) == '%')
if (*Format == '%') {
if (*(++Format) == '%')
Format++;
switch(*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);
@ -87,7 +88,7 @@ int SerialPrintf(const char* Format, ...) {
Base = 0;
if(*Format == 'd' || *Format == 'u') {
if (*Format == 'd' || *Format == 'u') {
Base = 10; // Decimal & Unsigned are base 10
} else {
Base = 16; // Hex and Ptr are base 16
@ -102,7 +103,7 @@ int SerialPrintf(const char* Format, ...) {
CharsWritten += Len;
break;
}
//case 'p':
//case 'p':
//uint8_t Base = 16;
//size_t Dest = (uintptr_t) va_arg(Parameters, void*);
default:
@ -132,14 +133,14 @@ int Printf(const char* Format, ...) {
char BufferStr[512] = {0};
while(*Format != '\0') {
while (*Format != '\0') {
size_t Limit = UINT64_MAX - CharsWritten;
if(*Format == '%') {
if(*(++Format) == '%')
if (*Format == '%') {
if (*(++Format) == '%')
Format++;
switch(*Format) {
switch (*Format) {
case 'c': {
Format++;
@ -156,7 +157,7 @@ int Printf(const char* Format, ...) {
size_t Len = strlen(Str);
if(Limit < Len)
if (Limit < Len)
return -1;
WriteString(Str);
@ -173,7 +174,7 @@ int Printf(const char* Format, ...) {
Base = 0;
if(*Format == 'd' || *Format == 'u') {
if (*Format == 'd' || *Format == 'u') {
Base = 10; // Decimal & Unsigned are base 10
} else {
Base = 16; // Hex and Ptr are base 16
@ -188,7 +189,7 @@ int Printf(const char* Format, ...) {
CharsWritten += Len;
break;
}
//case 'p':
//case 'p':
//uint8_t Base = 16;
//size_t Dest = (uintptr_t) va_arg(Parameters, void*);
default:
@ -196,17 +197,17 @@ int Printf(const char* Format, ...) {
break;
}
} else if(*Format == '\\') {
} else if (*Format == '\\') {
Format++; // Skip backslash
switch(*Format) {
switch (*Format) {
case '$': {
// COLOR
Format ++; // Skip $
Format++; // Skip $
size_t Color = 0;
bool bgFlag = false;
switch(*Format) {
switch (*Format) {
case '[':
// bg
bgFlag = true;
@ -215,24 +216,24 @@ int Printf(const char* Format, ...) {
// fg
Format++; // [ or {
if(*Format == '<') {
if (*Format == '<') {
Format++;
Color = ParseEnglishColor((char*) Format);
} else {
Color = ParseHexColor(Format, bgFlag);
}
if(bgFlag)
if (bgFlag)
SetBackgroundColor(Color);
else
SetForegroundColor(Color);
while(*Format != '}')
while (*Format != '}')
Format++;
Format++; // }
break;
}
break;
}
case 'f':
@ -251,23 +252,23 @@ int Printf(const char* Format, ...) {
size_t ParseEnglishColor(char* Stream) {
if(strcmp(Stream, "red"))
if (strcmp(Stream, "red"))
return 0xFF0000;
if(strcmp(Stream, "green"))
if (strcmp(Stream, "green"))
return 0xFF00;
if(strcmp(Stream, "blue"))
if (strcmp(Stream, "blue"))
return 0xFF;
if(strcmp(Stream, "yellow"))
if (strcmp(Stream, "yellow"))
return 0xFFFF00;
if(strcmp(Stream, "cyan"))
if (strcmp(Stream, "cyan"))
return 0xFFFF;
if(strcmp(Stream, "magenta"))
if (strcmp(Stream, "magenta"))
return 0xFF00FF;
if(strcmp(Stream, "beans"))
if (strcmp(Stream, "beans"))
return 0xAA11CC;
if(strcmp(Stream, "forgeb"))
if (strcmp(Stream, "forgeb"))
return 0x1E2D42;
if(strcmp(Stream, "forgey"))
if (strcmp(Stream, "forgey"))
return 0xE0A969;
return 0xFFFFFF;
}