Large rewrites & struggles
This commit is contained in:
parent
06134ebcd9
commit
acda33948e
|
@ -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)
|
||||
|
|
3
Testing/Temporary/LastTest.log
Normal file
3
Testing/Temporary/LastTest.log
Normal file
|
@ -0,0 +1,3 @@
|
|||
Start testing: Feb 17 01:48 GMT Standard Time
|
||||
----------------------------------------------------------
|
||||
End testing: Feb 17 01:48 GMT Standard Time
|
BIN
chroma.iso
Normal file
BIN
chroma.iso
Normal file
Binary file not shown.
BIN
img/boot/exe
BIN
img/boot/exe
Binary file not shown.
|
@ -15,10 +15,11 @@ namespace Device {
|
|||
|
||||
// The internal typemap of devices used in Chroma.
|
||||
enum DeviceType : uint32_t {
|
||||
STORAGE = 0,
|
||||
KEYBOARD = 1,
|
||||
NETWORK = 2,
|
||||
UNKNOWN = 0xFFFFFFFF
|
||||
STORAGE = 0, // Stores data.
|
||||
INTERNAL = 1, // PCI, APIC, AHCI.
|
||||
INTERFACE = 2, // Peripherals and I/O
|
||||
NETWORK = 3, // NIC.
|
||||
UNKNOWN = 0xFFFFFFFF // Unsupported.
|
||||
};
|
||||
|
||||
// The base class that all devices extend from.
|
||||
|
@ -81,6 +82,35 @@ namespace Device {
|
|||
|
||||
};
|
||||
|
||||
// The base class for every device that uses port or MMIO to communicate.
|
||||
class IODevice : public GenericDevice {
|
||||
public:
|
||||
|
||||
// Pre-use setup.
|
||||
virtual void Init() = 0;
|
||||
|
||||
// This is an internal register device.
|
||||
DeviceType GetType() const final {
|
||||
return DeviceType::INTERNAL;
|
||||
}
|
||||
|
||||
// Provided for utility checks.
|
||||
static DeviceType GetRootType() {
|
||||
return DeviceType::INTERNAL;
|
||||
}
|
||||
|
||||
// Read data from a given port.
|
||||
virtual uint32_t ReadRegister(uint32_t Register) = 0;
|
||||
// Write data into a given port.
|
||||
virtual void WriteRegister(uint32_t Register, uint32_t Data) = 0;
|
||||
|
||||
// Read data from the given address.
|
||||
virtual uint32_t ReadIO(size_t Base, uint32_t Register) = 0;
|
||||
// Write data into the given address.
|
||||
virtual void WriteIO(size_t Base, uint32_t Register, uint32_t Data) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
// Add a device pointer to the managed list.
|
||||
void RegisterDevice(GenericDevice* Dev);
|
||||
|
|
115
inc/driver/io/apic.h
Normal file
115
inc/driver/io/apic.h
Normal file
|
@ -0,0 +1,115 @@
|
|||
#pragma once
|
||||
#include <driver/generic/device.h>
|
||||
#include <kernel/system/acpi/madt.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2021 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
namespace Device {
|
||||
|
||||
/**
|
||||
* Contains the driver definition for the Advanced Programmable Interrupt Controller - APIC.
|
||||
* Each processor core contains at least one APIC, and they have a unique identifier,
|
||||
* so they can be used to identify cores along with producing timed interrupts.
|
||||
*
|
||||
* However, this is only possible because this driver is loaded once per system.
|
||||
* This is a singleton class.
|
||||
*
|
||||
* The primary functionality of the APIC is to send an interrupt to the given core after the specified time is up.
|
||||
*/
|
||||
|
||||
class APIC : public IODevice {
|
||||
private:
|
||||
// Metadata of IOAPICs.
|
||||
struct IOAPICMeta {
|
||||
uint8_t Version;
|
||||
uint8_t Reserved;
|
||||
uint8_t MaxRedirect;
|
||||
uint8_t Reserved2;
|
||||
};
|
||||
|
||||
// The address in physical memory that refers to this device.
|
||||
void* Address;
|
||||
// Whether this APIC driver is ready for processing.
|
||||
bool Ready = false;
|
||||
|
||||
ACPI::MADT::IOAPICEntry** IOAPICs;
|
||||
ACPI::MADT::ISOEntry** ISOs;
|
||||
IOAPICMeta* Meta;
|
||||
|
||||
// The internal implementation of Set. Handles raw redirects at the hardware level.
|
||||
void SetInternal(uint8_t Vector, uint32_t TargetGSI, uint16_t Flags, int Core, int Status);
|
||||
|
||||
public:
|
||||
|
||||
APIC();
|
||||
|
||||
// The register locations of the APIC device.
|
||||
enum Registers {
|
||||
LAPIC_ID = 0x20, // ID of the APIC
|
||||
EOI = 0xB0, // Acknowledge
|
||||
SIVR = 0xF0, // Spurious Interrupt Vector Register
|
||||
ICR1 = 0x300, // Interrupt Command Register Lower
|
||||
ICR2 = 0x310, // Interrupt Command Register Higher
|
||||
LVT = 0x320, // Local Vector Table
|
||||
LINT1 = 0x350, // Local Interrupt ID
|
||||
LINT2 = 0x360, // Local Interrupt ID
|
||||
TIMER_DIVISOR = 0x3E0, // Frequency divisor for the timer.
|
||||
TIMER_INIT = 0x380, // Initializer for the timer.
|
||||
TIMER_CURRENT = 0x390, // Current "tick count" of the timer.
|
||||
};
|
||||
|
||||
// The instance of this singleton class.
|
||||
static APIC* driver;
|
||||
|
||||
const char* GetName() const override {
|
||||
return "APIC";
|
||||
}
|
||||
|
||||
// Dump all available information to the log (or to stdout eventually)
|
||||
void LogDump();
|
||||
|
||||
// Move all structs and internal handlers to a new address.
|
||||
void Move(size_t NewAddress);
|
||||
|
||||
// Prepare the APICs for use.
|
||||
void Init() override;
|
||||
// Load all data the APICs need.
|
||||
void LoadInterruptSystem();
|
||||
// Set the APICs ready for use.
|
||||
void Enable();
|
||||
// Check whether the APICs are ready for use.
|
||||
bool IsReady();
|
||||
|
||||
// Prepare a core for use with interrupts.
|
||||
void PreinitializeCore(int Core);
|
||||
// Set a core as available to use interrupts.
|
||||
void InitializeCore(int Core, size_t EntryPoint);
|
||||
|
||||
// Check what core ID is currently running.
|
||||
int GetCurrentCore();
|
||||
|
||||
uint32_t ReadRegister(uint32_t Register) override;
|
||||
void WriteRegister(uint32_t Register, uint32_t Data) override;
|
||||
|
||||
uint32_t ReadIO(size_t Base, uint32_t Register) override;
|
||||
void WriteIO(size_t Base, uint32_t Register, uint32_t Data) override;
|
||||
|
||||
// Send a specified interrupt to another core.
|
||||
void SendInterCoreInterrupt(int Core, uint32_t Interrupt);
|
||||
// Tell the APIC that the interrupt is acknowledged. EOI = End Of Interrupt.
|
||||
void SendEOI();
|
||||
|
||||
// Tell the APIC that the specified IRQ should come to this core.
|
||||
void Set(int Core, uint8_t IRQ, int status);
|
||||
|
||||
// Write data into an inter-core interrupt.
|
||||
void WriteICI(size_t Data);
|
||||
|
||||
// Check what the maximum allowed interrupt redirect is.
|
||||
uint32_t GetMaxRedirect(uint32_t APIC);
|
||||
|
||||
};
|
||||
};
|
|
@ -4,6 +4,8 @@
|
|||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -11,8 +13,10 @@ extern "C" {
|
|||
/*
|
||||
;* Memory map
|
||||
;* 0h - 600h reserved for the system
|
||||
* V----------- CAN REMOVE -----------V
|
||||
;* 600h - 800h stage1 (MBR/VBR, boot.bin)
|
||||
;* 800h - 6C00h stage2 (this)
|
||||
* ∧----------- CAN REMOVE -----------∧
|
||||
;* 6C00h - 7C00h stack (7000h - 700Fh SMP trampoline code)
|
||||
;* 8000h - 9000h bootboot structure
|
||||
;* 9000h - A000h environment
|
||||
|
@ -111,7 +115,7 @@ typedef struct {
|
|||
uint8_t protocol; /* 1, static addresses, see PROTOCOL_* and LOADER_* above */
|
||||
uint8_t fb_type; /* framebuffer type, see FB_* above */
|
||||
uint16_t numcores; /* number of processor cores */
|
||||
uint16_t bspid; /* Bootsrap processor ID (Local APIC Id on x86_64) */
|
||||
uint16_t bspid; /* Bootstrap processor ID (Local APIC Id on x86_64) */
|
||||
int16_t timezone; /* in minutes -1440..1440 */
|
||||
uint8_t datetime[8]; /* in BCD yyyymmddhhiiss UTC (independent to timezone) */
|
||||
uint64_t initrd_ptr; /* ramdisk image position and size */
|
||||
|
|
|
@ -24,7 +24,10 @@ extern "C" {
|
|||
#include <kernel/system/io.h>
|
||||
#include <kernel/system/memory.h>
|
||||
#include <kernel/system/pci.h>
|
||||
#include <kernel/system/stack.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <kernel/system/core.hpp>
|
||||
#endif
|
||||
|
||||
#include <lainlib/lainlib.h>
|
||||
#include <lainlib/ethernet/e1000/e1000.h>
|
||||
|
|
15
inc/kernel/constants.hpp
Normal file
15
inc/kernel/constants.hpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2021 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
namespace Constants {
|
||||
namespace Core {
|
||||
const size_t STACK_SIZE = 65536;
|
||||
const size_t MAX_CORES = 12;
|
||||
}
|
||||
}
|
104
inc/kernel/system/acpi/madt.h
Normal file
104
inc/kernel/system/acpi/madt.h
Normal file
|
@ -0,0 +1,104 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <kernel/system/acpi/rsdt.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2021 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
namespace ACPI {
|
||||
|
||||
// Multiple APIC Descriptor Table. Enumerates every available APIC.
|
||||
class MADT {
|
||||
private:
|
||||
void* Address = 0;
|
||||
|
||||
public:
|
||||
|
||||
// The type of a table entry.
|
||||
enum Type {
|
||||
LAPIC = 0,
|
||||
IOAPIC = 1,
|
||||
ISO = 2,
|
||||
NMI = 4,
|
||||
LAPIC_OVERRIDE = 5
|
||||
};
|
||||
|
||||
// The header to a MADT Table Entry.
|
||||
struct RecordTableEntry {
|
||||
uint8_t Type; // The Type Enum value that represents this entry.
|
||||
uint8_t Length; // The length in bytes of this entry.
|
||||
} __attribute__((packed));
|
||||
|
||||
// The data of a Local APIC table Entry.
|
||||
struct LAPICEntry {
|
||||
RecordTableEntry Header;
|
||||
uint8_t Core; // The Core ID where the Local APIC is stored
|
||||
uint8_t APIC; // The ID of the APIC for the above Core ID.
|
||||
uint32_t Flags; // Capability flags for the APIC.
|
||||
} __attribute__((packed));
|
||||
|
||||
// The data of an IO (global) APIC table entry.
|
||||
struct IOAPICEntry {
|
||||
RecordTableEntry Header;
|
||||
uint8_t APIC; // The ID of the global APIC.
|
||||
uint8_t Unused;
|
||||
uint32_t Address; // The Base address of the MMIO port of the APIC.
|
||||
uint32_t GSI; // Global System Interrupt number.
|
||||
} __attribute__((packed));
|
||||
|
||||
// The data of an Interrupt Source Override entry - allows interrupt redirection.
|
||||
struct ISOEntry {
|
||||
RecordTableEntry Header;
|
||||
uint8_t Bus;
|
||||
uint8_t IRQ;
|
||||
uint32_t Interrupt;
|
||||
uint16_t Flags;
|
||||
} __attribute__((packed));
|
||||
|
||||
// The data of a Non-Maskable Interrupt source entry.
|
||||
struct NMIEntry {
|
||||
RecordTableEntry Header;
|
||||
uint8_t Core;
|
||||
uint16_t Flags;
|
||||
uint8_t LocalInterrupt;
|
||||
} __attribute__((packed));
|
||||
|
||||
// The data of a Local APIC Override Entry.
|
||||
struct LocalOverrideEntry {
|
||||
RecordTableEntry Header;
|
||||
uint8_t Reserved;
|
||||
size_t Address; // The 64 bit address of the Local APIC.
|
||||
} __attribute__((packed));
|
||||
|
||||
struct MADTHeader {
|
||||
ACPIHeader Header;
|
||||
uint32_t LocalAPIC;
|
||||
uint32_t Flags;
|
||||
RecordTableEntry Table[];
|
||||
} __attribute__((packed));
|
||||
|
||||
/***************************************
|
||||
***************************************
|
||||
***************************************/
|
||||
|
||||
static MADT* instance;
|
||||
MADTHeader* Header = 0;
|
||||
size_t LocalAPICBase = 0;
|
||||
|
||||
MADT();
|
||||
|
||||
void LogDump();
|
||||
void Initialize();
|
||||
// Get the byte of the end of the table.
|
||||
size_t GetEndOfTable();
|
||||
// Get all of the entries in the table, as an array.
|
||||
RecordTableEntry* GetTableEntries();
|
||||
// Get an array of pointers to IOAPIC entries. Should only be one.
|
||||
IOAPICEntry** GetIOApicEntries();
|
||||
// Get an array of pointers to ISO entries.
|
||||
ISOEntry** GetISOEntries();
|
||||
|
||||
};
|
||||
}
|
77
inc/kernel/system/acpi/rsdt.h
Normal file
77
inc/kernel/system/acpi/rsdt.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2021 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
namespace ACPI {
|
||||
|
||||
// The header of all System Descriptor Tables in the ACPI system.
|
||||
struct ACPIHeader {
|
||||
char Signature[4];
|
||||
uint32_t Length;
|
||||
uint8_t Revision;
|
||||
uint8_t Checksum;
|
||||
char OEMID[6];
|
||||
char OEMTableID[8];
|
||||
uint32_t OEMRevision;
|
||||
uint32_t CreatorID;
|
||||
uint32_t CreatorRevision;
|
||||
} __attribute__((packed));
|
||||
|
||||
// Root System Description Pointer table container.
|
||||
class RSDP {
|
||||
public:
|
||||
|
||||
// Header of RSDP Version 1 entries.
|
||||
struct DescriptorV1 {
|
||||
char Signature[8];
|
||||
uint8_t Checksum;
|
||||
char OEM[6];
|
||||
uint8_t Revision;
|
||||
uint32_t RSDT;
|
||||
} __attribute__((packed));
|
||||
|
||||
// Header of RSDP Version 2 entries.
|
||||
struct DescriptorV2 {
|
||||
DescriptorV1 Header;
|
||||
uint32_t Length;
|
||||
size_t XSDT;
|
||||
uint8_t Checksum;
|
||||
uint8_t Reserved[3];
|
||||
} __attribute__((packed));
|
||||
|
||||
// RSDP Entries themselves.
|
||||
struct RSDT {
|
||||
ACPIHeader Header;
|
||||
uint32_t* OtherSDTs;
|
||||
} __attribute__((packed));
|
||||
|
||||
RSDP();
|
||||
static RSDP* instance;
|
||||
|
||||
// Find the RSDP pointer in memory.
|
||||
void* GetRSDP();
|
||||
// Find the Fixed ACPI Descriptor (FADT) in memory.
|
||||
void* GetFACP(RSDT* Root);
|
||||
// Prepare virtual mapping of the RSDT
|
||||
void PagingInit();
|
||||
|
||||
// Prepare the RSDT for reading.
|
||||
__attribute__((unused)) void Init(size_t RSDP);
|
||||
|
||||
// Find the table with the specified name.
|
||||
void* FindEntry(const char* Name);
|
||||
|
||||
// Dump all available information to the system log.
|
||||
void LogDump();
|
||||
|
||||
private:
|
||||
size_t Version = 0;
|
||||
DescriptorV2* Descriptor;
|
||||
RSDT* Table;
|
||||
};
|
||||
}
|
80
inc/kernel/system/core.hpp
Normal file
80
inc/kernel/system/core.hpp
Normal file
|
@ -0,0 +1,80 @@
|
|||
#pragma once
|
||||
|
||||
#include <kernel/constants.hpp>
|
||||
#include <kernel/system/descriptors.h>
|
||||
#include <kernel/system/memory.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2021 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
/**
|
||||
* The relevant information contained within a stack trace - each call consists of the
|
||||
* contained information. By navigating the RBP until the base is found, a full backwards call stack can be determined.
|
||||
*/
|
||||
struct StackFrame {
|
||||
StackFrame* rbp;
|
||||
size_t rip;
|
||||
};
|
||||
|
||||
/**
|
||||
* Contains the definitions required to define and manage a single physical processing core.
|
||||
* These include; active GDT and IDT, TSS segments, saved stacks for execution and syscalls.
|
||||
* There are some utility functions for saving and loading extended registers, as well as
|
||||
* for identifying individual Cores in a running system.
|
||||
*
|
||||
*/
|
||||
class Core {
|
||||
public:
|
||||
Core() {}
|
||||
Core(size_t LAPIC, size_t ID);
|
||||
|
||||
size_t ID;
|
||||
size_t LocalAPIC;
|
||||
|
||||
address_space_t* AddressSpace;
|
||||
|
||||
uint8_t* SyscallStack;
|
||||
size_t StackAddress;
|
||||
uint8_t StackData[Constants::Core::STACK_SIZE];
|
||||
|
||||
IDT CoreIDT;
|
||||
GDT CoreGDT;
|
||||
TSS64 CoreTSS;
|
||||
|
||||
void LoadExtraRegisters(uint8_t* Data);
|
||||
void SaveExtraRegisters(uint8_t* Data);
|
||||
|
||||
void StackTrace(size_t Cycles);
|
||||
|
||||
static Core* GetCurrent() {
|
||||
size_t CoreID = 0;
|
||||
__asm__ __volatile__("mov %0, %%fs\n" : "=r"(CoreID) : :);
|
||||
return &Processors[CoreID];
|
||||
}
|
||||
|
||||
static Core* GetCore(int ID) { return &Processors[ID]; }
|
||||
|
||||
static void Init();
|
||||
|
||||
private:
|
||||
static Core Processors[];
|
||||
|
||||
// Initialization vectors for all new cores.
|
||||
// Numbers derived from boot.h space.
|
||||
// Specifically, the bootloader ROM.
|
||||
enum Initialization {
|
||||
PAGETABLES = 0x600,
|
||||
STARTUP = 0x620,
|
||||
STACK = 0x670,
|
||||
GDT = 0x680,
|
||||
IDT = 0x690
|
||||
};
|
||||
|
||||
void Bootstrap();
|
||||
void SetupData(size_t ID);
|
||||
|
||||
} __attribute__((packed));
|
|
@ -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
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"); }
|
||||
};
|
|
@ -1,24 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
typedef struct stackframe {
|
||||
struct stackframe* rbp;
|
||||
size_t rip;
|
||||
} stackframe_t;
|
||||
|
||||
void StackTrace(size_t cycles);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -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();
|
||||
|
|
|
@ -22,7 +22,7 @@ Device::GenericStorage* StorageDevicesArray[MAX_STORAGE_DEVICES];
|
|||
size_t CurrentStorageDevice = 0;
|
||||
|
||||
// Internal storage. TODO: Make this not a pain to maintain
|
||||
const char* DeviceNames[] = { "Storage", "Keyboard", "Networking" };
|
||||
const char* DeviceNames[] = {"Storage", "Keyboard", "Networking"};
|
||||
|
||||
|
||||
// Add a device pointer to the managed list.
|
||||
|
@ -30,7 +30,8 @@ void Device::RegisterDevice(Device::GenericDevice* Device) {
|
|||
DevicesArray[CurrentDevice] = Device;
|
||||
Device->DeviceID = CurrentDevice;
|
||||
CurrentDevice++;
|
||||
SerialPrintf("[DEVICE] Registered device %d called %s of type %s\r\n", CurrentDevice - 1, Device->GetName(), DeviceNames[Device->GetType()]);
|
||||
SerialPrintf("[DEVICE] Registered device %d called %s of type %s\r\n", CurrentDevice - 1, Device->GetName(),
|
||||
DeviceNames[Device->GetType()]);
|
||||
}
|
||||
|
||||
// Retrieve a device pointer from the managed list.
|
||||
|
@ -54,8 +55,8 @@ size_t Device::GetTotalDevices() { return CurrentDevice; }
|
|||
template <typename T>
|
||||
// Get the first registered instance of a specific type of device
|
||||
T* Device::FindDevice() {
|
||||
for(size_t i = 0; i < CurrentDevice; i++)
|
||||
if(DevicesArray[i]->GetType() == T::GetRootType())
|
||||
for (size_t i = 0; i < CurrentDevice; i++)
|
||||
if (DevicesArray[i]->GetType() == T::GetRootType())
|
||||
return static_cast<T*>(DevicesArray[i]);
|
||||
|
||||
SerialPrintf("[DEVICE] Warning: Unable to find a %s device.\r\n", DeviceNames[T::GetRootType()]);
|
||||
|
|
|
@ -23,59 +23,59 @@ extern "C" {
|
|||
KBD_FLAGS KbdFlags;
|
||||
|
||||
char keys[128] = {
|
||||
0, 27,
|
||||
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
|
||||
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
|
||||
0,
|
||||
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '#',
|
||||
0,
|
||||
'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/',
|
||||
0,
|
||||
'*', 0,
|
||||
' ', 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
'-',
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
'+',
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, 0, 0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, 27,
|
||||
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
|
||||
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
|
||||
0,
|
||||
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '#',
|
||||
0,
|
||||
'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/',
|
||||
0,
|
||||
'*', 0,
|
||||
' ', 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
'-',
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
'+',
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, 0, 0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
KeyboardCallback KeyboardCallbacks[16] = {
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
static int CurrentCallback = 0;
|
||||
|
||||
int SetupKBCallback(void (*Handler)(KeyboardData Frame)) {
|
||||
int SetupKBCallback(void (* Handler)(KeyboardData Frame)) {
|
||||
KeyboardCallbacks[CurrentCallback++] = Handler;
|
||||
return CurrentCallback;
|
||||
}
|
||||
|
||||
void UninstallKBCallback(int Number) {
|
||||
KeyboardCallbacks[Number] = NULL; // 0 is used in the common check to make sure that the function is callable.
|
||||
// This removes this callback from that check, ergo the function will no longer be called.
|
||||
KeyboardCallbacks[Number] = NULL; // 0 is used in the common check to make sure that the function is callable.
|
||||
// This removes this callback from that check, ergo the function will no longer be called.
|
||||
}
|
||||
|
||||
void KbdEcho() {
|
||||
if(!KbdFlags.EchoCount) {
|
||||
if(!KbdFlags.Echo) {
|
||||
if (!KbdFlags.EchoCount) {
|
||||
if (!KbdFlags.Echo) {
|
||||
Send8042(0xEE);
|
||||
}
|
||||
} else {
|
||||
|
@ -87,7 +87,7 @@ void KbdEcho() {
|
|||
|
||||
void UpdateKeyboard(uint8_t msg) {
|
||||
|
||||
switch(msg) {
|
||||
switch (msg) {
|
||||
case 0x0:
|
||||
KbdFlags.Error = 1;
|
||||
//ResendBuffer();
|
||||
|
@ -122,25 +122,25 @@ void UpdateKeyboard(uint8_t msg) {
|
|||
}
|
||||
|
||||
KeyboardData data = (KeyboardData) {
|
||||
.Scancode = msg,
|
||||
.Pressed = msg > 0x80 && msg < 0xD8 ? false : true,
|
||||
.Char = msg > 0x80 && msg < 0xD8 ? keys[msg - 0x80] : keys[msg]
|
||||
.Char = msg > 0x80 && msg < 0xD8 ? keys[msg - 0x80] : keys[msg],
|
||||
.Scancode = static_cast<char>(msg),
|
||||
.Pressed = !(msg > 0x80 && msg < 0xD8),
|
||||
};
|
||||
|
||||
void (*Handler)(KeyboardData data);
|
||||
void (* Handler)(KeyboardData data);
|
||||
|
||||
for(size_t handlerNum = 0; handlerNum < 16; handlerNum++) {
|
||||
Handler = KeyboardCallbacks[handlerNum];
|
||||
if(Handler) {
|
||||
Handler(data);
|
||||
}
|
||||
for (size_t handlerNum = 0; handlerNum < 16; handlerNum++) {
|
||||
Handler = KeyboardCallbacks[handlerNum];
|
||||
if (Handler) {
|
||||
Handler(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Send8042(size_t info) {
|
||||
for(size_t i = 0; i < 8; i++) {
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
unsigned char chr = (unsigned char) info;
|
||||
if(chr != 0) {
|
||||
if (chr != 0) {
|
||||
WritePort(0x60, chr, 1);
|
||||
WaitFor8042();
|
||||
}
|
||||
|
@ -149,10 +149,10 @@ void Send8042(size_t info) {
|
|||
|
||||
void WaitFor8042() {
|
||||
|
||||
bool full = true;
|
||||
while(full) {
|
||||
full = ReadPort(0x64, 1) & 1;
|
||||
}
|
||||
bool full = true;
|
||||
while (full) {
|
||||
full = ReadPort(0x64, 1) & 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
139
src/drivers/devices/io/apic.cpp
Normal file
139
src/drivers/devices/io/apic.cpp
Normal file
|
@ -0,0 +1,139 @@
|
|||
#include <driver/io/apic.h>
|
||||
#include <kernel/system/acpi/madt.h>
|
||||
#include <kernel/system/io.h>
|
||||
#include <kernel/system/memory.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2021 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
//TODO: remove
|
||||
#define UNUSED(x) (void)x
|
||||
|
||||
// All of these functions are in the Device namespace.
|
||||
using namespace Device;
|
||||
|
||||
Device::APIC* APIC::driver;
|
||||
|
||||
APIC::APIC() {
|
||||
Ready = false;
|
||||
driver = this;
|
||||
}
|
||||
|
||||
void APIC::WriteIO(size_t Base, uint32_t Register, uint32_t Data) {
|
||||
// MMIO - Set the base to the register we want to write into,
|
||||
// 16 bytes higher the data we want to write, and the hardware does the rest.
|
||||
*((volatile uint32_t*) Base) = Register;
|
||||
*((volatile uint32_t*) (Base + 16)) = Data;
|
||||
}
|
||||
|
||||
uint32_t APIC::ReadIO(size_t Base, uint32_t Register) {
|
||||
// MMIO- Set the base to the register we want to read.
|
||||
// The data we want will be put 16 bytes higher.
|
||||
|
||||
*((volatile uint32_t*) Base) = Register;
|
||||
|
||||
return *((volatile uint32_t*) (Base + 16));
|
||||
}
|
||||
|
||||
uint32_t APIC::ReadRegister(uint32_t Register) {
|
||||
return *((volatile uint32_t*) ((size_t*) Address + Register));
|
||||
}
|
||||
|
||||
void APIC::WriteRegister(uint32_t Register, uint32_t Data) {
|
||||
*((volatile uint32_t*) ((size_t*) Address + Register)) = Data;
|
||||
}
|
||||
|
||||
void APIC::Enable() {
|
||||
// Set the correct bits in the SIVR register. The APIC will be enabled.
|
||||
WriteRegister(Registers::SIVR, ReadRegister(Registers::SIVR) | 0x1FF);
|
||||
}
|
||||
|
||||
void APIC::SendEOI() {
|
||||
WriteRegister(Registers::EOI, 0);
|
||||
}
|
||||
|
||||
bool APIC::IsReady() {
|
||||
return Ready;
|
||||
}
|
||||
|
||||
void APIC::Init() {
|
||||
SerialPrintf("[ACPI] Enabling APICs...");
|
||||
|
||||
Address = (void*) ACPI::MADT::instance->LocalAPICBase;
|
||||
|
||||
// TODO: Check whether the identity mapping covers this address
|
||||
|
||||
if (Address == nullptr) {
|
||||
SerialPrintf("[ACPI] Unable to locate APICs.");
|
||||
for (;;) { }
|
||||
}
|
||||
|
||||
// Write "Local APIC Enabled" to the APIC Control Register.
|
||||
WriteModelSpecificRegister(0x1B, (ReadModelSpecificRegister(0x1B) | 0x800) & ~(1 << 10));
|
||||
Enable();
|
||||
|
||||
// Disable PIC1 and 2
|
||||
WritePort(0x21, 0xFF, 1);
|
||||
WritePort(0xA1, 0xFF, 1);
|
||||
|
||||
SerialPrintf("[ACPI] Enabling Global APIC..");
|
||||
IOAPICs = ACPI::MADT::instance->GetIOApicEntries();
|
||||
SerialPrintf("[ACPI] Enabling Interrupt Source Overrides..");
|
||||
ISOs = ACPI::MADT::instance->GetISOEntries();
|
||||
|
||||
Ready = true;
|
||||
}
|
||||
|
||||
uint32_t APIC::GetMaxRedirect(uint32_t ID) {
|
||||
size_t address = (IOAPICs[ID]->Address);
|
||||
uint32_t raw = (ReadIO(address, 0x1));
|
||||
|
||||
IOAPICMeta* table = (IOAPICMeta * ) & raw;
|
||||
return table->MaxRedirect;
|
||||
}
|
||||
|
||||
int APIC::GetCurrentCore() {
|
||||
return ReadRegister(Registers::LAPIC_ID) >> 24;
|
||||
}
|
||||
|
||||
void APIC::PreinitializeCore(int Core) {
|
||||
WriteRegister(Registers::ICR2, Core << 24);
|
||||
WriteRegister(Registers::ICR1, 0x500);
|
||||
}
|
||||
|
||||
void APIC::InitializeCore(int Core, size_t EntryPoint) {
|
||||
WriteRegister(Registers::ICR2, Core << 24);
|
||||
WriteRegister(Registers::ICR1, 0x600 | ((uint32_t) (EntryPoint / PAGE_SIZE)));
|
||||
}
|
||||
|
||||
void APIC::SetInternal(uint8_t Vector, uint32_t GSI, uint16_t Flags, int Core, int Status) {
|
||||
UNUSED(Core);
|
||||
size_t temp = Vector;
|
||||
int64_t target = -1;
|
||||
|
||||
for (size_t i = 0; IOAPICs[i] != 0x0; i++)
|
||||
if (IOAPICs[i]->GSI <= GSI)
|
||||
if (IOAPICs[i]->GSI + GetMaxRedirect(i) > GSI) {
|
||||
target = i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (target == -1) {
|
||||
SerialPrintf("[APIC] No ISO found when setting up redirect.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Flags & 2)
|
||||
temp |= (1 << 13);
|
||||
|
||||
if (Flags & 8)
|
||||
temp |= (1 << 15);
|
||||
|
||||
if (!Status)
|
||||
temp |= (1 << 16);
|
||||
|
||||
// TODO
|
||||
|
||||
}
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,7 +28,7 @@ void Editor::StartEditor(int callbackID) {
|
|||
layout.TextBoxX = (layout.ScreenWidth - layout.TextBoxWidth) / 2;
|
||||
|
||||
SetForegroundColor(0x000084);
|
||||
FillScreen();
|
||||
FillScreen(0x000084);
|
||||
|
||||
SetForegroundColor(0x00BBBBBB);
|
||||
DrawFilledRect(0, 0, PrintInfo.screenWidth, layout.HeaderHeight);
|
||||
|
|
138
src/global/core.s
Normal file
138
src/global/core.s
Normal file
|
@ -0,0 +1,138 @@
|
|||
;************************
|
||||
;*** Team Kitty, 2021 ***
|
||||
;*** Chroma ***
|
||||
;************************
|
||||
|
||||
; Initial startup routines for new cores.
|
||||
; New cores start in 16 bit real mode.
|
||||
; Because of this, this is the only necessary assembler file in the OS.
|
||||
|
||||
; First, bring them up to Protected and Long mode.
|
||||
; Then enable all necessary auxiliary features.
|
||||
; Pass off to the CPP code to handle the heavy work, we just want the core running.
|
||||
|
||||
[bits 16]
|
||||
BASE equ 0x1000
|
||||
|
||||
global stack
|
||||
extern initcpu
|
||||
|
||||
extern coreidt
|
||||
extern coregdt
|
||||
|
||||
global startCore
|
||||
startCore:
|
||||
cli
|
||||
mov ax, 0x0
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
mov ss, ax
|
||||
|
||||
o32 lgdt [gdt_protected - startCore + BASE]
|
||||
|
||||
mov eax, cr0
|
||||
or al, 0x1
|
||||
mov cr0, eax
|
||||
|
||||
jmp 0x8:(startCore32 - startCore + BASE)
|
||||
|
||||
[bits 32]
|
||||
|
||||
section .text
|
||||
startCore32:
|
||||
mov bx, 0x10
|
||||
mov ds, bx
|
||||
mov es, bx
|
||||
mov ss, bx
|
||||
|
||||
mov eax, dword [0xa000] ; Load bootloader tables into the new core
|
||||
mov cr3, eax
|
||||
|
||||
mov eax, cr4 ; Enable PAE
|
||||
or eax, 1 << 5
|
||||
or eax, 1 << 7
|
||||
mov cr4, eax
|
||||
|
||||
mov ecx, 0xc0000080
|
||||
rdmsr
|
||||
or eax, 1 << 8 ; Enable LME
|
||||
wrmsr
|
||||
|
||||
mov eax, cr0
|
||||
or eax, 1 << 31
|
||||
mov cr0, eax
|
||||
|
||||
lgdt [gdt_long - startCore + BASE]
|
||||
jmp 8:(startCore64 - startCore + BASE)
|
||||
|
||||
[bits 64]
|
||||
startCore64:
|
||||
mov ax, 0x10
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov ss, ax
|
||||
|
||||
mov ax, 0x0 ; These will contain core information later on
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
lgdt [coregdt]
|
||||
lidt [coreidt]
|
||||
|
||||
mov rbp, 0
|
||||
push 0
|
||||
popf
|
||||
|
||||
mov rax, qword leave
|
||||
jmp leave
|
||||
|
||||
leave:
|
||||
push rbp
|
||||
mov rax, cr0
|
||||
btr eax, 2
|
||||
bts eax, 1
|
||||
mov cr0, rax
|
||||
|
||||
mov rax, cr4
|
||||
bts eax, 9
|
||||
bts eax, 10
|
||||
mov cr4, rax
|
||||
|
||||
call initcpu
|
||||
|
||||
|
||||
align 16
|
||||
gdt_long:
|
||||
dw gdt_long_end - gdt_long_start - 1 ; gdt length
|
||||
dq gdt_long_start - startCore + BASE ; address of the gdt
|
||||
|
||||
align 16
|
||||
gdt_long_start:
|
||||
dq 0
|
||||
dq 0x00AF98000000FFFF
|
||||
dq 0x00CF92000000FFFF
|
||||
gdt_long_end:
|
||||
|
||||
align 16
|
||||
gdt_protected:
|
||||
dw gdt_protected_end - gdt_protected_start - 1 ; gdt length
|
||||
dd gdt_protected_start - startCore + BASE ; address of the gdt
|
||||
|
||||
align 16
|
||||
gdt_protected_start:
|
||||
dq 0
|
||||
dq 0x00CF9A000000FFFF
|
||||
dq 0x00CF92000000FFFF
|
||||
gdt_protected_end:
|
||||
|
||||
align 16
|
||||
idt_protected:
|
||||
dw 0
|
||||
dd 0
|
||||
dd 0
|
||||
align 16
|
||||
|
||||
global endCore
|
||||
endCore:
|
|
@ -36,26 +36,32 @@ char* InternalBuffer;
|
|||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* C++ code! Scary!
|
||||
* This is a temporary measure to experiment with the Editor system.
|
||||
*/
|
||||
|
||||
int Main(void) {
|
||||
extern "C" int Main(void) {
|
||||
KernelAddressSpace.Lock.NextTicket = 0;
|
||||
KernelAddressSpace.Lock.NowServing = 0;
|
||||
KernelAddressSpace.PML4 = nullptr;
|
||||
|
||||
SerialPrintf("\r\n[ boot] Booting Chroma..\r\n");
|
||||
SerialPrintf("[ boot] Bootloader data structure at 0x%p\r\n", (size_t) &bootldr);
|
||||
SerialPrintf("[ boot] Kernel loaded at 0x%p, ends at 0x%p, is %d bytes long.\r\n", KernelAddr, KernelEnd, KernelEnd - KernelAddr);
|
||||
SerialPrintf("[ boot] Framebuffer at 0x%p / 0x%p, is %dx%d, 0x%x bytes long.\r\n", bootldr.fb_ptr, (size_t) &fb, bootldr.fb_width, bootldr.fb_height, bootldr.fb_size);
|
||||
SerialPrintf("[ boot] Initrd is physically at 0x%p, and is %d bytes long.\r\n", bootldr.initrd_ptr, bootldr.initrd_size);
|
||||
SerialPrintf("[ boot] 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);
|
||||
}
|
|
@ -22,8 +22,8 @@ void ListRemove(list_entry_t* Entry) {
|
|||
Entry->Next->Previous = Entry->Previous;
|
||||
Entry->Previous->Next = Entry->Next;
|
||||
|
||||
Entry->Previous = (void*)0xDEADull;
|
||||
Entry->Next = (void*)0xBEEFull;
|
||||
Entry->Previous = static_cast<list_entry*>((void*) 0xDEADull);
|
||||
Entry->Next = static_cast<list_entry*>((void*) 0xBEEFull);
|
||||
}
|
||||
|
||||
bool ListIsEmpty(list_entry_t* Head) {
|
74
src/system/acpi/MADT.cpp
Normal file
74
src/system/acpi/MADT.cpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
#include <kernel/system/acpi/madt.h>
|
||||
#include <kernel/chroma.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2021 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
using namespace ACPI;
|
||||
|
||||
ACPI::MADT* MADT::instance;
|
||||
|
||||
MADT::MADT() {
|
||||
instance = this;
|
||||
}
|
||||
|
||||
size_t MADT::GetEndOfTable() {
|
||||
return ((size_t) &Header->Header) + Header->Header.Length;
|
||||
}
|
||||
|
||||
void MADT::Initialize() {
|
||||
SerialPrintf("[ACPI] Loading Multiple APIC Descriptor Tables..");
|
||||
Address = ACPI::RSDP::instance->FindEntry("APIC");
|
||||
Header = reinterpret_cast<MADTHeader*>(Address);
|
||||
|
||||
LocalAPICBase = Header->LocalAPIC;
|
||||
|
||||
// TODO: Check whether the Base is identity mapped
|
||||
}
|
||||
|
||||
MADT::IOAPICEntry** MADT::GetIOApicEntries() {
|
||||
MADT::RecordTableEntry* table;
|
||||
table = Header->Table;
|
||||
auto** entries = (MADT::IOAPICEntry**) kmalloc(255);
|
||||
|
||||
size_t count = 0;
|
||||
|
||||
while ((size_t) table < GetEndOfTable()) {
|
||||
table = (MADT::RecordTableEntry*) (((size_t) table) + table->Length);
|
||||
|
||||
if (table->Type == MADT::Type::IOAPIC) {
|
||||
MADT::IOAPICEntry* io_apic = reinterpret_cast<MADT::IOAPICEntry*>(table);
|
||||
entries[count] = (MADT::IOAPICEntry*) ((size_t) io_apic);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
entries[count] = 0;
|
||||
return entries;
|
||||
}
|
||||
|
||||
MADT::ISOEntry** MADT::GetISOEntries() {
|
||||
MADT::RecordTableEntry* table = Header->Table;
|
||||
auto** entries = (MADT::ISOEntry**) kmalloc(255);
|
||||
|
||||
size_t count = 0;
|
||||
|
||||
while ((size_t) table < GetEndOfTable()) {
|
||||
table = (MADT::RecordTableEntry*) (((size_t) table) + table->Length);
|
||||
|
||||
if (table->Type == MADT::Type::ISO) {
|
||||
MADT::ISOEntry* io_apic = reinterpret_cast<MADT::ISOEntry*>(table);
|
||||
entries[count] = (MADT::ISOEntry*) ((size_t) io_apic);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
entries[count] = 0;
|
||||
return entries;
|
||||
}
|
||||
|
||||
MADT::RecordTableEntry* MADT::GetTableEntries() {
|
||||
return Header->Table;
|
||||
}
|
87
src/system/acpi/RSDP.cpp
Normal file
87
src/system/acpi/RSDP.cpp
Normal file
|
@ -0,0 +1,87 @@
|
|||
#include <kernel/system/acpi/rsdt.h>
|
||||
#include <kernel/chroma.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2021 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
using namespace ACPI;
|
||||
|
||||
ACPI::RSDP* RSDP::instance;
|
||||
|
||||
void* RSDP::GetRSDP() {
|
||||
|
||||
// Search physical memory (via the direct region) for the "RSD PTR " magic string.
|
||||
// TODO: this is extremely slow!
|
||||
for (size_t i = TO_DIRECT(0x80000); i < TO_DIRECT(0x100000); i += 16) {
|
||||
if (i == TO_DIRECT(0xA0000)) {
|
||||
i = TO_DIRECT(0xE0000 - 16);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp((char*) i, "RSD PTR ")) {
|
||||
return (void*) i;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RSDP::RSDP() {
|
||||
instance = this;
|
||||
Table = (RSDT*) 0;
|
||||
Descriptor = (DescriptorV2*) 0;
|
||||
}
|
||||
|
||||
void* RSDP::FindEntry(const char* Name) {
|
||||
// Take the pointer to the RSD Table from the Direct region.
|
||||
auto* table = reinterpret_cast<RSDP::RSDT*>(TO_DIRECT(Descriptor->Header.RSDT));
|
||||
size_t entries = (table->Header.Length - sizeof(table->Header)) / 4;
|
||||
|
||||
|
||||
// For each entry: if valid, search for the specified name.
|
||||
for (size_t i = 0; i < entries; i++) {
|
||||
if (table->OtherSDTs[i] == 0x0)
|
||||
continue;
|
||||
|
||||
ACPIHeader* header = reinterpret_cast<ACPIHeader*>(table->OtherSDTs[i]);
|
||||
|
||||
if (strcmp(header->Signature, Name))
|
||||
return (void*) header;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* RSDP::GetFACP(RSDT* Root) {
|
||||
UNUSED(Root);
|
||||
return FindEntry("FACP");
|
||||
}
|
||||
|
||||
void RSDP::Init(size_t RSDP) {
|
||||
UNUSED(RSDP);
|
||||
SerialPrintf("[ACPI] Loading ACPI subsystem..");
|
||||
|
||||
Descriptor = (DescriptorV2*) GetRSDP();
|
||||
Table = (RSDT *) TO_DIRECT(Descriptor->Header.RSDT);
|
||||
|
||||
SerialPrintf("[RSDP] Dumping RSDT..");
|
||||
auto* table = reinterpret_cast<RSDP::RSDT*>(TO_DIRECT(Descriptor->Header.RSDT));
|
||||
size_t entries = (table->Header.Length - sizeof(table->Header)) / 4;
|
||||
|
||||
|
||||
// For each entry: if valid, search for the specified name.
|
||||
for (size_t i = 0; i < entries; i++) {
|
||||
if (table->OtherSDTs[i] == 0x0)
|
||||
continue;
|
||||
|
||||
ACPIHeader* header = reinterpret_cast<ACPIHeader*>(table->OtherSDTs[i]);
|
||||
SerialPrintf("[RSDP] Entry %d: Signature %.4s, OEM %.6s\n", i, header->Signature, header->OEMID);
|
||||
}
|
||||
}
|
||||
|
||||
void RSDP::PagingInit() {
|
||||
// TODO: check whether the identity mapping makes this necessary.
|
||||
}
|
||||
|
134
src/system/core.cpp
Normal file
134
src/system/core.cpp
Normal file
|
@ -0,0 +1,134 @@
|
|||
#include <kernel/chroma.h>
|
||||
#include <kernel/system/acpi/madt.h>
|
||||
#include <driver/io/apic.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2021 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
extern size_t startCore;
|
||||
extern size_t endCore;
|
||||
|
||||
int Cores = 0;
|
||||
volatile bool Ready = false;
|
||||
|
||||
Core Core::Processors[Constants::Core::MAX_CORES];
|
||||
TSS64 Tasks[Constants::Core::MAX_CORES];
|
||||
ACPI::MADT::LAPICEntry* LAPICs[Constants::Core::MAX_CORES];
|
||||
|
||||
extern "C" void initcpu() {
|
||||
// Init APIC
|
||||
WriteModelSpecificRegister(0x1B, (ReadModelSpecificRegister(0x1B) | 0x800) & ~(1 << 10));
|
||||
Device::APIC::driver->Enable();
|
||||
|
||||
__asm__ __volatile__("mov %%fs, %0" : : "r" (Device::APIC::driver->GetCurrentCore()) : );
|
||||
|
||||
SerialPrintf("[CORE] Core %d ready.\r\n", Device::APIC::driver->GetCurrentCore());
|
||||
// TODO: New GDT
|
||||
__asm__ __volatile__("cli");
|
||||
Ready = true;
|
||||
__asm__ __volatile__("sti");
|
||||
|
||||
for (;;) { }
|
||||
}
|
||||
|
||||
Core::Core(size_t APIC, size_t ID) {
|
||||
Device::APIC::driver->PreinitializeCore(APIC);
|
||||
GetCore(ID)->LocalAPIC = APIC;
|
||||
|
||||
Bootstrap();
|
||||
SetupData(ID);
|
||||
|
||||
Device::APIC::driver->InitializeCore(APIC, CORE_BOOTSTRAP);
|
||||
|
||||
while (Ready != true) {
|
||||
__asm__ ("nop");
|
||||
}
|
||||
|
||||
Ready = false;
|
||||
}
|
||||
|
||||
void Core::Init() {
|
||||
using namespace ACPI;
|
||||
|
||||
Ready = false;
|
||||
SerialPrintf("[CORE] Enabling Multiprocessing\n");
|
||||
|
||||
memset(Tasks, 0, Constants::Core::MAX_CORES * sizeof(TSS64));
|
||||
for (size_t i = 0; i < Constants::Core::MAX_CORES; i++)
|
||||
LAPICs[i] = nullptr;
|
||||
|
||||
// Parse MADT for cores
|
||||
MADT::RecordTableEntry* table = MADT::instance->GetTableEntries();
|
||||
Cores = 0;
|
||||
|
||||
// While there are more entries in the table..
|
||||
while ((size_t) table < MADT::instance->GetEndOfTable()) {
|
||||
// Move to the next entry (by skipping the length of the current entry)
|
||||
table = (MADT::RecordTableEntry*) (((size_t) table) + table->Length);
|
||||
// Check for a LAPIC record (which indicates a unique physical core)
|
||||
if (table->Type == MADT::Type::LAPIC) {
|
||||
// Find the data for the LAPIC with a reinterpret
|
||||
MADT::LAPICEntry* lapic = reinterpret_cast<MADT::LAPICEntry*>(table);
|
||||
|
||||
// Set the current ID
|
||||
LAPICs[Cores] = lapic;
|
||||
// Tell the core that its' LAPIC is the current id
|
||||
Core::GetCore(Cores)->LocalAPIC = lapic->APIC;
|
||||
// Move to the next core if there is one.
|
||||
Cores++;
|
||||
}
|
||||
}
|
||||
|
||||
SerialPrintf("[CORE] Found %d cores.\n", Cores);
|
||||
|
||||
if (Cores > 1)
|
||||
SerialPrintf("[CORE] Bringing up other cores.\n");
|
||||
|
||||
// For each non-bootstrap core, initialize the necessary data and populate the array.
|
||||
for (int i = 0; i < Cores; i++) {
|
||||
SerialPrintf("[CORE] Enabling core %d.\n", i);
|
||||
if (Device::APIC::driver->GetCurrentCore() != LAPICs[i]->Core)
|
||||
Processors[i] = Core(LAPICs[i]->APIC, LAPICs[i]->Core);
|
||||
}
|
||||
}
|
||||
|
||||
void Core::Bootstrap() {
|
||||
size_t coreStarterLen = endCore - startCore;
|
||||
|
||||
for (size_t i = 0; i < coreStarterLen + 2; i += PAGE_SIZE)
|
||||
MapVirtualPage(AddressSpace, CORE_BOOTSTRAP + i, CORE_BOOTSTRAP + i, 0);
|
||||
|
||||
memcpy((void*) CORE_BOOTSTRAP, &startCore, coreStarterLen);
|
||||
}
|
||||
|
||||
void Core::SetupData(size_t Core) {
|
||||
// Write page tables
|
||||
GetCore(Core)->AddressSpace->PML4 = GetCurrent()->AddressSpace->PML4;
|
||||
*((size_t*) Initialization::PAGETABLES) = (size_t) GetCore(Core)->AddressSpace->PML4;
|
||||
|
||||
// Prepare stack
|
||||
memset(GetCore(Core)->StackData, 0, Constants::Core::STACK_SIZE);
|
||||
*((size_t*) Initialization::STACK) = (size_t) GetCore(Core)->StackData + Constants::Core::STACK_SIZE;
|
||||
|
||||
// GDT = 0x680
|
||||
// IDT = 0x690
|
||||
__asm__ __volatile__("sgdt (0x680)\n sidt (0x690)");
|
||||
|
||||
// Set startup address
|
||||
*((size_t*) Initialization::STARTUP) = (size_t) &initcpu;
|
||||
}
|
||||
|
||||
|
||||
void Core::StackTrace(size_t Cycles) {
|
||||
StackFrame* stack;
|
||||
|
||||
__asm__ __volatile__ ("mov %%rbp, %[dest]" : [dest] "=r"(stack) : :);
|
||||
SerialPrintf("[Trace] Beginning stack trace. RBP is currently 0x%p\r\n", stack);
|
||||
for (size_t frame = 0; stack != 0 && frame < Cycles; ++frame) {
|
||||
SerialPrintf("[Trace] (%d) 0x%p: 0x%p \r\n", frame, stack->rbp, stack->rip);
|
||||
stack = stack->rbp;
|
||||
}
|
||||
SerialPrintf("[Trace] Stack trace over.\r\n");
|
||||
}
|
|
@ -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,16 +37,16 @@ __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() {
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -1,468 +0,0 @@
|
|||
#include <kernel/chroma.h>
|
||||
#include <kernel/video/draw.h>
|
||||
#include <kernel/system/interrupts.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This file contains all of the ISR and IRQ
|
||||
* (Interrupt Service Request) functions.
|
||||
*
|
||||
* As they use the GCC interrupt attribute,
|
||||
* this file must be compiled without red-
|
||||
* zone protection, thus all of these
|
||||
* functions are in their own file to
|
||||
* accomodate this.
|
||||
*
|
||||
* Additionally, the kernel now has SSE/AVX support.
|
||||
* So this file and this file *alone* must be compiled with
|
||||
* -mgeneral-regs-only
|
||||
*
|
||||
* Calling a function like so:
|
||||
*
|
||||
* __attribute__((interrupt)) isr1(registers_t* frame) {}
|
||||
*
|
||||
* allows the function to be used to serve
|
||||
* interrupts - GCC compiles it under unique
|
||||
* conditions, as it preserves the state of
|
||||
* the processor and stack between execution,
|
||||
* as well as using the IRET instruction to
|
||||
* return to the middle of the previous function.
|
||||
*
|
||||
* There is also a version of the interrupt
|
||||
* attribute which allows for error handlers,
|
||||
* these having a size_t input as an error code.
|
||||
*/
|
||||
|
||||
const char* ExceptionStrings[] = {
|
||||
"Division by Zero",
|
||||
"Debug",
|
||||
"Non Maskable Interrupt",
|
||||
"Breakpoint",
|
||||
"Into Detected Overflow",
|
||||
"Out of Bounds",
|
||||
"Invalid Opcode",
|
||||
"No Coprocessor",
|
||||
"Double Fault",
|
||||
"Coprocessor Segment Overrun",
|
||||
"Bad TSS",
|
||||
"Segment Not Present",
|
||||
"Stack Fault",
|
||||
"General Protection Fault",
|
||||
"Page Fault",
|
||||
"Unknown Interrupt",
|
||||
"Coprocessor Fault",
|
||||
"Alignment Check",
|
||||
"Machine Check",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved"
|
||||
};
|
||||
|
||||
typedef void (*IRQHandler)(INTERRUPT_FRAME* Frame);
|
||||
|
||||
IRQHandler IRQ_Handlers[16] = {
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
|
||||
typedef unsigned long long int uword_t;
|
||||
|
||||
/* All of the ISR routines call this function for now.
|
||||
! This function is NOT leaf, and it might clobber the stack.
|
||||
! Be careful!
|
||||
*/
|
||||
void ISR_Common(INTERRUPT_FRAME* Frame, size_t Exception) {
|
||||
|
||||
UNUSED(Frame);
|
||||
|
||||
/* Only the first 32 ISR/IRQs are reserved for exceptions by the CPU. We can handle up to 512 interrupts total, though. */
|
||||
if(Exception < 32) {
|
||||
SetForegroundColor(0x0000FF00);
|
||||
FillScreen();
|
||||
/* ExceptionStrings is an array of c-strings defined in kernel.h */
|
||||
SerialPrintf("[ ISR] %s exception!\r\n", ExceptionStrings[Exception]);
|
||||
}
|
||||
}
|
||||
|
||||
/* The common handler for exceptions that throw error codes, which give us useful insight
|
||||
into what went wrong. In pure Curle style, though, we just ignore the error code. */
|
||||
void ISR_Error_Common(INTERRUPT_FRAME* Frame, size_t ErrorCode, size_t Exception) {
|
||||
|
||||
UNUSED(Frame);
|
||||
|
||||
if(Exception < 32) {
|
||||
SetForegroundColor(0x0000FF00);
|
||||
FillScreen();
|
||||
SerialPrintf("[ ISR] ISR Error %d raised, EC %d!\r\n", Exception, ErrorCode);
|
||||
SerialPrintf("[ ISR] %s exception!\r\n", ExceptionStrings[Exception]);
|
||||
while(true) {}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Likewise, this function is common to all IRQ handlers. It calls the assigned routine,
|
||||
which was set up earlier by irq_install.*/
|
||||
void IRQ_Common(INTERRUPT_FRAME* Frame, size_t Interrupt) {
|
||||
// First we need to define a function pointer..
|
||||
void (*Handler)(INTERRUPT_FRAME* Frame);
|
||||
|
||||
/* We set all uninitialized routines to 0, so the if(handler) check here allows us to
|
||||
safely tell whether we've actually got something for this IRQ. */
|
||||
Handler = IRQ_Handlers[Interrupt];
|
||||
// If there's something there,
|
||||
if(Handler) {
|
||||
SerialPrintf("[ IRQ] IRQ %d raised!\r\n", Interrupt);
|
||||
// Call the handler.
|
||||
Handler(Frame);
|
||||
}
|
||||
/* The Slave PIC must be told it's been read in order to receive another 8+ IRQ. */
|
||||
if(Interrupt > 7)
|
||||
WritePort(0xA0, 0x20, 1);
|
||||
|
||||
/* In either case, we tell the Master PIC it's been read to receive any IRQ. */
|
||||
WritePort(0x20, 0x20, 1);
|
||||
|
||||
}
|
||||
|
||||
/* However, in order to actually be able to receive IRQs, we need to remap the PICs. */
|
||||
void RemapIRQControllers() {
|
||||
/* 0x20 is the Master PIC,
|
||||
0xA0 is the Slave PIC. */
|
||||
WritePort(0x20, 0x11, 1);
|
||||
WritePort(0xA0, 0x11, 1);
|
||||
WritePort(0x21, 0x20, 1);
|
||||
WritePort(0xA1, 0x28, 1);
|
||||
WritePort(0x21, 0x04, 1);
|
||||
WritePort(0xA1, 0x02, 1);
|
||||
WritePort(0x21, 0x01, 1);
|
||||
WritePort(0xA1, 0x01, 1);
|
||||
WritePort(0x21, 0x0, 1);
|
||||
WritePort(0xA1, 0x0, 1);
|
||||
}
|
||||
|
||||
/* In order to actually handle the IRQs, though, we need to tell the kernel *where* the handlers are. */
|
||||
/* A simple wrapper that adds a function pointer to the IRQ array. */
|
||||
void InstallIRQ(int IRQ, void (*Handler)(INTERRUPT_FRAME* Frame)) {
|
||||
IRQ_Handlers[IRQ] = Handler;
|
||||
}
|
||||
|
||||
/* A simple wrapper that unlinks a function pointer, rendering the IRQ unused. */
|
||||
void UninstallIRQHandler(int IRQ) {
|
||||
IRQ_Handlers[IRQ] = NULL; // 0 is used in the common check to make sure that the function is callable.
|
||||
// This removes this IRQ from that check, ergo the function will no longer be called.
|
||||
}
|
||||
|
||||
void EmptyIRQ(INTERRUPT_FRAME* frame) {
|
||||
|
||||
UNUSED(frame);
|
||||
|
||||
// Flash the borders green, then back to blue
|
||||
SetForegroundColor(0x0000FF00);
|
||||
for(size_t y = 0; y < bootldr.fb_height; y++) {
|
||||
for(size_t x = 0; x < 20; x++) {
|
||||
DrawPixel(x, y);
|
||||
}
|
||||
|
||||
for(size_t x = (bootldr.fb_width - 20); x < bootldr.fb_width; x++) {
|
||||
DrawPixel(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t x = 0; x < bootldr.fb_width; x++) {
|
||||
for(size_t y = 0; y < 20; y++) {
|
||||
DrawPixel(x, y);
|
||||
}
|
||||
|
||||
for(size_t y = (bootldr.fb_height - 20); y < bootldr.fb_height; y++) {
|
||||
DrawPixel(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < 100000; i++) {}
|
||||
|
||||
SetForegroundColor(0x000000FF);
|
||||
for(size_t y = 0; y < bootldr.fb_height; y++) {
|
||||
for(size_t x = 0; x < 20; x++) {
|
||||
DrawPixel(x, y);
|
||||
}
|
||||
|
||||
for(size_t x = (bootldr.fb_width - 20); x < bootldr.fb_width; x++) {
|
||||
DrawPixel(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t x = 0; x < bootldr.fb_width; x++) {
|
||||
for(size_t y = 0; y < 20; y++) {
|
||||
DrawPixel(x, y);
|
||||
}
|
||||
|
||||
for(size_t y = (bootldr.fb_height - 20); y < bootldr.fb_height; y++) {
|
||||
DrawPixel(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void KeyboardCallback(INTERRUPT_FRAME* frame) {
|
||||
UNUSED(frame);
|
||||
|
||||
uint8_t msg = ReadPort(0x60, 1);
|
||||
|
||||
UpdateKeyboard(msg);
|
||||
|
||||
WaitFor8042();
|
||||
}
|
||||
|
||||
void InitInterrupts() {
|
||||
size_t RFLAGS = ReadControlRegister('f');
|
||||
|
||||
if(!(RFLAGS & (1 << 9))) {
|
||||
WriteControlRegister('f', RFLAGS | (1 << 9));
|
||||
}
|
||||
|
||||
|
||||
InstallIRQ(1, &KeyboardCallback);
|
||||
|
||||
Send8042(0xF002);
|
||||
|
||||
__asm__ __volatile__("sti");
|
||||
}
|
||||
|
||||
|
||||
/* The interrupt numbers, their meanings, and
|
||||
* special information is laid out below:
|
||||
*
|
||||
* 0 - Divide by Zero
|
||||
* 1 - Debug
|
||||
* 2 - Non-Maskable
|
||||
* 3 - Breakpoint
|
||||
* 4 - Into Detected Overflow
|
||||
* 5 - Out of Bounds
|
||||
* 6 - Invalid Opcode
|
||||
* 7 - No Coprocessor
|
||||
* 8 - Double Fault * (With Error)
|
||||
* 9 - Coprocessor Segment Overrun
|
||||
* 10 - Bad TSS * (With Error)
|
||||
* 11 - Segment Not Present * (With Error)
|
||||
* 12 - Stack Fault * (With Error)
|
||||
* 13 - General Protection Fault * (With Error)
|
||||
* 14 - Page Fault * (With Error)
|
||||
* 15 - Unknown Interrupt
|
||||
* 16 - Coprocessor Fault
|
||||
* 17 - Alignment Check
|
||||
* 18 - Machine Check
|
||||
* 19 to 31 - Reserved
|
||||
*/
|
||||
|
||||
__attribute__((interrupt)) void ISR0Handler(INTERRUPT_FRAME* Frame) {
|
||||
|
||||
ISR_Common(Frame, 0);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR1Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 1);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR2Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 2);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR3Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 3);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR4Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 4);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR5Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 5);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR6Handler(INTERRUPT_FRAME* Frame) {
|
||||
|
||||
__asm__ __volatile__("sti");
|
||||
|
||||
SerialPrintf("[FAULT] Invalid Opcode!\n");
|
||||
size_t retAddr = 0;
|
||||
size_t opcodeAddr = Frame->rip;
|
||||
|
||||
__asm__ __volatile__("popq %%rax\n\t" "pushq %%rax": "=a" (retAddr) : :);
|
||||
SerialPrintf("[FAULT] Opcode is at 0x%x, called from 0x%p\r\n", opcodeAddr, retAddr);
|
||||
Printf("Invalid Opcode: 0x%p\n", opcodeAddr);
|
||||
|
||||
StackTrace(15);
|
||||
|
||||
for(;;) {}
|
||||
}
|
||||
__attribute__((interrupt)) void ISR7Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 7);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR8Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
|
||||
ISR_Error_Common(Frame, ErrorCode, 8);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR9Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 9);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR10Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
|
||||
ISR_Error_Common(Frame, ErrorCode, 10);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR11Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
|
||||
ISR_Error_Common(Frame, ErrorCode, 11);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR12Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
|
||||
ISR_Error_Common(Frame, ErrorCode, 12);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR13Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
|
||||
|
||||
SerialPrintf("\r\n\n[ GPF] RIP: 0x%p, CS: 0x%x, FLAGS: 0x%p, RSP: 0x%x, SS: 0x%x\r\n", Frame->rip, Frame->cs, Frame->rflags, Frame->rsp, Frame->ss);
|
||||
|
||||
StackTrace(6);
|
||||
|
||||
ISR_Error_Common(Frame, ErrorCode, 13); // General Protection
|
||||
}
|
||||
__attribute__((interrupt)) void ISR14Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
|
||||
__asm__ __volatile__("sti");
|
||||
|
||||
SerialPrintf("\r\n\n\n[FAULT] Page fault! Caused by {\r\n");
|
||||
|
||||
//size_t FaultAddr = ReadControlRegister(2);
|
||||
uint8_t FaultPres = ErrorCode & 0x1;
|
||||
uint8_t FaultRW = ErrorCode & 0x2;
|
||||
uint8_t FaultUser = ErrorCode & 0x4;
|
||||
uint8_t FaultReserved = ErrorCode & 0x8;
|
||||
uint8_t FaultInst = ErrorCode & 0x10;
|
||||
|
||||
if(!FaultPres) SerialPrintf("[FAULT] Accessed a page that isn't present.\r\n");
|
||||
if(FaultRW || FaultUser) SerialPrintf("[FAULT] Accessed a Read-Only page.\r\n");
|
||||
if(FaultReserved) SerialPrintf("[FAULT] Overwrote reserved bits.\r\n");
|
||||
if(FaultInst) SerialPrintf("[FAULT] \"Instruction Fetch\"");
|
||||
|
||||
SerialPrintf("[FAULT] } at address\n[FAULT] 0x%p\r\n\n", ReadControlRegister(2));
|
||||
|
||||
StackTrace(6);
|
||||
ISR_Error_Common(Frame, ErrorCode, 14); // Page Fault
|
||||
}
|
||||
__attribute__((interrupt)) void ISR15Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 15);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR16Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 16);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR17Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
|
||||
ISR_Error_Common(Frame, ErrorCode, 17);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR18Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 18);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR19Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 19);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR20Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 20);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR21Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 21);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR22Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 22);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR23Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 23);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR24Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 24);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR25Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 25);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR26Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 26);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR27Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 27);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR28Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 28);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR29Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 29);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR30Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
|
||||
ISR_Error_Common(Frame, ErrorCode, 30);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR31Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 31);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ReservedISRHandler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 33); // if < 32, isn't handled.
|
||||
// Effectively disables this ISR.
|
||||
}
|
||||
|
||||
|
||||
__attribute__((interrupt)) void IRQ0Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 0);
|
||||
}
|
||||
__attribute__((interrupt)) void IRQ1Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 1); // Keyboard handler
|
||||
}
|
||||
__attribute__((interrupt)) void IRQ2Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 2);
|
||||
}
|
||||
__attribute__((interrupt)) void IRQ3Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 3);
|
||||
}
|
||||
__attribute__((interrupt)) void IRQ4Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 4);
|
||||
}
|
||||
__attribute__((interrupt)) void IRQ5Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 5);
|
||||
}
|
||||
__attribute__((interrupt)) void IRQ6Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 6);
|
||||
}
|
||||
__attribute__((interrupt)) void IRQ7Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 7);
|
||||
}
|
||||
__attribute__((interrupt)) void IRQ8Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 8);
|
||||
}
|
||||
__attribute__((interrupt)) void IRQ9Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 9);
|
||||
}
|
||||
__attribute__((interrupt)) void IRQ10Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 10);
|
||||
}
|
||||
__attribute__((interrupt)) void IRQ11Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 11);
|
||||
}
|
||||
__attribute__((interrupt)) void IRQ12Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 12);
|
||||
}
|
||||
__attribute__((interrupt)) void IRQ13Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 13);
|
||||
}
|
||||
__attribute__((interrupt)) void IRQ14Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 14);
|
||||
}
|
||||
__attribute__((interrupt)) void IRQ15Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 15);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
515
src/system/interrupts.cpp
Normal file
515
src/system/interrupts.cpp
Normal file
|
@ -0,0 +1,515 @@
|
|||
#include <kernel/chroma.h>
|
||||
#include <kernel/video/draw.h>
|
||||
#include <kernel/system/interrupts.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This file contains all of the ISR and IRQ
|
||||
* (Interrupt Service Request) functions.
|
||||
*
|
||||
* As they use the GCC interrupt attribute,
|
||||
* this file must be compiled without red-
|
||||
* zone protection, thus all of these
|
||||
* functions are in their own file to
|
||||
* accomodate this.
|
||||
*
|
||||
* Additionally, the kernel now has SSE/AVX support.
|
||||
* So this file and this file *alone* must be compiled with
|
||||
* -mgeneral-regs-only
|
||||
*
|
||||
* Calling a function like so:
|
||||
*
|
||||
* __attribute__((interrupt)) isr1(registers_t* frame) {}
|
||||
*
|
||||
* allows the function to be used to serve
|
||||
* interrupts - GCC compiles it under unique
|
||||
* conditions, as it preserves the state of
|
||||
* the processor and stack between execution,
|
||||
* as well as using the IRET instruction to
|
||||
* return to the middle of the previous function.
|
||||
*
|
||||
* There is also a version of the interrupt
|
||||
* attribute which allows for error handlers,
|
||||
* these having a size_t input as an error code.
|
||||
*/
|
||||
|
||||
const char* ExceptionStrings[] = {
|
||||
"Division by Zero",
|
||||
"Debug",
|
||||
"Non Maskable Interrupt",
|
||||
"Breakpoint",
|
||||
"Into Detected Overflow",
|
||||
"Out of Bounds",
|
||||
"Invalid Opcode",
|
||||
"No Coprocessor",
|
||||
"Double Fault",
|
||||
"Coprocessor Segment Overrun",
|
||||
"Bad TSS",
|
||||
"Segment Not Present",
|
||||
"Stack Fault",
|
||||
"General Protection Fault",
|
||||
"Page Fault",
|
||||
"Unknown Interrupt",
|
||||
"Coprocessor Fault",
|
||||
"Alignment Check",
|
||||
"Machine Check",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved"
|
||||
};
|
||||
|
||||
typedef void (* IRQHandler)(INTERRUPT_FRAME* Frame);
|
||||
|
||||
IRQHandler IRQ_Handlers[16] = {
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
|
||||
typedef unsigned long long int uword_t;
|
||||
|
||||
/* All of the ISR routines call this function for now.
|
||||
! This function is NOT leaf, and it might clobber the stack.
|
||||
! Be careful!
|
||||
*/
|
||||
__attribute__((no_caller_saved_registers)) void ISR_Common(INTERRUPT_FRAME* Frame, size_t Exception) {
|
||||
|
||||
UNUSED(Frame);
|
||||
|
||||
/* Only the first 32 ISR/IRQs are reserved for exceptions by the CPU. We can handle up to 512 interrupts total, though. */
|
||||
if (Exception < 32) {
|
||||
SetForegroundColor(0x0000FF00);
|
||||
FillScreen(0x0000FF00);
|
||||
/* ExceptionStrings is an array of c-strings defined in kernel.h */
|
||||
SerialPrintf("[ ISR] %s exception!\r\n", ExceptionStrings[Exception]);
|
||||
}
|
||||
}
|
||||
|
||||
/* The common handler for exceptions that throw error codes, which give us useful insight
|
||||
into what went wrong. In pure Curle style, though, we just ignore the error code. */
|
||||
void ISR_Error_Common(INTERRUPT_FRAME* Frame, size_t ErrorCode, size_t Exception) {
|
||||
|
||||
UNUSED(Frame);
|
||||
|
||||
if (Exception < 32) {
|
||||
SetForegroundColor(0x0000FF00);
|
||||
FillScreen(0x0000FF00);
|
||||
SerialPrintf("[ ISR] ISR Error %d raised, EC %d!\r\n", Exception, ErrorCode);
|
||||
SerialPrintf("[ ISR] %s exception!\r\n", ExceptionStrings[Exception]);
|
||||
while (true) { }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Likewise, this function is common to all IRQ handlers. It calls the assigned routine,
|
||||
which was set up earlier by irq_install.*/
|
||||
void IRQ_Common(INTERRUPT_FRAME* Frame, size_t Interrupt) {
|
||||
// First we need to define a function pointer..
|
||||
void (* Handler)(INTERRUPT_FRAME* Frame);
|
||||
|
||||
/* We set all uninitialized routines to 0, so the if(handler) check here allows us to
|
||||
safely tell whether we've actually got something for this IRQ. */
|
||||
Handler = IRQ_Handlers[Interrupt];
|
||||
// If there's something there,
|
||||
if (Handler) {
|
||||
SerialPrintf("[ IRQ] IRQ %d raised!\r\n", Interrupt);
|
||||
// Call the handler.
|
||||
Handler(Frame);
|
||||
}
|
||||
/* The Slave PIC must be told it's been read in order to receive another 8+ IRQ. */
|
||||
if (Interrupt > 7)
|
||||
WritePort(0xA0, 0x20, 1);
|
||||
|
||||
/* In either case, we tell the Master PIC it's been read to receive any IRQ. */
|
||||
WritePort(0x20, 0x20, 1);
|
||||
|
||||
}
|
||||
|
||||
/* However, in order to actually be able to receive IRQs, we need to remap the PICs. */
|
||||
void RemapIRQControllers() {
|
||||
/* 0x20 is the Master PIC,
|
||||
0xA0 is the Slave PIC. */
|
||||
WritePort(0x20, 0x11, 1);
|
||||
WritePort(0xA0, 0x11, 1);
|
||||
WritePort(0x21, 0x20, 1);
|
||||
WritePort(0xA1, 0x28, 1);
|
||||
WritePort(0x21, 0x04, 1);
|
||||
WritePort(0xA1, 0x02, 1);
|
||||
WritePort(0x21, 0x01, 1);
|
||||
WritePort(0xA1, 0x01, 1);
|
||||
WritePort(0x21, 0x0, 1);
|
||||
WritePort(0xA1, 0x0, 1);
|
||||
}
|
||||
|
||||
/* In order to actually handle the IRQs, though, we need to tell the kernel *where* the handlers are. */
|
||||
/* A simple wrapper that adds a function pointer to the IRQ array. */
|
||||
void InstallIRQ(int IRQ, void (* Handler)(INTERRUPT_FRAME* Frame)) {
|
||||
IRQ_Handlers[IRQ] = Handler;
|
||||
}
|
||||
|
||||
/* A simple wrapper that unlinks a function pointer, rendering the IRQ unused. */
|
||||
void UninstallIRQHandler(int IRQ) {
|
||||
IRQ_Handlers[IRQ] = NULL; // 0 is used in the common check to make sure that the function is callable.
|
||||
// This removes this IRQ from that check, ergo the function will no longer be called.
|
||||
}
|
||||
|
||||
void EmptyIRQ(INTERRUPT_FRAME* frame) {
|
||||
|
||||
UNUSED(frame);
|
||||
|
||||
// Flash the borders green, then back to blue
|
||||
SetForegroundColor(0x0000FF00);
|
||||
for (size_t y = 0; y < bootldr.fb_height; y++) {
|
||||
for (size_t x = 0; x < 20; x++) {
|
||||
DrawPixel(x, y);
|
||||
}
|
||||
|
||||
for (size_t x = (bootldr.fb_width - 20); x < bootldr.fb_width; x++) {
|
||||
DrawPixel(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t x = 0; x < bootldr.fb_width; x++) {
|
||||
for (size_t y = 0; y < 20; y++) {
|
||||
DrawPixel(x, y);
|
||||
}
|
||||
|
||||
for (size_t y = (bootldr.fb_height - 20); y < bootldr.fb_height; y++) {
|
||||
DrawPixel(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 100000; i++) { }
|
||||
|
||||
SetForegroundColor(0x000000FF);
|
||||
for (size_t y = 0; y < bootldr.fb_height; y++) {
|
||||
for (size_t x = 0; x < 20; x++) {
|
||||
DrawPixel(x, y);
|
||||
}
|
||||
|
||||
for (size_t x = (bootldr.fb_width - 20); x < bootldr.fb_width; x++) {
|
||||
DrawPixel(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t x = 0; x < bootldr.fb_width; x++) {
|
||||
for (size_t y = 0; y < 20; y++) {
|
||||
DrawPixel(x, y);
|
||||
}
|
||||
|
||||
for (size_t y = (bootldr.fb_height - 20); y < bootldr.fb_height; y++) {
|
||||
DrawPixel(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void KeyboardCallback(INTERRUPT_FRAME* frame) {
|
||||
UNUSED(frame);
|
||||
|
||||
uint8_t msg = ReadPort(0x60, 1);
|
||||
|
||||
UpdateKeyboard(msg);
|
||||
|
||||
WaitFor8042();
|
||||
}
|
||||
|
||||
void InitInterrupts() {
|
||||
size_t RFLAGS = ReadControlRegister('f');
|
||||
|
||||
if (!(RFLAGS & (1 << 9))) {
|
||||
WriteControlRegister('f', RFLAGS | (1 << 9));
|
||||
}
|
||||
|
||||
|
||||
InstallIRQ(1, &KeyboardCallback);
|
||||
|
||||
Send8042(0xF002);
|
||||
|
||||
__asm__ __volatile__("sti");
|
||||
}
|
||||
|
||||
|
||||
/* The interrupt numbers, their meanings, and
|
||||
* special information is laid out below:
|
||||
*
|
||||
* 0 - Divide by Zero
|
||||
* 1 - Debug
|
||||
* 2 - Non-Maskable
|
||||
* 3 - Breakpoint
|
||||
* 4 - Into Detected Overflow
|
||||
* 5 - Out of Bounds
|
||||
* 6 - Invalid Opcode
|
||||
* 7 - No Coprocessor
|
||||
* 8 - Double Fault * (With Error)
|
||||
* 9 - Coprocessor Segment Overrun
|
||||
* 10 - Bad TSS * (With Error)
|
||||
* 11 - Segment Not Present * (With Error)
|
||||
* 12 - Stack Fault * (With Error)
|
||||
* 13 - General Protection Fault * (With Error)
|
||||
* 14 - Page Fault * (With Error)
|
||||
* 15 - Unknown Interrupt
|
||||
* 16 - Coprocessor Fault
|
||||
* 17 - Alignment Check
|
||||
* 18 - Machine Check
|
||||
* 19 to 31 - Reserved
|
||||
*/
|
||||
|
||||
__attribute__((interrupt)) void ISR0Handler(INTERRUPT_FRAME* Frame) {
|
||||
|
||||
ISR_Common(Frame, 0);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR1Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 1);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR2Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 2);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR3Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 3);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR4Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 4);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR5Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 5);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR6Handler(INTERRUPT_FRAME* Frame) {
|
||||
|
||||
__asm__ __volatile__("sti");
|
||||
|
||||
SerialPrintf("[FAULT] Invalid Opcode!\n");
|
||||
size_t retAddr = 0;
|
||||
size_t opcodeAddr = Frame->rip;
|
||||
|
||||
__asm__ __volatile__("popq %%rax\n\t" "pushq %%rax": "=a" (retAddr) : :);
|
||||
SerialPrintf("[FAULT] Opcode is at 0x%x, called from 0x%p\r\n", opcodeAddr, retAddr);
|
||||
Printf("Invalid Opcode: 0x%p\n", opcodeAddr);
|
||||
|
||||
Core::GetCurrent()->StackTrace(15);
|
||||
|
||||
for (;;) { }
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR7Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 7);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR8Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
|
||||
ISR_Error_Common(Frame, ErrorCode, 8);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR9Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 9);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR10Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
|
||||
ISR_Error_Common(Frame, ErrorCode, 10);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR11Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
|
||||
ISR_Error_Common(Frame, ErrorCode, 11);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR12Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
|
||||
ISR_Error_Common(Frame, ErrorCode, 12);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR13Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
|
||||
|
||||
SerialPrintf("\r\n\n[ GPF] RIP: 0x%p, CS: 0x%x, FLAGS: 0x%p, RSP: 0x%x, SS: 0x%x\r\n", Frame->rip, Frame->cs,
|
||||
Frame->rflags, Frame->rsp, Frame->ss);
|
||||
|
||||
Core::GetCurrent()->StackTrace(6);
|
||||
|
||||
ISR_Error_Common(Frame, ErrorCode, 13); // General Protection
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR14Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
|
||||
__asm__ __volatile__("sti");
|
||||
|
||||
SerialPrintf("\r\n\n\n[FAULT] Page fault! Caused by {\r\n");
|
||||
|
||||
//size_t FaultAddr = ReadControlRegister(2);
|
||||
uint8_t FaultPres = ErrorCode & 0x1;
|
||||
uint8_t FaultRW = ErrorCode & 0x2;
|
||||
uint8_t FaultUser = ErrorCode & 0x4;
|
||||
uint8_t FaultReserved = ErrorCode & 0x8;
|
||||
uint8_t FaultInst = ErrorCode & 0x10;
|
||||
|
||||
if (!FaultPres) SerialPrintf("[FAULT] Accessed a page that isn't present.\r\n");
|
||||
if (FaultRW || FaultUser) SerialPrintf("[FAULT] Accessed a Read-Only page.\r\n");
|
||||
if (FaultReserved) SerialPrintf("[FAULT] Overwrote reserved bits.\r\n");
|
||||
if (FaultInst) SerialPrintf("[FAULT] \"Instruction Fetch\"");
|
||||
|
||||
SerialPrintf("[FAULT] } at address\n[FAULT] 0x%p\r\n\n", ReadControlRegister(2));
|
||||
|
||||
Core::GetCurrent()->StackTrace(6);
|
||||
ISR_Error_Common(Frame, ErrorCode, 14); // Page Fault
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR15Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 15);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR16Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 16);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR17Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
|
||||
ISR_Error_Common(Frame, ErrorCode, 17);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR18Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 18);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR19Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 19);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR20Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 20);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR21Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 21);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR22Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 22);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR23Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 23);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR24Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 24);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR25Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 25);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR26Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 26);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR27Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 27);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR28Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 28);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR29Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 29);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR30Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
|
||||
ISR_Error_Common(Frame, ErrorCode, 30);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ISR31Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 31);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void ReservedISRHandler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 33); // if < 32, isn't handled.
|
||||
// Effectively disables this ISR.
|
||||
}
|
||||
|
||||
|
||||
__attribute__((interrupt)) void IRQ0Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 0);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void IRQ1Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 1); // Keyboard handler
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void IRQ2Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 2);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void IRQ3Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 3);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void IRQ4Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 4);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void IRQ5Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 5);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void IRQ6Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 6);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void IRQ7Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 7);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void IRQ8Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 8);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void IRQ9Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 9);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void IRQ10Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 10);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void IRQ11Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 11);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void IRQ12Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 12);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void IRQ13Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 13);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void IRQ14Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 14);
|
||||
}
|
||||
|
||||
__attribute__((interrupt)) void IRQ15Handler(INTERRUPT_FRAME* Frame) {
|
||||
IRQ_Common(Frame, 15);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -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 {
|
||||
|
@ -226,11 +225,11 @@ 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)
|
||||
);
|
||||
((
|
||||
CAST(ptrdiff_t, Pointer)
|
||||
+ (Alignment - 1))
|
||||
& ~(Alignment - 1)
|
||||
);
|
||||
ASSERT(((Alignment & (Alignment - 1)) == 0), "AlignPointer: Requested alignment not aligned!");
|
||||
|
||||
return CAST(void*, AlignedPointer);
|
||||
|
@ -244,10 +243,10 @@ 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);
|
||||
|
||||
}
|
||||
|
@ -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,11 +287,11 @@ 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);
|
||||
|
@ -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,7 +380,8 @@ static block_header_t* SplitBlock(block_header_t* Block, size_t NewSize) {
|
|||
|
||||
const size_t RemainingSize = BlockSize(Block) - (NewSize + BLOCK_OVERHEAD);
|
||||
|
||||
ASSERT(WhereBlock(Overlap) == AlignPointer(WhereBlock(Overlap), ALIGN_SIZE), "SplitBlock: Requested size results in intermediary block which is not aligned!");
|
||||
ASSERT(WhereBlock(Overlap) == AlignPointer(WhereBlock(Overlap), ALIGN_SIZE),
|
||||
"SplitBlock: Requested size results in intermediary block which is not aligned!");
|
||||
|
||||
ASSERT(BlockSize(Block) == RemainingSize + NewSize + BLOCK_OVERHEAD, "SplitBlock: Maths error!");
|
||||
|
||||
|
@ -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,7 +421,7 @@ 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);
|
||||
|
@ -428,7 +433,7 @@ static block_header_t* MergeNextBlockDown(allocator_control_t* Controller, 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);
|
||||
|
@ -604,9 +610,9 @@ mempool_t AddPoolToAllocator(allocator_t Allocator, void* Address, size_t Size)
|
|||
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,30 +625,30 @@ 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;
|
||||
/* 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;
|
||||
TestsFailed += (Alloc_FindLastOne_64(0x80000000) == 31) ? 0 : 0x100;
|
||||
TestsFailed += (Alloc_FindLastOne_64(0x100000000) == 32) ? 0 : 0x200;
|
||||
TestsFailed += (Alloc_FindLastOne_64(0xffffffffffffffff) == 63) ? 0 : 0x400;
|
||||
|
||||
if (TestsFailed) {
|
||||
SerialPrintf("TestBuiltins: %x ffs/fls tests failed.\n", TestsFailed);
|
||||
}
|
||||
if (TestsFailed) {
|
||||
SerialPrintf("TestBuiltins: %x ffs/fls tests failed.\n", TestsFailed);
|
||||
}
|
||||
|
||||
return TestsFailed;
|
||||
return TestsFailed;
|
||||
}
|
||||
|
||||
allocator_t CreateAllocator(void* Memory) {
|
||||
if(TestBuiltins())
|
||||
if (TestBuiltins())
|
||||
return 0;
|
||||
|
||||
if (((ptrdiff_t) Memory % ALIGN_SIZE) != 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,7 +765,7 @@ 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
|
||||
|
@ -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);
|
||||
}
|
|
@ -1,867 +0,0 @@
|
|||
#include <stdint.h>
|
||||
#include <kernel/system/memory.h>
|
||||
|
||||
/** Durand's Amazing Super Duper Memory functions. */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define VERSION "1.1"
|
||||
#define ALIGNMENT 16ul//4ul ///< This is the byte alignment that memory must be allocated on. IMPORTANT for GTK and other stuff.
|
||||
|
||||
#define ALIGN_TYPE char ///unsigned char[16] /// unsigned short
|
||||
#define ALIGN_INFO sizeof(ALIGN_TYPE)*16 ///< Alignment information is stored right before the pointer. This is the number of bytes of information stored there.
|
||||
|
||||
|
||||
#define USE_CASE1
|
||||
#define USE_CASE2
|
||||
#define USE_CASE3
|
||||
#define USE_CASE4
|
||||
#define USE_CASE5
|
||||
|
||||
extern address_space_t KernelAddressSpace;
|
||||
|
||||
/** This function is supposed to lock the memory data structures. It
|
||||
* could be as simple as disabling interrupts or acquiring a spinlock.
|
||||
* It's up to you to decide.
|
||||
*
|
||||
* \return 0 if the lock was acquired successfully. Anything else is
|
||||
* failure.
|
||||
*/
|
||||
static int liballoc_lock() {
|
||||
return TicketAttemptLock(&KernelAddressSpace.Lock) ? 0 : 1;
|
||||
}
|
||||
|
||||
/** This function unlocks what was previously locked by the liballoc_lock
|
||||
* function. If it disabled interrupts, it enables interrupts. If it
|
||||
* had acquiried a spinlock, it releases the spinlock. etc.
|
||||
*
|
||||
*/
|
||||
static void liballoc_unlock() {
|
||||
TicketUnlock(&KernelAddressSpace.Lock);
|
||||
}
|
||||
|
||||
/** This is the hook into the local system which allocates pages. It
|
||||
* accepts an integer parameter which is the number of pages
|
||||
* required. The page size was set up in the liballoc_init function.
|
||||
*
|
||||
* \return NULL if the pages were not allocated.
|
||||
* \return A pointer to the allocated memory.
|
||||
*/
|
||||
static void* liballoc_alloc(size_t count) {
|
||||
return (void*) PhysAllocateZeroMem(count * PAGE_SIZE);
|
||||
}
|
||||
|
||||
/** This frees previously allocated memory. The void* parameter passed
|
||||
* to the function is the exact same value returned from a previous
|
||||
* liballoc_alloc call.
|
||||
*
|
||||
* The integer value is the number of pages to free.
|
||||
*
|
||||
* \return 0 if the memory was successfully freed.
|
||||
*/
|
||||
static int liballoc_free(void* ptr, size_t count) {
|
||||
PhysFreeMem(ptr, count * PAGE_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/** This macro will conveniently align our pointer upwards */
|
||||
#define ALIGN( ptr ) \
|
||||
if ( ALIGNMENT > 1 ) \
|
||||
{ \
|
||||
uintptr_t diff; \
|
||||
ptr = (void*)((uintptr_t)ptr + ALIGN_INFO); \
|
||||
diff = (uintptr_t)ptr & (ALIGNMENT-1); \
|
||||
if ( diff != 0 ) \
|
||||
{ \
|
||||
diff = ALIGNMENT - diff; \
|
||||
ptr = (void*)((uintptr_t)ptr + diff); \
|
||||
} \
|
||||
*((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)) = \
|
||||
diff + ALIGN_INFO; \
|
||||
}
|
||||
|
||||
|
||||
#define UNALIGN( ptr ) \
|
||||
if ( ALIGNMENT > 1 ) \
|
||||
{ \
|
||||
uintptr_t diff = *((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)); \
|
||||
if ( diff < (ALIGNMENT + ALIGN_INFO) ) \
|
||||
{ \
|
||||
ptr = (void*)((uintptr_t)ptr - diff); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define LIBALLOC_MAGIC 0xc001c0de
|
||||
#define LIBALLOC_DEAD 0xdeaddead
|
||||
|
||||
#if defined DEBUG || defined INFO
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define FLUSH() fflush( stdout )
|
||||
|
||||
#endif
|
||||
|
||||
/** A structure found at the top of all system allocated
|
||||
* memory blocks. It details the usage of the memory block.
|
||||
*/
|
||||
struct liballoc_major
|
||||
{
|
||||
struct liballoc_major *prev; ///< Linked list information.
|
||||
struct liballoc_major *next; ///< Linked list information.
|
||||
unsigned int pages; ///< The number of pages in the block.
|
||||
unsigned int size; ///< The number of pages in the block.
|
||||
unsigned int usage; ///< The number of bytes used in the block.
|
||||
struct liballoc_minor *first; ///< A pointer to the first allocated memory in the block.
|
||||
};
|
||||
|
||||
|
||||
/** This is a structure found at the beginning of all
|
||||
* sections in a major block which were allocated by a
|
||||
* malloc, calloc, realloc call.
|
||||
*/
|
||||
struct liballoc_minor
|
||||
{
|
||||
struct liballoc_minor *prev; ///< Linked list information.
|
||||
struct liballoc_minor *next; ///< Linked list information.
|
||||
struct liballoc_major *block; ///< The owning block. A pointer to the major structure.
|
||||
unsigned int magic; ///< A magic number to idenfity correctness.
|
||||
unsigned int size; ///< The size of the memory allocated. Could be 1 byte or more.
|
||||
unsigned int req_size; ///< The size of memory requested.
|
||||
};
|
||||
|
||||
|
||||
static struct liballoc_major *l_memRoot = NULL; ///< The root memory block acquired from the system.
|
||||
static struct liballoc_major *l_bestBet = NULL; ///< The major with the most free memory.
|
||||
|
||||
static unsigned int l_pageSize = 4096; ///< The size of an individual page. Set up in liballoc_init.
|
||||
static unsigned int l_pageCount = 16; ///< The number of pages to request per chunk. Set up in liballoc_init.
|
||||
static unsigned long long l_allocated = 0; ///< Running total of allocated memory.
|
||||
static unsigned long long l_inuse = 0; ///< Running total of used memory.
|
||||
|
||||
|
||||
static long long l_warningCount = 0; ///< Number of warnings encountered
|
||||
static long long l_errorCount = 0; ///< Number of actual errors
|
||||
static long long l_possibleOverruns = 0; ///< Number of possible overruns
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// *********** HELPER FUNCTIONS *******************************
|
||||
|
||||
static void *liballoc_memset(void* s, int c, size_t n)
|
||||
{
|
||||
unsigned int i;
|
||||
for ( i = 0; i < n ; i++)
|
||||
((char*)s)[i] = c;
|
||||
|
||||
return s;
|
||||
}
|
||||
static void* liballoc_memcpy(void* s1, const void* s2, size_t n)
|
||||
{
|
||||
char *cdest;
|
||||
char *csrc;
|
||||
unsigned int *ldest = (unsigned int*)s1;
|
||||
unsigned int *lsrc = (unsigned int*)s2;
|
||||
|
||||
while ( n >= sizeof(unsigned int) )
|
||||
{
|
||||
*ldest++ = *lsrc++;
|
||||
n -= sizeof(unsigned int);
|
||||
}
|
||||
|
||||
cdest = (char*)ldest;
|
||||
csrc = (char*)lsrc;
|
||||
|
||||
while ( n > 0 )
|
||||
{
|
||||
*cdest++ = *csrc++;
|
||||
n -= 1;
|
||||
}
|
||||
|
||||
return s1;
|
||||
}
|
||||
|
||||
|
||||
#if defined DEBUG || defined INFO
|
||||
static void liballoc_dump()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
struct liballoc_major *maj = l_memRoot;
|
||||
struct liballoc_minor *min = NULL;
|
||||
#endif
|
||||
|
||||
printf( "liballoc: ------ Memory data ---------------\n");
|
||||
printf( "liballoc: System memory allocated: %i bytes\n", l_allocated );
|
||||
printf( "liballoc: Memory in used (malloc'ed): %i bytes\n", l_inuse );
|
||||
printf( "liballoc: Warning count: %i\n", l_warningCount );
|
||||
printf( "liballoc: Error count: %i\n", l_errorCount );
|
||||
printf( "liballoc: Possible overruns: %i\n", l_possibleOverruns );
|
||||
|
||||
#ifdef DEBUG
|
||||
while ( maj != NULL )
|
||||
{
|
||||
printf( "liballoc: %x: total = %i, used = %i\n",
|
||||
maj,
|
||||
maj->size,
|
||||
maj->usage );
|
||||
|
||||
min = maj->first;
|
||||
while ( min != NULL )
|
||||
{
|
||||
printf( "liballoc: %x: %i bytes\n",
|
||||
min,
|
||||
min->size );
|
||||
min = min->next;
|
||||
}
|
||||
|
||||
maj = maj->next;
|
||||
}
|
||||
#endif
|
||||
|
||||
FLUSH();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// ***************************************************************
|
||||
|
||||
static struct liballoc_major *allocate_new_page( unsigned int size )
|
||||
{
|
||||
unsigned int st;
|
||||
struct liballoc_major *maj;
|
||||
|
||||
// This is how much space is required.
|
||||
st = size + sizeof(struct liballoc_major);
|
||||
st += sizeof(struct liballoc_minor);
|
||||
|
||||
// Perfect amount of space?
|
||||
if ( (st % l_pageSize) == 0 )
|
||||
st = st / (l_pageSize);
|
||||
else
|
||||
st = st / (l_pageSize) + 1;
|
||||
// No, add the buffer.
|
||||
|
||||
|
||||
// Make sure it's >= the minimum size.
|
||||
if ( st < l_pageCount ) st = l_pageCount;
|
||||
|
||||
maj = (struct liballoc_major*)liballoc_alloc( st );
|
||||
|
||||
if ( maj == NULL )
|
||||
{
|
||||
l_warningCount += 1;
|
||||
#if defined DEBUG || defined INFO
|
||||
printf( "liballoc: WARNING: liballoc_alloc( %i ) return NULL\n", st );
|
||||
FLUSH();
|
||||
#endif
|
||||
return NULL; // uh oh, we ran out of memory.
|
||||
}
|
||||
|
||||
maj->prev = NULL;
|
||||
maj->next = NULL;
|
||||
maj->pages = st;
|
||||
maj->size = st * l_pageSize;
|
||||
maj->usage = sizeof(struct liballoc_major);
|
||||
maj->first = NULL;
|
||||
|
||||
l_allocated += maj->size;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "liballoc: Resource allocated %x of %i pages (%i bytes) for %i size.\n", maj, st, maj->size, size );
|
||||
|
||||
printf( "liballoc: Total memory usage = %i KB\n", (int)((l_allocated / (1024))) );
|
||||
FLUSH();
|
||||
#endif
|
||||
|
||||
|
||||
return maj;
|
||||
}
|
||||
|
||||
|
||||
void *PREFIX(malloc)(size_t req_size)
|
||||
{
|
||||
int startedBet = 0;
|
||||
unsigned long long bestSize = 0;
|
||||
void *p = NULL;
|
||||
uintptr_t diff;
|
||||
struct liballoc_major *maj;
|
||||
struct liballoc_minor *min;
|
||||
struct liballoc_minor *new_min;
|
||||
unsigned long size = req_size;
|
||||
|
||||
// For alignment, we adjust size so there's enough space to align.
|
||||
if ( ALIGNMENT > 1 )
|
||||
{
|
||||
size += ALIGNMENT + ALIGN_INFO;
|
||||
}
|
||||
// So, ideally, we really want an alignment of 0 or 1 in order
|
||||
// to save space.
|
||||
|
||||
liballoc_lock();
|
||||
|
||||
if ( size == 0 )
|
||||
{
|
||||
l_warningCount += 1;
|
||||
#if defined DEBUG || defined INFO
|
||||
printf( "liballoc: WARNING: alloc( 0 ) called from %x\n",
|
||||
__builtin_return_address(0) );
|
||||
FLUSH();
|
||||
#endif
|
||||
liballoc_unlock();
|
||||
return PREFIX(malloc)(1);
|
||||
}
|
||||
|
||||
|
||||
if ( l_memRoot == NULL )
|
||||
{
|
||||
#if defined DEBUG || defined INFO
|
||||
#ifdef DEBUG
|
||||
printf( "liballoc: initialization of liballoc " VERSION "\n" );
|
||||
#endif
|
||||
atexit( liballoc_dump );
|
||||
FLUSH();
|
||||
#endif
|
||||
|
||||
// This is the first time we are being used.
|
||||
l_memRoot = allocate_new_page( size );
|
||||
if ( l_memRoot == NULL )
|
||||
{
|
||||
liballoc_unlock();
|
||||
#ifdef DEBUG
|
||||
printf( "liballoc: initial l_memRoot initialization failed\n", p);
|
||||
FLUSH();
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "liballoc: set up first memory major %x\n", l_memRoot );
|
||||
FLUSH();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "liballoc: %x PREFIX(malloc)( %i ): ",
|
||||
__builtin_return_address(0),
|
||||
size );
|
||||
FLUSH();
|
||||
#endif
|
||||
|
||||
// Now we need to bounce through every major and find enough space....
|
||||
|
||||
maj = l_memRoot;
|
||||
startedBet = 0;
|
||||
|
||||
// Start at the best bet....
|
||||
if ( l_bestBet != NULL )
|
||||
{
|
||||
bestSize = l_bestBet->size - l_bestBet->usage;
|
||||
|
||||
if ( bestSize > (size + sizeof(struct liballoc_minor)))
|
||||
{
|
||||
maj = l_bestBet;
|
||||
startedBet = 1;
|
||||
}
|
||||
}
|
||||
|
||||
while ( maj != NULL )
|
||||
{
|
||||
diff = maj->size - maj->usage;
|
||||
// free memory in the block
|
||||
|
||||
if ( bestSize < diff )
|
||||
{
|
||||
// Hmm.. this one has more memory then our bestBet. Remember!
|
||||
l_bestBet = maj;
|
||||
bestSize = diff;
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_CASE1
|
||||
|
||||
// CASE 1: There is not enough space in this major block.
|
||||
if ( diff < (size + sizeof( struct liballoc_minor )) )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf( "CASE 1: Insufficient space in block %x\n", maj);
|
||||
FLUSH();
|
||||
#endif
|
||||
|
||||
// Another major block next to this one?
|
||||
if ( maj->next != NULL )
|
||||
{
|
||||
maj = maj->next; // Hop to that one.
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( startedBet == 1 ) // If we started at the best bet,
|
||||
{ // let's start all over again.
|
||||
maj = l_memRoot;
|
||||
startedBet = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create a new major block next to this one and...
|
||||
maj->next = allocate_new_page( size ); // next one will be okay.
|
||||
if ( maj->next == NULL ) break; // no more memory.
|
||||
maj->next->prev = maj;
|
||||
maj = maj->next;
|
||||
|
||||
// .. fall through to CASE 2 ..
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_CASE2
|
||||
|
||||
// CASE 2: It's a brand new block.
|
||||
if ( maj->first == NULL )
|
||||
{
|
||||
maj->first = (struct liballoc_minor*)((uintptr_t)maj + sizeof(struct liballoc_major) );
|
||||
|
||||
|
||||
maj->first->magic = LIBALLOC_MAGIC;
|
||||
maj->first->prev = NULL;
|
||||
maj->first->next = NULL;
|
||||
maj->first->block = maj;
|
||||
maj->first->size = size;
|
||||
maj->first->req_size = req_size;
|
||||
maj->usage += size + sizeof( struct liballoc_minor );
|
||||
|
||||
|
||||
l_inuse += size;
|
||||
|
||||
|
||||
p = (void*)((uintptr_t)(maj->first) + sizeof( struct liballoc_minor ));
|
||||
|
||||
ALIGN( p );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "CASE 2: returning %x\n", p);
|
||||
FLUSH();
|
||||
#endif
|
||||
liballoc_unlock(); // release the lock
|
||||
return p;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_CASE3
|
||||
|
||||
// CASE 3: Block in use and enough space at the start of the block.
|
||||
diff = (uintptr_t)(maj->first);
|
||||
diff -= (uintptr_t)maj;
|
||||
diff -= sizeof(struct liballoc_major);
|
||||
|
||||
if ( diff >= (size + sizeof(struct liballoc_minor)) )
|
||||
{
|
||||
// Yes, space in front. Squeeze in.
|
||||
maj->first->prev = (struct liballoc_minor*)((uintptr_t)maj + sizeof(struct liballoc_major) );
|
||||
maj->first->prev->next = maj->first;
|
||||
maj->first = maj->first->prev;
|
||||
|
||||
maj->first->magic = LIBALLOC_MAGIC;
|
||||
maj->first->prev = NULL;
|
||||
maj->first->block = maj;
|
||||
maj->first->size = size;
|
||||
maj->first->req_size = req_size;
|
||||
maj->usage += size + sizeof( struct liballoc_minor );
|
||||
|
||||
l_inuse += size;
|
||||
|
||||
p = (void*)((uintptr_t)(maj->first) + sizeof( struct liballoc_minor ));
|
||||
ALIGN( p );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "CASE 3: returning %x\n", p);
|
||||
FLUSH();
|
||||
#endif
|
||||
liballoc_unlock(); // release the lock
|
||||
return p;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USE_CASE4
|
||||
|
||||
// CASE 4: There is enough space in this block. But is it contiguous?
|
||||
min = maj->first;
|
||||
|
||||
// Looping within the block now...
|
||||
while ( min != NULL )
|
||||
{
|
||||
// CASE 4.1: End of minors in a block. Space from last and end?
|
||||
if ( min->next == NULL )
|
||||
{
|
||||
// the rest of this block is free... is it big enough?
|
||||
diff = (uintptr_t)(maj) + maj->size;
|
||||
diff -= (uintptr_t)min;
|
||||
diff -= sizeof( struct liballoc_minor );
|
||||
diff -= min->size;
|
||||
// minus already existing usage..
|
||||
|
||||
if ( diff >= (size + sizeof( struct liballoc_minor )) )
|
||||
{
|
||||
// yay....
|
||||
min->next = (struct liballoc_minor*)((uintptr_t)min + sizeof( struct liballoc_minor ) + min->size);
|
||||
min->next->prev = min;
|
||||
min = min->next;
|
||||
min->next = NULL;
|
||||
min->magic = LIBALLOC_MAGIC;
|
||||
min->block = maj;
|
||||
min->size = size;
|
||||
min->req_size = req_size;
|
||||
maj->usage += size + sizeof( struct liballoc_minor );
|
||||
|
||||
l_inuse += size;
|
||||
|
||||
p = (void*)((uintptr_t)min + sizeof( struct liballoc_minor ));
|
||||
ALIGN( p );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "CASE 4.1: returning %x\n", p);
|
||||
FLUSH();
|
||||
#endif
|
||||
liballoc_unlock(); // release the lock
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// CASE 4.2: Is there space between two minors?
|
||||
if ( min->next != NULL )
|
||||
{
|
||||
// is the difference between here and next big enough?
|
||||
diff = (uintptr_t)(min->next);
|
||||
diff -= (uintptr_t)min;
|
||||
diff -= sizeof( struct liballoc_minor );
|
||||
diff -= min->size;
|
||||
// minus our existing usage.
|
||||
|
||||
if ( diff >= (size + sizeof( struct liballoc_minor )) )
|
||||
{
|
||||
// yay......
|
||||
new_min = (struct liballoc_minor*)((uintptr_t)min + sizeof( struct liballoc_minor ) + min->size);
|
||||
|
||||
new_min->magic = LIBALLOC_MAGIC;
|
||||
new_min->next = min->next;
|
||||
new_min->prev = min;
|
||||
new_min->size = size;
|
||||
new_min->req_size = req_size;
|
||||
new_min->block = maj;
|
||||
min->next->prev = new_min;
|
||||
min->next = new_min;
|
||||
maj->usage += size + sizeof( struct liballoc_minor );
|
||||
|
||||
l_inuse += size;
|
||||
|
||||
p = (void*)((uintptr_t)new_min + sizeof( struct liballoc_minor ));
|
||||
ALIGN( p );
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "CASE 4.2: returning %x\n", p);
|
||||
FLUSH();
|
||||
#endif
|
||||
|
||||
liballoc_unlock(); // release the lock
|
||||
return p;
|
||||
}
|
||||
} // min->next != NULL
|
||||
|
||||
min = min->next;
|
||||
} // while min != NULL ...
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_CASE5
|
||||
|
||||
// CASE 5: Block full! Ensure next block and loop.
|
||||
if ( maj->next == NULL )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf( "CASE 5: block full\n");
|
||||
FLUSH();
|
||||
#endif
|
||||
|
||||
if ( startedBet == 1 )
|
||||
{
|
||||
maj = l_memRoot;
|
||||
startedBet = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// we've run out. we need more...
|
||||
maj->next = allocate_new_page( size ); // next one guaranteed to be okay
|
||||
if ( maj->next == NULL ) break; // uh oh, no more memory.....
|
||||
maj->next->prev = maj;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
maj = maj->next;
|
||||
} // while (maj != NULL)
|
||||
|
||||
|
||||
|
||||
liballoc_unlock(); // release the lock
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "All cases exhausted. No memory available.\n");
|
||||
FLUSH();
|
||||
#endif
|
||||
#if defined DEBUG || defined INFO
|
||||
printf( "liballoc: WARNING: PREFIX(malloc)( %i ) returning NULL.\n", size);
|
||||
liballoc_dump();
|
||||
FLUSH();
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void PREFIX(free)(void *ptr)
|
||||
{
|
||||
struct liballoc_minor *min;
|
||||
struct liballoc_major *maj;
|
||||
|
||||
if ( ptr == NULL )
|
||||
{
|
||||
l_warningCount += 1;
|
||||
#if defined DEBUG || defined INFO
|
||||
printf( "liballoc: WARNING: PREFIX(free)( NULL ) called from %x\n",
|
||||
__builtin_return_address(0) );
|
||||
FLUSH();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
UNALIGN( ptr );
|
||||
|
||||
liballoc_lock(); // lockit
|
||||
|
||||
|
||||
min = (struct liballoc_minor*)((uintptr_t)ptr - sizeof( struct liballoc_minor ));
|
||||
|
||||
|
||||
if ( min->magic != LIBALLOC_MAGIC )
|
||||
{
|
||||
l_errorCount += 1;
|
||||
|
||||
// Check for overrun errors. For all bytes of LIBALLOC_MAGIC
|
||||
if (
|
||||
((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF)) ||
|
||||
((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF)) ||
|
||||
((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF))
|
||||
)
|
||||
{
|
||||
l_possibleOverruns += 1;
|
||||
#if defined DEBUG || defined INFO
|
||||
printf( "liballoc: ERROR: Possible 1-3 byte overrun for magic %x != %x\n",
|
||||
min->magic,
|
||||
LIBALLOC_MAGIC );
|
||||
FLUSH();
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( min->magic == LIBALLOC_DEAD )
|
||||
{
|
||||
#if defined DEBUG || defined INFO
|
||||
printf( "liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n",
|
||||
ptr,
|
||||
__builtin_return_address(0) );
|
||||
FLUSH();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined DEBUG || defined INFO
|
||||
printf( "liballoc: ERROR: Bad PREFIX(free)( %x ) called from %x\n",
|
||||
ptr,
|
||||
__builtin_return_address(0) );
|
||||
FLUSH();
|
||||
#endif
|
||||
}
|
||||
|
||||
// being lied to...
|
||||
liballoc_unlock(); // release the lock
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "liballoc: %x PREFIX(free)( %x ): ",
|
||||
__builtin_return_address( 0 ),
|
||||
ptr );
|
||||
FLUSH();
|
||||
#endif
|
||||
|
||||
|
||||
maj = min->block;
|
||||
|
||||
l_inuse -= min->size;
|
||||
|
||||
maj->usage -= (min->size + sizeof( struct liballoc_minor ));
|
||||
min->magic = LIBALLOC_DEAD; // No mojo.
|
||||
|
||||
if ( min->next != NULL ) min->next->prev = min->prev;
|
||||
if ( min->prev != NULL ) min->prev->next = min->next;
|
||||
|
||||
if ( min->prev == NULL ) maj->first = min->next;
|
||||
// Might empty the block. This was the first
|
||||
// minor.
|
||||
|
||||
|
||||
// We need to clean up after the majors now....
|
||||
|
||||
if ( maj->first == NULL ) // Block completely unused.
|
||||
{
|
||||
if ( l_memRoot == maj ) l_memRoot = maj->next;
|
||||
if ( l_bestBet == maj ) l_bestBet = NULL;
|
||||
if ( maj->prev != NULL ) maj->prev->next = maj->next;
|
||||
if ( maj->next != NULL ) maj->next->prev = maj->prev;
|
||||
l_allocated -= maj->size;
|
||||
|
||||
liballoc_free( maj, maj->pages );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( l_bestBet != NULL )
|
||||
{
|
||||
int bestSize = l_bestBet->size - l_bestBet->usage;
|
||||
int majSize = maj->size - maj->usage;
|
||||
|
||||
if ( majSize > bestSize ) l_bestBet = maj;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "OK\n");
|
||||
FLUSH();
|
||||
#endif
|
||||
|
||||
liballoc_unlock(); // release the lock
|
||||
}
|
||||
|
||||
void* PREFIX(calloc)(size_t nobj, size_t size)
|
||||
{
|
||||
int real_size;
|
||||
void *p;
|
||||
|
||||
real_size = nobj * size;
|
||||
|
||||
p = PREFIX(malloc)( real_size );
|
||||
|
||||
liballoc_memset( p, 0, real_size );
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void* PREFIX(realloc)(void *p, size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
struct liballoc_minor *min;
|
||||
unsigned int real_size;
|
||||
|
||||
// Honour the case of size == 0 => free old and return NULL
|
||||
if ( size == 0 )
|
||||
{
|
||||
PREFIX(free)( p );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// In the case of a NULL pointer, return a simple malloc.
|
||||
if ( p == NULL ) return PREFIX(malloc)( size );
|
||||
|
||||
// Unalign the pointer if required.
|
||||
ptr = p;
|
||||
UNALIGN(ptr);
|
||||
|
||||
liballoc_lock(); // lockit
|
||||
|
||||
min = (struct liballoc_minor*)((uintptr_t)ptr - sizeof( struct liballoc_minor ));
|
||||
|
||||
// Ensure it is a valid structure.
|
||||
if ( min->magic != LIBALLOC_MAGIC )
|
||||
{
|
||||
l_errorCount += 1;
|
||||
|
||||
// Check for overrun errors. For all bytes of LIBALLOC_MAGIC
|
||||
if (
|
||||
((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF)) ||
|
||||
((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF)) ||
|
||||
((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF))
|
||||
)
|
||||
{
|
||||
l_possibleOverruns += 1;
|
||||
#if defined DEBUG || defined INFO
|
||||
printf( "liballoc: ERROR: Possible 1-3 byte overrun for magic %x != %x\n",
|
||||
min->magic,
|
||||
LIBALLOC_MAGIC );
|
||||
FLUSH();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
if ( min->magic == LIBALLOC_DEAD )
|
||||
{
|
||||
#if defined DEBUG || defined INFO
|
||||
printf( "liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n",
|
||||
ptr,
|
||||
__builtin_return_address(0) );
|
||||
FLUSH();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined DEBUG || defined INFO
|
||||
printf( "liballoc: ERROR: Bad PREFIX(free)( %x ) called from %x\n",
|
||||
ptr,
|
||||
__builtin_return_address(0) );
|
||||
FLUSH();
|
||||
#endif
|
||||
}
|
||||
|
||||
// being lied to...
|
||||
liballoc_unlock(); // release the lock
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Definitely a memory block.
|
||||
|
||||
real_size = min->req_size;
|
||||
|
||||
if ( real_size >= size )
|
||||
{
|
||||
min->req_size = size;
|
||||
liballoc_unlock();
|
||||
return p;
|
||||
}
|
||||
|
||||
liballoc_unlock();
|
||||
|
||||
// If we got here then we're reallocating to a block bigger than us.
|
||||
ptr = PREFIX(malloc)( size ); // We need to allocate new memory
|
||||
liballoc_memcpy( ptr, p, real_size );
|
||||
PREFIX(free)( p );
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
827
src/system/memory/liballoc.cpp
Normal file
827
src/system/memory/liballoc.cpp
Normal file
|
@ -0,0 +1,827 @@
|
|||
#include <stdint.h>
|
||||
#include <kernel/system/memory.h>
|
||||
|
||||
/** Durand's Amazing Super Duper Memory functions. */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define VERSION "1.1"
|
||||
#define ALIGNMENT 16ul//4ul ///< This is the byte alignment that memory must be allocated on. IMPORTANT for GTK and other stuff.
|
||||
|
||||
#define ALIGN_TYPE char ///unsigned char[16] /// unsigned short
|
||||
#define ALIGN_INFO sizeof(ALIGN_TYPE)*16 ///< Alignment information is stored right before the pointer. This is the number of bytes of information stored there.
|
||||
|
||||
|
||||
#define USE_CASE1
|
||||
#define USE_CASE2
|
||||
#define USE_CASE3
|
||||
#define USE_CASE4
|
||||
#define USE_CASE5
|
||||
|
||||
extern address_space_t KernelAddressSpace;
|
||||
|
||||
/** This function is supposed to lock the memory data structures. It
|
||||
* could be as simple as disabling interrupts or acquiring a spinlock.
|
||||
* It's up to you to decide.
|
||||
*
|
||||
* \return 0 if the lock was acquired successfully. Anything else is
|
||||
* failure.
|
||||
*/
|
||||
static int liballoc_lock() {
|
||||
return TicketAttemptLock(&KernelAddressSpace.Lock) ? 0 : 1;
|
||||
}
|
||||
|
||||
/** This function unlocks what was previously locked by the liballoc_lock
|
||||
* function. If it disabled interrupts, it enables interrupts. If it
|
||||
* had acquiried a spinlock, it releases the spinlock. etc.
|
||||
*
|
||||
*/
|
||||
static void liballoc_unlock() {
|
||||
TicketUnlock(&KernelAddressSpace.Lock);
|
||||
}
|
||||
|
||||
/** This is the hook into the local system which allocates pages. It
|
||||
* accepts an integer parameter which is the number of pages
|
||||
* required. The page size was set up in the liballoc_init function.
|
||||
*
|
||||
* \return NULL if the pages were not allocated.
|
||||
* \return A pointer to the allocated memory.
|
||||
*/
|
||||
static void* liballoc_alloc(size_t count) {
|
||||
return (void*) PhysAllocateZeroMem(count * PAGE_SIZE);
|
||||
}
|
||||
|
||||
/** This frees previously allocated memory. The void* parameter passed
|
||||
* to the function is the exact same value returned from a previous
|
||||
* liballoc_alloc call.
|
||||
*
|
||||
* The integer value is the number of pages to free.
|
||||
*
|
||||
* \return 0 if the memory was successfully freed.
|
||||
*/
|
||||
static int liballoc_free(void* ptr, size_t count) {
|
||||
PhysFreeMem(ptr, count * PAGE_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/** This macro will conveniently align our pointer upwards */
|
||||
#define ALIGN(ptr) \
|
||||
if ( ALIGNMENT > 1 ) \
|
||||
{ \
|
||||
uintptr_t diff; \
|
||||
ptr = (void*)((uintptr_t)ptr + ALIGN_INFO); \
|
||||
diff = (uintptr_t)ptr & (ALIGNMENT-1); \
|
||||
if ( diff != 0 ) \
|
||||
{ \
|
||||
diff = ALIGNMENT - diff; \
|
||||
ptr = (void*)((uintptr_t)ptr + diff); \
|
||||
} \
|
||||
*((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)) = \
|
||||
diff + ALIGN_INFO; \
|
||||
}
|
||||
|
||||
|
||||
#define UNALIGN(ptr) \
|
||||
if ( ALIGNMENT > 1 ) \
|
||||
{ \
|
||||
uintptr_t diff = *((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)); \
|
||||
if ( diff < (ALIGNMENT + ALIGN_INFO) ) \
|
||||
{ \
|
||||
ptr = (void*)((uintptr_t)ptr - diff); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
#define LIBALLOC_MAGIC 0xc001c0de
|
||||
#define LIBALLOC_DEAD 0xdeaddead
|
||||
|
||||
#if defined DEBUG || defined INFO
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define FLUSH() fflush( stdout )
|
||||
|
||||
#endif
|
||||
|
||||
/** A structure found at the top of all system allocated
|
||||
* memory blocks. It details the usage of the memory block.
|
||||
*/
|
||||
struct liballoc_major {
|
||||
struct liballoc_major* prev; ///< Linked list information.
|
||||
struct liballoc_major* next; ///< Linked list information.
|
||||
unsigned int pages; ///< The number of pages in the block.
|
||||
unsigned int size; ///< The number of pages in the block.
|
||||
unsigned int usage; ///< The number of bytes used in the block.
|
||||
struct liballoc_minor* first; ///< A pointer to the first allocated memory in the block.
|
||||
};
|
||||
|
||||
|
||||
/** This is a structure found at the beginning of all
|
||||
* sections in a major block which were allocated by a
|
||||
* malloc, calloc, realloc call.
|
||||
*/
|
||||
struct liballoc_minor {
|
||||
struct liballoc_minor* prev; ///< Linked list information.
|
||||
struct liballoc_minor* next; ///< Linked list information.
|
||||
struct liballoc_major* block; ///< The owning block. A pointer to the major structure.
|
||||
unsigned int magic; ///< A magic number to idenfity correctness.
|
||||
unsigned int size; ///< The size of the memory allocated. Could be 1 byte or more.
|
||||
unsigned int req_size; ///< The size of memory requested.
|
||||
};
|
||||
|
||||
|
||||
static struct liballoc_major* l_memRoot = NULL; ///< The root memory block acquired from the system.
|
||||
static struct liballoc_major* l_bestBet = NULL; ///< The major with the most free memory.
|
||||
|
||||
static unsigned int l_pageSize = 4096; ///< The size of an individual page. Set up in liballoc_init.
|
||||
static unsigned int l_pageCount = 16; ///< The number of pages to request per chunk. Set up in liballoc_init.
|
||||
static unsigned long long l_allocated = 0; ///< Running total of allocated memory.
|
||||
static unsigned long long l_inuse = 0; ///< Running total of used memory.
|
||||
|
||||
|
||||
static long long l_warningCount = 0; ///< Number of warnings encountered
|
||||
static long long l_errorCount = 0; ///< Number of actual errors
|
||||
static long long l_possibleOverruns = 0; ///< Number of possible overruns
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// *********** HELPER FUNCTIONS *******************************
|
||||
|
||||
static void* liballoc_memset(void* s, int c, size_t n) {
|
||||
unsigned int i;
|
||||
for (i = 0; i < n; i++)
|
||||
((char*) s)[i] = c;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static void* liballoc_memcpy(void* s1, const void* s2, size_t n) {
|
||||
char* cdest;
|
||||
char* csrc;
|
||||
unsigned int* ldest = (unsigned int*) s1;
|
||||
unsigned int* lsrc = (unsigned int*) s2;
|
||||
|
||||
while (n >= sizeof(unsigned int)) {
|
||||
*ldest++ = *lsrc++;
|
||||
n -= sizeof(unsigned int);
|
||||
}
|
||||
|
||||
cdest = (char*) ldest;
|
||||
csrc = (char*) lsrc;
|
||||
|
||||
while (n > 0) {
|
||||
*cdest++ = *csrc++;
|
||||
n -= 1;
|
||||
}
|
||||
|
||||
return s1;
|
||||
}
|
||||
|
||||
|
||||
#if defined DEBUG || defined INFO
|
||||
static void liballoc_dump()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
struct liballoc_major *maj = l_memRoot;
|
||||
struct liballoc_minor *min = NULL;
|
||||
#endif
|
||||
|
||||
printf( "liballoc: ------ Memory data ---------------\n");
|
||||
printf( "liballoc: System memory allocated: %i bytes\n", l_allocated );
|
||||
printf( "liballoc: Memory in used (malloc'ed): %i bytes\n", l_inuse );
|
||||
printf( "liballoc: Warning count: %i\n", l_warningCount );
|
||||
printf( "liballoc: Error count: %i\n", l_errorCount );
|
||||
printf( "liballoc: Possible overruns: %i\n", l_possibleOverruns );
|
||||
|
||||
#ifdef DEBUG
|
||||
while ( maj != NULL )
|
||||
{
|
||||
printf( "liballoc: %x: total = %i, used = %i\n",
|
||||
maj,
|
||||
maj->size,
|
||||
maj->usage );
|
||||
|
||||
min = maj->first;
|
||||
while ( min != NULL )
|
||||
{
|
||||
printf( "liballoc: %x: %i bytes\n",
|
||||
min,
|
||||
min->size );
|
||||
min = min->next;
|
||||
}
|
||||
|
||||
maj = maj->next;
|
||||
}
|
||||
#endif
|
||||
|
||||
FLUSH();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// ***************************************************************
|
||||
|
||||
static struct liballoc_major* allocate_new_page(unsigned int size) {
|
||||
unsigned int st;
|
||||
struct liballoc_major* maj;
|
||||
|
||||
// This is how much space is required.
|
||||
st = size + sizeof(struct liballoc_major);
|
||||
st += sizeof(struct liballoc_minor);
|
||||
|
||||
// Perfect amount of space?
|
||||
if ((st % l_pageSize) == 0)
|
||||
st = st / (l_pageSize);
|
||||
else
|
||||
st = st / (l_pageSize) + 1;
|
||||
// No, add the buffer.
|
||||
|
||||
|
||||
// Make sure it's >= the minimum size.
|
||||
if (st < l_pageCount) st = l_pageCount;
|
||||
|
||||
maj = (struct liballoc_major*) liballoc_alloc(st);
|
||||
|
||||
if (maj == NULL) {
|
||||
l_warningCount += 1;
|
||||
#if defined DEBUG || defined INFO
|
||||
printf( "liballoc: WARNING: liballoc_alloc( %i ) return NULL\n", st );
|
||||
FLUSH();
|
||||
#endif
|
||||
return NULL; // uh oh, we ran out of memory.
|
||||
}
|
||||
|
||||
maj->prev = NULL;
|
||||
maj->next = NULL;
|
||||
maj->pages = st;
|
||||
maj->size = st * l_pageSize;
|
||||
maj->usage = sizeof(struct liballoc_major);
|
||||
maj->first = NULL;
|
||||
|
||||
l_allocated += maj->size;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "liballoc: Resource allocated %x of %i pages (%i bytes) for %i size.\n", maj, st, maj->size, size );
|
||||
|
||||
printf( "liballoc: Total memory usage = %i KB\n", (int)((l_allocated / (1024))) );
|
||||
FLUSH();
|
||||
#endif
|
||||
|
||||
|
||||
return maj;
|
||||
}
|
||||
|
||||
|
||||
void* PREFIX(malloc)(size_t req_size) {
|
||||
int startedBet = 0;
|
||||
unsigned long long bestSize = 0;
|
||||
void* p = NULL;
|
||||
uintptr_t diff;
|
||||
struct liballoc_major* maj;
|
||||
struct liballoc_minor* min;
|
||||
struct liballoc_minor* new_min;
|
||||
unsigned long size = req_size;
|
||||
|
||||
// For alignment, we adjust size so there's enough space to align.
|
||||
if (ALIGNMENT > 1) {
|
||||
size += ALIGNMENT + ALIGN_INFO;
|
||||
}
|
||||
// So, ideally, we really want an alignment of 0 or 1 in order
|
||||
// to save space.
|
||||
|
||||
liballoc_lock();
|
||||
|
||||
if (size == 0) {
|
||||
l_warningCount += 1;
|
||||
#if defined DEBUG || defined INFO
|
||||
printf( "liballoc: WARNING: alloc( 0 ) called from %x\n",
|
||||
__builtin_return_address(0) );
|
||||
FLUSH();
|
||||
#endif
|
||||
liballoc_unlock();
|
||||
return PREFIX(malloc)(1);
|
||||
}
|
||||
|
||||
|
||||
if (l_memRoot == NULL) {
|
||||
#if defined DEBUG || defined INFO
|
||||
#ifdef DEBUG
|
||||
printf( "liballoc: initialization of liballoc " VERSION "\n" );
|
||||
#endif
|
||||
atexit( liballoc_dump );
|
||||
FLUSH();
|
||||
#endif
|
||||
|
||||
// This is the first time we are being used.
|
||||
l_memRoot = allocate_new_page(size);
|
||||
if (l_memRoot == NULL) {
|
||||
liballoc_unlock();
|
||||
#ifdef DEBUG
|
||||
printf( "liballoc: initial l_memRoot initialization failed\n", p);
|
||||
FLUSH();
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "liballoc: set up first memory major %x\n", l_memRoot );
|
||||
FLUSH();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "liballoc: %x PREFIX(malloc)( %i ): ",
|
||||
__builtin_return_address(0),
|
||||
size );
|
||||
FLUSH();
|
||||
#endif
|
||||
|
||||
// Now we need to bounce through every major and find enough space....
|
||||
|
||||
maj = l_memRoot;
|
||||
startedBet = 0;
|
||||
|
||||
// Start at the best bet....
|
||||
if (l_bestBet != NULL) {
|
||||
bestSize = l_bestBet->size - l_bestBet->usage;
|
||||
|
||||
if (bestSize > (size + sizeof(struct liballoc_minor))) {
|
||||
maj = l_bestBet;
|
||||
startedBet = 1;
|
||||
}
|
||||
}
|
||||
|
||||
while (maj != NULL) {
|
||||
diff = maj->size - maj->usage;
|
||||
// free memory in the block
|
||||
|
||||
if (bestSize < diff) {
|
||||
// Hmm.. this one has more memory then our bestBet. Remember!
|
||||
l_bestBet = maj;
|
||||
bestSize = diff;
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_CASE1
|
||||
|
||||
// CASE 1: There is not enough space in this major block.
|
||||
if (diff < (size + sizeof(struct liballoc_minor))) {
|
||||
#ifdef DEBUG
|
||||
printf( "CASE 1: Insufficient space in block %x\n", maj);
|
||||
FLUSH();
|
||||
#endif
|
||||
|
||||
// Another major block next to this one?
|
||||
if (maj->next != NULL) {
|
||||
maj = maj->next; // Hop to that one.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (startedBet == 1) // If we started at the best bet,
|
||||
{ // let's start all over again.
|
||||
maj = l_memRoot;
|
||||
startedBet = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create a new major block next to this one and...
|
||||
maj->next = allocate_new_page(size); // next one will be okay.
|
||||
if (maj->next == NULL) break; // no more memory.
|
||||
maj->next->prev = maj;
|
||||
maj = maj->next;
|
||||
|
||||
// .. fall through to CASE 2 ..
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_CASE2
|
||||
|
||||
// CASE 2: It's a brand new block.
|
||||
if (maj->first == NULL) {
|
||||
maj->first = (struct liballoc_minor*) ((uintptr_t) maj + sizeof(struct liballoc_major));
|
||||
|
||||
|
||||
maj->first->magic = LIBALLOC_MAGIC;
|
||||
maj->first->prev = NULL;
|
||||
maj->first->next = NULL;
|
||||
maj->first->block = maj;
|
||||
maj->first->size = size;
|
||||
maj->first->req_size = req_size;
|
||||
maj->usage += size + sizeof(struct liballoc_minor);
|
||||
|
||||
|
||||
l_inuse += size;
|
||||
|
||||
|
||||
p = (void*) ((uintptr_t) (maj->first) + sizeof(struct liballoc_minor));
|
||||
|
||||
ALIGN(p);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "CASE 2: returning %x\n", p);
|
||||
FLUSH();
|
||||
#endif
|
||||
liballoc_unlock(); // release the lock
|
||||
return p;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_CASE3
|
||||
|
||||
// CASE 3: Block in use and enough space at the start of the block.
|
||||
diff = (uintptr_t) (maj->first);
|
||||
diff -= (uintptr_t) maj;
|
||||
diff -= sizeof(struct liballoc_major);
|
||||
|
||||
if (diff >= (size + sizeof(struct liballoc_minor))) {
|
||||
// Yes, space in front. Squeeze in.
|
||||
maj->first->prev = (struct liballoc_minor*) ((uintptr_t) maj + sizeof(struct liballoc_major));
|
||||
maj->first->prev->next = maj->first;
|
||||
maj->first = maj->first->prev;
|
||||
|
||||
maj->first->magic = LIBALLOC_MAGIC;
|
||||
maj->first->prev = NULL;
|
||||
maj->first->block = maj;
|
||||
maj->first->size = size;
|
||||
maj->first->req_size = req_size;
|
||||
maj->usage += size + sizeof(struct liballoc_minor);
|
||||
|
||||
l_inuse += size;
|
||||
|
||||
p = (void*) ((uintptr_t) (maj->first) + sizeof(struct liballoc_minor));
|
||||
ALIGN(p);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "CASE 3: returning %x\n", p);
|
||||
FLUSH();
|
||||
#endif
|
||||
liballoc_unlock(); // release the lock
|
||||
return p;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USE_CASE4
|
||||
|
||||
// CASE 4: There is enough space in this block. But is it contiguous?
|
||||
min = maj->first;
|
||||
|
||||
// Looping within the block now...
|
||||
while (min != NULL) {
|
||||
// CASE 4.1: End of minors in a block. Space from last and end?
|
||||
if (min->next == NULL) {
|
||||
// the rest of this block is free... is it big enough?
|
||||
diff = (uintptr_t) (maj) + maj->size;
|
||||
diff -= (uintptr_t) min;
|
||||
diff -= sizeof(struct liballoc_minor);
|
||||
diff -= min->size;
|
||||
// minus already existing usage..
|
||||
|
||||
if (diff >= (size + sizeof(struct liballoc_minor))) {
|
||||
// yay....
|
||||
min->next = (struct liballoc_minor*) ((uintptr_t) min + sizeof(struct liballoc_minor) + min->size);
|
||||
min->next->prev = min;
|
||||
min = min->next;
|
||||
min->next = NULL;
|
||||
min->magic = LIBALLOC_MAGIC;
|
||||
min->block = maj;
|
||||
min->size = size;
|
||||
min->req_size = req_size;
|
||||
maj->usage += size + sizeof(struct liballoc_minor);
|
||||
|
||||
l_inuse += size;
|
||||
|
||||
p = (void*) ((uintptr_t) min + sizeof(struct liballoc_minor));
|
||||
ALIGN(p);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "CASE 4.1: returning %x\n", p);
|
||||
FLUSH();
|
||||
#endif
|
||||
liballoc_unlock(); // release the lock
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// CASE 4.2: Is there space between two minors?
|
||||
if (min->next != NULL) {
|
||||
// is the difference between here and next big enough?
|
||||
diff = (uintptr_t) (min->next);
|
||||
diff -= (uintptr_t) min;
|
||||
diff -= sizeof(struct liballoc_minor);
|
||||
diff -= min->size;
|
||||
// minus our existing usage.
|
||||
|
||||
if (diff >= (size + sizeof(struct liballoc_minor))) {
|
||||
// yay......
|
||||
new_min = (struct liballoc_minor*) ((uintptr_t) min + sizeof(struct liballoc_minor) + min->size);
|
||||
|
||||
new_min->magic = LIBALLOC_MAGIC;
|
||||
new_min->next = min->next;
|
||||
new_min->prev = min;
|
||||
new_min->size = size;
|
||||
new_min->req_size = req_size;
|
||||
new_min->block = maj;
|
||||
min->next->prev = new_min;
|
||||
min->next = new_min;
|
||||
maj->usage += size + sizeof(struct liballoc_minor);
|
||||
|
||||
l_inuse += size;
|
||||
|
||||
p = (void*) ((uintptr_t) new_min + sizeof(struct liballoc_minor));
|
||||
ALIGN(p);
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "CASE 4.2: returning %x\n", p);
|
||||
FLUSH();
|
||||
#endif
|
||||
|
||||
liballoc_unlock(); // release the lock
|
||||
return p;
|
||||
}
|
||||
} // min->next != NULL
|
||||
|
||||
min = min->next;
|
||||
} // while min != NULL ...
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_CASE5
|
||||
|
||||
// CASE 5: Block full! Ensure next block and loop.
|
||||
if (maj->next == NULL) {
|
||||
#ifdef DEBUG
|
||||
printf( "CASE 5: block full\n");
|
||||
FLUSH();
|
||||
#endif
|
||||
|
||||
if (startedBet == 1) {
|
||||
maj = l_memRoot;
|
||||
startedBet = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// we've run out. we need more...
|
||||
maj->next = allocate_new_page(size); // next one guaranteed to be okay
|
||||
if (maj->next == NULL) break; // uh oh, no more memory.....
|
||||
maj->next->prev = maj;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
maj = maj->next;
|
||||
} // while (maj != NULL)
|
||||
|
||||
|
||||
|
||||
liballoc_unlock(); // release the lock
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "All cases exhausted. No memory available.\n");
|
||||
FLUSH();
|
||||
#endif
|
||||
#if defined DEBUG || defined INFO
|
||||
printf( "liballoc: WARNING: PREFIX(malloc)( %i ) returning NULL.\n", size);
|
||||
liballoc_dump();
|
||||
FLUSH();
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void PREFIX(free)(void* ptr) {
|
||||
struct liballoc_minor* min;
|
||||
struct liballoc_major* maj;
|
||||
|
||||
if (ptr == NULL) {
|
||||
l_warningCount += 1;
|
||||
#if defined DEBUG || defined INFO
|
||||
printf( "liballoc: WARNING: PREFIX(free)( NULL ) called from %x\n",
|
||||
__builtin_return_address(0) );
|
||||
FLUSH();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
UNALIGN(ptr);
|
||||
|
||||
liballoc_lock(); // lockit
|
||||
|
||||
|
||||
min = (struct liballoc_minor*) ((uintptr_t) ptr - sizeof(struct liballoc_minor));
|
||||
|
||||
|
||||
if (min->magic != LIBALLOC_MAGIC) {
|
||||
l_errorCount += 1;
|
||||
|
||||
// Check for overrun errors. For all bytes of LIBALLOC_MAGIC
|
||||
if (
|
||||
((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF)) ||
|
||||
((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF)) ||
|
||||
((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF))
|
||||
) {
|
||||
l_possibleOverruns += 1;
|
||||
#if defined DEBUG || defined INFO
|
||||
printf( "liballoc: ERROR: Possible 1-3 byte overrun for magic %x != %x\n",
|
||||
min->magic,
|
||||
LIBALLOC_MAGIC );
|
||||
FLUSH();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (min->magic == LIBALLOC_DEAD) {
|
||||
#if defined DEBUG || defined INFO
|
||||
printf( "liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n",
|
||||
ptr,
|
||||
__builtin_return_address(0) );
|
||||
FLUSH();
|
||||
#endif
|
||||
} else {
|
||||
#if defined DEBUG || defined INFO
|
||||
printf( "liballoc: ERROR: Bad PREFIX(free)( %x ) called from %x\n",
|
||||
ptr,
|
||||
__builtin_return_address(0) );
|
||||
FLUSH();
|
||||
#endif
|
||||
}
|
||||
|
||||
// being lied to...
|
||||
liballoc_unlock(); // release the lock
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "liballoc: %x PREFIX(free)( %x ): ",
|
||||
__builtin_return_address( 0 ),
|
||||
ptr );
|
||||
FLUSH();
|
||||
#endif
|
||||
|
||||
|
||||
maj = min->block;
|
||||
|
||||
l_inuse -= min->size;
|
||||
|
||||
maj->usage -= (min->size + sizeof(struct liballoc_minor));
|
||||
min->magic = LIBALLOC_DEAD; // No mojo.
|
||||
|
||||
if (min->next != NULL) min->next->prev = min->prev;
|
||||
if (min->prev != NULL) min->prev->next = min->next;
|
||||
|
||||
if (min->prev == NULL) maj->first = min->next;
|
||||
// Might empty the block. This was the first
|
||||
// minor.
|
||||
|
||||
|
||||
// We need to clean up after the majors now....
|
||||
|
||||
if (maj->first == NULL) // Block completely unused.
|
||||
{
|
||||
if (l_memRoot == maj) l_memRoot = maj->next;
|
||||
if (l_bestBet == maj) l_bestBet = NULL;
|
||||
if (maj->prev != NULL) maj->prev->next = maj->next;
|
||||
if (maj->next != NULL) maj->next->prev = maj->prev;
|
||||
l_allocated -= maj->size;
|
||||
|
||||
liballoc_free(maj, maj->pages);
|
||||
} else {
|
||||
if (l_bestBet != NULL) {
|
||||
int bestSize = l_bestBet->size - l_bestBet->usage;
|
||||
int majSize = maj->size - maj->usage;
|
||||
|
||||
if (majSize > bestSize) l_bestBet = maj;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "OK\n");
|
||||
FLUSH();
|
||||
#endif
|
||||
|
||||
liballoc_unlock(); // release the lock
|
||||
}
|
||||
|
||||
void* PREFIX(calloc)(size_t nobj, size_t size) {
|
||||
int real_size;
|
||||
void* p;
|
||||
|
||||
real_size = nobj * size;
|
||||
|
||||
p = PREFIX(malloc)(real_size);
|
||||
|
||||
liballoc_memset(p, 0, real_size);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
void* PREFIX(realloc)(void* p, size_t size) {
|
||||
void* ptr;
|
||||
struct liballoc_minor* min;
|
||||
unsigned int real_size;
|
||||
|
||||
// Honour the case of size == 0 => free old and return NULL
|
||||
if (size == 0) {
|
||||
PREFIX(free)(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// In the case of a NULL pointer, return a simple malloc.
|
||||
if (p == NULL) return PREFIX(malloc)(size);
|
||||
|
||||
// Unalign the pointer if required.
|
||||
ptr = p;
|
||||
UNALIGN(ptr);
|
||||
|
||||
liballoc_lock(); // lockit
|
||||
|
||||
min = (struct liballoc_minor*) ((uintptr_t) ptr - sizeof(struct liballoc_minor));
|
||||
|
||||
// Ensure it is a valid structure.
|
||||
if (min->magic != LIBALLOC_MAGIC) {
|
||||
l_errorCount += 1;
|
||||
|
||||
// Check for overrun errors. For all bytes of LIBALLOC_MAGIC
|
||||
if (
|
||||
((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF)) ||
|
||||
((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF)) ||
|
||||
((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF))
|
||||
) {
|
||||
l_possibleOverruns += 1;
|
||||
#if defined DEBUG || defined INFO
|
||||
printf( "liballoc: ERROR: Possible 1-3 byte overrun for magic %x != %x\n",
|
||||
min->magic,
|
||||
LIBALLOC_MAGIC );
|
||||
FLUSH();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
if (min->magic == LIBALLOC_DEAD) {
|
||||
#if defined DEBUG || defined INFO
|
||||
printf( "liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n",
|
||||
ptr,
|
||||
__builtin_return_address(0) );
|
||||
FLUSH();
|
||||
#endif
|
||||
} else {
|
||||
#if defined DEBUG || defined INFO
|
||||
printf( "liballoc: ERROR: Bad PREFIX(free)( %x ) called from %x\n",
|
||||
ptr,
|
||||
__builtin_return_address(0) );
|
||||
FLUSH();
|
||||
#endif
|
||||
}
|
||||
|
||||
// being lied to...
|
||||
liballoc_unlock(); // release the lock
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Definitely a memory block.
|
||||
|
||||
real_size = min->req_size;
|
||||
|
||||
if (real_size >= size) {
|
||||
min->req_size = size;
|
||||
liballoc_unlock();
|
||||
return p;
|
||||
}
|
||||
|
||||
liballoc_unlock();
|
||||
|
||||
// If we got here then we're reallocating to a block bigger than us.
|
||||
ptr = PREFIX(malloc)(size); // We need to allocate new memory
|
||||
liballoc_memcpy(ptr, p, real_size);
|
||||
PREFIX(free)(p);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
void operator delete(void* addr, unsigned long __attribute__((unused)) size) {
|
||||
PREFIX(free)(addr);
|
||||
}
|
||||
|
||||
void operator delete(void* addr) {
|
||||
PREFIX(free)(addr);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
#include <kernel/chroma.h>
|
||||
#include <lainlib/lainlib.h>
|
||||
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
|
@ -12,17 +13,12 @@ extern "C" {
|
|||
|
||||
/* This file contains functions for physical memory management.
|
||||
*
|
||||
* This is also called blocking, or block memory allocation.
|
||||
* It mostly deals with the memory map handed to us by the bootloader.
|
||||
* Physical Memory Management is performed with Buddy List allocators, which are one of the most performant systems available.
|
||||
* They tend to be able to allocate physical pages with O(1) efficiency.
|
||||
*
|
||||
* It is useful in virtual memory management, because it allows us to map one block of physical memory to one page of virtual memory.
|
||||
*
|
||||
* Most of the processing here is done with a bitwise mapping of blocks to allocations, normally called a memory bitmap.
|
||||
* See heap.h for the implementation.
|
||||
*
|
||||
* This file also contains memory manipulation functions, like memset and memcpy.
|
||||
* //TODO: replace these functions with SSE2 equivalent.
|
||||
* The implementation here is bespoke, and in need of documentation.
|
||||
*
|
||||
* TODO: Document this mess.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
#include <kernel/chroma.h>
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This file aims to implement stack unwinding
|
||||
* to trace faulty functions.
|
||||
*
|
||||
* I was in the middle of debugging a jump to null
|
||||
* when i started creating this, so there will be a
|
||||
* lot of functionality here left over from that
|
||||
* initial goal, probably...
|
||||
*
|
||||
* //TODO: Rework this to allow unwinding function parameters on call.
|
||||
*/
|
||||
|
||||
void StackTrace(size_t cycles) {
|
||||
struct stackframe* stack;
|
||||
|
||||
__asm__ __volatile__ ("mov %%rbp, %[dest]" : [dest] "=r" (stack) : :);
|
||||
SerialPrintf("[Trace] Beginning stack trace. RBP is currently 0x%p\r\n", stack);
|
||||
for(size_t frame = 0; stack != 0 && frame < cycles; ++frame) {
|
||||
SerialPrintf("[Trace] (%d) 0x%p: 0x%p \r\n", frame, stack->rbp, stack->rip);
|
||||
stack = stack->rbp;
|
||||
}
|
||||
SerialPrintf("[Trace] Stack trace over.\r\n");
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
531
src/system/pci.c
531
src/system/pci.c
|
@ -1,531 +0,0 @@
|
|||
#include <kernel/chroma.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This file contains functions for accessing the PCI bus,
|
||||
* and devices contained wherein.
|
||||
*
|
||||
* It allows you to query the bus, as well as communicate with individual devices.
|
||||
*
|
||||
*/
|
||||
|
||||
pci_device_t** pci_root_devices = NULL;
|
||||
pci_entry_t* pci_map = NULL;
|
||||
|
||||
//static uint32_t PCIReadConfig(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset);
|
||||
|
||||
//static const char* PCIGetDeviceName_Subclass(uint8_t DeviceClass, uint8_t Subclass, uint8_t ProgrammableInterface);
|
||||
|
||||
//static const char* PCIGetClassName(uint8_t DeviceClass);
|
||||
|
||||
void PCIEnumerate() {
|
||||
|
||||
uint8_t bus = 0, device = 0, function = 0;
|
||||
|
||||
uint32_t registerData;
|
||||
|
||||
uint16_t DeviceID, VendorID;
|
||||
|
||||
uint8_t ClassCode, subclass_code;
|
||||
|
||||
SerialPrintf("[ PCI] Started PCI Enumeration.");
|
||||
|
||||
SerialPrintf("\n[ PCI] PCI Scan result:\n[ PCI]");
|
||||
do {
|
||||
for (device = 0; device <= 31; device++) {
|
||||
for(function = 0; function <= 7; function++) {
|
||||
registerData = PCIReadConfig(bus, device, 0, 0xC); // Read BIST/Header/Latency/Cache Line register
|
||||
uint8_t header = (uint8_t) ((registerData & 0x00FF0000) >> 24); // Header is lower byte of upper word, so mask it off and shift it down
|
||||
uint8_t multifunction_bit = header & 0x80; // The multifunction bit is the highest bit of the header
|
||||
|
||||
registerData = PCIReadConfig(bus, device, function, 0); // Read the Vendor/Device ID register
|
||||
VendorID = (uint16_t) (registerData & 0x0000FFFF); // Vendor ID is bottom word
|
||||
DeviceID = (uint16_t) (registerData >> 16); // Device ID is top word
|
||||
|
||||
registerData = PCIReadConfig(bus, device, function, 8); // Read the Device Info register
|
||||
ClassCode = (uint16_t)( registerData >> 24); // Device class is top byte, so shift them down
|
||||
subclass_code = (uint16_t) ((registerData >> 16) & 0x00FF); // Device subclass is same as header - lower byte of higher word. Shift down and mask just like before.
|
||||
uint8_t device_progif = (uint16_t) ((registerData & 0x0000FF00) >> 8); // Device Programming Interface is higher byte of lower word, so mask and shift
|
||||
uint8_t device_revision = (uint16_t) (registerData & 0x000000FF); // Device revision is lower byte of whole double word. Just mask it.
|
||||
|
||||
|
||||
/* 0xFFFF is not a valid Vendor ID. This serves as a sanity check.
|
||||
* If this check is true, then nothing is logged and we continue for the next loop.
|
||||
*/
|
||||
if(VendorID != 0xFFFF) {
|
||||
SerialPrintf("[ PCI]\n[ PCI]\t%x:%x:\n[ PCI]\t\tVendor: %x\n[ PCI]\t\tDevice: %x", bus, device, VendorID, DeviceID);
|
||||
SerialPrintf("\n[ PCI]\t\tClass: %s\n[ PCI]\t\tDevice Type: %s\n[ PCI]\t\tRevision: %d\n", PCIGetClassName(ClassCode), PCIGetDeviceName_Subclass(ClassCode, subclass_code, device_progif), device_revision);
|
||||
}
|
||||
|
||||
/* If the PCI Device header tells us that this is not a multifunction device,
|
||||
* and we've already scanned function 0, then there is nothing else to see.
|
||||
* Therefore, stop this loop and move onto device++
|
||||
*/
|
||||
if (multifunction_bit == 0)
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
} while (++bus);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
uint32_t PCIReadConfig(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset) {
|
||||
uint32_t address;
|
||||
uint32_t busLong = (uint32_t) bus;
|
||||
uint32_t slotLong = (uint32_t) slot;
|
||||
uint32_t functionLong = (uint32_t) function;
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* | 31 | 30 ... 24 | 23 ... 16 | 15 ... 11 | 10 ... 8 | 7 ... 0 |
|
||||
* ---------------------------------------------------------------
|
||||
* | EN | RESERVED | BUS NUM | DEVICE NO | FUNC NO | REG OFF |
|
||||
* ---------------------------------------------------------------
|
||||
*
|
||||
* NOTE: REG OFF *must* have 0 last two bits (ie. & 0xFC)
|
||||
*/
|
||||
|
||||
address = (uint32_t) (( busLong << 16 ) | ( slotLong << 11 ) |
|
||||
( functionLong << 8 ) | ( offset & 0xFC) | ((uint32_t)0x80000000));
|
||||
|
||||
WritePort(0xCF8, address, 4);
|
||||
|
||||
|
||||
return ReadPort(0xCFC, 4);
|
||||
}
|
||||
|
||||
const char* PCIGetDeviceName_Subclass(uint8_t DeviceClass, uint8_t Subclass, uint8_t ProgrammableInterface) {
|
||||
switch(DeviceClass) {
|
||||
|
||||
case 0x00: {
|
||||
switch(Subclass) {
|
||||
case 0x00: return "Non-VGA-Compatible device";
|
||||
case 0x01: return "VGA-Compatible device";
|
||||
default: return "Unknown Unclassified";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x01: {
|
||||
switch(Subclass) {
|
||||
case 0x00: return "SCSI Bus Controller";
|
||||
case 0x01: {
|
||||
switch(ProgrammableInterface) {
|
||||
case 0x00: return "ISA Compatibility Mode-only IDE Controller";
|
||||
case 0x05: return "PCI Native Mode-only IDE Controller";
|
||||
case 0x0A: return "ISA Compatibility Mode IDE Controller (supports PCI Native Mode)";
|
||||
case 0x0F: return "PCI Native Mode IDE Controller (supports ISA Compatibility Mode)";
|
||||
case 0x80: return "ISA Compatibilty Mode-only IDE Controller (supports Bus Mastering)";
|
||||
case 0x85: return "PCI Native Mode-only IDE Controller (supports Bus Mastering)";
|
||||
case 0x8A: return "ISA Compatibility Mode IDE Controller (supports PCI Native Mode & Bus Mastering)";
|
||||
case 0x8F: return "PCI Native Mode IDE Controller (supports ISA Compatibiliy Mode & Bus Mastering)";
|
||||
default: return "IDE Controller";
|
||||
}
|
||||
}
|
||||
case 0x02: return "Floppy Disk Controller";
|
||||
case 0x03: return "IPI Bus Controller";
|
||||
case 0x04: return "RAID Controller";
|
||||
case 0x05: {
|
||||
switch(ProgrammableInterface) {
|
||||
case 0x20: return "Single-DMA ATA Controller";
|
||||
case 0x30: return "Chained-DMA ATA Controller";
|
||||
default: return "ATA Controller";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
case 0x06: {
|
||||
switch(ProgrammableInterface) {
|
||||
case 0x00: return "Vendor-Specific Interface SATA Controller";
|
||||
case 0x01: return "AHCI 1.0 SATA Controller";
|
||||
case 0x02: return "Serial Storage Bus SATA Controller";
|
||||
default: return "Serial ATA Controller";
|
||||
}
|
||||
}
|
||||
case 0x07: return "Serial Attached SCSI (SAS)";
|
||||
|
||||
case 0x08:{
|
||||
switch(ProgrammableInterface) {
|
||||
case 0x01: return "NVMHCI Memory Controller";
|
||||
case 0x02: return "NVMe Memory Controller";
|
||||
default: return "Non-Volatile Memory Controller";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Mass Storage Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x02: {
|
||||
switch(Subclass) {
|
||||
case 0x00: return "Ethernet Controller";
|
||||
case 0x01: return "Token Ring Controller";
|
||||
case 0x02: return "FDDI Controller";
|
||||
case 0x03: return "ATM Controller";
|
||||
case 0x04: return "ISDN Controller";
|
||||
case 0x05: return "WorldFip Controller";
|
||||
case 0x06: return "PICMG 2.14 Multi Computing";
|
||||
case 0x07: return "Infiniband Controller";
|
||||
case 0x08: return "Fabric Controller";
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Network Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x03: {
|
||||
switch(Subclass) {
|
||||
case 0x00: {
|
||||
switch(ProgrammableInterface) {
|
||||
case 0x00: return "VGA Controller";
|
||||
case 0x01: return "8514 VGA Controller";
|
||||
default: return "VGA Compatible Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x01: return "XGA Controller";
|
||||
case 0x02: return "3D Controller (Not VGA-Compatible)";
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Display Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x04: {
|
||||
switch(Subclass) {
|
||||
case 0x00: return "Multimedia Video Controller";
|
||||
case 0x01: return "Multimedia Audio Controller";
|
||||
case 0x02: return "Computer Telephony Device";
|
||||
case 0x03: return "Audio Device";
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Multimedia Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x05: {
|
||||
switch(Subclass) {
|
||||
case 0x00: return "RAM Controller";
|
||||
case 0x01: return "Flash Controller";
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Memory Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x06: {
|
||||
switch(Subclass) {
|
||||
case 0x00: return "Host Bridge";
|
||||
case 0x01: return "ISA Bridge";
|
||||
case 0x02: return "EISA Bridge";
|
||||
case 0x03: return "MCA Bridge";
|
||||
case 0x04:
|
||||
case 0x09:
|
||||
return "PCI-to-PCI Bridge";
|
||||
case 0x05: return "PCMCIA Bridge";
|
||||
case 0x06: return "NuBus Bridge";
|
||||
case 0x07: return "CardBus Bridge";
|
||||
case 0x08: return "RACEway Bridge";
|
||||
case 0x0A: return "InfiniBand-to-PCI Host Bridge";
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Bridge Device";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x07: {
|
||||
switch(Subclass) {
|
||||
|
||||
case 0x00: {
|
||||
switch(ProgrammableInterface) {
|
||||
case 0x00: return "Serial Controller <8250>";
|
||||
case 0x01: return "Serial controller <16450>";
|
||||
case 0x02: return "Serial controller <16550>";
|
||||
case 0x03: return "Serial controller <16650>";
|
||||
case 0x04: return "Serial controller <16750>";
|
||||
case 0x05: return "Serial controller <16850>";
|
||||
case 0x06: return "Serial controller <16950>";
|
||||
default: return "Serial Controller";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
case 0x01: {
|
||||
switch(ProgrammableInterface) {
|
||||
case 0x00: return "Standard Parallel Port";
|
||||
case 0x01: return "Bi-Directional Parallel Port";
|
||||
case 0x02: return "ECP 1.X Compliant Parallel Port";
|
||||
case 0x03: return "IEEE 1284 Parallel Controller";
|
||||
case 0x04: return "IEE 1284 Parallel Target";
|
||||
default: return "Parallel Controller";
|
||||
}
|
||||
}
|
||||
case 0x02: return "Multiport Serial Controller";
|
||||
|
||||
case 0x03: {
|
||||
switch(ProgrammableInterface) {
|
||||
case 0x00: return "Generic Modem";
|
||||
case 0x01: return "Hayes 16450 Compatible Modem";
|
||||
case 0x02: return "Hayes 16550 Compatible Modem";
|
||||
case 0x03: return "Hayes 16650 Compatible Modem";
|
||||
case 0x04: return "Hayes 16750 Compatible Modem";
|
||||
default: return "Modem";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x04: return "IEEE 488.1/2 (GPIB) Controller";
|
||||
case 0x05: return "Smart Card";
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Simple Comms Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x08: {
|
||||
switch(Subclass) {
|
||||
case 0x00: {
|
||||
switch(ProgrammableInterface) {
|
||||
case 0x00: return "Generic 8259-Compatible PIC";
|
||||
case 0x01: return "ISA-Compatible PIC";
|
||||
case 0x02: return "EISA-Compatible PIC";
|
||||
case 0x03: return "I/O APIC Interrupt Controller";
|
||||
case 0x04: return "I/O(x) APIC Interrupt Controller";
|
||||
default: return "PIC";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x01: {
|
||||
switch(ProgrammableInterface) {
|
||||
case 0x00: return "Generic 8237-Compatible DMA Controller";
|
||||
case 0x01: return "ISA-Compatible DMA Controller";
|
||||
case 0x02: return "EISA-Compatible DMA Controller";
|
||||
default: return "DMA Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x02: {
|
||||
switch(ProgrammableInterface) {
|
||||
case 0x00: return "Generic 8254-Compatible Timer";
|
||||
case 0x01: return "ISA-Compatible Timer";
|
||||
case 0x02: return "EISA-Compatible Timer";
|
||||
case 0x03: return "HPET Timer";
|
||||
default: return "Timer";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x03: {
|
||||
switch(ProgrammableInterface) {
|
||||
case 0x00: return "Generic RTC Controller";
|
||||
case 0x01: return "ISA-Compatible RTC Controller";
|
||||
default: return "RTC Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x04: return "PCI Hot-Plug Controller";
|
||||
case 0x05: return "SD Host Controller";
|
||||
case 0x06: return "IOMMU";
|
||||
case 0x80: return "Other";
|
||||
|
||||
default: return "Unknown Base System Peripheral";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x09: {
|
||||
switch(Subclass) {
|
||||
case 0x00: return "Keyboard Controller";
|
||||
case 0x01: return "Digitiser Pen";
|
||||
case 0x02: return "Mouse Controller";
|
||||
case 0x03: return "Scanner Controller";
|
||||
|
||||
case 0x04: {
|
||||
switch(ProgrammableInterface) {
|
||||
case 0x00: return "Generic Gameport Controller";
|
||||
case 0x10: return "Extended Gameport Controller";
|
||||
default: return "Gameport Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x80: return "Other";
|
||||
|
||||
default: return "Unknown Input Device Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x0A: {
|
||||
switch(Subclass) {
|
||||
case 0x00: return "Generic Docking Station";
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Docking Station";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x0B: {
|
||||
switch(Subclass) {
|
||||
case 0x00: return "386 Processor";
|
||||
case 0x01: return "486 Processor";
|
||||
case 0x02: return "Pentium Processor";
|
||||
case 0x03: return "Pentium Pro Processor";
|
||||
case 0x10: return "Alpha Processor";
|
||||
case 0x20: return "PowerPC Processor";
|
||||
case 0x30: return "MIPS Processor";
|
||||
case 0x40: return "Co-Processor";
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Processor";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x0C: {
|
||||
switch(Subclass) {
|
||||
case 0x00: {
|
||||
switch(ProgrammableInterface) {
|
||||
case 0x00: return "Generic Firewire Controller";
|
||||
case 0x10: return "OHCI Firewire Controller";
|
||||
default: return "FireWire (IEEE 1394) Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x01: return "ACCESS Bus";
|
||||
case 0x02: return "SSA";
|
||||
|
||||
case 0x03: {
|
||||
switch(ProgrammableInterface) {
|
||||
case 0x00: return "UHCI USB Controller";
|
||||
case 0x10: return "OHCI USB Controller";
|
||||
case 0x20: return "EHCI USB (2.0) Controller";
|
||||
case 0x30: return "XHCI USB (3.0) Controller";
|
||||
case 0x80: return "Unspecified USB Controller";
|
||||
case 0xFE: return "USB Device (NOT a Controller)";
|
||||
default: return "USB Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x04: return "Fibre Channel";
|
||||
case 0x05: return "SMBus";
|
||||
case 0x06: return "InfiniBand";
|
||||
|
||||
case 0x07: {
|
||||
switch(ProgrammableInterface) {
|
||||
case 0x00: return "SMIC IPMI Interface";
|
||||
case 0x01: return "Keyboard Controller-Style IPMI Interface";
|
||||
case 0x02: return "Block Transfer IPMI Interface";
|
||||
default: return "IPMI Interface";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x08: return "SERCOS Interface (IEC 61491)";
|
||||
case 0x09: return "CANbus";
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Serial Bus Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x0D: {
|
||||
switch(Subclass) {
|
||||
case 0x00: return "IRDA Compatible Controller";
|
||||
case 0x01: return "Consumer IR Controller";
|
||||
case 0x10: return "RF Controller";
|
||||
case 0x11: return "Bluetooth Controller";
|
||||
case 0x12: return "Broadband Controller";
|
||||
case 0x20: return "Ethernet Controller (802.1a)";
|
||||
case 0x21: return "Ethernet Controller (802.1b)";
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Wireless Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x0E: {
|
||||
switch(Subclass) {
|
||||
case 0x00: return "I20";
|
||||
default: return "Unknown Intelligent Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x0F: {
|
||||
switch(Subclass) {
|
||||
case 0x01: return "Satellite TV Controller";
|
||||
case 0x02: return "Satellite Audio Controller";
|
||||
case 0x03: return "Satellite Voice Controller";
|
||||
case 0x04: return "Satellite Data Controller";
|
||||
default: return "Unknown Satelllite Comms Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x10: {
|
||||
switch(Subclass) {
|
||||
case 0x00: return "Network & Computing Codec";
|
||||
case 0x10: return "Entertainment Codec";
|
||||
case 0x80: return "Other Codec";
|
||||
default: return "Unknown Encryption Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x11: {
|
||||
switch(Subclass) {
|
||||
case 0x00: return "DPIO Modules";
|
||||
case 0x01: return "Performance Counters";
|
||||
case 0x10: return "Communication Synchronizer";
|
||||
case 0x20: return "Signal Processing Management";
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Signal Processing Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x12: return "Processing Accelerator";
|
||||
|
||||
case 0x13: return "Non-Essential Instrumentation";
|
||||
|
||||
case 0x14:
|
||||
case 0x41: return "Reserved";
|
||||
|
||||
case 0x40: return "Co-Processor";
|
||||
|
||||
case 0xFF: return "Unassigned Class";
|
||||
|
||||
}
|
||||
|
||||
return "Invalid Device!";
|
||||
}
|
||||
|
||||
const char* PCIGetClassName(uint8_t DeviceClass) {
|
||||
|
||||
switch(DeviceClass) {
|
||||
case 0x00: return "Unclassified";
|
||||
case 0x01: return "Mass Storage Controller";
|
||||
case 0x02: return "Network Controller";
|
||||
case 0x03: return "Display Controller";
|
||||
case 0x04: return "Multimedia Controller";
|
||||
case 0x05: return "Memory Controller";
|
||||
case 0x06: return "Bridge Device";
|
||||
case 0x07: return "Simple Communication Controller";
|
||||
case 0x08: return "Base System Peripheral";
|
||||
case 0x09: return "Input Device Controller";
|
||||
case 0x0A: return "Docking Station";
|
||||
case 0x0B: return "Processor";
|
||||
case 0x0C: return "Serial Bus Controller";
|
||||
case 0x0D: return "Wireless Controller";
|
||||
case 0x0E: return "Intelligent Controller";
|
||||
case 0x0F: return "Satellite Communication Controller";
|
||||
case 0x10: return "Encryption Controller";
|
||||
case 0x11: return "Signal Processing Controller";
|
||||
case 0x12: return "Processing Accelerator";
|
||||
case 0x13: return "Non-Essential Instrumentation";
|
||||
case 0x14: return "Reserved";
|
||||
case 0x40: return "Co-Processor";
|
||||
case 0x41: return "Reserved";
|
||||
case 0xFF: return "Unassigned Class";
|
||||
default: return "Unknown Category";
|
||||
}
|
||||
|
||||
return "Invalid device!";
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
757
src/system/pci.cpp
Normal file
757
src/system/pci.cpp
Normal file
|
@ -0,0 +1,757 @@
|
|||
#include <kernel/chroma.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This file contains functions for accessing the PCI bus,
|
||||
* and devices contained wherein.
|
||||
*
|
||||
* It allows you to query the bus, as well as communicate with individual devices.
|
||||
*
|
||||
*/
|
||||
|
||||
pci_device_t** pci_root_devices = NULL;
|
||||
pci_entry_t* pci_map = NULL;
|
||||
|
||||
//static uint32_t PCIReadConfig(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset);
|
||||
|
||||
//static const char* PCIGetDeviceName_Subclass(uint8_t DeviceClass, uint8_t Subclass, uint8_t ProgrammableInterface);
|
||||
|
||||
//static const char* PCIGetClassName(uint8_t DeviceClass);
|
||||
|
||||
void PCIEnumerate() {
|
||||
|
||||
uint8_t bus = 0, device = 0, function = 0;
|
||||
|
||||
uint32_t registerData;
|
||||
|
||||
uint16_t DeviceID, VendorID;
|
||||
|
||||
uint8_t ClassCode, subclass_code;
|
||||
|
||||
SerialPrintf("[ PCI] Started PCI Enumeration.");
|
||||
|
||||
SerialPrintf("\n[ PCI] PCI Scan result:\n[ PCI]");
|
||||
do {
|
||||
for (device = 0; device <= 31; device++) {
|
||||
for (function = 0; function <= 7; function++) {
|
||||
registerData = PCIReadConfig(bus, device, 0,
|
||||
0xC); // Read BIST/Header/Latency/Cache Line register
|
||||
uint8_t header = (uint8_t) ((registerData & 0x00FF0000)
|
||||
>> 24); // Header is lower byte of upper word, so mask it off and shift it down
|
||||
uint8_t multifunction_bit = header &
|
||||
0x80; // The multifunction bit is the highest bit of the header
|
||||
|
||||
registerData = PCIReadConfig(bus, device, function,
|
||||
0); // Read the Vendor/Device ID register
|
||||
VendorID = (uint16_t) (registerData & 0x0000FFFF); // Vendor ID is bottom word
|
||||
DeviceID = (uint16_t) (registerData >> 16); // Device ID is top word
|
||||
|
||||
registerData = PCIReadConfig(bus, device, function, 8); // Read the Device Info register
|
||||
ClassCode = (uint16_t) (registerData
|
||||
>> 24); // Device class is top byte, so shift them down
|
||||
subclass_code = (uint16_t) ((registerData >> 16) &
|
||||
0x00FF); // Device subclass is same as header - lower byte of higher word. Shift down and mask just like before.
|
||||
uint8_t device_progif = (uint16_t) ((registerData & 0x0000FF00)
|
||||
>> 8); // Device Programming Interface is higher byte of lower word, so mask and shift
|
||||
uint8_t device_revision = (uint16_t) (registerData &
|
||||
0x000000FF); // Device revision is lower byte of whole double word. Just mask it.
|
||||
|
||||
|
||||
/* 0xFFFF is not a valid Vendor ID. This serves as a sanity check.
|
||||
* If this check is true, then nothing is logged and we continue for the next loop.
|
||||
*/
|
||||
if (VendorID != 0xFFFF) {
|
||||
SerialPrintf("[ PCI]\n[ PCI]\t%x:%x:\n[ PCI]\t\tVendor: %x\n[ PCI]\t\tDevice: %x", bus, device,
|
||||
VendorID, DeviceID);
|
||||
SerialPrintf("\n[ PCI]\t\tClass: %s\n[ PCI]\t\tDevice Type: %s\n[ PCI]\t\tRevision: %d\n",
|
||||
PCIGetClassName(ClassCode),
|
||||
PCIGetDeviceName_Subclass(ClassCode, subclass_code, device_progif), device_revision);
|
||||
}
|
||||
|
||||
/* If the PCI Device header tells us that this is not a multifunction device,
|
||||
* and we've already scanned function 0, then there is nothing else to see.
|
||||
* Therefore, stop this loop and move onto device++
|
||||
*/
|
||||
if (multifunction_bit == 0)
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
} while (++bus);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
uint32_t PCIReadConfig(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset) {
|
||||
uint32_t address;
|
||||
uint32_t busLong = (uint32_t) bus;
|
||||
uint32_t slotLong = (uint32_t) slot;
|
||||
uint32_t functionLong = (uint32_t) function;
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* | 31 | 30 ... 24 | 23 ... 16 | 15 ... 11 | 10 ... 8 | 7 ... 0 |
|
||||
* ---------------------------------------------------------------
|
||||
* | EN | RESERVED | BUS NUM | DEVICE NO | FUNC NO | REG OFF |
|
||||
* ---------------------------------------------------------------
|
||||
*
|
||||
* NOTE: REG OFF *must* have 0 last two bits (ie. & 0xFC)
|
||||
*/
|
||||
|
||||
address = (uint32_t) ((busLong << 16) | (slotLong << 11) |
|
||||
(functionLong << 8) | (offset & 0xFC) | ((uint32_t) 0x80000000));
|
||||
|
||||
WritePort(0xCF8, address, 4);
|
||||
|
||||
|
||||
return ReadPort(0xCFC, 4);
|
||||
}
|
||||
|
||||
const char* PCIGetDeviceName_Subclass(uint8_t DeviceClass, uint8_t Subclass, uint8_t ProgrammableInterface) {
|
||||
switch (DeviceClass) {
|
||||
|
||||
case 0x00: {
|
||||
switch (Subclass) {
|
||||
case 0x00:
|
||||
return "Non-VGA-Compatible device";
|
||||
case 0x01:
|
||||
return "VGA-Compatible device";
|
||||
default:
|
||||
return "Unknown Unclassified";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x01: {
|
||||
switch (Subclass) {
|
||||
case 0x00:
|
||||
return "SCSI Bus Controller";
|
||||
case 0x01: {
|
||||
switch (ProgrammableInterface) {
|
||||
case 0x00:
|
||||
return "ISA Compatibility Mode-only IDE Controller";
|
||||
case 0x05:
|
||||
return "PCI Native Mode-only IDE Controller";
|
||||
case 0x0A:
|
||||
return "ISA Compatibility Mode IDE Controller (supports PCI Native Mode)";
|
||||
case 0x0F:
|
||||
return "PCI Native Mode IDE Controller (supports ISA Compatibility Mode)";
|
||||
case 0x80:
|
||||
return "ISA Compatibilty Mode-only IDE Controller (supports Bus Mastering)";
|
||||
case 0x85:
|
||||
return "PCI Native Mode-only IDE Controller (supports Bus Mastering)";
|
||||
case 0x8A:
|
||||
return "ISA Compatibility Mode IDE Controller (supports PCI Native Mode & Bus Mastering)";
|
||||
case 0x8F:
|
||||
return "PCI Native Mode IDE Controller (supports ISA Compatibiliy Mode & Bus Mastering)";
|
||||
default:
|
||||
return "IDE Controller";
|
||||
}
|
||||
}
|
||||
case 0x02:
|
||||
return "Floppy Disk Controller";
|
||||
case 0x03:
|
||||
return "IPI Bus Controller";
|
||||
case 0x04:
|
||||
return "RAID Controller";
|
||||
case 0x05: {
|
||||
switch (ProgrammableInterface) {
|
||||
case 0x20:
|
||||
return "Single-DMA ATA Controller";
|
||||
case 0x30:
|
||||
return "Chained-DMA ATA Controller";
|
||||
default:
|
||||
return "ATA Controller";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
case 0x06: {
|
||||
switch (ProgrammableInterface) {
|
||||
case 0x00:
|
||||
return "Vendor-Specific Interface SATA Controller";
|
||||
case 0x01:
|
||||
return "AHCI 1.0 SATA Controller";
|
||||
case 0x02:
|
||||
return "Serial Storage Bus SATA Controller";
|
||||
default:
|
||||
return "Serial ATA Controller";
|
||||
}
|
||||
}
|
||||
case 0x07:
|
||||
return "Serial Attached SCSI (SAS)";
|
||||
|
||||
case 0x08: {
|
||||
switch (ProgrammableInterface) {
|
||||
case 0x01:
|
||||
return "NVMHCI Memory Controller";
|
||||
case 0x02:
|
||||
return "NVMe Memory Controller";
|
||||
default:
|
||||
return "Non-Volatile Memory Controller";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
case 0x80:
|
||||
return "Other";
|
||||
default:
|
||||
return "Unknown Mass Storage Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x02: {
|
||||
switch (Subclass) {
|
||||
case 0x00:
|
||||
return "Ethernet Controller";
|
||||
case 0x01:
|
||||
return "Token Ring Controller";
|
||||
case 0x02:
|
||||
return "FDDI Controller";
|
||||
case 0x03:
|
||||
return "ATM Controller";
|
||||
case 0x04:
|
||||
return "ISDN Controller";
|
||||
case 0x05:
|
||||
return "WorldFip Controller";
|
||||
case 0x06:
|
||||
return "PICMG 2.14 Multi Computing";
|
||||
case 0x07:
|
||||
return "Infiniband Controller";
|
||||
case 0x08:
|
||||
return "Fabric Controller";
|
||||
case 0x80:
|
||||
return "Other";
|
||||
default:
|
||||
return "Unknown Network Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x03: {
|
||||
switch (Subclass) {
|
||||
case 0x00: {
|
||||
switch (ProgrammableInterface) {
|
||||
case 0x00:
|
||||
return "VGA Controller";
|
||||
case 0x01:
|
||||
return "8514 VGA Controller";
|
||||
default:
|
||||
return "VGA Compatible Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x01:
|
||||
return "XGA Controller";
|
||||
case 0x02:
|
||||
return "3D Controller (Not VGA-Compatible)";
|
||||
case 0x80:
|
||||
return "Other";
|
||||
default:
|
||||
return "Unknown Display Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x04: {
|
||||
switch (Subclass) {
|
||||
case 0x00:
|
||||
return "Multimedia Video Controller";
|
||||
case 0x01:
|
||||
return "Multimedia Audio Controller";
|
||||
case 0x02:
|
||||
return "Computer Telephony Device";
|
||||
case 0x03:
|
||||
return "Audio Device";
|
||||
case 0x80:
|
||||
return "Other";
|
||||
default:
|
||||
return "Unknown Multimedia Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x05: {
|
||||
switch (Subclass) {
|
||||
case 0x00:
|
||||
return "RAM Controller";
|
||||
case 0x01:
|
||||
return "Flash Controller";
|
||||
case 0x80:
|
||||
return "Other";
|
||||
default:
|
||||
return "Unknown Memory Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x06: {
|
||||
switch (Subclass) {
|
||||
case 0x00:
|
||||
return "Host Bridge";
|
||||
case 0x01:
|
||||
return "ISA Bridge";
|
||||
case 0x02:
|
||||
return "EISA Bridge";
|
||||
case 0x03:
|
||||
return "MCA Bridge";
|
||||
case 0x04:
|
||||
case 0x09:
|
||||
return "PCI-to-PCI Bridge";
|
||||
case 0x05:
|
||||
return "PCMCIA Bridge";
|
||||
case 0x06:
|
||||
return "NuBus Bridge";
|
||||
case 0x07:
|
||||
return "CardBus Bridge";
|
||||
case 0x08:
|
||||
return "RACEway Bridge";
|
||||
case 0x0A:
|
||||
return "InfiniBand-to-PCI Host Bridge";
|
||||
case 0x80:
|
||||
return "Other";
|
||||
default:
|
||||
return "Unknown Bridge Device";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x07: {
|
||||
switch (Subclass) {
|
||||
|
||||
case 0x00: {
|
||||
switch (ProgrammableInterface) {
|
||||
case 0x00:
|
||||
return "Serial Controller <8250>";
|
||||
case 0x01:
|
||||
return "Serial controller <16450>";
|
||||
case 0x02:
|
||||
return "Serial controller <16550>";
|
||||
case 0x03:
|
||||
return "Serial controller <16650>";
|
||||
case 0x04:
|
||||
return "Serial controller <16750>";
|
||||
case 0x05:
|
||||
return "Serial controller <16850>";
|
||||
case 0x06:
|
||||
return "Serial controller <16950>";
|
||||
default:
|
||||
return "Serial Controller";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
case 0x01: {
|
||||
switch (ProgrammableInterface) {
|
||||
case 0x00:
|
||||
return "Standard Parallel Port";
|
||||
case 0x01:
|
||||
return "Bi-Directional Parallel Port";
|
||||
case 0x02:
|
||||
return "ECP 1.X Compliant Parallel Port";
|
||||
case 0x03:
|
||||
return "IEEE 1284 Parallel Controller";
|
||||
case 0x04:
|
||||
return "IEE 1284 Parallel Target";
|
||||
default:
|
||||
return "Parallel Controller";
|
||||
}
|
||||
}
|
||||
case 0x02:
|
||||
return "Multiport Serial Controller";
|
||||
|
||||
case 0x03: {
|
||||
switch (ProgrammableInterface) {
|
||||
case 0x00:
|
||||
return "Generic Modem";
|
||||
case 0x01:
|
||||
return "Hayes 16450 Compatible Modem";
|
||||
case 0x02:
|
||||
return "Hayes 16550 Compatible Modem";
|
||||
case 0x03:
|
||||
return "Hayes 16650 Compatible Modem";
|
||||
case 0x04:
|
||||
return "Hayes 16750 Compatible Modem";
|
||||
default:
|
||||
return "Modem";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x04:
|
||||
return "IEEE 488.1/2 (GPIB) Controller";
|
||||
case 0x05:
|
||||
return "Smart Card";
|
||||
case 0x80:
|
||||
return "Other";
|
||||
default:
|
||||
return "Unknown Simple Comms Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x08: {
|
||||
switch (Subclass) {
|
||||
case 0x00: {
|
||||
switch (ProgrammableInterface) {
|
||||
case 0x00:
|
||||
return "Generic 8259-Compatible PIC";
|
||||
case 0x01:
|
||||
return "ISA-Compatible PIC";
|
||||
case 0x02:
|
||||
return "EISA-Compatible PIC";
|
||||
case 0x03:
|
||||
return "I/O APIC Interrupt Controller";
|
||||
case 0x04:
|
||||
return "I/O(x) APIC Interrupt Controller";
|
||||
default:
|
||||
return "PIC";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x01: {
|
||||
switch (ProgrammableInterface) {
|
||||
case 0x00:
|
||||
return "Generic 8237-Compatible DMA Controller";
|
||||
case 0x01:
|
||||
return "ISA-Compatible DMA Controller";
|
||||
case 0x02:
|
||||
return "EISA-Compatible DMA Controller";
|
||||
default:
|
||||
return "DMA Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x02: {
|
||||
switch (ProgrammableInterface) {
|
||||
case 0x00:
|
||||
return "Generic 8254-Compatible Timer";
|
||||
case 0x01:
|
||||
return "ISA-Compatible Timer";
|
||||
case 0x02:
|
||||
return "EISA-Compatible Timer";
|
||||
case 0x03:
|
||||
return "HPET Timer";
|
||||
default:
|
||||
return "Timer";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x03: {
|
||||
switch (ProgrammableInterface) {
|
||||
case 0x00:
|
||||
return "Generic RTC Controller";
|
||||
case 0x01:
|
||||
return "ISA-Compatible RTC Controller";
|
||||
default:
|
||||
return "RTC Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x04:
|
||||
return "PCI Hot-Plug Controller";
|
||||
case 0x05:
|
||||
return "SD Host Controller";
|
||||
case 0x06:
|
||||
return "IOMMU";
|
||||
case 0x80:
|
||||
return "Other";
|
||||
|
||||
default:
|
||||
return "Unknown Base System Peripheral";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x09: {
|
||||
switch (Subclass) {
|
||||
case 0x00:
|
||||
return "Keyboard Controller";
|
||||
case 0x01:
|
||||
return "Digitiser Pen";
|
||||
case 0x02:
|
||||
return "Mouse Controller";
|
||||
case 0x03:
|
||||
return "Scanner Controller";
|
||||
|
||||
case 0x04: {
|
||||
switch (ProgrammableInterface) {
|
||||
case 0x00:
|
||||
return "Generic Gameport Controller";
|
||||
case 0x10:
|
||||
return "Extended Gameport Controller";
|
||||
default:
|
||||
return "Gameport Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x80:
|
||||
return "Other";
|
||||
|
||||
default:
|
||||
return "Unknown Input Device Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x0A: {
|
||||
switch (Subclass) {
|
||||
case 0x00:
|
||||
return "Generic Docking Station";
|
||||
case 0x80:
|
||||
return "Other";
|
||||
default:
|
||||
return "Unknown Docking Station";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x0B: {
|
||||
switch (Subclass) {
|
||||
case 0x00:
|
||||
return "386 Processor";
|
||||
case 0x01:
|
||||
return "486 Processor";
|
||||
case 0x02:
|
||||
return "Pentium Processor";
|
||||
case 0x03:
|
||||
return "Pentium Pro Processor";
|
||||
case 0x10:
|
||||
return "Alpha Processor";
|
||||
case 0x20:
|
||||
return "PowerPC Processor";
|
||||
case 0x30:
|
||||
return "MIPS Processor";
|
||||
case 0x40:
|
||||
return "Co-Processor";
|
||||
case 0x80:
|
||||
return "Other";
|
||||
default:
|
||||
return "Unknown Processor";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x0C: {
|
||||
switch (Subclass) {
|
||||
case 0x00: {
|
||||
switch (ProgrammableInterface) {
|
||||
case 0x00:
|
||||
return "Generic Firewire Controller";
|
||||
case 0x10:
|
||||
return "OHCI Firewire Controller";
|
||||
default:
|
||||
return "FireWire (IEEE 1394) Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x01:
|
||||
return "ACCESS Bus";
|
||||
case 0x02:
|
||||
return "SSA";
|
||||
|
||||
case 0x03: {
|
||||
switch (ProgrammableInterface) {
|
||||
case 0x00:
|
||||
return "UHCI USB Controller";
|
||||
case 0x10:
|
||||
return "OHCI USB Controller";
|
||||
case 0x20:
|
||||
return "EHCI USB (2.0) Controller";
|
||||
case 0x30:
|
||||
return "XHCI USB (3.0) Controller";
|
||||
case 0x80:
|
||||
return "Unspecified USB Controller";
|
||||
case 0xFE:
|
||||
return "USB Device (NOT a Controller)";
|
||||
default:
|
||||
return "USB Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x04:
|
||||
return "Fibre Channel";
|
||||
case 0x05:
|
||||
return "SMBus";
|
||||
case 0x06:
|
||||
return "InfiniBand";
|
||||
|
||||
case 0x07: {
|
||||
switch (ProgrammableInterface) {
|
||||
case 0x00:
|
||||
return "SMIC IPMI Interface";
|
||||
case 0x01:
|
||||
return "Keyboard Controller-Style IPMI Interface";
|
||||
case 0x02:
|
||||
return "Block Transfer IPMI Interface";
|
||||
default:
|
||||
return "IPMI Interface";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x08:
|
||||
return "SERCOS Interface (IEC 61491)";
|
||||
case 0x09:
|
||||
return "CANbus";
|
||||
case 0x80:
|
||||
return "Other";
|
||||
default:
|
||||
return "Unknown Serial Bus Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x0D: {
|
||||
switch (Subclass) {
|
||||
case 0x00:
|
||||
return "IRDA Compatible Controller";
|
||||
case 0x01:
|
||||
return "Consumer IR Controller";
|
||||
case 0x10:
|
||||
return "RF Controller";
|
||||
case 0x11:
|
||||
return "Bluetooth Controller";
|
||||
case 0x12:
|
||||
return "Broadband Controller";
|
||||
case 0x20:
|
||||
return "Ethernet Controller (802.1a)";
|
||||
case 0x21:
|
||||
return "Ethernet Controller (802.1b)";
|
||||
case 0x80:
|
||||
return "Other";
|
||||
default:
|
||||
return "Unknown Wireless Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x0E: {
|
||||
switch (Subclass) {
|
||||
case 0x00:
|
||||
return "I20";
|
||||
default:
|
||||
return "Unknown Intelligent Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x0F: {
|
||||
switch (Subclass) {
|
||||
case 0x01:
|
||||
return "Satellite TV Controller";
|
||||
case 0x02:
|
||||
return "Satellite Audio Controller";
|
||||
case 0x03:
|
||||
return "Satellite Voice Controller";
|
||||
case 0x04:
|
||||
return "Satellite Data Controller";
|
||||
default:
|
||||
return "Unknown Satelllite Comms Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x10: {
|
||||
switch (Subclass) {
|
||||
case 0x00:
|
||||
return "Network & Computing Codec";
|
||||
case 0x10:
|
||||
return "Entertainment Codec";
|
||||
case 0x80:
|
||||
return "Other Codec";
|
||||
default:
|
||||
return "Unknown Encryption Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x11: {
|
||||
switch (Subclass) {
|
||||
case 0x00:
|
||||
return "DPIO Modules";
|
||||
case 0x01:
|
||||
return "Performance Counters";
|
||||
case 0x10:
|
||||
return "Communication Synchronizer";
|
||||
case 0x20:
|
||||
return "Signal Processing Management";
|
||||
case 0x80:
|
||||
return "Other";
|
||||
default:
|
||||
return "Unknown Signal Processing Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x12:
|
||||
return "Processing Accelerator";
|
||||
|
||||
case 0x13:
|
||||
return "Non-Essential Instrumentation";
|
||||
|
||||
case 0x14:
|
||||
case 0x41:
|
||||
return "Reserved";
|
||||
|
||||
case 0x40:
|
||||
return "Co-Processor";
|
||||
|
||||
case 0xFF:
|
||||
return "Unassigned Class";
|
||||
|
||||
}
|
||||
|
||||
return "Invalid Device!";
|
||||
}
|
||||
|
||||
const char* PCIGetClassName(uint8_t DeviceClass) {
|
||||
|
||||
switch (DeviceClass) {
|
||||
case 0x00:
|
||||
return "Unclassified";
|
||||
case 0x01:
|
||||
return "Mass Storage Controller";
|
||||
case 0x02:
|
||||
return "Network Controller";
|
||||
case 0x03:
|
||||
return "Display Controller";
|
||||
case 0x04:
|
||||
return "Multimedia Controller";
|
||||
case 0x05:
|
||||
return "Memory Controller";
|
||||
case 0x06:
|
||||
return "Bridge Device";
|
||||
case 0x07:
|
||||
return "Simple Communication Controller";
|
||||
case 0x08:
|
||||
return "Base System Peripheral";
|
||||
case 0x09:
|
||||
return "Input Device Controller";
|
||||
case 0x0A:
|
||||
return "Docking Station";
|
||||
case 0x0B:
|
||||
return "Processor";
|
||||
case 0x0C:
|
||||
return "Serial Bus Controller";
|
||||
case 0x0D:
|
||||
return "Wireless Controller";
|
||||
case 0x0E:
|
||||
return "Intelligent Controller";
|
||||
case 0x0F:
|
||||
return "Satellite Communication Controller";
|
||||
case 0x10:
|
||||
return "Encryption Controller";
|
||||
case 0x11:
|
||||
return "Signal Processing Controller";
|
||||
case 0x12:
|
||||
return "Processing Accelerator";
|
||||
case 0x13:
|
||||
return "Non-Essential Instrumentation";
|
||||
case 0x14:
|
||||
return "Reserved";
|
||||
case 0x40:
|
||||
return "Co-Processor";
|
||||
case 0x41:
|
||||
return "Reserved";
|
||||
case 0xFF:
|
||||
return "Unassigned Class";
|
||||
default:
|
||||
return "Unknown Category";
|
||||
}
|
||||
|
||||
return "Invalid device!";
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
27
src/system/process/process.cpp
Normal file
27
src/system/process/process.cpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
#include <kernel/chroma.h>
|
||||
#include <kernel/system/process/process.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2021 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
// An array of pointers to the header of each active process.
|
||||
Process** processes;
|
||||
// An array of pointers to the header of each process active on the current core.
|
||||
Process* processesPerCore[MAX_CORES];
|
||||
|
||||
// A lock "counter". This can be increased and decreased at will.
|
||||
// Positive values mean the process is being locked by another, zero and negative means it is active.
|
||||
int locked = 0;
|
||||
// Whether the current process is fully loaded into memory and ready to run.
|
||||
bool loaded = false;
|
||||
|
||||
// A ticketlock that prevents two threads being created at the same time.
|
||||
ticketlock_t creatorlock;
|
||||
// A ticketlock that prevents two threads from being switched into at the same time.
|
||||
ticketlock_t switcherlock;
|
||||
|
||||
// The PID of the next process to be created. The kernel is always 0.
|
||||
size_t nextPID = 1;
|
||||
|
|
@ -19,56 +19,56 @@ 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) :);
|
||||
}
|
||||
|
||||
|
|
@ -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]);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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,19 +216,19 @@ 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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user