Compare commits
No commits in common. "master" and "struggles" have entirely different histories.
|
@ -11,10 +11,6 @@ set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
|
||||||
SET(CMAKE_SYSTEM_NAME Generic)
|
SET(CMAKE_SYSTEM_NAME Generic)
|
||||||
SET(CMAKE_CROSSCOMPILING 1)
|
SET(CMAKE_CROSSCOMPILING 1)
|
||||||
|
|
||||||
enable_language(ASM)
|
|
||||||
enable_language(C)
|
|
||||||
enable_language(CXX)
|
|
||||||
|
|
||||||
project(chroma)
|
project(chroma)
|
||||||
|
|
||||||
SET(src_files
|
SET(src_files
|
||||||
|
@ -33,10 +29,9 @@ SET(src_files
|
||||||
${CMAKE_SOURCE_DIR}/src/system/memory/liballoc.cpp
|
${CMAKE_SOURCE_DIR}/src/system/memory/liballoc.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/system/memory/physmem.c
|
${CMAKE_SOURCE_DIR}/src/system/memory/physmem.c
|
||||||
${CMAKE_SOURCE_DIR}/src/system/process/process.cpp
|
${CMAKE_SOURCE_DIR}/src/system/process/process.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/system/extern/extern_defs.cpp
|
|
||||||
${CMAKE_SOURCE_DIR}/src/drivers/elf.cpp
|
${CMAKE_SOURCE_DIR}/src/drivers/elf.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/drivers/devices/devices.cpp
|
${CMAKE_SOURCE_DIR}/src/drivers/devices/devices.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/drivers/devices/io/ps2_keyboard.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/io/apic.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/drivers/devices/storage/ata.cpp
|
${CMAKE_SOURCE_DIR}/src/drivers/devices/storage/ata.cpp
|
||||||
)
|
)
|
||||||
|
@ -46,7 +41,7 @@ SET(lib_files
|
||||||
${CMAKE_SOURCE_DIR}/src/lainlib/mutex/ticketlock.cpp
|
${CMAKE_SOURCE_DIR}/src/lainlib/mutex/ticketlock.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/lainlib/compression/lzgmini.c
|
${CMAKE_SOURCE_DIR}/src/lainlib/compression/lzgmini.c
|
||||||
${CMAKE_SOURCE_DIR}/src/lainlib/string/str.cpp
|
${CMAKE_SOURCE_DIR}/src/lainlib/string/str.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/lainlib/vector/vector.cpp
|
${CMAKE_SOURCE_DIR}/src/editor/EditorMain.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
include_directories("inc" "D:/mingw/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++" "D:/mingw/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32")
|
include_directories("inc" "D:/mingw/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++" "D:/mingw/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32")
|
||||||
|
@ -55,10 +50,6 @@ SET(src_no_sse
|
||||||
${CMAKE_SOURCE_DIR}/src/system/interrupts.cpp
|
${CMAKE_SOURCE_DIR}/src/system/interrupts.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
SET(src_as
|
|
||||||
${CMAKE_SOURCE_DIR}/src/global/core-att.s
|
|
||||||
)
|
|
||||||
|
|
||||||
SET(src_preamble
|
SET(src_preamble
|
||||||
${CMAKE_SOURCE_DIR}/src/global/crt0.o
|
${CMAKE_SOURCE_DIR}/src/global/crt0.o
|
||||||
${CMAKE_SOURCE_DIR}/src/global/crti.o
|
${CMAKE_SOURCE_DIR}/src/global/crti.o
|
||||||
|
@ -79,5 +70,5 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
|
||||||
add_executable(kernel)
|
add_executable(kernel)
|
||||||
|
|
||||||
target_sources(kernel PUBLIC ${src_preamble} PUBLIC ${src_files} PUBLIC ${src_no_sse} PUBLIC ${lib_files} PUBLIC ${src_epilogue})
|
target_sources(kernel PUBLIC ${src_preamble} PUBLIC ${src_files} PUBLIC ${src_no_sse} PUBLIC ${lib_files} PUBLIC ${src_epilogue})
|
||||||
target_compile_options(kernel PRIVATE -ffreestanding -O0 -Wall -Wextra -Wall -Werror -fPIC -fno-exceptions -fno-omit-frame-pointer -mno-red-zone -fno-stack-protector -fno-strict-aliasing $<$<COMPILE_LANGUAGE:CXX>:-fno-rtti> -ggdb3)
|
target_compile_options(kernel PRIVATE -ffreestanding -O0 -Wall -Wextra -Wall -Werror -fPIC -fno-exceptions -fno-omit-frame-pointer -mno-red-zone -fno-stack-protector -fno-rtti -ggdb3)
|
||||||
target_link_options(kernel PRIVATE -T ${CMAKE_SOURCE_DIR}/linker.ld -ffreestanding -O2 -nostdlib -nostartfiles -lgcc)
|
target_link_options(kernel PRIVATE -T ${CMAKE_SOURCE_DIR}/linker.ld -ffreestanding -O2 -nostdlib -nostartfiles -lgcc)
|
||||||
|
|
47
README.md
47
README.md
|
@ -38,55 +38,10 @@ It will compile the kernel, and create an OS image with `mkbootimg`.
|
||||||
### Linux
|
### Linux
|
||||||
|
|
||||||
The system for linux is a lot easier, but you *do* need an x86_64-elf-gcc cross compiler. You can get one from the AUR on Arch-based distros (like Manjaro), or make one yourself using [the OSDev Wiki guide](https://wiki.osdev.org/GCC_Cross-Compiler)
|
The system for linux is a lot easier, but you *do* need an x86_64-elf-gcc cross compiler. You can get one from the AUR on Arch-based distros (like Manjaro), or make one yourself using [the OSDev Wiki guide](https://wiki.osdev.org/GCC_Cross-Compiler)
|
||||||
|
Simply run the `init.sh` to generate a makefile, then `make` to create the image file.
|
||||||
On the Chroma side, Simply run the `init.sh` to generate a makefile, then `make` to create the image file.
|
|
||||||
|
|
||||||
|
|
||||||
The generated IMG works in QEMU, or on a physical test device (unlike a lot of other hobby OSes!)
|
The generated IMG works in QEMU, or on a physical test device (unlike a lot of other hobby OSes!)
|
||||||
This means you can use any emulator or hypervisor to run it.
|
This means you can use any emulator or hypervisor to run it.
|
||||||
|
|
||||||
|
|
||||||
## Project structure
|
|
||||||
|
|
||||||
The repository has a lot of files and folders after setting up a workspace. This is a guide to all the files and folders.
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
File Location | Description
|
|
||||||
/
|
|
||||||
├── bin/ | Binary Output folder
|
|
||||||
│ └── img/ | Image Output folder.
|
|
||||||
│ └── chroma.img | Disk Image file, as an alternative to ISO below.
|
|
||||||
│ |
|
|
||||||
├── inc/ | Global header include folder.
|
|
||||||
│ ├── driver/ | Header files for the default driver implementations.
|
|
||||||
│ ├── editor/ | Header files for the builtin editor and debugger.
|
|
||||||
│ ├── kernel/ | Header files for the Chroma kernel itself.
|
|
||||||
│ └── lainlib/ | Header files for the Lainlib standard library.
|
|
||||||
│ |
|
|
||||||
├── src/ | Source files.
|
|
||||||
│ ├── assets/ | Assorted linkable files that will be bundled with the built image.
|
|
||||||
│ ├── drivers/ | Handling of the default driver implementations.
|
|
||||||
│ ├── editor/ | Handling of the builtin editor and debugger.
|
|
||||||
│ ├── global/ | Various files used in global objects (ie. the C RunTime, new core bootstrapping, etc)
|
|
||||||
│ ├── lainlib/ | Handling of the Lainlib standard library.
|
|
||||||
│ ├── system/ | Core Kernel files.
|
|
||||||
│ ├── video/ | Writing and drawing on the screen.
|
|
||||||
│ └── kernel.cpp | The primary kernel entry point.
|
|
||||||
│ |
|
|
||||||
├── tools/ | Auxiliary tools used in the buildsystem.
|
|
||||||
│ └── mkbootimg/ | Creates a bootable .img file based on the chroma.json configuration file below.
|
|
||||||
│ |
|
|
||||||
├── .gitignore | Git Repository Ignored Files
|
|
||||||
├── build_and_run.sh | shell script that builds the img file and runs it using run.sh below.
|
|
||||||
├── choma.bxrc | bxrc (Bochs Runtime Config) file for the Bochs emulator and debugger.
|
|
||||||
├── chroma.iso | ISO disc image file that can be loaded into a VM or onto a boot disk.
|
|
||||||
├── chroma.json | MkBootImg configuration file
|
|
||||||
├── CMakeLists.txt | Buildscript and CMake project configuration file.
|
|
||||||
├── LICENSE | Chroma's License. MIT License.
|
|
||||||
├── linker.ld | GCC linkerscript that places files and addresses at their expected positions.
|
|
||||||
├── post.sh | Postprocessing script; Generates the final img file, and attempts to update a VirtualBox configuration named "Chroma" to run this new file instead.
|
|
||||||
├── pre.sh | First-time setup script; generates the font file binary and generates the CMake buildscripts.
|
|
||||||
├── README.md | This file.
|
|
||||||
└── run.bat | Attempts to start a Virtualbox VM named "chroma".
|
|
||||||
```
|
|
|
@ -2,7 +2,6 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "lainlib/vector/vector.h"
|
|
||||||
|
|
||||||
/************************
|
/************************
|
||||||
*** Team Kitty, 2021 ***
|
*** Team Kitty, 2021 ***
|
||||||
|
@ -51,50 +50,7 @@ namespace Device {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
class GenericKeyboard : public GenericDevice {
|
// TODO: GenericKeyboard
|
||||||
public:
|
|
||||||
struct KeyboardData {
|
|
||||||
char Char;
|
|
||||||
char Scancode;
|
|
||||||
bool Pressed;
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is an input device.
|
|
||||||
DeviceType GetType() const final {
|
|
||||||
return DeviceType::INTERFACE;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Provided for utility checks.
|
|
||||||
static DeviceType GetRootType() {
|
|
||||||
return DeviceType::INTERFACE;
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual bool isPressed(uint8_t) const = 0;
|
|
||||||
virtual uint8_t getLastPress() const = 0;
|
|
||||||
|
|
||||||
size_t readBuffer(void* dest, size_t index, size_t len) {
|
|
||||||
size_t lengthRead = len;
|
|
||||||
|
|
||||||
if (index > buffer.size()) {
|
|
||||||
return 0;
|
|
||||||
} else if (index + len > buffer.size()) {
|
|
||||||
lengthRead = sizeof(KeyboardData) - index; // TODO: wat?
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy((uint8_t*) dest, ((uint8_t*)buffer.data) + index, lengthRead);
|
|
||||||
return lengthRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t getBufferSize() {
|
|
||||||
return buffer.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
lainlib::vector<KeyboardData> buffer;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: GenericDebugger
|
// TODO: GenericDebugger
|
||||||
// TODO: GenericNetwork
|
// TODO: GenericNetwork
|
||||||
|
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <driver/generic/device.h>
|
|
||||||
|
|
||||||
/************************
|
|
||||||
*** Team Kitty, 2022 ***
|
|
||||||
*** Chroma ***
|
|
||||||
***********************/
|
|
||||||
|
|
||||||
extern char keys[128];
|
|
||||||
|
|
||||||
namespace Device {
|
|
||||||
class PS2Keyboard : public GenericKeyboard {
|
|
||||||
bool keyStates[128];
|
|
||||||
uint8_t lastPress = 0;
|
|
||||||
uint8_t* callback;
|
|
||||||
|
|
||||||
public:
|
|
||||||
PS2Keyboard();
|
|
||||||
|
|
||||||
// The instance of this singleton class.
|
|
||||||
static PS2Keyboard* driver;
|
|
||||||
|
|
||||||
const char* GetName() const {
|
|
||||||
return "PS2 Keyboard";
|
|
||||||
};
|
|
||||||
|
|
||||||
void Init();
|
|
||||||
void InterruptHandler();
|
|
||||||
|
|
||||||
void setState(bool state, uint8_t key);
|
|
||||||
bool isPressed(uint8_t key) const;
|
|
||||||
|
|
||||||
uint8_t getLastPress() const {
|
|
||||||
return keys[lastPress];
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetCallback(uint32_t*);
|
|
||||||
};
|
|
||||||
}
|
|
28
inc/driver/keyboard.h
Normal file
28
inc/driver/keyboard.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#include <kernel/chroma.h>
|
||||||
|
|
||||||
|
/************************
|
||||||
|
*** Team Kitty, 2020 ***
|
||||||
|
*** Chroma ***
|
||||||
|
***********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char Char;
|
||||||
|
char Scancode;
|
||||||
|
bool Pressed;
|
||||||
|
} KeyboardData;
|
||||||
|
|
||||||
|
typedef void (*KeyboardCallback)(KeyboardData Frame);
|
||||||
|
|
||||||
|
extern KeyboardCallback KeyboardCallbacks[16];
|
||||||
|
|
||||||
|
int SetupKBCallback(void (*Handler)(KeyboardData Frame));
|
||||||
|
|
||||||
|
void UninstallKBCallback(int Index);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -6,6 +6,10 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
;* Memory map
|
;* Memory map
|
||||||
;* 0h - 600h reserved for the system
|
;* 0h - 600h reserved for the system
|
||||||
|
@ -152,3 +156,9 @@ typedef struct {
|
||||||
* MMapEnt *mmap_ent = &bootboot.mmap; mmap_ent++;
|
* MMapEnt *mmap_ent = &bootboot.mmap; mmap_ent++;
|
||||||
* until you reach bootboot->size */
|
* until you reach bootboot->size */
|
||||||
} __attribute__((packed)) bootinfo;
|
} __attribute__((packed)) bootinfo;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -9,6 +9,10 @@
|
||||||
* It also provides the symbols for the framebuffer and configuration file, which are both equually important.
|
* It also provides the symbols for the framebuffer and configuration file, which are both equually important.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
#define UNUSED(x) (void)x
|
#define UNUSED(x) (void)x
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -69,6 +73,7 @@ void WriteChar(const char character);
|
||||||
|
|
||||||
void WriteStringWithFont(const char* string);
|
void WriteStringWithFont(const char* string);
|
||||||
|
|
||||||
|
void InitInterrupts();
|
||||||
void InitSerial();
|
void InitSerial();
|
||||||
void InitPrint();
|
void InitPrint();
|
||||||
|
|
||||||
|
@ -77,14 +82,12 @@ void SetupIDT();
|
||||||
|
|
||||||
int ParseKernelHeader(size_t InitrdPtr);
|
int ParseKernelHeader(size_t InitrdPtr);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
int Main();
|
||||||
extern "C" {
|
|
||||||
#endif
|
void Exit(int code);
|
||||||
void InitInterrupts();
|
|
||||||
|
void SomethingWentWrong(const char* Message);
|
||||||
|
|
||||||
int Main();
|
|
||||||
void Exit(int code);
|
|
||||||
void SomethingWentWrong(const char* Message);
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
} // extern "C"
|
||||||
#endif
|
#endif
|
|
@ -90,7 +90,7 @@ namespace ACPI {
|
||||||
MADT();
|
MADT();
|
||||||
|
|
||||||
void LogDump();
|
void LogDump();
|
||||||
void Init();
|
void Initialize();
|
||||||
// Get the byte of the end of the table.
|
// Get the byte of the end of the table.
|
||||||
size_t GetEndOfTable();
|
size_t GetEndOfTable();
|
||||||
// Get all of the entries in the table, as an array.
|
// Get all of the entries in the table, as an array.
|
||||||
|
|
|
@ -47,7 +47,7 @@ namespace ACPI {
|
||||||
// RSDP Entries themselves.
|
// RSDP Entries themselves.
|
||||||
struct RSDT {
|
struct RSDT {
|
||||||
ACPIHeader Header;
|
ACPIHeader Header;
|
||||||
uint32_t OtherSDTs[];
|
uint32_t* OtherSDTs;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
RSDP();
|
RSDP();
|
||||||
|
|
|
@ -29,21 +29,21 @@ struct StackFrame {
|
||||||
*/
|
*/
|
||||||
class Core {
|
class Core {
|
||||||
public:
|
public:
|
||||||
Core(){}
|
Core() {}
|
||||||
Core(size_t LAPIC, size_t ID);
|
Core(size_t LAPIC, size_t ID);
|
||||||
|
|
||||||
size_t ID = 0;
|
size_t ID;
|
||||||
size_t LocalAPIC = 0;
|
size_t LocalAPIC;
|
||||||
|
|
||||||
address_space_t* AddressSpace = nullptr;
|
address_space_t* AddressSpace;
|
||||||
|
|
||||||
uint8_t* SyscallStack = 0;
|
uint8_t* SyscallStack;
|
||||||
size_t StackAddress = 0;
|
size_t StackAddress;
|
||||||
uint8_t StackData[Constants::Core::STACK_SIZE] = { 0 };
|
uint8_t StackData[Constants::Core::STACK_SIZE];
|
||||||
|
|
||||||
IDT CoreIDT = { 0, 0 };
|
IDT CoreIDT;
|
||||||
GDT CoreGDT = { 0, 0 };
|
GDT CoreGDT;
|
||||||
TSS64 CoreTSS = { };
|
TSS64 CoreTSS;
|
||||||
|
|
||||||
void LoadExtraRegisters(uint8_t* Data);
|
void LoadExtraRegisters(uint8_t* Data);
|
||||||
void SaveExtraRegisters(uint8_t* Data);
|
void SaveExtraRegisters(uint8_t* Data);
|
||||||
|
@ -53,17 +53,28 @@ class Core {
|
||||||
static Core* GetCurrent() {
|
static Core* GetCurrent() {
|
||||||
size_t CoreID = 0;
|
size_t CoreID = 0;
|
||||||
__asm__ __volatile__("mov %0, %%fs\n" : "=r"(CoreID) : :);
|
__asm__ __volatile__("mov %0, %%fs\n" : "=r"(CoreID) : :);
|
||||||
return Processors[CoreID];
|
return &Processors[CoreID];
|
||||||
}
|
}
|
||||||
|
|
||||||
static Core* GetCore(int ID) { return Processors[ID]; }
|
static Core* GetCore(int ID) { return &Processors[ID]; }
|
||||||
|
|
||||||
static void PreInit();
|
|
||||||
static void Init();
|
static void Init();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Core* Processors[];
|
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 Bootstrap();
|
||||||
|
void SetupData(size_t ID);
|
||||||
|
|
||||||
};
|
} __attribute__((packed));
|
||||||
|
|
|
@ -8,6 +8,10 @@
|
||||||
*** Chroma ***
|
*** Chroma ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct __attribute__((packed)) {
|
typedef struct __attribute__((packed)) {
|
||||||
uint16_t LowLimit;
|
uint16_t LowLimit;
|
||||||
uint16_t BaseLow;
|
uint16_t BaseLow;
|
||||||
|
@ -82,3 +86,7 @@ typedef struct __attribute__((packed)) {
|
||||||
uint16_t Length;
|
uint16_t Length;
|
||||||
size_t Address;
|
size_t Address;
|
||||||
} IDT;
|
} IDT;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
|
@ -6,12 +6,13 @@
|
||||||
*** Chroma ***
|
*** Chroma ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern const char* ExceptionStrings[];
|
extern const char* ExceptionStrings[];
|
||||||
|
|
||||||
|
|
||||||
typedef struct __attribute__((packed)) {
|
typedef struct __attribute__((packed)) {
|
||||||
size_t rip;
|
size_t rip;
|
||||||
size_t cs;
|
size_t cs;
|
||||||
|
@ -29,17 +30,12 @@ typedef struct __attribute__((packed)) {
|
||||||
size_t ss;
|
size_t ss;
|
||||||
} EXCEPTION_FRAME;
|
} EXCEPTION_FRAME;
|
||||||
|
|
||||||
|
|
||||||
typedef void (*IRQHandler)(INTERRUPT_FRAME* Frame);
|
typedef void (*IRQHandler)(INTERRUPT_FRAME* Frame);
|
||||||
|
|
||||||
typedef struct {
|
extern IRQHandler IRQ_Handlers[16];
|
||||||
IRQHandler handlers[8];
|
|
||||||
size_t numHandlers;
|
|
||||||
} IRQHandlerData;
|
|
||||||
|
|
||||||
extern IRQHandlerData IRQHandlers[32];
|
void InstallIRQ(int IRQ, void (*Handler)(INTERRUPT_FRAME* Frame));
|
||||||
|
|
||||||
size_t InstallIRQ(int IRQ, IRQHandler handler);
|
|
||||||
void UninstallIRQHandler(int IRQ, size_t ID);
|
|
||||||
|
|
||||||
__attribute__((no_caller_saved_registers)) void IRQ_Common(INTERRUPT_FRAME* Frame, size_t Interupt);
|
__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_Common(INTERRUPT_FRAME* Frame, size_t Interrupt);
|
||||||
|
@ -99,5 +95,5 @@ void IRQ14Handler(INTERRUPT_FRAME* Frame);
|
||||||
void IRQ15Handler(INTERRUPT_FRAME* Frame);
|
void IRQ15Handler(INTERRUPT_FRAME* Frame);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
} // extern "C"
|
||||||
#endif
|
#endif
|
|
@ -8,7 +8,11 @@
|
||||||
|
|
||||||
#define PAUSE __asm__ __volatile__("pause")
|
#define PAUSE __asm__ __volatile__("pause")
|
||||||
|
|
||||||
typedef struct {
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
uint8_t ACK;
|
uint8_t ACK;
|
||||||
uint8_t SelfTest;
|
uint8_t SelfTest;
|
||||||
uint8_t Echo;
|
uint8_t Echo;
|
||||||
|
@ -18,6 +22,7 @@ typedef struct {
|
||||||
|
|
||||||
extern KBD_FLAGS KbdFlags;
|
extern KBD_FLAGS KbdFlags;
|
||||||
|
|
||||||
|
|
||||||
DESC_TBL ReadGDT(void);
|
DESC_TBL ReadGDT(void);
|
||||||
void WriteGDT(DESC_TBL GDTData);
|
void WriteGDT(DESC_TBL GDTData);
|
||||||
|
|
||||||
|
@ -64,14 +69,12 @@ void Send8042(size_t);
|
||||||
void WriteSerialChar(const char);
|
void WriteSerialChar(const char);
|
||||||
void WriteSerialString(const char*, size_t);
|
void WriteSerialString(const char*, size_t);
|
||||||
|
|
||||||
|
int SerialPrintf(const char* format, ...);
|
||||||
|
int Printf(const char* Format, ...);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
void* memcpy(void* dest, void const* src, size_t len);
|
||||||
extern "C" {
|
void* memset(void* dst, int src, size_t len);
|
||||||
#endif
|
|
||||||
int SerialPrintf(const char* format, ...);
|
#ifdef __cplusplus
|
||||||
int Printf(const char* Format, ...);
|
|
||||||
void* memcpy(void* dest, void const* src, size_t len);
|
|
||||||
void* memset(void* dst, int src, size_t len);
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
|
@ -1,10 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <lainlib/lainlib.h>
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <kernel/system/interrupts.h>
|
#include <kernel/system/interrupts.h>
|
||||||
|
#include <lainlib/lainlib.h>
|
||||||
|
|
||||||
/************************
|
/************************
|
||||||
*** Team Kitty, 2020 ***
|
*** Team Kitty, 2020 ***
|
||||||
|
@ -38,18 +41,10 @@
|
||||||
|
|
||||||
#define CONCAT(x, y) x ## y
|
#define CONCAT(x, y) x ## y
|
||||||
#define CONCAT2(x, y) CONCAT(x, y)
|
#define CONCAT2(x, y) CONCAT(x, y)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
#define ASSERT(exp, error) \
|
#define ASSERT(exp, error) \
|
||||||
if(!(exp)) SomethingWentWrong(error);
|
if(!(exp)) SomethingWentWrong(error);
|
||||||
// typedef char CONCAT2(static_assert, __LINE__) [(exp) ? 1 : -1]
|
// typedef char CONCAT2(static_assert, __LINE__) [(exp) ? 1 : -1]
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define CLZ(num) (num ? __builtin_clzll(num) : 64)
|
#define CLZ(num) (num ? __builtin_clzll(num) : 64)
|
||||||
|
|
||||||
#define IS_ALIGNED(addr) (((size_t) addr | 0xFFFFFFFFFFFFF000) == 0)
|
#define IS_ALIGNED(addr) (((size_t) addr | 0xFFFFFFFFFFFFF000) == 0)
|
||||||
|
@ -147,8 +142,6 @@ extern "C" {
|
||||||
#define KERNEL_HEAP_REGION 0xFFFFE00080000000ull // Kernel Object Space (kmalloc will allocate into this region)
|
#define KERNEL_HEAP_REGION 0xFFFFE00080000000ull // Kernel Object Space (kmalloc will allocate into this region)
|
||||||
#define KERNEL_HEAP_END 0xFFFFE000C0000000ull // End of Kernel Object Space
|
#define KERNEL_HEAP_END 0xFFFFE000C0000000ull // End of Kernel Object Space
|
||||||
|
|
||||||
#define APIC_REGION 0x00000000FEE00000ull // Physical location of the APIC MMIO region.
|
|
||||||
|
|
||||||
#define DIRECT_REGION 0xFFFF800000000000ull
|
#define DIRECT_REGION 0xFFFF800000000000ull
|
||||||
|
|
||||||
#define LOWER_REGION 0x0000000100000000ull // Lower Memory cutoff - 4GB
|
#define LOWER_REGION 0x0000000100000000ull // Lower Memory cutoff - 4GB
|
||||||
|
@ -228,15 +221,10 @@ size_t AllocatorMaxBlockSize(void);
|
||||||
size_t AllocatorPoolOverhead(void);
|
size_t AllocatorPoolOverhead(void);
|
||||||
size_t AllocatorAllocateOverhead(void);
|
size_t AllocatorAllocateOverhead(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
size_t AlignUpwards(size_t Pointer, size_t Alignment);
|
size_t AlignUpwards(size_t Pointer, size_t Alignment);
|
||||||
size_t AlignDownwards(size_t Pointer, size_t Alignment);
|
size_t AlignDownwards(size_t Pointer, size_t Alignment);
|
||||||
void* AlignPointer(const void* Pointer, size_t Alignment);
|
void* AlignPointer(const void* Pointer, size_t Alignment);
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/************************************************************
|
/************************************************************
|
||||||
|
@ -247,10 +235,6 @@ extern size_t memstart;
|
||||||
|
|
||||||
extern size_t end;
|
extern size_t end;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void ListMemoryMap();
|
void ListMemoryMap();
|
||||||
|
|
||||||
void InitMemoryManager();
|
void InitMemoryManager();
|
||||||
|
@ -284,7 +268,6 @@ void TraversePageTables();
|
||||||
void* memcpy(void* dest, void const* src, size_t len);
|
void* memcpy(void* dest, void const* src, size_t len);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*********************************************
|
/*********************************************
|
||||||
* C h r o m a A l l o c a t o r
|
* C h r o m a A l l o c a t o r
|
||||||
**********************************************/
|
**********************************************/
|
||||||
|
@ -315,6 +298,6 @@ extern void *PREFIX(realloc)(void *, size_t); ///< The standard function.
|
||||||
extern void *PREFIX(calloc)(size_t, size_t); ///< The standard function.
|
extern void *PREFIX(calloc)(size_t, size_t); ///< The standard function.
|
||||||
extern void PREFIX(free)(void *); ///< The standard function.
|
extern void PREFIX(free)(void *); ///< The standard function.
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
|
@ -1,5 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
@ -175,3 +179,7 @@ typedef struct {
|
||||||
|
|
||||||
extern pci_device_t** pci_root_devices;
|
extern pci_device_t** pci_root_devices;
|
||||||
extern pci_entry_t* pci_map;
|
extern pci_entry_t* pci_map;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -3,6 +3,10 @@
|
||||||
*** Chroma ***
|
*** Chroma ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
// This file contains all of the bitmap fonts made by me (Curle) and taken from the public domain
|
// This file contains all of the bitmap fonts made by me (Curle) and taken from the public domain
|
||||||
// eg. http://dimensionalrift.homelinux.net/combuster/mos3/?p=viewsource&file=/modules/gfx/font8_8.asm
|
// eg. http://dimensionalrift.homelinux.net/combuster/mos3/?p=viewsource&file=/modules/gfx/font8_8.asm
|
||||||
|
|
||||||
|
@ -464,3 +468,7 @@ const unsigned char bitfont_block[32][8] = {
|
||||||
{ 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F}, // U+259E (boxes top right and bottom left)
|
{ 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F}, // U+259E (boxes top right and bottom left)
|
||||||
{ 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF}, // U+259F (boxes right and bottom)
|
{ 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF}, // U+259F (boxes right and bottom)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -5,6 +5,10 @@
|
||||||
*** Chroma ***
|
*** Chroma ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Drawing routines for screen manipulation.
|
* Drawing routines for screen manipulation.
|
||||||
* This will be pulled out into the Helix library soon.
|
* This will be pulled out into the Helix library soon.
|
||||||
|
@ -56,3 +60,7 @@ void DrawLineRoundedRect(size_t x, size_t y, size_t width, size_t height, size_t
|
||||||
void DrawFilledCircle(size_t centerX, size_t centerY, size_t radius);
|
void DrawFilledCircle(size_t centerX, size_t centerY, size_t radius);
|
||||||
void DrawLineCircle(size_t centerX, size_t centerY, size_t radius);
|
void DrawLineCircle(size_t centerX, size_t centerY, size_t radius);
|
||||||
void DrawLineCircleCorners(size_t centerX, size_t centerY, size_t radius, char cornerMask);
|
void DrawLineCircleCorners(size_t centerX, size_t centerY, size_t radius, char cornerMask);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -28,6 +28,10 @@
|
||||||
#ifndef _LIBLZG_H_
|
#ifndef _LIBLZG_H_
|
||||||
#define _LIBLZG_H_
|
#define _LIBLZG_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
#define LZG_VERSION "1.0.10" /**< @brief LZG library version string */
|
#define LZG_VERSION "1.0.10" /**< @brief LZG library version string */
|
||||||
#define LZG_VERNUM 0x0100000a /**< @brief LZG library version number (strictly */
|
#define LZG_VERNUM 0x0100000a /**< @brief LZG library version number (strictly */
|
||||||
/* incremental) */
|
/* incremental) */
|
||||||
|
@ -316,4 +320,8 @@ lzg_uint32_t LZG_Version(void);
|
||||||
*/
|
*/
|
||||||
const char* LZG_VersionString(void);
|
const char* LZG_VersionString(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // _LIBLZG_H_
|
#endif // _LIBLZG_H_
|
||||||
|
|
|
@ -3,6 +3,10 @@
|
||||||
*** Chroma ***
|
*** Chroma ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <kernel/system/pci.h>
|
#include <kernel/system/pci.h>
|
||||||
|
@ -179,3 +183,7 @@ void E1000InterruptFired(INTERRUPT_FRAME* InterruptContext);
|
||||||
uint8_t* E1000GetMAC(e1000_device_t* Device);
|
uint8_t* E1000GetMAC(e1000_device_t* Device);
|
||||||
// Send a packet
|
// Send a packet
|
||||||
int E1000Send(e1000_device_t* Device, const void* Data, uint16_t Length);
|
int E1000Send(e1000_device_t* Device, const void* Data, uint16_t Length);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -1,5 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/************************
|
/************************
|
||||||
*** Team Kitty, 2020 ***
|
*** Team Kitty, 2020 ***
|
||||||
*** Chroma ***
|
*** Chroma ***
|
||||||
|
@ -21,5 +25,5 @@
|
||||||
#include <lainlib/compression/lzg.h>
|
#include <lainlib/compression/lzg.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
#include <lainlib/vector/vector.h>
|
} // extern "C"
|
||||||
#endif
|
#endif
|
|
@ -1,5 +1,9 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct list_entry {
|
typedef struct list_entry {
|
||||||
struct list_entry* Previous;
|
struct list_entry* Previous;
|
||||||
struct list_entry* Next;
|
struct list_entry* Next;
|
||||||
|
@ -32,3 +36,7 @@ bool ListIsEmpty(list_entry_t* Head);
|
||||||
for(pos = UNSAFE_CAST((head)->next, typeof(*(pos)), member); &pos->member != (head); pos = LISTNEXT(pos, member))
|
for(pos = UNSAFE_CAST((head)->next, typeof(*(pos)), member); &pos->member != (head); pos = LISTNEXT(pos, member))
|
||||||
|
|
||||||
#define LASTENTRY 0
|
#define LASTENTRY 0
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -5,6 +5,10 @@
|
||||||
*** Chroma ***
|
*** Chroma ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef volatile int spinlock_t;
|
typedef volatile int spinlock_t;
|
||||||
|
|
||||||
/* A set of macros that acquire and release a mutex spinlock. */
|
/* A set of macros that acquire and release a mutex spinlock. */
|
||||||
|
@ -18,3 +22,7 @@ typedef volatile int spinlock_t;
|
||||||
#define SPUNLOCK(name) \
|
#define SPUNLOCK(name) \
|
||||||
__sync_synchronize(); \
|
__sync_synchronize(); \
|
||||||
name = 0;
|
name = 0;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -7,6 +7,11 @@
|
||||||
*** Chroma ***
|
*** Chroma ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* This file provides a simple implementation of a ticket-based locking system.
|
/* This file provides a simple implementation of a ticket-based locking system.
|
||||||
* You should probably prefer Spinlock over Ticketlock.
|
* You should probably prefer Spinlock over Ticketlock.
|
||||||
*
|
*
|
||||||
|
@ -17,10 +22,6 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t NowServing;
|
size_t NowServing;
|
||||||
size_t NextTicket;
|
size_t NextTicket;
|
||||||
|
@ -34,6 +35,6 @@ bool TicketAttemptLock(ticketlock_t* Lock);
|
||||||
|
|
||||||
void TicketUnlock(ticketlock_t* Lock);
|
void TicketUnlock(ticketlock_t* Lock);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
|
@ -6,6 +6,14 @@
|
||||||
*** Chroma ***
|
*** Chroma ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
size_t strlen(const char* String);
|
size_t strlen(const char* String);
|
||||||
|
|
||||||
bool strcmp(char* a, const char* b);
|
bool strcmp(char* a, const char* b);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -1,129 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <kernel/system/memory.h>
|
|
||||||
|
|
||||||
/************************
|
|
||||||
*** Team Kitty, 2022 ***
|
|
||||||
*** Lainlib ***
|
|
||||||
***********************/
|
|
||||||
|
|
||||||
// integer typedefs
|
|
||||||
using u32 = uint32_t;
|
|
||||||
|
|
||||||
namespace lainlib {
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct vector {
|
|
||||||
T& operator [] (u32 i) {
|
|
||||||
return this->data[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
T operator [] (u32 i) const {
|
|
||||||
return this->data[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 size() {
|
|
||||||
return bytes / sizeof(T);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename access_type>
|
|
||||||
access_type handle_read(const void *buf) {
|
|
||||||
access_type v;
|
|
||||||
memcpy(&v,buf,sizeof(access_type));
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename access_type>
|
|
||||||
void handle_write(void *buf, access_type v) {
|
|
||||||
memcpy(buf,&v,sizeof(access_type));
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert at end as a var as a raw set of bytes into the Array
|
|
||||||
template<typename Y>
|
|
||||||
void emplace_back(Y v) {
|
|
||||||
const u32 len = sizeof(v);
|
|
||||||
|
|
||||||
reserve(len);
|
|
||||||
|
|
||||||
// actually write in the data
|
|
||||||
handle_write(&data[size()], v);
|
|
||||||
bytes += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
T pop() {
|
|
||||||
const T v = data[size() - 1];
|
|
||||||
bytes -= sizeof(v);
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reserve_raw(u32 size) {
|
|
||||||
capacity = size;
|
|
||||||
data = (T*)krealloc(data, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void resize(u32 in) {
|
|
||||||
const u32 len = in * sizeof(T);
|
|
||||||
|
|
||||||
const u32 old_len = size();
|
|
||||||
|
|
||||||
reserve_raw( bytes);
|
|
||||||
bytes = len;
|
|
||||||
|
|
||||||
// default initialize the new elements
|
|
||||||
for(u32 i = old_len; i < size(); i++) {
|
|
||||||
data[i] = {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure there is enough left for the allocation we are doing
|
|
||||||
void reserve(u32 size) {
|
|
||||||
const u32 free_size = capacity - bytes;
|
|
||||||
|
|
||||||
// we have room to just dump this in
|
|
||||||
if(free_size >= size) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
const u32 new_capacity = (capacity + size) * 2;
|
|
||||||
reserve_raw(new_capacity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// raw mem read and writes over the array
|
|
||||||
T read_var(u32 idx) {
|
|
||||||
return handle_read<T>(data[idx]);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Y>
|
|
||||||
void write_var(u32 idx, T v) {
|
|
||||||
return handle_write(data[idx], v);
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert raw memory block into the array
|
|
||||||
void push_mem(const void* newData, u32 size)
|
|
||||||
{
|
|
||||||
reserve(size);
|
|
||||||
|
|
||||||
memcpy(data[bytes], newData, size);
|
|
||||||
bytes += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroy() {
|
|
||||||
if(data) {
|
|
||||||
kfree(data);
|
|
||||||
data = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes = 0;
|
|
||||||
capacity = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
T* data = nullptr;
|
|
||||||
|
|
||||||
// in raw bytes
|
|
||||||
u32 bytes = 0;
|
|
||||||
u32 capacity = 0;
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -22,7 +22,7 @@ Device::GenericStorage* StorageDevicesArray[MAX_STORAGE_DEVICES];
|
||||||
size_t CurrentStorageDevice = 0;
|
size_t CurrentStorageDevice = 0;
|
||||||
|
|
||||||
// Internal storage. TODO: Make this not a pain to maintain
|
// Internal storage. TODO: Make this not a pain to maintain
|
||||||
const char* DeviceNames[] = {"Storage", "Internal", "Peripheral", "Networking"};
|
const char* DeviceNames[] = {"Storage", "Keyboard", "Networking"};
|
||||||
|
|
||||||
|
|
||||||
// Add a device pointer to the managed list.
|
// Add a device pointer to the managed list.
|
||||||
|
@ -30,7 +30,7 @@ void Device::RegisterDevice(Device::GenericDevice* Device) {
|
||||||
DevicesArray[CurrentDevice] = Device;
|
DevicesArray[CurrentDevice] = Device;
|
||||||
Device->DeviceID = CurrentDevice;
|
Device->DeviceID = CurrentDevice;
|
||||||
CurrentDevice++;
|
CurrentDevice++;
|
||||||
SerialPrintf("[ DEV] Registered device %d called %s of type %s\r\n", CurrentDevice - 1, Device->GetName(),
|
SerialPrintf("[DEVICE] Registered device %d called %s of type %s\r\n", CurrentDevice - 1, Device->GetName(),
|
||||||
DeviceNames[Device->GetType()]);
|
DeviceNames[Device->GetType()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
160
src/drivers/devices/input/keyboard.cpp
Normal file
160
src/drivers/devices/input/keyboard.cpp
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
#include <kernel/chroma.h>
|
||||||
|
#include <driver/keyboard.h>
|
||||||
|
|
||||||
|
/************************
|
||||||
|
*** Team Kitty, 2020 ***
|
||||||
|
*** Chroma ***
|
||||||
|
***********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* This file contains (mostly unused) implementations of a full PS/2 keyboard driver.
|
||||||
|
*
|
||||||
|
* It provides provisions for full 2-way communication, as well as auxiliary key commands.
|
||||||
|
* //TODO: Media keys?
|
||||||
|
*
|
||||||
|
* Once this driver is to a workable state, I would like to start adding a proper keyboard buffer,
|
||||||
|
* which will integrate with a window system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
KBD_FLAGS KbdFlags;
|
||||||
|
|
||||||
|
char keys[128] = {
|
||||||
|
0, 27,
|
||||||
|
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
|
||||||
|
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
|
||||||
|
0,
|
||||||
|
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '#',
|
||||||
|
0,
|
||||||
|
'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/',
|
||||||
|
0,
|
||||||
|
'*', 0,
|
||||||
|
' ', 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
'-',
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
'+',
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0, 0, 0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
|
||||||
|
KeyboardCallback KeyboardCallbacks[16] = {
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static int CurrentCallback = 0;
|
||||||
|
|
||||||
|
int SetupKBCallback(void (* Handler)(KeyboardData Frame)) {
|
||||||
|
KeyboardCallbacks[CurrentCallback++] = Handler;
|
||||||
|
return CurrentCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UninstallKBCallback(int Number) {
|
||||||
|
KeyboardCallbacks[Number] = NULL; // 0 is used in the common check to make sure that the function is callable.
|
||||||
|
// This removes this callback from that check, ergo the function will no longer be called.
|
||||||
|
}
|
||||||
|
|
||||||
|
void KbdEcho() {
|
||||||
|
if (!KbdFlags.EchoCount) {
|
||||||
|
if (!KbdFlags.Echo) {
|
||||||
|
Send8042(0xEE);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
KbdFlags.EchoCount = 0;
|
||||||
|
KbdFlags.Echo = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void UpdateKeyboard(uint8_t msg) {
|
||||||
|
|
||||||
|
switch (msg) {
|
||||||
|
case 0x0:
|
||||||
|
KbdFlags.Error = 1;
|
||||||
|
//ResendBuffer();
|
||||||
|
break;
|
||||||
|
case 0xAA:
|
||||||
|
KbdFlags.SelfTest = 1;
|
||||||
|
break;
|
||||||
|
case 0xEE:
|
||||||
|
KbdFlags.Echo = 0;
|
||||||
|
KbdFlags.EchoCount = 2;
|
||||||
|
KbdEcho();
|
||||||
|
break;
|
||||||
|
case 0xFA:
|
||||||
|
KbdFlags.ACK = 1;
|
||||||
|
//ProgressBuffer();
|
||||||
|
break;
|
||||||
|
case 0xFC:
|
||||||
|
case 0xFD:
|
||||||
|
KbdFlags.SelfTest = 0;
|
||||||
|
KbdFlags.Error = 1;
|
||||||
|
//RestartKbd();
|
||||||
|
break;
|
||||||
|
case 0xFE:
|
||||||
|
//ResendBuffer();
|
||||||
|
break;
|
||||||
|
case 0xFF:
|
||||||
|
KbdFlags.Error = 1;
|
||||||
|
//ResendBuffer();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyboardData data = (KeyboardData) {
|
||||||
|
.Char = msg > 0x80 && msg < 0xD8 ? keys[msg - 0x80] : keys[msg],
|
||||||
|
.Scancode = static_cast<char>(msg),
|
||||||
|
.Pressed = !(msg > 0x80 && msg < 0xD8),
|
||||||
|
};
|
||||||
|
|
||||||
|
void (* Handler)(KeyboardData data);
|
||||||
|
|
||||||
|
for (size_t handlerNum = 0; handlerNum < 16; handlerNum++) {
|
||||||
|
Handler = KeyboardCallbacks[handlerNum];
|
||||||
|
if (Handler) {
|
||||||
|
Handler(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Send8042(size_t info) {
|
||||||
|
for (size_t i = 0; i < 8; i++) {
|
||||||
|
unsigned char chr = (unsigned char) info;
|
||||||
|
if (chr != 0) {
|
||||||
|
WritePort(0x60, chr, 1);
|
||||||
|
WaitFor8042();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaitFor8042() {
|
||||||
|
|
||||||
|
bool full = true;
|
||||||
|
while (full) {
|
||||||
|
full = ReadPort(0x64, 1) & 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -2,8 +2,6 @@
|
||||||
#include <kernel/system/acpi/madt.h>
|
#include <kernel/system/acpi/madt.h>
|
||||||
#include <kernel/system/io.h>
|
#include <kernel/system/io.h>
|
||||||
#include <kernel/system/memory.h>
|
#include <kernel/system/memory.h>
|
||||||
#include "kernel/system/core.hpp"
|
|
||||||
#include "kernel/chroma.h"
|
|
||||||
|
|
||||||
/************************
|
/************************
|
||||||
*** Team Kitty, 2021 ***
|
*** Team Kitty, 2021 ***
|
||||||
|
@ -53,7 +51,7 @@ void APIC::Enable() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void APIC::SendEOI() {
|
void APIC::SendEOI() {
|
||||||
*((volatile uint32_t*) 0xfee000B0) = 0;
|
WriteRegister(Registers::EOI, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool APIC::IsReady() {
|
bool APIC::IsReady() {
|
||||||
|
@ -61,20 +59,14 @@ bool APIC::IsReady() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void APIC::Init() {
|
void APIC::Init() {
|
||||||
Device::RegisterDevice(this);
|
SerialPrintf("[ACPI] Enabling APICs...");
|
||||||
|
|
||||||
SerialPrintf("[ ACPI] Enabling APICs...\r\n");
|
|
||||||
|
|
||||||
SerialPrintf("[ ACPI] Memory Mapping APICs..\r\n");
|
|
||||||
for (int i = 0; i < 3; i++) {
|
|
||||||
MapVirtualPage(&KernelAddressSpace, (size_t) Address + i * PAGE_SIZE, (size_t) Address + i * PAGE_SIZE, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
Address = (void*) ACPI::MADT::instance->LocalAPICBase;
|
Address = (void*) ACPI::MADT::instance->LocalAPICBase;
|
||||||
SerialPrintf("[ MADT] The APIC of this core is at 0x%p\r\n", (size_t) Address);
|
|
||||||
|
// TODO: Check whether the identity mapping covers this address
|
||||||
|
|
||||||
if (Address == nullptr) {
|
if (Address == nullptr) {
|
||||||
SerialPrintf("[ ACPI] Unable to locate APICs.\r\n");
|
SerialPrintf("[ACPI] Unable to locate APICs.");
|
||||||
for (;;) { }
|
for (;;) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,9 +74,13 @@ void APIC::Init() {
|
||||||
WriteModelSpecificRegister(0x1B, (ReadModelSpecificRegister(0x1B) | 0x800) & ~(1 << 10));
|
WriteModelSpecificRegister(0x1B, (ReadModelSpecificRegister(0x1B) | 0x800) & ~(1 << 10));
|
||||||
Enable();
|
Enable();
|
||||||
|
|
||||||
SerialPrintf("[ ACPI] Enabling Global APIC..\r\n");
|
// Disable PIC1 and 2
|
||||||
|
WritePort(0x21, 0xFF, 1);
|
||||||
|
WritePort(0xA1, 0xFF, 1);
|
||||||
|
|
||||||
|
SerialPrintf("[ACPI] Enabling Global APIC..");
|
||||||
IOAPICs = ACPI::MADT::instance->GetIOApicEntries();
|
IOAPICs = ACPI::MADT::instance->GetIOApicEntries();
|
||||||
SerialPrintf("[ ACPI] Enabling Interrupt Source Overrides..\r\n");
|
SerialPrintf("[ACPI] Enabling Interrupt Source Overrides..");
|
||||||
ISOs = ACPI::MADT::instance->GetISOEntries();
|
ISOs = ACPI::MADT::instance->GetISOEntries();
|
||||||
|
|
||||||
Ready = true;
|
Ready = true;
|
||||||
|
@ -112,8 +108,8 @@ void APIC::InitializeCore(int Core, size_t EntryPoint) {
|
||||||
WriteRegister(Registers::ICR1, 0x600 | ((uint32_t) (EntryPoint / PAGE_SIZE)));
|
WriteRegister(Registers::ICR1, 0x600 | ((uint32_t) (EntryPoint / PAGE_SIZE)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void APIC::SetInternal(uint8_t Vector, uint32_t GSI, uint16_t Flags, int CoreID, int Status) {
|
void APIC::SetInternal(uint8_t Vector, uint32_t GSI, uint16_t Flags, int Core, int Status) {
|
||||||
|
UNUSED(Core);
|
||||||
size_t temp = Vector;
|
size_t temp = Vector;
|
||||||
int64_t target = -1;
|
int64_t target = -1;
|
||||||
|
|
||||||
|
@ -125,7 +121,7 @@ void APIC::SetInternal(uint8_t Vector, uint32_t GSI, uint16_t Flags, int CoreID,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target == -1) {
|
if (target == -1) {
|
||||||
SerialPrintf("[ APIC] No ISO found when setting up redirect.\r\n");
|
SerialPrintf("[APIC] No ISO found when setting up redirect.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,24 +134,6 @@ void APIC::SetInternal(uint8_t Vector, uint32_t GSI, uint16_t Flags, int CoreID,
|
||||||
if (!Status)
|
if (!Status)
|
||||||
temp |= (1 << 16);
|
temp |= (1 << 16);
|
||||||
|
|
||||||
temp |= (((size_t) Core::GetCore(CoreID)->LocalAPIC) << 56);
|
// TODO
|
||||||
uint32_t IORegister = (GSI - IOAPICs[target]->GSI) * 2 + 0x10;
|
|
||||||
|
|
||||||
SerialPrintf("[ APIC] Setting interrupt %u, redirect %u, on LAPIC %u(%u) of core %u, address 0x%p, register 0x%p, data 0x%p\r\n", GSI, Vector, Core::GetCore(CoreID)->LocalAPIC, target, CoreID, IOAPICs[target]->Address, IORegister, temp);
|
|
||||||
|
|
||||||
WriteIO(IOAPICs[target]->Address, IORegister, (uint32_t) temp);
|
|
||||||
WriteIO(IOAPICs[target]->Address, IORegister + 1, (uint32_t)(temp >> 32));
|
|
||||||
}
|
|
||||||
|
|
||||||
void APIC::Set(int CPU, uint8_t IRQ, int Enabled) {
|
|
||||||
for(size_t i = 0; ISOs[i] != 0; i++) {
|
|
||||||
// We need to make sure we take into account the overrides, so check whether any IRQ is overriden
|
|
||||||
if (ISOs[i]->IRQ == IRQ) {
|
|
||||||
SetInternal(ISOs[i]->IRQ + 0x20, ISOs[i]->Interrupt, ISOs[i]->Flags, CPU, Enabled);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there are no overrides, we can just remap it upwards
|
|
||||||
SetInternal(IRQ + 0x20, IRQ, 0, CPU, Enabled);
|
|
||||||
}
|
}
|
|
@ -1,170 +0,0 @@
|
||||||
#include <driver/io/ps2_keyboard.h>
|
|
||||||
#include <kernel/chroma.h>
|
|
||||||
#include "driver/io/apic.h"
|
|
||||||
|
|
||||||
/************************
|
|
||||||
*** Team Kitty, 2022 ***
|
|
||||||
*** Chroma ***
|
|
||||||
***********************/
|
|
||||||
|
|
||||||
char keys[128] = {
|
|
||||||
0, 27,
|
|
||||||
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
|
|
||||||
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
|
|
||||||
0,
|
|
||||||
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '#',
|
|
||||||
0,
|
|
||||||
'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/',
|
|
||||||
0,
|
|
||||||
'*', 0,
|
|
||||||
' ', 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
'-',
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
'+',
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0, 0, 0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
};
|
|
||||||
|
|
||||||
char shiftedKeys[128] = {
|
|
||||||
0,
|
|
||||||
0, // ESC
|
|
||||||
33, // !
|
|
||||||
64, // @
|
|
||||||
35, // #
|
|
||||||
36, // $
|
|
||||||
37, // %
|
|
||||||
94, // ^
|
|
||||||
38, // &
|
|
||||||
42, // *
|
|
||||||
40, // (
|
|
||||||
41, // )
|
|
||||||
95, // _
|
|
||||||
43, // +
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
81, // Q
|
|
||||||
87,
|
|
||||||
69,
|
|
||||||
82,
|
|
||||||
84,
|
|
||||||
89,
|
|
||||||
85,
|
|
||||||
73,
|
|
||||||
79,
|
|
||||||
80, // P
|
|
||||||
123, // {
|
|
||||||
125, // }
|
|
||||||
0,
|
|
||||||
10,
|
|
||||||
65, // A
|
|
||||||
83,
|
|
||||||
68,
|
|
||||||
70,
|
|
||||||
71,
|
|
||||||
72,
|
|
||||||
74,
|
|
||||||
75,
|
|
||||||
76, // L
|
|
||||||
58, // :
|
|
||||||
34, // "
|
|
||||||
126, // ~
|
|
||||||
0,
|
|
||||||
124, // |
|
|
||||||
90, // Z
|
|
||||||
88,
|
|
||||||
67,
|
|
||||||
86,
|
|
||||||
66,
|
|
||||||
78,
|
|
||||||
77, // M
|
|
||||||
60, // <
|
|
||||||
62, // >
|
|
||||||
63, // ?
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
32, // SPACE
|
|
||||||
};
|
|
||||||
|
|
||||||
Device::PS2Keyboard* Device::PS2Keyboard::driver;
|
|
||||||
|
|
||||||
using namespace Device;
|
|
||||||
|
|
||||||
void IRQRedirect(INTERRUPT_FRAME* irq) {
|
|
||||||
UNUSED(irq);
|
|
||||||
PS2Keyboard::driver->InterruptHandler();
|
|
||||||
}
|
|
||||||
|
|
||||||
PS2Keyboard::PS2Keyboard() {
|
|
||||||
driver = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PS2Keyboard::setState(bool state, uint8_t key) {
|
|
||||||
keyStates[key] = state;
|
|
||||||
|
|
||||||
if(state)
|
|
||||||
lastPress = key;
|
|
||||||
else
|
|
||||||
lastPress = 0;
|
|
||||||
|
|
||||||
if(callback != nullptr)
|
|
||||||
callback[key] = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PS2Keyboard::isPressed(uint8_t key) const {
|
|
||||||
return keyStates[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
void PS2Keyboard::Init() {
|
|
||||||
Device::RegisterDevice(this);
|
|
||||||
buffer.reserve(100);
|
|
||||||
|
|
||||||
for (size_t idx = 0; idx < 128; idx++) {
|
|
||||||
keyStates[idx] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstallIRQ(1, IRQRedirect);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PS2Keyboard::InterruptHandler() {
|
|
||||||
uint8_t state = ReadPort(0x64, 1);
|
|
||||||
|
|
||||||
// while keyboard has input and the buffer is not empty
|
|
||||||
while (state & 1 && !(state & 0x20)) {
|
|
||||||
uint8_t keycode = ReadPort(0x60, 1);
|
|
||||||
uint8_t scancode = keycode & 0x7f;
|
|
||||||
uint8_t keystate = !(keycode & 0x80);
|
|
||||||
|
|
||||||
if (keystate)
|
|
||||||
SerialPrintf("[ KEY] %c pressed.\r\n", keys[scancode]);
|
|
||||||
|
|
||||||
state = ReadPort(0x64, 1);
|
|
||||||
setState(keystate, scancode);
|
|
||||||
KeyboardData data { keys[scancode], (char) scancode, (bool) keystate };
|
|
||||||
buffer.emplace_back(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PS2Keyboard::SetCallback(uint32_t* data) {
|
|
||||||
callback = (uint8_t*) data;
|
|
||||||
|
|
||||||
for (size_t idx = 0; idx < 128; idx++) {
|
|
||||||
callback[idx] = false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,6 +4,10 @@
|
||||||
*** Chroma ***
|
*** Chroma ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file provides utility functions for parsing ELF headers.
|
* This file provides utility functions for parsing ELF headers.
|
||||||
* This exists so that the kernel can find itself for remapping,
|
* This exists so that the kernel can find itself for remapping,
|
||||||
|
@ -88,3 +92,7 @@ int ParseKernelHeader(size_t InitrdPtr) {
|
||||||
return flag;
|
return flag;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -1,4 +1,5 @@
|
||||||
#include <kernel/chroma.h>
|
#include <kernel/chroma.h>
|
||||||
|
#include <driver/keyboard.h>
|
||||||
#include <kernel/video/draw.h>
|
#include <kernel/video/draw.h>
|
||||||
#include <editor/main.h>
|
#include <editor/main.h>
|
||||||
|
|
||||||
|
@ -10,9 +11,11 @@
|
||||||
/**
|
/**
|
||||||
* Contains startup and setup routines for the Chroma Editor.
|
* Contains startup and setup routines for the Chroma Editor.
|
||||||
*/
|
*/
|
||||||
|
static KeyboardCallback KernelHandler;
|
||||||
|
|
||||||
void Editor::StartEditor(int callbackID) {
|
void Editor::StartEditor(int callbackID) {
|
||||||
UNUSED(callbackID);
|
KernelHandler = KeyboardCallbacks[callbackID];
|
||||||
|
|
||||||
EditorLayout layout;
|
EditorLayout layout;
|
||||||
layout.ScreenHeight = PrintInfo.screenHeight;
|
layout.ScreenHeight = PrintInfo.screenHeight;
|
||||||
layout.ScreenWidth = PrintInfo.screenWidth;
|
layout.ScreenWidth = PrintInfo.screenWidth;
|
||||||
|
|
|
@ -1,131 +0,0 @@
|
||||||
#************************
|
|
||||||
#*** 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.
|
|
||||||
|
|
||||||
.code16
|
|
||||||
.equ BASE, 0x1000
|
|
||||||
|
|
||||||
.global stack
|
|
||||||
.extern initcpu
|
|
||||||
|
|
||||||
.extern coreidt
|
|
||||||
|
|
||||||
.extern ProtectedGDT
|
|
||||||
.extern LongGDT
|
|
||||||
|
|
||||||
# 16-bit startup.
|
|
||||||
# Initialize registers.
|
|
||||||
# Load GDT
|
|
||||||
# Set flags
|
|
||||||
# Immediately jump to protected mode.
|
|
||||||
|
|
||||||
.global startCore
|
|
||||||
startCore:
|
|
||||||
cli
|
|
||||||
mov $0x0, %ax
|
|
||||||
mov %ax, %ds
|
|
||||||
mov %ax, %es
|
|
||||||
mov %ax, %fs
|
|
||||||
mov %ax, %gs
|
|
||||||
mov %ax, %ss
|
|
||||||
.code64
|
|
||||||
lgdt ProtectedGDT
|
|
||||||
.code16
|
|
||||||
mov %cr0, %eax
|
|
||||||
or $0x1, %ax
|
|
||||||
mov %eax, %cr0
|
|
||||||
|
|
||||||
ljmpl $0x8, $startCore32
|
|
||||||
|
|
||||||
.code32
|
|
||||||
|
|
||||||
# Protected mode setup.
|
|
||||||
# Set page tables
|
|
||||||
# Set PAE
|
|
||||||
# Immediately jump to long mode.
|
|
||||||
|
|
||||||
.section .text
|
|
||||||
startCore32:
|
|
||||||
mov $0x10, %bx
|
|
||||||
mov %bx, %ds
|
|
||||||
mov %bx, %es
|
|
||||||
mov %bx, %ss
|
|
||||||
|
|
||||||
mov $0xA000, %eax
|
|
||||||
mov %eax, %cr3
|
|
||||||
|
|
||||||
mov %cr4, %eax # Enable PAE
|
|
||||||
or $32, %eax # 1 << 5
|
|
||||||
or $128, %eax # 1 << 7
|
|
||||||
mov %eax, %cr4
|
|
||||||
|
|
||||||
mov $0xC0000080, %ecx
|
|
||||||
rdmsr
|
|
||||||
or $256, %eax # 1 << 8
|
|
||||||
wrmsr
|
|
||||||
|
|
||||||
mov %cr0, %eax
|
|
||||||
or $2147483648, %eax # 1 << 31
|
|
||||||
mov %eax, %cr0
|
|
||||||
.code64
|
|
||||||
lgdt LongGDT
|
|
||||||
.code32
|
|
||||||
ljmp $0x8, $startCore64
|
|
||||||
|
|
||||||
# Long mode setup.
|
|
||||||
# Prepare registers.
|
|
||||||
# Set flags
|
|
||||||
# Load the final GDT and IDT
|
|
||||||
# Jump to the leave function.
|
|
||||||
|
|
||||||
.code64
|
|
||||||
startCore64:
|
|
||||||
mov $0x10, %ax
|
|
||||||
mov %ax, %ds
|
|
||||||
mov %ax, %es
|
|
||||||
mov %ax, %ss
|
|
||||||
|
|
||||||
mov $0x0, %ax
|
|
||||||
mov %ax, %ds
|
|
||||||
mov %ax, %gs
|
|
||||||
|
|
||||||
lgdt LongGDT
|
|
||||||
lidt coreidt
|
|
||||||
|
|
||||||
mov $0x0, %rbp
|
|
||||||
push $0
|
|
||||||
popf
|
|
||||||
|
|
||||||
mov (leave), %rax
|
|
||||||
jmp leave
|
|
||||||
|
|
||||||
# Final setup.
|
|
||||||
# Set some flags in registers.
|
|
||||||
# Jump into C++ code.
|
|
||||||
|
|
||||||
leave:
|
|
||||||
push %rbp
|
|
||||||
|
|
||||||
mov %cr0, %rax
|
|
||||||
btr $2, %eax
|
|
||||||
bts $1, %eax
|
|
||||||
mov %rax, %cr0
|
|
||||||
|
|
||||||
mov %cr4, %rax
|
|
||||||
bts $9, %eax
|
|
||||||
bts $10, %eax
|
|
||||||
mov %rax, %cr4
|
|
||||||
|
|
||||||
call initcpu
|
|
||||||
|
|
||||||
.global endCore
|
|
||||||
endCore:
|
|
|
@ -1,29 +1,27 @@
|
||||||
.intel_syntax noprefix
|
;************************
|
||||||
#************************
|
;*** Team Kitty, 2021 ***
|
||||||
#*** Team Kitty, 2021 ***
|
;*** Chroma ***
|
||||||
#*** Chroma ***
|
;************************
|
||||||
#************************
|
|
||||||
|
|
||||||
# Initial startup routines for new cores.
|
; Initial startup routines for new cores.
|
||||||
# New cores start in 16 bit real mode.
|
; New cores start in 16 bit real mode.
|
||||||
# Because of this, this is the only necessary assembler file in the OS.
|
; Because of this, this is the only necessary assembler file in the OS.
|
||||||
|
|
||||||
# First, bring them up to Protected and Long mode.
|
; First, bring them up to Protected and Long mode.
|
||||||
# Then enable all necessary auxiliary features.
|
; Then enable all necessary auxiliary features.
|
||||||
# Pass off to the CPP code to handle the heavy work, we just want the core running.
|
; Pass off to the CPP code to handle the heavy work, we just want the core running.
|
||||||
|
|
||||||
.intel_syntax
|
[bits 16]
|
||||||
|
BASE equ 0x1000
|
||||||
|
|
||||||
.code16
|
global stack
|
||||||
.equ BASE, 0x1000
|
extern initcpu
|
||||||
|
|
||||||
.global stack
|
extern coreidt
|
||||||
.extern initcpu
|
extern coregdt
|
||||||
|
|
||||||
.extern coreidt
|
global startCore
|
||||||
.extern coregdt
|
startCore:
|
||||||
|
|
||||||
.global startCore
|
|
||||||
cli
|
cli
|
||||||
mov ax, 0x0
|
mov ax, 0x0
|
||||||
mov ds, ax
|
mov ds, ax
|
||||||
|
@ -40,9 +38,9 @@
|
||||||
|
|
||||||
jmp 0x8:(startCore32 - startCore + BASE)
|
jmp 0x8:(startCore32 - startCore + BASE)
|
||||||
|
|
||||||
.code32
|
[bits 32]
|
||||||
|
|
||||||
.section .text
|
section .text
|
||||||
startCore32:
|
startCore32:
|
||||||
mov bx, 0x10
|
mov bx, 0x10
|
||||||
mov ds, bx
|
mov ds, bx
|
||||||
|
@ -69,7 +67,7 @@ startCore32:
|
||||||
lgdt [gdt_long - startCore + BASE]
|
lgdt [gdt_long - startCore + BASE]
|
||||||
jmp 8:(startCore64 - startCore + BASE)
|
jmp 8:(startCore64 - startCore + BASE)
|
||||||
|
|
||||||
.code64
|
[bits 64]
|
||||||
startCore64:
|
startCore64:
|
||||||
mov ax, 0x10
|
mov ax, 0x10
|
||||||
mov ds, ax
|
mov ds, ax
|
||||||
|
|
|
@ -1,35 +1,42 @@
|
||||||
#include <kernel/chroma.h>
|
#include <kernel/chroma.h>
|
||||||
#include <kernel/video/draw.h>
|
#include <kernel/video/draw.h>
|
||||||
|
#include <driver/keyboard.h>
|
||||||
#include <editor/main.h>
|
#include <editor/main.h>
|
||||||
#include "kernel/system/acpi/rsdt.h"
|
|
||||||
#include "kernel/system/acpi/madt.h"
|
|
||||||
#include "driver/io/apic.h"
|
|
||||||
#include "driver/io/ps2_keyboard.h"
|
|
||||||
|
|
||||||
/************************
|
/************************
|
||||||
*** Team Kitty, 2020 ***
|
*** Team Kitty, 2020 ***
|
||||||
*** Chroma ***
|
*** Chroma ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/* This file is the entry point to the system.
|
/* This file is the entry point to the system.
|
||||||
* It dictates the order of operations of everything the kernel actually does.
|
* It dictates the order of operations of everything the kernel actually does.
|
||||||
* If a function isn't fired here, directly or indirectly, it is not run.
|
* If a function isn't fired here, directly or indirectly, it is not run.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool KernelLoaded = false;
|
static bool KernelLoaded = false;
|
||||||
|
|
||||||
address_space_t KernelAddressSpace;
|
address_space_t KernelAddressSpace;
|
||||||
|
|
||||||
|
|
||||||
size_t KernelAddr = (size_t) &LoadAddr;
|
size_t KernelAddr = (size_t) &LoadAddr;
|
||||||
size_t KernelEnd = (size_t) &end;
|
size_t KernelEnd = (size_t) &end;
|
||||||
|
|
||||||
|
void PrintPressedChar(KeyboardData data);
|
||||||
int CharPrinterCallbackID;
|
int CharPrinterCallbackID;
|
||||||
void TrackInternalBuffer(Device::GenericKeyboard::KeyboardData data);
|
void TrackInternalBuffer(KeyboardData data);
|
||||||
int InternalBufferID;
|
int InternalBufferID;
|
||||||
|
|
||||||
size_t BufferLength = 0;
|
size_t BufferLength = 0;
|
||||||
char* InternalBuffer;
|
char* InternalBuffer;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* C++ code! Scary!
|
* C++ code! Scary!
|
||||||
* This is a temporary measure to experiment with the Editor system.
|
* This is a temporary measure to experiment with the Editor system.
|
||||||
|
@ -63,7 +70,9 @@ extern "C" int Main(void) {
|
||||||
PrepareCPU();
|
PrepareCPU();
|
||||||
|
|
||||||
PCIEnumerate();
|
PCIEnumerate();
|
||||||
|
|
||||||
InitMemoryManager();
|
InitMemoryManager();
|
||||||
|
|
||||||
InitPaging();
|
InitPaging();
|
||||||
|
|
||||||
Printf("Paging complete. System initialized.\n\r");
|
Printf("Paging complete. System initialized.\n\r");
|
||||||
|
@ -77,24 +86,26 @@ extern "C" int Main(void) {
|
||||||
|
|
||||||
SetForegroundColor(0x00FFFFFF);
|
SetForegroundColor(0x00FFFFFF);
|
||||||
|
|
||||||
|
CharPrinterCallbackID = SetupKBCallback(&PrintPressedChar);
|
||||||
|
|
||||||
Device::APIC::driver = new Device::APIC();
|
InternalBufferID = SetupKBCallback(&TrackInternalBuffer);
|
||||||
Device::PS2Keyboard::driver = new Device::PS2Keyboard();
|
|
||||||
|
|
||||||
ACPI::RSDP::instance->Init(0);
|
|
||||||
ACPI::MADT::instance->Init();
|
|
||||||
|
|
||||||
Core::PreInit();
|
|
||||||
|
|
||||||
Device::APIC::driver->Init();
|
|
||||||
Device::PS2Keyboard::driver->Init();
|
|
||||||
|
|
||||||
Core::Init();
|
|
||||||
|
|
||||||
for (;;) { }
|
for (;;) { }
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void PrintPressedChar(KeyboardData data) {
|
||||||
|
if (!KernelLoaded) return;
|
||||||
|
|
||||||
|
if (data.Pressed) {
|
||||||
|
SerialPrintf("Key pressed: [\\%c (%x)]\r\n", data.Char, data.Scancode);
|
||||||
|
Printf("%c", data.Char);
|
||||||
|
} else {
|
||||||
|
SerialPrintf("Key released: [\\%c]\r\n", data.Char);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
extern "C" void TrackInternalBuffer(KeyboardData data) {
|
extern "C" void TrackInternalBuffer(KeyboardData data) {
|
||||||
if (!data.Pressed) return;
|
if (!data.Pressed) return;
|
||||||
|
|
||||||
|
@ -128,7 +139,8 @@ extern "C" void TrackInternalBuffer(KeyboardData data) {
|
||||||
InternalBuffer[BufferLength] = data.Char;
|
InternalBuffer[BufferLength] = data.Char;
|
||||||
BufferLength++;
|
BufferLength++;
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
|
|
||||||
|
|
||||||
extern "C" void SomethingWentWrong(const char* Message) {
|
extern "C" void SomethingWentWrong(const char* Message) {
|
||||||
SerialPrintf("Assertion failed! %s\r\n", Message);
|
SerialPrintf("Assertion failed! %s\r\n", Message);
|
||||||
|
|
|
@ -27,6 +27,10 @@
|
||||||
|
|
||||||
#include <lainlib/lainlib.h>
|
#include <lainlib/lainlib.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/*-- PRIVATE -----------------------------------------------------------------*/
|
/*-- PRIVATE -----------------------------------------------------------------*/
|
||||||
|
|
||||||
/* Internal definitions */
|
/* Internal definitions */
|
||||||
|
@ -187,4 +191,8 @@ lzg_uint32_t LZG_Decode(const unsigned char *in, lzg_uint32_t insize,
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
return decodedSize;
|
return decodedSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -8,6 +8,10 @@
|
||||||
*** Lainlib ***
|
*** Lainlib ***
|
||||||
************************/
|
************************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file handles all the logic for interfacing with the E1000 networking device.
|
* This file handles all the logic for interfacing with the E1000 networking device.
|
||||||
* This card is labelled either the Intel I217, or Intel Gigabit 82577LM.
|
* This card is labelled either the Intel I217, or Intel Gigabit 82577LM.
|
||||||
|
@ -351,3 +355,7 @@ int E1000Send(e1000_device_t* Device, const void* Data, uint16_t Length) {
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -5,6 +5,9 @@
|
||||||
*** Lainlib ***
|
*** Lainlib ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
struct mac_address {
|
struct mac_address {
|
||||||
uint8_t MAC[6];
|
uint8_t MAC[6];
|
||||||
|
@ -22,3 +25,7 @@ struct ethernet_packet {
|
||||||
uint16_t Type;
|
uint16_t Type;
|
||||||
uint8_t Payload[];
|
uint8_t Payload[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -1,5 +1,8 @@
|
||||||
#include <lainlib/list/list.h>
|
#include <lainlib/list/list.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
void ListAdd(list_entry_t* Head, list_entry_t* New) {
|
void ListAdd(list_entry_t* Head, list_entry_t* New) {
|
||||||
New->Next = Head->Next;
|
New->Next = Head->Next;
|
||||||
|
@ -26,3 +29,7 @@ void ListRemove(list_entry_t* Entry) {
|
||||||
bool ListIsEmpty(list_entry_t* Head) {
|
bool ListIsEmpty(list_entry_t* Head) {
|
||||||
return Head->Next == Head;
|
return Head->Next == Head;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -2,12 +2,14 @@
|
||||||
|
|
||||||
#define PAUSE __asm__ __volatile__("pause")
|
#define PAUSE __asm__ __volatile__("pause")
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
void TicketLock(ticketlock_t* Lock) {
|
void TicketLock(ticketlock_t* Lock) {
|
||||||
size_t Ticket = __atomic_fetch_add(&Lock->NextTicket, 1, __ATOMIC_RELAXED);
|
size_t Ticket = __atomic_fetch_add(&Lock->NextTicket, 1, __ATOMIC_RELAXED);
|
||||||
__sync_synchronize();
|
__sync_synchronize();
|
||||||
while (__atomic_load_8(&Lock->NowServing, __ATOMIC_ACQUIRE) != Ticket) {
|
while(__atomic_load_8(&Lock->NowServing, __ATOMIC_ACQUIRE) != Ticket) {
|
||||||
PAUSE;
|
PAUSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,8 +17,7 @@ void TicketLock(ticketlock_t* Lock) {
|
||||||
bool TicketAttemptLock(ticketlock_t* Lock) {
|
bool TicketAttemptLock(ticketlock_t* Lock) {
|
||||||
size_t Ticket = __atomic_load_8(&Lock->NowServing, __ATOMIC_RELAXED);
|
size_t Ticket = __atomic_load_8(&Lock->NowServing, __ATOMIC_RELAXED);
|
||||||
__sync_synchronize();
|
__sync_synchronize();
|
||||||
return __atomic_compare_exchange_8(&Lock->NowServing, &Ticket, Ticket + 1, false, __ATOMIC_ACQUIRE,
|
return __atomic_compare_exchange_8(&Lock->NowServing, &Ticket, Ticket + 1, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
|
||||||
__ATOMIC_RELAXED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TicketUnlock(ticketlock_t* Lock) {
|
void TicketUnlock(ticketlock_t* Lock) {
|
||||||
|
@ -25,4 +26,6 @@ void TicketUnlock(ticketlock_t* Lock) {
|
||||||
__atomic_store_8(&Lock->NowServing, NextTicket, __ATOMIC_RELEASE);
|
__atomic_store_8(&Lock->NowServing, NextTicket, __ATOMIC_RELEASE);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -7,6 +7,10 @@
|
||||||
*** Lainlib ***
|
*** Lainlib ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
size_t strlen(const char* String) {
|
size_t strlen(const char* String) {
|
||||||
size_t Len = 0;
|
size_t Len = 0;
|
||||||
while(String[Len] != '\0') {
|
while(String[Len] != '\0') {
|
||||||
|
@ -24,3 +28,7 @@ bool strcmp(char* a, const char* b) {
|
||||||
bI++;
|
bI++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -1,6 +0,0 @@
|
||||||
#include <lainlib/lainlib.h>
|
|
||||||
|
|
||||||
/************************
|
|
||||||
*** Team Kitty, 2022 ***
|
|
||||||
*** Lainlib ***
|
|
||||||
***********************/
|
|
|
@ -18,8 +18,8 @@ size_t MADT::GetEndOfTable() {
|
||||||
return ((size_t) &Header->Header) + Header->Header.Length;
|
return ((size_t) &Header->Header) + Header->Header.Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MADT::Init() {
|
void MADT::Initialize() {
|
||||||
SerialPrintf("[ ACPI] Loading Multiple APIC Descriptor Tables..\r\n");
|
SerialPrintf("[ACPI] Loading Multiple APIC Descriptor Tables..");
|
||||||
Address = ACPI::RSDP::instance->FindEntry("APIC");
|
Address = ACPI::RSDP::instance->FindEntry("APIC");
|
||||||
Header = reinterpret_cast<MADTHeader*>(Address);
|
Header = reinterpret_cast<MADTHeader*>(Address);
|
||||||
|
|
||||||
|
@ -40,7 +40,6 @@ MADT::IOAPICEntry** MADT::GetIOApicEntries() {
|
||||||
|
|
||||||
if (table->Type == MADT::Type::IOAPIC) {
|
if (table->Type == MADT::Type::IOAPIC) {
|
||||||
MADT::IOAPICEntry* io_apic = reinterpret_cast<MADT::IOAPICEntry*>(table);
|
MADT::IOAPICEntry* io_apic = reinterpret_cast<MADT::IOAPICEntry*>(table);
|
||||||
MapVirtualPage(&KernelAddressSpace, io_apic->Address, io_apic->Address, 3);
|
|
||||||
entries[count] = (MADT::IOAPICEntry*) ((size_t) io_apic);
|
entries[count] = (MADT::IOAPICEntry*) ((size_t) io_apic);
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,28 +61,23 @@ void* RSDP::GetFACP(RSDT* Root) {
|
||||||
|
|
||||||
void RSDP::Init(size_t RSDP) {
|
void RSDP::Init(size_t RSDP) {
|
||||||
UNUSED(RSDP);
|
UNUSED(RSDP);
|
||||||
SerialPrintf("[ ACPI] Loading ACPI subsystem..\r\n");
|
SerialPrintf("[ACPI] Loading ACPI subsystem..");
|
||||||
|
|
||||||
Descriptor = (DescriptorV2*) GetRSDP();
|
Descriptor = (DescriptorV2*) GetRSDP();
|
||||||
Table = (RSDT *) TO_DIRECT(Descriptor->Header.RSDT);
|
Table = (RSDT *) TO_DIRECT(Descriptor->Header.RSDT);
|
||||||
|
|
||||||
SerialPrintf("[ RSDP] Dumping RSDT. Table at 0x%p..\r\n", (size_t) Table);
|
SerialPrintf("[RSDP] Dumping RSDT..");
|
||||||
size_t entries = (Table->Header.Length - sizeof(Table->Header)) / 4;
|
auto* table = reinterpret_cast<RSDP::RSDT*>(TO_DIRECT(Descriptor->Header.RSDT));
|
||||||
SerialPrintf("[ RSDP] Found %u entries.\r\n", entries);
|
size_t entries = (table->Header.Length - sizeof(table->Header)) / 4;
|
||||||
|
|
||||||
|
|
||||||
// For each entry: if valid, search for the specified name.
|
// For each entry: if valid, search for the specified name.
|
||||||
for (size_t i = 0; i < entries; i++) {
|
for (size_t i = 0; i < entries; i++) {
|
||||||
if (Table->OtherSDTs[i] == 0x0)
|
if (table->OtherSDTs[i] == 0x0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ACPIHeader* header = (ACPIHeader*) ((size_t) 0 + (uint32_t) Table->OtherSDTs[i]);
|
ACPIHeader* header = reinterpret_cast<ACPIHeader*>(table->OtherSDTs[i]);
|
||||||
char signature[5];
|
SerialPrintf("[RSDP] Entry %d: Signature %.4s, OEM %.6s\n", i, header->Signature, header->OEMID);
|
||||||
memcpy(signature, header->Signature, 4);
|
|
||||||
signature[4] = '\0';
|
|
||||||
char oem[7];
|
|
||||||
memcpy(oem, header->OEMID, 6);
|
|
||||||
oem[6] = '\0';
|
|
||||||
SerialPrintf("[ RSDP] Entry %d: Signature %s, OEM %s\n", i, signature, oem);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,14 +7,17 @@
|
||||||
*** Chroma ***
|
*** Chroma ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
|
extern size_t startCore;
|
||||||
|
extern size_t endCore;
|
||||||
|
|
||||||
int Cores = 0;
|
int Cores = 0;
|
||||||
volatile bool Ready = false;
|
volatile bool Ready = false;
|
||||||
|
|
||||||
Core* Core::Processors[Constants::Core::MAX_CORES];
|
Core Core::Processors[Constants::Core::MAX_CORES];
|
||||||
TSS64 Tasks[Constants::Core::MAX_CORES];
|
TSS64 Tasks[Constants::Core::MAX_CORES];
|
||||||
ACPI::MADT::LAPICEntry* LAPICs[Constants::Core::MAX_CORES];
|
ACPI::MADT::LAPICEntry* LAPICs[Constants::Core::MAX_CORES];
|
||||||
|
|
||||||
extern "C" [[noreturn]] void initcpu() {
|
extern "C" void initcpu() {
|
||||||
// Init APIC
|
// Init APIC
|
||||||
WriteModelSpecificRegister(0x1B, (ReadModelSpecificRegister(0x1B) | 0x800) & ~(1 << 10));
|
WriteModelSpecificRegister(0x1B, (ReadModelSpecificRegister(0x1B) | 0x800) & ~(1 << 10));
|
||||||
Device::APIC::driver->Enable();
|
Device::APIC::driver->Enable();
|
||||||
|
@ -22,6 +25,7 @@ extern "C" [[noreturn]] void initcpu() {
|
||||||
__asm__ __volatile__("mov %%fs, %0" : : "r" (Device::APIC::driver->GetCurrentCore()) : );
|
__asm__ __volatile__("mov %%fs, %0" : : "r" (Device::APIC::driver->GetCurrentCore()) : );
|
||||||
|
|
||||||
SerialPrintf("[CORE] Core %d ready.\r\n", Device::APIC::driver->GetCurrentCore());
|
SerialPrintf("[CORE] Core %d ready.\r\n", Device::APIC::driver->GetCurrentCore());
|
||||||
|
// TODO: New GDT
|
||||||
__asm__ __volatile__("cli");
|
__asm__ __volatile__("cli");
|
||||||
Ready = true;
|
Ready = true;
|
||||||
__asm__ __volatile__("sti");
|
__asm__ __volatile__("sti");
|
||||||
|
@ -34,29 +38,22 @@ Core::Core(size_t APIC, size_t ID) {
|
||||||
GetCore(ID)->LocalAPIC = APIC;
|
GetCore(ID)->LocalAPIC = APIC;
|
||||||
|
|
||||||
Bootstrap();
|
Bootstrap();
|
||||||
//SetupData(ID);
|
SetupData(ID);
|
||||||
|
|
||||||
Device::APIC::driver->InitializeCore(APIC, reinterpret_cast<size_t>(initcpu));
|
Device::APIC::driver->InitializeCore(APIC, CORE_BOOTSTRAP);
|
||||||
|
|
||||||
while (!Ready) {
|
while (Ready != true) {
|
||||||
__asm__ __volatile__ ("nop");
|
__asm__ ("nop");
|
||||||
}
|
}
|
||||||
|
|
||||||
Ready = false;
|
Ready = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::PreInit() {
|
|
||||||
for (size_t i = 0; i < Constants::Core::MAX_CORES; i++) {
|
|
||||||
Processors[i] = new Core();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::Init() {
|
void Core::Init() {
|
||||||
|
|
||||||
using namespace ACPI;
|
using namespace ACPI;
|
||||||
|
|
||||||
Ready = false;
|
Ready = false;
|
||||||
SerialPrintf("[ CORE] Enabling Multiprocessing\r\n");
|
SerialPrintf("[CORE] Enabling Multiprocessing\n");
|
||||||
|
|
||||||
memset(Tasks, 0, Constants::Core::MAX_CORES * sizeof(TSS64));
|
memset(Tasks, 0, Constants::Core::MAX_CORES * sizeof(TSS64));
|
||||||
for (size_t i = 0; i < Constants::Core::MAX_CORES; i++)
|
for (size_t i = 0; i < Constants::Core::MAX_CORES; i++)
|
||||||
|
@ -68,6 +65,8 @@ void Core::Init() {
|
||||||
|
|
||||||
// While there are more entries in the table..
|
// While there are more entries in the table..
|
||||||
while ((size_t) table < MADT::instance->GetEndOfTable()) {
|
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)
|
// Check for a LAPIC record (which indicates a unique physical core)
|
||||||
if (table->Type == MADT::Type::LAPIC) {
|
if (table->Type == MADT::Type::LAPIC) {
|
||||||
// Find the data for the LAPIC with a reinterpret
|
// Find the data for the LAPIC with a reinterpret
|
||||||
|
@ -80,30 +79,48 @@ void Core::Init() {
|
||||||
// Move to the next core if there is one.
|
// Move to the next core if there is one.
|
||||||
Cores++;
|
Cores++;
|
||||||
}
|
}
|
||||||
// Move to the next entry (by skipping the length of the current entry)
|
|
||||||
table = (MADT::RecordTableEntry*) (((size_t) table) + table->Length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SerialPrintf("[ CORE] Found %d core(s).\r\n", Cores);
|
SerialPrintf("[CORE] Found %d cores.\n", Cores);
|
||||||
|
|
||||||
if (Cores > 1)
|
if (Cores > 1)
|
||||||
SerialPrintf("[ CORE] Bringing up other cores.\r\n");
|
SerialPrintf("[CORE] Bringing up other cores.\n");
|
||||||
|
|
||||||
// For each non-bootstrap core, initialize the necessary data and populate the array.
|
// For each non-bootstrap core, initialize the necessary data and populate the array.
|
||||||
for (int i = 0; i < Cores; i++) {
|
for (int i = 0; i < Cores; i++) {
|
||||||
|
SerialPrintf("[CORE] Enabling core %d.\n", i);
|
||||||
if (Device::APIC::driver->GetCurrentCore() != LAPICs[i]->Core) {
|
if (Device::APIC::driver->GetCurrentCore() != LAPICs[i]->Core)
|
||||||
SerialPrintf("[ CORE] Enabling core %d.\r\n", i);
|
Processors[i] = Core(LAPICs[i]->APIC, LAPICs[i]->Core);
|
||||||
delete Processors[i];
|
|
||||||
Core* c = new Core(LAPICs[i]->APIC, LAPICs[i]->Core);
|
|
||||||
Processors[i] = c;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Bootstrap() {
|
void Core::Bootstrap() {
|
||||||
// TODO
|
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) {
|
void Core::StackTrace(size_t Cycles) {
|
||||||
StackFrame* stack;
|
StackFrame* stack;
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
#include <kernel/chroma.h>
|
#include <kernel/chroma.h>
|
||||||
#include <kernel/system/interrupts.h>
|
#include <kernel/system/interrupts.h>
|
||||||
#include "driver/io/apic.h"
|
|
||||||
|
|
||||||
/************************
|
/************************
|
||||||
*** Team Kitty, 2020 ***
|
*** Team Kitty, 2020 ***
|
||||||
*** Chroma ***
|
*** Chroma ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/* This class provides functions for setting up and preparing the CPU for the things the kernel will do.
|
/* This class provides functions for setting up and preparing the CPU for the things the kernel will do.
|
||||||
* Mainly, it allows you to:
|
* Mainly, it allows you to:
|
||||||
*
|
*
|
||||||
|
@ -41,11 +44,6 @@ __attribute__((aligned(64))) static volatile size_t InitGDT[5] = {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
__attribute__((aligned(64))) static DESC_TBL CoreGDT = {
|
|
||||||
.Limit = sizeof(InitGDT),
|
|
||||||
.Base = (size_t) InitGDT
|
|
||||||
};
|
|
||||||
|
|
||||||
__attribute__((aligned(64))) static volatile TSS64 TSSEntries;
|
__attribute__((aligned(64))) static volatile TSS64 TSSEntries;
|
||||||
|
|
||||||
__attribute__((aligned(64))) static volatile IDT_GATE IDTEntries[256];
|
__attribute__((aligned(64))) static volatile IDT_GATE IDTEntries[256];
|
||||||
|
@ -67,17 +65,53 @@ static void RefreshCS() {
|
||||||
|
|
||||||
|
|
||||||
void PrepareCPU() {
|
void PrepareCPU() {
|
||||||
|
|
||||||
SetupInitialGDT();
|
SetupInitialGDT();
|
||||||
SetupIDT();
|
SetupIDT();
|
||||||
|
|
||||||
//SetupExtensions();
|
//SetupExtensions();
|
||||||
|
|
||||||
InitInterrupts();
|
InitInterrupts();
|
||||||
|
|
||||||
/* In either case, we tell the Master PIC it's been read to receive any IRQ. */
|
|
||||||
WritePort(0x20, 0x20, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*void SetupExtensions() {
|
||||||
|
|
||||||
|
// Enable SSE
|
||||||
|
size_t CR0 = ReadControlRegister(0);
|
||||||
|
|
||||||
|
CR0 &= ~(1 << 2);
|
||||||
|
CR0 |= 1;
|
||||||
|
|
||||||
|
WriteControlRegister(0, CR0);
|
||||||
|
|
||||||
|
// Enable OSXSAVE and gang
|
||||||
|
size_t CR4 = ReadControlRegister(4);
|
||||||
|
CR4 |= (1 << 9);
|
||||||
|
CR4 |= (1 << 10);
|
||||||
|
CR4 |= (1 << 18);
|
||||||
|
|
||||||
|
WriteControlRegister(4, CR4);
|
||||||
|
|
||||||
|
// Enable AVX (and AVX-512 in future)
|
||||||
|
|
||||||
|
CR0 = ReadExtendedControlRegister(0);
|
||||||
|
SerialPrintf("XCR0 is currently %x.\n", CR0);
|
||||||
|
CR0 |= (1 << 0);
|
||||||
|
CR0 |= (1 << 1);
|
||||||
|
CR0 |= (1 << 2);
|
||||||
|
|
||||||
|
CR0 |= (1 << 5);
|
||||||
|
CR0 |= (1 << 6);
|
||||||
|
CR0 |= (1 << 7);
|
||||||
|
|
||||||
|
SerialPrintf("About to write xcr0: %x\n", CR0);
|
||||||
|
WriteExtendedControlRegister(0, CR0);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
void SetupInitialGDT() {
|
void SetupInitialGDT() {
|
||||||
|
DESC_TBL GDTData;
|
||||||
size_t TSSBase = (uint64_t) (&TSSEntries);
|
size_t TSSBase = (uint64_t) (&TSSEntries);
|
||||||
|
|
||||||
uint16_t TSSLower = (uint16_t) TSSBase;
|
uint16_t TSSLower = (uint16_t) TSSBase;
|
||||||
|
@ -85,13 +119,15 @@ void SetupInitialGDT() {
|
||||||
uint8_t TSSMid2 = (uint8_t) (TSSBase >> 24);
|
uint8_t TSSMid2 = (uint8_t) (TSSBase >> 24);
|
||||||
uint32_t TSSHigher = (uint32_t) (TSSBase >> 32);
|
uint32_t TSSHigher = (uint32_t) (TSSBase >> 32);
|
||||||
|
|
||||||
|
GDTData.Limit = sizeof(InitGDT) - 1;
|
||||||
|
GDTData.Base = (size_t) InitGDT;
|
||||||
|
|
||||||
((TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]))->BaseLow = TSSLower;
|
((TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]))->BaseLow = TSSLower;
|
||||||
((TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]))->BaseMid1 = TSSMid1;
|
((TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]))->BaseMid1 = TSSMid1;
|
||||||
((TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]))->BaseMid2 = TSSMid2;
|
((TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]))->BaseMid2 = TSSMid2;
|
||||||
((TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]))->BaseHigh = TSSHigher;
|
((TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]))->BaseHigh = TSSHigher;
|
||||||
|
|
||||||
WriteGDT(CoreGDT);
|
WriteGDT(GDTData);
|
||||||
WriteTSR(3 << 3);
|
WriteTSR(3 << 3);
|
||||||
RefreshCS();
|
RefreshCS();
|
||||||
}
|
}
|
||||||
|
@ -226,10 +262,13 @@ void SetupIDT() {
|
||||||
SetISR(46, (size_t) IRQ14Handler);
|
SetISR(46, (size_t) IRQ14Handler);
|
||||||
SetISR(47, (size_t) IRQ15Handler);
|
SetISR(47, (size_t) IRQ15Handler);
|
||||||
|
|
||||||
for (size_t i = 0; i < 32; i++) {
|
|
||||||
IRQHandlers[i] = {{}, 0 };
|
//TODO: ISRs 32 to 256
|
||||||
}
|
|
||||||
|
|
||||||
WriteIDT(IDTData);
|
WriteIDT(IDTData);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
55
src/system/extern/extern_defs.cpp
vendored
55
src/system/extern/extern_defs.cpp
vendored
|
@ -1,55 +0,0 @@
|
||||||
/************************
|
|
||||||
*** Team Kitty, 2022 ***
|
|
||||||
*** Chroma ***
|
|
||||||
***********************/
|
|
||||||
|
|
||||||
#include <kernel/system/descriptors.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains definitions that are used by external files.
|
|
||||||
* That means, independent programs or assembler files.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The template GDT entry for a newly initialized core.
|
|
||||||
* Protected Mode.
|
|
||||||
* TODO: Document what the entries here are.
|
|
||||||
*/
|
|
||||||
|
|
||||||
__attribute__((aligned(64))) size_t ProtectedGDTEntry[3] = {
|
|
||||||
0,
|
|
||||||
0x00CF9A000000FFFF,
|
|
||||||
0x00CF92000000FFFF
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The GDT table value to be loaded into each newly initialized core.
|
|
||||||
* Protected Mode.
|
|
||||||
*/
|
|
||||||
|
|
||||||
DESC_TBL ProtectedGDT = {
|
|
||||||
.Limit = sizeof(ProtectedGDTEntry) - 1,
|
|
||||||
.Base = (size_t) &ProtectedGDTEntry
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The template GDT entry for a newly initialized core.
|
|
||||||
* Long Mode.
|
|
||||||
* TODO: Document what the entries here are.
|
|
||||||
*/
|
|
||||||
__attribute__((aligned(64))) size_t LongGDTEntry[3] = {
|
|
||||||
0,
|
|
||||||
0x00AF98000000FFFF,
|
|
||||||
0x00CF92000000FFFF
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The GDT table value to be loaded into each newly initialized core.
|
|
||||||
* Long Mode.
|
|
||||||
*/
|
|
||||||
|
|
||||||
DESC_TBL LongGDT = {
|
|
||||||
.Limit = sizeof(LongGDTEntry) - 1,
|
|
||||||
.Base = (size_t) &LongGDTEntry
|
|
||||||
};
|
|
||||||
|
|
|
@ -2,13 +2,16 @@
|
||||||
#include <kernel/video/draw.h>
|
#include <kernel/video/draw.h>
|
||||||
#include <kernel/system/interrupts.h>
|
#include <kernel/system/interrupts.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "driver/io/apic.h"
|
|
||||||
|
|
||||||
/************************
|
/************************
|
||||||
*** Team Kitty, 2020 ***
|
*** Team Kitty, 2020 ***
|
||||||
*** Chroma ***
|
*** Chroma ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/* This file contains all of the ISR and IRQ
|
/* This file contains all of the ISR and IRQ
|
||||||
* (Interrupt Service Request) functions.
|
* (Interrupt Service Request) functions.
|
||||||
*
|
*
|
||||||
|
@ -38,10 +41,6 @@
|
||||||
* these having a size_t input as an error code.
|
* these having a size_t input as an error code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const char* ExceptionStrings[] = {
|
const char* ExceptionStrings[] = {
|
||||||
"Division by Zero",
|
"Division by Zero",
|
||||||
"Debug",
|
"Debug",
|
||||||
|
@ -77,7 +76,15 @@ const char* ExceptionStrings[] = {
|
||||||
"Reserved"
|
"Reserved"
|
||||||
};
|
};
|
||||||
|
|
||||||
IRQHandlerData IRQHandlers[32];
|
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.
|
/* All of the ISR routines call this function for now.
|
||||||
! This function is NOT leaf, and it might clobber the stack.
|
! This function is NOT leaf, and it might clobber the stack.
|
||||||
|
@ -117,83 +124,114 @@ void ISR_Error_Common(INTERRUPT_FRAME* Frame, size_t ErrorCode, size_t Exception
|
||||||
which was set up earlier by irq_install.*/
|
which was set up earlier by irq_install.*/
|
||||||
void IRQ_Common(INTERRUPT_FRAME* Frame, size_t Interrupt) {
|
void IRQ_Common(INTERRUPT_FRAME* Frame, size_t Interrupt) {
|
||||||
// First we need to define a function pointer..
|
// First we need to define a function pointer..
|
||||||
IRQHandlerData handler;
|
void (* Handler)(INTERRUPT_FRAME* Frame);
|
||||||
|
|
||||||
/* We set all uninitialized routines to 0, so the if(handler) check here allows us to
|
/* 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. */
|
safely tell whether we've actually got something for this IRQ. */
|
||||||
handler = IRQHandlers[Interrupt];
|
Handler = IRQ_Handlers[Interrupt];
|
||||||
if (handler.numHandlers > 0) {
|
// If there's something there,
|
||||||
//SerialPrintf("[ IRQ] IRQ %d raised!\r\n", Interrupt);
|
if (Handler) {
|
||||||
// Call the handlers
|
SerialPrintf("[ IRQ] IRQ %d raised!\r\n", Interrupt);
|
||||||
for (size_t i = 0; i < handler.numHandlers; i++)
|
// Call the handler.
|
||||||
handler.handlers[i](Frame);
|
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);
|
||||||
|
|
||||||
Device::APIC::driver->SendEOI();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PIC1 0x20 /* IO base address for master PIC */
|
|
||||||
#define PIC2 0xA0 /* IO base address for slave PIC */
|
|
||||||
#define PIC1_COMMAND PIC1
|
|
||||||
#define PIC1_DATA (PIC1+1)
|
|
||||||
#define PIC2_COMMAND PIC2
|
|
||||||
#define PIC2_DATA (PIC2+1)
|
|
||||||
|
|
||||||
#define ICW1_ICW4 0x01 /* ICW4 (not) needed */
|
|
||||||
#define ICW1_SINGLE 0x02 /* Single (cascade) mode */
|
|
||||||
#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */
|
|
||||||
#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */
|
|
||||||
#define ICW1_INIT 0x10 /* Initialization - required! */
|
|
||||||
|
|
||||||
#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */
|
|
||||||
#define ICW4_AUTO 0x02 /* Auto (normal) EOI */
|
|
||||||
#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */
|
|
||||||
#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */
|
|
||||||
#define ICW4_SFNM 0x10 /* Special fully nested (not) */
|
|
||||||
|
|
||||||
/* However, in order to actually be able to receive IRQs, we need to remap the PICs. */
|
/* However, in order to actually be able to receive IRQs, we need to remap the PICs. */
|
||||||
void RemapIRQControllers() {
|
void RemapIRQControllers() {
|
||||||
/* 0x20 is the Master PIC,
|
/* 0x20 is the Master PIC,
|
||||||
0xA0 is the Slave PIC. */
|
0xA0 is the Slave PIC. */
|
||||||
|
WritePort(0x20, 0x11, 1);
|
||||||
WritePort(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4, 1); // starts the initialization sequence (in cascade mode)
|
WritePort(0xA0, 0x11, 1);
|
||||||
WritePort(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4, 1);
|
WritePort(0x21, 0x20, 1);
|
||||||
WritePort(PIC1_DATA, 32, 1); // ICW2: Master PIC vector offset
|
WritePort(0xA1, 0x28, 1);
|
||||||
WritePort(PIC2_DATA, 32 + 8, 1); // ICW2: Slave PIC vector offset
|
WritePort(0x21, 0x04, 1);
|
||||||
WritePort(PIC1_DATA, 4, 1); // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100)
|
WritePort(0xA1, 0x02, 1);
|
||||||
WritePort(PIC2_DATA, 2, 1); // ICW3: tell Slave PIC its cascade identity (0000 0010)
|
WritePort(0x21, 0x01, 1);
|
||||||
|
WritePort(0xA1, 0x01, 1);
|
||||||
WritePort(PIC1_DATA, ICW4_8086, 1);
|
WritePort(0x21, 0x0, 1);
|
||||||
WritePort(PIC2_DATA, ICW4_8086, 1);
|
WritePort(0xA1, 0x0, 1);
|
||||||
|
|
||||||
WritePort(PIC1_DATA, 0xFF, 1); // restore saved masks.
|
|
||||||
WritePort(PIC2_DATA, 0xFF, 1);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* In order to actually handle the IRQs, though, we need to tell the kernel *where* the handlers are. */
|
/* 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. */
|
/* A simple wrapper that adds a function pointer to the IRQ array. */
|
||||||
size_t InstallIRQ(int IRQ, IRQHandler Handler) {
|
void InstallIRQ(int IRQ, void (* Handler)(INTERRUPT_FRAME* Frame)) {
|
||||||
if (IRQ <= 32) {
|
IRQ_Handlers[IRQ] = Handler;
|
||||||
Device::APIC::driver->Set(Core::GetCurrent()->ID, IRQ, 1);
|
|
||||||
|
|
||||||
IRQHandlerData* target = &IRQHandlers[IRQ];
|
|
||||||
if (target->numHandlers < 7) {
|
|
||||||
target->handlers[target->numHandlers] = Handler;
|
|
||||||
target->numHandlers++;
|
|
||||||
return target->numHandlers;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A simple wrapper that unlinks a function pointer, rendering the IRQ unused. */
|
/* A simple wrapper that unlinks a function pointer, rendering the IRQ unused. */
|
||||||
void UninstallIRQHandler(int IRQ, size_t ID) {
|
void UninstallIRQHandler(int IRQ) {
|
||||||
IRQHandlers[IRQ].handlers[ID] = NULL; // 0 is used in the common check to make sure that the function is callable.
|
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.
|
// 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() {
|
void InitInterrupts() {
|
||||||
size_t RFLAGS = ReadControlRegister('f');
|
size_t RFLAGS = ReadControlRegister('f');
|
||||||
|
|
||||||
|
@ -201,6 +239,11 @@ void InitInterrupts() {
|
||||||
WriteControlRegister('f', RFLAGS | (1 << 9));
|
WriteControlRegister('f', RFLAGS | (1 << 9));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
InstallIRQ(1, &KeyboardCallback);
|
||||||
|
|
||||||
|
Send8042(0xF002);
|
||||||
|
|
||||||
__asm__ __volatile__("sti");
|
__asm__ __volatile__("sti");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,7 +368,7 @@ __attribute__((interrupt)) void ISR14Handler(INTERRUPT_FRAME* Frame, size_t Erro
|
||||||
|
|
||||||
SerialPrintf("[FAULT] } at address\n[FAULT] 0x%p\r\n\n", ReadControlRegister(2));
|
SerialPrintf("[FAULT] } at address\n[FAULT] 0x%p\r\n\n", ReadControlRegister(2));
|
||||||
|
|
||||||
Core::GetCurrent()->StackTrace(10);
|
Core::GetCurrent()->StackTrace(6);
|
||||||
ISR_Error_Common(Frame, ErrorCode, 14); // Page Fault
|
ISR_Error_Common(Frame, ErrorCode, 14); // Page Fault
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,6 +510,6 @@ __attribute__((interrupt)) void IRQ15Handler(INTERRUPT_FRAME* Frame) {
|
||||||
IRQ_Common(Frame, 15);
|
IRQ_Common(Frame, 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
|
@ -1,4 +1,6 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <kernel/system/memory.h>
|
#include <kernel/system/memory.h>
|
||||||
#include <kernel/system/io.h>
|
#include <kernel/system/io.h>
|
||||||
|
|
||||||
|
@ -7,6 +9,10 @@
|
||||||
*** Chroma ***
|
*** Chroma ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/************************************************
|
/************************************************
|
||||||
* C O N S T A N T S A N D M A C R O S
|
* C O N S T A N T S A N D M A C R O S
|
||||||
*************************************************/
|
*************************************************/
|
||||||
|
@ -132,6 +138,10 @@ static void BlockSetSize(block_header_t* Block, size_t Size) {
|
||||||
Block->Size = Size | (Block->Size & (BLOCK_FREE | BLOCK_PREV_FREE));
|
Block->Size = Size | (Block->Size & (BLOCK_FREE | BLOCK_PREV_FREE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int BlockIsLast(const block_header_t* Block) {
|
||||||
|
return BlockSize(Block) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int BlockIsFree(const block_header_t* Block) {
|
static int BlockIsFree(const block_header_t* Block) {
|
||||||
return CAST(int, Block->Size & BLOCK_FREE);
|
return CAST(int, Block->Size & BLOCK_FREE);
|
||||||
}
|
}
|
||||||
|
@ -169,11 +179,13 @@ static block_header_t* OffsetToBlock(const void* Address, size_t Size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static block_header_t* BlockGetPrevious(const block_header_t* Current) {
|
static block_header_t* BlockGetPrevious(const block_header_t* Current) {
|
||||||
|
ASSERT(BlockPrevIsFree(Current), "BlockGetPrevious: Previous block NOT free");
|
||||||
return Current->LastBlock;
|
return Current->LastBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
static block_header_t* BlockGetNext(const block_header_t* Current) {
|
static block_header_t* BlockGetNext(const block_header_t* Current) {
|
||||||
block_header_t* NextBlock = OffsetToBlock(WhereBlock(Current), BlockSize(Current) - BLOCK_OVERHEAD);
|
block_header_t* NextBlock = OffsetToBlock(WhereBlock(Current), BlockSize(Current) - BLOCK_OVERHEAD);
|
||||||
|
ASSERT(!BlockIsLast(Current), "BlockGetNext: Current block is last!");
|
||||||
return NextBlock;
|
return NextBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,17 +212,17 @@ static void BlockMarkUsed(block_header_t* Current) {
|
||||||
* P O I N T E R A L I G N M E N T F U N C T I O N S
|
* P O I N T E R A L I G N M E N T F U N C T I O N S
|
||||||
************************************************************************************/
|
************************************************************************************/
|
||||||
|
|
||||||
extern "C" size_t AlignUpwards(size_t Pointer, size_t Alignment) {
|
size_t AlignUpwards(size_t Pointer, size_t Alignment) {
|
||||||
//ASSERT(((Alignment & (Alignment - 1)) == 0));
|
//ASSERT(((Alignment & (Alignment - 1)) == 0));
|
||||||
return (Pointer + (Alignment - 1)) & ~(Alignment - 1);
|
return (Pointer + (Alignment - 1)) & ~(Alignment - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" size_t AlignDownwards(size_t Pointer, size_t Alignment) {
|
size_t AlignDownwards(size_t Pointer, size_t Alignment) {
|
||||||
//ASSERT((Alignment & (Alignment - 1) == 0));
|
//ASSERT((Alignment & (Alignment - 1) == 0));
|
||||||
return (Pointer - (Pointer & (Alignment - 1)));
|
return (Pointer - (Pointer & (Alignment - 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void* AlignPointer(const void* Pointer, size_t Alignment) {
|
void* AlignPointer(const void* Pointer, size_t Alignment) {
|
||||||
|
|
||||||
const ptrdiff_t AlignedPointer =
|
const ptrdiff_t AlignedPointer =
|
||||||
((
|
((
|
||||||
|
@ -218,6 +230,7 @@ extern "C" void* AlignPointer(const void* Pointer, size_t Alignment) {
|
||||||
+ (Alignment - 1))
|
+ (Alignment - 1))
|
||||||
& ~(Alignment - 1)
|
& ~(Alignment - 1)
|
||||||
);
|
);
|
||||||
|
ASSERT(((Alignment & (Alignment - 1)) == 0), "AlignPointer: Requested alignment not aligned!");
|
||||||
|
|
||||||
return CAST(void*, AlignedPointer);
|
return CAST(void*, AlignedPointer);
|
||||||
}
|
}
|
||||||
|
@ -286,6 +299,8 @@ static block_header_t* FindSuitableBlock(allocator_control_t* Controller, int* F
|
||||||
SLMap = Controller->SecondLevel_Bitmap[FirstLevel];
|
SLMap = Controller->SecondLevel_Bitmap[FirstLevel];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ASSERT(SLMap, "FindSuitableBlock: Second level bitmap not present!");
|
||||||
|
|
||||||
SecondLevel = Alloc_FindFirstOne(SLMap);
|
SecondLevel = Alloc_FindFirstOne(SLMap);
|
||||||
*SecondLevelIndex = SecondLevel;
|
*SecondLevelIndex = SecondLevel;
|
||||||
|
|
||||||
|
@ -296,6 +311,9 @@ static void RemoveFreeBlock(allocator_control_t* Controller, block_header_t* Blo
|
||||||
block_header_t* PreviousBlock = Block->LastFreeBlock;
|
block_header_t* PreviousBlock = Block->LastFreeBlock;
|
||||||
block_header_t* NextBlock = Block->NextFreeBlock;
|
block_header_t* NextBlock = Block->NextFreeBlock;
|
||||||
|
|
||||||
|
ASSERT(PreviousBlock, "RemoveFreeBlock: PreviousBlock is null!");
|
||||||
|
ASSERT(NextBlock, "RemoveFreeBlock: NextBlock is null!");
|
||||||
|
|
||||||
NextBlock->LastFreeBlock = PreviousBlock;
|
NextBlock->LastFreeBlock = PreviousBlock;
|
||||||
PreviousBlock->NextFreeBlock = NextBlock;
|
PreviousBlock->NextFreeBlock = NextBlock;
|
||||||
|
|
||||||
|
@ -316,6 +334,7 @@ static void
|
||||||
InsertFreeBlock(allocator_control_t* Controller, block_header_t* NewBlock, int FirstLevel, int SecondLevel) {
|
InsertFreeBlock(allocator_control_t* Controller, block_header_t* NewBlock, int FirstLevel, int SecondLevel) {
|
||||||
block_header_t* Current = Controller->Blocks[FirstLevel][SecondLevel];
|
block_header_t* Current = Controller->Blocks[FirstLevel][SecondLevel];
|
||||||
|
|
||||||
|
ASSERT(Current, "InsertFreeBlock: Current Block is null!");
|
||||||
if (!Current) {
|
if (!Current) {
|
||||||
SerialPrintf(
|
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",
|
"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",
|
||||||
|
@ -323,12 +342,16 @@ InsertFreeBlock(allocator_control_t* Controller, block_header_t* NewBlock, int F
|
||||||
Controller->Blocks, Controller->Blocks[FirstLevel][SecondLevel]);
|
Controller->Blocks, Controller->Blocks[FirstLevel][SecondLevel]);
|
||||||
for (;;) { }
|
for (;;) { }
|
||||||
}
|
}
|
||||||
|
ASSERT(NewBlock, "InsertFreeBlock: New Block is null!");
|
||||||
|
|
||||||
NewBlock->NextFreeBlock = Current;
|
NewBlock->NextFreeBlock = Current;
|
||||||
NewBlock->LastFreeBlock = &Controller->BlockNull;
|
NewBlock->LastFreeBlock = &Controller->BlockNull;
|
||||||
|
|
||||||
Current->LastFreeBlock = NewBlock;
|
Current->LastFreeBlock = NewBlock;
|
||||||
|
|
||||||
|
ASSERT(WhereBlock(NewBlock) == AlignPointer(WhereBlock(NewBlock), ALIGN_SIZE),
|
||||||
|
"InsertFreeBlock: Current block is not memory aligned!");
|
||||||
|
|
||||||
Controller->Blocks[FirstLevel][SecondLevel] = NewBlock;
|
Controller->Blocks[FirstLevel][SecondLevel] = NewBlock;
|
||||||
Controller->FirstLevel_Bitmap |= (1U << FirstLevel);
|
Controller->FirstLevel_Bitmap |= (1U << FirstLevel);
|
||||||
Controller->SecondLevel_Bitmap[FirstLevel] |= (1U << SecondLevel);
|
Controller->SecondLevel_Bitmap[FirstLevel] |= (1U << SecondLevel);
|
||||||
|
@ -357,8 +380,15 @@ static block_header_t* SplitBlock(block_header_t* Block, size_t NewSize) {
|
||||||
|
|
||||||
const size_t RemainingSize = BlockSize(Block) - (NewSize + BLOCK_OVERHEAD);
|
const size_t RemainingSize = BlockSize(Block) - (NewSize + BLOCK_OVERHEAD);
|
||||||
|
|
||||||
|
ASSERT(WhereBlock(Overlap) == AlignPointer(WhereBlock(Overlap), ALIGN_SIZE),
|
||||||
|
"SplitBlock: Requested size results in intermediary block which is not aligned!");
|
||||||
|
|
||||||
|
ASSERT(BlockSize(Block) == RemainingSize + NewSize + BLOCK_OVERHEAD, "SplitBlock: Maths error!");
|
||||||
|
|
||||||
BlockSetSize(Overlap, RemainingSize);
|
BlockSetSize(Overlap, RemainingSize);
|
||||||
|
|
||||||
|
ASSERT(BlockSize(Overlap) >= BLOCK_MIN_SIZE, "SplitBlock: Requested size results in new block that is too small!");
|
||||||
|
|
||||||
BlockSetSize(Block, NewSize);
|
BlockSetSize(Block, NewSize);
|
||||||
|
|
||||||
BlockMarkFree(Overlap);
|
BlockMarkFree(Overlap);
|
||||||
|
@ -367,6 +397,7 @@ static block_header_t* SplitBlock(block_header_t* Block, size_t NewSize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static block_header_t* MergeBlockDown(block_header_t* Previous, block_header_t* Block) {
|
static block_header_t* MergeBlockDown(block_header_t* Previous, block_header_t* Block) {
|
||||||
|
ASSERT(!BlockIsLast(Previous), "MergeBlockDown: Previous block is the last block! (Current block is first block?)");
|
||||||
|
|
||||||
Previous->Size += BlockSize(Block) + BLOCK_OVERHEAD;
|
Previous->Size += BlockSize(Block) + BLOCK_OVERHEAD;
|
||||||
BlockLinkToNext(Previous);
|
BlockLinkToNext(Previous);
|
||||||
|
@ -377,6 +408,8 @@ static block_header_t* MergeEmptyBlockDown(allocator_control_t* Controller, bloc
|
||||||
|
|
||||||
if (BlockPrevIsFree(Block)) {
|
if (BlockPrevIsFree(Block)) {
|
||||||
block_header_t* Previous = BlockGetPrevious(Block);
|
block_header_t* Previous = BlockGetPrevious(Block);
|
||||||
|
ASSERT(Previous, "MergeEmptyBlockDown: Previous block is null!");
|
||||||
|
ASSERT(BlockIsFree(Previous), "MergeEmptyBlockDown: Previous block is free!");
|
||||||
RemoveBlock(Controller, Previous);
|
RemoveBlock(Controller, Previous);
|
||||||
Block = MergeBlockDown(Previous, Block);
|
Block = MergeBlockDown(Previous, Block);
|
||||||
}
|
}
|
||||||
|
@ -386,8 +419,10 @@ static block_header_t* MergeEmptyBlockDown(allocator_control_t* Controller, bloc
|
||||||
|
|
||||||
static block_header_t* MergeNextBlockDown(allocator_control_t* Controller, block_header_t* Block) {
|
static block_header_t* MergeNextBlockDown(allocator_control_t* Controller, block_header_t* Block) {
|
||||||
block_header_t* NextBlock = BlockGetNext(Block);
|
block_header_t* NextBlock = BlockGetNext(Block);
|
||||||
|
ASSERT(NextBlock, "MergeNextBlockDown: Next Block is null!");
|
||||||
|
|
||||||
if (BlockIsFree(NextBlock)) {
|
if (BlockIsFree(NextBlock)) {
|
||||||
|
ASSERT(!BlockIsLast(Block), "MergeNextBlockDown: Current block is the last block!");
|
||||||
RemoveBlock(Controller, NextBlock);
|
RemoveBlock(Controller, NextBlock);
|
||||||
Block = MergeBlockDown(Block, NextBlock);
|
Block = MergeBlockDown(Block, NextBlock);
|
||||||
}
|
}
|
||||||
|
@ -396,6 +431,7 @@ static block_header_t* MergeNextBlockDown(allocator_control_t* Controller, block
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TrimBlockFree(allocator_control_t* Controller, block_header_t* Block, size_t Size) {
|
static void TrimBlockFree(allocator_control_t* Controller, block_header_t* Block, size_t Size) {
|
||||||
|
ASSERT(BlockIsFree(Block), "TrimBlockFree: Current block is wholly free!");
|
||||||
|
|
||||||
if (CanBlockSplit(Block, Size)) {
|
if (CanBlockSplit(Block, Size)) {
|
||||||
block_header_t* RemainingBlock = SplitBlock(Block, Size);
|
block_header_t* RemainingBlock = SplitBlock(Block, Size);
|
||||||
|
@ -409,6 +445,8 @@ static void TrimBlockFree(allocator_control_t* Controller, block_header_t* Block
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TrimBlockUsed(allocator_control_t* Controller, block_header_t* Block, size_t Size) {
|
static void TrimBlockUsed(allocator_control_t* Controller, block_header_t* Block, size_t Size) {
|
||||||
|
ASSERT(!BlockIsFree(Block), "TrimBlockUsed: The current block is wholly used!");
|
||||||
|
|
||||||
if (CanBlockSplit(Block, Size)) {
|
if (CanBlockSplit(Block, Size)) {
|
||||||
|
|
||||||
block_header_t* RemainingBlock = SplitBlock(Block, Size);
|
block_header_t* RemainingBlock = SplitBlock(Block, Size);
|
||||||
|
@ -454,6 +492,7 @@ static block_header_t* LocateFreeBlock(allocator_control_t* Controller, size_t S
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Block) {
|
if (Block) {
|
||||||
|
ASSERT(BlockSize(Block) >= Size, "LocateFreeBlock: Found a block that is too small!");
|
||||||
RemoveFreeBlock(Controller, Block, FirstLevel, SecondLevel);
|
RemoveFreeBlock(Controller, Block, FirstLevel, SecondLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,6 +503,7 @@ static void* PrepareUsedBlock(allocator_control_t* Controller, block_header_t* B
|
||||||
void* Pointer = 0;
|
void* Pointer = 0;
|
||||||
|
|
||||||
if (Block) {
|
if (Block) {
|
||||||
|
ASSERT(Size, "PrepareUsedBlock: Size is 0!");
|
||||||
TrimBlockFree(Controller, Block, Size);
|
TrimBlockFree(Controller, Block, Size);
|
||||||
BlockMarkUsed(Block);
|
BlockMarkUsed(Block);
|
||||||
Pointer = WhereBlock(Block);
|
Pointer = WhereBlock(Block);
|
||||||
|
@ -576,6 +616,10 @@ void RemovePoolFromAllocator(allocator_t Allocator, mempool_t Pool) {
|
||||||
|
|
||||||
int FirstLevel = 0, SecondLevel = 0;
|
int FirstLevel = 0, SecondLevel = 0;
|
||||||
|
|
||||||
|
ASSERT(BlockIsFree(Block), "RemovePoolFromAllocator: Current block is free!");
|
||||||
|
ASSERT(!BlockIsFree(BlockGetNext(Block)), "RemovePoolFromAllocator: Next Block is not free!");
|
||||||
|
ASSERT(BlockSize(BlockGetNext(Block)) == 0, "RemovePoolFromAllocator: Next block is size 0!");
|
||||||
|
|
||||||
RoundUpBlockSize(BlockSize(Block), &FirstLevel, &SecondLevel);
|
RoundUpBlockSize(BlockSize(Block), &FirstLevel, &SecondLevel);
|
||||||
RemoveFreeBlock(Controller, Block, FirstLevel, SecondLevel);
|
RemoveFreeBlock(Controller, Block, FirstLevel, SecondLevel);
|
||||||
}
|
}
|
||||||
|
@ -658,6 +702,8 @@ void* AllocatorMalign(allocator_t Allocator, size_t Alignment, size_t Size) {
|
||||||
|
|
||||||
block_header_t* Block = LocateFreeBlock(Controller, AlignedSize);
|
block_header_t* Block = LocateFreeBlock(Controller, AlignedSize);
|
||||||
|
|
||||||
|
ASSERT(sizeof(block_header_t) == BLOCK_MIN_SIZE + BLOCK_OVERHEAD, "AllocatorMalign: Maths error!");
|
||||||
|
|
||||||
if (Block) {
|
if (Block) {
|
||||||
void* Address = WhereBlock(Block);
|
void* Address = WhereBlock(Block);
|
||||||
void* AlignedAddress = AlignPointer(Address, Alignment);
|
void* AlignedAddress = AlignPointer(Address, Alignment);
|
||||||
|
@ -675,6 +721,8 @@ void* AllocatorMalign(allocator_t Allocator, size_t Alignment, size_t Size) {
|
||||||
Gap = CAST(size_t, CAST(ptrdiff_t, AlignedAddress) - CAST(ptrdiff_t, Address));
|
Gap = CAST(size_t, CAST(ptrdiff_t, AlignedAddress) - CAST(ptrdiff_t, Address));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ASSERT(Gap >= MinimumGap, "AllocatorMalign: Maths error 2!");
|
||||||
|
|
||||||
Block = TrimBlockLeadingFree(Controller, Block, Gap);
|
Block = TrimBlockLeadingFree(Controller, Block, Gap);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -687,6 +735,7 @@ void AllocatorFree(allocator_t Allocator, void* Address) {
|
||||||
if (Address) {
|
if (Address) {
|
||||||
allocator_control_t* Controller = CAST(allocator_control_t*, Allocator);
|
allocator_control_t* Controller = CAST(allocator_control_t*, Allocator);
|
||||||
block_header_t* Block = WhichBlock(Address);
|
block_header_t* Block = WhichBlock(Address);
|
||||||
|
ASSERT(!BlockIsFree(Block), "AllocatorFree: Attempting to free a freed block!");
|
||||||
|
|
||||||
BlockMarkFree(Block);
|
BlockMarkFree(Block);
|
||||||
Block = MergeEmptyBlockDown(Controller, Block);
|
Block = MergeEmptyBlockDown(Controller, Block);
|
||||||
|
@ -731,6 +780,8 @@ void* AllocatorRealloc(allocator_t Allocator, void* Address, size_t NewSize) {
|
||||||
|
|
||||||
const size_t AdjustedSize = AlignRequestSize(NewSize, ALIGN_SIZE);
|
const size_t AdjustedSize = AlignRequestSize(NewSize, ALIGN_SIZE);
|
||||||
|
|
||||||
|
ASSERT(!BlockIsFree(Block), "AllocatorRealloc: Requested block is not free!");
|
||||||
|
|
||||||
if (AdjustedSize > CurrentSize && (!BlockIsFree(NextBlock) || AdjustedSize > CombinedSize)) {
|
if (AdjustedSize > CurrentSize && (!BlockIsFree(NextBlock) || AdjustedSize > CombinedSize)) {
|
||||||
// We're going to need more room
|
// We're going to need more room
|
||||||
|
|
||||||
|
@ -753,3 +804,7 @@ void* AllocatorRealloc(allocator_t Allocator, void* Address, size_t NewSize) {
|
||||||
|
|
||||||
return Pointer;
|
return Pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -3,6 +3,10 @@
|
||||||
|
|
||||||
/** Durand's Amazing Super Duper Memory functions. */
|
/** Durand's Amazing Super Duper Memory functions. */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
#define VERSION "1.1"
|
#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 ALIGNMENT 16ul//4ul ///< This is the byte alignment that memory must be allocated on. IMPORTANT for GTK and other stuff.
|
||||||
|
|
||||||
|
@ -65,29 +69,29 @@ static int liballoc_free(void* ptr, size_t count) {
|
||||||
|
|
||||||
/** This macro will conveniently align our pointer upwards */
|
/** This macro will conveniently align our pointer upwards */
|
||||||
#define ALIGN(ptr) \
|
#define ALIGN(ptr) \
|
||||||
if ( ALIGNMENT > 1 ) \
|
if ( ALIGNMENT > 1 ) \
|
||||||
{ \
|
{ \
|
||||||
uintptr_t ldiff; \
|
uintptr_t diff; \
|
||||||
ptr = (void*)((uintptr_t)ptr + ALIGN_INFO); \
|
ptr = (void*)((uintptr_t)ptr + ALIGN_INFO); \
|
||||||
ldiff = (uintptr_t)ptr & (ALIGNMENT-1); \
|
diff = (uintptr_t)ptr & (ALIGNMENT-1); \
|
||||||
if ( diff != 0 ) \
|
if ( diff != 0 ) \
|
||||||
{ \
|
{ \
|
||||||
ldiff = ALIGNMENT - ldiff; \
|
diff = ALIGNMENT - diff; \
|
||||||
ptr = (void*)((uintptr_t)ptr + ldiff); \
|
ptr = (void*)((uintptr_t)ptr + diff); \
|
||||||
} \
|
} \
|
||||||
*((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)) = \
|
*((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)) = \
|
||||||
ldiff + ALIGN_INFO; \
|
diff + ALIGN_INFO; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define UNALIGN(ptr) \
|
#define UNALIGN(ptr) \
|
||||||
if ( ALIGNMENT > 1 ) \
|
if ( ALIGNMENT > 1 ) \
|
||||||
{ \
|
{ \
|
||||||
uintptr_t diff = *((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)); \
|
uintptr_t diff = *((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)); \
|
||||||
if ( diff < (ALIGNMENT + ALIGN_INFO) ) \
|
if ( diff < (ALIGNMENT + ALIGN_INFO) ) \
|
||||||
{ \
|
{ \
|
||||||
ptr = (void*)((uintptr_t)ptr - diff); \
|
ptr = (void*)((uintptr_t)ptr - diff); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -810,6 +814,10 @@ void* PREFIX(realloc)(void* p, size_t size) {
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void operator delete(void* addr, unsigned long __attribute__((unused)) size) {
|
void operator delete(void* addr, unsigned long __attribute__((unused)) size) {
|
||||||
PREFIX(free)(addr);
|
PREFIX(free)(addr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
*** Chroma ***
|
*** Chroma ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
#define PAGE_TABLES_GET_PDPT(address) \
|
#define PAGE_TABLES_GET_PDPT(address) \
|
||||||
(address & ((size_t) 0x1FF << 39)) >> 39
|
(address & ((size_t) 0x1FF << 39)) >> 39
|
||||||
#define PAGE_TABLES_GET_PDP(address) \
|
#define PAGE_TABLES_GET_PDP(address) \
|
||||||
|
@ -54,19 +58,6 @@ void InitPaging() {
|
||||||
MapVirtualPageNoDirect(&KernelAddressSpace, Addr, TO_DIRECT(Addr), DEFAULT_PAGE_FLAGS);
|
MapVirtualPageNoDirect(&KernelAddressSpace, Addr, TO_DIRECT(Addr), DEFAULT_PAGE_FLAGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
SerialPrintf("[ Mem] Identity mapping the entire BIOS memory map.\r\n");
|
|
||||||
for (MMapEnt* MapEntry = &bootldr.mmap; (size_t) MapEntry < (size_t) &bootldr + bootldr.size; MapEntry++) {
|
|
||||||
size_t entry_from = MMapEnt_Ptr(MapEntry);
|
|
||||||
size_t entry_to = MMapEnt_Ptr(MapEntry) + MMapEnt_Size(MapEntry);
|
|
||||||
for (size_t i = entry_from; i < entry_to; i += PAGE_SIZE) {
|
|
||||||
MapVirtualPageNoDirect(&KernelAddressSpace, i, i, DEFAULT_PAGE_FLAGS);
|
|
||||||
MapVirtualPageNoDirect(&KernelAddressSpace, i, TO_DIRECT(i), DEFAULT_PAGE_FLAGS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SerialPrintf("[ Mem] Identity mapping core system hardware.\r\n");
|
|
||||||
MapVirtualPageNoDirect(&KernelAddressSpace, APIC_REGION, APIC_REGION, DEFAULT_PAGE_FLAGS);
|
|
||||||
|
|
||||||
SerialPrintf("[ Mem] Mapping 0x%x bytes of bootloader structure, starting at 0x%p\r\n", bootldr.size,
|
SerialPrintf("[ Mem] Mapping 0x%x bytes of bootloader structure, starting at 0x%p\r\n", bootldr.size,
|
||||||
BootldrAddress);
|
BootldrAddress);
|
||||||
for (size_t i = BootldrAddress; i < (BootldrAddress + bootldr.size); i += PAGE_SIZE)
|
for (size_t i = BootldrAddress; i < (BootldrAddress + bootldr.size); i += PAGE_SIZE)
|
||||||
|
@ -349,10 +340,6 @@ size_t* CreateNewPageTable(address_space_t* AddressSpace) {
|
||||||
return NewPML4;
|
return NewPML4;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *operator new(size_t size) {
|
#ifdef __cplusplus
|
||||||
return kmalloc(size);
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
void *operator new[](size_t size) {
|
|
||||||
return kmalloc(size);
|
|
||||||
}
|
|
|
@ -1,11 +1,16 @@
|
||||||
#include <kernel/chroma.h>
|
#include <kernel/chroma.h>
|
||||||
#include <lainlib/lainlib.h>
|
#include <lainlib/lainlib.h>
|
||||||
|
|
||||||
|
|
||||||
/************************
|
/************************
|
||||||
*** Team Kitty, 2020 ***
|
*** Team Kitty, 2020 ***
|
||||||
*** Chroma ***
|
*** Chroma ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/* This file contains functions for physical memory management.
|
/* This file contains functions for physical memory management.
|
||||||
*
|
*
|
||||||
* Physical Memory Management is performed with Buddy List allocators, which are one of the most performant systems available.
|
* Physical Memory Management is performed with Buddy List allocators, which are one of the most performant systems available.
|
||||||
|
@ -16,9 +21,6 @@
|
||||||
* TODO: Document this mess.
|
* TODO: Document this mess.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define MIN_ORDER 3
|
#define MIN_ORDER 3
|
||||||
#define PEEK(type, address) (*((volatile type*)(address)))
|
#define PEEK(type, address) (*((volatile type*)(address)))
|
||||||
|
@ -172,7 +174,7 @@ void InitMemoryManager() {
|
||||||
|
|
||||||
MemoryPages = FreeMemorySize / PAGE_SIZE;
|
MemoryPages = FreeMemorySize / PAGE_SIZE;
|
||||||
|
|
||||||
SerialPrintf("[ Mem] %u MB of usable memory detected, %u MB total.\r\n", (FreeMemorySize / 1024) / 1024, (FullMemorySize / 1024) / 1024);
|
SerialPrintf("[ Mem] %u MB of memory detected.\r\n", (FreeMemorySize / 1024) / 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -344,6 +346,6 @@ void* memset(void* dst, int src, size_t len) {
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
|
@ -5,6 +5,10 @@
|
||||||
*** Chroma ***
|
*** Chroma ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/* This file contains functions for accessing the PCI bus,
|
/* This file contains functions for accessing the PCI bus,
|
||||||
* and devices contained wherein.
|
* and devices contained wherein.
|
||||||
*
|
*
|
||||||
|
@ -746,4 +750,8 @@ const char* PCIGetClassName(uint8_t DeviceClass) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return "Invalid device!";
|
return "Invalid device!";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -5,6 +5,10 @@
|
||||||
*** Chroma ***
|
*** Chroma ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/* This file serves to allow us to communicate with the computer through raw I/O.
|
/* This file serves to allow us to communicate with the computer through raw I/O.
|
||||||
* It provides interfaces for Ports and commonly used Registers (Control Registers, Model-Specific Registers, GDT, IDT..)
|
* It provides interfaces for Ports and commonly used Registers (Control Registers, Model-Specific Registers, GDT, IDT..)
|
||||||
*
|
*
|
||||||
|
@ -253,3 +257,8 @@ void WriteTSR(uint16_t TSRData) {
|
||||||
|
|
||||||
__asm__ __volatile__("ltr %[src]" : : [src] "m"(TSRData) :);
|
__asm__ __volatile__("ltr %[src]" : : [src] "m"(TSRData) :);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -4,6 +4,10 @@
|
||||||
*** Chroma ***
|
*** Chroma ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/* This file provides functions related to the Serial port.
|
/* This file provides functions related to the Serial port.
|
||||||
* Through this file, you send and receive text and extra debugging information if available.
|
* Through this file, you send and receive text and extra debugging information if available.
|
||||||
*/
|
*/
|
||||||
|
@ -45,4 +49,8 @@ void WriteSerialString(const char* str, size_t len) {
|
||||||
for (size_t i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
WriteSerialChar(str[i]);
|
WriteSerialChar(str[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -7,6 +7,10 @@
|
||||||
*** Chroma ***
|
*** Chroma ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file contains all of the draw-to-screen routines.
|
* This file contains all of the draw-to-screen routines.
|
||||||
* It (currently; 23/08/20) handles the keyboard input test routine,
|
* It (currently; 23/08/20) handles the keyboard input test routine,
|
||||||
|
@ -474,3 +478,7 @@ void DrawFilledCircle(size_t centerX, size_t centerY, size_t radius) {
|
||||||
DrawVerticalLine(centerX, centerY - radius, 2 * radius + 1);
|
DrawVerticalLine(centerX, centerY - radius, 2 * radius + 1);
|
||||||
DrawFilledCircleInternal(centerX, centerY, radius, 3, 0);
|
DrawFilledCircleInternal(centerX, centerY, radius, 3, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -6,6 +6,10 @@
|
||||||
*** Chroma ***
|
*** Chroma ***
|
||||||
***********************/
|
***********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/* This file contains all of the String / Print related functions
|
/* This file contains all of the String / Print related functions
|
||||||
* that are required by the core of the kernel.
|
* that are required by the core of the kernel.
|
||||||
*
|
*
|
||||||
|
@ -32,7 +36,7 @@ void NumToStr(char* Buffer, size_t Num, size_t Base) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" int SerialPrintf(const char* Format, ...) {
|
int SerialPrintf(const char* Format, ...) {
|
||||||
va_list Parameters;
|
va_list Parameters;
|
||||||
va_start(Parameters, Format);
|
va_start(Parameters, Format);
|
||||||
|
|
||||||
|
@ -279,3 +283,7 @@ size_t ParseHexColor(const char* Stream, bool bgFlag) {
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user