Compare commits
54 Commits
c94a469baf
...
986c7816b1
Author | SHA1 | Date | |
---|---|---|---|
986c7816b1 | |||
2b1d6cca5f | |||
4468cee2e7 | |||
4e7f8d47a5 | |||
e2635c8125 | |||
c451afba0d | |||
3f2ac2db36 | |||
a9c0fcdfde | |||
39c1956819 | |||
c8c1af3961 | |||
63a5bfa4d6 | |||
0de541b069 | |||
1cb5c671f7 | |||
91063e12d2 | |||
903b5439ba | |||
|
162c4def06 | ||
|
5421541208 | ||
|
b9b1cb4337 | ||
266e00a3d8 | |||
ff60205e11 | |||
5ad73b7046 | |||
81313cef42 | |||
d342772ed3 | |||
|
cf30822677 | ||
f30a0ebd68 | |||
ee7f3c76f7 | |||
78fb7f061f | |||
833562c7be | |||
35715d1501 | |||
48f574a170 | |||
baf09c80f2 | |||
53506eccb8 | |||
58a944ee6e | |||
59896e4765 | |||
ed89a1fb77 | |||
|
b6554e8501 | ||
aba82eaacb | |||
4c9108bc87 | |||
73b51c851d | |||
493ef776e2 | |||
3eb69c052d | |||
7d0e2142a3 | |||
e580d20e0d | |||
5498f1f923 | |||
|
9d539287a7 | ||
0d21ec9f02 | |||
|
4b4ad2ca65 | ||
|
c26e0e0599 | ||
|
f2531d9ec5 | ||
|
39917539af | ||
e475442f4b | |||
|
86307dda70 | ||
5892af699d | |||
97576bab02 |
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
*.o
|
||||
*.elf
|
||||
|
||||
*.img
|
||||
*.vdi
|
||||
|
||||
|
||||
Makefile
|
||||
CMakeFiles
|
||||
CMakeCache.txt
|
58
CMakeLists.txt
Normal file
58
CMakeLists.txt
Normal file
|
@ -0,0 +1,58 @@
|
|||
#project config
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
set(CMAKE_C_COMPILER x86_64-elf-gcc)
|
||||
|
||||
# cheat the compile test
|
||||
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
|
||||
SET(CMAKE_SYSTEM_NAME Generic)
|
||||
SET(CMAKE_CROSSCOMPILING 1)
|
||||
|
||||
project(chroma)
|
||||
|
||||
|
||||
SET(src_files
|
||||
${CMAKE_SOURCE_DIR}/chroma/kernel.c
|
||||
${CMAKE_SOURCE_DIR}/chroma/video/draw.c
|
||||
${CMAKE_SOURCE_DIR}/chroma/video/print.c
|
||||
${CMAKE_SOURCE_DIR}/chroma/system/cpu.c
|
||||
${CMAKE_SOURCE_DIR}/chroma/system/rw.c
|
||||
${CMAKE_SOURCE_DIR}/chroma/system/serial.c
|
||||
${CMAKE_SOURCE_DIR}/chroma/system/pci.c
|
||||
${CMAKE_SOURCE_DIR}/chroma/system/memory/stack.c
|
||||
${CMAKE_SOURCE_DIR}/chroma/system/memory/paging.c
|
||||
${CMAKE_SOURCE_DIR}/chroma/system/memory/abstract_allocator.c
|
||||
${CMAKE_SOURCE_DIR}/chroma/system/memory/physmem.c
|
||||
${CMAKE_SOURCE_DIR}/chroma/system/drivers/keyboard.c
|
||||
)
|
||||
|
||||
SET(lib_files
|
||||
${CMAKE_SOURCE_DIR}/chroma/lainlib/list/basic_list.c
|
||||
${CMAKE_SOURCE_DIR}/chroma/lainlib/mutex/ticketlock.c
|
||||
${CMAKE_SOURCE_DIR}/chroma/lainlib/compression/lzgmini.c
|
||||
)
|
||||
|
||||
include_directories("chroma/inc")
|
||||
|
||||
SET(src_no_sse
|
||||
${CMAKE_SOURCE_DIR}/chroma/system/interrupts.c
|
||||
)
|
||||
|
||||
SET(src_preamble
|
||||
${CMAKE_SOURCE_DIR}/global/crt0.o
|
||||
${CMAKE_SOURCE_DIR}/global/crti.o
|
||||
${CMAKE_SOURCE_DIR}/global/crtbegin.o
|
||||
)
|
||||
|
||||
set(src_epilogue
|
||||
${CMAKE_SOURCE_DIR}/global/crtend.o
|
||||
${CMAKE_SOURCE_DIR}/global/crtn.o
|
||||
)
|
||||
|
||||
set_property(SOURCE ${src_no_sse} PROPERTY COMPILE_FLAGS -mgeneral-regs-only)
|
||||
|
||||
add_executable(kernel)
|
||||
|
||||
target_sources(kernel PUBLIC ${src_preamble} PUBLIC ${src_files} PUBLIC ${src_no_sse} PUBLIC ${lib_files} PUBLIC ${CMAKE_SOURCE_DIR}/font.o PUBLIC ${src_epilogue})
|
||||
target_compile_options(kernel PRIVATE -ffreestanding -O0 -Wall -Wextra -Wall -Werror -pedantic -fPIC -fno-exceptions -fno-omit-frame-pointer -mno-red-zone -fno-stack-protector -g)
|
||||
target_link_options(kernel PRIVATE -T linker.ld -ffreestanding -O2 -nostdlib -nostartfiles -lgcc)
|
47
README.md
Normal file
47
README.md
Normal file
|
@ -0,0 +1,47 @@
|
|||
![Chroma Logo](https://gemwire.uk/img/chroma/logo/480p.png)
|
||||
|
||||
# Chroma
|
||||
The Chromatic OS
|
||||
|
||||
## About
|
||||
Chroma is an x86_64 kernel, soon to be Operating System.
|
||||
It uses the [bootboot](https://gitlab.com/bztsrc/bootboot) bootloader.
|
||||
|
||||
## Features
|
||||
It can currently:
|
||||
- [x] read keyboard input
|
||||
- [x] draw to the screen, including text and basic images.
|
||||
- [x] output audio over the PC Speaker
|
||||
- [x] manage physical memory
|
||||
- [x] manage virtual memory
|
||||
- [ ] switch to ring 3
|
||||
- [ ] switch tasks
|
||||
- [ ] schedule tasks
|
||||
- [ ] handle processes and threads
|
||||
- [ ] handle mouse input
|
||||
- [ ] display a basic 3D object
|
||||
- [ ] display a basic 3D world
|
||||
- [ ] display a basic 3D world *in VR*
|
||||
|
||||
Once we reach this point... well, the world is our oyster.
|
||||
|
||||
## Building
|
||||
|
||||
Chroma can be built on Windows or Linux.
|
||||
|
||||
### Windows
|
||||
I (Curle) use Windows for developing Chroma.
|
||||
Simply have an [x86_64-elf-gcc](https://github.com/lordmilko/i686-elf-tools) and ld (included!) in your PATH, run `cmake` in the source directory, then `make`.
|
||||
It will compile the kernel, and create an OS image with `mkbootimg`.
|
||||
|
||||
|
||||
### 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)
|
||||
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!)
|
||||
This means you can use any emulator or hypervisor to run it.
|
||||
|
||||
|
56
chroma.bxrc
Normal file
56
chroma.bxrc
Normal file
|
@ -0,0 +1,56 @@
|
|||
# configuration file generated by Bochs
|
||||
plugin_ctrl: unmapped=true, biosdev=true, speaker=true, extfpuirq=true, parallel=true, serial=true, gameport=true
|
||||
config_interface: win32config
|
||||
display_library: win32
|
||||
memory: host=128, guest=128
|
||||
romimage: file="C:\Program Files\Bochs-2.6.11/BIOS-bochs-latest", address=0x00000000, options=none
|
||||
vgaromimage: file="C:\Program Files\Bochs-2.6.11/VGABIOS-lgpl-latest"
|
||||
boot: disk
|
||||
floppy_bootsig_check: disabled=0
|
||||
# no floppya
|
||||
# no floppyb
|
||||
ata0: enabled=true, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
|
||||
ata0-master: type=disk, path="C:/Users/tcrl/Documents/Coding/chroma/chroma.img", cylinders=615, heads=6, spt=17, sect_size=512, model="ChromaDrive", biosdetect=auto, translation=auto
|
||||
ata0-slave: type=none
|
||||
ata1: enabled=true, ioaddr1=0x170, ioaddr2=0x370, irq=15
|
||||
ata1-master: type=none
|
||||
ata1-slave: type=none
|
||||
ata2: enabled=false
|
||||
ata3: enabled=false
|
||||
optromimage1: file=none
|
||||
optromimage2: file=none
|
||||
optromimage3: file=none
|
||||
optromimage4: file=none
|
||||
optramimage1: file=none
|
||||
optramimage2: file=none
|
||||
optramimage3: file=none
|
||||
optramimage4: file=none
|
||||
pci: enabled=1, chipset=i440fx
|
||||
vga: extension=vbe, update_freq=5, realtime=1
|
||||
cpu: count=1, ips=4000000, model=bx_generic, reset_on_triple_fault=0, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0
|
||||
cpuid: level=6, stepping=3, model=3, family=6, vendor_string="GenuineIntel", brand_string=" Intel(R) Pentium(R) 4 CPU "
|
||||
cpuid: mmx=true, apic=xapic, simd=sse2, sse4a=false, misaligned_sse=false, sep=true
|
||||
cpuid: movbe=false, adx=false, aes=false, sha=false, xsave=false, xsaveopt=false, x86_64=true
|
||||
cpuid: 1g_pages=false, pcid=false, fsgsbase=false, smep=false, smap=false, mwait=true
|
||||
cpuid: vmx=1
|
||||
print_timestamps: enabled=0
|
||||
port_e9_hack: enabled=1
|
||||
private_colormap: enabled=0
|
||||
clock: sync=none, time0=local, rtc_sync=0
|
||||
# no cmosimage
|
||||
log: -
|
||||
logprefix: %t%e%d
|
||||
debug: action=ignore
|
||||
info: action=report
|
||||
error: action=report
|
||||
panic: action=ask
|
||||
keyboard: type=mf, serial_delay=250, paste_delay=100000, user_shortcut=none
|
||||
mouse: type=ps2, enabled=false, toggle=ctrl+mbutton
|
||||
sound: waveoutdrv=win, waveout=none, waveindrv=win, wavein=none, midioutdrv=win, midiout=none
|
||||
speaker: enabled=true, mode=sound
|
||||
parport1: enabled=true, file=none
|
||||
parport2: enabled=false
|
||||
com1: enabled=true, mode=file, dev="C:\Users\tcrl\Documents\Coding\chroma\serial.txt"
|
||||
com2: enabled=false
|
||||
com3: enabled=false
|
||||
com4: enabled=false
|
20
chroma.json
Normal file
20
chroma.json
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"disksize": 80,
|
||||
"config": "img/boot/config",
|
||||
"initrd": {
|
||||
"type": "tar",
|
||||
"file": "img/boot/exe"
|
||||
},
|
||||
"partitions": [
|
||||
{
|
||||
"type": "boot",
|
||||
"size": 4,
|
||||
"directory": "img/boot/loader"
|
||||
},
|
||||
{
|
||||
"type": "Microsoft basic data",
|
||||
"size": 76,
|
||||
"name": "Chroma Data"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -2,6 +2,11 @@
|
|||
#ifndef _BOOTLOADER_H_
|
||||
#define _BOOTLOADER_H_
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -9,7 +14,8 @@ extern "C" {
|
|||
#define BOOT_MAGIC "BOOT"
|
||||
|
||||
/* minimum protocol level:
|
||||
* hardcoded kernel name, static kernel memory addresses */
|
||||
* hardcoded kernel name, static kernel memory addresses
|
||||
* this is the default */
|
||||
#define PROTOCOL_MINIMAL 0
|
||||
/* static protocol level:
|
||||
* kernel name parsed from environment, static kernel memory addresses */
|
||||
|
@ -22,6 +28,7 @@ extern "C" {
|
|||
|
||||
/* loader types, just informational */
|
||||
#define LOADER_BIOS (0<<2)
|
||||
/* unless we get to a weird stage, these should never be used. */
|
||||
#define LOADER_UEFI (1<<2)
|
||||
#define LOADER_RPI (2<<2)
|
||||
|
||||
|
@ -101,6 +108,31 @@ typedef struct {
|
|||
} __attribute__((packed)) bootinfo;
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t Magic;
|
||||
uint8_t Class;
|
||||
uint8_t Endianness;
|
||||
uint8_t Version;
|
||||
uint8_t ABI;
|
||||
uint8_t ABIVersion;
|
||||
uint8_t Unused[7];
|
||||
uint16_t Type;
|
||||
uint16_t TargetArchitecture;
|
||||
uint32_t ELFVersion;
|
||||
size_t EntryPoint;
|
||||
size_t ProgramHeadersTable;
|
||||
size_t SectionHeadersTable;
|
||||
uint32_t Flags;
|
||||
uint16_t ELFHeaderSize;
|
||||
uint16_t ProgramHeadersEntrySize;
|
||||
uint16_t ProgramHeaderEntries;
|
||||
uint16_t SectionHeadersEntrySize;
|
||||
uint16_t SectionHeaderEntries;
|
||||
uint16_t SectionHeaderNameEntry;
|
||||
uint8_t End;
|
||||
} __attribute__((packed)) ELF64Header_t;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
#pragma once
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Sync ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
/* This file serves as the central kernel header. Every file in the kernel should include this header.
|
||||
* It provides functionality to every core component of the system, and provides unrestricted cross-communication between modules.
|
||||
* It also provides the symbols for the framebuffer and configuration file, which are both equually important.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
|
@ -11,21 +17,60 @@
|
|||
#include <kernel/boot/boot.h>
|
||||
#include <kernel/system/io.h>
|
||||
#include <kernel/system/memory.h>
|
||||
#include <kernel/system/pci.h>
|
||||
#include <kernel/system/stack.h>
|
||||
|
||||
//Removed cause "wacky copyrighted stuff"
|
||||
//#include <kernel/system/screen.h>
|
||||
|
||||
extern size_t LoadAddr;
|
||||
extern bootinfo bootldr;
|
||||
extern unsigned char* environment;
|
||||
extern uint8_t fb;
|
||||
extern volatile unsigned char _binary_font_psf_start;
|
||||
extern volatile size_t* _kernel_text_start;
|
||||
|
||||
extern address_space_t KernelAddressSpace;
|
||||
|
||||
typedef struct {
|
||||
uint32_t magic;
|
||||
uint32_t version;
|
||||
uint32_t headerSize;
|
||||
uint32_t flags;
|
||||
uint32_t numGlyphs;
|
||||
uint32_t glyphSize;
|
||||
uint32_t glyphHeight;
|
||||
uint32_t glyphWidth;
|
||||
uint8_t glyphs;
|
||||
} __attribute__((packed)) psf_t;
|
||||
|
||||
|
||||
size_t KernelAddr;
|
||||
size_t KernelEnd;
|
||||
size_t MemoryPages;
|
||||
size_t MemorySize;
|
||||
|
||||
|
||||
void DrawPixel(uint32_t x, uint32_t y, uint32_t color);
|
||||
void FillScreen(uint32_t color);
|
||||
|
||||
void SetupExtensions();
|
||||
void PrepareCPU();
|
||||
|
||||
void WriteString(const char* string);
|
||||
void WriteChar(const char character);
|
||||
|
||||
void WriteStringWithFont(const char* string);
|
||||
|
||||
void InitInterrupts();
|
||||
void InitSerial();
|
||||
void InitPrint();
|
||||
|
||||
void SetupInitialGDT();
|
||||
void SetupIDT();
|
||||
|
||||
int Main();
|
||||
|
||||
void Exit();
|
||||
|
||||
void SomethingWentWrong(const char* Message);
|
|
@ -1,6 +1,11 @@
|
|||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint16_t LowLimit;
|
||||
uint16_t BaseLow;
|
||||
|
|
12
chroma/inc/kernel/system/heap.h
Normal file
12
chroma/inc/kernel/system/heap.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
uint8_t HeapEnabled = 0;
|
||||
|
|
@ -1,11 +1,20 @@
|
|||
#pragma once
|
||||
#include <stddef.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
extern const char* ExceptionStrings[];
|
||||
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
size_t ss;
|
||||
size_t rsp;
|
||||
size_t rflags;
|
||||
size_t cs;
|
||||
size_t rip;
|
||||
size_t cs;
|
||||
size_t rflags;
|
||||
size_t rsp;
|
||||
size_t ss;
|
||||
} INTERRUPT_FRAME;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
|
@ -17,10 +26,10 @@ typedef struct __attribute__((packed)) {
|
|||
size_t ss;
|
||||
} EXCEPTION_FRAME;
|
||||
|
||||
static void* IRQ_Handlers[16] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
typedef void (*IRQHandler)(INTERRUPT_FRAME* Frame);
|
||||
|
||||
extern IRQHandler IRQ_Handlers[16];
|
||||
|
||||
void IRQ_Common(INTERRUPT_FRAME* Frame, size_t Interupt);
|
||||
void ISR_Common(INTERRUPT_FRAME* Frame, size_t Interrupt);
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
#include <kernel/system/descriptors.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
#define PAUSE __asm__ __volatile__("pause")
|
||||
|
||||
uint8_t kbdSBuffer[8];
|
||||
uint8_t InputBuffer[128];
|
||||
|
||||
|
@ -32,6 +39,10 @@ void WriteTSR(uint16_t TSRData);
|
|||
|
||||
uint32_t ReadPort(uint16_t Port, int Length);
|
||||
uint32_t WritePort(uint16_t Port, uint32_t Data, int Length);
|
||||
|
||||
size_t ReadMMIO(size_t Address, int Length);
|
||||
void WriteMMIO(size_t Address, size_t Data, int Length);
|
||||
|
||||
size_t ReadModelSpecificRegister(size_t MSR);
|
||||
size_t WriteModelSpecificRegister(size_t MSR, size_t Data);
|
||||
|
||||
|
@ -44,9 +55,11 @@ uint32_t WriteMXCSR(uint32_t Data);
|
|||
size_t ReadControlRegister(int CRX);
|
||||
size_t WriteControlRegister(int CRX, size_t Data);
|
||||
|
||||
size_t ReadExtendedControlRegister(size_t XCRX);
|
||||
//size_t ReadExtendedControlRegister(size_t XCRX);
|
||||
size_t WriteExtendedControlRegister(size_t XCRX, size_t Data);
|
||||
|
||||
void InvalidatePage(size_t Page);
|
||||
|
||||
// XCS = Extended Code Segment
|
||||
size_t ReadXCS(void);
|
||||
|
||||
|
|
|
@ -1,5 +1,19 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <kernel/system/interrupts.h>
|
||||
#include <lainlib/lainlib.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
size_t KernelLocation;
|
||||
|
||||
|
||||
/************************************************
|
||||
* C O N S T A N T S A N D M A C R O S
|
||||
*************************************************/
|
||||
|
||||
#define PAGE_SIZE 4096
|
||||
#define PAGES_PER_BUCKET 8
|
||||
|
@ -10,16 +24,239 @@
|
|||
#define READ_BIT(i) ((OFFSET_BIT(i) >> (i % PAGES_PER_BUCKET)) & 0x1)
|
||||
#define GET_BUCKET32(i) (*((uint32_t*) (&Memory[i / 32])))
|
||||
|
||||
#define PAGE_ALIGN(addr) (((addr) & 0xFFFFF000) + 0x1000)
|
||||
#define CAST(a, b) ((a) (b))
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
#define REINTERPRET_CAST(target, intermediate, value) ((target*)((intermediate*)value))
|
||||
|
||||
#define CONCAT(x, y) x ## y
|
||||
#define CONCAT2(x, y) CONCAT(x, y)
|
||||
#define ASSERT(exp, error) \
|
||||
if(!(exp)) SomethingWentWrong(error);
|
||||
// typedef char CONCAT2(static_assert, __LINE__) [(exp) ? 1 : -1]
|
||||
|
||||
#define CLZ(num) (num ? __builtin_clzll(num) : 64)
|
||||
|
||||
#define IS_ALIGNED(addr) (((size_t) addr | 0xFFFFFFFFFFFFF000) == 0)
|
||||
#define PAGE_ALIGN(addr) ((((size_t) addr) & 0xFFFFFFFFFFFFF000) + 0x1000)
|
||||
|
||||
#define SET_PGBIT(cr0) (cr0 = cr0 | 1 << 31)
|
||||
#define UNSET_PGBIT(cr0) (cr0 = cr0 ^ 1 << 31)
|
||||
#define UNSET_PSEBIT(cr4) (cr4 = cr4 & 0xFFFFFFEF)
|
||||
|
||||
#define TOGGLE_PGEBIT(cr4) (cr4 = cr4 ^ (1 << 7))
|
||||
#define SET_PAEBIT(cr4) (cr4 = cr4 | 1 << 5)
|
||||
|
||||
#define ERR_PRESENT 0x1
|
||||
#define ERR_RW 0x2
|
||||
#define ERR_USER 0x4
|
||||
#define ERR_RESERVED 0x8
|
||||
#define ERR_INST 0x10
|
||||
|
||||
#define ELF64MAGIC 0x7F454c46
|
||||
|
||||
|
||||
/*
|
||||
* The way we boot, using BOOTBOOT, and the static hard drive images, means
|
||||
* we're limited to Protocol 1 - we cannot ask the bootloader to move anything
|
||||
* around for us.
|
||||
*
|
||||
* That means we need to account for these unmovable sections in the paging system.
|
||||
*
|
||||
* MMIO_REGION
|
||||
* Represents the MMIO symbol defined in the linkerscript and chroma.h.
|
||||
* FB_REGION
|
||||
* Represents the framebuffer used throughout the kernel.
|
||||
* This is likely the most important thing to keep where it is. Without this, we
|
||||
* have no video output.
|
||||
* KERNEL_REGION
|
||||
* This is where the kernel itself is loaded into memory. Protocol 1 means
|
||||
* we're loaded into the -2MB area.
|
||||
* We *CAN* mvoe the kernel about in memory. It's as simple as memcpying it around
|
||||
* and calling a void pointer as a function to return to where we were.
|
||||
* We *CANNOT* move the framebuffer in this manner, as it is set directly by BIOS,
|
||||
* and the graphics device most likely will not allow this to happen.
|
||||
* For this reason, the kernel, framebuffer and MMIO will remain where they are.
|
||||
* Luckily, there are more components of Chroma than the kernel itself. That's what
|
||||
* the kernel heap and kernel stack areas are for.
|
||||
*
|
||||
* USER_REGION
|
||||
* This is the dedicated space 0...7FFFFFFFFFFF for userspace.
|
||||
* No kernel objects or data will be put into this space.
|
||||
* Protocol 1 puts the page tables at 0xA000 by default, so these will have to be moved
|
||||
* up to kernel space.
|
||||
*
|
||||
* KERNEL_STACK_REGION
|
||||
* KERNEL_STACK_END
|
||||
* Encapsulate a 1GB large area of memory, to be used by the kernel for thread & interrupt stacks,
|
||||
* call unwinding and other debug information.
|
||||
*
|
||||
* KERNEL_HEAP_REGION
|
||||
* KERNEL_HEAP_END
|
||||
* Encapsulate another 1GB large area for kernel objects. ie. resources (images, sounds), libraries,
|
||||
* data structures, assorted information about the system.. etc.
|
||||
*
|
||||
* DIRECT_REGION
|
||||
* As mentioned above, the lower half is reserved for user space.
|
||||
* The higher half will be direct-mapped throughout.
|
||||
* This is the cutoff for the higher half - FFFF800000000000.
|
||||
*
|
||||
*/
|
||||
|
||||
#define MMIO_REGION 0xFFFFFFFFF8000000ull // Cannot move!
|
||||
#define FB_REGION 0xFFFFFFFFFC000000ull // Cannot move!
|
||||
#define FB_PHYSICAL 0x00000000E0000000ull // Physical location of the Framebuffer
|
||||
#define KERNEL_REGION 0xFFFFFFFFFFE00000ull // -2MiB, from bootloader
|
||||
|
||||
#define USER_REGION 0x00007FFFFFFFFFFFull // Not needed yet, but we're higher half so we might as well be thorough
|
||||
|
||||
#define KERNEL_STACK_REGION 0xFFFFE00000000000ull // Kernel Stack Space
|
||||
#define KERNEL_STACK_END 0xFFFFE00040000000ull // End of Kernel Stack Space
|
||||
|
||||
#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 DIRECT_REGION 0xFFFF800000000000ull
|
||||
|
||||
#define LOWER_REGION 0x0000000100000000ull // Lower Memory cutoff - 4GB
|
||||
|
||||
#define PAGE_SHIFT 12
|
||||
|
||||
/*********************************************
|
||||
* T Y P E D E F I N I T I O N S
|
||||
**********************************************/
|
||||
|
||||
typedef void* directptr_t;
|
||||
|
||||
typedef struct {
|
||||
ticketlock_t Lock;
|
||||
|
||||
directptr_t PML4;
|
||||
} address_space_t;
|
||||
|
||||
typedef enum {
|
||||
MAP_WRITE = 0x1,
|
||||
MAP_EXEC = 0x2,
|
||||
} mapflags_t;
|
||||
|
||||
typedef enum {
|
||||
CACHE_NONE,
|
||||
CACHE_WRITE_THROUGH,
|
||||
CACHE_WRITE_BACK,
|
||||
CACHE_WRITE_COMBINING
|
||||
} pagecache_t;
|
||||
|
||||
typedef struct {
|
||||
int MaxOrder;
|
||||
|
||||
directptr_t Base;
|
||||
|
||||
directptr_t* List;
|
||||
|
||||
ticketlock_t Lock;
|
||||
} buddy_t;
|
||||
|
||||
/*********************************************
|
||||
* A b s t r a c t A l l o c a t o r
|
||||
**********************************************/
|
||||
|
||||
const char* IntToAscii(int In);
|
||||
|
||||
typedef void* allocator_t;
|
||||
typedef void* mempool_t;
|
||||
|
||||
allocator_t CreateAllocator(void* Memory);
|
||||
allocator_t CreateAllocatorWithPool(void* Memory, size_t Bytes);
|
||||
|
||||
void DestroyAllocator(allocator_t Allocator);
|
||||
|
||||
mempool_t GetPoolFromAllocator(allocator_t Allocator);
|
||||
|
||||
mempool_t AddPoolToAllocator(allocator_t Allocator, void* Memory, size_t Bytes);
|
||||
void RemovePoolFromAllocator(allocator_t Allocator, mempool_t pool);
|
||||
|
||||
void* AllocatorMalloc (allocator_t Allocator, size_t Bytes);
|
||||
void* AllocatorMalign (allocator_t Allocator, size_t Alignment, size_t Bytes);
|
||||
void* AllocatorRealloc(allocator_t Allocator, void* VirtualAddress, size_t NewSize);
|
||||
void AllocatorFree (allocator_t Allocator, void* VirtualAddress);
|
||||
|
||||
size_t AllocatorGetBlockSize(void* VirtualAddress);
|
||||
|
||||
size_t AllocatorSize(void);
|
||||
size_t AllocatorAlignSize(void);
|
||||
size_t AllocatorMinBlockSize(void);
|
||||
size_t AllocatorMaxBlockSize(void);
|
||||
|
||||
size_t AllocatorPoolOverhead(void);
|
||||
size_t AllocatorAllocateOverhead(void);
|
||||
|
||||
|
||||
size_t AlignUpwards(size_t Pointer, size_t Alignment);
|
||||
size_t AlignDownwards(size_t Pointer, size_t Alignment);
|
||||
void* AlignPointer(const void* Pointer, size_t Alignment);
|
||||
|
||||
|
||||
/************************************************************
|
||||
* C h r o m a M e m o r y M a n a g e m e n t
|
||||
*************************************************************/
|
||||
|
||||
extern size_t memstart;
|
||||
|
||||
extern size_t end;
|
||||
|
||||
void ListMemoryMap();
|
||||
|
||||
void InitMemoryManager();
|
||||
|
||||
size_t AllocatePage();
|
||||
void AddRangeToPhysMem(directptr_t Base, size_t Size);
|
||||
|
||||
void FreePage(size_t PageNumber);
|
||||
directptr_t PhysAllocateLowMem(size_t Size);
|
||||
|
||||
size_t FirstFreePage();
|
||||
directptr_t PhysAllocateMem(size_t Size);
|
||||
|
||||
directptr_t PhysAllocateZeroMem(size_t Size);
|
||||
|
||||
directptr_t PhysAllocateLowZeroMem(size_t Size);
|
||||
|
||||
directptr_t PhysAllocatePage();
|
||||
|
||||
void PhysRefPage(directptr_t Page);
|
||||
|
||||
void PhysFreePage(directptr_t Page);
|
||||
|
||||
void FreePhysMem(directptr_t Phys);
|
||||
|
||||
size_t SeekFrame();
|
||||
|
||||
void MemoryTest();
|
||||
|
||||
void InitPaging();
|
||||
|
||||
void TraversePageTables();
|
||||
|
||||
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
|
||||
**********************************************/
|
||||
|
||||
void SetAddressSpace(address_space_t* Space);
|
||||
//TODO: Copy to/from Userspace
|
||||
void MapVirtualMemory(address_space_t* Space, void* VirtualAddress, size_t PhysicalAddress, mapflags_t Flags);
|
||||
void UnmapVirtualMemory(address_space_t* Space, void* VirtualAddress);
|
||||
|
||||
void CacheVirtualMemory(address_space_t* Space, void* VirtualAddress, pagecache_t CacheType);
|
||||
|
||||
void* AllocateMemory(size_t Bits);
|
||||
|
||||
void* ReallocateMemory(void* VirtualAddress, size_t NewSize);
|
||||
|
||||
void FreeMemory(void* VirtualAddress);
|
||||
|
||||
void* AllocateKernelStack();
|
||||
|
||||
void FreeKernelStack(void* StackAddress);
|
||||
|
||||
void PageFaultHandler(INTERRUPT_FRAME Frame);
|
173
chroma/inc/kernel/system/pci.h
Normal file
173
chroma/inc/kernel/system/pci.h
Normal file
|
@ -0,0 +1,173 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
/* This file contains all of the structures and definitions
|
||||
* required to compatibly access the PCI bus,
|
||||
* as well as set up new PCI devices, PCI bridges, and manipulate
|
||||
* the connections of PCI lanes.
|
||||
*/
|
||||
|
||||
#define PCI_CONFIG_ADDRESS 0xCF8
|
||||
#define PCI_CONFIG_DATA 0xCFC
|
||||
|
||||
|
||||
const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_t progif);
|
||||
|
||||
const char* PCIGetClassName(uint8_t devclass);
|
||||
|
||||
void PCIEnumerate();
|
||||
|
||||
uint32_t PCIReadConfig(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset);
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t io_space : 1; // Device can respond to I/O access
|
||||
uint8_t memory_space : 1; // Device can respond to memory access (device is MMIO mapped)
|
||||
uint8_t bus_master : 1; // Device is Bus Master; can generate PCI addresses
|
||||
uint8_t special_cycle : 1; // Device can monitor Special Cycle
|
||||
uint8_t memory_write_and_invalidate : 1; // Device can generate Memory Write And Invalidate commands; else Memory Write must be used
|
||||
uint8_t vga_palette : 1; // Device snoops the VGA palette on write; else is treated like a normal access
|
||||
uint8_t parity_error_response : 1; // Device responds to Parity Errors by setting PERR#; else will set pci_status#parity_error and continue.
|
||||
uint8_t _reserved : 1; // Hardwired to 0
|
||||
uint8_t serr : 1; // Enable SERR# driver; System ERRor
|
||||
uint8_t fast_back_back : 1; // Device is allowed to generate fast back-to-back transactions to other agents.
|
||||
uint8_t disable_interrupt : 1; // Disable assertion of INTx# signal; else enable.
|
||||
} pci_command_t;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t _reserved : 3; // 3 bits hardwired to 0
|
||||
uint8_t interrupt : 1; // State of device's INTx# signal. If pci_command#disable_interrupt is 0 and this is 1, the signal will be asserted.
|
||||
uint8_t capability_list : 1; // If set, device will implement New Capabilities list at 0x34 offset.
|
||||
uint8_t freq_66_capable : 1; // Device can run at 66MHz. Else, device will run at 33MHz.
|
||||
uint8_t _reserved1 : 1; // Reserved as of 3.0, Used in 2.1 as "Supports User Definable Features"
|
||||
uint8_t fast_back_back : 1; // Device is allowed to accept fast back-to-back transactions from other agents.
|
||||
uint8_t master_parity_error : 1; // Only set when PERR# is asserted by the Bus Master while pci_command#parity_error_response is set.
|
||||
uint8_t devsel_timing : 2; // Read-Only; represents the slowest time a device will assert DEVSEL#. 00 = fast, 01 = medium, 11 = slow.
|
||||
uint8_t target_signalled_abort : 1; // Target device terminated transaction via Target-Abort
|
||||
uint8_t received_target_abort : 1; // Master's connection was terminated by Target-Abort
|
||||
uint8_t received_master_abort : 1; // Master's connection was terminated by Master-Abort
|
||||
uint8_t system_error_asserted : 1; // Device asserted SERR#
|
||||
uint8_t parity_error : 1; // Device detected parity error. Parity error may not be handled.
|
||||
} pci_status_t;
|
||||
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint16_t vendor_id; // 16 bit Vendor ID allocated by PCI-SIG. 0xFFFF is invalid.
|
||||
uint16_t device_id; // 16 bit Device ID allocated by the vendor.
|
||||
pci_command_t command; // 16 bit PCI_COMMAND register.
|
||||
pci_status_t status; // 16 bit PCI_STATUS register.
|
||||
uint8_t revision_id; // 8 bit register, revision identifier specified by vendor.
|
||||
uint8_t progIF; // 8 bit register, identifies any programming interface the device may have.
|
||||
uint8_t subclass; // 8 bit Subclass code; identifies the specific function of the device
|
||||
uint8_t class_code; // 8 bit Class Code; identifies the function of the device
|
||||
uint8_t cache_line_size; // 8 bit; specifies system cache line size in 32-bit blocks. Devices can limit this. Unsupported values are treated as 0.
|
||||
uint8_t latency_timer; // 8 bit; specifies latency timer in (bus clock) units.
|
||||
uint8_t header_type; // 8 bit; identifies the layout of the header and the type of device; 00 = device, 01 = pci-pci bridge, 11 = CardBus bridge. Multi-function defined by bit 7.
|
||||
uint8_t bist; // 8 bit; status and control of a device's built-in self-test (BIST)
|
||||
} pci_header_common_t;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
// pci_header_common_t first, then..
|
||||
uint32_t bar[6]; // 6 x 32 bit Base Address Registers (BARs)
|
||||
uint32_t cis_pointer; // Points to Card Information Structure for PCI devices that share silicon with CardBus
|
||||
uint16_t subsystem_vendor_id;
|
||||
uint16_t subsystem_id;
|
||||
uint32_t expansion_bar; // Points to the base of an Expansion ROM.
|
||||
uint8_t capabilities; // The pointer generated by pci_status#capabilities_list
|
||||
uint8_t _reserved[3]; // 24 bit reserved at top end of register.
|
||||
uint32_t _reserved2;
|
||||
uint8_t interrupt_line; // Specifies the PIC pin that INTx# is connected to. Can be 0-15 because x86 PICs have 16 IRQs. 0xFF is no connection.
|
||||
uint8_t interrupt; // Specifies the interrupt pin the device uses. 0x1 is INTA#, 0x2 is INTB#, 0x3 is INTC#, 0x4 is INTD#, 0x0 is no interrupt.
|
||||
uint8_t min_grant; // Specifies the length of the burst period, in quarter-microsecond units
|
||||
uint8_t max_latency; // Specifies how often the device accesses the PCI bus - in quarter-microseconds
|
||||
} pci_header_device_t;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
// pci_header_common_t first
|
||||
uint32_t bar[2];
|
||||
uint8_t pri_bus; // Primary Bus Number.
|
||||
uint8_t sec_bus; // Secondary Bus Number.
|
||||
uint8_t sub_bus; // Subordinate Bus Number.
|
||||
uint8_t sec_latency_timer; // Secondary Latency Timer.
|
||||
uint8_t io_base; // IO Base is 24 bits. This is lower 8.
|
||||
uint8_t io_limit; // IO Limit is 24 bits. This is lower 8.
|
||||
pci_status_t sec_status; // Secondary Status.
|
||||
uint16_t mem_base;
|
||||
uint16_t mem_limit;
|
||||
uint16_t mem_base_prefetch; // Prefetchable Memory Base is 48 bits. This is lower 16.
|
||||
uint16_t mem_limit_prefetch; // Prefetchable Memory Limit is 48 bits. This is lower 16.
|
||||
uint32_t mem_base_prefetch_upper; // Prefetchable Memory Base is 48 bits. This is upper 32.
|
||||
uint32_t mem_limit_prefetch_upper; // Prefetchable Memory Limit is 48 bits. This is upper 32.
|
||||
uint16_t io_base_upper; // IO Base is 24 bits. This is upper 16.
|
||||
uint16_t io_limit_upper; // IO Limit is 24 bits. This is upper 16.
|
||||
uint8_t capabilities; // Pointer generated by pci_status#capabilities_list
|
||||
uint8_t _reserved[3]; // 24 reserved bits.
|
||||
uint32_t expansion_bar; // Base of Expansion ROM.
|
||||
uint8_t interrupt_line; // Specifies the PIC pin that INTx# is connected to. Can be 0-15 because x86 PICs have 16 IRQs. 0xFF is no connection.
|
||||
uint8_t interrupt; // Specifies the interrupt pin the device uses. 0x1 is INTA#, 0x2 is INTB#, 0x3 is INTC#, 0x4 is INTD#, 0x0 is no interrupt.
|
||||
uint16_t bridge_control;
|
||||
} pci_header_bridge_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint16_t segment;
|
||||
uint8_t bus;
|
||||
uint8_t slot;
|
||||
uint8_t function;
|
||||
} pci_address_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t present : 1;
|
||||
uint8_t mmio : 1;
|
||||
|
||||
union {
|
||||
size_t addr;
|
||||
uint16_t port;
|
||||
};
|
||||
size_t length;
|
||||
} pci_bar_t;
|
||||
|
||||
typedef struct pci_dev{
|
||||
|
||||
struct pci_dev* parent; // Parent of the device (for PCI hubs / splitters)
|
||||
|
||||
uint16_t device_id;
|
||||
uint16_t vendor_id;
|
||||
|
||||
uint8_t devclass;
|
||||
uint8_t subclass;
|
||||
|
||||
uint8_t progif;
|
||||
|
||||
pci_address_t address;
|
||||
|
||||
pci_bar_t bars[6];
|
||||
|
||||
int irq; // The IRQ of the device if already handled
|
||||
|
||||
// The headers!
|
||||
volatile pci_header_common_t* header;
|
||||
|
||||
union { // The device can only be one of these at a time, but they both form part of the config space.
|
||||
volatile pci_header_bridge_t* bridge;
|
||||
volatile pci_header_device_t* device;
|
||||
};
|
||||
|
||||
struct pci_dev** children; // If this device is a hub, it has children...
|
||||
|
||||
// acpi_node_t acpi;
|
||||
} pci_dev_t;
|
||||
|
||||
typedef struct {
|
||||
pci_address_t key;
|
||||
pci_dev_t* value;
|
||||
} pci_entry_t;
|
||||
|
||||
|
||||
extern pci_dev_t** pci_root_devices;
|
||||
extern pci_entry_t* pci_map;
|
15
chroma/inc/kernel/system/stack.h
Normal file
15
chroma/inc/kernel/system/stack.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
typedef struct stackframe {
|
||||
struct stackframe* rbp;
|
||||
size_t rip;
|
||||
} stackframe_t;
|
||||
|
||||
void StackTrace(size_t cycles);
|
|
@ -1,6 +1,6 @@
|
|||
/************************
|
||||
*** Team Kitty, 2019 ***
|
||||
*** Sync ***
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
// This file contains all of the bitmap fonts made by me (Curle) and taken from the public domain
|
||||
|
|
327
chroma/inc/lainlib/compression/lzg.h
Normal file
327
chroma/inc/lainlib/compression/lzg.h
Normal file
|
@ -0,0 +1,327 @@
|
|||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* This file is part of liblzg.
|
||||
*
|
||||
* Copyright (c) 2010-2018 Marcus Geelnard
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would
|
||||
* be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
|
||||
#ifndef _LIBLZG_H_
|
||||
#define _LIBLZG_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define LZG_VERSION "1.0.10" /**< @brief LZG library version string */
|
||||
#define LZG_VERNUM 0x0100000a /**< @brief LZG library version number (strictly
|
||||
incremental) */
|
||||
#define LZG_VER_MAJOR 1 /**< @brief LZG library major version */
|
||||
#define LZG_VER_MINOR 0 /**< @brief LZG library minor version */
|
||||
#define LZG_VER_REVISION 10 /**< @brief LZG library revision */
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @mainpage
|
||||
*
|
||||
* @section intro_sec Introduction
|
||||
*
|
||||
* liblzg is a minimal implementation of an LZ77 class compression library. The
|
||||
* main characteristic of the library is that the decoding routine is very
|
||||
* simple, fast and requires no extra memory (except for the encoded and decoded
|
||||
* data buffers).
|
||||
*
|
||||
* @section funcs_sec Functions
|
||||
*
|
||||
* @li LZG_MaxEncodedSize() - Determine the maximum size of the encoded data for
|
||||
* a given uncompressed buffer (worst case).
|
||||
* @li LZG_InitEncoderConfig() - Set default encoder configuration.
|
||||
* @li LZG_Encode() - Encode uncompressed data as LZG coded data.
|
||||
* @li LZG_EncodeFull() - Same as LZG_Encode(), but using custom memory
|
||||
* allocation.
|
||||
* @li LZG_WorkMemSize() - Determine the amount of memory required for encoding
|
||||
* (useful for LZG_EncodeFull()).
|
||||
*
|
||||
* @li LZG_DecodedSize() - Determine the size of the decoded data for a given
|
||||
* LZG coded buffer.
|
||||
* @li LZG_Decode() - Decode LZG coded data.
|
||||
*
|
||||
* @li LZG_Version() - Get the version of the LZG library.
|
||||
* @li LZG_VersionString() - Get the version of the LZG library.
|
||||
*
|
||||
* @section compr_sec Compression
|
||||
* Here is a simple example of compressing an uncompressed data buffer (given
|
||||
* as buf/bufSize).
|
||||
*
|
||||
* @code
|
||||
* unsigned char *encBuf;
|
||||
* lzg_uint32_t encSize, maxEncSize;
|
||||
*
|
||||
* // Determine maximum size of compressed data
|
||||
* maxEncSize = LZG_MaxEncodedSize(bufSize);
|
||||
*
|
||||
* // Allocate memory for the compressed data
|
||||
* encBuf = (unsigned char*) malloc(maxEncSize);
|
||||
* if (encBuf)
|
||||
* {
|
||||
* // Compress
|
||||
* encSize = LZG_Encode(buf, bufSize, encBuf, maxEncSize, NULL);
|
||||
* if (encSize)
|
||||
* {
|
||||
* // Compressed data is now in encBuf, use it...
|
||||
* // ...
|
||||
* }
|
||||
* else
|
||||
* fprintf(stderr, "Compression failed!\n");
|
||||
*
|
||||
* // Free memory when we're done with the compressed data
|
||||
* free(encBuf);
|
||||
* }
|
||||
* else
|
||||
* fprintf(stderr, "Out of memory!\n");
|
||||
* @endcode
|
||||
*
|
||||
* @section decompr_sec Decompression
|
||||
* Here is a simple example of decompressing a compressed data buffer (given
|
||||
* as buf/bufSize).
|
||||
*
|
||||
* @code
|
||||
* unsigned char *decBuf;
|
||||
* lzg_uint32_t decSize;
|
||||
*
|
||||
* // Determine size of decompressed data
|
||||
* decSize = LZG_DecodedSize(buf, bufSize);
|
||||
* if (decSize)
|
||||
* {
|
||||
* // Allocate memory for the decompressed data
|
||||
* decBuf = (unsigned char*) malloc(decSize);
|
||||
* if (decBuf)
|
||||
* {
|
||||
* // Decompress
|
||||
* decSize = LZG_Decode(buf, bufSize, decBuf, decSize);
|
||||
* if (decSize)
|
||||
* {
|
||||
* // Uncompressed data is now in decBuf, use it...
|
||||
* // ...
|
||||
* }
|
||||
* else
|
||||
* printf("Decompression failed (bad data)!\n");
|
||||
*
|
||||
* // Free memory when we're done with the decompressed data
|
||||
* free(decBuf);
|
||||
* }
|
||||
* else
|
||||
* printf("Out of memory!\n");
|
||||
* }
|
||||
* else
|
||||
* printf("Bad input data!\n");
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
/* Basic types */
|
||||
typedef int lzg_bool_t; /**< @brief Boolean (@ref LZG_TRUE/@ref LZG_FALSE) */
|
||||
typedef int lzg_int32_t; /**< @brief Signed 32-bit integer */
|
||||
typedef unsigned int lzg_uint32_t; /**< @brief Unsigned 32-bit integer */
|
||||
|
||||
#define LZG_FALSE 0 /**< @brief Boolean FALSE (see @ref lzg_bool_t) */
|
||||
#define LZG_TRUE 1 /**< @brief Boolean TRUE (see @ref lzg_bool_t) */
|
||||
|
||||
/* Compression levels */
|
||||
#define LZG_LEVEL_1 1 /**< @brief Lowest/fastest compression level */
|
||||
#define LZG_LEVEL_2 2 /**< @brief Compression level 2 */
|
||||
#define LZG_LEVEL_3 3 /**< @brief Compression level 3 */
|
||||
#define LZG_LEVEL_4 4 /**< @brief Compression level 4 */
|
||||
#define LZG_LEVEL_5 5 /**< @brief Medium compression level */
|
||||
#define LZG_LEVEL_6 6 /**< @brief Compression level 6 */
|
||||
#define LZG_LEVEL_7 7 /**< @brief Compression level 7 */
|
||||
#define LZG_LEVEL_8 8 /**< @brief Compression level 8 */
|
||||
#define LZG_LEVEL_9 9 /**< @brief Best/slowest compression level */
|
||||
|
||||
/** @brief Default compression level */
|
||||
#define LZG_LEVEL_DEFAULT LZG_LEVEL_5
|
||||
|
||||
/**
|
||||
* Progress callback function.
|
||||
* @param[in] progress The current progress (0-100).
|
||||
* @param[in] userdata User supplied data pointer.
|
||||
*/
|
||||
typedef void (*LZGPROGRESSFUN)(lzg_int32_t progress, void *userdata);
|
||||
|
||||
/** @brief LZG compression configuration parameters.
|
||||
*
|
||||
* This structure is used for passing configuration options to the LZG_Encode()
|
||||
* function. Initialize this structure to default values with
|
||||
* @ref LZG_InitEncoderConfig().
|
||||
*/
|
||||
typedef struct {
|
||||
/** @brief Compression level (1-9).
|
||||
|
||||
For convenience, you can use the predefined constants
|
||||
@ref LZG_LEVEL_1 (fast) to @ref LZG_LEVEL_9 (slow), or
|
||||
@ref LZG_LEVEL_DEFAULT.
|
||||
|
||||
Default value: LZG_LEVEL_DEFAULT */
|
||||
lzg_int32_t level;
|
||||
|
||||
/** @brief Use fast method (LZG_FALSE or LZG_TRUE).
|
||||
|
||||
Boolean flag that specifies whether or not to use a faster encoding
|
||||
acceleration data structure, which requires more memory. When using the
|
||||
fast method, the compression ratio is usually slightly improved.
|
||||
|
||||
Default value: LZG_TRUE */
|
||||
lzg_bool_t fast;
|
||||
|
||||
/** @brief Encoding progress callback function.
|
||||
|
||||
This function will be called during compression to report progress
|
||||
back to the caller (set this to NULL to disable progress
|
||||
callback).
|
||||
|
||||
Default value: NULL */
|
||||
LZGPROGRESSFUN progressfun;
|
||||
|
||||
/** @brief User data pointer for the progress callback function.
|
||||
|
||||
A user defined data pointer that can point to anything that the
|
||||
progress callback function may need, such as an object reference
|
||||
(this can set to NULL if the callback function does not need it).
|
||||
|
||||
Default value: NULL */
|
||||
void *userdata;
|
||||
} lzg_encoder_config_t;
|
||||
|
||||
|
||||
/**
|
||||
* Determine the maximum size of the encoded data for a given uncompressed
|
||||
* buffer.
|
||||
* @param[in] insize Size of the uncompressed buffer (number of bytes).
|
||||
* @return Worst case (maximum) size of the encoded data.
|
||||
*/
|
||||
lzg_uint32_t LZG_MaxEncodedSize(lzg_uint32_t insize);
|
||||
|
||||
/**
|
||||
* Initialize an encoder configuration object.
|
||||
* @param[out] config Configuration object.
|
||||
*/
|
||||
void LZG_InitEncoderConfig(lzg_encoder_config_t *config);
|
||||
|
||||
/**
|
||||
* Determine the amount of memory required for encoding.
|
||||
* @param[in] config Compression configuration (if set to NULL, default encoder
|
||||
* configuration parameters are used).
|
||||
* @retrun The size of the buffer required.
|
||||
*/
|
||||
lzg_uint32_t LZG_WorkMemSize(lzg_encoder_config_t *config);
|
||||
|
||||
/**
|
||||
* Encode uncompressed data using the LZG coder (i.e. compress the data).
|
||||
* @param[in] in Input (uncompressed) buffer.
|
||||
* @param[in] insize Size of the input buffer (number of bytes).
|
||||
* @param[out] out Output (compressed) buffer.
|
||||
* @param[in] outsize Size of the output buffer (number of bytes).
|
||||
* @param[in] config Compression configuration (if set to NULL, default encoder
|
||||
* configuration parameters are used).
|
||||
* @return The size of the encoded data, or zero if the function failed
|
||||
* (e.g. if the end of the output buffer was reached before the
|
||||
* entire input buffer was encoded).
|
||||
* @note For the slow method (config->fast = 0), the memory requirement during
|
||||
* compression is 136 KB (LZG_LEVEL_1) to 2 MB (LZG_LEVEL_9). For the fast
|
||||
* method (config->fast = 1), the memory requirement is 64 MB (LZG_LEVEL_1) to
|
||||
* 66 MB (LZG_LEVEL_9). Also note that these figures are doubled on 64-bit
|
||||
* systems.
|
||||
*/
|
||||
lzg_uint32_t LZG_Encode(const unsigned char *in, lzg_uint32_t insize,
|
||||
unsigned char *out, lzg_uint32_t outsize,
|
||||
lzg_encoder_config_t *config);
|
||||
|
||||
/**
|
||||
* Encode uncompressed data using the LZG coder (i.e. compress the data).
|
||||
* @param[in] in Input (uncompressed) buffer.
|
||||
* @param[in] insize Size of the input buffer (number of bytes).
|
||||
* @param[out] out Output (compressed) buffer.
|
||||
* @param[in] outsize Size of the output buffer (number of bytes).
|
||||
* @param[in] config Compression configuration (if set to NULL, default encoder
|
||||
* configuration parameters are used).
|
||||
* @param[in] workmem Buffer to be used for compression, or NULL. See
|
||||
* @ref LZG_WorkMemSize.
|
||||
* @return The size of the encoded data, or zero if the function failed
|
||||
* (e.g. if the end of the output buffer was reached before the
|
||||
* entire input buffer was encoded).
|
||||
* @note For the slow method (config->fast = 0), the memory requirement during
|
||||
* compression is 136 KB (LZG_LEVEL_1) to 2 MB (LZG_LEVEL_9). For the fast
|
||||
* method (config->fast = 1), the memory requirement is 64 MB (LZG_LEVEL_1) to
|
||||
* 66 MB (LZG_LEVEL_9). Also note that these figures are doubled on 64-bit
|
||||
* systems.
|
||||
*/
|
||||
lzg_uint32_t LZG_EncodeFull(const unsigned char *in, lzg_uint32_t insize,
|
||||
unsigned char *out, lzg_uint32_t outsize,
|
||||
lzg_encoder_config_t *config,
|
||||
void *workmem);
|
||||
|
||||
/**
|
||||
* Determine the size of the decoded data for a given LZG coded buffer.
|
||||
* @param[in] in Input (compressed) buffer.
|
||||
* @param[in] insize Size of the input buffer (number of bytes). This does
|
||||
* not have to be the size of the entire compressed data, but
|
||||
* it has to be at least 7 bytes (the first few bytes of the
|
||||
* header, including the decompression size).
|
||||
* @return The size of the decoded data, or zero if the function failed
|
||||
* (e.g. if the magic header ID could not be found).
|
||||
*/
|
||||
lzg_uint32_t LZG_DecodedSize(const unsigned char *in, lzg_uint32_t insize);
|
||||
|
||||
|
||||
/**
|
||||
* Decode LZG coded data.
|
||||
* @param[in] in Input (compressed) buffer.
|
||||
* @param[in] insize Size of the input buffer (number of bytes).
|
||||
* @param[out] out Output (uncompressed) buffer.
|
||||
* @param[in] outsize Size of the output buffer (number of bytes).
|
||||
* @return The size of the decoded data, or zero if the function failed
|
||||
* (e.g. if the end of the output buffer was reached before the
|
||||
* entire input buffer was decoded).
|
||||
*/
|
||||
lzg_uint32_t LZG_Decode(const unsigned char *in, lzg_uint32_t insize,
|
||||
unsigned char *out, lzg_uint32_t outsize);
|
||||
|
||||
|
||||
/**
|
||||
* Get the version of the LZG library.
|
||||
* @return The version of the LZG library, on the same format as
|
||||
* @ref LZG_VERNUM.
|
||||
*/
|
||||
lzg_uint32_t LZG_Version(void);
|
||||
|
||||
|
||||
/**
|
||||
* Get the version string of the LZG library.
|
||||
* @return The version of the LZG library, on the same format as
|
||||
* @ref LZG_VERSION.
|
||||
*/
|
||||
const char* LZG_VersionString(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _LIBLZG_H_
|
25
chroma/inc/lainlib/lainlib.h
Normal file
25
chroma/inc/lainlib/lainlib.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
|
||||
/* Defines all of the temporary library functions.
|
||||
* All of this must be moved into the Chroma stdlib.
|
||||
* They exist here as guidance, and as utility for the kernel itself.
|
||||
* If need be, they can also be moved into a trimmed-down "kernel libc" or "libk".
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <lainlib/vector/vector.h>
|
||||
|
||||
#include <lainlib/list/list.h>
|
||||
|
||||
#include <lainlib/mutex/spinlock.h>
|
||||
#include <lainlib/mutex/ticketlock.h>
|
||||
|
||||
#include <lainlib/compression/lzg.h>
|
34
chroma/inc/lainlib/list/list.h
Normal file
34
chroma/inc/lainlib/list/list.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#include <stdbool.h>
|
||||
|
||||
typedef struct list_entry {
|
||||
struct list_entry* Previous;
|
||||
struct list_entry* Next;
|
||||
} list_entry_t;
|
||||
|
||||
#define UNSAFE_CAST(ptr, type, member) \
|
||||
((type*)((char*)(ptr) - (char*)offsetof(type, member)))
|
||||
|
||||
#define LISTNEW(var) \
|
||||
((list_entry_t){ 0, 0 })
|
||||
|
||||
void ListAdd(list_entry_t* Head, list_entry_t* New);
|
||||
|
||||
void ListEmplaceBack(list_entry_t* Head, list_entry_t* Tail);
|
||||
|
||||
void ListRemove(list_entry_t* List);
|
||||
|
||||
bool ListIsEmpty(list_entry_t* Head);
|
||||
|
||||
#define LISTNEXT(current, member) \
|
||||
UNSAFE_CAST((current)->member.next, typeof(*(current)), member);
|
||||
|
||||
#define LISTPREV(current, member) \
|
||||
UNSAFE_CAST((current)->member.prev, typeof(*(curent)), member)
|
||||
|
||||
#define LISTFOREACH(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||
|
||||
#define LISTFOREACHENTRY(pos, head, member) \
|
||||
for(pos = UNSAFE_CAST((head)->next, typeof(*(pos)), member); &pos->member != (head); pos = LISTNEXT(pos, member))
|
||||
|
||||
#define LASTENTRY 0
|
22
chroma/inc/lainlib/mutex/spinlock.h
Normal file
22
chroma/inc/lainlib/mutex/spinlock.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
|
||||
typedef volatile int spinlock_t;
|
||||
|
||||
/* A set of macros that acquire and release a mutex spinlock. */
|
||||
//TODO: this *needs* to be moved to a kernel header.
|
||||
|
||||
#define SPINLOCK(name) \
|
||||
while( !__sync_bool_compare_and_swap(name, 0, 1)); \
|
||||
__sync_synchronize();
|
||||
|
||||
|
||||
#define SPUNLOCK(name) \
|
||||
__sync_synchronize(); \
|
||||
name = 0;
|
||||
|
32
chroma/inc/lainlib/mutex/ticketlock.h
Normal file
32
chroma/inc/lainlib/mutex/ticketlock.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
#include <stdbool.h>
|
||||
#include <stdatomic.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
/* This file provides a simple implementation of a ticket-based locking system.
|
||||
* You should probably prefer Spinlock over Ticketlock.
|
||||
*
|
||||
* Create a new lock with NEW_TICKETLOCK(),
|
||||
* lock a resource with TicketLock().
|
||||
*
|
||||
* Use TicketUnlock() to free the resource after you are done.
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
atomic_size_t NowServing;
|
||||
atomic_size_t NextTicket;
|
||||
} ticketlock_t;
|
||||
|
||||
#define NEW_TICKETLOCK() (ticketlock_t{0})
|
||||
|
||||
void TicketLock(ticketlock_t* Lock);
|
||||
|
||||
bool TicketAttemptLock(ticketlock_t* Lock);
|
||||
|
||||
void TicketUnlock(ticketlock_t* Lock);
|
||||
|
30
chroma/inc/lainlib/vector/vector.h
Normal file
30
chroma/inc/lainlib/vector/vector.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include<stddef.h>
|
||||
#include<stdint.h>
|
||||
#include <lainlib/mutex/spinlock.h>
|
||||
|
||||
struct vector_t {
|
||||
void** items;
|
||||
size_t n;
|
||||
|
||||
spinlock_t vector_lock;
|
||||
};
|
||||
|
||||
int VectorRemoveItem(struct vector_t* vec, void* item);
|
||||
|
||||
int VectorRemove(struct vector_t* vec, size_t index);
|
||||
|
||||
void* VectorGet(struct vector_t* vec, size_t index);
|
||||
|
||||
int VectorInsert(struct vector_t* vec, void* item, size_t index);
|
||||
|
||||
int VectorAppend(struct vector_t* vec, void* item);
|
||||
|
||||
int VectorDestroy(struct vector_t* vec);
|
|
@ -1,20 +1,101 @@
|
|||
#include <kernel/chroma.h>
|
||||
//#include <kernel/system/screen.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
/* This file is the entry point to the system.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
void _start(void) {
|
||||
|
||||
SerialPrintf("\r\nBooting Chroma..\r\n");
|
||||
size_t KernelAddr = (size_t) &LoadAddr;
|
||||
size_t KernelEnd = (size_t) &end;
|
||||
|
||||
address_space_t KernelAddressSpace;
|
||||
|
||||
int Main(void) {
|
||||
KernelAddressSpace = (address_space_t) {0};
|
||||
KernelLocation = 0x112600;
|
||||
|
||||
SerialPrintf("\r\n[ boot] Booting Chroma..\r\n");
|
||||
SerialPrintf("[ boot] Kernel loaded at 0x%p, ends at 0x%p, is %d bytes long.\r\n", KernelAddr, KernelEnd, KernelEnd - KernelAddr);
|
||||
SerialPrintf("[ boot] Initrd is physically at 0x%p, and is %d bytes long.\r\n", bootldr.initrd_ptr, bootldr.initrd_size);
|
||||
|
||||
SerialPrintf("[ boot] Searching for kernel... Constants start at 0x%p\r\n", &_kernel_text_start);
|
||||
// We stop at the constants in the kernel, otherwise we'll read the constant ELF64MAGIC which is stored inside the kernel...
|
||||
|
||||
size_t headerLoc = 0;
|
||||
for(size_t i = KernelAddr; i < KernelEnd; i++) {
|
||||
if(i < (size_t) (&_kernel_text_start) - KernelAddr) {
|
||||
if(*((volatile uint32_t*)(i)) == ELF64MAGIC) {
|
||||
SerialPrintf("[ boot] Matched kernel header at 0x%p.\r\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int flag = 0;
|
||||
|
||||
if(headerLoc) {
|
||||
ELF64Header_t* PotentialKernelHeader = (ELF64Header_t*) &headerLoc;
|
||||
SerialPrintf(
|
||||
"[ boot] Considering ELF with:\r\n\tBitness %d\r\n\tEntry point 0x%p\r\n\tFile type %s : %d\r\n\tArchitecture %s : %d\r\n",
|
||||
PotentialKernelHeader->Class == 2 ? 64 : 32, PotentialKernelHeader->EntryPoint, PotentialKernelHeader->Type == 0x02 ? "EXECUTABLE" : "OTHER", PotentialKernelHeader->Type, PotentialKernelHeader->TargetArchitecture == 0x3E ? "AMD64" : "OTHER", PotentialKernelHeader->TargetArchitecture);
|
||||
if(PotentialKernelHeader->EntryPoint == KernelAddr) {
|
||||
SerialPrintf("[ boot] Header at 0x%p matches kernel header.\r\n", headerLoc);
|
||||
flag = 1;
|
||||
}
|
||||
|
||||
if(!flag) {
|
||||
|
||||
for(size_t i = 0; i < 8; i++) {
|
||||
SerialPrintf("[ boot] Header dump part %d: 0x%x\r\n", i, *((volatile uint32_t*)(headerLoc + i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!flag) {
|
||||
SerialPrintf("[ boot] Unable to find kernel in memory. Fatal error.\r\n");
|
||||
//for(;;) {}
|
||||
}
|
||||
|
||||
SerialPrintf("[ boot] The bootloader has put the paging tables at 0x%p.\r\n", ReadControlRegister(3));
|
||||
|
||||
//TraversePageTables();
|
||||
|
||||
ListMemoryMap();
|
||||
|
||||
InitPrint();
|
||||
|
||||
SetupInitialGDT();
|
||||
SetupIDT();
|
||||
InitInterrupts();
|
||||
WriteStringWithFont("Initty Testing");
|
||||
|
||||
PrepareCPU();
|
||||
|
||||
PCIEnumerate();
|
||||
|
||||
InitMemoryManager();
|
||||
MemoryTest();
|
||||
|
||||
//DrawSplash();
|
||||
|
||||
InitPaging();
|
||||
|
||||
|
||||
for(;;) { }
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void SomethingWentWrong(const char* Message) {
|
||||
SerialPrintf("Assertion failed! %s\r\n", Message);
|
||||
//for(;;){}
|
||||
}
|
||||
|
||||
void Exit(int ExitCode) {
|
||||
SerialPrintf("Kernel stopped with code %x\r\n", ExitCode);
|
||||
|
||||
}
|
190
chroma/lainlib/compression/lzgmini.c
Normal file
190
chroma/lainlib/compression/lzgmini.c
Normal file
|
@ -0,0 +1,190 @@
|
|||
/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* This file is part of liblzg.
|
||||
*
|
||||
* Copyright (c) 2010 Marcus Geelnard
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would
|
||||
* be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
|
||||
#include <lainlib/lainlib.h>
|
||||
|
||||
/*-- PRIVATE -----------------------------------------------------------------*/
|
||||
|
||||
/* Internal definitions */
|
||||
#define LZG_HEADER_SIZE 16
|
||||
#define LZG_METHOD_COPY 0
|
||||
#define LZG_METHOD_LZG1 1
|
||||
|
||||
/* Endian and alignment independent reader for 32-bit integers */
|
||||
#define _LZG_GetUINT32(in, offs) \
|
||||
((((lzg_uint32_t)in[offs]) << 24) | \
|
||||
(((lzg_uint32_t)in[offs+1]) << 16) | \
|
||||
(((lzg_uint32_t)in[offs+2]) << 8) | \
|
||||
((lzg_uint32_t)in[offs+3]))
|
||||
|
||||
/* Calculate the checksum */
|
||||
static lzg_uint32_t _LZG_CalcChecksum(const unsigned char *data, lzg_uint32_t size)
|
||||
{
|
||||
unsigned short a = 1, b = 0;
|
||||
unsigned char *end = (unsigned char *)data + size;
|
||||
while (data != end)
|
||||
{
|
||||
a += *data++;
|
||||
b += a;
|
||||
}
|
||||
return (((lzg_uint32_t)b) << 16) | a;
|
||||
}
|
||||
|
||||
/* LUT for decoding the copy length parameter */
|
||||
static const unsigned char _LZG_LENGTH_DECODE_LUT[32] = {
|
||||
2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,
|
||||
18,19,20,21,22,23,24,25,26,27,28,29,35,48,72,128
|
||||
};
|
||||
|
||||
|
||||
/*-- PUBLIC ------------------------------------------------------------------*/
|
||||
|
||||
lzg_uint32_t LZG_DecodedSize(const unsigned char *in, lzg_uint32_t insize)
|
||||
{
|
||||
/* Check header */
|
||||
if ((insize < 7) || (in[0] != 'L') || (in[1] != 'Z') || (in[2] != 'G'))
|
||||
return 0;
|
||||
|
||||
/* Get output buffer size */
|
||||
return _LZG_GetUINT32(in, 3);
|
||||
}
|
||||
|
||||
lzg_uint32_t LZG_Decode(const unsigned char *in, lzg_uint32_t insize,
|
||||
unsigned char *out, lzg_uint32_t outsize)
|
||||
{
|
||||
unsigned char *src, *inEnd, *dst, *outEnd, *copy, symbol, b, b2;
|
||||
unsigned char m1, m2, m3, m4, method;
|
||||
lzg_uint32_t i, length, offset, encodedSize, decodedSize, checksum;
|
||||
|
||||
/* Check magic ID */
|
||||
if ((insize < LZG_HEADER_SIZE) || (in[0] != 'L') || (in[1] != 'Z') || (in[2] != 'G'))
|
||||
return 0;
|
||||
|
||||
/* Get header data */
|
||||
decodedSize = _LZG_GetUINT32(in, 3);
|
||||
encodedSize = _LZG_GetUINT32(in, 7);
|
||||
checksum = _LZG_GetUINT32(in, 11);
|
||||
|
||||
/* Check sizes */
|
||||
if ((outsize < decodedSize) || (encodedSize != (insize - LZG_HEADER_SIZE)))
|
||||
return 0;
|
||||
|
||||
/* Check checksum */
|
||||
if (_LZG_CalcChecksum(&in[LZG_HEADER_SIZE], encodedSize) != checksum)
|
||||
return 0;
|
||||
|
||||
/* Initialize the byte streams */
|
||||
src = (unsigned char *)in + LZG_HEADER_SIZE;;
|
||||
inEnd = ((unsigned char *)in) + insize;
|
||||
dst = out;
|
||||
outEnd = out + outsize;
|
||||
|
||||
/* Check which method to use */
|
||||
method = in[15];
|
||||
if (method == LZG_METHOD_LZG1)
|
||||
{
|
||||
if (!((src + 4) <= inEnd)) return 0;
|
||||
m1 = *src++; m2 = *src++; m3 = *src++; m4 = *src++;
|
||||
|
||||
/* Main decompression loop */
|
||||
while (src < inEnd)
|
||||
{
|
||||
symbol = *src++;
|
||||
|
||||
if ((symbol != m1) && (symbol != m2) && (symbol != m3) && (symbol != m4))
|
||||
{
|
||||
/* Literal copy */
|
||||
if (!(dst < outEnd)) return 0;
|
||||
*dst++ = symbol;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Decode offset / length parameters */
|
||||
if (!(src < inEnd)) return 0;
|
||||
if ((b = *src++))
|
||||
{
|
||||
if (symbol == m1)
|
||||
{
|
||||
/* Distant copy */
|
||||
if (!((src + 2) <= inEnd)) return 0;
|
||||
length = _LZG_LENGTH_DECODE_LUT[b & 0x1f];
|
||||
b2 = *src++;
|
||||
offset = (((unsigned int)(b & 0xe0)) << 11) |
|
||||
(((unsigned int)b2) << 8) |
|
||||
(*src++);
|
||||
offset += 2056;
|
||||
}
|
||||
else if (symbol == m2)
|
||||
{
|
||||
/* Medium copy */
|
||||
if (!(src < inEnd)) return 0;
|
||||
length = _LZG_LENGTH_DECODE_LUT[b & 0x1f];
|
||||
b2 = *src++;
|
||||
offset = (((unsigned int)(b & 0xe0)) << 3) | b2;
|
||||
offset += 8;
|
||||
}
|
||||
else if (symbol == m3)
|
||||
{
|
||||
/* Short copy */
|
||||
length = (b >> 6) + 3;
|
||||
offset = (b & 0x3f) + 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Near copy (including RLE) */
|
||||
length = _LZG_LENGTH_DECODE_LUT[b & 0x1f];
|
||||
offset = (b >> 5) + 1;
|
||||
}
|
||||
|
||||
/* Copy the corresponding data from the history window */
|
||||
copy = dst - offset;
|
||||
if (!((copy >= out) && ((dst + length) <= outEnd))) return 0;
|
||||
for (i = 0; i < length; ++i)
|
||||
*dst++ = *copy++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Literal copy (single occurance of a marker symbol) */
|
||||
if (!(dst < outEnd)) return 0;
|
||||
*dst++ = symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (method == LZG_METHOD_COPY)
|
||||
{
|
||||
/* Plain copy */
|
||||
while ((src < inEnd) && (dst < outEnd))
|
||||
*dst++ = *src++;
|
||||
}
|
||||
|
||||
/* All OK? */
|
||||
if ((unsigned int)(dst - out) != decodedSize)
|
||||
return 0;
|
||||
else
|
||||
return decodedSize;
|
||||
}
|
27
chroma/lainlib/list/basic_list.c
Normal file
27
chroma/lainlib/list/basic_list.c
Normal file
|
@ -0,0 +1,27 @@
|
|||
#include <lainlib/list/list.h>
|
||||
|
||||
void ListAdd(list_entry_t* Head, list_entry_t* New) {
|
||||
New->Next = Head->Next;
|
||||
New->Previous = Head;
|
||||
New->Next->Previous = New;
|
||||
Head->Next = New;
|
||||
}
|
||||
|
||||
void ListEmplaceBack(list_entry_t* Head, list_entry_t* New) {
|
||||
New->Next = Head;
|
||||
New->Previous = Head->Previous;
|
||||
New->Previous->Next = New;
|
||||
Head->Previous = New;
|
||||
}
|
||||
|
||||
void ListRemove(list_entry_t* Entry) {
|
||||
Entry->Next->Previous = Entry->Previous;
|
||||
Entry->Previous->Next = Entry->Next;
|
||||
|
||||
Entry->Previous = (void*)0xDEADull;
|
||||
Entry->Next = (void*)0xBEEFull;
|
||||
}
|
||||
|
||||
bool ListIsEmpty(list_entry_t* Head) {
|
||||
return Head->Next == Head;
|
||||
}
|
21
chroma/lainlib/mutex/ticketlock.c
Normal file
21
chroma/lainlib/mutex/ticketlock.c
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include <kernel/chroma.h>
|
||||
#include <lainlib/lainlib.h>
|
||||
|
||||
void TicketLock(ticketlock_t* Lock) {
|
||||
size_t Ticket = atomic_fetch_add_explicit(&Lock->NextTicket, 1, memory_order_relaxed);
|
||||
|
||||
while(atomic_load_explicit(&Lock->NowServing, memory_order_acquire) != Ticket) {
|
||||
PAUSE;
|
||||
}
|
||||
}
|
||||
|
||||
bool TicketAttemptLock(ticketlock_t* Lock) {
|
||||
size_t Ticket = atomic_load_explicit(&Lock->NowServing, memory_order_relaxed);
|
||||
|
||||
return atomic_compare_exchange_strong_explicit(&Lock->NowServing, &Ticket, Ticket + 1, memory_order_acquire, memory_order_relaxed);
|
||||
}
|
||||
|
||||
void TicketUnlock(ticketlock_t* Lock) {
|
||||
size_t NextTicket = atomic_load_explicit(&Lock->NowServing, memory_order_relaxed) + 1;
|
||||
atomic_store_explicit(&Lock->NowServing, NextTicket, memory_order_release);
|
||||
}
|
68
chroma/lainlib/vector.c
Normal file
68
chroma/lainlib/vector.c
Normal file
|
@ -0,0 +1,68 @@
|
|||
#include <templib/templib.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
/* This file provides a Chroma implementation of std::vector, a C++ standard library class.
|
||||
* It has a lot of work left to be done, but it's usable for its intended function (Graphics)
|
||||
*/
|
||||
|
||||
int VectorRemoveItem(struct vector_t* vec, void* item) {
|
||||
//TODO
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int VectorRemove(struct vector_t* vec, size_t index) {
|
||||
|
||||
if (!vec) return 0;
|
||||
|
||||
//TODO: Vector spinlock
|
||||
// AcqSpinlock(&vec->lock);
|
||||
|
||||
if((index + 1) > vec->n) return 0;
|
||||
|
||||
vec->items[index] = NULL;
|
||||
|
||||
for (int i = 0; i < vec->n; i++) {
|
||||
vec->items[i] = vec->items[i + 1];
|
||||
}
|
||||
|
||||
//TODO: vector reallocate
|
||||
// realloc(vec->items, vec->n - 1);
|
||||
|
||||
vec->n--;
|
||||
|
||||
// ReleaseSpinlock(&vec->lock);
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
void* VectorGet(struct vector_t* vec, size_t index) {
|
||||
|
||||
if(!vec) return 0;
|
||||
|
||||
//TODO: Vector spinlock
|
||||
// AcqSpinlock(&vec->lock);
|
||||
|
||||
if((index + 1) > vec->n) return NULL;
|
||||
|
||||
// ReleaseSpinlock(&vec->lock);
|
||||
return vec->items[index];
|
||||
|
||||
}
|
||||
|
||||
int VectorInsert(struct vector_t* vec, void* item, size_t index) {
|
||||
|
||||
}
|
||||
|
||||
int VectorAppend(struct vector_t* vec, void* item) {
|
||||
|
||||
}
|
||||
|
||||
int VectorDestroy(struct vector_t* vec) {
|
||||
|
||||
}
|
|
@ -1,11 +1,32 @@
|
|||
#include <kernel/chroma.h>
|
||||
#include <kernel/system/interrupts.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
/* This class provides functions for setting up and preparing the CPU for the things the kernel will do.
|
||||
* Mainly, it allows you to:
|
||||
*
|
||||
* Set up and install the GDT and IDT
|
||||
* Refresh the Code Segment to force ourselves into our own GDT
|
||||
* Install new ISR and IRQ handlers.
|
||||
|
||||
* It also has (unused) functionality for extra stacks, to be used with Non-Maskable Interrupt, Double Fault, Machine Check and Breakpoint Exceptions.
|
||||
* //TODO
|
||||
*
|
||||
*/
|
||||
|
||||
#define NMI_STACK 4096
|
||||
#define DF_STACK 4096
|
||||
#define MC_STACK 4096
|
||||
#define BP_STACK 4096
|
||||
|
||||
void InvalidatePage(size_t Page) {
|
||||
__asm__ __volatile__("invlpg (%%eax)" : : "a" (Page) );
|
||||
}
|
||||
|
||||
__attribute__((aligned(64))) static volatile unsigned char NMIStack[NMI_STACK] = {0};
|
||||
__attribute__((aligned(64))) static volatile unsigned char DFStack[DF_STACK] = {0};
|
||||
__attribute__((aligned(64))) static volatile unsigned char MCStack[MC_STACK] = {0};
|
||||
|
@ -39,6 +60,52 @@ static void RefreshCS() {
|
|||
}
|
||||
|
||||
|
||||
void PrepareCPU() {
|
||||
|
||||
SetupInitialGDT();
|
||||
SetupIDT();
|
||||
|
||||
//SetupExtensions();
|
||||
|
||||
InitInterrupts();
|
||||
|
||||
}
|
||||
|
||||
/*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() {
|
||||
DESC_TBL GDTData = {0};
|
||||
size_t TSSBase = (uint64_t) (&TSSEntries);
|
||||
|
|
|
@ -1,5 +1,20 @@
|
|||
#include <kernel/chroma.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
/* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
char keys[128] = {
|
||||
0, 27,
|
||||
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
|
||||
|
@ -36,6 +51,18 @@ char keys[128] = {
|
|||
|
||||
|
||||
|
||||
void KbdEcho() {
|
||||
if(!KbdFlags.EchoCount) {
|
||||
if(!KbdFlags.Echo) {
|
||||
Send8042(0xEE);
|
||||
}
|
||||
} else {
|
||||
KbdFlags.EchoCount = 0;
|
||||
KbdFlags.Echo = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UpdateKeyboard(uint8_t msg) {
|
||||
|
||||
InputBuffer[0] = msg;
|
||||
|
@ -79,23 +106,12 @@ void UpdateKeyboard(uint8_t msg) {
|
|||
if(msg & 0x80) {
|
||||
|
||||
} else {
|
||||
SerialPrintf("Key pressed %c\r\n", keys[msg]);
|
||||
SerialPrintf("Key pressed: [\\%c]\r\n", keys[msg]);
|
||||
WriteChar(keys[msg]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void KbdEcho() {
|
||||
if(!KbdFlags.EchoCount) {
|
||||
if(!KbdFlags.Echo) {
|
||||
Send8042(0xEE);
|
||||
}
|
||||
} else {
|
||||
KbdFlags.EchoCount = 0;
|
||||
KbdFlags.Echo = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Send8042(size_t info) {
|
||||
for(size_t i = 0; i < 8; i++) {
|
||||
unsigned char chr = (unsigned char) info;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/************************
|
||||
*** Team Kitty, 2019 ***
|
||||
*** Sync ***
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
/* This file contains all of the ISR and IRQ
|
||||
|
@ -36,6 +36,51 @@
|
|||
#include <kernel/system/interrupts.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define UNUSED(X) ((void)X)
|
||||
|
||||
const char* ExceptionStrings[] = {
|
||||
"Division by Zero",
|
||||
"Debug",
|
||||
"Non Maskable Interrupt",
|
||||
"Breakpoint",
|
||||
"Into Detected Overflow",
|
||||
"Out of Bounds",
|
||||
"Invalid Opcode",
|
||||
"No Coprocessor",
|
||||
"Double Fault",
|
||||
"Coprocessor Segment Overrun",
|
||||
"Bad TSS",
|
||||
"Segment Not Present",
|
||||
"Stack Fault",
|
||||
"General Protection Fault",
|
||||
"Page Fault",
|
||||
"Unknown Interrupt",
|
||||
"Coprocessor Fault",
|
||||
"Alignment Check",
|
||||
"Machine Check",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved"
|
||||
};
|
||||
|
||||
typedef void (*IRQHandler)(INTERRUPT_FRAME* Frame);
|
||||
|
||||
IRQHandler IRQ_Handlers[16] = {
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
|
||||
typedef unsigned long long int uword_t;
|
||||
|
||||
/* All of the ISR routines call this function for now.
|
||||
|
@ -43,14 +88,16 @@ typedef unsigned long long int uword_t;
|
|||
! Be careful!
|
||||
*/
|
||||
void ISR_Common(INTERRUPT_FRAME* Frame, size_t Exception) {
|
||||
|
||||
UNUSED(Frame);
|
||||
|
||||
/* Only the first 32 ISR/IRQs are reserved for exceptions by the CPU. We can handle up to 512 interrupts total, though. */
|
||||
if(Exception < 32) {
|
||||
|
||||
FillScreen(0x0000FF00);
|
||||
/* ExceptionStrings is an array of c-strings defined in kernel.h */
|
||||
|
||||
//serialPrint(ExceptionStrings[Exception]);
|
||||
//serialPrint(" Exception.\r\n");
|
||||
SerialPrintf("[ ISR] %s exception!\r\n", ExceptionStrings[Exception]);
|
||||
//printf("%s exception!", ExceptionStrings[Exception]);
|
||||
//panic();
|
||||
}
|
||||
|
@ -59,12 +106,15 @@ void ISR_Common(INTERRUPT_FRAME* Frame, size_t Exception) {
|
|||
/* The common handler for exceptions that throw error codes, which give us useful insight
|
||||
into what went wrong. In pure Curle style, though, we just ignore the error code. */
|
||||
void ISR_Error_Common(INTERRUPT_FRAME* Frame, size_t ErrorCode, size_t Exception) {
|
||||
|
||||
UNUSED(Frame);
|
||||
|
||||
if(Exception < 32) {
|
||||
|
||||
FillScreen(0x00FF0000);
|
||||
|
||||
SerialPrintf("ISR Error %d raised, EC %d!\r\n", Exception, ErrorCode);
|
||||
FillScreen(0x0000FF00);
|
||||
|
||||
SerialPrintf("[ ISR] ISR Error %d raised, EC %d!\r\n", Exception, ErrorCode);
|
||||
SerialPrintf("[ ISR] %s exception!\r\n", ExceptionStrings[Exception]);
|
||||
while(true) {}
|
||||
//serialPrint(ExceptionStrings[Exception]);
|
||||
//serialPrintf(" Exception. Context given: %d\r\n", Frame->ErrorCode);
|
||||
|
@ -90,7 +140,7 @@ void IRQ_Common(INTERRUPT_FRAME* Frame, size_t Interrupt) {
|
|||
Handler = IRQ_Handlers[Interrupt];
|
||||
// If there's something there,
|
||||
if(Handler) {
|
||||
SerialPrintf("IRQ %d raised!\r\n", Interrupt);
|
||||
SerialPrintf("[ IRQ] IRQ %d raised!\r\n", Interrupt);
|
||||
// Call the handler.
|
||||
Handler(Frame);
|
||||
}
|
||||
|
@ -100,6 +150,7 @@ void IRQ_Common(INTERRUPT_FRAME* Frame, size_t Interrupt) {
|
|||
|
||||
/* In either case, we tell the Master PIC it's been read to receive any IRQ. */
|
||||
WritePort(0x20, 0x20, 1);
|
||||
|
||||
}
|
||||
|
||||
/* However, in order to actually be able to receive IRQs, we need to remap the PICs. */
|
||||
|
@ -126,11 +177,14 @@ void InstallIRQ(int IRQ, void (*Handler)(INTERRUPT_FRAME* Frame)) {
|
|||
|
||||
/* A simple wrapper that unlinks a function pointer, rendering the IRQ unused. */
|
||||
void UninstallIRQHandler(int IRQ) {
|
||||
IRQ_Handlers[IRQ] = 0; // 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.
|
||||
}
|
||||
|
||||
void EmptyIRQ(INTERRUPT_FRAME* frame) {
|
||||
|
||||
UNUSED(frame);
|
||||
|
||||
// Flash the borders green, then back to blue
|
||||
|
||||
for(size_t y = 0; y < bootldr.fb_height; y++) {
|
||||
|
@ -176,6 +230,8 @@ void EmptyIRQ(INTERRUPT_FRAME* frame) {
|
|||
|
||||
static void KeyboardCallback(INTERRUPT_FRAME* frame) {
|
||||
|
||||
UNUSED(frame);
|
||||
|
||||
uint8_t msg = ReadPort(0x60, 1);
|
||||
|
||||
UpdateKeyboard(msg);
|
||||
|
@ -244,7 +300,19 @@ __attribute__((interrupt)) void ISR5Handler(INTERRUPT_FRAME* Frame) {
|
|||
ISR_Common(Frame, 5);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR6Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 6);
|
||||
|
||||
__asm__ __volatile__("sti");
|
||||
|
||||
SerialPrintf("[FAULT] Invalid Opcode!\n");
|
||||
size_t retAddr = 0;
|
||||
size_t opcodeAddr = Frame->rip;
|
||||
|
||||
__asm__ __volatile__("popq %%rax\n\t" "pushq %%rax": "=a" (retAddr) : :);
|
||||
SerialPrintf("[FAULT] Opcode is at 0x%x, called from 0x%p\r\n", opcodeAddr, retAddr);
|
||||
|
||||
StackTrace(15);
|
||||
|
||||
for(;;) {}
|
||||
}
|
||||
__attribute__((interrupt)) void ISR7Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 7);
|
||||
|
@ -265,10 +333,34 @@ __attribute__((interrupt)) void ISR12Handler(INTERRUPT_FRAME* Frame, size_t Erro
|
|||
ISR_Error_Common(Frame, ErrorCode, 12);
|
||||
}
|
||||
__attribute__((interrupt)) void ISR13Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
|
||||
|
||||
SerialPrintf("\r\n\n[ GPF] RIP: 0x%p, CS: 0x%x, FLAGS: 0x%p, RSP: 0x%x, SS: 0x%x\r\n", Frame->rip, Frame->cs, Frame->rflags, Frame->rsp, Frame->ss);
|
||||
|
||||
StackTrace(6);
|
||||
|
||||
ISR_Error_Common(Frame, ErrorCode, 13); // General Protection
|
||||
}
|
||||
__attribute__((interrupt)) void ISR14Handler(INTERRUPT_FRAME* Frame, size_t ErrorCode) {
|
||||
ISR_Error_Common(Frame, ErrorCode, 14);
|
||||
__asm__ __volatile__("sti");
|
||||
|
||||
SerialPrintf("\r\n\n\n[FAULT] Page fault! Caused by {\r\n");
|
||||
|
||||
//size_t FaultAddr = ReadControlRegister(2);
|
||||
uint8_t FaultPres = ErrorCode & 0x1;
|
||||
uint8_t FaultRW = ErrorCode & 0x2;
|
||||
uint8_t FaultUser = ErrorCode & 0x4;
|
||||
uint8_t FaultReserved = ErrorCode & 0x8;
|
||||
uint8_t FaultInst = ErrorCode & 0x10;
|
||||
|
||||
if(!FaultPres) SerialPrintf("[FAULT] Accessed a page that isn't present.\r\n");
|
||||
if(FaultRW || FaultUser) SerialPrintf("[FAULT] Accessed a Read-Only page.\r\n");
|
||||
if(FaultReserved) SerialPrintf("[FAULT] Overwrote reserved bits.\r\n");
|
||||
if(FaultInst) SerialPrintf("[FAULT] \"Instruction Fetch\"");
|
||||
|
||||
SerialPrintf("[FAULT] } at address\n[FAULT] 0x%p\r\n\n", ReadControlRegister(2));
|
||||
|
||||
StackTrace(6);
|
||||
ISR_Error_Common(Frame, ErrorCode, 14); // Page Fault
|
||||
}
|
||||
__attribute__((interrupt)) void ISR15Handler(INTERRUPT_FRAME* Frame) {
|
||||
ISR_Common(Frame, 15);
|
||||
|
|
|
@ -1,124 +0,0 @@
|
|||
#include <kernel/chroma.h>
|
||||
|
||||
uint8_t* Memory = ((uint8_t*)(&end));
|
||||
uint8_t MemoryStart;
|
||||
uint32_t MemoryPages;
|
||||
uint32_t MemoryLength;
|
||||
|
||||
void InitMemoryManager() {
|
||||
|
||||
size_t BootstructSize = bootldr.size;
|
||||
size_t BootstructLoc = (size_t) &bootldr;
|
||||
|
||||
size_t BootstructEnd = BootstructLoc + BootstructSize;
|
||||
size_t MemorySize = 0, MemMapEntryCount = 0;
|
||||
|
||||
MMapEnt* MemMap = &bootldr.mmap;
|
||||
|
||||
while((size_t) MemMap < BootstructEnd) {
|
||||
if(MMapEnt_IsFree(MemMap)) {
|
||||
MemorySize += MMapEnt_Size(MemMap);
|
||||
}
|
||||
MemMapEntryCount++;
|
||||
MemMap++;
|
||||
}
|
||||
|
||||
|
||||
MemoryPages = MemorySize / PAGE_SIZE;
|
||||
MemoryLength = MemoryPages / PAGES_PER_BUCKET;
|
||||
|
||||
if(MemoryLength * PAGES_PER_BUCKET < MemoryPages)
|
||||
MemoryLength++; // Always round up
|
||||
|
||||
|
||||
memset(Memory, 0, MemoryLength);
|
||||
|
||||
MemoryStart = (uint8_t*)PAGE_ALIGN(((uint32_t)(Memory + MemoryLength)));
|
||||
|
||||
|
||||
SerialPrintf("Initializing Memory.\r\n");
|
||||
|
||||
SerialPrintf("%u MB of memory detected.\r\n", (MemorySize / 1024) / 1024);
|
||||
|
||||
for(size_t i = 0; i < MemoryLength; i++) {
|
||||
if(Memory[i] != 0)
|
||||
SerialPrintf("Memory at 0x%p is not empty!", Memory + i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
size_t AllocatePage() {
|
||||
size_t FreePage = FirstFreePage();
|
||||
SET_BIT(FreePage);
|
||||
return FreePage;
|
||||
}
|
||||
|
||||
void FreePage(size_t Page) {
|
||||
UNSET_BIT(Page);
|
||||
}
|
||||
|
||||
size_t FirstFreePage() {
|
||||
for(size_t i = 0; i < MemoryPages; i++) {
|
||||
if(!READ_BIT(i))
|
||||
return i;
|
||||
}
|
||||
|
||||
SerialPrintf("Memory manager: Critical!\r\n");
|
||||
return (size_t) -1;
|
||||
}
|
||||
|
||||
void MemoryTest() {
|
||||
SerialPrintf("Initializing basic memory test..\r\n");
|
||||
bool Passed = true;
|
||||
size_t FirstPage = FirstFreePage();
|
||||
void* FirstPageAlloc = AllocatePage();
|
||||
size_t SecondPage = FirstFreePage();
|
||||
void* SecondPageAlloc = AllocatePage();
|
||||
|
||||
if(!(FirstPage == 0 && SecondPage == 1)) {
|
||||
Passed = false;
|
||||
SerialPrintf("First iteration: Failed, First page %x, Second page %x.\r\n", FirstPage, SecondPage);
|
||||
}
|
||||
|
||||
FreePage(SecondPage);
|
||||
SecondPage = FirstFreePage();
|
||||
|
||||
if(SecondPage != 1)
|
||||
Passed = false;
|
||||
|
||||
FreePage(FirstPage);
|
||||
FirstPage = FirstFreePage();
|
||||
|
||||
if(FirstPage != 0)
|
||||
Passed = false;
|
||||
|
||||
if(Passed)
|
||||
SerialPrintf("Memory test passed.\r\n");
|
||||
else {
|
||||
SerialPrintf("Memory test failed.\r\n");
|
||||
SerialPrintf("First page %x, Second page %x.\r\n", FirstPage, SecondPage);
|
||||
}
|
||||
}
|
||||
|
||||
void* memcpy(void* dest, void const* src, size_t len) {
|
||||
unsigned char* dst = (unsigned char*) dest;
|
||||
const unsigned char* source = (const unsigned char*) src;
|
||||
|
||||
for(size_t i = 0; i < len; i++) {
|
||||
dst[i] = source[i];
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
void* memset(void* dst, int src, size_t len) {
|
||||
unsigned char* buf = (unsigned char*) dst;
|
||||
|
||||
for(size_t i = 0; i < len; i++) {
|
||||
buf[i] = (unsigned char) src;
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
798
chroma/system/memory/abstract_allocator.c
Normal file
798
chroma/system/memory/abstract_allocator.c
Normal file
|
@ -0,0 +1,798 @@
|
|||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <kernel/system/memory.h>
|
||||
#include <kernel/system/io.h>
|
||||
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
|
||||
/************************************************
|
||||
* C O N S T A N T S A N D M A C R O S
|
||||
*************************************************/
|
||||
|
||||
#define BLOCK_FREE (1 << 0)
|
||||
#define BLOCK_PREV_FREE (1 << 1)
|
||||
|
||||
#define BLOCK_OVERHEAD (sizeof(size_t))
|
||||
|
||||
#define BLOCK_OFFSET (offsetof(block_header_t, Size) + sizeof(size_t))
|
||||
|
||||
#define BLOCK_MIN_SIZE (sizeof(block_header_t) - sizeof(block_header_t*))
|
||||
#define BLOCK_MAX_SIZE (CAST(size_t, 1) << FL_LIMIT)
|
||||
|
||||
#define static_assert _Static_assert
|
||||
|
||||
extern void SomethingWentWrong(const char* Message);
|
||||
|
||||
//#define ASSERT(X) _Static_assert(X)
|
||||
/************************************************
|
||||
* S A N I T Y C H E C K S
|
||||
*************************************************/
|
||||
|
||||
//_Static_Assert(sizeof(int) * __CHAR_BIT__ == 32);
|
||||
//_Static_Assert(sizeof(int) * __CHAR_BIT__ == 32);
|
||||
//_Static_Assert(sizeof(size_t) * __CHAR_BIT__ >= 32);
|
||||
//_Static_Assert(sizeof(size_t) * __CHAR_BIT__ <= 64);
|
||||
//_Static_Assert(sizeof(unsigned int) * __CHAR_BIT__ >= SL_INDEX_COUNT);
|
||||
//_Static_Assert(ALIGN_SIZE == SMALL_BLOCK_SIZE / SL_INDEX_COUNT);
|
||||
|
||||
|
||||
/************************************************
|
||||
* F F S A N D F L S
|
||||
*************************************************/
|
||||
|
||||
#ifdef _cplusplus
|
||||
#define alloc_decl inline
|
||||
#else
|
||||
#define alloc_decl static
|
||||
#endif
|
||||
|
||||
|
||||
alloc_decl int Alloc_FindFirstOne(unsigned int word) {
|
||||
return __builtin_ffs(word) - 1;
|
||||
}
|
||||
|
||||
alloc_decl int Alloc_FindLastOne(unsigned int word) {
|
||||
const int bit = word ? 32 - __builtin_clz(word) : 0;
|
||||
return bit -1;
|
||||
}
|
||||
|
||||
alloc_decl int Alloc_FindLastOne_64(size_t size) {
|
||||
|
||||
int high = (int)(size >> 32);
|
||||
int bits = 0;
|
||||
|
||||
if(high)
|
||||
bits = 32 + Alloc_FindLastOne(high);
|
||||
else
|
||||
bits = Alloc_FindLastOne((int)size & 0xFFFFFFFF);
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
#undef alloc_decl
|
||||
|
||||
|
||||
|
||||
/*********************************************
|
||||
* T Y P E D E F I N I T I O N S
|
||||
**********************************************/
|
||||
|
||||
enum Alloc_Public {
|
||||
|
||||
SL_LIMIT_LN = 5,
|
||||
};
|
||||
|
||||
enum Alloc_Private {
|
||||
ALIGN_SIZE_LN = 3,
|
||||
ALIGN_SIZE = (1 << ALIGN_SIZE_LN),
|
||||
|
||||
FL_LIMIT = 32,
|
||||
|
||||
SL_INDEX_COUNT = (1 << SL_LIMIT_LN),
|
||||
|
||||
FL_INDEX_SHIFT = (SL_LIMIT_LN + ALIGN_SIZE_LN),
|
||||
FL_INDEX_COUNT = (FL_LIMIT - FL_INDEX_SHIFT + 1),
|
||||
|
||||
SMALL_BLOCK_SIZE = (1 << FL_INDEX_SHIFT),
|
||||
|
||||
};
|
||||
|
||||
|
||||
typedef struct block_header_t {
|
||||
struct block_header_t* LastBlock;
|
||||
|
||||
size_t Size; // Not including this header
|
||||
|
||||
struct block_header_t* NextFreeBlock;
|
||||
struct block_header_t* LastFreeBlock;
|
||||
} block_header_t ;
|
||||
|
||||
|
||||
typedef struct allocator_control_t {
|
||||
|
||||
block_header_t BlockNull;
|
||||
|
||||
unsigned int FirstLevel_Bitmap;
|
||||
unsigned int SecondLevel_Bitmap[FL_INDEX_COUNT];
|
||||
|
||||
block_header_t* Blocks[FL_INDEX_COUNT][SL_INDEX_COUNT];
|
||||
} allocator_control_t;
|
||||
|
||||
|
||||
/**********************************************************************************
|
||||
* B L O C K _ H E A D E R _ T M E M B E R F U N C T I O N S
|
||||
************************************************************************************/
|
||||
|
||||
static size_t BlockSize(const block_header_t* Block) {
|
||||
return Block->Size & ~(BLOCK_FREE | BLOCK_PREV_FREE);
|
||||
}
|
||||
|
||||
static void BlockSetSize(block_header_t* Block, size_t Size) {
|
||||
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) {
|
||||
return CAST(int, Block->Size & BLOCK_FREE);
|
||||
}
|
||||
|
||||
static void BlockSetFree(block_header_t* Block) {
|
||||
Block->Size |= BLOCK_FREE;
|
||||
}
|
||||
|
||||
static void BlockSetUsed(block_header_t* Block) {
|
||||
Block->Size &= ~BLOCK_FREE;
|
||||
}
|
||||
|
||||
static int BlockPrevIsFree(const block_header_t* Block) {
|
||||
return CAST(int, Block->Size & BLOCK_PREV_FREE);
|
||||
}
|
||||
|
||||
static void BlockSetPrevFree(block_header_t* Block) {
|
||||
Block->Size |= BLOCK_PREV_FREE;
|
||||
}
|
||||
|
||||
static void BlockSetPrevUsed(block_header_t* Block) {
|
||||
Block->Size &= ~BLOCK_PREV_FREE;
|
||||
}
|
||||
|
||||
static block_header_t* WhichBlock(const void* Address) {
|
||||
return CAST(block_header_t*, CAST(unsigned char*, Address) - BLOCK_OFFSET);
|
||||
}
|
||||
|
||||
static void* WhereBlock(const block_header_t* Block) {
|
||||
return CAST(void*, CAST(unsigned char*, Block) + BLOCK_OFFSET);
|
||||
}
|
||||
|
||||
static block_header_t* OffsetToBlock(const void* Address, size_t Size) {
|
||||
return CAST(block_header_t*, CAST(ptrdiff_t, Address) + Size);
|
||||
}
|
||||
|
||||
static block_header_t* BlockGetPrevious(const block_header_t* Current) {
|
||||
ASSERT(BlockPrevIsFree(Current), "BlockGetPrevious: Previous block NOT free");
|
||||
return Current->LastBlock;
|
||||
}
|
||||
|
||||
static block_header_t* BlockGetNext(const block_header_t* Current) {
|
||||
block_header_t* NextBlock = OffsetToBlock(WhereBlock(Current), BlockSize(Current) - BLOCK_OVERHEAD);
|
||||
ASSERT(!BlockIsLast(Current), "BlockGetNext: Current block is last!");
|
||||
return NextBlock;
|
||||
}
|
||||
|
||||
static block_header_t* BlockLinkToNext(block_header_t* Current) {
|
||||
block_header_t* NextBlock = BlockGetNext(Current);
|
||||
NextBlock->LastBlock = Current;
|
||||
return NextBlock;
|
||||
}
|
||||
|
||||
static void BlockMarkFree(block_header_t* Current) {
|
||||
block_header_t* NextBlock = BlockLinkToNext(Current);
|
||||
BlockSetPrevFree(NextBlock);
|
||||
BlockSetFree(Current);
|
||||
}
|
||||
|
||||
static void BlockMarkUsed(block_header_t* Current) {
|
||||
block_header_t* NextBlock = BlockGetNext(Current);
|
||||
BlockSetPrevUsed(NextBlock);
|
||||
BlockSetUsed(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
|
||||
************************************************************************************/
|
||||
|
||||
size_t AlignUpwards(size_t Pointer, size_t Alignment) {
|
||||
//ASSERT(((Alignment & (Alignment - 1)) == 0));
|
||||
return (Pointer + (Alignment - 1)) & ~(Alignment - 1);
|
||||
}
|
||||
|
||||
size_t AlignDownwards(size_t Pointer, size_t Alignment) {
|
||||
//ASSERT((Alignment & (Alignment - 1) == 0));
|
||||
return (Pointer - (Pointer & (Alignment - 1)));
|
||||
}
|
||||
|
||||
void* AlignPointer(const void* Pointer, size_t Alignment) {
|
||||
|
||||
const ptrdiff_t AlignedPointer =
|
||||
((
|
||||
CAST(ptrdiff_t, Pointer)
|
||||
+ (Alignment - 1))
|
||||
& ~(Alignment - 1)
|
||||
);
|
||||
ASSERT(((Alignment & (Alignment - 1)) == 0), "AlignPointer: Requested alignment not aligned!");
|
||||
|
||||
return CAST(void*, AlignedPointer);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************
|
||||
* M E M O R Y B L O C K M A N A G E M E N T
|
||||
************************************************************************************/
|
||||
|
||||
static size_t AlignRequestSize(size_t Size, size_t Alignment) {
|
||||
size_t Adjustment = 0;
|
||||
|
||||
if(Size) {
|
||||
const size_t Aligned = AlignUpwards(Size, Alignment);
|
||||
|
||||
if(Aligned < BLOCK_MAX_SIZE)
|
||||
Adjustment = MAX(Aligned, BLOCK_MIN_SIZE);
|
||||
|
||||
}
|
||||
|
||||
return Adjustment;
|
||||
}
|
||||
|
||||
static void InsertMapping(size_t Size, int* FirstLevelIndex, int* SecondLevelIndex) {
|
||||
int FirstLevel, SecondLevel;
|
||||
|
||||
if(Size < SMALL_BLOCK_SIZE) {
|
||||
|
||||
FirstLevel = 0;
|
||||
SecondLevel = CAST(int, Size) / (SMALL_BLOCK_SIZE / SL_INDEX_COUNT);
|
||||
} else {
|
||||
FirstLevel = Alloc_FindLastOne_64(Size);
|
||||
SecondLevel = CAST(int, Size >> (FirstLevel - SL_LIMIT_LN)) ^ (1 << SL_LIMIT_LN);
|
||||
|
||||
FirstLevel -= (FL_INDEX_SHIFT - 1);
|
||||
}
|
||||
|
||||
*FirstLevelIndex = FirstLevel;
|
||||
*SecondLevelIndex = SecondLevel;
|
||||
}
|
||||
|
||||
static void RoundUpBlockSize(size_t Size, int* FirstLevelIndex, int* SecondLevelIndex) {
|
||||
if(Size >= SMALL_BLOCK_SIZE) {
|
||||
const size_t Rounded = (1 << (Alloc_FindLastOne_64(Size) - SL_LIMIT_LN)) - 1;
|
||||
Size += Rounded;
|
||||
}
|
||||
|
||||
InsertMapping(Size, FirstLevelIndex, SecondLevelIndex);
|
||||
}
|
||||
|
||||
static block_header_t* FindSuitableBlock(allocator_control_t* Controller, int* FirstLevelIndex, int* SecondLevelIndex) {
|
||||
int FirstLevel = *FirstLevelIndex;
|
||||
int SecondLevel = *SecondLevelIndex;
|
||||
|
||||
unsigned int SLMap = Controller->SecondLevel_Bitmap[FirstLevel] & (~0U << SecondLevel);
|
||||
|
||||
if(!SLMap) {
|
||||
|
||||
const unsigned int FLMap = Controller->FirstLevel_Bitmap & (~0U << (FirstLevel + 1));
|
||||
|
||||
if(!FLMap)
|
||||
return 0;
|
||||
|
||||
FirstLevel = Alloc_FindFirstOne(FLMap);
|
||||
*FirstLevelIndex = FirstLevel;
|
||||
SLMap = Controller->SecondLevel_Bitmap[FirstLevel];
|
||||
}
|
||||
|
||||
ASSERT(SLMap, "FindSuitableBlock: Second level bitmap not present!");
|
||||
|
||||
SecondLevel = Alloc_FindFirstOne(SLMap);
|
||||
*SecondLevelIndex = SecondLevel;
|
||||
|
||||
return Controller->Blocks[FirstLevel][SecondLevel];
|
||||
}
|
||||
|
||||
static void RemoveFreeBlock(allocator_control_t* Controller, block_header_t* Block, int FirstLevel, int SecondLevel) {
|
||||
block_header_t* PreviousBlock = Block->LastFreeBlock;
|
||||
block_header_t* NextBlock = Block->NextFreeBlock;
|
||||
|
||||
ASSERT(PreviousBlock, "RemoveFreeBlock: PreviousBlock is null!");
|
||||
ASSERT(NextBlock, "RemoveFreeBlock: NextBlock is null!");
|
||||
|
||||
NextBlock->LastFreeBlock = PreviousBlock;
|
||||
PreviousBlock->NextFreeBlock = NextBlock;
|
||||
|
||||
if(Controller->Blocks[FirstLevel][SecondLevel] == Block) {
|
||||
Controller->Blocks[FirstLevel][SecondLevel] = NextBlock;
|
||||
|
||||
if(NextBlock == &Controller->BlockNull) {
|
||||
Controller->SecondLevel_Bitmap[FirstLevel] &= ~(1U << SecondLevel);
|
||||
|
||||
if(!Controller->SecondLevel_Bitmap[FirstLevel]) {
|
||||
Controller->FirstLevel_Bitmap &= ~(1U << FirstLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void InsertFreeBlock(allocator_control_t* Controller, block_header_t* NewBlock, int FirstLevel, int SecondLevel) {
|
||||
block_header_t* Current = Controller->Blocks[FirstLevel][SecondLevel];
|
||||
|
||||
ASSERT(Current, "InsertFreeBlock: Current Block is null!");
|
||||
if(!Current) {
|
||||
SerialPrintf("Extra info: \r\n\tFirst Level: %x Second Level: %x\r\nFirst Level bitmap: %x, Second Level bitmap: %x\r\n\tBlocks %x, BlocksAddress: %x", FirstLevel, SecondLevel, Controller->FirstLevel_Bitmap, Controller->SecondLevel_Bitmap, Controller->Blocks, Controller->Blocks[FirstLevel][SecondLevel]);
|
||||
for(;;){}
|
||||
}
|
||||
ASSERT(NewBlock, "InsertFreeBlock: New Block is null!");
|
||||
|
||||
NewBlock->NextFreeBlock = Current;
|
||||
NewBlock->LastFreeBlock = &Controller->BlockNull;
|
||||
|
||||
Current->LastFreeBlock = NewBlock;
|
||||
|
||||
ASSERT(WhereBlock(NewBlock) == AlignPointer(WhereBlock(NewBlock), ALIGN_SIZE), "InsertFreeBlock: Current block is not memory aligned!");
|
||||
|
||||
Controller->Blocks[FirstLevel][SecondLevel] = NewBlock;
|
||||
Controller->FirstLevel_Bitmap |= (1U << FirstLevel);
|
||||
Controller->SecondLevel_Bitmap[FirstLevel] |= (1U << SecondLevel);
|
||||
|
||||
}
|
||||
|
||||
static void RemoveBlock(allocator_control_t* Controller, block_header_t* Block) {
|
||||
int FirstLevel, SecondLevel;
|
||||
|
||||
InsertMapping(BlockSize(Block), &FirstLevel, &SecondLevel);
|
||||
RemoveFreeBlock(Controller, Block, FirstLevel, SecondLevel);
|
||||
}
|
||||
|
||||
static void InsertBlock(allocator_control_t* Controller, block_header_t* Block) {
|
||||
int FirstLevel, SecondLevel;
|
||||
InsertMapping(BlockSize(Block), &FirstLevel, &SecondLevel);
|
||||
InsertFreeBlock(Controller, Block, FirstLevel, SecondLevel);
|
||||
}
|
||||
|
||||
static int CanBlockSplit(block_header_t* Block, size_t NewSize) {
|
||||
return BlockSize(Block) >= sizeof(block_header_t) + NewSize;
|
||||
}
|
||||
|
||||
static block_header_t* SplitBlock(block_header_t* Block, size_t NewSize) {
|
||||
block_header_t* Overlap = OffsetToBlock(WhereBlock(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);
|
||||
|
||||
ASSERT(BlockSize(Overlap) >= BLOCK_MIN_SIZE, "SplitBlock: Requested size results in new block that is too small!");
|
||||
|
||||
BlockSetSize(Block, NewSize);
|
||||
|
||||
BlockMarkFree(Overlap);
|
||||
|
||||
return Overlap;
|
||||
}
|
||||
|
||||
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;
|
||||
BlockLinkToNext(Previous);
|
||||
return Previous;
|
||||
}
|
||||
|
||||
static block_header_t* MergeEmptyBlockDown(allocator_control_t* Controller, block_header_t* Block) {
|
||||
|
||||
if(BlockPrevIsFree(Block)) {
|
||||
block_header_t* Previous = BlockGetPrevious(Block);
|
||||
ASSERT(Previous, "MergeEmptyBlockDown: Previous block is null!");
|
||||
ASSERT(BlockIsFree(Previous), "MergeEmptyBlockDown: Previous block is free!");
|
||||
RemoveBlock(Controller, Previous);
|
||||
Block = MergeBlockDown(Previous, Block);
|
||||
}
|
||||
|
||||
return Block;
|
||||
}
|
||||
|
||||
static block_header_t* MergeNextBlockDown(allocator_control_t* Controller, block_header_t* Block) {
|
||||
block_header_t* NextBlock = BlockGetNext(Block);
|
||||
ASSERT(NextBlock, "MergeNextBlockDown: Next Block is null!");
|
||||
|
||||
if(BlockIsFree(NextBlock)) {
|
||||
ASSERT(!BlockIsLast(Block), "MergeNextBlockDown: Current block is the last block!");
|
||||
RemoveBlock(Controller, NextBlock);
|
||||
Block = MergeBlockDown(Block, NextBlock);
|
||||
}
|
||||
|
||||
return Block;
|
||||
}
|
||||
|
||||
static void TrimBlockFree(allocator_control_t* Controller, block_header_t* Block, size_t Size) {
|
||||
ASSERT(BlockIsFree(Block), "TrimBlockFree: Current block is wholly free!");
|
||||
|
||||
if(CanBlockSplit(Block, Size)) {
|
||||
block_header_t* RemainingBlock = SplitBlock(Block, Size);
|
||||
|
||||
BlockLinkToNext(Block);
|
||||
|
||||
BlockSetPrevFree(RemainingBlock);
|
||||
|
||||
InsertBlock(Controller, RemainingBlock);
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
|
||||
block_header_t* RemainingBlock = SplitBlock(Block, Size);
|
||||
|
||||
BlockSetPrevUsed(RemainingBlock);
|
||||
|
||||
RemainingBlock = MergeNextBlockDown(Controller, RemainingBlock);
|
||||
|
||||
InsertBlock(Controller, RemainingBlock);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static block_header_t* TrimBlockLeadingFree(allocator_control_t* Controller, block_header_t* Block, size_t Size) {
|
||||
block_header_t* RemainingBlock = Block;
|
||||
|
||||
if(CanBlockSplit(Block, Size)) {
|
||||
RemainingBlock = SplitBlock(Block, Size - BLOCK_OVERHEAD);
|
||||
|
||||
BlockSetPrevFree(RemainingBlock);
|
||||
|
||||
BlockLinkToNext(Block);
|
||||
InsertBlock(Controller, Block);
|
||||
}
|
||||
|
||||
return RemainingBlock;
|
||||
}
|
||||
|
||||
static block_header_t* LocateFreeBlock(allocator_control_t* Controller, size_t Size) {
|
||||
|
||||
int FirstLevel = 0, SecondLevel = 0;
|
||||
|
||||
block_header_t* Block = 0;
|
||||
|
||||
if(Size) {
|
||||
|
||||
RoundUpBlockSize(Size, &FirstLevel, &SecondLevel);
|
||||
|
||||
if(FirstLevel < FL_INDEX_COUNT) {
|
||||
Block = FindSuitableBlock(Controller, &FirstLevel, &SecondLevel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(Block) {
|
||||
ASSERT(BlockSize(Block) >= Size, "LocateFreeBlock: Found a block that is too small!");
|
||||
RemoveFreeBlock(Controller, Block, FirstLevel, SecondLevel);
|
||||
}
|
||||
|
||||
return Block;
|
||||
}
|
||||
|
||||
static void* PrepareUsedBlock(allocator_control_t* Controller, block_header_t* Block, size_t Size) {
|
||||
void* Pointer = 0;
|
||||
|
||||
if(Block){
|
||||
ASSERT(Size, "PrepareUsedBlock: Size is 0!");
|
||||
TrimBlockFree(Controller, Block, Size);
|
||||
BlockMarkUsed(Block);
|
||||
Pointer = WhereBlock(Block);
|
||||
}
|
||||
|
||||
return Pointer;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************
|
||||
* C O N T R O L L E R M A N A G E M E N T
|
||||
************************************************************************************/
|
||||
|
||||
static void ConstructController(allocator_control_t* Controller) {
|
||||
int i, j;
|
||||
|
||||
Controller->BlockNull.NextFreeBlock = &Controller->BlockNull;
|
||||
Controller->BlockNull.LastFreeBlock = &Controller->BlockNull;
|
||||
|
||||
Controller->FirstLevel_Bitmap = 0;
|
||||
|
||||
for ( i = 0; i < FL_INDEX_COUNT; i++) {
|
||||
Controller->SecondLevel_Bitmap[i] = 0;
|
||||
|
||||
for (j = 0; j < SL_INDEX_COUNT; j++) {
|
||||
Controller->Blocks[i][j] = &Controller->BlockNull;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************
|
||||
* H E A D E R ( A P I ) F U N C T I O N S
|
||||
************************************************************************************/
|
||||
|
||||
|
||||
size_t AllocatorGetBlockSize(void* Memory) {
|
||||
size_t Size = 0;
|
||||
|
||||
if(Memory) {
|
||||
const block_header_t* Block = WhichBlock(Memory);
|
||||
Size = BlockSize(Block);
|
||||
}
|
||||
|
||||
return Size;
|
||||
}
|
||||
|
||||
size_t AllocatorSize(void) {
|
||||
return sizeof(allocator_control_t);
|
||||
}
|
||||
|
||||
size_t AllocatorAlignSize(void) {
|
||||
return ALIGN_SIZE;
|
||||
}
|
||||
|
||||
size_t AllocatorMinBlockSize(void) {
|
||||
return BLOCK_MIN_SIZE;
|
||||
}
|
||||
|
||||
size_t AllocatorMaxBlockSize(void) {
|
||||
return BLOCK_MAX_SIZE;
|
||||
}
|
||||
|
||||
size_t AllocatorPoolOverhead(void) {
|
||||
return 2* BLOCK_OVERHEAD; // Free block + Sentinel block
|
||||
}
|
||||
|
||||
size_t AllocatorAllocateOverhead(void) {
|
||||
return BLOCK_OVERHEAD;
|
||||
}
|
||||
|
||||
mempool_t AddPoolToAllocator(allocator_t Allocator, void* Address, size_t Size) {
|
||||
|
||||
block_header_t* Block;
|
||||
block_header_t* NextBlock;
|
||||
|
||||
const size_t PoolOverhead = AllocatorPoolOverhead();
|
||||
const size_t PoolBytes = AlignDownwards(Size - PoolOverhead, ALIGN_SIZE);
|
||||
|
||||
if(((ptrdiff_t) Address % ALIGN_SIZE) != 0) {
|
||||
SerialPrintf("Memory manager error at [%s:%x]: Memory not properly aligned.\r\n", __FILE__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( PoolBytes < BLOCK_MIN_SIZE || PoolBytes > BLOCK_MAX_SIZE) {
|
||||
SerialPrintf("Memory manager error at [%s:%x]: Memory Size out of bounds: 0x%x-0x%x: 0x%x.\r\n", __FILE__, __LINE__, (unsigned int)(PoolOverhead + BLOCK_MIN_SIZE), (unsigned int)(PoolOverhead + BLOCK_MAX_SIZE) / 256, PoolBytes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Block = OffsetToBlock(Address, -(ptrdiff_t)BLOCK_OVERHEAD);
|
||||
BlockSetSize(Block, PoolBytes);
|
||||
BlockSetFree(Block);
|
||||
BlockSetPrevUsed(Block);
|
||||
|
||||
InsertBlock(CAST(allocator_control_t*, Allocator), Block);
|
||||
|
||||
NextBlock = BlockLinkToNext(Block);
|
||||
BlockSetSize(NextBlock, 0);
|
||||
BlockSetUsed(NextBlock);
|
||||
BlockSetPrevFree(NextBlock);
|
||||
|
||||
return Address;
|
||||
}
|
||||
|
||||
void RemovePoolFromAllocator(allocator_t Allocator, mempool_t Pool){
|
||||
allocator_control_t* Controller = CAST(allocator_control_t*, Allocator);
|
||||
block_header_t* Block = OffsetToBlock(Pool, -(int)BLOCK_OVERHEAD);
|
||||
|
||||
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);
|
||||
RemoveFreeBlock(Controller, Block, FirstLevel, SecondLevel);
|
||||
}
|
||||
|
||||
int TestBuiltins() {
|
||||
/* Verify ffs/fls work properly. */
|
||||
int TestsFailed = 0;
|
||||
TestsFailed += (Alloc_FindFirstOne(0) == -1) ? 0 : 0x1;
|
||||
TestsFailed += (Alloc_FindLastOne(0) == -1) ? 0 : 0x2;
|
||||
TestsFailed += (Alloc_FindFirstOne(1) == 0) ? 0 : 0x4;
|
||||
TestsFailed += (Alloc_FindLastOne(1) == 0) ? 0 : 0x8;
|
||||
TestsFailed += (Alloc_FindFirstOne(0x80000000) == 31) ? 0 : 0x10;
|
||||
TestsFailed += (Alloc_FindFirstOne(0x80008000) == 15) ? 0 : 0x20;
|
||||
TestsFailed += (Alloc_FindLastOne(0x80000008) == 31) ? 0 : 0x40;
|
||||
TestsFailed += (Alloc_FindLastOne(0x7FFFFFFF) == 30) ? 0 : 0x80;
|
||||
|
||||
TestsFailed += (Alloc_FindLastOne_64(0x80000000) == 31) ? 0 : 0x100;
|
||||
TestsFailed += (Alloc_FindLastOne_64(0x100000000) == 32) ? 0 : 0x200;
|
||||
TestsFailed += (Alloc_FindLastOne_64(0xffffffffffffffff) == 63) ? 0 : 0x400;
|
||||
|
||||
if (TestsFailed) {
|
||||
SerialPrintf("TestBuiltins: %x ffs/fls tests failed.\n", TestsFailed);
|
||||
}
|
||||
|
||||
return TestsFailed;
|
||||
}
|
||||
|
||||
allocator_t CreateAllocator(void* Memory) {
|
||||
if(TestBuiltins())
|
||||
return 0;
|
||||
|
||||
if (((ptrdiff_t) Memory % ALIGN_SIZE) != 0) {
|
||||
SerialPrintf("Memory manager error at [%s:%x]: Memory not properly aligned.\r\n", __FILE__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ConstructController(CAST(allocator_control_t*, Memory));
|
||||
|
||||
return CAST(allocator_t, Memory);
|
||||
}
|
||||
|
||||
|
||||
allocator_t CreateAllocatorWithPool(void* Memory, size_t Bytes) {
|
||||
allocator_t Allocator = CreateAllocator(Memory);
|
||||
|
||||
AddPoolToAllocator(Allocator, (char*)Memory + AllocatorSize(), Bytes - AllocatorSize());
|
||||
|
||||
return Allocator;
|
||||
}
|
||||
|
||||
void DestroyAllocator(allocator_t Allocator) {
|
||||
(void) Allocator;
|
||||
}
|
||||
|
||||
mempool_t GetPoolFromAllocator(allocator_t Allocator) {
|
||||
return CAST(mempool_t, (char*)Allocator + AllocatorSize());
|
||||
}
|
||||
|
||||
/***********************************************************************************
|
||||
* S T D L I B A L L O C A T E F U N C T I O N S
|
||||
************************************************************************************/
|
||||
|
||||
void* AllocatorMalloc(allocator_t Allocator, size_t Size) {
|
||||
allocator_control_t* Controller = CAST(allocator_control_t*, Allocator);
|
||||
const size_t Adjustment = AlignRequestSize(Size, ALIGN_SIZE);
|
||||
block_header_t* Block = LocateFreeBlock(Controller, Adjustment);
|
||||
return PrepareUsedBlock(Controller, Block, Adjustment);
|
||||
}
|
||||
|
||||
void* AllocatorMalign(allocator_t Allocator, size_t Alignment, size_t Size) {
|
||||
allocator_control_t* Controller = CAST(allocator_control_t*, Allocator);
|
||||
const size_t Adjustment = AlignRequestSize(Size, ALIGN_SIZE);
|
||||
|
||||
|
||||
const size_t MinimumGap = sizeof(block_header_t);
|
||||
|
||||
const size_t SizeWithGap = AlignRequestSize(Adjustment + Alignment + MinimumGap, Alignment);
|
||||
|
||||
const size_t AlignedSize = (Adjustment && Alignment > ALIGN_SIZE) ? SizeWithGap : Adjustment;
|
||||
|
||||
block_header_t* Block = LocateFreeBlock(Controller, AlignedSize);
|
||||
|
||||
ASSERT(sizeof(block_header_t) == BLOCK_MIN_SIZE + BLOCK_OVERHEAD, "AllocatorMalign: Maths error!");
|
||||
|
||||
if(Block) {
|
||||
void* Address = WhereBlock(Block);
|
||||
void* AlignedAddress = AlignPointer(Address, Alignment);
|
||||
|
||||
size_t Gap = CAST(size_t, CAST(ptrdiff_t, AlignedAddress) - CAST(ptrdiff_t, Address));
|
||||
|
||||
if(Gap) {
|
||||
if(Gap << MinimumGap) {
|
||||
const size_t GapRemaining = MinimumGap - Gap;
|
||||
const size_t Offset = MAX(GapRemaining, Alignment);
|
||||
const void* NextAlignedAddress = CAST(void*, CAST(ptrdiff_t, AlignedAddress) + Offset);
|
||||
|
||||
AlignedAddress = AlignPointer(NextAlignedAddress, Alignment);
|
||||
|
||||
Gap = CAST(size_t, CAST(ptrdiff_t, AlignedAddress) - CAST(ptrdiff_t, Address));
|
||||
}
|
||||
|
||||
ASSERT(Gap >= MinimumGap, "AllocatorMalign: Maths error 2!");
|
||||
|
||||
Block = TrimBlockLeadingFree(Controller, Block, Gap);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return PrepareUsedBlock(Controller, Block, Adjustment);
|
||||
}
|
||||
|
||||
void AllocatorFree(allocator_t Allocator, void* Address) {
|
||||
if(Address) {
|
||||
allocator_control_t* Controller = CAST(allocator_control_t*, Allocator);
|
||||
block_header_t* Block = WhichBlock(Address);
|
||||
ASSERT(!BlockIsFree(Block), "AllocatorFree: Attempting to free a freed block!");
|
||||
|
||||
BlockMarkFree(Block);
|
||||
Block = MergeEmptyBlockDown(Controller, Block);
|
||||
Block = MergeNextBlockDown(Controller, Block);
|
||||
|
||||
InsertBlock(Controller, Block);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Realloc should, with:
|
||||
* * A valid size with an invalid pointer:
|
||||
* - Allocate space
|
||||
* * An invalid size with a valid pointer:
|
||||
* - Free Space
|
||||
* * An invalid request:
|
||||
* - Do nothing
|
||||
* * A valid extension request:
|
||||
* - Leave the new area as it is
|
||||
* // TODO: memset this area to 0.
|
||||
*/
|
||||
|
||||
|
||||
void* AllocatorRealloc(allocator_t Allocator, void* Address, size_t NewSize) {
|
||||
allocator_control_t* Controller = CAST(allocator_control_t*, Allocator);
|
||||
|
||||
void* Pointer = 0;
|
||||
|
||||
// Valid address, invalid size; free
|
||||
if(Address && NewSize == 0)
|
||||
AllocatorFree(Allocator, Address);
|
||||
|
||||
else if (!Address) // Invalid address; alloc
|
||||
AllocatorMalloc(Allocator, NewSize);
|
||||
|
||||
else {
|
||||
block_header_t* Block = WhichBlock(Address);
|
||||
block_header_t* NextBlock = BlockGetNext(Block);
|
||||
|
||||
const size_t CurrentSize = BlockSize(Block);
|
||||
const size_t CombinedSize = CurrentSize + BlockSize(NextBlock) + BLOCK_OVERHEAD;
|
||||
|
||||
const size_t AdjustedSize = AlignRequestSize(NewSize, ALIGN_SIZE);
|
||||
|
||||
ASSERT(!BlockIsFree(Block), "AllocatorRealloc: Requested block is not free!");
|
||||
|
||||
if(AdjustedSize > CurrentSize && (!BlockIsFree(NextBlock) || AdjustedSize > CombinedSize)) {
|
||||
// We're going to need more room
|
||||
|
||||
Pointer = AllocatorMalloc(Allocator, NewSize);
|
||||
if(Pointer) {
|
||||
const size_t MinimumSize = MIN(CurrentSize, NewSize);
|
||||
memcpy(Pointer, Address, MinimumSize);
|
||||
AllocatorFree(Allocator, Address);
|
||||
}
|
||||
} else {
|
||||
if( AdjustedSize > CurrentSize) {
|
||||
MergeNextBlockDown(Controller, Block);
|
||||
BlockMarkUsed(Block);
|
||||
}
|
||||
|
||||
TrimBlockUsed(Controller, Block, AdjustedSize);
|
||||
Pointer = Address;
|
||||
}
|
||||
}
|
||||
|
||||
return Pointer;
|
||||
}
|
310
chroma/system/memory/legacypaging.c
Normal file
310
chroma/system/memory/legacypaging.c
Normal file
|
@ -0,0 +1,310 @@
|
|||
|
||||
void InitPagingT() {
|
||||
|
||||
size_t* PML4 = (size_t*) 0xFFA000; // Layer 4
|
||||
size_t* PDPE_RAM = (size_t*) 0xFFE000; // Layer 3, contains map for the first 4GB of RAM
|
||||
size_t* PDE_RAM = (size_t*) 0xFFF000;
|
||||
|
||||
size_t* PDPE_KERNEL = (size_t*) 0xFFB000; // Layer 3, contains map for the Kernel and everything it needs to run.
|
||||
size_t* PDE_KERNEL_FB = (size_t*) 0xFFC000; // Layer 2, contains map for the linear framebuffer.
|
||||
|
||||
size_t* PT_KERNEL = (size_t*) 0xFFD000; // Layer 1, the page table for the kernel itself.
|
||||
|
||||
size_t fb_ptr = (size_t) &fb;
|
||||
|
||||
SET_ADDRESS(PML4, PDPE_RAM); // 3rd Layer entry for RAM
|
||||
SET_ADDRESS(PML4 + LAST_ENTRY, PDPE_KERNEL); // 3rd Layer entry for Kernel
|
||||
|
||||
SET_ADDRESS(PDPE_KERNEL + LAST_ENTRY, PDE_KERNEL_FB); // 2nd Layer entry for the framebuffer
|
||||
|
||||
// Set the 480th entry (PDE_KERNEL_FB + (480 * 8))
|
||||
// To the framebuffer + flags
|
||||
SET_ADDRESS(PDE_KERNEL_FB + 3840, USERWRITEABLE_FLAGS(fb_ptr));
|
||||
|
||||
// In 4 byte increments, we're gonna map 3840 (the framebuffer)
|
||||
// Up to (4096 - 8) in the PDE_KERNEL_FB with 2MB paging.
|
||||
size_t MappingIterations = 1;
|
||||
for(size_t i = 3844; i < 4088; i += 4) {
|
||||
SET_ADDRESS(PDE_KERNEL_FB + i, USERWRITEABLE_FLAGS(fb_ptr) + (MappingIterations * (2 * MiB)));
|
||||
MappingIterations++;
|
||||
}
|
||||
|
||||
// Now we map the last entry of PDE_KERNEL_FB to our Page Table
|
||||
SET_ADDRESS(PDE_KERNEL_FB + LAST_ENTRY, PT_KERNEL);
|
||||
|
||||
// Mapping the kernel into the page tables....
|
||||
|
||||
SET_ADDRESS(PT_KERNEL, 0xFF8001); // bootldr, bootinfo
|
||||
SET_ADDRESS(PT_KERNEL + 8, 0xFF9001); // environment
|
||||
|
||||
// Map the kernel itself
|
||||
SET_ADDRESS(PT_KERNEL + 16, KernelAddr + 1);
|
||||
|
||||
// Iterate through the pages, identity mapping each one
|
||||
MappingIterations = 1;
|
||||
size_t MappingOffset = 0x14;
|
||||
for(size_t i = 0; i < ((KernelEnd - KernelAddr) >> 12); i++) {
|
||||
// Page Table + (0x10 increasing by 0x04 each time) = x * 4KiB
|
||||
SET_ADDRESS(PT_KERNEL + MappingOffset, (MappingIterations * (4 * KiB)));
|
||||
MappingOffset += 4;
|
||||
MappingIterations++;
|
||||
}
|
||||
|
||||
// Now we need to map the core stacks. Top-down, from 0xDFF8
|
||||
// There's always at least one core, so we do that one fixed.
|
||||
// TODO: Account for 0-core CPUs
|
||||
SET_ADDRESS(PT_KERNEL + LAST_ENTRY, 0xF14003);
|
||||
MappingIterations = 1;
|
||||
// For every core:
|
||||
for(size_t i = 0; i < (bootldr.numcores + 3U) >> 2; i++) {
|
||||
// PT_KERNEL[512 - (iterations + 1)] = 0x14003 + (iterations * page-width)
|
||||
SET_ADDRESS(PT_KERNEL + LAST_ENTRY - (MappingIterations * 8), 0xF14003 + (4096 * MappingIterations));
|
||||
MappingIterations++;
|
||||
}
|
||||
|
||||
SET_ADDRESS(PDPE_RAM, PDE_RAM + PAGE_PRESENT + PAGE_RW);
|
||||
SET_ADDRESS(PDPE_RAM + 8, 0xF10000 + PAGE_PRESENT + PAGE_RW);
|
||||
SET_ADDRESS(PDPE_RAM + 16, 0xF11000 + PAGE_PRESENT + PAGE_RW);
|
||||
SET_ADDRESS(PDPE_RAM + 24, 0xF12000 + PAGE_PRESENT + PAGE_RW);
|
||||
|
||||
// Identity map 4GB of ram
|
||||
// Each page table can only hold 512 entries, but we
|
||||
// just set up 4 of them - overflowing PDE_RAM (0xF000)
|
||||
// will take us into 0x10000, into 0x11000, into 0x120000.
|
||||
for(size_t i = 0; i < 512 * 4/*GB*/; i++) {
|
||||
// add PDE_RAM, 4
|
||||
// mov eax, 0x83
|
||||
// add eax, 2*1024*1024
|
||||
SET_ADDRESS(PDE_RAM + (i * 4), USERWRITEABLE_FLAGS(i * (2 * MiB)));
|
||||
}
|
||||
|
||||
// Map first 2MB of memory
|
||||
SET_ADDRESS(PDE_RAM, 0xF13000 + PAGE_PRESENT + PAGE_RW);
|
||||
|
||||
for(size_t i = 0; i < 512; i++) {
|
||||
SET_ADDRESS(0xF13000 + i * 4, i * (4 * KiB) + PAGE_PRESENT + PAGE_RW);
|
||||
}
|
||||
|
||||
// 0xA000 should now contain our memory map.
|
||||
|
||||
}
|
||||
|
||||
void TraversePageTables() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void InitPagingOldImpl() {
|
||||
|
||||
// Disable paging so that we can work with the pagetable
|
||||
//size_t registerTemp = ReadControlRegister(0);
|
||||
//UNSET_PGBIT(registerTemp);
|
||||
//WriteControlRegister(0, registerTemp);
|
||||
|
||||
// Clear space for our pagetable
|
||||
size_t PagetableDest = 0x1000;
|
||||
memset((char*)PagetableDest, 0, 4096);
|
||||
|
||||
// Start setting pagetable indexes
|
||||
*((size_t*)PagetableDest) = 0x2003; // PDP at 0x2000, present & r/w
|
||||
*((size_t*)PagetableDest + 0x1000) = 0x3003; // PDT at 0x3000, present & r/w
|
||||
*((size_t*)PagetableDest + 0x2000) = 0x4003; // PT at 0x4000, present & r/w
|
||||
|
||||
size_t value = 0x3;
|
||||
size_t offset = 8;
|
||||
for(size_t i = 0; i < 512; i++) { // 512 iterations (entries into the page table)
|
||||
*((size_t*) PagetableDest + offset) = value; // We're setting 512 bytes with x003
|
||||
// (identity mapping the first 4 megabytes of memory)
|
||||
// (mapping the page table to itself)
|
||||
value += 4096; // Point to start of next page
|
||||
offset += 8; // + 8 bytes (next entry in list)
|
||||
}
|
||||
|
||||
// Enable PAE paging
|
||||
size_t reg = ReadControlRegister(4);
|
||||
SET_PAEBIT(reg);
|
||||
WriteControlRegister(4, reg);
|
||||
|
||||
WriteControlRegister(3, PagetableDest);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* size_t registerTemp = ReadControlRegister(4);
|
||||
if(registerTemp & (1 << 7)) {
|
||||
TOGGLE_PGEBIT(registerTemp);
|
||||
WriteControlRegister(4, registerTemp);
|
||||
}
|
||||
|
||||
if(registerTemp & (1 << 7))
|
||||
WriteControlRegister(4, registerTemp ^ (1 << 7));
|
||||
|
||||
size_t CPUIDReturn;
|
||||
asm volatile("cpuid" : "=d" (CPUIDReturn) : "a" (0x80000001) : "%rbx", "%rcx");
|
||||
|
||||
if(CPUIDReturn & (1 << 26)) {
|
||||
SerialPrintf("System supports 1GB pages.\r\n");
|
||||
|
||||
if(registerTemp & (1 << 12)) {
|
||||
SerialPrintf("PML5 paging available - using that instead.\r\n");
|
||||
|
||||
if(MemorySize > (1ULL << 57))
|
||||
SerialPrintf("System has over 128Petabytes of RAM. Please consider upgrading the OS on your supercomputer.\r\n");
|
||||
|
||||
size_t MaxPML5 = 1;
|
||||
size_t MaxPML4 = 1;
|
||||
size_t MaxPDP = 512;
|
||||
|
||||
size_t LastPML4Entry = 512;
|
||||
size_t LastPDPEntry = 512;
|
||||
|
||||
size_t MemorySearchDepth = MemorySize;
|
||||
|
||||
while(MemorySearchDepth > (256ULL << 30)) {
|
||||
MaxPML5++;
|
||||
MemorySearchDepth -= (256ULL << 30);
|
||||
}
|
||||
|
||||
if(MaxPML5 > 512)
|
||||
MaxPML5 = 512;
|
||||
|
||||
if(MemorySearchDepth) {
|
||||
LastPDPEntry = ( (MemorySearchDepth + ((1 << 30) - 1)) & (~0ULL << 30)) >> 30;
|
||||
|
||||
if(MaxPML5 > 512)
|
||||
MaxPML5 = 512;
|
||||
|
||||
}
|
||||
|
||||
size_t PML4Size = PAGETABLE_SIZE * MaxPML5;
|
||||
size_t PDPSize = PML4Size * MaxPML4;
|
||||
|
||||
size_t PML4Base = AllocatePagetable(PML4Size + PDPSize);
|
||||
size_t PDPBase = PML4Base + PML4Size;
|
||||
|
||||
for(size_t PML5Entry = 0; PML5Entry < MaxPML5; PML5Entry++) {
|
||||
Pagetable[PML5Entry] = PML4Base + (PML5Entry << 12);
|
||||
|
||||
if(PML5Entry == (MaxPML5 - 1))
|
||||
MaxPML4 = LastPML4Entry;
|
||||
|
||||
for(size_t PML4Entry = 0; PML4Entry < MaxPML4; PML4Entry++) {
|
||||
|
||||
((size_t*) Pagetable[PML5Entry])[PML4Entry] = PDPBase + (((PML5Entry << 9) + PML5Entry) << 12);
|
||||
|
||||
if( (PML5Entry == (MaxPML5 - 1)) && (PML4Entry == (MaxPML4 -1)) )
|
||||
MaxPDP = LastPDPEntry;
|
||||
|
||||
for(size_t PDPEntry = 0; PDPEntry < MaxPDP; PDPEntry++) {
|
||||
((size_t* ) ((size_t* ) Pagetable[PML5Entry])[PML4Entry])[PDPEntry] = ( ((PML5Entry << 18) + (PML4Entry << 9) + PDPEntry) << 30) | (0x83);
|
||||
}
|
||||
|
||||
((size_t* ) Pagetable[PML5Entry])[PML4Entry] |= 0x3;
|
||||
}
|
||||
|
||||
Pagetable[PML5Entry] |= 0x3;
|
||||
}
|
||||
} else {
|
||||
SerialPrintf("PML4 available - using that instead.\r\n");
|
||||
size_t MemorySearchDepth = MemorySize;
|
||||
|
||||
if(MemorySearchDepth > (1ULL << 48))
|
||||
SerialPrintf("RAM limited to 256TB.\r\n");
|
||||
|
||||
size_t MaxPML4 = 1;
|
||||
size_t MaxPDP = 512;
|
||||
|
||||
size_t LastPDPEntry = 512;
|
||||
|
||||
while(MemorySearchDepth > (512ULL << 30)) {
|
||||
MaxPML4++;
|
||||
MemorySearchDepth -= (512ULL << 30);
|
||||
}
|
||||
|
||||
if(MaxPML4 > 512)
|
||||
MaxPML4 = 512;
|
||||
|
||||
if(MemorySearchDepth) {
|
||||
LastPDPEntry = ( (MemorySearchDepth + ((1 << 30) - 1)) & (~0ULL << 30)) >> 30;
|
||||
|
||||
if(LastPDPEntry > 512)
|
||||
LastPDPEntry = 512;
|
||||
}
|
||||
|
||||
size_t PDPSize = PAGETABLE_SIZE * MaxPML4;
|
||||
size_t PDPBase = AllocatePagetable(PDPSize);
|
||||
|
||||
for(size_t PML4Entry = 0; PML4Entry < MaxPML4; PML4Entry++) {
|
||||
Pagetable[PML4Entry] = PDPBase + (PML4Entry << 12);
|
||||
|
||||
if(PML4Entry == (MaxPML4 - 1)) {
|
||||
MaxPDP = LastPDPEntry;
|
||||
}
|
||||
|
||||
for(size_t PDPEntry = 0; PDPEntry < MaxPDP; PDPEntry++) {
|
||||
((size_t* ) Pagetable[PML4Entry])[PDPEntry] = (((PML4Entry << 9) + PDPEntry) << 30) | 0x83;
|
||||
}
|
||||
|
||||
Pagetable[PML4Entry] |= 0x3;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SerialPrintf("System does not support 1GB pages - using 2MiB paging instead.\r\n");
|
||||
|
||||
size_t MemorySearchDepth = MemorySize;
|
||||
|
||||
if(MemorySearchDepth > (1ULL << 48)) {
|
||||
SerialPrintf("Usable RAM is limited to 256TB, and the page table alone will use 1GB of space in memory.\r\n");
|
||||
}
|
||||
|
||||
size_t MaxPML4 = 1, MaxPDP = 512, MaxPD = 512, LastPDPEntry = 1;
|
||||
|
||||
while(MemorySearchDepth > (512ULL << 30)) {
|
||||
MaxPML4++;
|
||||
MemorySearchDepth -= (512ULL << 30);
|
||||
}
|
||||
|
||||
if(MaxPML4 > 512)
|
||||
MaxPML4 = 512;
|
||||
|
||||
if(MemorySearchDepth) {
|
||||
LastPDPEntry = ((MemorySearchDepth + ((1 << 30) - 1)) & (~0ULL << 30)) >> 30;
|
||||
|
||||
if(LastPDPEntry > 512)
|
||||
LastPDPEntry = 512;
|
||||
}
|
||||
|
||||
size_t PDPSize = PAGETABLE_SIZE * MaxPML4;
|
||||
size_t PDSize = PDPSize * MaxPDP;
|
||||
|
||||
size_t PDPBase = AllocatePagetable(PDPSize + PDSize);
|
||||
size_t PDBase = PDPBase + PDSize;
|
||||
|
||||
for(size_t PML4Entry = 0; PML4Entry < MaxPML4; PML4Entry++) {
|
||||
Pagetable[PML4Entry] = PDBase + (PML4Entry << 12);
|
||||
|
||||
if(PML4Entry == (MaxPML4 - 1)) {
|
||||
MaxPDP = LastPDPEntry;
|
||||
}
|
||||
|
||||
for(size_t PDPEntry = 0; PDPEntry < MaxPDP; PDPEntry++) {
|
||||
( (size_t* ) Pagetable[PML4Entry])[PDPEntry] = PDBase + (((PML4Entry << 9) + PDPEntry) << 12);
|
||||
|
||||
for(size_t PDEntry = 0; PDEntry < MaxPD; PDEntry++) {
|
||||
( (size_t* ) ((size_t*) Pagetable[PML4Entry])[PDPEntry])[PDEntry] = (( (PML4Entry << 18) + (PDPEntry << 9) + PDPEntry) << 21) | 0x83;
|
||||
}
|
||||
|
||||
( (size_t* ) Pagetable[PML4Entry])[PDPEntry] |= 0x3;
|
||||
}
|
||||
|
||||
Pagetable[PML4Entry] |= 0x3;
|
||||
}
|
||||
}
|
||||
|
||||
WriteControlRegister(3, Pagetable);
|
||||
|
||||
registerTemp = ReadControlRegister(4);
|
||||
if(!(registerTemp & (1 << 7))) {
|
||||
TOGGLE_PGEBIT(registerTemp);
|
||||
WriteControlRegister(4, registerTemp);
|
||||
}*/
|
53
chroma/system/memory/legacyphysmem.c
Normal file
53
chroma/system/memory/legacyphysmem.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
|
||||
size_t AllocateFrame() {
|
||||
size_t FreePage = SeekFrame();
|
||||
SET_BIT(FreePage);
|
||||
return FreePage;
|
||||
}
|
||||
|
||||
void FreeFrame(size_t Frame) {
|
||||
UNSET_BIT(Frame);
|
||||
}
|
||||
|
||||
size_t SeekFrame() {
|
||||
for(size_t i = 0; i < MemoryPages; i++) {
|
||||
if(!READ_BIT(i))
|
||||
return i;
|
||||
}
|
||||
|
||||
SerialPrintf("Memory manager: Critical!\r\n");
|
||||
return (size_t) -1;
|
||||
}
|
||||
|
||||
void MemoryTest() {
|
||||
SerialPrintf("Initializing basic memory test..\r\n");
|
||||
bool Passed = true;
|
||||
size_t FirstPage = SeekFrame();
|
||||
/*(void* FirstPageAlloc = (void*)*/ AllocateFrame();
|
||||
size_t SecondPage = SeekFrame();
|
||||
/*void* SecondPageAlloc = (void*)*/ AllocateFrame();
|
||||
|
||||
if(!(FirstPage == 0 && SecondPage == 1)) {
|
||||
Passed = false;
|
||||
SerialPrintf("First iteration: Failed, First page %x, Second page %x.\r\n", FirstPage, SecondPage);
|
||||
}
|
||||
|
||||
FreeFrame(SecondPage);
|
||||
SecondPage = SeekFrame();
|
||||
|
||||
if(SecondPage != 1)
|
||||
Passed = false;
|
||||
|
||||
FreeFrame(FirstPage);
|
||||
FirstPage = SeekFrame();
|
||||
|
||||
if(FirstPage != 0)
|
||||
Passed = false;
|
||||
|
||||
if(Passed)
|
||||
SerialPrintf("Memory test passed.\r\n");
|
||||
else {
|
||||
SerialPrintf("Memory test failed.\r\n");
|
||||
SerialPrintf("First page %x, Second page %x.\r\n", FirstPage, SecondPage);
|
||||
}
|
||||
}
|
382
chroma/system/memory/paging.c
Normal file
382
chroma/system/memory/paging.c
Normal file
|
@ -0,0 +1,382 @@
|
|||
#include <kernel/chroma.h>
|
||||
#include <lainlib/lainlib.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
/****************************************
|
||||
* W O R K I N P R O G R E S S *
|
||||
****************************************
|
||||
*
|
||||
* This file contains functions for virtual memory management.
|
||||
*
|
||||
* Virtual Memory Management is still a work in progress.
|
||||
* The functions here are hold-offs from old versions of the software implemented here, as well as from the EFI version of Chroma, called Sync.
|
||||
*
|
||||
* There, these functions worked, but here, under BIOS, it's a lot more difficult.
|
||||
* It will take some time to get these functions working.
|
||||
*
|
||||
* The general plan, being that the BOOTBOOT loader has given us static addresses for all of our doodads,
|
||||
* is to keep the core kernel where it is (FFFFFFFFFFE00000) and load in modules and libraries around it.
|
||||
*
|
||||
* We start in the higher half, so we'll dedicate the lower half (7FFFFFFFFFFF and below) to userspace.
|
||||
*
|
||||
* That means we have about 3 terabytes of RAM for the kernel.
|
||||
* This will be identity mapped, always.
|
||||
*
|
||||
* Handily, since most modern processors ignore the highest 2 bytes of a virtual address, and the kernel
|
||||
* is mapped to 0x80000000000 and above, we can use the nomenclature:
|
||||
* * 0x00007FFFFFFFFFFF and below is user space.
|
||||
* * 0xFFFF800000000000 and above is kernel space.
|
||||
* The processor will ignore the first 4 chars, and this provides a great deal of readability for the
|
||||
* future of the kernel.
|
||||
*
|
||||
* We'll have a kernel heap mapped into this kernel space, as well as a kernel stack (for task switching and error tracing).
|
||||
* These will be 1GB each.
|
||||
* We may have to increase this in the future, once Helix is fully integrated.
|
||||
* Helix will take a lot of memory, as it is a fully featured 3D engine. We may have to implement things like
|
||||
* texture streaming and mipmapping. Minimising RAM usage is NOT a priority for me, but it would be nice
|
||||
* to have a minimum requirement above 32GB.
|
||||
*
|
||||
* // TODO: Expand Kernel Heap
|
||||
*
|
||||
*
|
||||
* //TODO: there are lots of calls to AllocateFrame here, those need to be separated out into AllocateZeroFrame if necessary.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
//extern size_t _kernel_text_start;
|
||||
extern size_t _kernel_rodata_start;
|
||||
extern size_t _kernel_data_start;
|
||||
|
||||
//__attribute__((aligned(4096))) static size_t Pagetable[512] = {0};
|
||||
|
||||
#define LAST_ENTRY 0xFF8
|
||||
|
||||
#define SET_ADDRESS(a,b) ((*(size_t*) (a)) = (size_t) b)
|
||||
|
||||
/*
|
||||
* It turns out it's useful to have macros for the standard
|
||||
* data size units.
|
||||
*
|
||||
* Who would've thoguht?
|
||||
*/
|
||||
|
||||
#define KiB 1 * 1024
|
||||
#define MiB 1 * 1024 * KiB
|
||||
|
||||
|
||||
#define PAGE_PRESENT 1
|
||||
#define PAGE_RW 2
|
||||
#define PAGE_USER 4
|
||||
#define PAGE_GLOBAL 8
|
||||
|
||||
|
||||
#define USERWRITEABLE_FLAGS(a) ((a & 0xFFFFFF00) + 0x83)
|
||||
|
||||
// The AbstractAllocator control struct
|
||||
static allocator_t Allocator = NULL;
|
||||
// The AbstractAllocator Ticketlock.
|
||||
static ticketlock_t AllocatorLock = {0};
|
||||
|
||||
// Entries to help allocate the Kernel Stack
|
||||
static list_entry_t StackFreeList;
|
||||
static ticketlock_t StackLock = {0};
|
||||
static void* StackPointer = (void*) KERNEL_STACK_REGION;
|
||||
|
||||
// A temporary itoa function for better debugging..
|
||||
const char* IntToAscii(int In) {
|
||||
char* OutputBuffer = " ";
|
||||
|
||||
size_t Temp, i = 0, j = 0;
|
||||
|
||||
do {
|
||||
Temp = In % 10;
|
||||
OutputBuffer[i++] = (Temp < 10) ? (Temp + '0') : (Temp + 'a' - 10);
|
||||
} while (In /= 10);
|
||||
|
||||
OutputBuffer[i--] = 0;
|
||||
|
||||
for(j = 0; j < i; j++, i--) {
|
||||
Temp = OutputBuffer[j];
|
||||
OutputBuffer[j] = OutputBuffer[i];
|
||||
OutputBuffer[i] = Temp;
|
||||
}
|
||||
|
||||
return OutputBuffer;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void InitPaging() {
|
||||
StackFreeList = (list_entry_t) { &StackFreeList, &StackFreeList };
|
||||
|
||||
size_t Size = AlignUpwards(AllocatorSize(), PAGE_SIZE);
|
||||
Allocator = PhysAllocateZeroMem(Size);
|
||||
Allocator = CreateAllocatorWithPool(Allocator, Size);
|
||||
|
||||
SerialPrintf("[ Mem] Everything preallocated for paging.\n");
|
||||
|
||||
KernelAddressSpace = (address_space_t) {
|
||||
.Lock = {0},
|
||||
.PML4 = PhysAllocateZeroMem(PAGE_SIZE)
|
||||
};
|
||||
|
||||
size_t* Pagetable = KernelAddressSpace.PML4;
|
||||
|
||||
//SerialPrintf("[ Mem] About to identity map the higher half.\n");
|
||||
// Identity map the higher half
|
||||
for(int i = 256; i < 512; i++) {
|
||||
Pagetable[i] = (size_t)PhysAllocateZeroMem(PAGE_SIZE);
|
||||
Pagetable[i] = (size_t)(((char*)Pagetable[i]) - DIRECT_REGION);
|
||||
Pagetable[i] |= (PAGE_PRESENT | PAGE_RW);
|
||||
//SerialPrintf("%d", i - 256);
|
||||
}
|
||||
|
||||
SerialPrintf("[ Mem] Identity mapping higher half complete.\n");
|
||||
|
||||
MMapEnt* TopEntry = (MMapEnt*)(((size_t) (&bootldr) + bootldr.size) - sizeof(MMapEnt));
|
||||
size_t LargestAddress = TopEntry->ptr + TopEntry->size;
|
||||
|
||||
SerialPrintf("[ Mem] About to map lower memory into the Direct Region. Highest address = 0x%p\n", AlignUpwards(LargestAddress, PAGE_SIZE));
|
||||
for(size_t Address = 0; Address < AlignUpwards(LargestAddress, PAGE_SIZE); Address += PAGE_SIZE) {
|
||||
MapVirtualMemory(&KernelAddressSpace, (size_t*)(((char*)Address) + DIRECT_REGION), Address, MAP_WRITE);
|
||||
}
|
||||
SerialPrintf("[ Mem] Lower half mapping complete.\n");
|
||||
|
||||
SerialPrintf("[ Mem] Mapping kernel into new memory map.\r\n");
|
||||
|
||||
//TODO: Disallow execution of rodata and data, and bootldr/environment
|
||||
for(void* Address = CAST(void*, KERNEL_REGION);
|
||||
Address < CAST(void*, KERNEL_REGION + (KernelEnd - KernelAddr)); // Lower half of Kernel
|
||||
Address = CAST(void*, CAST(char*, Address) + PAGE_SIZE)) {
|
||||
MapVirtualMemory(&KernelAddressSpace, Address, (CAST(size_t, Address) - KERNEL_REGION) + KernelLocation, MAP_EXEC);
|
||||
}
|
||||
|
||||
/*for(void* Address = CAST(void*, KERNEL_REGION + 0x2000);
|
||||
Address < CAST(void*, KERNEL_REGION + 0x12000); // Higher half of kernel
|
||||
Address = CAST(void*, CAST(char*, Address) + PAGE_SIZE)) {
|
||||
MapVirtualMemory(&KernelAddressSpace, Address, (CAST(size_t, Address) - KERNEL_REGION) + KERNEL_PHYSICAL_2, MAP_EXEC);
|
||||
}*/
|
||||
|
||||
for(void* Address = CAST(void*, FB_REGION);
|
||||
Address < CAST(void*, 0x200000); // TODO: Turn this into a calculation with bootldr.fb_size
|
||||
Address = CAST(void*, CAST(char*, Address) + PAGE_SIZE)) {
|
||||
MapVirtualMemory(&KernelAddressSpace, Address, (CAST(size_t, Address) - FB_REGION) + FB_PHYSICAL, MAP_WRITE);
|
||||
}
|
||||
|
||||
SerialPrintf("[ Mem] Kernel mapped into pagetables. New PML4 at 0x%p\r\n", KernelAddressSpace.PML4);
|
||||
SerialPrintf("[ Mem] About to move into our own pagetables.\r\n");
|
||||
WriteControlRegister(3, (size_t) KernelAddressSpace.PML4);
|
||||
SerialPrintf("[ Mem] We survived!\r\n");
|
||||
//ASSERT(Allocator != NULL);
|
||||
}
|
||||
|
||||
static size_t GetCachingAttribute(pagecache_t Cache) {
|
||||
switch (Cache) {
|
||||
case CACHE_WRITE_BACK: return 0;
|
||||
case CACHE_WRITE_THROUGH: return 1 << 2;
|
||||
case CACHE_NONE: return 1 << 3;
|
||||
case CACHE_WRITE_COMBINING: return 1 << 6;
|
||||
}
|
||||
|
||||
return 1 << 3;
|
||||
}
|
||||
|
||||
static bool ExpandAllocator(size_t NewSize) {
|
||||
size_t AllocSize = AlignUpwards(AllocatorPoolOverhead() + sizeof(size_t) * 5 + NewSize, PAGE_SIZE);
|
||||
void* Pool = PhysAllocateMem(AllocSize);
|
||||
return AddPoolToAllocator(Allocator, Pool, AllocSize) != NULL;
|
||||
}
|
||||
|
||||
static void GetPageFromTables(address_space_t* AddressSpace, size_t VirtualAddress, size_t** Page) {
|
||||
|
||||
//ASSERT(Page != NULL);
|
||||
//ASSERT(AddressSpace != NULL);
|
||||
|
||||
size_t* Pagetable = AddressSpace->PML4;
|
||||
for(int Level = 4; Level > 1; Level--) {
|
||||
size_t* Entry = &Pagetable[(VirtualAddress >> (12u + 9u * (Level - 1))) & 0x1FFU];
|
||||
|
||||
ASSERT(*Entry & PAGE_PRESENT, "Page not present during retrieval");
|
||||
|
||||
Pagetable = (size_t*)((char*)(*Entry & 0x7ffffffffffff000ull) + DIRECT_REGION);
|
||||
}
|
||||
|
||||
ASSERT(Pagetable[(VirtualAddress >> 12U) & 0x1FFU] & PAGE_PRESENT, "PDPE not present during retrieval");
|
||||
*Page = &Pagetable[(VirtualAddress >> 12U) & 0x1FFU];
|
||||
|
||||
}
|
||||
|
||||
void SetAddressSpace(address_space_t* AddressSpace) {
|
||||
//ASSERT(AddressSpace != NULL);
|
||||
|
||||
if((size_t)((char*)ReadControlRegister(3) + DIRECT_REGION) != (size_t) &AddressSpace->PML4) {
|
||||
WriteControlRegister(3, CAST(size_t, &AddressSpace->PML4));
|
||||
}
|
||||
}
|
||||
|
||||
void MapVirtualMemory(address_space_t* AddressSpace, void* VirtualAddress, size_t PhysicalAddress, mapflags_t Flag) {
|
||||
|
||||
//bool MapGlobally = false;
|
||||
size_t Virtual = (size_t)VirtualAddress;
|
||||
|
||||
//ASSERT(AddressSpace != NULL);
|
||||
TicketAttemptLock(&AddressSpace->Lock);
|
||||
|
||||
size_t Flags = PAGE_PRESENT;
|
||||
|
||||
if(Flag & MAP_WRITE)
|
||||
Flags |= MAP_WRITE;
|
||||
|
||||
if(Virtual < USER_REGION)
|
||||
Flags |= PAGE_USER;
|
||||
//TODO: Global mapping
|
||||
|
||||
size_t* Pagetable = AddressSpace->PML4;
|
||||
for(int Level = 4; Level > 1; Level--) {
|
||||
size_t* Entry = &Pagetable[(Virtual >> (12u + 9u * (Level - 1))) & 0x1FFu];
|
||||
|
||||
if(!(*Entry & PAGE_PRESENT)) {
|
||||
directptr_t Pointer = PhysAllocateZeroMem(PAGE_SIZE);
|
||||
*Entry = (size_t)(((char*)Pointer) - DIRECT_REGION);
|
||||
}
|
||||
|
||||
*Entry |= Flags;
|
||||
|
||||
Pagetable = (size_t*)(((char*)(*Entry & 0x7ffffffffffff000ull) + DIRECT_REGION));
|
||||
}
|
||||
|
||||
size_t* Entry = &Pagetable[(Virtual >> 12u) & 0x1FFu];
|
||||
*Entry = Flags | PhysicalAddress;
|
||||
|
||||
|
||||
if(AddressSpace != NULL) {
|
||||
TicketUnlock(&AddressSpace->Lock);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void UnmapVirtualMemory(address_space_t* AddressSpace, void* VirtualAddress){
|
||||
//ASSERT(AddressSpace != NULL);
|
||||
|
||||
TicketAttemptLock(&AddressSpace->Lock);
|
||||
|
||||
size_t* Entry;
|
||||
GetPageFromTables(AddressSpace, (size_t)VirtualAddress, &Entry);
|
||||
|
||||
*Entry = 0;
|
||||
InvalidatePage((size_t)VirtualAddress);
|
||||
|
||||
if(AddressSpace != NULL) {
|
||||
TicketUnlock(&AddressSpace->Lock);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CacheVirtualMemory(address_space_t* AddressSpace, void* VirtualAddress, pagecache_t Cache) {
|
||||
|
||||
//ASSERT(AddressSpace != NULL);
|
||||
|
||||
TicketAttemptLock(&AddressSpace->Lock);
|
||||
|
||||
size_t* Entry;
|
||||
|
||||
GetPageFromTables(AddressSpace, (size_t)VirtualAddress, &Entry);
|
||||
|
||||
*Entry &= ~((1 << 6) | (1 << 2) | (1 << 3));
|
||||
*Entry |= GetCachingAttribute(Cache);
|
||||
|
||||
InvalidatePage((size_t)VirtualAddress);
|
||||
|
||||
if(AddressSpace != NULL) {
|
||||
TicketUnlock(&AddressSpace->Lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void* AllocateMemory(size_t Bits) {
|
||||
TicketAttemptLock(&AllocatorLock);
|
||||
|
||||
void* Result = AllocatorMalloc(Allocator, Bits);
|
||||
|
||||
if(Result == NULL) {
|
||||
if(!ExpandAllocator(Bits)) {
|
||||
TicketUnlock(&AllocatorLock);
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
Result = AllocatorMalloc(Allocator, Bits);
|
||||
}
|
||||
|
||||
if(Result != NULL) {
|
||||
memset(Result, 0, Bits);
|
||||
}
|
||||
|
||||
TicketUnlock(&AllocatorLock);
|
||||
return Result;
|
||||
|
||||
}
|
||||
|
||||
void* ReallocateMemory(void* Address, size_t NewSize) {
|
||||
TicketAttemptLock(&AllocatorLock);
|
||||
void* Result = AllocatorRealloc(Allocator, Address, NewSize);
|
||||
|
||||
if(Result == NULL) {
|
||||
if(!ExpandAllocator(NewSize)) {
|
||||
TicketUnlock(&AllocatorLock);
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
Result = AllocatorRealloc(Allocator, Address, NewSize);
|
||||
}
|
||||
|
||||
TicketUnlock(&AllocatorLock);
|
||||
return Result;
|
||||
|
||||
}
|
||||
|
||||
void FreeMemory(void* Address) {
|
||||
TicketAttemptLock(&AllocatorLock);
|
||||
AllocatorFree(Allocator, Address);
|
||||
TicketUnlock(&AllocatorLock);
|
||||
}
|
||||
|
||||
void* AllocateKernelStack() {
|
||||
void* StackAddress = NULL;
|
||||
size_t StackSize = PAGE_SIZE * 4;
|
||||
|
||||
TicketAttemptLock(&StackLock);
|
||||
if(ListIsEmpty(&StackFreeList)) {
|
||||
StackAddress = StackPointer;
|
||||
StackPointer = (void*)(((char*)StackPointer) + (4*KiB) + StackSize);
|
||||
|
||||
for(size_t i = 0; i < (StackSize / PAGE_SIZE); i++) {
|
||||
directptr_t NewStack;
|
||||
NewStack = PhysAllocateZeroMem(PAGE_SIZE);
|
||||
MapVirtualMemory(&KernelAddressSpace, (void*)((size_t)StackAddress + i * PAGE_SIZE), (size_t)((char*)NewStack) - DIRECT_REGION, MAP_WRITE);
|
||||
}
|
||||
} else {
|
||||
list_entry_t* StackEntry = StackFreeList.Next;
|
||||
ListRemove(StackEntry);
|
||||
memset(StackEntry, 0, StackSize);
|
||||
StackAddress = (void*)StackEntry;
|
||||
}
|
||||
|
||||
TicketUnlock(&StackLock);
|
||||
|
||||
StackAddress = (void*)((size_t)StackAddress + StackSize);
|
||||
StackAddress = (void*)((size_t)StackAddress - sizeof(size_t) * 2);
|
||||
|
||||
return StackAddress;
|
||||
}
|
||||
|
||||
void FreeKernelStack(void* StackAddress) {
|
||||
TicketAttemptLock(&StackLock);
|
||||
list_entry_t* ListEntry = (list_entry_t*)(((size_t)(StackAddress) + (sizeof(size_t) * 2)) - (PAGE_SIZE * 4));
|
||||
ListAdd(&StackFreeList, ListEntry);
|
||||
TicketUnlock(&StackLock);
|
||||
}
|
340
chroma/system/memory/physmem.c
Normal file
340
chroma/system/memory/physmem.c
Normal file
|
@ -0,0 +1,340 @@
|
|||
#include <kernel/chroma.h>
|
||||
#include <kernel/system/heap.h>
|
||||
#include <lainlib/lainlib.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
/* This file contains functions for physical memory management.
|
||||
*
|
||||
* This is also called blocking, or block memory allocation.
|
||||
* It mostly deals with the memory map handed to us by the bootloader.
|
||||
*
|
||||
* It is useful in virtual memory management, because it allows us to map one block of physical memory to one page of virtual memory.
|
||||
*
|
||||
* Most of the processing here is done with a bitwise mapping of blocks to allocations, normally called a memory bitmap.
|
||||
* See heap.h for the implementation.
|
||||
*
|
||||
* This file also contains memory manipulation functions, like memset and memcpy.
|
||||
* //TODO: replace these functions with SSE2 equivalent.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#define MIN_ORDER 3
|
||||
#define PEEK(type, address) (*((volatile type*)(address)))
|
||||
|
||||
uint8_t* Memory = ((uint8_t*)(&memstart));
|
||||
uint8_t* MemoryStart;
|
||||
size_t MemoryBuckets;
|
||||
|
||||
static buddy_t LowBuddy = {
|
||||
.MaxOrder = 32,
|
||||
.Base = (directptr_t) DIRECT_REGION,
|
||||
.List = (directptr_t[32 - MIN_ORDER]) {0},
|
||||
.Lock = {0},
|
||||
};
|
||||
|
||||
static buddy_t HighBuddy = {
|
||||
.MaxOrder = 64,
|
||||
.Base = 0,
|
||||
.List = (directptr_t[64 - MIN_ORDER]) {0},
|
||||
.Lock = {0},
|
||||
};
|
||||
|
||||
static size_t MemoryLength;
|
||||
|
||||
static bool CheckBuddies(buddy_t* Buddy, directptr_t InputA, directptr_t InputB, size_t Size) {
|
||||
size_t LowerBuddy = MIN(CAST(size_t, InputA), CAST(size_t, InputB)) - (size_t) Buddy->Base;
|
||||
size_t HigherBuddy = MAX(CAST(size_t, InputA), CAST(size_t, InputB)) - (size_t) Buddy->Base;
|
||||
|
||||
return (LowerBuddy ^ Size) == HigherBuddy;
|
||||
}
|
||||
|
||||
static void AddToBuddyList(buddy_t* Buddy, directptr_t Address, size_t Order, bool NewEntry) {
|
||||
directptr_t ListHead = Buddy->List[Order - MIN_ORDER];
|
||||
|
||||
//SerialPrintf("Adding new entry to buddy: Address 0x%p with order %d, New Entry is %s\r\n", Address, Order, NewEntry ? "true" : "false");
|
||||
|
||||
/*
|
||||
SerialPrintf("About to poke memory..\r\n");
|
||||
PEEK(directptr_t, Address) = 0;
|
||||
SerialPrintf("Did it work?\r\n");
|
||||
*/
|
||||
|
||||
size_t Size = 1ull << Order;
|
||||
|
||||
TicketAttemptLock(&Buddy->Lock);
|
||||
|
||||
//SerialPrintf("Ticketlock engaged\r\n");
|
||||
|
||||
if(!NewEntry && ListHead != 0) {
|
||||
directptr_t ListPrevious = 0;
|
||||
|
||||
while(true) {
|
||||
if(CheckBuddies(Buddy, ListHead, Address, Size)) {
|
||||
if(ListPrevious != 0) {
|
||||
PEEK(directptr_t, ListPrevious) = PEEK(directptr_t, ListHead);
|
||||
} else
|
||||
Buddy->List[Order - MIN_ORDER] = PEEK(directptr_t, ListHead);
|
||||
|
||||
AddToBuddyList(Buddy, MIN(ListHead, Address), Order + 1, false);
|
||||
break;
|
||||
}
|
||||
|
||||
if(PEEK(directptr_t, ListHead) == 0) {
|
||||
PEEK(directptr_t, ListHead) = Address;
|
||||
break;
|
||||
}
|
||||
|
||||
ListPrevious = ListHead;
|
||||
ListHead = PEEK(directptr_t, ListHead);
|
||||
}
|
||||
} else {
|
||||
//SerialPrintf("\tAbout to poke memory 0x%p - current value is 0x%x\r\n", Address, *((size_t*)(Address)));
|
||||
*((size_t*)(Address)) = (size_t) ListHead;
|
||||
Buddy->List[Order - MIN_ORDER] = Address;
|
||||
}
|
||||
|
||||
TicketUnlock(&Buddy->Lock);
|
||||
|
||||
//SerialPrintf("Ticketlock Released.\r\n");
|
||||
}
|
||||
|
||||
static void AddRangeToBuddy(buddy_t* Buddy, directptr_t Base, size_t Size) {
|
||||
//SerialPrintf("Starting a new range addition.\r\n\t");
|
||||
while(Size > (1ull << MIN_ORDER)) {
|
||||
//SerialPrintf("New iteration. Current Size: 0x%x\r\n\t", Size);
|
||||
for(int Order = Buddy->MaxOrder - 1; Order >= MIN_ORDER; Order--) {
|
||||
//SerialPrintf("New Loop. Current Order: %d\r\n\t", Order);
|
||||
if(Size >= (1ull << Order)) {
|
||||
//SerialPrintf("\tNew loop check passed.\r\n\t");
|
||||
AddToBuddyList(Buddy, Base, Order, true);
|
||||
//SerialPrintf("\tEntry added to current buddy. Moving onto memory operations..\r\n\t");
|
||||
Base = (void*)((((char*)Base) + (1ull << Order)));
|
||||
Size -= 1ull << Order;
|
||||
//SerialPrintf("\tMemory operations complete. Moving onto next iteration.\r\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static directptr_t BuddyAllocate(buddy_t* Buddy, size_t Size) {
|
||||
int InitialOrder = MAX((64 - CLZ(Size - 1)), MIN_ORDER);
|
||||
|
||||
size_t WantedSize = 1ull << InitialOrder;
|
||||
|
||||
if(InitialOrder >= Buddy->MaxOrder) {
|
||||
SerialPrintf("Tried to allocate too much physical memory for buddy 0x%p\r\n", Buddy);
|
||||
SerialPrintf("Buddy 0x%p has max order %d, but 0x%x bytes was requested.\r\nInitial Order: %d, Wanted Size: 0x%x\r\n", Buddy, Buddy->MaxOrder, Size, InitialOrder, WantedSize);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TicketAttemptLock(&Buddy->Lock);
|
||||
|
||||
//SerialPrintf("Searching for a valid order to allocate into. Condition: {\r\n\tOrder: %d,\r\n\tSize: 0x%x\r\n}\r\n\n", InitialOrder, WantedSize);
|
||||
|
||||
for(int Order = InitialOrder; Order < Buddy->MaxOrder; Order++) {
|
||||
//SerialPrintf("\tCurrent Order: %d, Buddy entry: %x\r\n", Order, Buddy->List[Order - MIN_ORDER]);
|
||||
if(Buddy->List[Order - MIN_ORDER] != 0) {
|
||||
//SerialPrintf("\tFound a valid Order!\r\n");
|
||||
directptr_t Address = Buddy->List[Order - MIN_ORDER];
|
||||
Buddy->List[Order - MIN_ORDER] = PEEK(directptr_t, Address);
|
||||
TicketUnlock(&Buddy->Lock);
|
||||
|
||||
size_t FoundSize = 1ull << Order;
|
||||
|
||||
//SerialPrintf("\tAdding area - Address 0x%p, Size 0x%x\r\n\n", Address, FoundSize);
|
||||
|
||||
AddRangeToBuddy(Buddy, (void*)((size_t)Address + WantedSize), FoundSize - WantedSize);
|
||||
|
||||
//SerialPrintf("\tArea added!\r\n");
|
||||
return Address;
|
||||
}
|
||||
}
|
||||
|
||||
//SerialPrintf("BuddyAllocate: Unable to find a valid order to allocate!\r\nInitial Order: %d, WantedSize: 0x%x\r\n\r\n", InitialOrder, WantedSize);
|
||||
|
||||
TicketUnlock(&Buddy->Lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void InitMemoryManager() {
|
||||
|
||||
SerialPrintf("[ Mem] Counting memory..\r\n");
|
||||
|
||||
MemorySize = 0;
|
||||
size_t MemMapEntryCount = 0;
|
||||
|
||||
MMapEnt* MemMap = &bootldr.mmap;
|
||||
|
||||
while((size_t) MemMap < ((size_t) &bootldr) + bootldr.size) {
|
||||
if(MMapEnt_IsFree(MemMap)) {
|
||||
MemorySize += MMapEnt_Size(MemMap);
|
||||
}
|
||||
MemMapEntryCount++;
|
||||
MemMap++;
|
||||
}
|
||||
|
||||
SerialPrintf("[ Mem] Counted %d entries in the memory map..\r\n", MemMapEntryCount);
|
||||
|
||||
MemoryPages = MemorySize / PAGE_SIZE;
|
||||
|
||||
SerialPrintf("[ Mem] %u MB of memory detected.\r\n", (MemorySize / 1024) / 1024);
|
||||
}
|
||||
|
||||
|
||||
void ListMemoryMap() {
|
||||
|
||||
SerialPrintf("[ Mem] BIOS-Provided memory map:\r\n");
|
||||
|
||||
|
||||
for(MMapEnt* MapEntry = &bootldr.mmap; (size_t)MapEntry < (size_t) &bootldr + bootldr.size; MapEntry++) {
|
||||
char EntryType[8] = {0};
|
||||
switch(MMapEnt_Type(MapEntry)) {
|
||||
case MMAP_FREE:
|
||||
memcpy(EntryType, "FREE", 5);
|
||||
break;
|
||||
case MMAP_USED:
|
||||
memcpy(EntryType, "RESERVED", 8);
|
||||
break;
|
||||
case MMAP_ACPI:
|
||||
memcpy(EntryType, "ACPI", 4);
|
||||
break;
|
||||
case MMAP_MMIO:
|
||||
memcpy(EntryType, "MMIO", 4);
|
||||
break;
|
||||
}
|
||||
|
||||
size_t entry_from = MMapEnt_Ptr(MapEntry);
|
||||
size_t entry_to = MMapEnt_Ptr(MapEntry) + MMapEnt_Size(MapEntry);
|
||||
|
||||
|
||||
if(entry_from != 0 && entry_to != 0)
|
||||
SerialPrintf("[ Mem] 0x%p-0x%p %s\r\n", entry_from, entry_to, EntryType);
|
||||
|
||||
if(MMapEnt_Type(MapEntry) == MMAP_FREE) {
|
||||
SerialPrintf("[ Mem] Adding this entry to the physical memory manager!\r\n");
|
||||
AddRangeToPhysMem((void*)((char*)(MMapEnt_Ptr(MapEntry) /* + DIRECT_REGION*/ )), MMapEnt_Size(MapEntry));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AddRangeToPhysMem(directptr_t Base, size_t Size) {
|
||||
if(Base < (void*)(LOWER_REGION + DIRECT_REGION)) {
|
||||
SerialPrintf("[ Mem] New range in lower memory: 0x%p, size 0x%x\r\n", Base, Size);
|
||||
AddRangeToBuddy(&LowBuddy, Base, Size);
|
||||
} else {
|
||||
if(HighBuddy.Base == NULL) {
|
||||
HighBuddy.Base = Base;
|
||||
}
|
||||
|
||||
AddRangeToBuddy(&HighBuddy, Base, Size);
|
||||
}
|
||||
|
||||
if(MemoryLength < AlignUpwards((size_t)Base + Size, PAGE_SIZE) / PAGE_SIZE) {
|
||||
MemoryLength = AlignUpwards((size_t)Base + Size, PAGE_SIZE) / PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
directptr_t PhysAllocateLowMem(size_t Size) {
|
||||
directptr_t Pointer = BuddyAllocate(&LowBuddy, Size);
|
||||
ASSERT(Pointer != NULL, "PhysAllocateLowMem: Allocation failed!");
|
||||
|
||||
return Pointer;
|
||||
}
|
||||
|
||||
directptr_t PhysAllocateMem(size_t Size) {
|
||||
directptr_t Pointer = NULL;
|
||||
|
||||
if(HighBuddy.Base == 0) {
|
||||
//SerialPrintf("Attempting allocation into high memory.\n");
|
||||
Pointer = BuddyAllocate(&HighBuddy, Size);
|
||||
}
|
||||
|
||||
if(Pointer == NULL) {
|
||||
//SerialPrintf("Attempting allocation into low memory.\n");
|
||||
Pointer = BuddyAllocate(&LowBuddy, Size);
|
||||
}
|
||||
|
||||
ASSERT(Pointer != NULL, "PhysAllocateMem: Unable to allocate memory!");
|
||||
|
||||
return Pointer;
|
||||
}
|
||||
|
||||
directptr_t PhysAllocateZeroMem(size_t Size) {
|
||||
directptr_t Pointer = PhysAllocateMem(Size);
|
||||
memset(Pointer, 0, Size);
|
||||
return Pointer;
|
||||
}
|
||||
|
||||
directptr_t PhysAllocateLowZeroMem(size_t Size) {
|
||||
directptr_t Pointer = PhysAllocateLowMem(Size);
|
||||
memset(Pointer, 0, Size);
|
||||
return Pointer;
|
||||
|
||||
}
|
||||
|
||||
void PhysFreeMem(directptr_t Pointer, size_t Size) {
|
||||
ASSERT(Pointer >= (directptr_t) DIRECT_REGION, "PhysFreeMem: Attempting to free memory not in the direct mapping region.");
|
||||
|
||||
buddy_t* Buddy;
|
||||
|
||||
if(Pointer < (void*)(LOWER_REGION + DIRECT_REGION))
|
||||
Buddy = &LowBuddy;
|
||||
else
|
||||
Buddy = &HighBuddy;
|
||||
|
||||
int Order = MAX(64 - CLZ(Size - 1), MIN_ORDER);
|
||||
AddToBuddyList(Buddy, Pointer, Order, false);
|
||||
}
|
||||
|
||||
static _Atomic(uint16_t)* PageRefCount = NULL;
|
||||
|
||||
void PhysAllocatorInit() {
|
||||
PageRefCount = PhysAllocateZeroMem(sizeof(uint16_t) * MemoryPages);
|
||||
}
|
||||
|
||||
directptr_t PhysAllocatePage() {
|
||||
directptr_t Page = PhysAllocateMem(PAGE_SIZE);
|
||||
PhysRefPage(Page);
|
||||
return Page;
|
||||
}
|
||||
|
||||
void PhysRefPage(directptr_t Page) {
|
||||
PageRefCount[(size_t) Page >> PAGE_SHIFT]++;
|
||||
}
|
||||
|
||||
void PhysFreePage(directptr_t Page) {
|
||||
if(--PageRefCount[(size_t)Page >> PAGE_SHIFT] == 0) {
|
||||
PhysFreeMem(Page, PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
void* memcpy(void* dest, void const* src, size_t len) {
|
||||
unsigned char* dst = (unsigned char*) dest;
|
||||
const unsigned char* source = (const unsigned char*) src;
|
||||
|
||||
for(size_t i = 0; i < len; i++) {
|
||||
dst[i] = source[i];
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
void* memset(void* dst, int src, size_t len) {
|
||||
unsigned char* buf = (unsigned char*) dst;
|
||||
|
||||
for(size_t i = 0; i < len; i++) {
|
||||
buf[i] = (unsigned char) src;
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
29
chroma/system/memory/stack.c
Normal file
29
chroma/system/memory/stack.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
#include <kernel/chroma.h>
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
/*
|
||||
* This file aims to implement stack unwinding
|
||||
* to trace faulty functions.
|
||||
*
|
||||
* I was in the middle of debugging a jump to null
|
||||
* when i started creating this, so there will be a
|
||||
* lot of functionality here left over from that
|
||||
* initial goal, probably...
|
||||
*
|
||||
* //TODO: Rework this to allow unwinding function parameters on call.
|
||||
*/
|
||||
|
||||
void StackTrace(size_t cycles) {
|
||||
struct stackframe* stack;
|
||||
|
||||
__asm__ __volatile__ ("mov %%rbp, %[dest]" : [dest] "=r" (stack) : :);
|
||||
SerialPrintf("[Trace] Beginning stack trace. RBP is currently 0x%p\r\n", stack);
|
||||
for(size_t frame = 0; stack != 0 && frame < cycles; ++frame) {
|
||||
SerialPrintf("[Trace] 0x%p \r\n", stack->rip);
|
||||
stack = stack->rbp;
|
||||
}
|
||||
SerialPrintf("[Trace] Stack trace over.\r\n");
|
||||
}
|
523
chroma/system/pci.c
Normal file
523
chroma/system/pci.c
Normal file
|
@ -0,0 +1,523 @@
|
|||
#include <kernel/chroma.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
/* This file contains functions for accessing the PCI bus,
|
||||
* and devices contained wherein.
|
||||
*
|
||||
* It allows you to query the bus, as well as communicate with individual devices.
|
||||
*
|
||||
*/
|
||||
|
||||
pci_dev_t** pci_root_devices = NULL;
|
||||
pci_entry_t* pci_map = NULL;
|
||||
|
||||
//static uint32_t PCIReadConfig(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset);
|
||||
|
||||
//static const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_t progif);
|
||||
|
||||
//static const char* PCIGetClassName(uint8_t devclass);
|
||||
|
||||
void PCIEnumerate() {
|
||||
|
||||
uint8_t bus = 0, device = 0, function = 0;
|
||||
|
||||
uint32_t registerData;
|
||||
|
||||
uint16_t device_id, vendor_id;
|
||||
|
||||
uint8_t class_code, subclass_code;
|
||||
|
||||
SerialPrintf("[ PCI] Started PCI Enumeration.");
|
||||
|
||||
SerialPrintf("\n[ PCI] PCI Scan result:\n[ PCI]");
|
||||
do {
|
||||
for (device = 0; device <= 31; device++) {
|
||||
for(function = 0; function <= 7; function++) {
|
||||
registerData = PCIReadConfig(bus, device, 0, 0xC); // Read BIST/Header/Latency/Cache Line register
|
||||
uint8_t header = (uint8_t) ((registerData & 0x00FF0000) >> 24); // Header is lower byte of upper word, so mask it off and shift it down
|
||||
uint8_t multifunction_bit = header & 0x80; // The multifunction bit is the highest bit of the header
|
||||
|
||||
registerData = PCIReadConfig(bus, device, function, 0); // Read the Vendor/Device ID register
|
||||
vendor_id = (uint16_t) (registerData & 0x0000FFFF); // Vendor ID is bottom word
|
||||
device_id = (uint16_t) (registerData >> 16); // Device ID is top word
|
||||
|
||||
registerData = PCIReadConfig(bus, device, function, 8); // Read the Device Info register
|
||||
class_code = (uint16_t)( registerData >> 24); // Device class is top byte, so shift them down
|
||||
subclass_code = (uint16_t) ((registerData >> 16) & 0x00FF); // Device subclass is same as header - lower byte of higher word. Shift down and mask just like before.
|
||||
uint8_t device_progif = (uint16_t) ((registerData & 0x0000FF00) >> 8); // Device Programming Interface is higher byte of lower word, so mask and shift
|
||||
uint8_t device_revision = (uint16_t) (registerData & 0x000000FF); // Device revision is lower byte of whole double word. Just mask it.
|
||||
|
||||
|
||||
/* 0xFFFF is not a valid Vendor ID. This serves as a sanity check.
|
||||
* If this check is true, then nothing is logged and we continue for the next loop.
|
||||
*/
|
||||
if(vendor_id != 0xFFFF) {
|
||||
SerialPrintf("[ PCI]\n[ PCI]\t%x:%x:\n[ PCI]\t\tVendor: %x\n[ PCI]\t\tDevice: %x", bus, device, vendor_id, device_id);
|
||||
SerialPrintf("\n[ PCI]\t\tClass: %s\n[ PCI]\t\tDevice Type: %s\n[ PCI]\t\tRevision: %d\n", PCIGetClassName(class_code), PCIGetDeviceName_Subclass(class_code, subclass_code, device_progif), device_revision);
|
||||
}
|
||||
|
||||
/* If the PCI Device header tells us that this is not a multifunction device,
|
||||
* and we've already scanned function 0, then there is nothing else to see.
|
||||
* Therefore, stop this loop and move onto device++
|
||||
*/
|
||||
if (multifunction_bit == 0)
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
} while (++bus);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
uint32_t PCIReadConfig(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset) {
|
||||
uint32_t address;
|
||||
uint32_t busLong = (uint32_t) bus;
|
||||
uint32_t slotLong = (uint32_t) slot;
|
||||
uint32_t functionLong = (uint32_t) function;
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* | 31 | 30 ... 24 | 23 ... 16 | 15 ... 11 | 10 ... 8 | 7 ... 0 |
|
||||
* ---------------------------------------------------------------
|
||||
* | EN | RESERVED | BUS NUM | DEVICE NO | FUNC NO | REG OFF |
|
||||
* ---------------------------------------------------------------
|
||||
*
|
||||
* NOTE: REG OFF *must* have 0 last two bits (ie. & 0xFC)
|
||||
*/
|
||||
|
||||
address = (uint32_t) (( busLong << 16 ) | ( slotLong << 11 ) |
|
||||
( functionLong << 8 ) | ( offset & 0xFC) | ((uint32_t)0x80000000));
|
||||
|
||||
WritePort(0xCF8, address, 4);
|
||||
|
||||
|
||||
return ReadPort(0xCFC, 4);
|
||||
}
|
||||
|
||||
const char* PCIGetDeviceName_Subclass(uint8_t devclass, uint8_t subclass, uint8_t progif) {
|
||||
switch(devclass) {
|
||||
|
||||
case 0x00: {
|
||||
switch(subclass) {
|
||||
case 0x00: return "Non-VGA-Compatible device";
|
||||
case 0x01: return "VGA-Compatible device";
|
||||
default: return "Unknown Unclassified";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x01: {
|
||||
switch(subclass) {
|
||||
case 0x00: return "SCSI Bus Controller";
|
||||
case 0x01: {
|
||||
switch(progif) {
|
||||
case 0x00: return "ISA Compatibility Mode-only IDE Controller";
|
||||
case 0x05: return "PCI Native Mode-only IDE Controller";
|
||||
case 0x0A: return "ISA Compatibility Mode IDE Controller (supports PCI Native Mode)";
|
||||
case 0x0F: return "PCI Native Mode IDE Controller (supports ISA Compatibility Mode)";
|
||||
case 0x80: return "ISA Compatibilty Mode-only IDE Controller (supports Bus Mastering)";
|
||||
case 0x85: return "PCI Native Mode-only IDE Controller (supports Bus Mastering)";
|
||||
case 0x8A: return "ISA Compatibility Mode IDE Controller (supports PCI Native Mode & Bus Mastering)";
|
||||
case 0x8F: return "PCI Native Mode IDE Controller (supports ISA Compatibiliy Mode & Bus Mastering)";
|
||||
default: return "IDE Controller";
|
||||
}
|
||||
}
|
||||
case 0x02: return "Floppy Disk Controller";
|
||||
case 0x03: return "IPI Bus Controller";
|
||||
case 0x04: return "RAID Controller";
|
||||
case 0x05: {
|
||||
switch(progif) {
|
||||
case 0x20: return "Single-DMA ATA Controller";
|
||||
case 0x30: return "Chained-DMA ATA Controller";
|
||||
default: return "ATA Controller";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
case 0x06: {
|
||||
switch(progif) {
|
||||
case 0x00: return "Vendor-Specific Interface SATA Controller";
|
||||
case 0x01: return "AHCI 1.0 SATA Controller";
|
||||
case 0x02: return "Serial Storage Bus SATA Controller";
|
||||
default: return "Serial ATA Controller";
|
||||
}
|
||||
}
|
||||
case 0x07: return "Serial Attached SCSI (SAS)";
|
||||
|
||||
case 0x08:{
|
||||
switch(progif) {
|
||||
case 0x01: return "NVMHCI Memory Controller";
|
||||
case 0x02: return "NVMe Memory Controller";
|
||||
default: return "Non-Volatile Memory Controller";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Mass Storage Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x02: {
|
||||
switch(subclass) {
|
||||
case 0x00: return "Ethernet Controller";
|
||||
case 0x01: return "Token Ring Controller";
|
||||
case 0x02: return "FDDI Controller";
|
||||
case 0x03: return "ATM Controller";
|
||||
case 0x04: return "ISDN Controller";
|
||||
case 0x05: return "WorldFip Controller";
|
||||
case 0x06: return "PICMG 2.14 Multi Computing";
|
||||
case 0x07: return "Infiniband Controller";
|
||||
case 0x08: return "Fabric Controller";
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Network Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x03: {
|
||||
switch(subclass) {
|
||||
case 0x00: {
|
||||
switch(progif) {
|
||||
case 0x00: return "VGA Controller";
|
||||
case 0x01: return "8514 VGA Controller";
|
||||
default: return "VGA Compatible Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x01: return "XGA Controller";
|
||||
case 0x02: return "3D Controller (Not VGA-Compatible)";
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Display Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x04: {
|
||||
switch(subclass) {
|
||||
case 0x00: return "Multimedia Video Controller";
|
||||
case 0x01: return "Multimedia Audio Controller";
|
||||
case 0x02: return "Computer Telephony Device";
|
||||
case 0x03: return "Audio Device";
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Multimedia Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x05: {
|
||||
switch(subclass) {
|
||||
case 0x00: return "RAM Controller";
|
||||
case 0x01: return "Flash Controller";
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Memory Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x06: {
|
||||
switch(subclass) {
|
||||
case 0x00: return "Host Bridge";
|
||||
case 0x01: return "ISA Bridge";
|
||||
case 0x02: return "EISA Bridge";
|
||||
case 0x03: return "MCA Bridge";
|
||||
case 0x04:
|
||||
case 0x09:
|
||||
return "PCI-to-PCI Bridge";
|
||||
case 0x05: return "PCMCIA Bridge";
|
||||
case 0x06: return "NuBus Bridge";
|
||||
case 0x07: return "CardBus Bridge";
|
||||
case 0x08: return "RACEway Bridge";
|
||||
case 0x0A: return "InfiniBand-to-PCI Host Bridge";
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Bridge Device";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x07: {
|
||||
switch(subclass) {
|
||||
|
||||
case 0x00: {
|
||||
switch(progif) {
|
||||
case 0x00: return "Serial Controller <8250>";
|
||||
case 0x01: return "Serial controller <16450>";
|
||||
case 0x02: return "Serial controller <16550>";
|
||||
case 0x03: return "Serial controller <16650>";
|
||||
case 0x04: return "Serial controller <16750>";
|
||||
case 0x05: return "Serial controller <16850>";
|
||||
case 0x06: return "Serial controller <16950>";
|
||||
default: return "Serial Controller";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
case 0x01: {
|
||||
switch(progif) {
|
||||
case 0x00: return "Standard Parallel Port";
|
||||
case 0x01: return "Bi-Directional Parallel Port";
|
||||
case 0x02: return "ECP 1.X Compliant Parallel Port";
|
||||
case 0x03: return "IEEE 1284 Parallel Controller";
|
||||
case 0x04: return "IEE 1284 Parallel Target";
|
||||
default: return "Parallel Controller";
|
||||
}
|
||||
}
|
||||
case 0x02: return "Multiport Serial Controller";
|
||||
|
||||
case 0x03: {
|
||||
switch(progif) {
|
||||
case 0x00: return "Generic Modem";
|
||||
case 0x01: return "Hayes 16450 Compatible Modem";
|
||||
case 0x02: return "Hayes 16550 Compatible Modem";
|
||||
case 0x03: return "Hayes 16650 Compatible Modem";
|
||||
case 0x04: return "Hayes 16750 Compatible Modem";
|
||||
default: return "Modem";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x04: return "IEEE 488.1/2 (GPIB) Controller";
|
||||
case 0x05: return "Smart Card";
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Simple Comms Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x08: {
|
||||
switch(subclass) {
|
||||
case 0x00: {
|
||||
switch(progif) {
|
||||
case 0x00: return "Generic 8259-Compatible PIC";
|
||||
case 0x01: return "ISA-Compatible PIC";
|
||||
case 0x02: return "EISA-Compatible PIC";
|
||||
case 0x03: return "I/O APIC Interrupt Controller";
|
||||
case 0x04: return "I/O(x) APIC Interrupt Controller";
|
||||
default: return "PIC";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x01: {
|
||||
switch(progif) {
|
||||
case 0x00: return "Generic 8237-Compatible DMA Controller";
|
||||
case 0x01: return "ISA-Compatible DMA Controller";
|
||||
case 0x02: return "EISA-Compatible DMA Controller";
|
||||
default: return "DMA Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x02: {
|
||||
switch(progif) {
|
||||
case 0x00: return "Generic 8254-Compatible Timer";
|
||||
case 0x01: return "ISA-Compatible Timer";
|
||||
case 0x02: return "EISA-Compatible Timer";
|
||||
case 0x03: return "HPET Timer";
|
||||
default: return "Timer";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x03: {
|
||||
switch(progif) {
|
||||
case 0x00: return "Generic RTC Controller";
|
||||
case 0x01: return "ISA-Compatible RTC Controller";
|
||||
default: return "RTC Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x04: return "PCI Hot-Plug Controller";
|
||||
case 0x05: return "SD Host Controller";
|
||||
case 0x06: return "IOMMU";
|
||||
case 0x80: return "Other";
|
||||
|
||||
default: return "Unknown Base System Peripheral";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x09: {
|
||||
switch(subclass) {
|
||||
case 0x00: return "Keyboard Controller";
|
||||
case 0x01: return "Digitiser Pen";
|
||||
case 0x02: return "Mouse Controller";
|
||||
case 0x03: return "Scanner Controller";
|
||||
|
||||
case 0x04: {
|
||||
switch(progif) {
|
||||
case 0x00: return "Generic Gameport Controller";
|
||||
case 0x10: return "Extended Gameport Controller";
|
||||
default: return "Gameport Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x80: return "Other";
|
||||
|
||||
default: return "Unknown Input Device Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x0A: {
|
||||
switch(subclass) {
|
||||
case 0x00: return "Generic Docking Station";
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Docking Station";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x0B: {
|
||||
switch(subclass) {
|
||||
case 0x00: return "386 Processor";
|
||||
case 0x01: return "486 Processor";
|
||||
case 0x02: return "Pentium Processor";
|
||||
case 0x03: return "Pentium Pro Processor";
|
||||
case 0x10: return "Alpha Processor";
|
||||
case 0x20: return "PowerPC Processor";
|
||||
case 0x30: return "MIPS Processor";
|
||||
case 0x40: return "Co-Processor";
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Processor";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x0C: {
|
||||
switch(subclass) {
|
||||
case 0x00: {
|
||||
switch(progif) {
|
||||
case 0x00: return "Generic Firewire Controller";
|
||||
case 0x10: return "OHCI Firewire Controller";
|
||||
default: return "FireWire (IEEE 1394) Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x01: return "ACCESS Bus";
|
||||
case 0x02: return "SSA";
|
||||
|
||||
case 0x03: {
|
||||
switch(progif) {
|
||||
case 0x00: return "UHCI USB Controller";
|
||||
case 0x10: return "OHCI USB Controller";
|
||||
case 0x20: return "EHCI USB (2.0) Controller";
|
||||
case 0x30: return "XHCI USB (3.0) Controller";
|
||||
case 0x80: return "Unspecified USB Controller";
|
||||
case 0xFE: return "USB Device (NOT a Controller)";
|
||||
default: return "USB Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x04: return "Fibre Channel";
|
||||
case 0x05: return "SMBus";
|
||||
case 0x06: return "InfiniBand";
|
||||
|
||||
case 0x07: {
|
||||
switch(progif) {
|
||||
case 0x00: return "SMIC IPMI Interface";
|
||||
case 0x01: return "Keyboard Controller-Style IPMI Interface";
|
||||
case 0x02: return "Block Transfer IPMI Interface";
|
||||
default: return "IPMI Interface";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x08: return "SERCOS Interface (IEC 61491)";
|
||||
case 0x09: return "CANbus";
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Serial Bus Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x0D: {
|
||||
switch(subclass) {
|
||||
case 0x00: return "IRDA Compatible Controller";
|
||||
case 0x01: return "Consumer IR Controller";
|
||||
case 0x10: return "RF Controller";
|
||||
case 0x11: return "Bluetooth Controller";
|
||||
case 0x12: return "Broadband Controller";
|
||||
case 0x20: return "Ethernet Controller (802.1a)";
|
||||
case 0x21: return "Ethernet Controller (802.1b)";
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Wireless Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x0E: {
|
||||
switch(subclass) {
|
||||
case 0x00: return "I20";
|
||||
default: return "Unknown Intelligent Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x0F: {
|
||||
switch(subclass) {
|
||||
case 0x01: return "Satellite TV Controller";
|
||||
case 0x02: return "Satellite Audio Controller";
|
||||
case 0x03: return "Satellite Voice Controller";
|
||||
case 0x04: return "Satellite Data Controller";
|
||||
default: return "Unknown Satelllite Comms Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x10: {
|
||||
switch(subclass) {
|
||||
case 0x00: return "Network & Computing Codec";
|
||||
case 0x10: return "Entertainment Codec";
|
||||
case 0x80: return "Other Codec";
|
||||
default: return "Unknown Encryption Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x11: {
|
||||
switch(subclass) {
|
||||
case 0x00: return "DPIO Modules";
|
||||
case 0x01: return "Performance Counters";
|
||||
case 0x10: return "Communication Synchronizer";
|
||||
case 0x20: return "Signal Processing Management";
|
||||
case 0x80: return "Other";
|
||||
default: return "Unknown Signal Processing Controller";
|
||||
}
|
||||
}
|
||||
|
||||
case 0x12: return "Processing Accelerator";
|
||||
|
||||
case 0x13: return "Non-Essential Instrumentation";
|
||||
|
||||
case 0x14:
|
||||
case 0x41: return "Reserved";
|
||||
|
||||
case 0x40: return "Co-Processor";
|
||||
|
||||
case 0xFF: return "Unassigned Class";
|
||||
|
||||
}
|
||||
|
||||
return "Invalid Device!";
|
||||
}
|
||||
|
||||
const char* PCIGetClassName(uint8_t devclass) {
|
||||
|
||||
switch(devclass) {
|
||||
case 0x00: return "Unclassified";
|
||||
case 0x01: return "Mass Storage Controller";
|
||||
case 0x02: return "Network Controller";
|
||||
case 0x03: return "Display Controller";
|
||||
case 0x04: return "Multimedia Controller";
|
||||
case 0x05: return "Memory Controller";
|
||||
case 0x06: return "Bridge Device";
|
||||
case 0x07: return "Simple Communication Controller";
|
||||
case 0x08: return "Base System Peripheral";
|
||||
case 0x09: return "Input Device Controller";
|
||||
case 0x0A: return "Docking Station";
|
||||
case 0x0B: return "Processor";
|
||||
case 0x0C: return "Serial Bus Controller";
|
||||
case 0x0D: return "Wireless Controller";
|
||||
case 0x0E: return "Intelligent Controller";
|
||||
case 0x0F: return "Satellite Communication Controller";
|
||||
case 0x10: return "Encryption Controller";
|
||||
case 0x11: return "Signal Processing Controller";
|
||||
case 0x12: return "Processing Accelerator";
|
||||
case 0x13: return "Non-Essential Instrumentation";
|
||||
case 0x14: return "Reserved";
|
||||
case 0x40: return "Co-Processor";
|
||||
case 0x41: return "Reserved";
|
||||
case 0xFF: return "Unassigned Class";
|
||||
default: return "Unknown Category";
|
||||
}
|
||||
|
||||
return "Invalid device!";
|
||||
}
|
|
@ -1,5 +1,17 @@
|
|||
#include <kernel/chroma.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
/* 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..)
|
||||
*
|
||||
* Additionally, there are wrapper functions for MMIO accesses.
|
||||
*
|
||||
*/
|
||||
|
||||
uint32_t ReadPort(uint16_t Port, int Length) {
|
||||
uint32_t Data = 0;
|
||||
uint16_t Data16 = 0;
|
||||
|
@ -32,6 +44,31 @@ uint32_t WritePort(uint16_t Port, uint32_t Data, int Length) {
|
|||
return Data;
|
||||
}
|
||||
|
||||
size_t ReadMMIO(size_t Address, int Length) {
|
||||
if (Length == 1) {
|
||||
return *((volatile uint8_t*)(Address));
|
||||
} else if (Length == 2) {
|
||||
return *((volatile uint16_t*)(Address));
|
||||
} else if (Length == 4) {
|
||||
return *((volatile uint32_t*)(Address));
|
||||
} else {
|
||||
return *((volatile size_t*)(Address));
|
||||
}
|
||||
}
|
||||
|
||||
void WriteMMIO(size_t Address, size_t Data, int Length) {
|
||||
if(Length == 1) {
|
||||
(*((volatile uint8_t*)(Address))) = ((uint8_t) Data);
|
||||
} else if (Length == 2) {
|
||||
(*((volatile uint16_t*)(Address))) = ((uint16_t) Data);
|
||||
} else if (Length == 4) {
|
||||
(*((volatile uint32_t*)(Address))) = ((uint32_t) Data);
|
||||
} else {
|
||||
(*((volatile uint8_t*)(Address))) = (Data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t ReadModelSpecificRegister(size_t MSR) {
|
||||
size_t RegHigh = 0, RegLow = 0;
|
||||
|
||||
|
@ -41,10 +78,9 @@ size_t ReadModelSpecificRegister(size_t MSR) {
|
|||
}
|
||||
|
||||
size_t WriteModelSpecificRegister(size_t MSR, size_t Data) {
|
||||
size_t DataLow = 0, DataHigh = 0;
|
||||
|
||||
DataLow = ((uint32_t*) &Data)[0];
|
||||
DataHigh = ((uint32_t*) &Data)[1];
|
||||
const size_t DataLow = Data & 0x00000000ffffffff;
|
||||
const size_t DataHigh = (Data & 0xffffffff00000000) >> 32;
|
||||
|
||||
__asm__ __volatile__ ("wrmsr" : : "a" (DataLow), "c" (MSR), "d" (DataHigh) :);
|
||||
|
||||
|
@ -104,6 +140,8 @@ size_t ReadControlRegister(int CRX) {
|
|||
__asm__ __volatile__ ("pushfq\n\t" "popq %[dest]" : [dest] "=r" (Data) : :);
|
||||
break;
|
||||
default:
|
||||
SerialPrintf("invalid crx read %x\r\n",CRX);
|
||||
Data = 0xdeadbeef;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -148,9 +186,12 @@ size_t ReadExtendedControlRegister(size_t XCRX) {
|
|||
return (RegHigh << 32 | RegLow);
|
||||
}
|
||||
|
||||
//TODO: make this just have an assert as returning data for a write to catch
|
||||
// errors that shoudlunt really happen doesent make alot of sense
|
||||
size_t WriteExtendedControlRegister(size_t XCRX, size_t Data){
|
||||
|
||||
__asm__ __volatile__("xsetbv" : : "a" ( ((uint32_t*) &Data)[0]), "c" (XCRX), "d" ( ((uint32_t*) &Data)[1] ) :);
|
||||
uint32_t DataLow = Data & 0x00000000ffffffff;
|
||||
uint32_t DataHigh = (Data & 0xffffffff00000000) >> 32;
|
||||
__asm__ __volatile__("xsetbv" : : "a" (DataLow), "c" (XCRX), "d" (DataHigh) :);
|
||||
return Data;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
#include <kernel/chroma.h>
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
/* This file provides functions related to the Serial port.
|
||||
* Through this file, you send and receive text and extra debugging information if available.
|
||||
*/
|
||||
|
||||
#define SERIAL_DATA(base) (base)
|
||||
#define SERIAL_DLAB(base) (base + 1)
|
||||
|
|
|
@ -1,6 +1,24 @@
|
|||
#include <kernel/chroma.h>
|
||||
#include <kernel/video/bitmapfont.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
/* This file contains all of the draw-to-screen routines.
|
||||
* It (currently; 23/08/20) handles the keyboard input test routine,
|
||||
* moving the current character back and forth, up and down.
|
||||
*
|
||||
* It also handles filling the screen with color in the case of an event,
|
||||
* and will be hooked into Vector and Shape of lainlib to eventually provide
|
||||
* geometry.
|
||||
*
|
||||
* It will also eventually be plugged into stb_image to provide a way to draw PNGs
|
||||
* and JPGs from disk.
|
||||
*/
|
||||
|
||||
|
||||
#define FONT bitfont_latin
|
||||
|
||||
static size_t strlen(const char* String) {
|
||||
|
@ -39,14 +57,14 @@ void InitPrint() {
|
|||
PrintInfo.charScale = 2;
|
||||
|
||||
PrintInfo.charPosX = 0;
|
||||
PrintInfo.charPosY = 0;
|
||||
PrintInfo.charPosY = 1;
|
||||
|
||||
PrintInfo.scrlMode = 0;
|
||||
|
||||
PrintInfo.charsPerRow = bootldr.fb_width / (PrintInfo.charScale * PrintInfo.charWidth) - 5;
|
||||
PrintInfo.rowsPerScrn = bootldr.fb_height / (PrintInfo.charScale * PrintInfo.charHeight);
|
||||
SerialPrintf("A single character is %ux%u pixels.\r\n", PrintInfo.charScale * PrintInfo.charWidth, PrintInfo.charScale * PrintInfo.charHeight);
|
||||
SerialPrintf("The screen is %ux%u, meaning you can fit %ux%u characters on screen.\r\n", bootldr.fb_width, bootldr.fb_height, PrintInfo.charsPerRow, PrintInfo.rowsPerScrn);
|
||||
SerialPrintf("[Print] A single character is %ux%u pixels.\r\n", PrintInfo.charScale * PrintInfo.charWidth, PrintInfo.charScale * PrintInfo.charHeight);
|
||||
SerialPrintf("[Print] The screen is %ux%u, meaning you can fit %ux%u characters on screen.\r\n", bootldr.fb_width, bootldr.fb_height, PrintInfo.charsPerRow, PrintInfo.rowsPerScrn);
|
||||
|
||||
}
|
||||
|
||||
|
@ -68,23 +86,23 @@ static void DrawChar(const char character, size_t x, size_t y) {
|
|||
X++;
|
||||
}
|
||||
|
||||
if((FONT[character][Row * Y + X] >> (Bit & 0x7)) & 1) {
|
||||
for(uint32_t ScaleY = 0; ScaleY < PrintInfo.charScale; ScaleY++) {
|
||||
for(uint32_t ScaleX = 0; ScaleX < PrintInfo.charScale; ScaleX++) {
|
||||
|
||||
size_t offset = ((y * bootldr.fb_width + x) +
|
||||
PrintInfo.charScale * (Row * bootldr.fb_width + Bit) +
|
||||
(ScaleY * bootldr.fb_width + ScaleX) +
|
||||
PrintInfo.charScale * 1 * PrintInfo.charWidth) - 10;
|
||||
|
||||
// This one is crazy. Stick with me.
|
||||
*(uint32_t* )(&fb + offset * 4)// Offset from the framebuffer, find the pixel..
|
||||
// and find which column we need to be in. Multiply by 4 to navigate the 4bpp array,
|
||||
= PrintInfo.charFGColor; // And set the color of the pixel.
|
||||
|
||||
if((FONT[(int)character][Row * Y + X] >> (Bit & 0x7)) & 1) { // Check the bit in the bitmap, if it's solid..
|
||||
for(uint32_t ScaleY = 0; ScaleY < PrintInfo.charScale; ScaleY++) { // Take care of the scale height
|
||||
for(uint32_t ScaleX = 0; ScaleX < PrintInfo.charScale; ScaleX++) { // And the scale width
|
||||
|
||||
size_t offset = ((y * bootldr.fb_width + x) + // Calculate the offset from the framebuffer
|
||||
PrintInfo.charScale * (Row * bootldr.fb_width + Bit) + // With the appropriate scale
|
||||
(ScaleY * bootldr.fb_width + ScaleX) + // In X and Y
|
||||
PrintInfo.charScale * 1 * PrintInfo.charWidth) - 10; // With some offset to start at 0
|
||||
|
||||
*(uint32_t* )(&fb + offset * 4) // And use it to set the correct pixel on the screen
|
||||
= PrintInfo.charFGColor; // In the set foreground color
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We need to draw the pixel transparently..
|
||||
// We need to draw the pixel transparently, using the background color
|
||||
for(uint32_t ScaleY = 0; ScaleY < PrintInfo.charScale; ScaleY++) {
|
||||
for(uint32_t ScaleX = 0; ScaleX < PrintInfo.charScale; ScaleX++) {
|
||||
if(PrintInfo.charHLColor != 0xFF000000) {
|
||||
|
@ -93,7 +111,7 @@ static void DrawChar(const char character, size_t x, size_t y) {
|
|||
(ScaleY * bootldr.fb_width + ScaleX) +
|
||||
PrintInfo.charScale * 1 * PrintInfo.charWidth) - 10;
|
||||
if( y == 0 && x == 0){
|
||||
SerialPrintf("Writing first pixel at %x\r\n", offset);
|
||||
//SerialPrintf("Writing first pixel at %x\r\n", offset);
|
||||
}
|
||||
|
||||
*(uint32_t*)(&fb + offset *4)
|
||||
|
@ -190,8 +208,8 @@ void DrawPixel(uint32_t x, uint32_t y, uint32_t color) {
|
|||
} else if(y > bootldr.fb_height) {
|
||||
DrawPixel(x, y - bootldr.fb_height, color);
|
||||
} else {
|
||||
*((uint32_t*) (&fb + (y * bootldr.fb_scanline + x) * 4)) = color;
|
||||
SerialPrintf("Drawing a pixel at %d, %d with color 0x%x\r\n", x, y, color);
|
||||
*((uint32_t*) (&fb + (y * bootldr.fb_width + x) * 4)) = color;
|
||||
//SerialPrintf("Drawing a pixel at %d, %d with color 0x%x\r\n", x, y, color);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -226,6 +244,21 @@ static void ProgressCursor() {
|
|||
ProgressCursorS(1);
|
||||
}
|
||||
|
||||
static void Backspace() {
|
||||
|
||||
SerialPrintf("Backspacing from %d to %d\r\n", PrintInfo.charPosX, PrintInfo.charPosX - 1);
|
||||
if(PrintInfo.charPosX - 1 <= 0) {
|
||||
if(PrintInfo.charPosY - 1 <= 0) {
|
||||
PrintInfo.charPosY = 0;
|
||||
} else {
|
||||
PrintInfo.charPosY--;
|
||||
}
|
||||
PrintInfo.charPosX = 0;
|
||||
} else {
|
||||
PrintInfo.charPosX -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
void WriteChar(const char character) {
|
||||
|
||||
//size_t y = PrintInfo.charPos / RowsWidth * (PrintInfo.charScale * PrintInfo.charHeight);
|
||||
|
@ -233,19 +266,15 @@ void WriteChar(const char character) {
|
|||
|
||||
switch(character) {
|
||||
case '\b':
|
||||
if(PrintInfo.charPosX - 1 == 0) {
|
||||
if(PrintInfo.charPosY - 1 == 0) {
|
||||
PrintInfo.charPosY = 0;
|
||||
} else {
|
||||
PrintInfo.charPosY--;
|
||||
}
|
||||
} else {
|
||||
PrintInfo.charPosX = 0;
|
||||
}
|
||||
Backspace();
|
||||
DrawChar((char) 32, PrintInfo.charPosX, PrintInfo.charPosY);
|
||||
break;
|
||||
case '\n':
|
||||
Newline();
|
||||
break;
|
||||
case '\t':
|
||||
ProgressCursorS(4);
|
||||
break;
|
||||
default:
|
||||
DrawChar(character, PrintInfo.charPosX, PrintInfo.charPosY);
|
||||
|
||||
|
@ -255,10 +284,48 @@ void WriteChar(const char character) {
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void WriteString(const char* string) {
|
||||
for(int i = 0; i < strlen(string); i++) {
|
||||
for(unsigned int i = 0; i < strlen(string); i++) {
|
||||
WriteChar(string[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteStringWithFont(const char *inChar)
|
||||
{
|
||||
psf_t *font = (psf_t*) &_binary_font_psf_start;
|
||||
|
||||
unsigned int drawX, drawY, kx = 0, fontLine, bitMask, offset;
|
||||
|
||||
const unsigned int bytesPerLine = ( font -> glyphWidth + 7 ) / 8;
|
||||
|
||||
while(*inChar) {
|
||||
unsigned char *glyph =
|
||||
(unsigned char*) &_binary_font_psf_start
|
||||
+ font->headerSize
|
||||
+ (*inChar > 0 && *inChar < (int)font->numGlyphs ? *inChar : 0) *
|
||||
font->glyphSize;
|
||||
|
||||
|
||||
offset = (kx * (font->glyphWidth + 1) * 4);
|
||||
|
||||
for( drawY = 0; drawY < font->glyphHeight ; drawY++) {
|
||||
fontLine = offset;
|
||||
bitMask = 1 << (font->glyphWidth - 1);
|
||||
|
||||
for( drawX = 0; drawX < font->glyphWidth; drawX++) {
|
||||
|
||||
*((uint32_t*)((uint64_t) &fb + fontLine)) =
|
||||
((int) *glyph) & (bitMask) ? 0xFFFFFF : 0;
|
||||
bitMask >>= 1;
|
||||
fontLine += 4;
|
||||
|
||||
}
|
||||
|
||||
*((uint32_t*)((uint64_t) &fb + fontLine)) = 0;
|
||||
glyph += bytesPerLine;
|
||||
offset += bootldr.fb_scanline;
|
||||
}
|
||||
|
||||
inChar++; kx++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,18 @@
|
|||
#include <kernel/chroma.h>
|
||||
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
/* This file contains all of the String / Print related functions
|
||||
* that are required by the core of the kernel.
|
||||
*
|
||||
* There will be a proper C++ std::string implementation in lainlib.
|
||||
*
|
||||
* This file also provides SerialPrintf.
|
||||
*/
|
||||
|
||||
static size_t strlen(const char* String) {
|
||||
size_t Len = 0;
|
||||
while(String[Len] != '\0') {
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <kernel/video/tty.h>
|
||||
|
||||
#include <kernel/video/vga-textmode.h>
|
||||
|
||||
static const size_t TERM_WIDTH = 80;
|
||||
static const size_t TERM_HEIGHT = 25;
|
||||
|
||||
size_t TERM_ROW;
|
||||
size_t TERM_COL;
|
||||
uint8_t TERM_COLOR;
|
||||
|
||||
uint16_t* TERM_BUFFER;
|
||||
|
||||
void Term_Init(void) {
|
||||
|
||||
TERM_ROW = 0;
|
||||
TERM_COL = 0;
|
||||
TERM_COLOR = VGACharColor(VGA_COLOR_LIGHTGREY, VGA_COLOR_BLACK);
|
||||
|
||||
TERM_BUFFER = (uint16_t*) 0xB8000;
|
||||
|
||||
for(size_t y = 0; y < TERM_HEIGHT; y++) {
|
||||
for(size_t x = 0; x < TERM_WIDTH; x++) {
|
||||
const size_t index = y * TERM_WIDTH + x;
|
||||
TERM_BUFFER[index] = VGAChar(' ', TERM_COLOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Term_SetColor(uint8_t color) {
|
||||
TERM_COLOR = color;
|
||||
}
|
||||
|
||||
void Term_PutVGAChar(char c, uint8_t color, size_t x, size_t y) {
|
||||
const size_t index = y * TERM_WIDTH + x;
|
||||
TERM_BUFFER[index] = VGAChar(c, color);
|
||||
}
|
||||
|
||||
void Term_PutChar(char c) {
|
||||
Term_PutVGAChar(c, TERM_COLOR, TERM_COL, TERM_ROW);
|
||||
|
||||
if(++TERM_COL == TERM_WIDTH) {
|
||||
TERM_COL = 0;
|
||||
if(++TERM_ROW == TERM_HEIGHT)
|
||||
TERM_ROW = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Term_Write(const char* str, size_t len) {
|
||||
for(size_t i = 0; i < len; i++)
|
||||
Term_PutChar(str[i]);
|
||||
}
|
||||
|
||||
void Term_WriteString(const char* str) {
|
||||
Term_Write(str, strlen(str));
|
||||
}
|
||||
|
13
global/crt0.c
Normal file
13
global/crt0.c
Normal file
|
@ -0,0 +1,13 @@
|
|||
|
||||
extern void Exit(int code);
|
||||
extern int Main();
|
||||
|
||||
extern void _init();
|
||||
|
||||
void _start() {
|
||||
_init();
|
||||
unsigned long long zero = 0;
|
||||
__asm__ __volatile__("movq %%rbp, %[input]" : : [input] "m" (zero) : );
|
||||
int ex = Main();
|
||||
Exit(ex);
|
||||
}
|
BIN
global/crt0.o
Normal file
BIN
global/crt0.o
Normal file
Binary file not shown.
BIN
global/crt0.old
Normal file
BIN
global/crt0.old
Normal file
Binary file not shown.
22
global/crt0.s
Normal file
22
global/crt0.s
Normal file
|
@ -0,0 +1,22 @@
|
|||
.section .text
|
||||
.global _start
|
||||
.global _init
|
||||
.global Main
|
||||
.global Exit
|
||||
.type _start, @function
|
||||
_start:
|
||||
push %rbp
|
||||
movq %rsp, %rbp
|
||||
sub $0x10, %rsp
|
||||
|
||||
xor %rax, %rax
|
||||
call _init
|
||||
|
||||
xor %rbp, %rbp
|
||||
|
||||
xor %rax, %rax
|
||||
call Main
|
||||
|
||||
movq %rax, %rdi
|
||||
call Exit
|
||||
|
BIN
global/crtbegin.o
Normal file
BIN
global/crtbegin.o
Normal file
Binary file not shown.
BIN
global/crtend.o
Normal file
BIN
global/crtend.o
Normal file
Binary file not shown.
BIN
global/crti.o
Normal file
BIN
global/crti.o
Normal file
Binary file not shown.
13
global/crti.s
Normal file
13
global/crti.s
Normal file
|
@ -0,0 +1,13 @@
|
|||
.section .init
|
||||
.global _init
|
||||
.type _init, @function
|
||||
_init:
|
||||
push %rbp
|
||||
movq %rsp, %rbp
|
||||
|
||||
.section .fini
|
||||
.global _fini
|
||||
.type _fini, @function
|
||||
_fini:
|
||||
push %rbp
|
||||
movq %rsp, %rbp
|
BIN
global/crtn.o
Normal file
BIN
global/crtn.o
Normal file
Binary file not shown.
9
global/crtn.s
Normal file
9
global/crtn.s
Normal file
|
@ -0,0 +1,9 @@
|
|||
.section .init
|
||||
|
||||
popq %rbp
|
||||
ret
|
||||
|
||||
.section .fini
|
||||
|
||||
popq %rbp
|
||||
ret
|
1
img/boot/config
Normal file
1
img/boot/config
Normal file
|
@ -0,0 +1 @@
|
|||
kernel=exe
|
BIN
img/boot/exe
Normal file
BIN
img/boot/exe
Normal file
Binary file not shown.
|
@ -1,4 +0,0 @@
|
|||
menuentry "Sync" {
|
||||
multiboot /boot/bootloader
|
||||
module /boot/initrd
|
||||
}
|
17
linker.ld
17
linker.ld
|
@ -1,4 +1,5 @@
|
|||
|
||||
memstart = 0x14400;
|
||||
mmio = 0xfffffffff8000000;
|
||||
fb = 0xfffffffffc000000;
|
||||
|
||||
|
@ -9,14 +10,18 @@ PHDRS
|
|||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0xffffffffffe00000;
|
||||
. = 0xFFFFFFFFFFE00000;
|
||||
LoadAddr = .;
|
||||
bootldr = .; . += 4096;
|
||||
environment = .; . += 4096;
|
||||
|
||||
|
||||
.text : {
|
||||
|
||||
_kernel_text_start = .;
|
||||
KEEP(*(.text.boot)) *(.text .text.*)
|
||||
_kernel_rodata_start = .;
|
||||
*(.rodata .rodata.*)
|
||||
_kernel_data_start = .;
|
||||
*(.data .data.*)
|
||||
} :boot
|
||||
.bss (NOLOAD) : {
|
||||
|
@ -25,7 +30,13 @@ SECTIONS
|
|||
*(COMMON)
|
||||
} :boot
|
||||
|
||||
/DISCARD/ : { *(.eh_frame) *(.comment) }
|
||||
.eh_frame_hdr : {
|
||||
*(.eh_frame_hdr)
|
||||
*(.eh_frame)
|
||||
*(.gcc_except_table)
|
||||
} :boot
|
||||
|
||||
/DISCARD/ : {*(.comment) }
|
||||
|
||||
end = .;
|
||||
}
|
||||
|
|
BIN
mkbootimg.exe
Normal file
BIN
mkbootimg.exe
Normal file
Binary file not shown.
18
post.sh
Normal file
18
post.sh
Normal file
|
@ -0,0 +1,18 @@
|
|||
cp kernel img/boot/exe
|
||||
echo "Performing post-build actions:"
|
||||
echo "Creating raw img file for writing to a drive:"
|
||||
./mkbootimg.exe chroma.json chroma.img # for linux remove the .exe
|
||||
|
||||
echo "Checking for VirtualBox management tools"
|
||||
if [ -x "$(command -v VBoxManage)" ]; then
|
||||
echo " VBoxManage found.. integrating."
|
||||
echo " Clearing VirtualBox cache:"
|
||||
VBoxManage storageattach Chroma --port 0 --storagectl AHCI --medium none # removing a drive in virtualbox = attaching nothing
|
||||
VBoxManage closemedium disk --delete "`pwd`/chroma.vdi" # remove the existing .vdi image from the registry so we can overwrite it
|
||||
echo " Creating new VirtualBox VDI image:"
|
||||
VBoxManage convertfromraw chroma.img --format VDI chroma.vdi # generate the new vdi from the img
|
||||
echo " Attaching image to the VM."
|
||||
VBoxManage storageattach Chroma --port 0 --storagectl AHCI --type hdd --medium "`pwd`/chroma.vdi" # attach the new vdi to the vm so we can run it
|
||||
echo " VirtualBox integrations complete. You may execute run.sh to run your VirtualBox VM."
|
||||
fi
|
||||
|
3
pre.sh
Normal file
3
pre.sh
Normal file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
x86_64-elf-ld -r -b binary -o font.o font.psf
|
||||
cmake -G"Unix Makefiles" .
|
Loading…
Reference in New Issue
Block a user