Large rewrites & struggles
This commit is contained in:
parent
06134ebcd9
commit
acda33948e
|
@ -15,37 +15,39 @@ project(chroma)
|
|||
|
||||
SET(src_files
|
||||
${CMAKE_SOURCE_DIR}/src/kernel.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/video/draw.c
|
||||
${CMAKE_SOURCE_DIR}/src/video/draw.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/video/print.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/system/cpu.c
|
||||
${CMAKE_SOURCE_DIR}/src/system/rw.c
|
||||
${CMAKE_SOURCE_DIR}/src/system/serial.c
|
||||
${CMAKE_SOURCE_DIR}/src/system/pci.c
|
||||
${CMAKE_SOURCE_DIR}/src/system/memory/stack.c
|
||||
${CMAKE_SOURCE_DIR}/src/system/memory/paging.c
|
||||
${CMAKE_SOURCE_DIR}/src/system/memory/abstract_allocator.c
|
||||
${CMAKE_SOURCE_DIR}/src/system/memory/liballoc.c
|
||||
${CMAKE_SOURCE_DIR}/src/system/cpu.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/system/core.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/system/rw.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/system/serial.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/system/pci.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/system/acpi/MADT.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/system/acpi/RSDP.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/system/memory/paging.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/system/memory/abstract_allocator.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/system/memory/liballoc.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/system/memory/physmem.c
|
||||
${CMAKE_SOURCE_DIR}/src/drivers/keyboard.c
|
||||
${CMAKE_SOURCE_DIR}/src/drivers/elf.c
|
||||
${CMAKE_SOURCE_DIR}/src/system/process/process.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/drivers/elf.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/drivers/devices/devices.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/drivers/devices/input/keyboard.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/drivers/devices/io/apic.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/drivers/devices/storage/ata.cpp
|
||||
|
||||
)
|
||||
|
||||
SET(lib_files
|
||||
${CMAKE_SOURCE_DIR}/src/lainlib/list/basic_list.c
|
||||
${CMAKE_SOURCE_DIR}/src/lainlib/mutex/ticketlock.c
|
||||
${CMAKE_SOURCE_DIR}/src/lainlib/list/basic_list.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/lainlib/mutex/ticketlock.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/lainlib/compression/lzgmini.c
|
||||
${CMAKE_SOURCE_DIR}/src/lainlib/string/str.c
|
||||
|
||||
${CMAKE_SOURCE_DIR}/src/lainlib/string/str.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/editor/EditorMain.cpp
|
||||
)
|
||||
|
||||
include_directories("inc" "D:/mingw/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++" "D:/mingw/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32")
|
||||
|
||||
SET(src_no_sse
|
||||
${CMAKE_SOURCE_DIR}/src/system/interrupts.c
|
||||
${CMAKE_SOURCE_DIR}/src/system/interrupts.cpp
|
||||
)
|
||||
|
||||
SET(src_preamble
|
||||
|
@ -68,5 +70,5 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
|
|||
add_executable(kernel)
|
||||
|
||||
target_sources(kernel PUBLIC ${src_preamble} PUBLIC ${src_files} PUBLIC ${src_no_sse} PUBLIC ${lib_files} PUBLIC ${src_epilogue})
|
||||
target_compile_options(kernel PRIVATE -ffreestanding -O0 -Wall -Wextra -Wall -Werror -fPIC -fno-exceptions -fno-omit-frame-pointer -mno-red-zone -fno-stack-protector -ggdb3)
|
||||
target_compile_options(kernel PRIVATE -ffreestanding -O0 -Wall -Wextra -Wall -Werror -fPIC -fno-exceptions -fno-omit-frame-pointer -mno-red-zone -fno-stack-protector -fno-rtti -ggdb3)
|
||||
target_link_options(kernel PRIVATE -T ${CMAKE_SOURCE_DIR}/linker.ld -ffreestanding -O2 -nostdlib -nostartfiles -lgcc)
|
||||
|
|
3
Testing/Temporary/LastTest.log
Normal file
3
Testing/Temporary/LastTest.log
Normal file
|
@ -0,0 +1,3 @@
|
|||
Start testing: Feb 17 01:48 GMT Standard Time
|
||||
----------------------------------------------------------
|
||||
End testing: Feb 17 01:48 GMT Standard Time
|
BIN
chroma.iso
Normal file
BIN
chroma.iso
Normal file
Binary file not shown.
BIN
img/boot/exe
BIN
img/boot/exe
Binary file not shown.
|
@ -15,10 +15,11 @@ namespace Device {
|
|||
|
||||
// The internal typemap of devices used in Chroma.
|
||||
enum DeviceType : uint32_t {
|
||||
STORAGE = 0,
|
||||
KEYBOARD = 1,
|
||||
NETWORK = 2,
|
||||
UNKNOWN = 0xFFFFFFFF
|
||||
STORAGE = 0, // Stores data.
|
||||
INTERNAL = 1, // PCI, APIC, AHCI.
|
||||
INTERFACE = 2, // Peripherals and I/O
|
||||
NETWORK = 3, // NIC.
|
||||
UNKNOWN = 0xFFFFFFFF // Unsupported.
|
||||
};
|
||||
|
||||
// The base class that all devices extend from.
|
||||
|
@ -81,6 +82,35 @@ namespace Device {
|
|||
|
||||
};
|
||||
|
||||
// The base class for every device that uses port or MMIO to communicate.
|
||||
class IODevice : public GenericDevice {
|
||||
public:
|
||||
|
||||
// Pre-use setup.
|
||||
virtual void Init() = 0;
|
||||
|
||||
// This is an internal register device.
|
||||
DeviceType GetType() const final {
|
||||
return DeviceType::INTERNAL;
|
||||
}
|
||||
|
||||
// Provided for utility checks.
|
||||
static DeviceType GetRootType() {
|
||||
return DeviceType::INTERNAL;
|
||||
}
|
||||
|
||||
// Read data from a given port.
|
||||
virtual uint32_t ReadRegister(uint32_t Register) = 0;
|
||||
// Write data into a given port.
|
||||
virtual void WriteRegister(uint32_t Register, uint32_t Data) = 0;
|
||||
|
||||
// Read data from the given address.
|
||||
virtual uint32_t ReadIO(size_t Base, uint32_t Register) = 0;
|
||||
// Write data into the given address.
|
||||
virtual void WriteIO(size_t Base, uint32_t Register, uint32_t Data) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
// Add a device pointer to the managed list.
|
||||
void RegisterDevice(GenericDevice* Dev);
|
||||
|
|
115
inc/driver/io/apic.h
Normal file
115
inc/driver/io/apic.h
Normal file
|
@ -0,0 +1,115 @@
|
|||
#pragma once
|
||||
#include <driver/generic/device.h>
|
||||
#include <kernel/system/acpi/madt.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2021 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
namespace Device {
|
||||
|
||||
/**
|
||||
* Contains the driver definition for the Advanced Programmable Interrupt Controller - APIC.
|
||||
* Each processor core contains at least one APIC, and they have a unique identifier,
|
||||
* so they can be used to identify cores along with producing timed interrupts.
|
||||
*
|
||||
* However, this is only possible because this driver is loaded once per system.
|
||||
* This is a singleton class.
|
||||
*
|
||||
* The primary functionality of the APIC is to send an interrupt to the given core after the specified time is up.
|
||||
*/
|
||||
|
||||
class APIC : public IODevice {
|
||||
private:
|
||||
// Metadata of IOAPICs.
|
||||
struct IOAPICMeta {
|
||||
uint8_t Version;
|
||||
uint8_t Reserved;
|
||||
uint8_t MaxRedirect;
|
||||
uint8_t Reserved2;
|
||||
};
|
||||
|
||||
// The address in physical memory that refers to this device.
|
||||
void* Address;
|
||||
// Whether this APIC driver is ready for processing.
|
||||
bool Ready = false;
|
||||
|
||||
ACPI::MADT::IOAPICEntry** IOAPICs;
|
||||
ACPI::MADT::ISOEntry** ISOs;
|
||||
IOAPICMeta* Meta;
|
||||
|
||||
// The internal implementation of Set. Handles raw redirects at the hardware level.
|
||||
void SetInternal(uint8_t Vector, uint32_t TargetGSI, uint16_t Flags, int Core, int Status);
|
||||
|
||||
public:
|
||||
|
||||
APIC();
|
||||
|
||||
// The register locations of the APIC device.
|
||||
enum Registers {
|
||||
LAPIC_ID = 0x20, // ID of the APIC
|
||||
EOI = 0xB0, // Acknowledge
|
||||
SIVR = 0xF0, // Spurious Interrupt Vector Register
|
||||
ICR1 = 0x300, // Interrupt Command Register Lower
|
||||
ICR2 = 0x310, // Interrupt Command Register Higher
|
||||
LVT = 0x320, // Local Vector Table
|
||||
LINT1 = 0x350, // Local Interrupt ID
|
||||
LINT2 = 0x360, // Local Interrupt ID
|
||||
TIMER_DIVISOR = 0x3E0, // Frequency divisor for the timer.
|
||||
TIMER_INIT = 0x380, // Initializer for the timer.
|
||||
TIMER_CURRENT = 0x390, // Current "tick count" of the timer.
|
||||
};
|
||||
|
||||
// The instance of this singleton class.
|
||||
static APIC* driver;
|
||||
|
||||
const char* GetName() const override {
|
||||
return "APIC";
|
||||
}
|
||||
|
||||
// Dump all available information to the log (or to stdout eventually)
|
||||
void LogDump();
|
||||
|
||||
// Move all structs and internal handlers to a new address.
|
||||
void Move(size_t NewAddress);
|
||||
|
||||
// Prepare the APICs for use.
|
||||
void Init() override;
|
||||
// Load all data the APICs need.
|
||||
void LoadInterruptSystem();
|
||||
// Set the APICs ready for use.
|
||||
void Enable();
|
||||
// Check whether the APICs are ready for use.
|
||||
bool IsReady();
|
||||
|
||||
// Prepare a core for use with interrupts.
|
||||
void PreinitializeCore(int Core);
|
||||
// Set a core as available to use interrupts.
|
||||
void InitializeCore(int Core, size_t EntryPoint);
|
||||
|
||||
// Check what core ID is currently running.
|
||||
int GetCurrentCore();
|
||||
|
||||
uint32_t ReadRegister(uint32_t Register) override;
|
||||
void WriteRegister(uint32_t Register, uint32_t Data) override;
|
||||
|
||||
uint32_t ReadIO(size_t Base, uint32_t Register) override;
|
||||
void WriteIO(size_t Base, uint32_t Register, uint32_t Data) override;
|
||||
|
||||
// Send a specified interrupt to another core.
|
||||
void SendInterCoreInterrupt(int Core, uint32_t Interrupt);
|
||||
// Tell the APIC that the interrupt is acknowledged. EOI = End Of Interrupt.
|
||||
void SendEOI();
|
||||
|
||||
// Tell the APIC that the specified IRQ should come to this core.
|
||||
void Set(int Core, uint8_t IRQ, int status);
|
||||
|
||||
// Write data into an inter-core interrupt.
|
||||
void WriteICI(size_t Data);
|
||||
|
||||
// Check what the maximum allowed interrupt redirect is.
|
||||
uint32_t GetMaxRedirect(uint32_t APIC);
|
||||
|
||||
};
|
||||
};
|
|
@ -4,6 +4,8 @@
|
|||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -11,8 +13,10 @@ extern "C" {
|
|||
/*
|
||||
;* Memory map
|
||||
;* 0h - 600h reserved for the system
|
||||
* V----------- CAN REMOVE -----------V
|
||||
;* 600h - 800h stage1 (MBR/VBR, boot.bin)
|
||||
;* 800h - 6C00h stage2 (this)
|
||||
* ∧----------- CAN REMOVE -----------∧
|
||||
;* 6C00h - 7C00h stack (7000h - 700Fh SMP trampoline code)
|
||||
;* 8000h - 9000h bootboot structure
|
||||
;* 9000h - A000h environment
|
||||
|
@ -111,7 +115,7 @@ typedef struct {
|
|||
uint8_t protocol; /* 1, static addresses, see PROTOCOL_* and LOADER_* above */
|
||||
uint8_t fb_type; /* framebuffer type, see FB_* above */
|
||||
uint16_t numcores; /* number of processor cores */
|
||||
uint16_t bspid; /* Bootsrap processor ID (Local APIC Id on x86_64) */
|
||||
uint16_t bspid; /* Bootstrap processor ID (Local APIC Id on x86_64) */
|
||||
int16_t timezone; /* in minutes -1440..1440 */
|
||||
uint8_t datetime[8]; /* in BCD yyyymmddhhiiss UTC (independent to timezone) */
|
||||
uint64_t initrd_ptr; /* ramdisk image position and size */
|
||||
|
|
|
@ -24,7 +24,10 @@ extern "C" {
|
|||
#include <kernel/system/io.h>
|
||||
#include <kernel/system/memory.h>
|
||||
#include <kernel/system/pci.h>
|
||||
#include <kernel/system/stack.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <kernel/system/core.hpp>
|
||||
#endif
|
||||
|
||||
#include <lainlib/lainlib.h>
|
||||
#include <lainlib/ethernet/e1000/e1000.h>
|
||||
|
|
15
inc/kernel/constants.hpp
Normal file
15
inc/kernel/constants.hpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2021 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
namespace Constants {
|
||||
namespace Core {
|
||||
const size_t STACK_SIZE = 65536;
|
||||
const size_t MAX_CORES = 12;
|
||||
}
|
||||
}
|
104
inc/kernel/system/acpi/madt.h
Normal file
104
inc/kernel/system/acpi/madt.h
Normal file
|
@ -0,0 +1,104 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <kernel/system/acpi/rsdt.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2021 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
namespace ACPI {
|
||||
|
||||
// Multiple APIC Descriptor Table. Enumerates every available APIC.
|
||||
class MADT {
|
||||
private:
|
||||
void* Address = 0;
|
||||
|
||||
public:
|
||||
|
||||
// The type of a table entry.
|
||||
enum Type {
|
||||
LAPIC = 0,
|
||||
IOAPIC = 1,
|
||||
ISO = 2,
|
||||
NMI = 4,
|
||||
LAPIC_OVERRIDE = 5
|
||||
};
|
||||
|
||||
// The header to a MADT Table Entry.
|
||||
struct RecordTableEntry {
|
||||
uint8_t Type; // The Type Enum value that represents this entry.
|
||||
uint8_t Length; // The length in bytes of this entry.
|
||||
} __attribute__((packed));
|
||||
|
||||
// The data of a Local APIC table Entry.
|
||||
struct LAPICEntry {
|
||||
RecordTableEntry Header;
|
||||
uint8_t Core; // The Core ID where the Local APIC is stored
|
||||
uint8_t APIC; // The ID of the APIC for the above Core ID.
|
||||
uint32_t Flags; // Capability flags for the APIC.
|
||||
} __attribute__((packed));
|
||||
|
||||
// The data of an IO (global) APIC table entry.
|
||||
struct IOAPICEntry {
|
||||
RecordTableEntry Header;
|
||||
uint8_t APIC; // The ID of the global APIC.
|
||||
uint8_t Unused;
|
||||
uint32_t Address; // The Base address of the MMIO port of the APIC.
|
||||
uint32_t GSI; // Global System Interrupt number.
|
||||
} __attribute__((packed));
|
||||
|
||||
// The data of an Interrupt Source Override entry - allows interrupt redirection.
|
||||
struct ISOEntry {
|
||||
RecordTableEntry Header;
|
||||
uint8_t Bus;
|
||||
uint8_t IRQ;
|
||||
uint32_t Interrupt;
|
||||
uint16_t Flags;
|
||||
} __attribute__((packed));
|
||||
|
||||
// The data of a Non-Maskable Interrupt source entry.
|
||||
struct NMIEntry {
|
||||
RecordTableEntry Header;
|
||||
uint8_t Core;
|
||||
uint16_t Flags;
|
||||
uint8_t LocalInterrupt;
|
||||
} __attribute__((packed));
|
||||
|
||||
// The data of a Local APIC Override Entry.
|
||||
struct LocalOverrideEntry {
|
||||
RecordTableEntry Header;
|
||||
uint8_t Reserved;
|
||||
size_t Address; // The 64 bit address of the Local APIC.
|
||||
} __attribute__((packed));
|
||||
|
||||
struct MADTHeader {
|
||||
ACPIHeader Header;
|
||||
uint32_t LocalAPIC;
|
||||
uint32_t Flags;
|
||||
RecordTableEntry Table[];
|
||||
} __attribute__((packed));
|
||||
|
||||
/***************************************
|
||||
***************************************
|
||||
***************************************/
|
||||
|
||||
static MADT* instance;
|
||||
MADTHeader* Header = 0;
|
||||
size_t LocalAPICBase = 0;
|
||||
|
||||
MADT();
|
||||
|
||||
void LogDump();
|
||||
void Initialize();
|
||||
// Get the byte of the end of the table.
|
||||
size_t GetEndOfTable();
|
||||
// Get all of the entries in the table, as an array.
|
||||
RecordTableEntry* GetTableEntries();
|
||||
// Get an array of pointers to IOAPIC entries. Should only be one.
|
||||
IOAPICEntry** GetIOApicEntries();
|
||||
// Get an array of pointers to ISO entries.
|
||||
ISOEntry** GetISOEntries();
|
||||
|
||||
};
|
||||
}
|
77
inc/kernel/system/acpi/rsdt.h
Normal file
77
inc/kernel/system/acpi/rsdt.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2021 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
namespace ACPI {
|
||||
|
||||
// The header of all System Descriptor Tables in the ACPI system.
|
||||
struct ACPIHeader {
|
||||
char Signature[4];
|
||||
uint32_t Length;
|
||||
uint8_t Revision;
|
||||
uint8_t Checksum;
|
||||
char OEMID[6];
|
||||
char OEMTableID[8];
|
||||
uint32_t OEMRevision;
|
||||
uint32_t CreatorID;
|
||||
uint32_t CreatorRevision;
|
||||
} __attribute__((packed));
|
||||
|
||||
// Root System Description Pointer table container.
|
||||
class RSDP {
|
||||
public:
|
||||
|
||||
// Header of RSDP Version 1 entries.
|
||||
struct DescriptorV1 {
|
||||
char Signature[8];
|
||||
uint8_t Checksum;
|
||||
char OEM[6];
|
||||
uint8_t Revision;
|
||||
uint32_t RSDT;
|
||||
} __attribute__((packed));
|
||||
|
||||
// Header of RSDP Version 2 entries.
|
||||
struct DescriptorV2 {
|
||||
DescriptorV1 Header;
|
||||
uint32_t Length;
|
||||
size_t XSDT;
|
||||
uint8_t Checksum;
|
||||
uint8_t Reserved[3];
|
||||
} __attribute__((packed));
|
||||
|
||||
// RSDP Entries themselves.
|
||||
struct RSDT {
|
||||
ACPIHeader Header;
|
||||
uint32_t* OtherSDTs;
|
||||
} __attribute__((packed));
|
||||
|
||||
RSDP();
|
||||
static RSDP* instance;
|
||||
|
||||
// Find the RSDP pointer in memory.
|
||||
void* GetRSDP();
|
||||
// Find the Fixed ACPI Descriptor (FADT) in memory.
|
||||
void* GetFACP(RSDT* Root);
|
||||
// Prepare virtual mapping of the RSDT
|
||||
void PagingInit();
|
||||
|
||||
// Prepare the RSDT for reading.
|
||||
__attribute__((unused)) void Init(size_t RSDP);
|
||||
|
||||
// Find the table with the specified name.
|
||||
void* FindEntry(const char* Name);
|
||||
|
||||
// Dump all available information to the system log.
|
||||
void LogDump();
|
||||
|
||||
private:
|
||||
size_t Version = 0;
|
||||
DescriptorV2* Descriptor;
|
||||
RSDT* Table;
|
||||
};
|
||||
}
|
80
inc/kernel/system/core.hpp
Normal file
80
inc/kernel/system/core.hpp
Normal file
|
@ -0,0 +1,80 @@
|
|||
#pragma once
|
||||
|
||||
#include <kernel/constants.hpp>
|
||||
#include <kernel/system/descriptors.h>
|
||||
#include <kernel/system/memory.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2021 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
/**
|
||||
* The relevant information contained within a stack trace - each call consists of the
|
||||
* contained information. By navigating the RBP until the base is found, a full backwards call stack can be determined.
|
||||
*/
|
||||
struct StackFrame {
|
||||
StackFrame* rbp;
|
||||
size_t rip;
|
||||
};
|
||||
|
||||
/**
|
||||
* Contains the definitions required to define and manage a single physical processing core.
|
||||
* These include; active GDT and IDT, TSS segments, saved stacks for execution and syscalls.
|
||||
* There are some utility functions for saving and loading extended registers, as well as
|
||||
* for identifying individual Cores in a running system.
|
||||
*
|
||||
*/
|
||||
class Core {
|
||||
public:
|
||||
Core() {}
|
||||
Core(size_t LAPIC, size_t ID);
|
||||
|
||||
size_t ID;
|
||||
size_t LocalAPIC;
|
||||
|
||||
address_space_t* AddressSpace;
|
||||
|
||||
uint8_t* SyscallStack;
|
||||
size_t StackAddress;
|
||||
uint8_t StackData[Constants::Core::STACK_SIZE];
|
||||
|
||||
IDT CoreIDT;
|
||||
GDT CoreGDT;
|
||||
TSS64 CoreTSS;
|
||||
|
||||
void LoadExtraRegisters(uint8_t* Data);
|
||||
void SaveExtraRegisters(uint8_t* Data);
|
||||
|
||||
void StackTrace(size_t Cycles);
|
||||
|
||||
static Core* GetCurrent() {
|
||||
size_t CoreID = 0;
|
||||
__asm__ __volatile__("mov %0, %%fs\n" : "=r"(CoreID) : :);
|
||||
return &Processors[CoreID];
|
||||
}
|
||||
|
||||
static Core* GetCore(int ID) { return &Processors[ID]; }
|
||||
|
||||
static void Init();
|
||||
|
||||
private:
|
||||
static Core Processors[];
|
||||
|
||||
// Initialization vectors for all new cores.
|
||||
// Numbers derived from boot.h space.
|
||||
// Specifically, the bootloader ROM.
|
||||
enum Initialization {
|
||||
PAGETABLES = 0x600,
|
||||
STARTUP = 0x620,
|
||||
STACK = 0x670,
|
||||
GDT = 0x680,
|
||||
IDT = 0x690
|
||||
};
|
||||
|
||||
void Bootstrap();
|
||||
void SetupData(size_t ID);
|
||||
|
||||
} __attribute__((packed));
|
|
@ -77,6 +77,16 @@ typedef struct __attribute__((packed)) {
|
|||
uint16_t IOMap;
|
||||
} TSS64;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint16_t Length;
|
||||
size_t Address;
|
||||
} GDT;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint16_t Length;
|
||||
size_t Address;
|
||||
} IDT;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
|
@ -37,9 +37,9 @@ extern IRQHandler IRQ_Handlers[16];
|
|||
|
||||
void InstallIRQ(int IRQ, void (*Handler)(INTERRUPT_FRAME* Frame));
|
||||
|
||||
void IRQ_Common(INTERRUPT_FRAME* Frame, size_t Interupt);
|
||||
void ISR_Common(INTERRUPT_FRAME* Frame, size_t Interrupt);
|
||||
void ISR_Error_Common(INTERRUPT_FRAME* Frame, size_t ErrorCode, size_t Exception);
|
||||
__attribute__((no_caller_saved_registers)) void IRQ_Common(INTERRUPT_FRAME* Frame, size_t Interupt);
|
||||
__attribute__((no_caller_saved_registers)) void ISR_Common(INTERRUPT_FRAME* Frame, size_t Interrupt);
|
||||
__attribute__((no_caller_saved_registers)) void ISR_Error_Common(INTERRUPT_FRAME* Frame, size_t ErrorCode, size_t Exception);
|
||||
|
||||
void RemapIRQControllers();
|
||||
|
||||
|
|
|
@ -132,6 +132,8 @@ extern "C" {
|
|||
#define STACK_TOP 0xFFFFFFFFFFFFF000ull // The start of the highest stack
|
||||
#define MEM_CEILING 0xFFFFFFFFFFFFFFFFull // The top of the stack in the map
|
||||
|
||||
#define CORE_BOOTSTRAP 0x0000000000001000ull // The physical location of the core bootstrapping function.
|
||||
|
||||
#define USER_REGION 0x00007FFFFFFFFFFFull // Not needed yet, but we're higher half so we might as well be thorough
|
||||
|
||||
#define KERNEL_STACK_REGION 0xFFFFE00000000000ull // Kernel Stack Space
|
||||
|
|
|
@ -16,6 +16,8 @@ extern "C" {
|
|||
* required to compatibly access the PCI bus,
|
||||
* as well as set up new PCI devices, PCI bridges, and manipulate
|
||||
* the connections of PCI lanes.
|
||||
*
|
||||
* TODO: Refactor for consistent naming style
|
||||
*/
|
||||
|
||||
#define PCI_CONFIG_ADDRESS 0xCF8
|
||||
|
|
|
@ -77,7 +77,7 @@ class Process {
|
|||
|
||||
size_t UniquePID; // Globally Unique ID.
|
||||
size_t KernelPID; // If in kernel space, the PID.
|
||||
size_t ParentPID; // If this process was forked, the parent's PID.
|
||||
size_t ParentPID; // If this process was forked, the parent's PID. Otherwise, the kernel.
|
||||
|
||||
char Name[128];
|
||||
size_t Entry; // The entry point. Move execution here to start the process.
|
||||
|
@ -104,7 +104,8 @@ class Process {
|
|||
};
|
||||
|
||||
Process(const char* ProcessName, size_t KPID, size_t UPID, size_t EntryPoint, bool Userspace)
|
||||
: UniquePID(UPID), KernelPID(KPID), Entry(EntryPoint), ORS(false), LastMessage(0), User(Userspace), Sleeping(0) {
|
||||
: User(Userspace), UniquePID(UPID), KernelPID(KPID), Entry(EntryPoint), ORS(false), Sleeping(0),
|
||||
LastMessage(0) {
|
||||
|
||||
memcpy((void*) ProcessName, Name, strlen(Name) + 1);
|
||||
};
|
||||
|
@ -136,6 +137,7 @@ class Process {
|
|||
}
|
||||
|
||||
size_t* AllocateProcessSpace(size_t Bytes);
|
||||
|
||||
size_t FreeProcessSpace(size_t* Address, size_t Bytes);
|
||||
|
||||
bool OwnsAddress(size_t* Address, size_t Bytes);
|
||||
|
@ -158,6 +160,7 @@ class Process {
|
|||
void SetCore(size_t CoreID) { Core = CoreID; };
|
||||
|
||||
void IncreaseSleep(size_t Interval) { Sleeping += Interval; };
|
||||
|
||||
void DecreaseSleep(size_t Interval) { Sleeping -= Interval; };
|
||||
|
||||
/*************************************************************/
|
||||
|
@ -167,6 +170,7 @@ class Process {
|
|||
const char* GetName() const { return Name; };
|
||||
|
||||
size_t GetPID() const { return UniquePID; };
|
||||
|
||||
size_t GetKPID() const { return KernelPID; };
|
||||
|
||||
size_t GetParent() const { return ParentPID; };
|
||||
|
@ -175,7 +179,9 @@ class Process {
|
|||
|
||||
bool IsValid() const { return KernelPID != 0; };
|
||||
|
||||
bool IsUsed() const { return (State != ProcessState::PROCESS_AVAILABLE && State != ProcessState::PROCESS_CRASH && State != ProcessState::PROCESS_REAP) && IsValid(); };
|
||||
bool IsUsed() const { return (State != ProcessState::PROCESS_AVAILABLE && State != ProcessState::PROCESS_CRASH &&
|
||||
State != ProcessState::PROCESS_REAP) && IsValid();
|
||||
};
|
||||
|
||||
bool IsSleeping() const { return Sleeping; };
|
||||
|
||||
|
@ -190,13 +196,16 @@ class Process {
|
|||
size_t GetCore() const { return Core; };
|
||||
|
||||
bool IsUserspace() { return User; };
|
||||
|
||||
bool IsSystem() { return System; };
|
||||
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
static Process* FromName(const char* name);
|
||||
|
||||
static Process* FromPID(size_t PID);
|
||||
|
||||
static Process* Current();
|
||||
|
||||
static void SetCurrent(Process* Target);
|
||||
|
@ -216,22 +225,29 @@ class ProcessManagement {
|
|||
uint32_t CoreCount = 1;
|
||||
|
||||
ProcessManagement();
|
||||
|
||||
static ProcessManagement* instance();
|
||||
|
||||
void Wait();
|
||||
|
||||
void Initialize();
|
||||
|
||||
void InitialiseCore(size_t APIC, size_t ID);
|
||||
|
||||
void NotifyAllCores();
|
||||
|
||||
void DumpProcess(size_t PID);
|
||||
|
||||
void LockProcess(size_t PID);
|
||||
|
||||
void UnlockProcess(size_t PID);
|
||||
|
||||
static void Sleep(size_t Count);
|
||||
|
||||
void Sleep(size_t Count, size_t PID);
|
||||
|
||||
static void Kill(int Code);
|
||||
|
||||
void Kill(size_t PID, int Code);
|
||||
|
||||
bool CheckLocked(size_t PID);
|
||||
|
@ -240,10 +256,15 @@ class ProcessManagement {
|
|||
|
||||
// TODO: Process*
|
||||
size_t SwitchContext(INTERRUPT_FRAME* CurrentFrame);
|
||||
|
||||
void MapThreadMemory(size_t from, size_t to, size_t length);
|
||||
|
||||
void InitProcess(function_t EntryPoint, size_t argc, char** argv);
|
||||
|
||||
void InitKernelProcess(function_t EntryPoint);
|
||||
|
||||
void InitProcessPagetable(bool Userspace);
|
||||
|
||||
void InitProcessArch();
|
||||
|
||||
size_t HandleRequest(size_t CPU);
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
typedef struct stackframe {
|
||||
struct stackframe* rbp;
|
||||
size_t rip;
|
||||
} stackframe_t;
|
||||
|
||||
void StackTrace(size_t cycles);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -43,7 +43,7 @@ typedef struct {
|
|||
extern PRINTINFO PrintInfo;
|
||||
|
||||
void DrawPixel(size_t x, size_t y);
|
||||
void FillScreen();
|
||||
void FillScreen(uint32_t color);
|
||||
|
||||
void SetForegroundColor(uint32_t color);
|
||||
uint32_t GetForegroundColor();
|
||||
|
|
|
@ -30,7 +30,8 @@ void Device::RegisterDevice(Device::GenericDevice* Device) {
|
|||
DevicesArray[CurrentDevice] = Device;
|
||||
Device->DeviceID = CurrentDevice;
|
||||
CurrentDevice++;
|
||||
SerialPrintf("[DEVICE] Registered device %d called %s of type %s\r\n", CurrentDevice - 1, Device->GetName(), DeviceNames[Device->GetType()]);
|
||||
SerialPrintf("[DEVICE] Registered device %d called %s of type %s\r\n", CurrentDevice - 1, Device->GetName(),
|
||||
DeviceNames[Device->GetType()]);
|
||||
}
|
||||
|
||||
// Retrieve a device pointer from the managed list.
|
||||
|
|
|
@ -122,9 +122,9 @@ void UpdateKeyboard(uint8_t msg) {
|
|||
}
|
||||
|
||||
KeyboardData data = (KeyboardData) {
|
||||
.Scancode = msg,
|
||||
.Pressed = msg > 0x80 && msg < 0xD8 ? false : true,
|
||||
.Char = msg > 0x80 && msg < 0xD8 ? keys[msg - 0x80] : keys[msg]
|
||||
.Char = msg > 0x80 && msg < 0xD8 ? keys[msg - 0x80] : keys[msg],
|
||||
.Scancode = static_cast<char>(msg),
|
||||
.Pressed = !(msg > 0x80 && msg < 0xD8),
|
||||
};
|
||||
|
||||
void (* Handler)(KeyboardData data);
|
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,7 +22,8 @@ extern size_t KernelLocation;
|
|||
int ParseKernelHeader(size_t InitrdPtr) {
|
||||
int flag = 0;
|
||||
|
||||
SerialPrintf("[ boot] Searching for kernel... Constants start at 0x%p / 0x%p\r\n", ((size_t) (&_kernel_text_start) - KernelAddr) + InitrdPtr, (size_t) (&_kernel_text_start));
|
||||
SerialPrintf("[ boot] Searching for kernel... Constants start at 0x%p / 0x%p\r\n",
|
||||
((size_t) (&_kernel_text_start) - KernelAddr) + InitrdPtr, (size_t) (&_kernel_text_start));
|
||||
// We stop at the constants in the kernel, otherwise we'll read the constant ELF64MAGIC which is stored inside the kernel...
|
||||
|
||||
size_t headerLoc = 0;
|
||||
|
@ -47,7 +48,8 @@ int ParseKernelHeader(size_t InitrdPtr) {
|
|||
uint16_t EntryPoint1 = FIXENDIAN16(*((volatile uint16_t*) (headerLoc + ELFENTRY_OFF + 2)));
|
||||
uint16_t EntryPoint2 = FIXENDIAN16(*((volatile uint16_t*) (headerLoc + ELFENTRY_OFF + 4)));
|
||||
uint16_t EntryPoint3 = FIXENDIAN16(*((volatile uint16_t*) (headerLoc + ELFENTRY_OFF + 6)));
|
||||
size_t EntryPoint = ((size_t) EntryPoint0 << 48) | ((size_t) EntryPoint1 << 32) | ((size_t) EntryPoint2 << 16) | ((size_t) EntryPoint3);
|
||||
size_t EntryPoint = ((size_t) EntryPoint0 << 48) | ((size_t) EntryPoint1 << 32) | ((size_t) EntryPoint2 << 16) |
|
||||
((size_t) EntryPoint3);
|
||||
|
||||
/* At this point, EntryPoint is a little-endian 64 bit integer. That means we have to fix its endianness in order to read it */
|
||||
SerialPrintf("[ boot] Fixing entry point from 0x%p to 0x%p\r\n", EntryPoint, FIXENDIAN64(EntryPoint));
|
||||
|
@ -71,8 +73,6 @@ int ParseKernelHeader(size_t InitrdPtr) {
|
|||
FIXENDIAN16(MachineType));
|
||||
|
||||
|
||||
|
||||
|
||||
if (EntryPoint == (size_t) (&_kernel_text_start)) {
|
||||
SerialPrintf("[ boot] Header at 0x%p matches kernel header.\r\n", headerLoc);
|
||||
flag = 1;
|
|
@ -28,7 +28,7 @@ void Editor::StartEditor(int callbackID) {
|
|||
layout.TextBoxX = (layout.ScreenWidth - layout.TextBoxWidth) / 2;
|
||||
|
||||
SetForegroundColor(0x000084);
|
||||
FillScreen();
|
||||
FillScreen(0x000084);
|
||||
|
||||
SetForegroundColor(0x00BBBBBB);
|
||||
DrawFilledRect(0, 0, PrintInfo.screenWidth, layout.HeaderHeight);
|
||||
|
|
138
src/global/core.s
Normal file
138
src/global/core.s
Normal file
|
@ -0,0 +1,138 @@
|
|||
;************************
|
||||
;*** Team Kitty, 2021 ***
|
||||
;*** Chroma ***
|
||||
;************************
|
||||
|
||||
; Initial startup routines for new cores.
|
||||
; New cores start in 16 bit real mode.
|
||||
; Because of this, this is the only necessary assembler file in the OS.
|
||||
|
||||
; First, bring them up to Protected and Long mode.
|
||||
; Then enable all necessary auxiliary features.
|
||||
; Pass off to the CPP code to handle the heavy work, we just want the core running.
|
||||
|
||||
[bits 16]
|
||||
BASE equ 0x1000
|
||||
|
||||
global stack
|
||||
extern initcpu
|
||||
|
||||
extern coreidt
|
||||
extern coregdt
|
||||
|
||||
global startCore
|
||||
startCore:
|
||||
cli
|
||||
mov ax, 0x0
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
mov ss, ax
|
||||
|
||||
o32 lgdt [gdt_protected - startCore + BASE]
|
||||
|
||||
mov eax, cr0
|
||||
or al, 0x1
|
||||
mov cr0, eax
|
||||
|
||||
jmp 0x8:(startCore32 - startCore + BASE)
|
||||
|
||||
[bits 32]
|
||||
|
||||
section .text
|
||||
startCore32:
|
||||
mov bx, 0x10
|
||||
mov ds, bx
|
||||
mov es, bx
|
||||
mov ss, bx
|
||||
|
||||
mov eax, dword [0xa000] ; Load bootloader tables into the new core
|
||||
mov cr3, eax
|
||||
|
||||
mov eax, cr4 ; Enable PAE
|
||||
or eax, 1 << 5
|
||||
or eax, 1 << 7
|
||||
mov cr4, eax
|
||||
|
||||
mov ecx, 0xc0000080
|
||||
rdmsr
|
||||
or eax, 1 << 8 ; Enable LME
|
||||
wrmsr
|
||||
|
||||
mov eax, cr0
|
||||
or eax, 1 << 31
|
||||
mov cr0, eax
|
||||
|
||||
lgdt [gdt_long - startCore + BASE]
|
||||
jmp 8:(startCore64 - startCore + BASE)
|
||||
|
||||
[bits 64]
|
||||
startCore64:
|
||||
mov ax, 0x10
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov ss, ax
|
||||
|
||||
mov ax, 0x0 ; These will contain core information later on
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
lgdt [coregdt]
|
||||
lidt [coreidt]
|
||||
|
||||
mov rbp, 0
|
||||
push 0
|
||||
popf
|
||||
|
||||
mov rax, qword leave
|
||||
jmp leave
|
||||
|
||||
leave:
|
||||
push rbp
|
||||
mov rax, cr0
|
||||
btr eax, 2
|
||||
bts eax, 1
|
||||
mov cr0, rax
|
||||
|
||||
mov rax, cr4
|
||||
bts eax, 9
|
||||
bts eax, 10
|
||||
mov cr4, rax
|
||||
|
||||
call initcpu
|
||||
|
||||
|
||||
align 16
|
||||
gdt_long:
|
||||
dw gdt_long_end - gdt_long_start - 1 ; gdt length
|
||||
dq gdt_long_start - startCore + BASE ; address of the gdt
|
||||
|
||||
align 16
|
||||
gdt_long_start:
|
||||
dq 0
|
||||
dq 0x00AF98000000FFFF
|
||||
dq 0x00CF92000000FFFF
|
||||
gdt_long_end:
|
||||
|
||||
align 16
|
||||
gdt_protected:
|
||||
dw gdt_protected_end - gdt_protected_start - 1 ; gdt length
|
||||
dd gdt_protected_start - startCore + BASE ; address of the gdt
|
||||
|
||||
align 16
|
||||
gdt_protected_start:
|
||||
dq 0
|
||||
dq 0x00CF9A000000FFFF
|
||||
dq 0x00CF92000000FFFF
|
||||
gdt_protected_end:
|
||||
|
||||
align 16
|
||||
idt_protected:
|
||||
dw 0
|
||||
dd 0
|
||||
dd 0
|
||||
align 16
|
||||
|
||||
global endCore
|
||||
endCore:
|
|
@ -36,26 +36,32 @@ char* InternalBuffer;
|
|||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* C++ code! Scary!
|
||||
* This is a temporary measure to experiment with the Editor system.
|
||||
*/
|
||||
|
||||
int Main(void) {
|
||||
extern "C" int Main(void) {
|
||||
KernelAddressSpace.Lock.NextTicket = 0;
|
||||
KernelAddressSpace.Lock.NowServing = 0;
|
||||
KernelAddressSpace.PML4 = nullptr;
|
||||
|
||||
SerialPrintf("\r\n[ boot] Booting Chroma..\r\n");
|
||||
SerialPrintf("[ boot] Bootloader data structure at 0x%p\r\n", (size_t) &bootldr);
|
||||
SerialPrintf("[ boot] Kernel loaded at 0x%p, ends at 0x%p, is %d bytes long.\r\n", KernelAddr, KernelEnd, KernelEnd - KernelAddr);
|
||||
SerialPrintf("[ boot] Framebuffer at 0x%p / 0x%p, is %dx%d, 0x%x bytes long.\r\n", bootldr.fb_ptr, (size_t) &fb, bootldr.fb_width, bootldr.fb_height, bootldr.fb_size);
|
||||
SerialPrintf("[ boot] Initrd is physically at 0x%p, and is %d bytes long.\r\n", bootldr.initrd_ptr, bootldr.initrd_size);
|
||||
SerialPrintf("[ boot] Kernel loaded at 0x%p, ends at 0x%p, is %d bytes long.\r\n", KernelAddr, KernelEnd,
|
||||
KernelEnd - KernelAddr);
|
||||
SerialPrintf("[ boot] Framebuffer at 0x%p / 0x%p, is %dx%d, 0x%x bytes long.\r\n", bootldr.fb_ptr, (size_t) &fb,
|
||||
bootldr.fb_width, bootldr.fb_height, bootldr.fb_size);
|
||||
SerialPrintf("[ boot] Initrd is physically at 0x%p, and is %d bytes long.\r\n", bootldr.initrd_ptr,
|
||||
bootldr.initrd_size);
|
||||
SerialPrintf("[ boot] Initrd's header is 0x%p\r\n", FIXENDIAN32(*((volatile uint32_t*) (bootldr.initrd_ptr))));
|
||||
|
||||
ParseKernelHeader(bootldr.initrd_ptr);
|
||||
|
||||
SerialPrintf("[ boot] The bootloader has put the paging tables at 0x%p.\r\n", ReadControlRegister(3));
|
||||
SerialPrintf("[ boot] Removing bootloader code.\r\n");
|
||||
memset((void*) 0x600, 0, 0x6600);
|
||||
|
||||
ListMemoryMap();
|
||||
|
||||
|
@ -89,7 +95,7 @@ int Main(void) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void PrintPressedChar(KeyboardData data) {
|
||||
extern "C" void PrintPressedChar(KeyboardData data) {
|
||||
if (!KernelLoaded) return;
|
||||
|
||||
if (data.Pressed) {
|
||||
|
@ -100,7 +106,7 @@ void PrintPressedChar(KeyboardData data) {
|
|||
}
|
||||
}
|
||||
|
||||
void TrackInternalBuffer(KeyboardData data) {
|
||||
extern "C" void TrackInternalBuffer(KeyboardData data) {
|
||||
if (!data.Pressed) return;
|
||||
|
||||
bool tentative = false;
|
||||
|
@ -135,11 +141,14 @@ void TrackInternalBuffer(KeyboardData data) {
|
|||
}
|
||||
}
|
||||
|
||||
void SomethingWentWrong(const char* Message) {
|
||||
|
||||
extern "C" void SomethingWentWrong(const char* Message) {
|
||||
SerialPrintf("Assertion failed! %s\r\n", Message);
|
||||
//for(;;){}
|
||||
for(;;){}
|
||||
}
|
||||
|
||||
void Exit(int ExitCode) {
|
||||
extern "C" void __cxa_pure_virtual() { SomethingWentWrong("Pure Virtual Method Called"); }
|
||||
|
||||
extern "C" void Exit(int ExitCode) {
|
||||
SerialPrintf("Kernel stopped with code %x\r\n", ExitCode);
|
||||
}
|
|
@ -22,8 +22,8 @@ void ListRemove(list_entry_t* Entry) {
|
|||
Entry->Next->Previous = Entry->Previous;
|
||||
Entry->Previous->Next = Entry->Next;
|
||||
|
||||
Entry->Previous = (void*)0xDEADull;
|
||||
Entry->Next = (void*)0xBEEFull;
|
||||
Entry->Previous = static_cast<list_entry*>((void*) 0xDEADull);
|
||||
Entry->Next = static_cast<list_entry*>((void*) 0xBEEFull);
|
||||
}
|
||||
|
||||
bool ListIsEmpty(list_entry_t* Head) {
|
74
src/system/acpi/MADT.cpp
Normal file
74
src/system/acpi/MADT.cpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
#include <kernel/system/acpi/madt.h>
|
||||
#include <kernel/chroma.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2021 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
using namespace ACPI;
|
||||
|
||||
ACPI::MADT* MADT::instance;
|
||||
|
||||
MADT::MADT() {
|
||||
instance = this;
|
||||
}
|
||||
|
||||
size_t MADT::GetEndOfTable() {
|
||||
return ((size_t) &Header->Header) + Header->Header.Length;
|
||||
}
|
||||
|
||||
void MADT::Initialize() {
|
||||
SerialPrintf("[ACPI] Loading Multiple APIC Descriptor Tables..");
|
||||
Address = ACPI::RSDP::instance->FindEntry("APIC");
|
||||
Header = reinterpret_cast<MADTHeader*>(Address);
|
||||
|
||||
LocalAPICBase = Header->LocalAPIC;
|
||||
|
||||
// TODO: Check whether the Base is identity mapped
|
||||
}
|
||||
|
||||
MADT::IOAPICEntry** MADT::GetIOApicEntries() {
|
||||
MADT::RecordTableEntry* table;
|
||||
table = Header->Table;
|
||||
auto** entries = (MADT::IOAPICEntry**) kmalloc(255);
|
||||
|
||||
size_t count = 0;
|
||||
|
||||
while ((size_t) table < GetEndOfTable()) {
|
||||
table = (MADT::RecordTableEntry*) (((size_t) table) + table->Length);
|
||||
|
||||
if (table->Type == MADT::Type::IOAPIC) {
|
||||
MADT::IOAPICEntry* io_apic = reinterpret_cast<MADT::IOAPICEntry*>(table);
|
||||
entries[count] = (MADT::IOAPICEntry*) ((size_t) io_apic);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
entries[count] = 0;
|
||||
return entries;
|
||||
}
|
||||
|
||||
MADT::ISOEntry** MADT::GetISOEntries() {
|
||||
MADT::RecordTableEntry* table = Header->Table;
|
||||
auto** entries = (MADT::ISOEntry**) kmalloc(255);
|
||||
|
||||
size_t count = 0;
|
||||
|
||||
while ((size_t) table < GetEndOfTable()) {
|
||||
table = (MADT::RecordTableEntry*) (((size_t) table) + table->Length);
|
||||
|
||||
if (table->Type == MADT::Type::ISO) {
|
||||
MADT::ISOEntry* io_apic = reinterpret_cast<MADT::ISOEntry*>(table);
|
||||
entries[count] = (MADT::ISOEntry*) ((size_t) io_apic);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
entries[count] = 0;
|
||||
return entries;
|
||||
}
|
||||
|
||||
MADT::RecordTableEntry* MADT::GetTableEntries() {
|
||||
return Header->Table;
|
||||
}
|
87
src/system/acpi/RSDP.cpp
Normal file
87
src/system/acpi/RSDP.cpp
Normal file
|
@ -0,0 +1,87 @@
|
|||
#include <kernel/system/acpi/rsdt.h>
|
||||
#include <kernel/chroma.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2021 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
using namespace ACPI;
|
||||
|
||||
ACPI::RSDP* RSDP::instance;
|
||||
|
||||
void* RSDP::GetRSDP() {
|
||||
|
||||
// Search physical memory (via the direct region) for the "RSD PTR " magic string.
|
||||
// TODO: this is extremely slow!
|
||||
for (size_t i = TO_DIRECT(0x80000); i < TO_DIRECT(0x100000); i += 16) {
|
||||
if (i == TO_DIRECT(0xA0000)) {
|
||||
i = TO_DIRECT(0xE0000 - 16);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp((char*) i, "RSD PTR ")) {
|
||||
return (void*) i;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RSDP::RSDP() {
|
||||
instance = this;
|
||||
Table = (RSDT*) 0;
|
||||
Descriptor = (DescriptorV2*) 0;
|
||||
}
|
||||
|
||||
void* RSDP::FindEntry(const char* Name) {
|
||||
// Take the pointer to the RSD Table from the Direct region.
|
||||
auto* table = reinterpret_cast<RSDP::RSDT*>(TO_DIRECT(Descriptor->Header.RSDT));
|
||||
size_t entries = (table->Header.Length - sizeof(table->Header)) / 4;
|
||||
|
||||
|
||||
// For each entry: if valid, search for the specified name.
|
||||
for (size_t i = 0; i < entries; i++) {
|
||||
if (table->OtherSDTs[i] == 0x0)
|
||||
continue;
|
||||
|
||||
ACPIHeader* header = reinterpret_cast<ACPIHeader*>(table->OtherSDTs[i]);
|
||||
|
||||
if (strcmp(header->Signature, Name))
|
||||
return (void*) header;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* RSDP::GetFACP(RSDT* Root) {
|
||||
UNUSED(Root);
|
||||
return FindEntry("FACP");
|
||||
}
|
||||
|
||||
void RSDP::Init(size_t RSDP) {
|
||||
UNUSED(RSDP);
|
||||
SerialPrintf("[ACPI] Loading ACPI subsystem..");
|
||||
|
||||
Descriptor = (DescriptorV2*) GetRSDP();
|
||||
Table = (RSDT *) TO_DIRECT(Descriptor->Header.RSDT);
|
||||
|
||||
SerialPrintf("[RSDP] Dumping RSDT..");
|
||||
auto* table = reinterpret_cast<RSDP::RSDT*>(TO_DIRECT(Descriptor->Header.RSDT));
|
||||
size_t entries = (table->Header.Length - sizeof(table->Header)) / 4;
|
||||
|
||||
|
||||
// For each entry: if valid, search for the specified name.
|
||||
for (size_t i = 0; i < entries; i++) {
|
||||
if (table->OtherSDTs[i] == 0x0)
|
||||
continue;
|
||||
|
||||
ACPIHeader* header = reinterpret_cast<ACPIHeader*>(table->OtherSDTs[i]);
|
||||
SerialPrintf("[RSDP] Entry %d: Signature %.4s, OEM %.6s\n", i, header->Signature, header->OEMID);
|
||||
}
|
||||
}
|
||||
|
||||
void RSDP::PagingInit() {
|
||||
// TODO: check whether the identity mapping makes this necessary.
|
||||
}
|
||||
|
134
src/system/core.cpp
Normal file
134
src/system/core.cpp
Normal file
|
@ -0,0 +1,134 @@
|
|||
#include <kernel/chroma.h>
|
||||
#include <kernel/system/acpi/madt.h>
|
||||
#include <driver/io/apic.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2021 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
extern size_t startCore;
|
||||
extern size_t endCore;
|
||||
|
||||
int Cores = 0;
|
||||
volatile bool Ready = false;
|
||||
|
||||
Core Core::Processors[Constants::Core::MAX_CORES];
|
||||
TSS64 Tasks[Constants::Core::MAX_CORES];
|
||||
ACPI::MADT::LAPICEntry* LAPICs[Constants::Core::MAX_CORES];
|
||||
|
||||
extern "C" void initcpu() {
|
||||
// Init APIC
|
||||
WriteModelSpecificRegister(0x1B, (ReadModelSpecificRegister(0x1B) | 0x800) & ~(1 << 10));
|
||||
Device::APIC::driver->Enable();
|
||||
|
||||
__asm__ __volatile__("mov %%fs, %0" : : "r" (Device::APIC::driver->GetCurrentCore()) : );
|
||||
|
||||
SerialPrintf("[CORE] Core %d ready.\r\n", Device::APIC::driver->GetCurrentCore());
|
||||
// TODO: New GDT
|
||||
__asm__ __volatile__("cli");
|
||||
Ready = true;
|
||||
__asm__ __volatile__("sti");
|
||||
|
||||
for (;;) { }
|
||||
}
|
||||
|
||||
Core::Core(size_t APIC, size_t ID) {
|
||||
Device::APIC::driver->PreinitializeCore(APIC);
|
||||
GetCore(ID)->LocalAPIC = APIC;
|
||||
|
||||
Bootstrap();
|
||||
SetupData(ID);
|
||||
|
||||
Device::APIC::driver->InitializeCore(APIC, CORE_BOOTSTRAP);
|
||||
|
||||
while (Ready != true) {
|
||||
__asm__ ("nop");
|
||||
}
|
||||
|
||||
Ready = false;
|
||||
}
|
||||
|
||||
void Core::Init() {
|
||||
using namespace ACPI;
|
||||
|
||||
Ready = false;
|
||||
SerialPrintf("[CORE] Enabling Multiprocessing\n");
|
||||
|
||||
memset(Tasks, 0, Constants::Core::MAX_CORES * sizeof(TSS64));
|
||||
for (size_t i = 0; i < Constants::Core::MAX_CORES; i++)
|
||||
LAPICs[i] = nullptr;
|
||||
|
||||
// Parse MADT for cores
|
||||
MADT::RecordTableEntry* table = MADT::instance->GetTableEntries();
|
||||
Cores = 0;
|
||||
|
||||
// While there are more entries in the table..
|
||||
while ((size_t) table < MADT::instance->GetEndOfTable()) {
|
||||
// Move to the next entry (by skipping the length of the current entry)
|
||||
table = (MADT::RecordTableEntry*) (((size_t) table) + table->Length);
|
||||
// Check for a LAPIC record (which indicates a unique physical core)
|
||||
if (table->Type == MADT::Type::LAPIC) {
|
||||
// Find the data for the LAPIC with a reinterpret
|
||||
MADT::LAPICEntry* lapic = reinterpret_cast<MADT::LAPICEntry*>(table);
|
||||
|
||||
// Set the current ID
|
||||
LAPICs[Cores] = lapic;
|
||||
// Tell the core that its' LAPIC is the current id
|
||||
Core::GetCore(Cores)->LocalAPIC = lapic->APIC;
|
||||
// Move to the next core if there is one.
|
||||
Cores++;
|
||||
}
|
||||
}
|
||||
|
||||
SerialPrintf("[CORE] Found %d cores.\n", Cores);
|
||||
|
||||
if (Cores > 1)
|
||||
SerialPrintf("[CORE] Bringing up other cores.\n");
|
||||
|
||||
// For each non-bootstrap core, initialize the necessary data and populate the array.
|
||||
for (int i = 0; i < Cores; i++) {
|
||||
SerialPrintf("[CORE] Enabling core %d.\n", i);
|
||||
if (Device::APIC::driver->GetCurrentCore() != LAPICs[i]->Core)
|
||||
Processors[i] = Core(LAPICs[i]->APIC, LAPICs[i]->Core);
|
||||
}
|
||||
}
|
||||
|
||||
void Core::Bootstrap() {
|
||||
size_t coreStarterLen = endCore - startCore;
|
||||
|
||||
for (size_t i = 0; i < coreStarterLen + 2; i += PAGE_SIZE)
|
||||
MapVirtualPage(AddressSpace, CORE_BOOTSTRAP + i, CORE_BOOTSTRAP + i, 0);
|
||||
|
||||
memcpy((void*) CORE_BOOTSTRAP, &startCore, coreStarterLen);
|
||||
}
|
||||
|
||||
void Core::SetupData(size_t Core) {
|
||||
// Write page tables
|
||||
GetCore(Core)->AddressSpace->PML4 = GetCurrent()->AddressSpace->PML4;
|
||||
*((size_t*) Initialization::PAGETABLES) = (size_t) GetCore(Core)->AddressSpace->PML4;
|
||||
|
||||
// Prepare stack
|
||||
memset(GetCore(Core)->StackData, 0, Constants::Core::STACK_SIZE);
|
||||
*((size_t*) Initialization::STACK) = (size_t) GetCore(Core)->StackData + Constants::Core::STACK_SIZE;
|
||||
|
||||
// GDT = 0x680
|
||||
// IDT = 0x690
|
||||
__asm__ __volatile__("sgdt (0x680)\n sidt (0x690)");
|
||||
|
||||
// Set startup address
|
||||
*((size_t*) Initialization::STARTUP) = (size_t) &initcpu;
|
||||
}
|
||||
|
||||
|
||||
void Core::StackTrace(size_t Cycles) {
|
||||
StackFrame* stack;
|
||||
|
||||
__asm__ __volatile__ ("mov %%rbp, %[dest]" : [dest] "=r"(stack) : :);
|
||||
SerialPrintf("[Trace] Beginning stack trace. RBP is currently 0x%p\r\n", stack);
|
||||
for (size_t frame = 0; stack != 0 && frame < Cycles; ++frame) {
|
||||
SerialPrintf("[Trace] (%d) 0x%p: 0x%p \r\n", frame, stack->rbp, stack->rip);
|
||||
stack = stack->rbp;
|
||||
}
|
||||
SerialPrintf("[Trace] Stack trace over.\r\n");
|
||||
}
|
|
@ -44,9 +44,9 @@ __attribute__((aligned(64))) static volatile size_t InitGDT[5] = {
|
|||
0
|
||||
};
|
||||
|
||||
__attribute__((aligned(64))) static volatile TSS64 TSSEntries = {0};
|
||||
__attribute__((aligned(64))) static volatile TSS64 TSSEntries;
|
||||
|
||||
__attribute__((aligned(64))) static volatile IDT_GATE IDTEntries[256] = {0};
|
||||
__attribute__((aligned(64))) static volatile IDT_GATE IDTEntries[256];
|
||||
|
||||
static void RefreshCS() {
|
||||
|
||||
|
@ -111,7 +111,7 @@ void PrepareCPU() {
|
|||
*/
|
||||
|
||||
void SetupInitialGDT() {
|
||||
DESC_TBL GDTData = {0};
|
||||
DESC_TBL GDTData;
|
||||
size_t TSSBase = (uint64_t) (&TSSEntries);
|
||||
|
||||
uint16_t TSSLower = (uint16_t) TSSBase;
|
||||
|
@ -203,7 +203,7 @@ static void SetISRBP(size_t ISRNum, size_t ISRAddr) {
|
|||
}
|
||||
|
||||
void SetupIDT() {
|
||||
DESC_TBL IDTData = {0};
|
||||
DESC_TBL IDTData;
|
||||
IDTData.Limit = (sizeof(IDT_GATE) * 256) - 1;
|
||||
IDTData.Base = (size_t) &IDTEntries;
|
||||
|
|
@ -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
|
|
@ -80,7 +80,6 @@ alloc_decl int Alloc_FindLastOne_64(size_t size) {
|
|||
#undef alloc_decl
|
||||
|
||||
|
||||
|
||||
/*********************************************
|
||||
* T Y P E D E F I N I T I O N S
|
||||
**********************************************/
|
||||
|
@ -331,12 +330,16 @@ static void RemoveFreeBlock(allocator_control_t* Controller, block_header_t* Blo
|
|||
}
|
||||
}
|
||||
|
||||
static void InsertFreeBlock(allocator_control_t* Controller, block_header_t* NewBlock, int FirstLevel, int SecondLevel) {
|
||||
static void
|
||||
InsertFreeBlock(allocator_control_t* Controller, block_header_t* NewBlock, int FirstLevel, int SecondLevel) {
|
||||
block_header_t* Current = Controller->Blocks[FirstLevel][SecondLevel];
|
||||
|
||||
ASSERT(Current, "InsertFreeBlock: Current Block is null!");
|
||||
if (!Current) {
|
||||
SerialPrintf("Extra info: \r\n\tFirst Level: %x Second Level: %x\r\nFirst Level bitmap: %x, Second Level bitmap: %x\r\n\tBlocks %x, BlocksAddress: %x", FirstLevel, SecondLevel, Controller->FirstLevel_Bitmap, Controller->SecondLevel_Bitmap, Controller->Blocks, Controller->Blocks[FirstLevel][SecondLevel]);
|
||||
SerialPrintf(
|
||||
"Extra info: \r\n\tFirst Level: %x Second Level: %x\r\nFirst Level bitmap: %x, Second Level bitmap: %x\r\n\tBlocks %x, BlocksAddress: %x",
|
||||
FirstLevel, SecondLevel, Controller->FirstLevel_Bitmap, Controller->SecondLevel_Bitmap,
|
||||
Controller->Blocks, Controller->Blocks[FirstLevel][SecondLevel]);
|
||||
for (;;) { }
|
||||
}
|
||||
ASSERT(NewBlock, "InsertFreeBlock: New Block is null!");
|
||||
|
@ -346,7 +349,8 @@ static void InsertFreeBlock(allocator_control_t* Controller, block_header_t* New
|
|||
|
||||
Current->LastFreeBlock = NewBlock;
|
||||
|
||||
ASSERT(WhereBlock(NewBlock) == AlignPointer(WhereBlock(NewBlock), ALIGN_SIZE), "InsertFreeBlock: Current block is not memory aligned!");
|
||||
ASSERT(WhereBlock(NewBlock) == AlignPointer(WhereBlock(NewBlock), ALIGN_SIZE),
|
||||
"InsertFreeBlock: Current block is not memory aligned!");
|
||||
|
||||
Controller->Blocks[FirstLevel][SecondLevel] = NewBlock;
|
||||
Controller->FirstLevel_Bitmap |= (1U << FirstLevel);
|
||||
|
@ -376,7 +380,8 @@ static block_header_t* SplitBlock(block_header_t* Block, size_t NewSize) {
|
|||
|
||||
const size_t RemainingSize = BlockSize(Block) - (NewSize + BLOCK_OVERHEAD);
|
||||
|
||||
ASSERT(WhereBlock(Overlap) == AlignPointer(WhereBlock(Overlap), ALIGN_SIZE), "SplitBlock: Requested size results in intermediary block which is not aligned!");
|
||||
ASSERT(WhereBlock(Overlap) == AlignPointer(WhereBlock(Overlap), ALIGN_SIZE),
|
||||
"SplitBlock: Requested size results in intermediary block which is not aligned!");
|
||||
|
||||
ASSERT(BlockSize(Block) == RemainingSize + NewSize + BLOCK_OVERHEAD, "SplitBlock: Maths error!");
|
||||
|
||||
|
@ -530,7 +535,6 @@ static void ConstructController(allocator_control_t* Controller) {
|
|||
}
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************
|
||||
* H E A D E R ( A P I ) F U N C T I O N S
|
||||
************************************************************************************/
|
||||
|
@ -585,7 +589,9 @@ mempool_t AddPoolToAllocator(allocator_t Allocator, void* Address, size_t Size)
|
|||
}
|
||||
|
||||
if (PoolBytes < BLOCK_MIN_SIZE || PoolBytes > BLOCK_MAX_SIZE) {
|
||||
SerialPrintf("Memory manager error at [%s:%x]: Memory Size out of bounds: 0x%x-0x%x: 0x%x.\r\n", __FILE__, __LINE__, (unsigned int)(PoolOverhead + BLOCK_MIN_SIZE), (unsigned int)(PoolOverhead + BLOCK_MAX_SIZE) / 256, PoolBytes);
|
||||
SerialPrintf("Memory manager error at [%s:%x]: Memory Size out of bounds: 0x%x-0x%x: 0x%x.\r\n", __FILE__,
|
||||
__LINE__, (unsigned int) (PoolOverhead + BLOCK_MIN_SIZE),
|
||||
(unsigned int) (PoolOverhead + BLOCK_MAX_SIZE) / 256, PoolBytes);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -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,21 +34,23 @@ size_t KernelLocation;
|
|||
void InitPaging() {
|
||||
|
||||
KernelAddressSpace = (address_space_t) {
|
||||
.Lock = {0},
|
||||
.PML4 = PhysAllocateZeroMem(4096)
|
||||
.Lock = {.NowServing = 0, .NextTicket = 0},
|
||||
.PML4 = (size_t*) PhysAllocateZeroMem(4096)
|
||||
};
|
||||
|
||||
address_space_t BootloaderAddressSpace = (address_space_t) {
|
||||
.Lock = {0},
|
||||
.Lock = {.NowServing = 0, .NextTicket = 0},
|
||||
.PML4 = (size_t*) ReadControlRegister(3)
|
||||
};
|
||||
|
||||
size_t AddressToFind = KernelAddr + 0x2000;
|
||||
size_t BootldrAddress = 0x8000;
|
||||
KernelLocation = DecodeVirtualAddressNoDirect(&BootloaderAddressSpace, AddressToFind);
|
||||
SerialPrintf("[ Mem] Double check: Kernel physically starts at 0x%p (0x%p), ends at 0x%p.\r\n", KernelLocation, AddressToFind, KERNEL_END);
|
||||
SerialPrintf("[ Mem] Double check: Kernel physically starts at 0x%p (0x%p), ends at 0x%p.\r\n", KernelLocation,
|
||||
AddressToFind, KERNEL_END);
|
||||
|
||||
SerialPrintf("[ Mem] Identity mapping the entire 0x%p bytes of physical memory to 0x%p\r\n", FullMemorySize, (size_t) KernelAddressSpace.PML4);
|
||||
SerialPrintf("[ Mem] Identity mapping the entire 0x%p bytes of physical memory to 0x%p\r\n", FullMemorySize,
|
||||
(size_t) KernelAddressSpace.PML4);
|
||||
|
||||
for (size_t i = 0; i < (FullMemorySize / 4096); i++) {
|
||||
size_t Addr = i * 4096;
|
||||
|
@ -56,12 +58,14 @@ void InitPaging() {
|
|||
MapVirtualPageNoDirect(&KernelAddressSpace, Addr, TO_DIRECT(Addr), DEFAULT_PAGE_FLAGS);
|
||||
}
|
||||
|
||||
SerialPrintf("[ Mem] Mapping 0x%x bytes of bootloader structure, starting at 0x%p\r\n", bootldr.size, BootldrAddress);
|
||||
SerialPrintf("[ Mem] Mapping 0x%x bytes of bootloader structure, starting at 0x%p\r\n", bootldr.size,
|
||||
BootldrAddress);
|
||||
for (size_t i = BootldrAddress; i < (BootldrAddress + bootldr.size); i += PAGE_SIZE)
|
||||
MapVirtualPageNoDirect(&KernelAddressSpace, i, KERNEL_REGION + (i - BootldrAddress), 0x3);
|
||||
|
||||
// This allows the code to actually run
|
||||
SerialPrintf("[ Mem] Mapping 0x%x bytes of kernel, starting at 0x%p\r\n", KERNEL_END - KERNEL_PHYSICAL, KERNEL_PHYSICAL);
|
||||
SerialPrintf("[ Mem] Mapping 0x%x bytes of kernel, starting at 0x%p\r\n", KERNEL_END - KERNEL_PHYSICAL,
|
||||
KERNEL_PHYSICAL);
|
||||
for (size_t i = KERNEL_PHYSICAL; i < KERNEL_END; i += PAGE_SIZE)
|
||||
MapVirtualPageNoDirect(&KernelAddressSpace, i, (i - KERNEL_PHYSICAL) + KERNEL_REGION + KERNEL_TEXT, 0x3);
|
||||
|
||||
|
@ -82,9 +86,12 @@ void InitPaging() {
|
|||
SerialPrintf("[ Mem] Diagnostic: Querying existing page tables\r\n");
|
||||
|
||||
size_t KernelAddress = DecodeVirtualAddressNoDirect(&KernelAddressSpace, AddressToFind);
|
||||
SerialPrintf("[ Mem] Diagnostic: Our pagetables put 0x%p at 0x%p + 0x%p.\r\n", AddressToFind, KernelAddress, AddressToFind & ~STACK_TOP);
|
||||
SerialPrintf("[ Mem] Diagnostic: Existing pagetables put 0x%p at 0x%p + 0x%p.\r\n", AddressToFind, KERNEL_PHYSICAL, AddressToFind & ~STACK_TOP);
|
||||
SerialPrintf("[ Mem] %s\r\n", KernelAddress == KERNEL_PHYSICAL ? "These match. Continuing." : "These do not match. Continuing with caution..");
|
||||
SerialPrintf("[ Mem] Diagnostic: Our pagetables put 0x%p at 0x%p + 0x%p.\r\n", AddressToFind, KernelAddress,
|
||||
AddressToFind & ~STACK_TOP);
|
||||
SerialPrintf("[ Mem] Diagnostic: Existing pagetables put 0x%p at 0x%p + 0x%p.\r\n", AddressToFind, KERNEL_PHYSICAL,
|
||||
AddressToFind & ~STACK_TOP);
|
||||
SerialPrintf("[ Mem] %s\r\n", KernelAddress == KERNEL_PHYSICAL ? "These match. Continuing."
|
||||
: "These do not match. Continuing with caution..");
|
||||
|
||||
SerialPrintf("[ Mem] Attempting to jump into our new pagetables: 0x%p\r\n", (size_t) KernelAddressSpace.PML4);
|
||||
WriteControlRegister(3, (size_t) KernelAddressSpace.PML4 & STACK_TOP);
|
||||
|
@ -302,7 +309,7 @@ size_t* CreateNewPageTable(address_space_t* AddressSpace) {
|
|||
// Allocate the first page
|
||||
size_t* NewPML4 = (size_t*) TO_DIRECT(PhysAllocateZeroMem(4096));
|
||||
address_space_t TempAddressSpace = (address_space_t) {
|
||||
.Lock = {0},
|
||||
.Lock = {.NowServing = 0, .NextTicket = 0},
|
||||
.PML4 = NewPML4
|
||||
};
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
#include <kernel/chroma.h>
|
||||
#include <lainlib/lainlib.h>
|
||||
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
|
@ -12,17 +13,12 @@ extern "C" {
|
|||
|
||||
/* This file contains functions for physical memory management.
|
||||
*
|
||||
* This is also called blocking, or block memory allocation.
|
||||
* It mostly deals with the memory map handed to us by the bootloader.
|
||||
* Physical Memory Management is performed with Buddy List allocators, which are one of the most performant systems available.
|
||||
* They tend to be able to allocate physical pages with O(1) efficiency.
|
||||
*
|
||||
* It is useful in virtual memory management, because it allows us to map one block of physical memory to one page of virtual memory.
|
||||
*
|
||||
* Most of the processing here is done with a bitwise mapping of blocks to allocations, normally called a memory bitmap.
|
||||
* See heap.h for the implementation.
|
||||
*
|
||||
* This file also contains memory manipulation functions, like memset and memcpy.
|
||||
* //TODO: replace these functions with SSE2 equivalent.
|
||||
* The implementation here is bespoke, and in need of documentation.
|
||||
*
|
||||
* TODO: Document this mess.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -40,14 +36,14 @@ static buddy_t LowBuddy = {
|
|||
.MaxOrder = 32,
|
||||
.Base = (directptr_t) DIRECT_REGION,
|
||||
.List = (directptr_t[32 - MIN_ORDER]) {0},
|
||||
.Lock = {0},
|
||||
.Lock = {.NowServing = 0, .NextTicket = 0},
|
||||
};
|
||||
|
||||
static buddy_t HighBuddy = {
|
||||
.MaxOrder = 64,
|
||||
.Base = 0,
|
||||
.List = (directptr_t[64 - MIN_ORDER]) {0},
|
||||
.Lock = {0},
|
||||
.Lock = {.NowServing = 0, .NextTicket = 0},
|
||||
};
|
||||
|
||||
static size_t MemoryLength;
|
||||
|
@ -123,7 +119,9 @@ static directptr_t BuddyAllocate(buddy_t* Buddy, size_t Size) {
|
|||
|
||||
if (InitialOrder >= Buddy->MaxOrder) {
|
||||
SerialPrintf("Tried to allocate too much physical memory for buddy 0x%p\r\n", Buddy);
|
||||
SerialPrintf("Buddy 0x%p has max order %d, but 0x%x bytes was requested.\r\nInitial Order: %d, Wanted Size: 0x%x\r\n", Buddy, Buddy->MaxOrder, Size, InitialOrder, WantedSize);
|
||||
SerialPrintf(
|
||||
"Buddy 0x%p has max order %d, but 0x%x bytes was requested.\r\nInitial Order: %d, Wanted Size: 0x%x\r\n",
|
||||
Buddy, Buddy->MaxOrder, Size, InitialOrder, WantedSize);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -215,7 +213,8 @@ void ListMemoryMap() {
|
|||
size_t page_to = AlignDownwards(entry_to, 0x1000);
|
||||
|
||||
if (page_from != 0 && page_to != 0) {
|
||||
SerialPrintf("[ Mem] Adding the range 0x%p-0x%p to the physical memory manager!\r\n", page_from, page_to);
|
||||
SerialPrintf("[ Mem] Adding the range 0x%p-0x%p to the physical memory manager!\r\n", page_from,
|
||||
page_to);
|
||||
AddRangeToPhysMem((void*) ((char*) (page_from)), page_to - page_from);
|
||||
}
|
||||
|
||||
|
@ -231,7 +230,9 @@ void AddRangeToPhysMem(directptr_t Base, size_t Size) {
|
|||
} else {
|
||||
if ((size_t) Base < (size_t) LOWER_REGION) {
|
||||
size_t difference = (size_t) LOWER_REGION - (size_t) Base;
|
||||
SerialPrintf("[ Mem] Base is 0x%p bytes away from the threshold, allocating 0x%p-0x%p to lower memory..\r\n", difference, (size_t) Base, (size_t) Base + difference);
|
||||
SerialPrintf(
|
||||
"[ Mem] Base is 0x%p bytes away from the threshold, allocating 0x%p-0x%p to lower memory..\r\n",
|
||||
difference, (size_t) Base, (size_t) Base + difference);
|
||||
AddRangeToBuddy(&LowBuddy, Base, difference);
|
||||
Base = (void*) LOWER_REGION;
|
||||
Size = Size - difference;
|
||||
|
@ -305,7 +306,7 @@ void PhysFreeMem(directptr_t Pointer, size_t Size) {
|
|||
static _Atomic(uint16_t)* PageRefCount = NULL;
|
||||
|
||||
void PhysAllocatorInit() {
|
||||
PageRefCount = PhysAllocateZeroMem(sizeof(uint16_t) * MemoryPages);
|
||||
PageRefCount = (_Atomic(uint16_t)*) PhysAllocateZeroMem(sizeof(uint16_t) * MemoryPages);
|
||||
}
|
||||
|
||||
directptr_t PhysAllocatePage() {
|
||||
|
|
|
@ -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;
|
||||
|
|
@ -207,7 +207,7 @@ size_t ReadXCS() {
|
|||
}
|
||||
|
||||
DESC_TBL ReadGDT() {
|
||||
DESC_TBL GDTData = {0};
|
||||
DESC_TBL GDTData;
|
||||
|
||||
__asm__ __volatile__("sgdt %[dest]" : [dest] "=m"(GDTData) : :);
|
||||
|
||||
|
@ -220,7 +220,7 @@ void WriteGDT(DESC_TBL GDTData) {
|
|||
}
|
||||
|
||||
DESC_TBL ReadIDT() {
|
||||
DESC_TBL IDTData = {0};
|
||||
DESC_TBL IDTData;
|
||||
|
||||
__asm__ __volatile__("sidt %[dest]" : [dest] "=m"(IDTData) : :);
|
||||
|
|
@ -20,7 +20,7 @@ extern "C" {
|
|||
*/
|
||||
|
||||
|
||||
PRINTINFO PrintInfo = {0};
|
||||
PRINTINFO PrintInfo;
|
||||
|
||||
#define FONT bitfont_latin
|
||||
|
||||
|
@ -44,8 +44,10 @@ void InitPrint() {
|
|||
|
||||
PrintInfo.charsPerRow = bootldr.fb_width / (PrintInfo.charScale * PrintInfo.charWidth);
|
||||
PrintInfo.rowsPerScrn = bootldr.fb_height / (PrintInfo.charScale * PrintInfo.charHeight);
|
||||
SerialPrintf("[Print] A single character is %ux%u pixels.\r\n", PrintInfo.charScale * PrintInfo.charWidth, PrintInfo.charScale * PrintInfo.charHeight);
|
||||
SerialPrintf("[Print] The screen is %ux%u, meaning you can fit %ux%u characters on screen.\r\n", bootldr.fb_width, bootldr.fb_height, PrintInfo.charsPerRow, PrintInfo.rowsPerScrn);
|
||||
SerialPrintf("[Print] A single character is %ux%u pixels.\r\n", PrintInfo.charScale * PrintInfo.charWidth,
|
||||
PrintInfo.charScale * PrintInfo.charHeight);
|
||||
SerialPrintf("[Print] The screen is %ux%u, meaning you can fit %ux%u characters on screen.\r\n", bootldr.fb_width,
|
||||
bootldr.fb_height, PrintInfo.charsPerRow, PrintInfo.rowsPerScrn);
|
||||
|
||||
WriteString("Testing print\n");
|
||||
|
||||
|
@ -87,9 +89,11 @@ static void DrawChar(const char character, size_t x, size_t y) {
|
|||
for (uint32_t ScaleY = 0; ScaleY < PrintInfo.charScale; ScaleY++) { // Take care of the scale height
|
||||
for (uint32_t ScaleX = 0; ScaleX < PrintInfo.charScale; ScaleX++) { // And the scale width
|
||||
size_t offset = ((y * bootldr.fb_width + x) + // Calculate the offset from the framebuffer
|
||||
PrintInfo.charScale * (Row * bootldr.fb_width + Bit) + // With the appropriate scale
|
||||
PrintInfo.charScale * (Row * bootldr.fb_width + Bit) +
|
||||
// With the appropriate scale
|
||||
(ScaleY * bootldr.fb_width + ScaleX) + // In X and Y
|
||||
PrintInfo.charScale * 1 * PrintInfo.charWidth) - 10; // With some offset to start at 0
|
||||
PrintInfo.charScale * 1 * PrintInfo.charWidth) -
|
||||
10; // With some offset to start at 0
|
||||
|
||||
// Check the bit in the bitmap, if it's solid..
|
||||
if ((FONT[(int) character][Row * Y + X] >> (Bit & 0x7)) & 1) {
|
||||
|
@ -110,11 +114,9 @@ inline void DrawPixel(size_t x, size_t y) {
|
|||
}
|
||||
|
||||
void FillScreen(uint32_t color) {
|
||||
uint32_t currentColor = GetForegroundColor();
|
||||
for (uint32_t pixel = 0; pixel < bootldr.fb_width * bootldr.fb_height; pixel++) {
|
||||
((uint32_t*) &fb)[pixel] = color;
|
||||
}
|
||||
SetForegroundColor(currentColor);
|
||||
}
|
||||
|
||||
static void Newline() {
|
||||
|
@ -226,7 +228,8 @@ void WriteStringWithFont(const char *inChar) {
|
|||
offset += bootldr.fb_scanline;
|
||||
}
|
||||
|
||||
inChar++; kx++;
|
||||
inChar++;
|
||||
kx++;
|
||||
}
|
||||
}
|
||||
|
|
@ -54,6 +54,10 @@ int SerialPrintf(const char* Format, ...) {
|
|||
|
||||
|
||||
switch (*Format) {
|
||||
case '.':
|
||||
Limit = va_arg(Parameters, size_t);
|
||||
[[fallthrough]];
|
||||
|
||||
case 'c': {
|
||||
Format++;
|
||||
|
||||
|
@ -68,10 +72,7 @@ int SerialPrintf(const char* Format, ...) {
|
|||
Format++;
|
||||
const char* Str = va_arg(Parameters, char*);
|
||||
|
||||
size_t Len = strlen(Str);
|
||||
|
||||
if(Limit < Len)
|
||||
return -1;
|
||||
size_t Len = MIN(strlen(Str), Limit);
|
||||
|
||||
WriteSerialString(Str, Len);
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user