diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d7d909..181d9cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/Testing/Temporary/LastTest.log b/Testing/Temporary/LastTest.log new file mode 100644 index 0000000..5011435 --- /dev/null +++ b/Testing/Temporary/LastTest.log @@ -0,0 +1,3 @@ +Start testing: Feb 17 01:48 GMT Standard Time +---------------------------------------------------------- +End testing: Feb 17 01:48 GMT Standard Time diff --git a/chroma.iso b/chroma.iso new file mode 100644 index 0000000..dc69030 Binary files /dev/null and b/chroma.iso differ diff --git a/img/boot/exe b/img/boot/exe index 9cd0f5b..3cf6c84 100644 Binary files a/img/boot/exe and b/img/boot/exe differ diff --git a/inc/driver/generic/device.h b/inc/driver/generic/device.h index 7e112bf..a48bfa9 100644 --- a/inc/driver/generic/device.h +++ b/inc/driver/generic/device.h @@ -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); diff --git a/inc/driver/io/apic.h b/inc/driver/io/apic.h new file mode 100644 index 0000000..c357e61 --- /dev/null +++ b/inc/driver/io/apic.h @@ -0,0 +1,115 @@ +#pragma once +#include +#include + +/************************ + *** 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); + + }; +}; \ No newline at end of file diff --git a/inc/kernel/boot/boot.h b/inc/kernel/boot/boot.h index 00731fa..d4d79fe 100644 --- a/inc/kernel/boot/boot.h +++ b/inc/kernel/boot/boot.h @@ -4,6 +4,8 @@ *** Chroma *** ***********************/ +#include + #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 */ diff --git a/inc/kernel/chroma.h b/inc/kernel/chroma.h index 39d8417..5426d47 100644 --- a/inc/kernel/chroma.h +++ b/inc/kernel/chroma.h @@ -24,7 +24,10 @@ extern "C" { #include #include #include -#include + +#ifdef __cplusplus + #include +#endif #include #include diff --git a/inc/kernel/constants.hpp b/inc/kernel/constants.hpp new file mode 100644 index 0000000..b6a7086 --- /dev/null +++ b/inc/kernel/constants.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +/************************ + *** Team Kitty, 2021 *** + *** Chroma *** + ***********************/ + +namespace Constants { + namespace Core { + const size_t STACK_SIZE = 65536; + const size_t MAX_CORES = 12; + } +} \ No newline at end of file diff --git a/inc/kernel/system/acpi/madt.h b/inc/kernel/system/acpi/madt.h new file mode 100644 index 0000000..82cd7f9 --- /dev/null +++ b/inc/kernel/system/acpi/madt.h @@ -0,0 +1,104 @@ +#pragma once +#include +#include + +/************************ + *** 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(); + + }; +} \ No newline at end of file diff --git a/inc/kernel/system/acpi/rsdt.h b/inc/kernel/system/acpi/rsdt.h new file mode 100644 index 0000000..a4cc61e --- /dev/null +++ b/inc/kernel/system/acpi/rsdt.h @@ -0,0 +1,77 @@ +#pragma once +#include +#include + +/************************ + *** 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; + }; +} \ No newline at end of file diff --git a/inc/kernel/system/core.hpp b/inc/kernel/system/core.hpp new file mode 100644 index 0000000..b079fc7 --- /dev/null +++ b/inc/kernel/system/core.hpp @@ -0,0 +1,80 @@ +#pragma once + +#include +#include +#include +#include +#include + +/************************ + *** 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)); diff --git a/inc/kernel/system/descriptors.h b/inc/kernel/system/descriptors.h index 7d41c43..0e7f9ed 100644 --- a/inc/kernel/system/descriptors.h +++ b/inc/kernel/system/descriptors.h @@ -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 \ No newline at end of file diff --git a/inc/kernel/system/interrupts.h b/inc/kernel/system/interrupts.h index 43f5ea7..7e7c0e4 100644 --- a/inc/kernel/system/interrupts.h +++ b/inc/kernel/system/interrupts.h @@ -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(); diff --git a/inc/kernel/system/memory.h b/inc/kernel/system/memory.h index d94a630..fb6eba7 100644 --- a/inc/kernel/system/memory.h +++ b/inc/kernel/system/memory.h @@ -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 diff --git a/inc/kernel/system/pci.h b/inc/kernel/system/pci.h index 0942c55..1260618 100644 --- a/inc/kernel/system/pci.h +++ b/inc/kernel/system/pci.h @@ -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 diff --git a/inc/kernel/system/process/process.h b/inc/kernel/system/process/process.h index 6552989..12c7521 100644 --- a/inc/kernel/system/process/process.h +++ b/inc/kernel/system/process/process.h @@ -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"); } }; \ No newline at end of file diff --git a/inc/kernel/system/stack.h b/inc/kernel/system/stack.h deleted file mode 100644 index 2fb393e..0000000 --- a/inc/kernel/system/stack.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -/************************ - *** Team Kitty, 2020 *** - *** Chroma *** - ***********************/ - -typedef struct stackframe { - struct stackframe* rbp; - size_t rip; -} stackframe_t; - -void StackTrace(size_t cycles); - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/inc/kernel/video/draw.h b/inc/kernel/video/draw.h index ae386bd..1ffc1ff 100644 --- a/inc/kernel/video/draw.h +++ b/inc/kernel/video/draw.h @@ -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(); diff --git a/src/drivers/devices/devices.cpp b/src/drivers/devices/devices.cpp index 956e4b8..b19b0c2 100644 --- a/src/drivers/devices/devices.cpp +++ b/src/drivers/devices/devices.cpp @@ -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 // 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(DevicesArray[i]); SerialPrintf("[DEVICE] Warning: Unable to find a %s device.\r\n", DeviceNames[T::GetRootType()]); diff --git a/src/drivers/keyboard.c b/src/drivers/devices/input/keyboard.cpp similarity index 55% rename from src/drivers/keyboard.c rename to src/drivers/devices/input/keyboard.cpp index d4e09c2..35633e2 100644 --- a/src/drivers/keyboard.c +++ b/src/drivers/devices/input/keyboard.cpp @@ -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(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 diff --git a/src/drivers/devices/io/apic.cpp b/src/drivers/devices/io/apic.cpp new file mode 100644 index 0000000..203f3a1 --- /dev/null +++ b/src/drivers/devices/io/apic.cpp @@ -0,0 +1,139 @@ +#include +#include +#include +#include + +/************************ + *** 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 + +} \ No newline at end of file diff --git a/src/drivers/elf.c b/src/drivers/elf.cpp similarity index 58% rename from src/drivers/elf.c rename to src/drivers/elf.cpp index 5aff89b..1578363 100644 --- a/src/drivers/elf.c +++ b/src/drivers/elf.cpp @@ -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))); } } } diff --git a/src/editor/EditorMain.cpp b/src/editor/EditorMain.cpp index 715f0c1..9497577 100644 --- a/src/editor/EditorMain.cpp +++ b/src/editor/EditorMain.cpp @@ -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); diff --git a/src/global/core.s b/src/global/core.s new file mode 100644 index 0000000..8875ddd --- /dev/null +++ b/src/global/core.s @@ -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: \ No newline at end of file diff --git a/src/kernel.cpp b/src/kernel.cpp index 0d393e6..34d74be 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -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); } \ No newline at end of file diff --git a/src/lainlib/list/basic_list.c b/src/lainlib/list/basic_list.cpp similarity index 82% rename from src/lainlib/list/basic_list.c rename to src/lainlib/list/basic_list.cpp index 5d13657..2d473af 100644 --- a/src/lainlib/list/basic_list.c +++ b/src/lainlib/list/basic_list.cpp @@ -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((void*) 0xDEADull); + Entry->Next = static_cast((void*) 0xBEEFull); } bool ListIsEmpty(list_entry_t* Head) { diff --git a/src/lainlib/mutex/ticketlock.c b/src/lainlib/mutex/ticketlock.cpp similarity index 100% rename from src/lainlib/mutex/ticketlock.c rename to src/lainlib/mutex/ticketlock.cpp diff --git a/src/lainlib/string/str.c b/src/lainlib/string/str.cpp similarity index 100% rename from src/lainlib/string/str.c rename to src/lainlib/string/str.cpp diff --git a/src/system/acpi/MADT.cpp b/src/system/acpi/MADT.cpp new file mode 100644 index 0000000..2955a61 --- /dev/null +++ b/src/system/acpi/MADT.cpp @@ -0,0 +1,74 @@ +#include +#include + +/************************ + *** 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(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(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(table); + entries[count] = (MADT::ISOEntry*) ((size_t) io_apic); + count++; + } + } + + entries[count] = 0; + return entries; +} + +MADT::RecordTableEntry* MADT::GetTableEntries() { + return Header->Table; +} \ No newline at end of file diff --git a/src/system/acpi/RSDP.cpp b/src/system/acpi/RSDP.cpp new file mode 100644 index 0000000..1fbf3d5 --- /dev/null +++ b/src/system/acpi/RSDP.cpp @@ -0,0 +1,87 @@ +#include +#include + +/************************ + *** 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(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(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(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(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. +} + diff --git a/src/system/core.cpp b/src/system/core.cpp new file mode 100644 index 0000000..1bf03ee --- /dev/null +++ b/src/system/core.cpp @@ -0,0 +1,134 @@ +#include +#include +#include + +/************************ + *** 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(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"); +} diff --git a/src/system/cpu.c b/src/system/cpu.cpp similarity index 81% rename from src/system/cpu.c rename to src/system/cpu.cpp index 23c5513..afd0de9 100644 --- a/src/system/cpu.c +++ b/src/system/cpu.cpp @@ -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); } } diff --git a/src/system/interrupts.c b/src/system/interrupts.c deleted file mode 100644 index 6701ed6..0000000 --- a/src/system/interrupts.c +++ /dev/null @@ -1,468 +0,0 @@ -#include -#include -#include -#include - -/************************ - *** 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 \ No newline at end of file diff --git a/src/system/interrupts.cpp b/src/system/interrupts.cpp new file mode 100644 index 0000000..126fe3c --- /dev/null +++ b/src/system/interrupts.cpp @@ -0,0 +1,515 @@ +#include +#include +#include +#include + +/************************ + *** 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 \ No newline at end of file diff --git a/src/system/memory/abstract_allocator.c b/src/system/memory/abstract_allocator.cpp similarity index 85% rename from src/system/memory/abstract_allocator.c rename to src/system/memory/abstract_allocator.cpp index bc641ae..9dd02a2 100644 --- a/src/system/memory/abstract_allocator.c +++ b/src/system/memory/abstract_allocator.cpp @@ -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); } diff --git a/src/system/memory/liballoc.c b/src/system/memory/liballoc.c deleted file mode 100644 index c626771..0000000 --- a/src/system/memory/liballoc.c +++ /dev/null @@ -1,867 +0,0 @@ -#include -#include - -/** 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 -#include - -#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 \ No newline at end of file diff --git a/src/system/memory/liballoc.cpp b/src/system/memory/liballoc.cpp new file mode 100644 index 0000000..d5cb361 --- /dev/null +++ b/src/system/memory/liballoc.cpp @@ -0,0 +1,827 @@ +#include +#include + +/** 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 +#include + +#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); +} \ No newline at end of file diff --git a/src/system/memory/paging.c b/src/system/memory/paging.cpp similarity index 84% rename from src/system/memory/paging.c rename to src/system/memory/paging.cpp index 4883942..031d17e 100644 --- a/src/system/memory/paging.c +++ b/src/system/memory/paging.cpp @@ -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); } diff --git a/src/system/memory/physmem.c b/src/system/memory/physmem.c index ef673aa..27e1dea 100644 --- a/src/system/memory/physmem.c +++ b/src/system/memory/physmem.c @@ -1,6 +1,7 @@ #include #include + /************************ *** 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; diff --git a/src/system/memory/stack.c b/src/system/memory/stack.c deleted file mode 100644 index 12e4365..0000000 --- a/src/system/memory/stack.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -/************************ - *** 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 \ No newline at end of file diff --git a/src/system/pci.c b/src/system/pci.c deleted file mode 100644 index 4a40a60..0000000 --- a/src/system/pci.c +++ /dev/null @@ -1,531 +0,0 @@ -#include - -/************************ - *** 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 \ No newline at end of file diff --git a/src/system/pci.cpp b/src/system/pci.cpp new file mode 100644 index 0000000..f579f80 --- /dev/null +++ b/src/system/pci.cpp @@ -0,0 +1,757 @@ +#include + +/************************ + *** 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 \ No newline at end of file diff --git a/src/system/process/process.cpp b/src/system/process/process.cpp new file mode 100644 index 0000000..19f92ea --- /dev/null +++ b/src/system/process/process.cpp @@ -0,0 +1,27 @@ +#include +#include + +/************************ + *** 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; + diff --git a/src/system/rw.c b/src/system/rw.cpp similarity index 62% rename from src/system/rw.c rename to src/system/rw.cpp index 18c6d35..74ca152 100644 --- a/src/system/rw.c +++ b/src/system/rw.cpp @@ -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) :); } diff --git a/src/system/serial.c b/src/system/serial.cpp similarity index 94% rename from src/system/serial.c rename to src/system/serial.cpp index 3ed2cdb..5c73fba 100644 --- a/src/system/serial.c +++ b/src/system/serial.cpp @@ -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]); } } diff --git a/src/video/draw.c b/src/video/draw.cpp similarity index 78% rename from src/video/draw.c rename to src/video/draw.cpp index 39f0fe7..d7c17ea 100644 --- a/src/video/draw.c +++ b/src/video/draw.cpp @@ -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); } diff --git a/src/video/print.cpp b/src/video/print.cpp index 1cb22d8..b85f81a 100644 --- a/src/video/print.cpp +++ b/src/video/print.cpp @@ -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; }