Large rewrites & struggles
This commit is contained in:
parent
06134ebcd9
commit
acda33948e
|
@ -14,51 +14,53 @@ SET(CMAKE_CROSSCOMPILING 1)
|
||||||
project(chroma)
|
project(chroma)
|
||||||
|
|
||||||
SET(src_files
|
SET(src_files
|
||||||
${CMAKE_SOURCE_DIR}/src/kernel.cpp
|
${CMAKE_SOURCE_DIR}/src/kernel.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/video/draw.c
|
${CMAKE_SOURCE_DIR}/src/video/draw.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/video/print.cpp
|
${CMAKE_SOURCE_DIR}/src/video/print.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/system/cpu.c
|
${CMAKE_SOURCE_DIR}/src/system/cpu.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/system/rw.c
|
${CMAKE_SOURCE_DIR}/src/system/core.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/system/serial.c
|
${CMAKE_SOURCE_DIR}/src/system/rw.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/system/pci.c
|
${CMAKE_SOURCE_DIR}/src/system/serial.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/system/memory/stack.c
|
${CMAKE_SOURCE_DIR}/src/system/pci.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/system/memory/paging.c
|
${CMAKE_SOURCE_DIR}/src/system/acpi/MADT.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/system/memory/abstract_allocator.c
|
${CMAKE_SOURCE_DIR}/src/system/acpi/RSDP.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/system/memory/liballoc.c
|
${CMAKE_SOURCE_DIR}/src/system/memory/paging.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/system/memory/physmem.c
|
${CMAKE_SOURCE_DIR}/src/system/memory/abstract_allocator.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/drivers/keyboard.c
|
${CMAKE_SOURCE_DIR}/src/system/memory/liballoc.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/drivers/elf.c
|
${CMAKE_SOURCE_DIR}/src/system/memory/physmem.c
|
||||||
${CMAKE_SOURCE_DIR}/src/drivers/devices/devices.cpp
|
${CMAKE_SOURCE_DIR}/src/system/process/process.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/drivers/devices/storage/ata.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
|
SET(lib_files
|
||||||
${CMAKE_SOURCE_DIR}/src/lainlib/list/basic_list.c
|
${CMAKE_SOURCE_DIR}/src/lainlib/list/basic_list.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/lainlib/mutex/ticketlock.c
|
${CMAKE_SOURCE_DIR}/src/lainlib/mutex/ticketlock.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/lainlib/compression/lzgmini.c
|
${CMAKE_SOURCE_DIR}/src/lainlib/compression/lzgmini.c
|
||||||
${CMAKE_SOURCE_DIR}/src/lainlib/string/str.c
|
${CMAKE_SOURCE_DIR}/src/lainlib/string/str.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/src/editor/EditorMain.cpp
|
||||||
${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")
|
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
|
SET(src_no_sse
|
||||||
${CMAKE_SOURCE_DIR}/src/system/interrupts.c
|
${CMAKE_SOURCE_DIR}/src/system/interrupts.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
SET(src_preamble
|
SET(src_preamble
|
||||||
${CMAKE_SOURCE_DIR}/src/global/crt0.o
|
${CMAKE_SOURCE_DIR}/src/global/crt0.o
|
||||||
${CMAKE_SOURCE_DIR}/src/global/crti.o
|
${CMAKE_SOURCE_DIR}/src/global/crti.o
|
||||||
${CMAKE_SOURCE_DIR}/src/global/crtbegin.o
|
${CMAKE_SOURCE_DIR}/src/global/crtbegin.o
|
||||||
)
|
)
|
||||||
|
|
||||||
set(src_epilogue
|
set(src_epilogue
|
||||||
${CMAKE_SOURCE_DIR}/src/global/crtend.o
|
${CMAKE_SOURCE_DIR}/src/global/crtend.o
|
||||||
${CMAKE_SOURCE_DIR}/src/global/crtn.o
|
${CMAKE_SOURCE_DIR}/src/global/crtn.o
|
||||||
${CMAKE_SOURCE_DIR}/src/assets/font.o
|
${CMAKE_SOURCE_DIR}/src/assets/font.o
|
||||||
${CMAKE_SOURCE_DIR}/src/assets/zerosharp.o
|
${CMAKE_SOURCE_DIR}/src/assets/zerosharp.o
|
||||||
)
|
)
|
||||||
|
|
||||||
set_property(SOURCE ${src_no_sse} PROPERTY COMPILE_FLAGS -mgeneral-regs-only)
|
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)
|
add_executable(kernel)
|
||||||
|
|
||||||
target_sources(kernel PUBLIC ${src_preamble} PUBLIC ${src_files} PUBLIC ${src_no_sse} PUBLIC ${lib_files} PUBLIC ${src_epilogue})
|
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)
|
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.
|
// The internal typemap of devices used in Chroma.
|
||||||
enum DeviceType : uint32_t {
|
enum DeviceType : uint32_t {
|
||||||
STORAGE = 0,
|
STORAGE = 0, // Stores data.
|
||||||
KEYBOARD = 1,
|
INTERNAL = 1, // PCI, APIC, AHCI.
|
||||||
NETWORK = 2,
|
INTERFACE = 2, // Peripherals and I/O
|
||||||
UNKNOWN = 0xFFFFFFFF
|
NETWORK = 3, // NIC.
|
||||||
|
UNKNOWN = 0xFFFFFFFF // Unsupported.
|
||||||
};
|
};
|
||||||
|
|
||||||
// The base class that all devices extend from.
|
// 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.
|
// Add a device pointer to the managed list.
|
||||||
void RegisterDevice(GenericDevice* Dev);
|
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 ***
|
*** Chroma ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
@ -11,8 +13,10 @@ extern "C" {
|
||||||
/*
|
/*
|
||||||
;* Memory map
|
;* Memory map
|
||||||
;* 0h - 600h reserved for the system
|
;* 0h - 600h reserved for the system
|
||||||
|
* V----------- CAN REMOVE -----------V
|
||||||
;* 600h - 800h stage1 (MBR/VBR, boot.bin)
|
;* 600h - 800h stage1 (MBR/VBR, boot.bin)
|
||||||
;* 800h - 6C00h stage2 (this)
|
;* 800h - 6C00h stage2 (this)
|
||||||
|
* ∧----------- CAN REMOVE -----------∧
|
||||||
;* 6C00h - 7C00h stack (7000h - 700Fh SMP trampoline code)
|
;* 6C00h - 7C00h stack (7000h - 700Fh SMP trampoline code)
|
||||||
;* 8000h - 9000h bootboot structure
|
;* 8000h - 9000h bootboot structure
|
||||||
;* 9000h - A000h environment
|
;* 9000h - A000h environment
|
||||||
|
@ -111,7 +115,7 @@ typedef struct {
|
||||||
uint8_t protocol; /* 1, static addresses, see PROTOCOL_* and LOADER_* above */
|
uint8_t protocol; /* 1, static addresses, see PROTOCOL_* and LOADER_* above */
|
||||||
uint8_t fb_type; /* framebuffer type, see FB_* above */
|
uint8_t fb_type; /* framebuffer type, see FB_* above */
|
||||||
uint16_t numcores; /* number of processor cores */
|
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 */
|
int16_t timezone; /* in minutes -1440..1440 */
|
||||||
uint8_t datetime[8]; /* in BCD yyyymmddhhiiss UTC (independent to timezone) */
|
uint8_t datetime[8]; /* in BCD yyyymmddhhiiss UTC (independent to timezone) */
|
||||||
uint64_t initrd_ptr; /* ramdisk image position and size */
|
uint64_t initrd_ptr; /* ramdisk image position and size */
|
||||||
|
|
|
@ -24,7 +24,10 @@ extern "C" {
|
||||||
#include <kernel/system/io.h>
|
#include <kernel/system/io.h>
|
||||||
#include <kernel/system/memory.h>
|
#include <kernel/system/memory.h>
|
||||||
#include <kernel/system/pci.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/lainlib.h>
|
||||||
#include <lainlib/ethernet/e1000/e1000.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;
|
uint16_t IOMap;
|
||||||
} TSS64;
|
} 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
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
|
@ -37,9 +37,9 @@ extern IRQHandler IRQ_Handlers[16];
|
||||||
|
|
||||||
void InstallIRQ(int IRQ, void (*Handler)(INTERRUPT_FRAME* Frame));
|
void InstallIRQ(int IRQ, void (*Handler)(INTERRUPT_FRAME* Frame));
|
||||||
|
|
||||||
void IRQ_Common(INTERRUPT_FRAME* Frame, size_t Interupt);
|
__attribute__((no_caller_saved_registers)) void IRQ_Common(INTERRUPT_FRAME* Frame, size_t Interupt);
|
||||||
void ISR_Common(INTERRUPT_FRAME* Frame, size_t Interrupt);
|
__attribute__((no_caller_saved_registers)) 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 ISR_Error_Common(INTERRUPT_FRAME* Frame, size_t ErrorCode, size_t Exception);
|
||||||
|
|
||||||
void RemapIRQControllers();
|
void RemapIRQControllers();
|
||||||
|
|
||||||
|
|
|
@ -132,6 +132,8 @@ extern "C" {
|
||||||
#define STACK_TOP 0xFFFFFFFFFFFFF000ull // The start of the highest stack
|
#define STACK_TOP 0xFFFFFFFFFFFFF000ull // The start of the highest stack
|
||||||
#define MEM_CEILING 0xFFFFFFFFFFFFFFFFull // The top of the stack in the map
|
#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 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
|
#define KERNEL_STACK_REGION 0xFFFFE00000000000ull // Kernel Stack Space
|
||||||
|
|
|
@ -16,6 +16,8 @@ extern "C" {
|
||||||
* required to compatibly access the PCI bus,
|
* required to compatibly access the PCI bus,
|
||||||
* as well as set up new PCI devices, PCI bridges, and manipulate
|
* as well as set up new PCI devices, PCI bridges, and manipulate
|
||||||
* the connections of PCI lanes.
|
* the connections of PCI lanes.
|
||||||
|
*
|
||||||
|
* TODO: Refactor for consistent naming style
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PCI_CONFIG_ADDRESS 0xCF8
|
#define PCI_CONFIG_ADDRESS 0xCF8
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#define MAX_PROCESSES 128
|
#define MAX_PROCESSES 128
|
||||||
#define PROCESS_STACK 65535
|
#define PROCESS_STACK 65535
|
||||||
|
|
||||||
typedef void (*function_t)();
|
typedef void (* function_t)();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief All the data a process needs.
|
* @brief All the data a process needs.
|
||||||
|
@ -68,138 +68,147 @@ class Process {
|
||||||
address_space_t* AddressSpace;
|
address_space_t* AddressSpace;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ProcessHeader Header;
|
ProcessHeader Header;
|
||||||
ProcessState State;
|
ProcessState State;
|
||||||
|
|
||||||
bool User; // Is this process originated in userspace?
|
bool User; // Is this process originated in userspace?
|
||||||
bool System; // Was this process started by the system (ie. not user interaction)
|
bool System; // Was this process started by the system (ie. not user interaction)
|
||||||
|
|
||||||
size_t UniquePID; // Globally Unique ID.
|
size_t UniquePID; // Globally Unique ID.
|
||||||
size_t KernelPID; // If in kernel space, the PID.
|
size_t KernelPID; // If in kernel space, the PID.
|
||||||
size_t ParentPID; // If this process was forked, the parent's PID.
|
size_t ParentPID; // If this process was forked, the parent's PID. Otherwise, the kernel.
|
||||||
|
|
||||||
char Name[128];
|
char Name[128];
|
||||||
size_t Entry; // The entry point. Move execution here to start the process.
|
size_t Entry; // The entry point. Move execution here to start the process.
|
||||||
uint8_t Core;
|
uint8_t Core;
|
||||||
|
|
||||||
bool ORS = false;
|
bool ORS = false;
|
||||||
bool IsActive = false;
|
bool IsActive = false;
|
||||||
bool IsInterrupted = false; // True if an interrupt was fired while this process is active
|
bool IsInterrupted = false; // True if an interrupt was fired while this process is active
|
||||||
|
|
||||||
uint8_t Signals[8]; // Interrupt / IRQ / Signal handlers.
|
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 Sleeping; // 0 if active, else the process is waiting for something. TODO: remove this, use State?
|
||||||
|
|
||||||
ProcessMessage* Messages; // A queue of IPC messages.
|
ProcessMessage* Messages; // A queue of IPC messages.
|
||||||
size_t LastMessage; // The index of the current message.
|
size_t LastMessage; // The index of the current message.
|
||||||
|
|
||||||
uint8_t* ProcessMemory;
|
uint8_t* ProcessMemory;
|
||||||
size_t ProcessMemorySize;
|
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)
|
Process(const char* ProcessName, size_t KPID, size_t UPID, size_t EntryPoint, bool Userspace)
|
||||||
: UniquePID(UPID), KernelPID(KPID), Entry(EntryPoint), ORS(false), LastMessage(0), User(Userspace), Sleeping(0) {
|
: User(Userspace), UniquePID(UPID), KernelPID(KPID), Entry(EntryPoint), ORS(false), Sleeping(0),
|
||||||
|
LastMessage(0) {
|
||||||
|
|
||||||
memcpy((void*) ProcessName, Name, strlen(Name) + 1);
|
memcpy((void*) ProcessName, Name, strlen(Name) + 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
Process(const Process &Instance) {
|
Process(const Process &Instance) {
|
||||||
memcpy(this, &Instance, sizeof(Process));
|
memcpy(this, &Instance, sizeof(Process));
|
||||||
};
|
};
|
||||||
|
|
||||||
Process& operator=(const Process &Instance) {
|
Process &operator =(const Process &Instance) {
|
||||||
memcpy(this, &Instance, sizeof(Process));
|
memcpy(this, &Instance, sizeof(Process));
|
||||||
return *this;
|
return *this;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*************************************************************/
|
/*************************************************************/
|
||||||
|
|
||||||
void InitMemory();
|
void InitMemory();
|
||||||
|
|
||||||
void InitMessages();
|
void InitMessages();
|
||||||
|
|
||||||
void Kill() {
|
void Kill() {
|
||||||
State = ProcessState::PROCESS_REAP;
|
State = ProcessState::PROCESS_REAP;
|
||||||
Sleeping = -1;
|
Sleeping = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
void Destroy();
|
void Destroy();
|
||||||
|
|
||||||
void Rename(const char* NewName) {
|
void Rename(const char* NewName) {
|
||||||
memcpy(Name, NewName, strlen(Name) > strlen(NewName) ? strlen(Name) : strlen(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);
|
void SetState(ProcessState NewState) { State = NewState; };
|
||||||
size_t FreeProcessSpace(size_t* Address, size_t Bytes);
|
|
||||||
|
|
||||||
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) {
|
void DecreaseSleep(size_t Interval) { Sleeping -= Interval; };
|
||||||
System = Status;
|
|
||||||
if(System && User) {
|
|
||||||
// TODO: Log error.
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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; };
|
size_t GetPID() const { return UniquePID; };
|
||||||
void DecreaseSleep(size_t Interval) { Sleeping -= Interval; };
|
|
||||||
|
|
||||||
/*************************************************************/
|
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; };
|
bool IsValid() const { return KernelPID != 0; };
|
||||||
size_t GetKPID() const { return KernelPID; };
|
|
||||||
|
|
||||||
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 IsUserspace() { return User; };
|
||||||
bool flag = !(ORS && !IsActive);
|
|
||||||
|
|
||||||
return State == ProcessState::PROCESS_WAITING && Core == CPU && KernelPID != 0 && flag && !IsSleeping();
|
bool IsSystem() { return System; };
|
||||||
};
|
|
||||||
|
|
||||||
size_t GetCore() const { return Core; };
|
|
||||||
|
|
||||||
bool IsUserspace() { return User; };
|
|
||||||
bool IsSystem() { return System; };
|
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************/
|
/*************************************************************/
|
||||||
|
|
||||||
static Process* FromName(const char* name);
|
static Process* FromName(const char* name);
|
||||||
static Process* FromPID(size_t PID);
|
|
||||||
static Process* Current();
|
|
||||||
|
|
||||||
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.
|
* Stuff like switching tasks, sleeping, killing, etc.
|
||||||
*/
|
*/
|
||||||
class ProcessManagement {
|
class ProcessManagement {
|
||||||
public:
|
public:
|
||||||
TSS64 TSS[MAX_CORES];
|
TSS64 TSS[MAX_CORES];
|
||||||
uint32_t CoreCount = 1;
|
uint32_t CoreCount = 1;
|
||||||
|
|
||||||
ProcessManagement();
|
ProcessManagement();
|
||||||
static ProcessManagement* instance();
|
|
||||||
|
|
||||||
void Wait();
|
static ProcessManagement* instance();
|
||||||
void Initialize();
|
|
||||||
void InitialiseCore(size_t APIC, size_t ID);
|
|
||||||
|
|
||||||
void NotifyAllCores();
|
void Wait();
|
||||||
|
|
||||||
void DumpProcess(size_t PID);
|
void Initialize();
|
||||||
void LockProcess(size_t PID);
|
|
||||||
void UnlockProcess(size_t PID);
|
|
||||||
|
|
||||||
static void Sleep(size_t Count);
|
void InitialiseCore(size_t APIC, size_t ID);
|
||||||
void Sleep(size_t Count, size_t PID);
|
|
||||||
|
|
||||||
static void Kill(int Code);
|
void NotifyAllCores();
|
||||||
void Kill(size_t PID, int Code);
|
|
||||||
|
|
||||||
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*
|
void UnlockProcess(size_t PID);
|
||||||
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);
|
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;
|
extern PRINTINFO PrintInfo;
|
||||||
|
|
||||||
void DrawPixel(size_t x, size_t y);
|
void DrawPixel(size_t x, size_t y);
|
||||||
void FillScreen();
|
void FillScreen(uint32_t color);
|
||||||
|
|
||||||
void SetForegroundColor(uint32_t color);
|
void SetForegroundColor(uint32_t color);
|
||||||
uint32_t GetForegroundColor();
|
uint32_t GetForegroundColor();
|
||||||
|
|
|
@ -22,7 +22,7 @@ Device::GenericStorage* StorageDevicesArray[MAX_STORAGE_DEVICES];
|
||||||
size_t CurrentStorageDevice = 0;
|
size_t CurrentStorageDevice = 0;
|
||||||
|
|
||||||
// Internal storage. TODO: Make this not a pain to maintain
|
// 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.
|
// Add a device pointer to the managed list.
|
||||||
|
@ -30,7 +30,8 @@ void Device::RegisterDevice(Device::GenericDevice* Device) {
|
||||||
DevicesArray[CurrentDevice] = Device;
|
DevicesArray[CurrentDevice] = Device;
|
||||||
Device->DeviceID = CurrentDevice;
|
Device->DeviceID = CurrentDevice;
|
||||||
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.
|
// Retrieve a device pointer from the managed list.
|
||||||
|
@ -54,8 +55,8 @@ size_t Device::GetTotalDevices() { return CurrentDevice; }
|
||||||
template <typename T>
|
template <typename T>
|
||||||
// Get the first registered instance of a specific type of device
|
// Get the first registered instance of a specific type of device
|
||||||
T* Device::FindDevice() {
|
T* Device::FindDevice() {
|
||||||
for(size_t i = 0; i < CurrentDevice; i++)
|
for (size_t i = 0; i < CurrentDevice; i++)
|
||||||
if(DevicesArray[i]->GetType() == T::GetRootType())
|
if (DevicesArray[i]->GetType() == T::GetRootType())
|
||||||
return static_cast<T*>(DevicesArray[i]);
|
return static_cast<T*>(DevicesArray[i]);
|
||||||
|
|
||||||
SerialPrintf("[DEVICE] Warning: Unable to find a %s device.\r\n", DeviceNames[T::GetRootType()]);
|
SerialPrintf("[DEVICE] Warning: Unable to find a %s device.\r\n", DeviceNames[T::GetRootType()]);
|
||||||
|
|
|
@ -23,59 +23,59 @@ extern "C" {
|
||||||
KBD_FLAGS KbdFlags;
|
KBD_FLAGS KbdFlags;
|
||||||
|
|
||||||
char keys[128] = {
|
char keys[128] = {
|
||||||
0, 27,
|
0, 27,
|
||||||
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
|
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
|
||||||
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
|
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
|
||||||
0,
|
0,
|
||||||
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '#',
|
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '#',
|
||||||
0,
|
0,
|
||||||
'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/',
|
'\\', '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,
|
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] = {
|
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;
|
static int CurrentCallback = 0;
|
||||||
|
|
||||||
int SetupKBCallback(void (*Handler)(KeyboardData Frame)) {
|
int SetupKBCallback(void (* Handler)(KeyboardData Frame)) {
|
||||||
KeyboardCallbacks[CurrentCallback++] = Handler;
|
KeyboardCallbacks[CurrentCallback++] = Handler;
|
||||||
return CurrentCallback;
|
return CurrentCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UninstallKBCallback(int Number) {
|
void UninstallKBCallback(int Number) {
|
||||||
KeyboardCallbacks[Number] = NULL; // 0 is used in the common check to make sure that the function is callable.
|
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.
|
// This removes this callback from that check, ergo the function will no longer be called.
|
||||||
}
|
}
|
||||||
|
|
||||||
void KbdEcho() {
|
void KbdEcho() {
|
||||||
if(!KbdFlags.EchoCount) {
|
if (!KbdFlags.EchoCount) {
|
||||||
if(!KbdFlags.Echo) {
|
if (!KbdFlags.Echo) {
|
||||||
Send8042(0xEE);
|
Send8042(0xEE);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -87,7 +87,7 @@ void KbdEcho() {
|
||||||
|
|
||||||
void UpdateKeyboard(uint8_t msg) {
|
void UpdateKeyboard(uint8_t msg) {
|
||||||
|
|
||||||
switch(msg) {
|
switch (msg) {
|
||||||
case 0x0:
|
case 0x0:
|
||||||
KbdFlags.Error = 1;
|
KbdFlags.Error = 1;
|
||||||
//ResendBuffer();
|
//ResendBuffer();
|
||||||
|
@ -122,25 +122,25 @@ void UpdateKeyboard(uint8_t msg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyboardData data = (KeyboardData) {
|
KeyboardData data = (KeyboardData) {
|
||||||
.Scancode = msg,
|
.Char = msg > 0x80 && msg < 0xD8 ? keys[msg - 0x80] : keys[msg],
|
||||||
.Pressed = msg > 0x80 && msg < 0xD8 ? false : true,
|
.Scancode = static_cast<char>(msg),
|
||||||
.Char = msg > 0x80 && msg < 0xD8 ? keys[msg - 0x80] : keys[msg]
|
.Pressed = !(msg > 0x80 && msg < 0xD8),
|
||||||
};
|
};
|
||||||
|
|
||||||
void (*Handler)(KeyboardData data);
|
void (* Handler)(KeyboardData data);
|
||||||
|
|
||||||
for(size_t handlerNum = 0; handlerNum < 16; handlerNum++) {
|
for (size_t handlerNum = 0; handlerNum < 16; handlerNum++) {
|
||||||
Handler = KeyboardCallbacks[handlerNum];
|
Handler = KeyboardCallbacks[handlerNum];
|
||||||
if(Handler) {
|
if (Handler) {
|
||||||
Handler(data);
|
Handler(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Send8042(size_t info) {
|
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;
|
unsigned char chr = (unsigned char) info;
|
||||||
if(chr != 0) {
|
if (chr != 0) {
|
||||||
WritePort(0x60, chr, 1);
|
WritePort(0x60, chr, 1);
|
||||||
WaitFor8042();
|
WaitFor8042();
|
||||||
}
|
}
|
||||||
|
@ -149,10 +149,10 @@ void Send8042(size_t info) {
|
||||||
|
|
||||||
void WaitFor8042() {
|
void WaitFor8042() {
|
||||||
|
|
||||||
bool full = true;
|
bool full = true;
|
||||||
while(full) {
|
while (full) {
|
||||||
full = ReadPort(0x64, 1) & 1;
|
full = ReadPort(0x64, 1) & 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#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 ParseKernelHeader(size_t InitrdPtr) {
|
||||||
int flag = 0;
|
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...
|
// 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;
|
size_t headerLoc = 0;
|
||||||
for(size_t i = InitrdPtr; i < ((size_t) (&_kernel_text_start) - KernelAddr) + InitrdPtr; i++) {
|
for (size_t i = InitrdPtr; i < ((size_t) (&_kernel_text_start) - KernelAddr) + InitrdPtr; i++) {
|
||||||
if(*((volatile uint32_t*)(i)) == ELF64MAGIC) {
|
if (*((volatile uint32_t*) (i)) == ELF64MAGIC) {
|
||||||
SerialPrintf("[ boot] Matched kernel header at 0x%p.\r\n", i);
|
SerialPrintf("[ boot] Matched kernel header at 0x%p.\r\n", i);
|
||||||
headerLoc = 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);
|
SerialPrintf("[ boot] Matched little-endian kernel header at 0x%p.\r\n", i);
|
||||||
headerLoc = 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
|
/* 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.
|
* 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
|
* 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 EntryPoint0 = FIXENDIAN16(*((volatile uint16_t*) (headerLoc + ELFENTRY_OFF)));
|
||||||
uint16_t EntryPoint1 = FIXENDIAN16(*((volatile uint16_t*)(headerLoc + ELFENTRY_OFF + 2)));
|
uint16_t EntryPoint1 = FIXENDIAN16(*((volatile uint16_t*) (headerLoc + ELFENTRY_OFF + 2)));
|
||||||
uint16_t EntryPoint2 = FIXENDIAN16(*((volatile uint16_t*)(headerLoc + ELFENTRY_OFF + 4)));
|
uint16_t EntryPoint2 = FIXENDIAN16(*((volatile uint16_t*) (headerLoc + ELFENTRY_OFF + 4)));
|
||||||
uint16_t EntryPoint3 = FIXENDIAN16(*((volatile uint16_t*)(headerLoc + ELFENTRY_OFF + 6)));
|
uint16_t EntryPoint3 = FIXENDIAN16(*((volatile uint16_t*) (headerLoc + ELFENTRY_OFF + 6)));
|
||||||
size_t EntryPoint = ((size_t) EntryPoint0 << 48) | ((size_t) EntryPoint1 << 32) | ((size_t) EntryPoint2 << 16) | ((size_t) EntryPoint3);
|
size_t EntryPoint = ((size_t) EntryPoint0 << 48) | ((size_t) EntryPoint1 << 32) | ((size_t) EntryPoint2 << 16) |
|
||||||
|
((size_t) EntryPoint3);
|
||||||
|
|
||||||
/* At this point, EntryPoint is a little-endian 64 bit integer. That means we have to fix its endianness in order to read it */
|
/* 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));
|
SerialPrintf("[ boot] Fixing entry point from 0x%p to 0x%p\r\n", EntryPoint, FIXENDIAN64(EntryPoint));
|
||||||
EntryPoint = FIXENDIAN64(EntryPoint);
|
EntryPoint = FIXENDIAN64(EntryPoint);
|
||||||
|
|
||||||
/* Now we can continue as normal */
|
/* Now we can continue as normal */
|
||||||
uint8_t HeaderClass = *((volatile uint8_t*)(headerLoc + ELF_IDENT_CLASS_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 ExecutableType = (uint16_t) *((volatile uint8_t*) (headerLoc + ELFTYPE_OFF));
|
||||||
uint16_t MachineType = (uint16_t) *((volatile uint8_t*)(headerLoc + ELFMACHINE_OFF));
|
uint16_t MachineType = (uint16_t) *((volatile uint8_t*) (headerLoc + ELFMACHINE_OFF));
|
||||||
|
|
||||||
|
|
||||||
SerialPrintf(
|
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",
|
"[ 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,
|
headerLoc,
|
||||||
HeaderClass == 2 ? 64 : 32,
|
HeaderClass == 2 ? 64 : 32,
|
||||||
HeaderClass,
|
HeaderClass,
|
||||||
EntryPoint,
|
EntryPoint,
|
||||||
ExecutableType == FIXENDIAN16(0x0200) ? "EXECUTABLE" : "OTHER",
|
ExecutableType == FIXENDIAN16(0x0200) ? "EXECUTABLE" : "OTHER",
|
||||||
FIXENDIAN16(ExecutableType),
|
FIXENDIAN16(ExecutableType),
|
||||||
MachineType == FIXENDIAN16(0x3E00) ? "AMD64" : "OTHER",
|
MachineType == FIXENDIAN16(0x3E00) ? "AMD64" : "OTHER",
|
||||||
FIXENDIAN16(MachineType));
|
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);
|
SerialPrintf("[ boot] Header at 0x%p matches kernel header.\r\n", headerLoc);
|
||||||
flag = 1;
|
flag = 1;
|
||||||
// At this point, we've found the right ELF64 executable!
|
// At this point, we've found the right ELF64 executable!
|
||||||
|
@ -81,10 +81,10 @@ int ParseKernelHeader(size_t InitrdPtr) {
|
||||||
KernelLocation = headerLoc;
|
KernelLocation = headerLoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!flag) {
|
if (!flag) {
|
||||||
|
|
||||||
for(char i = 0; i < 64; i++) {
|
for (char i = 0; i < 64; i++) {
|
||||||
SerialPrintf("[ boot] Header dump part %x: 0x%x\r\n", i, *((volatile uint8_t*)(headerLoc + 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;
|
layout.TextBoxX = (layout.ScreenWidth - layout.TextBoxWidth) / 2;
|
||||||
|
|
||||||
SetForegroundColor(0x000084);
|
SetForegroundColor(0x000084);
|
||||||
FillScreen();
|
FillScreen(0x000084);
|
||||||
|
|
||||||
SetForegroundColor(0x00BBBBBB);
|
SetForegroundColor(0x00BBBBBB);
|
||||||
DrawFilledRect(0, 0, PrintInfo.screenWidth, layout.HeaderHeight);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* C++ code! Scary!
|
* C++ code! Scary!
|
||||||
* This is a temporary measure to experiment with the Editor system.
|
* 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.NextTicket = 0;
|
||||||
KernelAddressSpace.Lock.NowServing = 0;
|
KernelAddressSpace.Lock.NowServing = 0;
|
||||||
KernelAddressSpace.PML4 = nullptr;
|
KernelAddressSpace.PML4 = nullptr;
|
||||||
|
|
||||||
SerialPrintf("\r\n[ boot] Booting Chroma..\r\n");
|
SerialPrintf("\r\n[ boot] Booting Chroma..\r\n");
|
||||||
SerialPrintf("[ boot] Bootloader data structure at 0x%p\r\n", (size_t) &bootldr);
|
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] Kernel loaded at 0x%p, ends at 0x%p, is %d bytes long.\r\n", KernelAddr, KernelEnd,
|
||||||
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);
|
KernelEnd - KernelAddr);
|
||||||
SerialPrintf("[ boot] Initrd is physically at 0x%p, and is %d bytes long.\r\n", bootldr.initrd_ptr, bootldr.initrd_size);
|
SerialPrintf("[ boot] Framebuffer at 0x%p / 0x%p, is %dx%d, 0x%x bytes long.\r\n", bootldr.fb_ptr, (size_t) &fb,
|
||||||
SerialPrintf("[ boot] Initrd's header is 0x%p\r\n", FIXENDIAN32(*((volatile uint32_t*)(bootldr.initrd_ptr))));
|
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);
|
ParseKernelHeader(bootldr.initrd_ptr);
|
||||||
|
|
||||||
SerialPrintf("[ boot] The bootloader has put the paging tables at 0x%p.\r\n", ReadControlRegister(3));
|
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();
|
ListMemoryMap();
|
||||||
|
|
||||||
|
@ -84,15 +90,15 @@ int Main(void) {
|
||||||
|
|
||||||
InternalBufferID = SetupKBCallback(&TrackInternalBuffer);
|
InternalBufferID = SetupKBCallback(&TrackInternalBuffer);
|
||||||
|
|
||||||
for (;;) {}
|
for (;;) { }
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintPressedChar(KeyboardData data) {
|
extern "C" void PrintPressedChar(KeyboardData data) {
|
||||||
if(!KernelLoaded) return;
|
if (!KernelLoaded) return;
|
||||||
|
|
||||||
if(data.Pressed) {
|
if (data.Pressed) {
|
||||||
SerialPrintf("Key pressed: [\\%c (%x)]\r\n", data.Char, data.Scancode);
|
SerialPrintf("Key pressed: [\\%c (%x)]\r\n", data.Char, data.Scancode);
|
||||||
Printf("%c", data.Char);
|
Printf("%c", data.Char);
|
||||||
} else {
|
} else {
|
||||||
|
@ -100,24 +106,24 @@ void PrintPressedChar(KeyboardData data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackInternalBuffer(KeyboardData data) {
|
extern "C" void TrackInternalBuffer(KeyboardData data) {
|
||||||
if(!data.Pressed) return;
|
if (!data.Pressed) return;
|
||||||
|
|
||||||
bool tentative = false;
|
bool tentative = false;
|
||||||
if(BufferLength > 4097) tentative = true;
|
if (BufferLength > 4097) tentative = true;
|
||||||
|
|
||||||
if(data.Char == '\b') {
|
if (data.Char == '\b') {
|
||||||
BufferLength--;
|
BufferLength--;
|
||||||
tentative = false;
|
tentative = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(data.Scancode == 0x1C) {
|
if (data.Scancode == 0x1C) {
|
||||||
InternalBuffer[BufferLength] = '\0'; // Null-terminate to make checking easier
|
InternalBuffer[BufferLength] = '\0'; // Null-terminate to make checking easier
|
||||||
if(strcmp(InternalBuffer, "editor")) {
|
if (strcmp(InternalBuffer, "editor")) {
|
||||||
UninstallKBCallback(InternalBufferID);
|
UninstallKBCallback(InternalBufferID);
|
||||||
Editor editor;
|
Editor editor;
|
||||||
editor.StartEditor(CharPrinterCallbackID);
|
editor.StartEditor(CharPrinterCallbackID);
|
||||||
} else if(strcmp(InternalBuffer, "zero")) {
|
} else if (strcmp(InternalBuffer, "zero")) {
|
||||||
int returnVal = sharp_entryPoint();
|
int returnVal = sharp_entryPoint();
|
||||||
SerialPrintf("Sharp returned %d\r\n", returnVal);
|
SerialPrintf("Sharp returned %d\r\n", returnVal);
|
||||||
} else {
|
} else {
|
||||||
|
@ -128,18 +134,21 @@ void TrackInternalBuffer(KeyboardData data) {
|
||||||
BufferLength = 0;
|
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);
|
SerialPrintf("[ Kbd] Adding %c to the buffer.\r\n", data.Char);
|
||||||
InternalBuffer[BufferLength] = data.Char;
|
InternalBuffer[BufferLength] = data.Char;
|
||||||
BufferLength++;
|
BufferLength++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SomethingWentWrong(const char* Message) {
|
|
||||||
|
extern "C" void SomethingWentWrong(const char* Message) {
|
||||||
SerialPrintf("Assertion failed! %s\r\n", 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);
|
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->Next->Previous = Entry->Previous;
|
||||||
Entry->Previous->Next = Entry->Next;
|
Entry->Previous->Next = Entry->Next;
|
||||||
|
|
||||||
Entry->Previous = (void*)0xDEADull;
|
Entry->Previous = static_cast<list_entry*>((void*) 0xDEADull);
|
||||||
Entry->Next = (void*)0xBEEFull;
|
Entry->Next = static_cast<list_entry*>((void*) 0xBEEFull);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ListIsEmpty(list_entry_t* Head) {
|
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
|
#define BP_STACK 4096
|
||||||
|
|
||||||
void InvalidatePage(size_t Page) {
|
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};
|
__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 unsigned char BPStack[BP_STACK] = {0};
|
||||||
|
|
||||||
__attribute__((aligned(64))) static volatile size_t InitGDT[5] = {
|
__attribute__((aligned(64))) static volatile size_t InitGDT[5] = {
|
||||||
0,
|
0,
|
||||||
0x00af9a000000ffff,
|
0x00af9a000000ffff,
|
||||||
0x00cf92000000ffff,
|
0x00cf92000000ffff,
|
||||||
0x0080890000000067,
|
0x0080890000000067,
|
||||||
0
|
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() {
|
static void RefreshCS() {
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ void PrepareCPU() {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void SetupInitialGDT() {
|
void SetupInitialGDT() {
|
||||||
DESC_TBL GDTData = {0};
|
DESC_TBL GDTData;
|
||||||
size_t TSSBase = (uint64_t) (&TSSEntries);
|
size_t TSSBase = (uint64_t) (&TSSEntries);
|
||||||
|
|
||||||
uint16_t TSSLower = (uint16_t) TSSBase;
|
uint16_t TSSLower = (uint16_t) TSSBase;
|
||||||
|
@ -122,10 +122,10 @@ void SetupInitialGDT() {
|
||||||
GDTData.Limit = sizeof(InitGDT) - 1;
|
GDTData.Limit = sizeof(InitGDT) - 1;
|
||||||
GDTData.Base = (size_t) InitGDT;
|
GDTData.Base = (size_t) InitGDT;
|
||||||
|
|
||||||
( (TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]) )->BaseLow = TSSLower;
|
((TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]))->BaseLow = TSSLower;
|
||||||
( (TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]) )->BaseMid1 = TSSMid1;
|
((TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]))->BaseMid1 = TSSMid1;
|
||||||
( (TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]) )->BaseMid2 = TSSMid2;
|
((TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]))->BaseMid2 = TSSMid2;
|
||||||
( (TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]) )->BaseHigh = TSSHigher;
|
((TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]))->BaseHigh = TSSHigher;
|
||||||
|
|
||||||
WriteGDT(GDTData);
|
WriteGDT(GDTData);
|
||||||
WriteTSR(3 << 3);
|
WriteTSR(3 << 3);
|
||||||
|
@ -203,44 +203,44 @@ static void SetISRBP(size_t ISRNum, size_t ISRAddr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetupIDT() {
|
void SetupIDT() {
|
||||||
DESC_TBL IDTData = {0};
|
DESC_TBL IDTData;
|
||||||
IDTData.Limit = (sizeof(IDT_GATE) * 256) - 1;
|
IDTData.Limit = (sizeof(IDT_GATE) * 256) - 1;
|
||||||
IDTData.Base = (size_t) &IDTEntries;
|
IDTData.Base = (size_t) &IDTEntries;
|
||||||
|
|
||||||
//memset(&IDTEntries, 0, sizeof(IDT_GATE) * 256);
|
//memset(&IDTEntries, 0, sizeof(IDT_GATE) * 256);
|
||||||
|
|
||||||
RemapIRQControllers();
|
RemapIRQControllers();
|
||||||
|
|
||||||
*(size_t*) (&TSSEntries.IST1) = (size_t) (NMIStack + NMI_STACK);
|
*(size_t*) (&TSSEntries.IST1) = (size_t) (NMIStack + NMI_STACK);
|
||||||
*(size_t*) (&TSSEntries.IST2) = (size_t) (DFStack + DF_STACK);
|
*(size_t*) (&TSSEntries.IST2) = (size_t) (DFStack + DF_STACK);
|
||||||
*(size_t*) (&TSSEntries.IST3) = (size_t) (MCStack + MC_STACK);
|
*(size_t*) (&TSSEntries.IST3) = (size_t) (MCStack + MC_STACK);
|
||||||
*(size_t*) (&TSSEntries.IST4) = (size_t) (BPStack + BP_STACK);
|
*(size_t*) (&TSSEntries.IST4) = (size_t) (BPStack + BP_STACK);
|
||||||
|
|
||||||
SetISR (0, (size_t) ISR0Handler);
|
SetISR(0, (size_t) ISR0Handler);
|
||||||
SetISRBP (1, (size_t) ISR1Handler);
|
SetISRBP(1, (size_t) ISR1Handler);
|
||||||
SetISRNMI (2, (size_t) ISR2Handler);
|
SetISRNMI(2, (size_t) ISR2Handler);
|
||||||
SetISRBP (3, (size_t) ISR3Handler);
|
SetISRBP(3, (size_t) ISR3Handler);
|
||||||
SetISR (4, (size_t) ISR4Handler);
|
SetISR(4, (size_t) ISR4Handler);
|
||||||
SetISR (5, (size_t) ISR5Handler);
|
SetISR(5, (size_t) ISR5Handler);
|
||||||
SetISR (6, (size_t) ISR6Handler);
|
SetISR(6, (size_t) ISR6Handler);
|
||||||
SetISR (7, (size_t) ISR7Handler);
|
SetISR(7, (size_t) ISR7Handler);
|
||||||
SetISRDF (8, (size_t) ISR8Handler);
|
SetISRDF(8, (size_t) ISR8Handler);
|
||||||
SetISR (9, (size_t) ISR9Handler);
|
SetISR(9, (size_t) ISR9Handler);
|
||||||
SetISR (10, (size_t) ISR10Handler);
|
SetISR(10, (size_t) ISR10Handler);
|
||||||
SetISR (11, (size_t) ISR11Handler);
|
SetISR(11, (size_t) ISR11Handler);
|
||||||
SetISR (12, (size_t) ISR12Handler);
|
SetISR(12, (size_t) ISR12Handler);
|
||||||
SetISR (13, (size_t) ISR13Handler);
|
SetISR(13, (size_t) ISR13Handler);
|
||||||
SetISR (14, (size_t) ISR14Handler);
|
SetISR(14, (size_t) ISR14Handler);
|
||||||
SetISR (15, (size_t) ISR15Handler);
|
SetISR(15, (size_t) ISR15Handler);
|
||||||
SetISR (16, (size_t) ISR16Handler);
|
SetISR(16, (size_t) ISR16Handler);
|
||||||
SetISR (17, (size_t) ISR17Handler);
|
SetISR(17, (size_t) ISR17Handler);
|
||||||
SetISRMC (18, (size_t) ISR18Handler);
|
SetISRMC(18, (size_t) ISR18Handler);
|
||||||
SetISR (19, (size_t) ISR19Handler);
|
SetISR(19, (size_t) ISR19Handler);
|
||||||
SetISR (20, (size_t) ISR20Handler);
|
SetISR(20, (size_t) ISR20Handler);
|
||||||
SetISR (30, (size_t) ISR30Handler);
|
SetISR(30, (size_t) ISR30Handler);
|
||||||
|
|
||||||
for(size_t i = 1; i < 11; i++) {
|
for (size_t i = 1; i < 11; i++) {
|
||||||
if(i != 9) {
|
if (i != 9) {
|
||||||
SetISR(i + 20, (size_t) ReservedISRHandler);
|
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
|
#ifdef _cplusplus
|
||||||
#define alloc_decl inline
|
#define alloc_decl inline
|
||||||
#else
|
#else
|
||||||
#define alloc_decl static
|
#define alloc_decl static
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -61,18 +61,18 @@ alloc_decl int Alloc_FindFirstOne(unsigned int word) {
|
||||||
|
|
||||||
alloc_decl int Alloc_FindLastOne(unsigned int word) {
|
alloc_decl int Alloc_FindLastOne(unsigned int word) {
|
||||||
const int bit = word ? 32 - __builtin_clz(word) : 0;
|
const int bit = word ? 32 - __builtin_clz(word) : 0;
|
||||||
return bit -1;
|
return bit - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
alloc_decl int Alloc_FindLastOne_64(size_t size) {
|
alloc_decl int Alloc_FindLastOne_64(size_t size) {
|
||||||
|
|
||||||
int high = (int)(size >> 32);
|
int high = (int) (size >> 32);
|
||||||
int bits = 0;
|
int bits = 0;
|
||||||
|
|
||||||
if(high)
|
if (high)
|
||||||
bits = 32 + Alloc_FindLastOne(high);
|
bits = 32 + Alloc_FindLastOne(high);
|
||||||
else
|
else
|
||||||
bits = Alloc_FindLastOne((int)size & 0xFFFFFFFF);
|
bits = Alloc_FindLastOne((int) size & 0xFFFFFFFF);
|
||||||
|
|
||||||
return bits;
|
return bits;
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,6 @@ alloc_decl int Alloc_FindLastOne_64(size_t size) {
|
||||||
#undef alloc_decl
|
#undef alloc_decl
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*********************************************
|
/*********************************************
|
||||||
* T Y P E D E F I N I T I O N S
|
* 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* NextFreeBlock;
|
||||||
struct block_header_t* LastFreeBlock;
|
struct block_header_t* LastFreeBlock;
|
||||||
} block_header_t ;
|
} block_header_t;
|
||||||
|
|
||||||
|
|
||||||
typedef struct allocator_control_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) {
|
void* AlignPointer(const void* Pointer, size_t Alignment) {
|
||||||
|
|
||||||
const ptrdiff_t AlignedPointer =
|
const ptrdiff_t AlignedPointer =
|
||||||
((
|
((
|
||||||
CAST(ptrdiff_t, Pointer)
|
CAST(ptrdiff_t, Pointer)
|
||||||
+ (Alignment - 1))
|
+ (Alignment - 1))
|
||||||
& ~(Alignment - 1)
|
& ~(Alignment - 1)
|
||||||
);
|
);
|
||||||
ASSERT(((Alignment & (Alignment - 1)) == 0), "AlignPointer: Requested alignment not aligned!");
|
ASSERT(((Alignment & (Alignment - 1)) == 0), "AlignPointer: Requested alignment not aligned!");
|
||||||
|
|
||||||
return CAST(void*, AlignedPointer);
|
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) {
|
static size_t AlignRequestSize(size_t Size, size_t Alignment) {
|
||||||
size_t Adjustment = 0;
|
size_t Adjustment = 0;
|
||||||
|
|
||||||
if(Size) {
|
if (Size) {
|
||||||
const size_t Aligned = AlignUpwards(Size, Alignment);
|
const size_t Aligned = AlignUpwards(Size, Alignment);
|
||||||
|
|
||||||
if(Aligned < BLOCK_MAX_SIZE)
|
if (Aligned < BLOCK_MAX_SIZE)
|
||||||
Adjustment = MAX(Aligned, BLOCK_MIN_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) {
|
static void InsertMapping(size_t Size, int* FirstLevelIndex, int* SecondLevelIndex) {
|
||||||
int FirstLevel, SecondLevel;
|
int FirstLevel, SecondLevel;
|
||||||
|
|
||||||
if(Size < SMALL_BLOCK_SIZE) {
|
if (Size < SMALL_BLOCK_SIZE) {
|
||||||
|
|
||||||
FirstLevel = 0;
|
FirstLevel = 0;
|
||||||
SecondLevel = CAST(int, Size) / (SMALL_BLOCK_SIZE / SL_INDEX_COUNT);
|
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) {
|
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;
|
const size_t Rounded = (1 << (Alloc_FindLastOne_64(Size) - SL_LIMIT_LN)) - 1;
|
||||||
Size += Rounded;
|
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);
|
unsigned int SLMap = Controller->SecondLevel_Bitmap[FirstLevel] & (~0U << SecondLevel);
|
||||||
|
|
||||||
if(!SLMap) {
|
if (!SLMap) {
|
||||||
|
|
||||||
const unsigned int FLMap = Controller->FirstLevel_Bitmap & (~0U << (FirstLevel + 1));
|
const unsigned int FLMap = Controller->FirstLevel_Bitmap & (~0U << (FirstLevel + 1));
|
||||||
|
|
||||||
if(!FLMap)
|
if (!FLMap)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
FirstLevel = Alloc_FindFirstOne(FLMap);
|
FirstLevel = Alloc_FindFirstOne(FLMap);
|
||||||
|
@ -318,27 +317,31 @@ static void RemoveFreeBlock(allocator_control_t* Controller, block_header_t* Blo
|
||||||
NextBlock->LastFreeBlock = PreviousBlock;
|
NextBlock->LastFreeBlock = PreviousBlock;
|
||||||
PreviousBlock->NextFreeBlock = NextBlock;
|
PreviousBlock->NextFreeBlock = NextBlock;
|
||||||
|
|
||||||
if(Controller->Blocks[FirstLevel][SecondLevel] == Block) {
|
if (Controller->Blocks[FirstLevel][SecondLevel] == Block) {
|
||||||
Controller->Blocks[FirstLevel][SecondLevel] = NextBlock;
|
Controller->Blocks[FirstLevel][SecondLevel] = NextBlock;
|
||||||
|
|
||||||
if(NextBlock == &Controller->BlockNull) {
|
if (NextBlock == &Controller->BlockNull) {
|
||||||
Controller->SecondLevel_Bitmap[FirstLevel] &= ~(1U << SecondLevel);
|
Controller->SecondLevel_Bitmap[FirstLevel] &= ~(1U << SecondLevel);
|
||||||
|
|
||||||
if(!Controller->SecondLevel_Bitmap[FirstLevel]) {
|
if (!Controller->SecondLevel_Bitmap[FirstLevel]) {
|
||||||
Controller->FirstLevel_Bitmap &= ~(1U << 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];
|
block_header_t* Current = Controller->Blocks[FirstLevel][SecondLevel];
|
||||||
|
|
||||||
ASSERT(Current, "InsertFreeBlock: Current Block is null!");
|
ASSERT(Current, "InsertFreeBlock: Current Block is null!");
|
||||||
if(!Current) {
|
if (!Current) {
|
||||||
SerialPrintf("Extra info: \r\n\tFirst Level: %x Second Level: %x\r\nFirst Level bitmap: %x, Second Level bitmap: %x\r\n\tBlocks %x, BlocksAddress: %x", FirstLevel, SecondLevel, Controller->FirstLevel_Bitmap, Controller->SecondLevel_Bitmap, Controller->Blocks, Controller->Blocks[FirstLevel][SecondLevel]);
|
SerialPrintf(
|
||||||
for(;;){}
|
"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!");
|
ASSERT(NewBlock, "InsertFreeBlock: New Block is null!");
|
||||||
|
|
||||||
NewBlock->NextFreeBlock = Current;
|
NewBlock->NextFreeBlock = Current;
|
||||||
|
@ -346,10 +349,11 @@ static void InsertFreeBlock(allocator_control_t* Controller, block_header_t* New
|
||||||
|
|
||||||
Current->LastFreeBlock = NewBlock;
|
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->Blocks[FirstLevel][SecondLevel] = NewBlock;
|
||||||
Controller->FirstLevel_Bitmap |= (1U << FirstLevel);
|
Controller->FirstLevel_Bitmap |= (1U << FirstLevel);
|
||||||
Controller->SecondLevel_Bitmap[FirstLevel] |= (1U << SecondLevel);
|
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);
|
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!");
|
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) {
|
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);
|
block_header_t* Previous = BlockGetPrevious(Block);
|
||||||
ASSERT(Previous, "MergeEmptyBlockDown: Previous block is null!");
|
ASSERT(Previous, "MergeEmptyBlockDown: Previous block is null!");
|
||||||
ASSERT(BlockIsFree(Previous), "MergeEmptyBlockDown: Previous block is free!");
|
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);
|
block_header_t* NextBlock = BlockGetNext(Block);
|
||||||
ASSERT(NextBlock, "MergeNextBlockDown: Next Block is null!");
|
ASSERT(NextBlock, "MergeNextBlockDown: Next Block is null!");
|
||||||
|
|
||||||
if(BlockIsFree(NextBlock)) {
|
if (BlockIsFree(NextBlock)) {
|
||||||
ASSERT(!BlockIsLast(Block), "MergeNextBlockDown: Current block is the last block!");
|
ASSERT(!BlockIsLast(Block), "MergeNextBlockDown: Current block is the last block!");
|
||||||
RemoveBlock(Controller, NextBlock);
|
RemoveBlock(Controller, NextBlock);
|
||||||
Block = MergeBlockDown(Block, 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) {
|
static void TrimBlockFree(allocator_control_t* Controller, block_header_t* Block, size_t Size) {
|
||||||
ASSERT(BlockIsFree(Block), "TrimBlockFree: Current block is wholly free!");
|
ASSERT(BlockIsFree(Block), "TrimBlockFree: Current block is wholly free!");
|
||||||
|
|
||||||
if(CanBlockSplit(Block, Size)) {
|
if (CanBlockSplit(Block, Size)) {
|
||||||
block_header_t* RemainingBlock = SplitBlock(Block, Size);
|
block_header_t* RemainingBlock = SplitBlock(Block, Size);
|
||||||
|
|
||||||
BlockLinkToNext(Block);
|
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) {
|
static void TrimBlockUsed(allocator_control_t* Controller, block_header_t* Block, size_t Size) {
|
||||||
ASSERT(!BlockIsFree(Block), "TrimBlockUsed: The current block is wholly used!");
|
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);
|
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) {
|
static block_header_t* TrimBlockLeadingFree(allocator_control_t* Controller, block_header_t* Block, size_t Size) {
|
||||||
block_header_t* RemainingBlock = Block;
|
block_header_t* RemainingBlock = Block;
|
||||||
|
|
||||||
if(CanBlockSplit(Block, Size)) {
|
if (CanBlockSplit(Block, Size)) {
|
||||||
RemainingBlock = SplitBlock(Block, Size - BLOCK_OVERHEAD);
|
RemainingBlock = SplitBlock(Block, Size - BLOCK_OVERHEAD);
|
||||||
|
|
||||||
BlockSetPrevFree(RemainingBlock);
|
BlockSetPrevFree(RemainingBlock);
|
||||||
|
@ -476,17 +481,17 @@ static block_header_t* LocateFreeBlock(allocator_control_t* Controller, size_t S
|
||||||
|
|
||||||
block_header_t* Block = 0;
|
block_header_t* Block = 0;
|
||||||
|
|
||||||
if(Size) {
|
if (Size) {
|
||||||
|
|
||||||
RoundUpBlockSize(Size, &FirstLevel, &SecondLevel);
|
RoundUpBlockSize(Size, &FirstLevel, &SecondLevel);
|
||||||
|
|
||||||
if(FirstLevel < FL_INDEX_COUNT) {
|
if (FirstLevel < FL_INDEX_COUNT) {
|
||||||
Block = FindSuitableBlock(Controller, &FirstLevel, &SecondLevel);
|
Block = FindSuitableBlock(Controller, &FirstLevel, &SecondLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Block) {
|
if (Block) {
|
||||||
ASSERT(BlockSize(Block) >= Size, "LocateFreeBlock: Found a block that is too small!");
|
ASSERT(BlockSize(Block) >= Size, "LocateFreeBlock: Found a block that is too small!");
|
||||||
RemoveFreeBlock(Controller, Block, FirstLevel, SecondLevel);
|
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) {
|
static void* PrepareUsedBlock(allocator_control_t* Controller, block_header_t* Block, size_t Size) {
|
||||||
void* Pointer = 0;
|
void* Pointer = 0;
|
||||||
|
|
||||||
if(Block){
|
if (Block) {
|
||||||
ASSERT(Size, "PrepareUsedBlock: Size is 0!");
|
ASSERT(Size, "PrepareUsedBlock: Size is 0!");
|
||||||
TrimBlockFree(Controller, Block, Size);
|
TrimBlockFree(Controller, Block, Size);
|
||||||
BlockMarkUsed(Block);
|
BlockMarkUsed(Block);
|
||||||
|
@ -520,7 +525,7 @@ static void ConstructController(allocator_control_t* Controller) {
|
||||||
|
|
||||||
Controller->FirstLevel_Bitmap = 0;
|
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;
|
Controller->SecondLevel_Bitmap[i] = 0;
|
||||||
|
|
||||||
for (j = 0; j < SL_INDEX_COUNT; j++) {
|
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
|
* 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 AllocatorGetBlockSize(void* Memory) {
|
||||||
size_t Size = 0;
|
size_t Size = 0;
|
||||||
|
|
||||||
if(Memory) {
|
if (Memory) {
|
||||||
const block_header_t* Block = WhichBlock(Memory);
|
const block_header_t* Block = WhichBlock(Memory);
|
||||||
Size = BlockSize(Block);
|
Size = BlockSize(Block);
|
||||||
}
|
}
|
||||||
|
@ -564,7 +568,7 @@ size_t AllocatorMaxBlockSize(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t AllocatorPoolOverhead(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) {
|
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 PoolOverhead = AllocatorPoolOverhead();
|
||||||
const size_t PoolBytes = AlignDownwards(Size - PoolOverhead, ALIGN_SIZE);
|
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__);
|
SerialPrintf("Memory manager error at [%s:%x]: Memory not properly aligned.\r\n", __FILE__, __LINE__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( PoolBytes < BLOCK_MIN_SIZE || PoolBytes > BLOCK_MAX_SIZE) {
|
if (PoolBytes < BLOCK_MIN_SIZE || PoolBytes > BLOCK_MAX_SIZE) {
|
||||||
SerialPrintf("Memory manager error at [%s:%x]: Memory Size out of bounds: 0x%x-0x%x: 0x%x.\r\n", __FILE__, __LINE__, (unsigned int)(PoolOverhead + BLOCK_MIN_SIZE), (unsigned int)(PoolOverhead + BLOCK_MAX_SIZE) / 256, PoolBytes);
|
SerialPrintf("Memory manager error at [%s:%x]: Memory Size out of bounds: 0x%x-0x%x: 0x%x.\r\n", __FILE__,
|
||||||
|
__LINE__, (unsigned int) (PoolOverhead + BLOCK_MIN_SIZE),
|
||||||
|
(unsigned int) (PoolOverhead + BLOCK_MAX_SIZE) / 256, PoolBytes);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Block = OffsetToBlock(Address, -(ptrdiff_t)BLOCK_OVERHEAD);
|
Block = OffsetToBlock(Address, -(ptrdiff_t) BLOCK_OVERHEAD);
|
||||||
BlockSetSize(Block, PoolBytes);
|
BlockSetSize(Block, PoolBytes);
|
||||||
BlockSetFree(Block);
|
BlockSetFree(Block);
|
||||||
BlockSetPrevUsed(Block);
|
BlockSetPrevUsed(Block);
|
||||||
|
@ -604,9 +610,9 @@ mempool_t AddPoolToAllocator(allocator_t Allocator, void* Address, size_t Size)
|
||||||
return Address;
|
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);
|
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;
|
int FirstLevel = 0, SecondLevel = 0;
|
||||||
|
|
||||||
|
@ -619,30 +625,30 @@ void RemovePoolFromAllocator(allocator_t Allocator, mempool_t Pool){
|
||||||
}
|
}
|
||||||
|
|
||||||
int TestBuiltins() {
|
int TestBuiltins() {
|
||||||
/* Verify ffs/fls work properly. */
|
/* Verify ffs/fls work properly. */
|
||||||
int TestsFailed = 0;
|
int TestsFailed = 0;
|
||||||
TestsFailed += (Alloc_FindFirstOne(0) == -1) ? 0 : 0x1;
|
TestsFailed += (Alloc_FindFirstOne(0) == -1) ? 0 : 0x1;
|
||||||
TestsFailed += (Alloc_FindLastOne(0) == -1) ? 0 : 0x2;
|
TestsFailed += (Alloc_FindLastOne(0) == -1) ? 0 : 0x2;
|
||||||
TestsFailed += (Alloc_FindFirstOne(1) == 0) ? 0 : 0x4;
|
TestsFailed += (Alloc_FindFirstOne(1) == 0) ? 0 : 0x4;
|
||||||
TestsFailed += (Alloc_FindLastOne(1) == 0) ? 0 : 0x8;
|
TestsFailed += (Alloc_FindLastOne(1) == 0) ? 0 : 0x8;
|
||||||
TestsFailed += (Alloc_FindFirstOne(0x80000000) == 31) ? 0 : 0x10;
|
TestsFailed += (Alloc_FindFirstOne(0x80000000) == 31) ? 0 : 0x10;
|
||||||
TestsFailed += (Alloc_FindFirstOne(0x80008000) == 15) ? 0 : 0x20;
|
TestsFailed += (Alloc_FindFirstOne(0x80008000) == 15) ? 0 : 0x20;
|
||||||
TestsFailed += (Alloc_FindLastOne(0x80000008) == 31) ? 0 : 0x40;
|
TestsFailed += (Alloc_FindLastOne(0x80000008) == 31) ? 0 : 0x40;
|
||||||
TestsFailed += (Alloc_FindLastOne(0x7FFFFFFF) == 30) ? 0 : 0x80;
|
TestsFailed += (Alloc_FindLastOne(0x7FFFFFFF) == 30) ? 0 : 0x80;
|
||||||
|
|
||||||
TestsFailed += (Alloc_FindLastOne_64(0x80000000) == 31) ? 0 : 0x100;
|
TestsFailed += (Alloc_FindLastOne_64(0x80000000) == 31) ? 0 : 0x100;
|
||||||
TestsFailed += (Alloc_FindLastOne_64(0x100000000) == 32) ? 0 : 0x200;
|
TestsFailed += (Alloc_FindLastOne_64(0x100000000) == 32) ? 0 : 0x200;
|
||||||
TestsFailed += (Alloc_FindLastOne_64(0xffffffffffffffff) == 63) ? 0 : 0x400;
|
TestsFailed += (Alloc_FindLastOne_64(0xffffffffffffffff) == 63) ? 0 : 0x400;
|
||||||
|
|
||||||
if (TestsFailed) {
|
if (TestsFailed) {
|
||||||
SerialPrintf("TestBuiltins: %x ffs/fls tests failed.\n", TestsFailed);
|
SerialPrintf("TestBuiltins: %x ffs/fls tests failed.\n", TestsFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TestsFailed;
|
return TestsFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
allocator_t CreateAllocator(void* Memory) {
|
allocator_t CreateAllocator(void* Memory) {
|
||||||
if(TestBuiltins())
|
if (TestBuiltins())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (((ptrdiff_t) Memory % ALIGN_SIZE) != 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 CreateAllocatorWithPool(void* Memory, size_t Bytes) {
|
||||||
allocator_t Allocator = CreateAllocator(Memory);
|
allocator_t Allocator = CreateAllocator(Memory);
|
||||||
|
|
||||||
AddPoolToAllocator(Allocator, (char*)Memory + AllocatorSize(), Bytes - AllocatorSize());
|
AddPoolToAllocator(Allocator, (char*) Memory + AllocatorSize(), Bytes - AllocatorSize());
|
||||||
|
|
||||||
return Allocator;
|
return Allocator;
|
||||||
}
|
}
|
||||||
|
@ -669,7 +675,7 @@ void DestroyAllocator(allocator_t Allocator) {
|
||||||
}
|
}
|
||||||
|
|
||||||
mempool_t GetPoolFromAllocator(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!");
|
ASSERT(sizeof(block_header_t) == BLOCK_MIN_SIZE + BLOCK_OVERHEAD, "AllocatorMalign: Maths error!");
|
||||||
|
|
||||||
if(Block) {
|
if (Block) {
|
||||||
void* Address = WhereBlock(Block);
|
void* Address = WhereBlock(Block);
|
||||||
void* AlignedAddress = AlignPointer(Address, Alignment);
|
void* AlignedAddress = AlignPointer(Address, Alignment);
|
||||||
|
|
||||||
size_t Gap = CAST(size_t, CAST(ptrdiff_t, AlignedAddress) - CAST(ptrdiff_t, Address));
|
size_t Gap = CAST(size_t, CAST(ptrdiff_t, AlignedAddress) - CAST(ptrdiff_t, Address));
|
||||||
|
|
||||||
if(Gap) {
|
if (Gap) {
|
||||||
if(Gap << MinimumGap) {
|
if (Gap << MinimumGap) {
|
||||||
const size_t GapRemaining = MinimumGap - Gap;
|
const size_t GapRemaining = MinimumGap - Gap;
|
||||||
const size_t Offset = MAX(GapRemaining, Alignment);
|
const size_t Offset = MAX(GapRemaining, Alignment);
|
||||||
const void* NextAlignedAddress = CAST(void*, CAST(ptrdiff_t, AlignedAddress) + Offset);
|
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) {
|
void AllocatorFree(allocator_t Allocator, void* Address) {
|
||||||
if(Address) {
|
if (Address) {
|
||||||
allocator_control_t* Controller = CAST(allocator_control_t*, Allocator);
|
allocator_control_t* Controller = CAST(allocator_control_t*, Allocator);
|
||||||
block_header_t* Block = WhichBlock(Address);
|
block_header_t* Block = WhichBlock(Address);
|
||||||
ASSERT(!BlockIsFree(Block), "AllocatorFree: Attempting to free a freed block!");
|
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;
|
void* Pointer = 0;
|
||||||
|
|
||||||
// Valid address, invalid size; free
|
// Valid address, invalid size; free
|
||||||
if(Address && NewSize == 0)
|
if (Address && NewSize == 0)
|
||||||
AllocatorFree(Allocator, Address);
|
AllocatorFree(Allocator, Address);
|
||||||
|
|
||||||
else if (!Address) // Invalid address; alloc
|
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!");
|
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
|
// We're going to need more room
|
||||||
|
|
||||||
Pointer = AllocatorMalloc(Allocator, NewSize);
|
Pointer = AllocatorMalloc(Allocator, NewSize);
|
||||||
if(Pointer) {
|
if (Pointer) {
|
||||||
const size_t MinimumSize = MIN(CurrentSize, NewSize);
|
const size_t MinimumSize = MIN(CurrentSize, NewSize);
|
||||||
memcpy(Pointer, Address, MinimumSize);
|
memcpy(Pointer, Address, MinimumSize);
|
||||||
AllocatorFree(Allocator, Address);
|
AllocatorFree(Allocator, Address);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if( AdjustedSize > CurrentSize) {
|
if (AdjustedSize > CurrentSize) {
|
||||||
MergeNextBlockDown(Controller, Block);
|
MergeNextBlockDown(Controller, Block);
|
||||||
BlockMarkUsed(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() {
|
void InitPaging() {
|
||||||
|
|
||||||
KernelAddressSpace = (address_space_t) {
|
KernelAddressSpace = (address_space_t) {
|
||||||
.Lock = {0},
|
.Lock = {.NowServing = 0, .NextTicket = 0},
|
||||||
.PML4 = PhysAllocateZeroMem(4096)
|
.PML4 = (size_t*) PhysAllocateZeroMem(4096)
|
||||||
};
|
};
|
||||||
|
|
||||||
address_space_t BootloaderAddressSpace = (address_space_t) {
|
address_space_t BootloaderAddressSpace = (address_space_t) {
|
||||||
.Lock = {0},
|
.Lock = {.NowServing = 0, .NextTicket = 0},
|
||||||
.PML4 = (size_t*) ReadControlRegister(3)
|
.PML4 = (size_t*) ReadControlRegister(3)
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t AddressToFind = KernelAddr + 0x2000;
|
size_t AddressToFind = KernelAddr + 0x2000;
|
||||||
size_t BootldrAddress = 0x8000;
|
size_t BootldrAddress = 0x8000;
|
||||||
KernelLocation = DecodeVirtualAddressNoDirect(&BootloaderAddressSpace, AddressToFind);
|
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;
|
size_t Addr = i * 4096;
|
||||||
MapVirtualPageNoDirect(&KernelAddressSpace, Addr, Addr, DEFAULT_PAGE_FLAGS);
|
MapVirtualPageNoDirect(&KernelAddressSpace, Addr, Addr, DEFAULT_PAGE_FLAGS);
|
||||||
MapVirtualPageNoDirect(&KernelAddressSpace, Addr, TO_DIRECT(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);
|
SerialPrintf("[ Mem] Mapping 0x%x bytes of bootloader structure, starting at 0x%p\r\n", bootldr.size,
|
||||||
for(size_t i = BootldrAddress; i < (BootldrAddress + bootldr.size); i += PAGE_SIZE)
|
BootldrAddress);
|
||||||
|
for (size_t i = BootldrAddress; i < (BootldrAddress + bootldr.size); i += PAGE_SIZE)
|
||||||
MapVirtualPageNoDirect(&KernelAddressSpace, i, KERNEL_REGION + (i - BootldrAddress), 0x3);
|
MapVirtualPageNoDirect(&KernelAddressSpace, i, KERNEL_REGION + (i - BootldrAddress), 0x3);
|
||||||
|
|
||||||
// This allows the code to actually run
|
// This allows the code to actually run
|
||||||
SerialPrintf("[ Mem] Mapping 0x%x bytes of kernel, starting at 0x%p\r\n", KERNEL_END - KERNEL_PHYSICAL, KERNEL_PHYSICAL);
|
SerialPrintf("[ Mem] Mapping 0x%x bytes of kernel, starting at 0x%p\r\n", KERNEL_END - KERNEL_PHYSICAL,
|
||||||
for(size_t i = KERNEL_PHYSICAL; i < KERNEL_END; i += PAGE_SIZE)
|
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);
|
MapVirtualPageNoDirect(&KernelAddressSpace, i, (i - KERNEL_PHYSICAL) + KERNEL_REGION + KERNEL_TEXT, 0x3);
|
||||||
|
|
||||||
// TODO: The above mapping loses the ELF header.
|
// TODO: The above mapping loses the ELF header.
|
||||||
|
|
||||||
// This allows us to write to the screen
|
// 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);
|
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, 0x3); // FD000000 + (page)
|
||||||
MapVirtualPageNoDirect(&KernelAddressSpace, i, (i - FB_PHYSICAL) + FB_REGION, 0x3); // FFFFFFFFFC000000 + (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");
|
SerialPrintf("[ Mem] Diagnostic: Querying existing page tables\r\n");
|
||||||
|
|
||||||
size_t KernelAddress = DecodeVirtualAddressNoDirect(&KernelAddressSpace, AddressToFind);
|
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: Our pagetables put 0x%p at 0x%p + 0x%p.\r\n", AddressToFind, KernelAddress,
|
||||||
SerialPrintf("[ Mem] Diagnostic: Existing pagetables put 0x%p at 0x%p + 0x%p.\r\n", AddressToFind, KERNEL_PHYSICAL, AddressToFind & ~STACK_TOP);
|
AddressToFind & ~STACK_TOP);
|
||||||
SerialPrintf("[ Mem] %s\r\n", KernelAddress == KERNEL_PHYSICAL ? "These match. Continuing." : "These do not match. Continuing with caution..");
|
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);
|
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);
|
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 PDP = PAGE_TABLES_GET_PDP(VirtualAddress);
|
||||||
size_t PDE = PAGE_TABLES_GET_PDE(VirtualAddress);
|
size_t PDE = PAGE_TABLES_GET_PDE(VirtualAddress);
|
||||||
size_t PT = PAGE_TABLES_GET_PT(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);
|
PDPT_T = (size_t*) TO_DIRECT(AddressSpace->PML4[PDPT] & STACK_TOP);
|
||||||
else
|
else
|
||||||
return VirtualAddress;
|
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);
|
PDE_T = (size_t*) TO_DIRECT(PDPT_T[PDP] & STACK_TOP);
|
||||||
else
|
else
|
||||||
return VirtualAddress;
|
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);
|
PT_T = (size_t*) TO_DIRECT(PDE_T[PDE] & STACK_TOP);
|
||||||
else
|
else
|
||||||
return VirtualAddress;
|
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 PDP = PAGE_TABLES_GET_PDP(Virtual);
|
||||||
size_t PDE = PAGE_TABLES_GET_PDE(Virtual);
|
size_t PDE = PAGE_TABLES_GET_PDE(Virtual);
|
||||||
size_t PT = PAGE_TABLES_GET_PT(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..
|
// 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".
|
// 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);
|
PDPT_T = (size_t*) TO_DIRECT(AddressSpace->PML4[PDPT] & STACK_TOP);
|
||||||
else {
|
else {
|
||||||
|
@ -176,14 +183,14 @@ void MapVirtualPage(address_space_t* AddressSpace, size_t Physical, size_t Virtu
|
||||||
}
|
}
|
||||||
|
|
||||||
// The above repeats.
|
// 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);
|
PDE_T = (size_t*) TO_DIRECT(PDPT_T[PDP] & STACK_TOP);
|
||||||
else {
|
else {
|
||||||
PDE_T = (size_t*) TO_DIRECT(PhysAllocateZeroMem(4096));
|
PDE_T = (size_t*) TO_DIRECT(PhysAllocateZeroMem(4096));
|
||||||
PDPT_T[PDP] = FROM_DIRECT(PDE_T) | DEFAULT_PAGE_FLAGS;
|
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);
|
PT_T = (size_t*) TO_DIRECT(PDE_T[PDE] & STACK_TOP);
|
||||||
else {
|
else {
|
||||||
PT_T = (size_t*) TO_DIRECT(PhysAllocateZeroMem(4096));
|
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 PDP = PAGE_TABLES_GET_PDP(VirtualAddress);
|
||||||
size_t PDE = PAGE_TABLES_GET_PDE(VirtualAddress);
|
size_t PDE = PAGE_TABLES_GET_PDE(VirtualAddress);
|
||||||
size_t PT = PAGE_TABLES_GET_PT(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);
|
PDPT_T = (size_t*) (AddressSpace->PML4[PDPT] & STACK_TOP);
|
||||||
else
|
else
|
||||||
return VirtualAddress;
|
return VirtualAddress;
|
||||||
|
|
||||||
if(PDPT_T[PDP] & PRESENT_BIT)
|
if (PDPT_T[PDP] & PRESENT_BIT)
|
||||||
PDE_T = (size_t*) (PDPT_T[PDP] & STACK_TOP);
|
PDE_T = (size_t*) (PDPT_T[PDP] & STACK_TOP);
|
||||||
else
|
else
|
||||||
return VirtualAddress;
|
return VirtualAddress;
|
||||||
|
|
||||||
if(PDE_T[PDE] & PRESENT_BIT)
|
if (PDE_T[PDE] & PRESENT_BIT)
|
||||||
PT_T = (size_t*) (PDE_T[PDE] & STACK_TOP);
|
PT_T = (size_t*) (PDE_T[PDE] & STACK_TOP);
|
||||||
else
|
else
|
||||||
return VirtualAddress;
|
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 PDP = PAGE_TABLES_GET_PDP(Virtual);
|
||||||
size_t PDE = PAGE_TABLES_GET_PDE(Virtual);
|
size_t PDE = PAGE_TABLES_GET_PDE(Virtual);
|
||||||
size_t PT = PAGE_TABLES_GET_PT(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..
|
// 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".
|
// 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);
|
PDPT_T = (size_t*) (AddressSpace->PML4[PDPT] & STACK_TOP);
|
||||||
else {
|
else {
|
||||||
|
@ -269,7 +276,7 @@ void MapVirtualPageNoDirect(address_space_t* AddressSpace, size_t Physical, size
|
||||||
|
|
||||||
|
|
||||||
// The above repeats.
|
// The above repeats.
|
||||||
if(PDPT_T[PDP] & PRESENT_BIT)
|
if (PDPT_T[PDP] & PRESENT_BIT)
|
||||||
PDE_T = (size_t*) (PDPT_T[PDP] & STACK_TOP);
|
PDE_T = (size_t*) (PDPT_T[PDP] & STACK_TOP);
|
||||||
else {
|
else {
|
||||||
PDE_T = (size_t*) PhysAllocateZeroMem(4096);
|
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);
|
PT_T = (size_t*) (PDE_T[PDE] & STACK_TOP);
|
||||||
else {
|
else {
|
||||||
PT_T = (size_t*) PhysAllocateZeroMem(4096);
|
PT_T = (size_t*) PhysAllocateZeroMem(4096);
|
||||||
|
@ -302,20 +309,20 @@ size_t* CreateNewPageTable(address_space_t* AddressSpace) {
|
||||||
// Allocate the first page
|
// Allocate the first page
|
||||||
size_t* NewPML4 = (size_t*) TO_DIRECT(PhysAllocateZeroMem(4096));
|
size_t* NewPML4 = (size_t*) TO_DIRECT(PhysAllocateZeroMem(4096));
|
||||||
address_space_t TempAddressSpace = (address_space_t) {
|
address_space_t TempAddressSpace = (address_space_t) {
|
||||||
.Lock = {0},
|
.Lock = {.NowServing = 0, .NextTicket = 0},
|
||||||
.PML4 = NewPML4
|
.PML4 = NewPML4
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initialize to zeros
|
// Initialize to zeros
|
||||||
for(size_t i = 0; i < 512; i++)
|
for (size_t i = 0; i < 512; i++)
|
||||||
NewPML4[i] = 0;
|
NewPML4[i] = 0;
|
||||||
|
|
||||||
// Copy the current Address Space's higher half
|
// 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];
|
NewPML4[i] = AddressSpace->PML4[i];
|
||||||
|
|
||||||
// Identity map the bottom two megabytes into the higher half
|
// 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
|
// Get page offset
|
||||||
size_t Addr = i * 4096;
|
size_t Addr = i * 4096;
|
||||||
// Identity map
|
// Identity map
|
||||||
|
@ -325,7 +332,7 @@ size_t* CreateNewPageTable(address_space_t* AddressSpace) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Identity map the next 4gb
|
// 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;
|
size_t Addr = i * 4096;
|
||||||
MapVirtualPage(&TempAddressSpace, Addr, Addr, DEFAULT_PAGE_FLAGS);
|
MapVirtualPage(&TempAddressSpace, Addr, Addr, DEFAULT_PAGE_FLAGS);
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
#include <kernel/chroma.h>
|
#include <kernel/chroma.h>
|
||||||
#include <lainlib/lainlib.h>
|
#include <lainlib/lainlib.h>
|
||||||
|
|
||||||
|
|
||||||
/************************
|
/************************
|
||||||
*** Team Kitty, 2020 ***
|
*** Team Kitty, 2020 ***
|
||||||
*** Chroma ***
|
*** Chroma ***
|
||||||
|
@ -12,17 +13,12 @@ extern "C" {
|
||||||
|
|
||||||
/* This file contains functions for physical memory management.
|
/* This file contains functions for physical memory management.
|
||||||
*
|
*
|
||||||
* This is also called blocking, or block memory allocation.
|
* Physical Memory Management is performed with Buddy List allocators, which are one of the most performant systems available.
|
||||||
* It mostly deals with the memory map handed to us by the bootloader.
|
* 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.
|
* The implementation here is bespoke, and in need of documentation.
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
*
|
||||||
|
* TODO: Document this mess.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,17 +33,17 @@ size_t FreeMemorySize = 0;
|
||||||
size_t FullMemorySize = 0;
|
size_t FullMemorySize = 0;
|
||||||
|
|
||||||
static buddy_t LowBuddy = {
|
static buddy_t LowBuddy = {
|
||||||
.MaxOrder = 32,
|
.MaxOrder = 32,
|
||||||
.Base = (directptr_t) DIRECT_REGION,
|
.Base = (directptr_t) DIRECT_REGION,
|
||||||
.List = (directptr_t[32 - MIN_ORDER]) {0},
|
.List = (directptr_t[32 - MIN_ORDER]) {0},
|
||||||
.Lock = {0},
|
.Lock = {.NowServing = 0, .NextTicket = 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
static buddy_t HighBuddy = {
|
static buddy_t HighBuddy = {
|
||||||
.MaxOrder = 64,
|
.MaxOrder = 64,
|
||||||
.Base = 0,
|
.Base = 0,
|
||||||
.List = (directptr_t[64 - MIN_ORDER]) {0},
|
.List = (directptr_t[64 - MIN_ORDER]) {0},
|
||||||
.Lock = {0},
|
.Lock = {.NowServing = 0, .NextTicket = 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
static size_t MemoryLength;
|
static size_t MemoryLength;
|
||||||
|
@ -68,12 +64,12 @@ static void AddToBuddyList(buddy_t* Buddy, directptr_t Address, size_t Order, bo
|
||||||
|
|
||||||
TicketAttemptLock(&Buddy->Lock);
|
TicketAttemptLock(&Buddy->Lock);
|
||||||
|
|
||||||
if(!NewEntry && ListHead != 0) {
|
if (!NewEntry && ListHead != 0) {
|
||||||
directptr_t ListPrevious = 0;
|
directptr_t ListPrevious = 0;
|
||||||
|
|
||||||
while(true) {
|
while (true) {
|
||||||
if(CheckBuddies(Buddy, ListHead, Address, Size)) {
|
if (CheckBuddies(Buddy, ListHead, Address, Size)) {
|
||||||
if(ListPrevious != 0) {
|
if (ListPrevious != 0) {
|
||||||
PEEK(directptr_t, ListPrevious) = PEEK(directptr_t, ListHead);
|
PEEK(directptr_t, ListPrevious) = PEEK(directptr_t, ListHead);
|
||||||
} else
|
} else
|
||||||
Buddy->List[Order - MIN_ORDER] = PEEK(directptr_t, ListHead);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(PEEK(directptr_t, ListHead) == 0) {
|
if (PEEK(directptr_t, ListHead) == 0) {
|
||||||
PEEK(directptr_t, ListHead) = Address;
|
PEEK(directptr_t, ListHead) = Address;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -91,7 +87,7 @@ static void AddToBuddyList(buddy_t* Buddy, directptr_t Address, size_t Order, bo
|
||||||
ListHead = PEEK(directptr_t, ListHead);
|
ListHead = PEEK(directptr_t, ListHead);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
*((size_t*)(Address)) = (size_t) ListHead;
|
*((size_t*) (Address)) = (size_t) ListHead;
|
||||||
Buddy->List[Order - MIN_ORDER] = Address;
|
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) {
|
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);
|
//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);
|
//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");
|
//SerialPrintf("\tNew loop check passed.\r\n\t");
|
||||||
AddToBuddyList(Buddy, Base, Order, true);
|
AddToBuddyList(Buddy, Base, Order, true);
|
||||||
//SerialPrintf("\tEntry added to current buddy. Moving onto memory operations..\r\n\t");
|
//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;
|
Size -= 1ull << Order;
|
||||||
//SerialPrintf("\tMemory operations complete. Moving onto next iteration.\r\n");
|
//SerialPrintf("\tMemory operations complete. Moving onto next iteration.\r\n");
|
||||||
break;
|
break;
|
||||||
|
@ -121,9 +117,11 @@ static directptr_t BuddyAllocate(buddy_t* Buddy, size_t Size) {
|
||||||
|
|
||||||
size_t WantedSize = 1ull << InitialOrder;
|
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("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;
|
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);
|
//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]);
|
//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");
|
//SerialPrintf("\tFound a valid Order!\r\n");
|
||||||
directptr_t Address = Buddy->List[Order - MIN_ORDER];
|
directptr_t Address = Buddy->List[Order - MIN_ORDER];
|
||||||
Buddy->List[Order - MIN_ORDER] = PEEK(directptr_t, Address);
|
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);
|
//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");
|
//SerialPrintf("\tArea added!\r\n");
|
||||||
return Address;
|
return Address;
|
||||||
|
@ -163,8 +161,8 @@ void InitMemoryManager() {
|
||||||
|
|
||||||
MMapEnt* MemMap = &bootldr.mmap;
|
MMapEnt* MemMap = &bootldr.mmap;
|
||||||
|
|
||||||
while((size_t) MemMap < ((size_t) &bootldr) + bootldr.size) {
|
while ((size_t) MemMap < ((size_t) &bootldr) + bootldr.size) {
|
||||||
if(MMapEnt_IsFree(MemMap)) {
|
if (MMapEnt_IsFree(MemMap)) {
|
||||||
FreeMemorySize += MMapEnt_Size(MemMap);
|
FreeMemorySize += MMapEnt_Size(MemMap);
|
||||||
}
|
}
|
||||||
FullMemorySize += MMapEnt_Size(MemMap);
|
FullMemorySize += MMapEnt_Size(MemMap);
|
||||||
|
@ -185,9 +183,9 @@ void ListMemoryMap() {
|
||||||
SerialPrintf("[ Mem] BIOS-Provided memory map:\r\n");
|
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};
|
char EntryType[8] = {0};
|
||||||
switch(MMapEnt_Type(MapEntry)) {
|
switch (MMapEnt_Type(MapEntry)) {
|
||||||
case MMAP_FREE:
|
case MMAP_FREE:
|
||||||
memcpy(EntryType, "FREE", 5);
|
memcpy(EntryType, "FREE", 5);
|
||||||
break;
|
break;
|
||||||
|
@ -206,17 +204,18 @@ void ListMemoryMap() {
|
||||||
size_t entry_to = MMapEnt_Ptr(MapEntry) + MMapEnt_Size(MapEntry);
|
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);
|
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.
|
// We need to page align the inputs to the buddy lists.
|
||||||
size_t page_from = AlignUpwards(entry_from, 0x1000);
|
size_t page_from = AlignUpwards(entry_from, 0x1000);
|
||||||
size_t page_to = AlignDownwards(entry_to, 0x1000);
|
size_t page_to = AlignDownwards(entry_to, 0x1000);
|
||||||
|
|
||||||
if(page_from != 0 && page_to != 0) {
|
if (page_from != 0 && page_to != 0) {
|
||||||
SerialPrintf("[ Mem] Adding the range 0x%p-0x%p to the physical memory manager!\r\n", page_from, page_to);
|
SerialPrintf("[ Mem] Adding the range 0x%p-0x%p to the physical memory manager!\r\n", page_from,
|
||||||
AddRangeToPhysMem((void*)((char*)(page_from)), page_to - 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) {
|
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);
|
SerialPrintf("[ Mem] New range in lower memory: 0x%p, size 0x%x\r\n", Base, Size);
|
||||||
AddRangeToBuddy(&LowBuddy, Base, Size);
|
AddRangeToBuddy(&LowBuddy, Base, Size);
|
||||||
} else {
|
} 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;
|
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);
|
AddRangeToBuddy(&LowBuddy, Base, difference);
|
||||||
Base = (void*) LOWER_REGION;
|
Base = (void*) LOWER_REGION;
|
||||||
Size = Size - difference;
|
Size = Size - difference;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(HighBuddy.Base == NULL) {
|
if (HighBuddy.Base == NULL) {
|
||||||
HighBuddy.Base = Base;
|
HighBuddy.Base = Base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,8 +246,8 @@ void AddRangeToPhysMem(directptr_t Base, size_t Size) {
|
||||||
AddRangeToBuddy(&HighBuddy, Base, Size);
|
AddRangeToBuddy(&HighBuddy, Base, Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(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;
|
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 PhysAllocateMem(size_t Size) {
|
||||||
directptr_t Pointer = NULL;
|
directptr_t Pointer = NULL;
|
||||||
|
|
||||||
if(HighBuddy.Base == 0) {
|
if (HighBuddy.Base == 0) {
|
||||||
//SerialPrintf("Attempting allocation into high memory.\n");
|
//SerialPrintf("Attempting allocation into high memory.\n");
|
||||||
Pointer = BuddyAllocate(&HighBuddy, Size);
|
Pointer = BuddyAllocate(&HighBuddy, Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Pointer == NULL) {
|
if (Pointer == NULL) {
|
||||||
//SerialPrintf("Attempting allocation into low memory.\n");
|
//SerialPrintf("Attempting allocation into low memory.\n");
|
||||||
Pointer = BuddyAllocate(&LowBuddy, Size);
|
Pointer = BuddyAllocate(&LowBuddy, Size);
|
||||||
}
|
}
|
||||||
|
@ -293,7 +294,7 @@ void PhysFreeMem(directptr_t Pointer, size_t Size) {
|
||||||
|
|
||||||
buddy_t* Buddy;
|
buddy_t* Buddy;
|
||||||
|
|
||||||
if(Pointer < (void*)(LOWER_REGION /* + DIRECT_REGION */))
|
if (Pointer < (void*) (LOWER_REGION /* + DIRECT_REGION */))
|
||||||
Buddy = &LowBuddy;
|
Buddy = &LowBuddy;
|
||||||
else
|
else
|
||||||
Buddy = &HighBuddy;
|
Buddy = &HighBuddy;
|
||||||
|
@ -305,7 +306,7 @@ void PhysFreeMem(directptr_t Pointer, size_t Size) {
|
||||||
static _Atomic(uint16_t)* PageRefCount = NULL;
|
static _Atomic(uint16_t)* PageRefCount = NULL;
|
||||||
|
|
||||||
void PhysAllocatorInit() {
|
void PhysAllocatorInit() {
|
||||||
PageRefCount = PhysAllocateZeroMem(sizeof(uint16_t) * MemoryPages);
|
PageRefCount = (_Atomic(uint16_t)*) PhysAllocateZeroMem(sizeof(uint16_t) * MemoryPages);
|
||||||
}
|
}
|
||||||
|
|
||||||
directptr_t PhysAllocatePage() {
|
directptr_t PhysAllocatePage() {
|
||||||
|
@ -319,7 +320,7 @@ void PhysRefPage(directptr_t Page) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysFreePage(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);
|
PhysFreeMem(Page, PAGE_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -328,7 +329,7 @@ void* memcpy(void* dest, void const* src, size_t len) {
|
||||||
unsigned char* dst = (unsigned char*) dest;
|
unsigned char* dst = (unsigned char*) dest;
|
||||||
const unsigned char* source = (const unsigned char*) src;
|
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];
|
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) {
|
void* memset(void* dst, int src, size_t len) {
|
||||||
unsigned char* buf = (unsigned char*) dst;
|
unsigned char* buf = (unsigned char*) dst;
|
||||||
|
|
||||||
for(size_t i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
buf[i] = (unsigned char) src;
|
buf[i] = (unsigned char) src;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dst;
|
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 ReadPort(uint16_t Port, int Length) {
|
||||||
uint32_t Data = 0;
|
uint32_t Data = 0;
|
||||||
uint16_t Data16 = 0;
|
uint16_t Data16 = 0;
|
||||||
uint8_t Data8 = 0;
|
uint8_t Data8 = 0;
|
||||||
|
|
||||||
if(Length == 1) {
|
if (Length == 1) {
|
||||||
__asm__ __volatile__ ("inb %[address], %[value]" : [value] "=a" (Data8) : [address] "d" (Port) :);
|
__asm__ __volatile__ ("inb %[address], %[value]" : [value] "=a"(Data8) : [address] "d"(Port) :);
|
||||||
Data = (uint32_t) Data8;
|
Data = (uint32_t) Data8;
|
||||||
} else if(Length == 2) {
|
} else if (Length == 2) {
|
||||||
__asm__ __volatile__ ("inw %[address], %[value]" : [value] "=a" (Data16) : [address] "d" (Port) :);
|
__asm__ __volatile__ ("inw %[address], %[value]" : [value] "=a"(Data16) : [address] "d"(Port) :);
|
||||||
Data = (uint32_t) Data16;
|
Data = (uint32_t) Data16;
|
||||||
} else if(Length == 4)
|
} else if (Length == 4)
|
||||||
__asm__ __volatile__ ("inl %[address], %[value]" : [value] "=a" (Data) : [address] "d" (Port) :);
|
__asm__ __volatile__ ("inl %[address], %[value]" : [value] "=a"(Data) : [address] "d"(Port) :);
|
||||||
//else
|
//else
|
||||||
//printf("Readport: Invalid length\r\n");
|
//printf("Readport: Invalid length\r\n");
|
||||||
|
|
||||||
return Data;
|
return Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t WritePort(uint16_t Port, uint32_t Data, int Length) {
|
uint32_t WritePort(uint16_t Port, uint32_t Data, int Length) {
|
||||||
if(Length == 1)
|
if (Length == 1)
|
||||||
__asm__ __volatile__ ("outb %[value], %[address]" : : [value] "a" ((uint8_t) Data), [address] "d" (Port) :);
|
__asm__ __volatile__ ("outb %[value], %[address]" : : [value] "a"((uint8_t) Data), [address] "d"(Port) :);
|
||||||
else if(Length == 2)
|
else if (Length == 2)
|
||||||
__asm__ __volatile__ ("outw %[value], %[address]" : : [value] "a" ((uint16_t) Data), [address] "d" (Port) :);
|
__asm__ __volatile__ ("outw %[value], %[address]" : : [value] "a"((uint16_t) Data), [address] "d"(Port) :);
|
||||||
else if(Length == 4)
|
else if (Length == 4)
|
||||||
__asm__ __volatile__ ("outl %[value], %[address]" : : [value] "a" (Data), [address] "d" (Port) :);
|
__asm__ __volatile__ ("outl %[value], %[address]" : : [value] "a"(Data), [address] "d"(Port) :);
|
||||||
//else
|
//else
|
||||||
//printf("WritePort: Invalid length.\r\n");
|
//printf("WritePort: Invalid length.\r\n");
|
||||||
|
|
||||||
return Data;
|
return Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ReadMMIO(size_t Address, int Length) {
|
size_t ReadMMIO(size_t Address, int Length) {
|
||||||
if (Length == 1) {
|
if (Length == 1) {
|
||||||
return *((volatile uint8_t*)(Address));
|
return *((volatile uint8_t*) (Address));
|
||||||
} else if (Length == 2) {
|
} else if (Length == 2) {
|
||||||
return *((volatile uint16_t*)(Address));
|
return *((volatile uint16_t*) (Address));
|
||||||
} else if (Length == 4) {
|
} else if (Length == 4) {
|
||||||
return *((volatile uint32_t*)(Address));
|
return *((volatile uint32_t*) (Address));
|
||||||
} else {
|
} else {
|
||||||
return *((volatile size_t*)(Address));
|
return *((volatile size_t*) (Address));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteMMIO(size_t Address, size_t Data, int Length) {
|
void WriteMMIO(size_t Address, size_t Data, int Length) {
|
||||||
if(Length == 1) {
|
if (Length == 1) {
|
||||||
(*((volatile uint8_t*)(Address))) = ((uint8_t) Data);
|
(*((volatile uint8_t*) (Address))) = ((uint8_t) Data);
|
||||||
} else if (Length == 2) {
|
} else if (Length == 2) {
|
||||||
(*((volatile uint16_t*)(Address))) = ((uint16_t) Data);
|
(*((volatile uint16_t*) (Address))) = ((uint16_t) Data);
|
||||||
} else if (Length == 4) {
|
} else if (Length == 4) {
|
||||||
(*((volatile uint32_t*)(Address))) = ((uint32_t) Data);
|
(*((volatile uint32_t*) (Address))) = ((uint32_t) Data);
|
||||||
} else {
|
} 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 ReadVexMXCSR() {
|
||||||
uint32_t Data;
|
uint32_t Data;
|
||||||
|
|
||||||
__asm__ __volatile__ ("vstmxcsr %[dest]" : [dest] "=m" (Data) : :);
|
__asm__ __volatile__ ("vstmxcsr %[dest]" : [dest] "=m"(Data) : :);
|
||||||
return Data;
|
return Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t WriteVexMXCSR(uint32_t Data) {
|
uint32_t WriteVexMXCSR(uint32_t Data) {
|
||||||
|
|
||||||
__asm__ __volatile__ ("vldmxcsr %[src]" : : [src] "m" (Data) :);
|
__asm__ __volatile__ ("vldmxcsr %[src]" : : [src] "m"(Data) :);
|
||||||
return Data;
|
return Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ReadMXCSR() {
|
uint32_t ReadMXCSR() {
|
||||||
uint32_t Data;
|
uint32_t Data;
|
||||||
|
|
||||||
__asm__ __volatile__ ("stmxcsr %[dest]" : [dest] "=m" (Data) : :);
|
__asm__ __volatile__ ("stmxcsr %[dest]" : [dest] "=m"(Data) : :);
|
||||||
return Data;
|
return Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t WriteMXCSR(uint32_t Data) {
|
uint32_t WriteMXCSR(uint32_t Data) {
|
||||||
|
|
||||||
__asm__ __volatile__ ("ldmxcsr %[src]" : : [src] "m" (Data) :);
|
__asm__ __volatile__ ("ldmxcsr %[src]" : : [src] "m"(Data) :);
|
||||||
return Data;
|
return Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,30 +121,30 @@ size_t ReadControlRegister(int CRX) {
|
||||||
|
|
||||||
size_t Data;
|
size_t Data;
|
||||||
|
|
||||||
switch(CRX) {
|
switch (CRX) {
|
||||||
case 0:
|
case 0:
|
||||||
__asm__ __volatile__ ("mov %%cr0, %[dest]" : [dest] "=r" (Data) : :);
|
__asm__ __volatile__ ("mov %%cr0, %[dest]" : [dest] "=r"(Data) : :);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
__asm__ __volatile__ ("mov %%cr1, %[dest]" : [dest] "=r" (Data) : :);
|
__asm__ __volatile__ ("mov %%cr1, %[dest]" : [dest] "=r"(Data) : :);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
__asm__ __volatile__ ("mov %%cr2, %[dest]" : [dest] "=r" (Data) : :);
|
__asm__ __volatile__ ("mov %%cr2, %[dest]" : [dest] "=r"(Data) : :);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
__asm__ __volatile__ ("mov %%cr3, %[dest]" : [dest] "=r" (Data) : :);
|
__asm__ __volatile__ ("mov %%cr3, %[dest]" : [dest] "=r"(Data) : :);
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
__asm__ __volatile__ ("mov %%cr4, %[dest]" : [dest] "=r" (Data) : :);
|
__asm__ __volatile__ ("mov %%cr4, %[dest]" : [dest] "=r"(Data) : :);
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
__asm__ __volatile__ ("mov %%cr8, %[dest]" : [dest] "=r" (Data) : :);
|
__asm__ __volatile__ ("mov %%cr8, %[dest]" : [dest] "=r"(Data) : :);
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
__asm__ __volatile__ ("pushfq\n\t" "popq %[dest]" : [dest] "=r" (Data) : :);
|
__asm__ __volatile__ ("pushfq\n\t" "popq %[dest]" : [dest] "=r"(Data) : :);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
SerialPrintf("invalid crx read %x\r\n",CRX);
|
SerialPrintf("invalid crx read %x\r\n", CRX);
|
||||||
Data = 0xdeadbeef;
|
Data = 0xdeadbeef;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -153,27 +153,27 @@ size_t ReadControlRegister(int CRX) {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t WriteControlRegister(int CRX, size_t Data) {
|
size_t WriteControlRegister(int CRX, size_t Data) {
|
||||||
switch(CRX) {
|
switch (CRX) {
|
||||||
case 0:
|
case 0:
|
||||||
__asm__ __volatile__ ("movq %[dest], %%cr0" : : [dest] "r" (Data) : );
|
__asm__ __volatile__ ("movq %[dest], %%cr0" : : [dest] "r"(Data) : );
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
__asm__ __volatile__ ("movq %[dest], %%cr1" : : [dest] "r" (Data) : );
|
__asm__ __volatile__ ("movq %[dest], %%cr1" : : [dest] "r"(Data) : );
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
__asm__ __volatile__ ("movq %[dest], %%cr2" : : [dest] "r" (Data) : );
|
__asm__ __volatile__ ("movq %[dest], %%cr2" : : [dest] "r"(Data) : );
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
__asm__ __volatile__ ("movq %[dest], %%cr3" : : [dest] "r" (Data) : );
|
__asm__ __volatile__ ("movq %[dest], %%cr3" : : [dest] "r"(Data) : );
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
__asm__ __volatile__ ("movq %[dest], %%cr4" : : [dest] "r" (Data) : );
|
__asm__ __volatile__ ("movq %[dest], %%cr4" : : [dest] "r"(Data) : );
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
__asm__ __volatile__ ("movq %[dest], %%cr8" : : [dest] "r" (Data) : );
|
__asm__ __volatile__ ("movq %[dest], %%cr8" : : [dest] "r"(Data) : );
|
||||||
break;
|
break;
|
||||||
case 'f':
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
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
|
//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
|
// errors that shoudlunt really happen doesent make alot of sense
|
||||||
size_t WriteExtendedControlRegister(size_t XCRX, size_t Data){
|
size_t WriteExtendedControlRegister(size_t XCRX, size_t Data) {
|
||||||
uint32_t DataLow = Data & 0x00000000ffffffff;
|
uint32_t DataLow = Data & 0x00000000ffffffff;
|
||||||
uint32_t DataHigh = (Data & 0xffffffff00000000) >> 32;
|
uint32_t DataHigh = (Data & 0xffffffff00000000) >> 32;
|
||||||
__asm__ __volatile__("xsetbv" : : "a" (DataLow), "c" (XCRX), "d" (DataHigh) :);
|
__asm__ __volatile__("xsetbv" : : "a" (DataLow), "c" (XCRX), "d" (DataHigh) :);
|
||||||
return Data;
|
return Data;
|
||||||
|
@ -202,60 +202,60 @@ size_t WriteExtendedControlRegister(size_t XCRX, size_t Data){
|
||||||
size_t ReadXCS() {
|
size_t ReadXCS() {
|
||||||
size_t Data;
|
size_t Data;
|
||||||
|
|
||||||
__asm__ __volatile__("mov %%cs, %[dest]" : [dest] "=r" (Data) : :);
|
__asm__ __volatile__("mov %%cs, %[dest]" : [dest] "=r"(Data) : :);
|
||||||
return Data;
|
return Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
DESC_TBL ReadGDT() {
|
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;
|
return GDTData;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteGDT(DESC_TBL 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 ReadIDT() {
|
||||||
DESC_TBL IDTData = {0};
|
DESC_TBL IDTData;
|
||||||
|
|
||||||
__asm__ __volatile__("sidt %[dest]" : [dest] "=m" (IDTData) : :);
|
__asm__ __volatile__("sidt %[dest]" : [dest] "=m"(IDTData) : :);
|
||||||
|
|
||||||
return IDTData;
|
return IDTData;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteIDT(DESC_TBL 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 ReadLDT() {
|
||||||
uint16_t LDTData;
|
uint16_t LDTData;
|
||||||
|
|
||||||
__asm__ __volatile__("sldt %[dest]" : [dest] "=m" (LDTData) : :);
|
__asm__ __volatile__("sldt %[dest]" : [dest] "=m"(LDTData) : :);
|
||||||
|
|
||||||
return LDTData;
|
return LDTData;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteLDT(uint16_t 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 ReadTSR() {
|
||||||
uint16_t TSRData;
|
uint16_t TSRData;
|
||||||
|
|
||||||
__asm__ __volatile__("str %[dest]" : [dest] "=m" (TSRData) : :);
|
__asm__ __volatile__("str %[dest]" : [dest] "=m"(TSRData) : :);
|
||||||
|
|
||||||
return TSRData;
|
return TSRData;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteTSR(uint16_t 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) {
|
void WriteSerialChar(const char chr) {
|
||||||
while(!(CheckSerial() & 0x20));
|
while (!(CheckSerial() & 0x20));
|
||||||
WritePort(COM1, chr, 1);
|
WritePort(COM1, chr, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteSerialString(const char* str, size_t len) {
|
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]);
|
WriteSerialChar(str[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,7 +20,7 @@ extern "C" {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
PRINTINFO PrintInfo = {0};
|
PRINTINFO PrintInfo;
|
||||||
|
|
||||||
#define FONT bitfont_latin
|
#define FONT bitfont_latin
|
||||||
|
|
||||||
|
@ -44,8 +44,10 @@ void InitPrint() {
|
||||||
|
|
||||||
PrintInfo.charsPerRow = bootldr.fb_width / (PrintInfo.charScale * PrintInfo.charWidth);
|
PrintInfo.charsPerRow = bootldr.fb_width / (PrintInfo.charScale * PrintInfo.charWidth);
|
||||||
PrintInfo.rowsPerScrn = bootldr.fb_height / (PrintInfo.charScale * PrintInfo.charHeight);
|
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] A single character is %ux%u pixels.\r\n", PrintInfo.charScale * PrintInfo.charWidth,
|
||||||
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);
|
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");
|
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;
|
uint32_t Y = PrintInfo.charWidth >> 3, X = 0;
|
||||||
|
|
||||||
if((PrintInfo.charWidth & 0x7) != 0) {
|
if ((PrintInfo.charWidth & 0x7) != 0) {
|
||||||
Y++;
|
Y++;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(uint32_t Row = 0; Row < PrintInfo.charHeight; Row++) {
|
for (uint32_t Row = 0; Row < PrintInfo.charHeight; Row++) {
|
||||||
for(uint32_t Bit = 0; Bit < PrintInfo.charWidth; Bit++) {
|
for (uint32_t Bit = 0; Bit < PrintInfo.charWidth; Bit++) {
|
||||||
if ( ((Bit & 0x7) == 0) && (Bit > 0)) {
|
if (((Bit & 0x7) == 0) && (Bit > 0)) {
|
||||||
X++;
|
X++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This one is crazy. Stick with me.
|
// 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 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 ScaleX = 0; ScaleX < PrintInfo.charScale; ScaleX++) { // And the scale width
|
||||||
size_t offset = ((y * bootldr.fb_width + x) + // Calculate the offset from the framebuffer
|
size_t offset = ((y * bootldr.fb_width + x) + // Calculate the offset from the framebuffer
|
||||||
PrintInfo.charScale * (Row * bootldr.fb_width + Bit) + // With the appropriate scale
|
PrintInfo.charScale * (Row * bootldr.fb_width + Bit) +
|
||||||
(ScaleY * bootldr.fb_width + ScaleX) + // In X and Y
|
// With the appropriate scale
|
||||||
PrintInfo.charScale * 1 * PrintInfo.charWidth) - 10; // With some offset to start at 0
|
(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..
|
// Check the bit in the bitmap, if it's solid..
|
||||||
if((FONT[(int)character][Row * Y + X] >> (Bit & 0x7)) & 1) {
|
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
|
*(uint32_t*) (&fb + offset * 4) //use it to set the correct pixel on the screen
|
||||||
= PrintInfo.charFGColor; // In the set foreground color
|
= PrintInfo.charFGColor; // In the set foreground color
|
||||||
} else { // otherwise,
|
} else { // otherwise,
|
||||||
*(uint32_t* )(&fb + offset * 4)
|
*(uint32_t*) (&fb + offset * 4)
|
||||||
= PrintInfo.charBGColor; // set the background color.
|
= PrintInfo.charBGColor; // set the background color.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,11 +114,9 @@ inline void DrawPixel(size_t x, size_t y) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FillScreen(uint32_t color) {
|
void FillScreen(uint32_t color) {
|
||||||
uint32_t currentColor = GetForegroundColor();
|
for (uint32_t pixel = 0; pixel < bootldr.fb_width * bootldr.fb_height; pixel++) {
|
||||||
for(uint32_t pixel = 0; pixel < bootldr.fb_width * bootldr.fb_height; pixel++) {
|
((uint32_t*) &fb)[pixel] = color;
|
||||||
((uint32_t*)&fb)[pixel] = color;
|
|
||||||
}
|
}
|
||||||
SetForegroundColor(currentColor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Newline() {
|
static void Newline() {
|
||||||
|
@ -123,10 +125,10 @@ static void Newline() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ProgressCursorS(size_t Steps) {
|
static void ProgressCursorS(size_t Steps) {
|
||||||
if(PrintInfo.charPosX + Steps > PrintInfo.charsPerRow) {
|
if (PrintInfo.charPosX + Steps > PrintInfo.charsPerRow) {
|
||||||
PrintInfo.charPosX = 0;
|
PrintInfo.charPosX = 0;
|
||||||
size_t Rows = Steps / PrintInfo.charsPerRow;
|
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;
|
size_t RowsLeft = PrintInfo.rowsPerScrn - PrintInfo.charPosY;
|
||||||
ProgressCursorS(RowsLeft + 1);
|
ProgressCursorS(RowsLeft + 1);
|
||||||
Newline();
|
Newline();
|
||||||
|
@ -146,8 +148,8 @@ static void ProgressCursor() {
|
||||||
static void Backspace() {
|
static void Backspace() {
|
||||||
|
|
||||||
SerialPrintf("Backspacing from %d to %d\r\n", PrintInfo.charPosX, PrintInfo.charPosX - 1);
|
SerialPrintf("Backspacing from %d to %d\r\n", PrintInfo.charPosX, PrintInfo.charPosX - 1);
|
||||||
if(PrintInfo.charPosX - 1 <= 0) {
|
if (PrintInfo.charPosX - 1 <= 0) {
|
||||||
if(PrintInfo.charPosY - 1 <= 0) {
|
if (PrintInfo.charPosY - 1 <= 0) {
|
||||||
PrintInfo.charPosY = 0;
|
PrintInfo.charPosY = 0;
|
||||||
} else {
|
} else {
|
||||||
PrintInfo.charPosY--;
|
PrintInfo.charPosY--;
|
||||||
|
@ -160,7 +162,7 @@ static void Backspace() {
|
||||||
|
|
||||||
void WriteChar(const char character) {
|
void WriteChar(const char character) {
|
||||||
// TODO: Color codes!
|
// TODO: Color codes!
|
||||||
switch(character) {
|
switch (character) {
|
||||||
case '\b':
|
case '\b':
|
||||||
Backspace();
|
Backspace();
|
||||||
DrawChar((char) 32, PrintInfo.charPosX, PrintInfo.charPosY);
|
DrawChar((char) 32, PrintInfo.charPosX, PrintInfo.charPosY);
|
||||||
|
@ -184,49 +186,50 @@ void WriteChar(const char character) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteString(const char* string) {
|
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]);
|
WriteChar(string[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ! Deprecated.
|
// ! Deprecated.
|
||||||
// TODO: Fix this to work with arbitrary length and offset.
|
// TODO: Fix this to work with arbitrary length and offset.
|
||||||
void WriteStringWithFont(const char *inChar) {
|
void WriteStringWithFont(const char* inChar) {
|
||||||
psf_t *font = (psf_t*) &_binary_src_assets_font_psf_start;
|
psf_t* font = (psf_t*) &_binary_src_assets_font_psf_start;
|
||||||
|
|
||||||
unsigned int drawX, drawY, kx = 0, fontLine, bitMask, offset;
|
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) {
|
while (*inChar) {
|
||||||
unsigned char *glyph =
|
unsigned char* glyph =
|
||||||
(unsigned char*) &_binary_src_assets_font_psf_start
|
(unsigned char*) &_binary_src_assets_font_psf_start
|
||||||
+ font->headerSize
|
+ font->headerSize
|
||||||
+ (*inChar > 0 && *inChar < (int)font->numGlyphs ? *inChar : 0) *
|
+ (*inChar > 0 && *inChar < (int) font->numGlyphs ? *inChar : 0) *
|
||||||
font->glyphSize;
|
font->glyphSize;
|
||||||
|
|
||||||
|
|
||||||
offset = (kx * (font->glyphWidth + 1) * 4);
|
offset = (kx * (font->glyphWidth + 1) * 4);
|
||||||
|
|
||||||
for( drawY = 0; drawY < font->glyphHeight ; drawY++) {
|
for (drawY = 0; drawY < font->glyphHeight; drawY++) {
|
||||||
fontLine = offset;
|
fontLine = offset;
|
||||||
bitMask = 1 << (font->glyphWidth - 1);
|
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)) =
|
*((uint32_t*) ((uint64_t) &fb + fontLine)) =
|
||||||
((int) *glyph) & (bitMask) ? 0xFFFFFF : 0;
|
((int) *glyph) & (bitMask) ? 0xFFFFFF : 0;
|
||||||
bitMask >>= 1;
|
bitMask >>= 1;
|
||||||
fontLine += 4;
|
fontLine += 4;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*((uint32_t*)((uint64_t) &fb + fontLine)) = 0;
|
*((uint32_t*) ((uint64_t) &fb + fontLine)) = 0;
|
||||||
glyph += bytesPerLine;
|
glyph += bytesPerLine;
|
||||||
offset += bootldr.fb_scanline;
|
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++) {
|
for (; x0 <= x1; x0++) {
|
||||||
if (steep)
|
if (steep)
|
||||||
DrawPixel(y0, x0);
|
DrawPixel(y0, x0);
|
||||||
else
|
else
|
||||||
DrawPixel(x0, y0);
|
DrawPixel(x0, y0);
|
||||||
|
|
||||||
err -= dy;
|
err -= dy;
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
y0 += ystep;
|
y0 += ystep;
|
||||||
err += dx;
|
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);
|
DrawVerticalLine(x0, y0, y1 - y0 + 1);
|
||||||
} else if (y0 == y1) {
|
} else if (y0 == y1) {
|
||||||
if (x0 > x1)
|
if (x0 > x1)
|
||||||
_swap_size_t(x0, x1);
|
_swap_size_t(x0, x1);
|
||||||
|
|
||||||
DrawHorizontalLine(x0, y0, x1 - x0 + 1);
|
DrawHorizontalLine(x0, y0, x1 - x0 + 1);
|
||||||
} else {
|
} else {
|
||||||
|
@ -449,22 +452,22 @@ void DrawLineCircleCorners(size_t centerX, size_t centerY, size_t radius, char c
|
||||||
ddF_x += 2;
|
ddF_x += 2;
|
||||||
f += ddF_x;
|
f += ddF_x;
|
||||||
|
|
||||||
if(cornerMask & 0x4) {
|
if (cornerMask & 0x4) {
|
||||||
DrawPixel(centerX + x, centerY + y);
|
DrawPixel(centerX + x, centerY + y);
|
||||||
DrawPixel(centerX + y, centerY + x);
|
DrawPixel(centerX + y, centerY + x);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cornerMask & 0x2) {
|
if (cornerMask & 0x2) {
|
||||||
DrawPixel(centerX + x, centerY - y);
|
DrawPixel(centerX + x, centerY - y);
|
||||||
DrawPixel(centerX - y, centerY - x);
|
DrawPixel(centerX - y, centerY - x);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cornerMask & 0x8) {
|
if (cornerMask & 0x8) {
|
||||||
DrawPixel(centerX - y, centerY + x);
|
DrawPixel(centerX - y, centerY + x);
|
||||||
DrawPixel(centerX - x, centerY + y);
|
DrawPixel(centerX - x, centerY + y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cornerMask & 0x1) {
|
if (cornerMask & 0x1) {
|
||||||
DrawPixel(centerX - y, centerY - x);
|
DrawPixel(centerX - y, centerY - x);
|
||||||
DrawPixel(centerX - x, centerY - y);
|
DrawPixel(centerX - x, centerY - y);
|
||||||
}
|
}
|
|
@ -28,7 +28,7 @@ void NumToStr(char* Buffer, size_t Num, size_t Base) {
|
||||||
|
|
||||||
Buffer[i--] = 0;
|
Buffer[i--] = 0;
|
||||||
|
|
||||||
for(j = 0; j < i; j++, i--) {
|
for (j = 0; j < i; j++, i--) {
|
||||||
Temp = Buffer[j];
|
Temp = Buffer[j];
|
||||||
Buffer[j] = Buffer[i];
|
Buffer[j] = Buffer[i];
|
||||||
Buffer[i] = Temp;
|
Buffer[i] = Temp;
|
||||||
|
@ -45,15 +45,19 @@ int SerialPrintf(const char* Format, ...) {
|
||||||
|
|
||||||
char BufferStr[512] = {0};
|
char BufferStr[512] = {0};
|
||||||
|
|
||||||
while(*Format != '\0') {
|
while (*Format != '\0') {
|
||||||
size_t Limit = UINT64_MAX - CharsWritten;
|
size_t Limit = UINT64_MAX - CharsWritten;
|
||||||
|
|
||||||
if(*Format == '%') {
|
if (*Format == '%') {
|
||||||
if(*(++Format) == '%')
|
if (*(++Format) == '%')
|
||||||
Format++;
|
Format++;
|
||||||
|
|
||||||
|
|
||||||
switch(*Format) {
|
switch (*Format) {
|
||||||
|
case '.':
|
||||||
|
Limit = va_arg(Parameters, size_t);
|
||||||
|
[[fallthrough]];
|
||||||
|
|
||||||
case 'c': {
|
case 'c': {
|
||||||
Format++;
|
Format++;
|
||||||
|
|
||||||
|
@ -68,10 +72,7 @@ int SerialPrintf(const char* Format, ...) {
|
||||||
Format++;
|
Format++;
|
||||||
const char* Str = va_arg(Parameters, char*);
|
const char* Str = va_arg(Parameters, char*);
|
||||||
|
|
||||||
size_t Len = strlen(Str);
|
size_t Len = MIN(strlen(Str), Limit);
|
||||||
|
|
||||||
if(Limit < Len)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
WriteSerialString(Str, Len);
|
WriteSerialString(Str, Len);
|
||||||
|
|
||||||
|
@ -87,7 +88,7 @@ int SerialPrintf(const char* Format, ...) {
|
||||||
Base = 0;
|
Base = 0;
|
||||||
|
|
||||||
|
|
||||||
if(*Format == 'd' || *Format == 'u') {
|
if (*Format == 'd' || *Format == 'u') {
|
||||||
Base = 10; // Decimal & Unsigned are base 10
|
Base = 10; // Decimal & Unsigned are base 10
|
||||||
} else {
|
} else {
|
||||||
Base = 16; // Hex and Ptr are base 16
|
Base = 16; // Hex and Ptr are base 16
|
||||||
|
@ -102,7 +103,7 @@ int SerialPrintf(const char* Format, ...) {
|
||||||
CharsWritten += Len;
|
CharsWritten += Len;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//case 'p':
|
//case 'p':
|
||||||
//uint8_t Base = 16;
|
//uint8_t Base = 16;
|
||||||
//size_t Dest = (uintptr_t) va_arg(Parameters, void*);
|
//size_t Dest = (uintptr_t) va_arg(Parameters, void*);
|
||||||
default:
|
default:
|
||||||
|
@ -132,14 +133,14 @@ int Printf(const char* Format, ...) {
|
||||||
|
|
||||||
char BufferStr[512] = {0};
|
char BufferStr[512] = {0};
|
||||||
|
|
||||||
while(*Format != '\0') {
|
while (*Format != '\0') {
|
||||||
size_t Limit = UINT64_MAX - CharsWritten;
|
size_t Limit = UINT64_MAX - CharsWritten;
|
||||||
|
|
||||||
if(*Format == '%') {
|
if (*Format == '%') {
|
||||||
if(*(++Format) == '%')
|
if (*(++Format) == '%')
|
||||||
Format++;
|
Format++;
|
||||||
|
|
||||||
switch(*Format) {
|
switch (*Format) {
|
||||||
case 'c': {
|
case 'c': {
|
||||||
Format++;
|
Format++;
|
||||||
|
|
||||||
|
@ -156,7 +157,7 @@ int Printf(const char* Format, ...) {
|
||||||
|
|
||||||
size_t Len = strlen(Str);
|
size_t Len = strlen(Str);
|
||||||
|
|
||||||
if(Limit < Len)
|
if (Limit < Len)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
WriteString(Str);
|
WriteString(Str);
|
||||||
|
@ -173,7 +174,7 @@ int Printf(const char* Format, ...) {
|
||||||
Base = 0;
|
Base = 0;
|
||||||
|
|
||||||
|
|
||||||
if(*Format == 'd' || *Format == 'u') {
|
if (*Format == 'd' || *Format == 'u') {
|
||||||
Base = 10; // Decimal & Unsigned are base 10
|
Base = 10; // Decimal & Unsigned are base 10
|
||||||
} else {
|
} else {
|
||||||
Base = 16; // Hex and Ptr are base 16
|
Base = 16; // Hex and Ptr are base 16
|
||||||
|
@ -188,7 +189,7 @@ int Printf(const char* Format, ...) {
|
||||||
CharsWritten += Len;
|
CharsWritten += Len;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//case 'p':
|
//case 'p':
|
||||||
//uint8_t Base = 16;
|
//uint8_t Base = 16;
|
||||||
//size_t Dest = (uintptr_t) va_arg(Parameters, void*);
|
//size_t Dest = (uintptr_t) va_arg(Parameters, void*);
|
||||||
default:
|
default:
|
||||||
|
@ -196,17 +197,17 @@ int Printf(const char* Format, ...) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if(*Format == '\\') {
|
} else if (*Format == '\\') {
|
||||||
Format++; // Skip backslash
|
Format++; // Skip backslash
|
||||||
|
|
||||||
switch(*Format) {
|
switch (*Format) {
|
||||||
case '$': {
|
case '$': {
|
||||||
// COLOR
|
// COLOR
|
||||||
Format ++; // Skip $
|
Format++; // Skip $
|
||||||
size_t Color = 0;
|
size_t Color = 0;
|
||||||
bool bgFlag = false;
|
bool bgFlag = false;
|
||||||
|
|
||||||
switch(*Format) {
|
switch (*Format) {
|
||||||
case '[':
|
case '[':
|
||||||
// bg
|
// bg
|
||||||
bgFlag = true;
|
bgFlag = true;
|
||||||
|
@ -215,19 +216,19 @@ int Printf(const char* Format, ...) {
|
||||||
// fg
|
// fg
|
||||||
Format++; // [ or {
|
Format++; // [ or {
|
||||||
|
|
||||||
if(*Format == '<') {
|
if (*Format == '<') {
|
||||||
Format++;
|
Format++;
|
||||||
Color = ParseEnglishColor((char*) Format);
|
Color = ParseEnglishColor((char*) Format);
|
||||||
} else {
|
} else {
|
||||||
Color = ParseHexColor(Format, bgFlag);
|
Color = ParseHexColor(Format, bgFlag);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(bgFlag)
|
if (bgFlag)
|
||||||
SetBackgroundColor(Color);
|
SetBackgroundColor(Color);
|
||||||
else
|
else
|
||||||
SetForegroundColor(Color);
|
SetForegroundColor(Color);
|
||||||
|
|
||||||
while(*Format != '}')
|
while (*Format != '}')
|
||||||
Format++;
|
Format++;
|
||||||
Format++; // }
|
Format++; // }
|
||||||
break;
|
break;
|
||||||
|
@ -251,23 +252,23 @@ int Printf(const char* Format, ...) {
|
||||||
|
|
||||||
|
|
||||||
size_t ParseEnglishColor(char* Stream) {
|
size_t ParseEnglishColor(char* Stream) {
|
||||||
if(strcmp(Stream, "red"))
|
if (strcmp(Stream, "red"))
|
||||||
return 0xFF0000;
|
return 0xFF0000;
|
||||||
if(strcmp(Stream, "green"))
|
if (strcmp(Stream, "green"))
|
||||||
return 0xFF00;
|
return 0xFF00;
|
||||||
if(strcmp(Stream, "blue"))
|
if (strcmp(Stream, "blue"))
|
||||||
return 0xFF;
|
return 0xFF;
|
||||||
if(strcmp(Stream, "yellow"))
|
if (strcmp(Stream, "yellow"))
|
||||||
return 0xFFFF00;
|
return 0xFFFF00;
|
||||||
if(strcmp(Stream, "cyan"))
|
if (strcmp(Stream, "cyan"))
|
||||||
return 0xFFFF;
|
return 0xFFFF;
|
||||||
if(strcmp(Stream, "magenta"))
|
if (strcmp(Stream, "magenta"))
|
||||||
return 0xFF00FF;
|
return 0xFF00FF;
|
||||||
if(strcmp(Stream, "beans"))
|
if (strcmp(Stream, "beans"))
|
||||||
return 0xAA11CC;
|
return 0xAA11CC;
|
||||||
if(strcmp(Stream, "forgeb"))
|
if (strcmp(Stream, "forgeb"))
|
||||||
return 0x1E2D42;
|
return 0x1E2D42;
|
||||||
if(strcmp(Stream, "forgey"))
|
if (strcmp(Stream, "forgey"))
|
||||||
return 0xE0A969;
|
return 0xE0A969;
|
||||||
return 0xFFFFFF;
|
return 0xFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user