Compare commits

..

51 Commits

Author SHA1 Message Date
c94a469baf
Fix embarassing bug in paging impl that caused crashes.. 2020-11-26 04:03:44 +00:00
868eed64ef
Add better output to GPF handler 2020-11-26 04:03:43 +00:00
fc3efd7c68
Fix ordering of INTERRUPT_FRAME in header 2020-11-26 04:03:43 +00:00
4a86fbd114
Add debugging symbols to output.. 2020-11-26 04:03:43 +00:00
75f44b0514
Add a memstart symbol to the linkerscript
This replaces the old way of appending the memory bitmap to the end of the kernel, which started causing problems with expansion..

I hardcoded the value to 0x1440, which is the start of the first FREE block of memory given to SeaBIOS in QEMU. This should be changed in the future..
2020-11-26 04:03:43 +00:00
bd8213356e
Adjust the crt0 file to insert a null stack frame before calling the kernel. Provides a solid base for the stack unwinding. 2020-11-26 04:03:43 +00:00
9b0aceac55
Minimise printing in physmem - turns out serial output is SLOW. 2020-11-26 04:03:43 +00:00
c5be09fc5d
Adjust formatting in paging that i missed 2020-11-26 04:03:43 +00:00
429fa55a73
Flailing with Invalid Opcode.. 2020-11-26 04:03:43 +00:00
acfe8c2666
Add stack unwinding to critical ISRs.
Also adjust the formatting of serial prints..
2020-11-26 04:03:43 +00:00
9646eac29e
Add basic stack unwinding functionality 2020-11-26 04:03:42 +00:00
0c0f52dbb9
Add opcode handling.. started debugging memory management. 2020-11-26 04:03:42 +00:00
fe15a79fc3
Fix building on Windows by dpeter99
Fix CMake invocation that confused it into using Visual Studio build tools..
2020-11-26 04:03:42 +00:00
Curle
b4121964c5
Fix pre.sh
I can't spell!
2020-11-26 04:03:42 +00:00
Curle
649c475f5d
Comment out the post-build script.
More preparation for build server.
2020-11-26 04:03:42 +00:00
Curle
caca55de6e
Update pre.sh with explicit cross-linker
Just to help automating the build process.
2020-11-26 04:03:42 +00:00
ba9e97a46a
Fix typo in post-build script 2020-11-26 04:03:42 +00:00
428dfce021
Remove large image file, add extra stuff to the gitignore 2020-11-26 04:03:42 +00:00
19c2ba6b72
Move toolchain to VirtualBox. qemu is too restrictive :/ 2020-11-26 04:03:42 +00:00
b86d8af721
Refactor CPU preparation into cpu.c, work on enabling AVX and SSE 2020-11-26 04:03:42 +00:00
0ff9705fc8
Poke paging. Still a little strange. Removed excess debugging. 2020-11-26 04:03:41 +00:00
Curle
15165b1562
We have virtual memory management!
Even if it's a little broken...
2020-11-26 04:03:41 +00:00
8665e4c634
Add defs required for kernel to compile 2020-11-26 04:03:41 +00:00
25d8f97693
Add symbols to linker script for page table generation 2020-11-26 04:03:41 +00:00
bd5389f1fc
Add new files to CMake 2020-11-26 04:03:41 +00:00
bade5bde21
Change bracketing to make gcc -Werror happy 2020-11-26 04:03:41 +00:00
9c65d7d19f
Add MMIO read/write functions. 2020-11-26 04:03:41 +00:00
2e662e3717
Add missing invlpg function to cpu.c 2020-11-26 04:03:41 +00:00
6faadded24
Rework memory management. 2020-11-26 04:03:41 +00:00
be4ee498c4
Add BXRC file for Bochs support. 2020-11-26 04:03:40 +00:00
a915465fc1
Add startings of new kernel-side library
Lainlib is libk. It is separate from Helix, which will become the 3D engine common to the kernel and the userspace.
2020-11-26 04:03:40 +00:00
61dbcc0dec
Remove dead files 2020-11-26 04:03:40 +00:00
86778f1518
Remove ISO components 2020-11-26 04:03:40 +00:00
Curle
8a3e80213f
Update README for new build process 2020-11-26 04:03:40 +00:00
b3e3f153b5
Add support for C++
This was a doozy. I had to recompile gcc with a custom target to get it to output the CRT{BEGIN/END}.o files with proper 64 bit relocations.

The CMakeLists.txt file was also edited to allow these files to be linked (thereby actually adding the support) as well as to automatically create the boot image upon build.
2020-11-26 04:03:40 +00:00
aa9600b2b0
Add PCI Enumeration to boot output 2020-11-26 04:03:40 +00:00
e8214d5650
Add basic PCI support.
Currently can only enumerate the PCI bus with a basic process, and retrieve basic details on every valid device.
2020-11-26 04:03:39 +00:00
1f514e9cb2
Refresh all files with project headers and documentation 2020-11-26 04:03:39 +00:00
ce85ddbd1c
Removed unnecessary VGA textmode header 2020-11-26 04:03:39 +00:00
f6e2f3ac5d
Removed unnecessary ISO files 2020-11-26 04:03:39 +00:00
7e7a76a5b9
Add Windows version of mkbootimg for platform agnosticity 2020-11-26 04:03:38 +00:00
c992564365
Move from CD-ROM images to Hard Disk images.
This involves a new img/ folder, a new program called mkbootimg, the accompanying chroma.json file that instructs mkbootimg how to create the image.

An extra Powershell script is included for brevity.
2020-11-26 04:03:38 +00:00
Curle
83aef00afa
Create README.md 2020-11-26 04:03:29 +00:00
af77c415ac
Add shebang lines to scripts 2020-11-26 04:03:29 +00:00
destoer
7603180791
fix compilier warnings 2020-11-26 04:03:29 +00:00
destoer
65aa630701
remove junk files 2020-11-26 04:03:29 +00:00
destoer
2e78df807b
remove makefile 2020-11-26 04:03:29 +00:00
destoer
7e9d2ec0f8
removed junk files 2020-11-26 04:03:28 +00:00
54489cdc75
Added Windows build script 2020-11-26 04:03:28 +00:00
destoer
f192162c54
added build scripts 2020-11-26 04:03:28 +00:00
74b44aab7f
Add missing files from git migration 2020-11-26 04:02:56 +00:00
61 changed files with 4137 additions and 496 deletions

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
*.o
*.elf
*.img
*.vdi
Makefile
CMakeFiles
CMakeCache.txt

58
CMakeLists.txt Normal file
View 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
View 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
View 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

19
chroma.json Normal file
View File

@ -0,0 +1,19 @@
{
"disksize": 80,
"config": "img/boot/config",
"initrd": {
"type": "tar",
"directory": "img/boot"
},
"partitions": [
{
"type": "boot",
"size": 4
},
{
"type": "Microsoft basic data",
"size": 76,
"name": "Chroma Data"
}
]
}

View File

@ -2,6 +2,11 @@
#ifndef _BOOTLOADER_H_
#define _BOOTLOADER_H_
/************************
*** Team Kitty, 2020 ***
*** Chroma ***
***********************/
#ifdef __cplusplus
extern "C" {
#endif

View File

@ -1,9 +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>
@ -12,6 +17,11 @@
#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;
@ -19,6 +29,8 @@ extern unsigned char* environment;
extern uint8_t fb;
extern volatile unsigned char _binary_font_psf_start;
extern address_space_t KernelAddressSpace;
typedef struct {
uint32_t magic;
uint32_t version;
@ -41,6 +53,9 @@ 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);
@ -52,3 +67,9 @@ void InitPrint();
void SetupInitialGDT();
void SetupIDT();
int Main();
void Exit();
void SomethingWentWrong(const char* Message);

View File

@ -1,6 +1,11 @@
#include <stdint.h>
#include <stddef.h>
/************************
*** Team Kitty, 2020 ***
*** Chroma ***
***********************/
typedef struct __attribute__((packed)) {
uint16_t LowLimit;
uint16_t BaseLow;

View File

@ -0,0 +1,12 @@
#pragma once
/************************
*** Team Kitty, 2020 ***
*** Chroma ***
***********************/
#include <stddef.h>
#include <stdint.h>
uint8_t HeapEnabled = 0;

View File

@ -1,49 +1,20 @@
#pragma once
#include <stddef.h>
static 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"
};
/************************
*** 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)) {
@ -55,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);

View File

@ -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);

View File

@ -1,6 +1,17 @@
#include <stddef.h>
#include <stdint.h>
#include <kernel/system/interrupts.h>
#include <lainlib/lainlib.h>
/************************
*** Team Kitty, 2020 ***
*** Chroma ***
***********************/
/************************************************
* 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
@ -11,6 +22,20 @@
#define READ_BIT(i) ((OFFSET_BIT(i) >> (i % PAGES_PER_BUCKET)) & 0x1)
#define GET_BUCKET32(i) (*((uint32_t*) (&Memory[i / 32])))
#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)
@ -28,20 +53,208 @@
#define ERR_INST 0x10
/*
* 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 KERNEL_PHYSICAL 0x0000000000008000ull // Physical location of the kernel
#define KERNEL_PHYSICAL_2 0x000000000011C000ull // For some reason the kernel is split in half
#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 ListMemoryMap();
void InitMemoryManager();
void InitMemoryManager();
size_t AllocateFrame();
void AddRangeToPhysMem(directptr_t Base, size_t Size);
void FreeFrame(size_t FrameNumber);
directptr_t PhysAllocateLowMem(size_t Size);
size_t SeekFrame();
directptr_t PhysAllocateMem(size_t Size);
void MemoryTest();
directptr_t PhysAllocateZeroMem(size_t Size);
void InitPaging();
directptr_t PhysAllocateLowZeroMem(size_t Size);
void PageFaultHandler(INTERRUPT_FRAME frame);
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);

View 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;

View 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);

View File

@ -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

View 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_

View 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>

View 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

View 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;

View 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);

View 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);

View File

@ -1,14 +1,32 @@
#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.
*/
size_t KernelAddr = (size_t) &LoadAddr;
size_t KernelEnd = (size_t) &end;
address_space_t KernelAddressSpace;
void _start(void) {
int Main(void) {
KernelAddressSpace = (address_space_t) {0};
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("\r\nBooting Chroma..\r\n");
SerialPrintf("Kernel loaded at 0x%p, ends at 0x%p, is %d bytes long.\r\n", KernelAddr, KernelEnd, KernelEnd - KernelAddr);
SerialPrintf("[ boot] The bootloader has put the paging tables at 0x%p.\r\n", ReadControlRegister(3));
//TraversePageTables();
ListMemoryMap();
@ -16,16 +34,29 @@ void _start(void) {
WriteStringWithFont("Initty Testing");
SetupInitialGDT();
SetupIDT();
InitInterrupts();
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);
}

View 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;
}

View 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;
}

View 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
View 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) {
}

View File

@ -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);

View File

@ -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;

View File

@ -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,13 +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 */
SerialPrintf("%s exception!\r\n", ExceptionStrings[Exception]);
SerialPrintf("[ ISR] %s exception!\r\n", ExceptionStrings[Exception]);
//printf("%s exception!", ExceptionStrings[Exception]);
//panic();
}
@ -58,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(0x0000FF00);
SerialPrintf("ISR Error %d raised, EC %d!\r\n", Exception, ErrorCode);
SerialPrintf("%s exception!\r\n", ExceptionStrings[Exception]);
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);
@ -89,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);
}
@ -99,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. */
@ -125,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++) {
@ -175,6 +230,8 @@ void EmptyIRQ(INTERRUPT_FRAME* frame) {
static void KeyboardCallback(INTERRUPT_FRAME* frame) {
UNUSED(frame);
uint8_t msg = ReadPort(0x60, 1);
UpdateKeyboard(msg);
@ -243,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);
@ -264,28 +333,33 @@ __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) {
__asm__ __volatile__("sti");
SerialPrintf("Page fault! Caused by: [\r\n");
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;
//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;
uint8_t FaultInst = ErrorCode & 0x10;
if(!FaultPres) SerialPrintf("Accessed a page that isn't present.\r\n");
if(FaultRW || FaultUser) SerialPrintf("Accessed a Read-Only page.\r\n");
if(FaultReserved) SerialPrintf("Overwrote reserved bits.\r\n");
if(FaultInst) SerialPrintf("\"Instruction Fetch\"");
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("];");
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) {

View 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;
}

View 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);
}*/

View 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);
}
}

View File

@ -1,322 +1,379 @@
#include <kernel/chroma.h>
#include <lainlib/lainlib.h>
__attribute__((aligned(4096))) static size_t Pagetable[512] = {0};
/************************
*** 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 USERWRITEABLE_FLAGS(a) ((a & 0xFFFFFF00) + 0x83)
#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* 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 Size = AlignUpwards(AllocatorSize(), PAGE_SIZE);
Allocator = PhysAllocateZeroMem(Size);
Allocator = CreateAllocatorWithPool(Allocator, Size);
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.
SerialPrintf("[ Mem] Everything preallocated for paging.\n");
size_t* PT_KERNEL = (size_t*) 0xFFD000; // Layer 1, the page table for the kernel itself.
KernelAddressSpace = (address_space_t) {
.Lock = {0},
.PML4 = PhysAllocateZeroMem(PAGE_SIZE)
};
size_t fb_ptr = (size_t) &fb;
size_t* Pagetable = KernelAddressSpace.PML4;
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++;
//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);
}
// Now we map the last entry of PDE_KERNEL_FB to our Page Table
SET_ADDRESS(PDE_KERNEL_FB + LAST_ENTRY, PT_KERNEL);
SerialPrintf("[ Mem] Identity mapping higher half complete.\n");
// Mapping the kernel into the page tables....
MMapEnt* TopEntry = (MMapEnt*)(((&bootldr) + bootldr.size) - sizeof(MMapEnt));
size_t LargestAddress = TopEntry->ptr + TopEntry->size;
SET_ADDRESS(PT_KERNEL, 0xFF8001); // bootldr, bootinfo
SET_ADDRESS(PT_KERNEL + 8, 0xFF9001); // environment
SerialPrintf("[ Mem] About to map lower memory into the Direct Region.\n");
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");
// Map the kernel itself
SET_ADDRESS(PT_KERNEL + 16, KernelAddr + 1);
SerialPrintf("[ Mem] Mapping kernel into new memory map.\r\n");
// 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++;
//TODO: Disallow execution of rodata and data, and bootldr/environment
for(void* Address = CAST(void*, KERNEL_REGION);
Address < CAST(void*, KERNEL_REGION + 0x2000); // Lower half of Kernel
Address = CAST(void*, CAST(char*, Address) + PAGE_SIZE)) {
MapVirtualMemory(&KernelAddressSpace, Address, (CAST(size_t, Address) - KERNEL_REGION) + KERNEL_PHYSICAL, MAP_EXEC);
}
// 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 + 3) >> 2; i++) {
// PT_KERNEL[512 - (iterations + 1)] = 0x14003 + (iterations * page-width)
SET_ADDRESS(PT_KERNEL + LAST_ENTRY - (MappingIterations * 8), 0xF14003 + (4096 * MappingIterations));
MappingIterations++;
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);
}
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)));
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);
}
// Map first 2MB of memory
SET_ADDRESS(PDE_RAM, 0xF13000 + PAGE_PRESENT + PAGE_RW);
SerialPrintf("[ Mem] Kernel mapped into pagetables. New PML4 at 0x%p\r\n", KernelAddressSpace.PML4);
//ASSERT(Allocator != NULL);
}
for(size_t i = 0; i < 512; i++) {
SET_ADDRESS(0xF13000 + i * 4, i * (4 * KiB) + PAGE_PRESENT + PAGE_RW);
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;
}
// 0xA000 should now contain our memory map.
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);
void InitPagingOldImpl() {
if((size_t)((char*)ReadControlRegister(3) + DIRECT_REGION) != (size_t) &AddressSpace->PML4) {
WriteControlRegister(3, CAST(size_t, &AddressSpace->PML4));
}
}
// Disable paging so that we can work with the pagetable
//size_t registerTemp = ReadControlRegister(0);
//UNSET_PGBIT(registerTemp);
//WriteControlRegister(0, registerTemp);
void MapVirtualMemory(address_space_t* AddressSpace, void* VirtualAddress, size_t PhysicalAddress, mapflags_t Flag) {
// Clear space for our pagetable
size_t PagetableDest = 0x1000;
memset(PagetableDest, 0, 4096);
//bool MapGlobally = false;
size_t Virtual = (size_t)VirtualAddress;
// 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
//ASSERT(AddressSpace != NULL);
TicketAttemptLock(&AddressSpace->Lock);
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)
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));
}
// Enable PAE paging
size_t reg = ReadControlRegister(4);
SET_PAEBIT(reg);
WriteControlRegister(4, reg);
WriteControlRegister(3, PagetableDest);
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);
}
}
/* size_t registerTemp = ReadControlRegister(4);
if(registerTemp & (1 << 7)) {
TOGGLE_PGEBIT(registerTemp);
WriteControlRegister(4, registerTemp);
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(registerTemp & (1 << 7))
WriteControlRegister(4, registerTemp ^ (1 << 7));
if(Result != NULL) {
memset(Result, 0, Bits);
}
size_t CPUIDReturn;
asm volatile("cpuid" : "=d" (CPUIDReturn) : "a" (0x80000001) : "%rbx", "%rcx");
TicketUnlock(&AllocatorLock);
return Result;
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;
void* ReallocateMemory(void* Address, size_t NewSize) {
TicketAttemptLock(&AllocatorLock);
void* Result = AllocatorRealloc(Allocator, Address, NewSize);
size_t LastPML4Entry = 512;
size_t LastPDPEntry = 512;
if(Result == NULL) {
if(!ExpandAllocator(NewSize)) {
TicketUnlock(&AllocatorLock);
return 0ULL;
}
size_t MemorySearchDepth = MemorySize;
Result = AllocatorRealloc(Allocator, Address, NewSize);
}
while(MemorySearchDepth > (256ULL << 30)) {
MaxPML5++;
MemorySearchDepth -= (256ULL << 30);
}
TicketUnlock(&AllocatorLock);
return Result;
}
if(MaxPML5 > 512)
MaxPML5 = 512;
if(MemorySearchDepth) {
LastPDPEntry = ( (MemorySearchDepth + ((1 << 30) - 1)) & (~0ULL << 30)) >> 30;
void FreeMemory(void* Address) {
TicketAttemptLock(&AllocatorLock);
AllocatorFree(Allocator, Address);
TicketUnlock(&AllocatorLock);
}
if(MaxPML5 > 512)
MaxPML5 = 512;
}
void* AllocateKernelStack() {
void* StackAddress = NULL;
size_t StackSize = PAGE_SIZE * 4;
size_t PML4Size = PAGETABLE_SIZE * MaxPML5;
size_t PDPSize = PML4Size * MaxPML4;
TicketAttemptLock(&StackLock);
if(ListIsEmpty(&StackFreeList)) {
StackAddress = StackPointer;
StackPointer = (void*)(((char*)StackPointer) + (4*KiB) + StackSize);
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;
}
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 {
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;
}
list_entry_t* StackEntry = StackFreeList.Next;
ListRemove(StackEntry);
memset(StackEntry, 0, StackSize);
StackAddress = (void*)StackEntry;
}
WriteControlRegister(3, Pagetable);
TicketUnlock(&StackLock);
registerTemp = ReadControlRegister(4);
if(!(registerTemp & (1 << 7))) {
TOGGLE_PGEBIT(registerTemp);
WriteControlRegister(4, registerTemp);
}*/
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);
}

View File

@ -1,23 +1,177 @@
#include <kernel/chroma.h>
#include <kernel/system/heap.h>
#include <lainlib/lainlib.h>
uint8_t* Memory = ((uint8_t*)(&end));
uint8_t MemoryStart;
/************************
*** 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() {
size_t BootstructSize = bootldr.size;
size_t BootstructLoc = (size_t) &bootldr;
SerialPrintf("[ Mem] Counting memory..\r\n");
size_t BootstructEnd = BootstructLoc + BootstructSize;
MemorySize = 0;
size_t MemMapEntryCount = 0;
MMapEnt* MemMap = &bootldr.mmap;
while((size_t) MemMap < BootstructEnd) {
while((size_t) MemMap < ((size_t) &bootldr) + bootldr.size) {
if(MMapEnt_IsFree(MemMap)) {
MemorySize += MMapEnt_Size(MemMap);
}
@ -25,38 +179,20 @@ void InitMemoryManager() {
MemMap++;
}
SerialPrintf("[ Mem] Counted %d entries in the memory map..\r\n", MemMapEntryCount);
MemoryPages = MemorySize / PAGE_SIZE;
MemoryBuckets = MemoryPages / PAGES_PER_BUCKET;
if(MemoryBuckets * PAGES_PER_BUCKET < MemoryPages)
MemoryBuckets++; // Always round up
memset(Memory, 0, MemoryBuckets);
MemoryStart = (uint8_t*) PAGE_ALIGN((size_t)(Memory + MemoryBuckets));
SerialPrintf("Initializing Memory.\r\n");
SerialPrintf("%u MB of memory detected.\r\n", (MemorySize / 1024) / 1024);
for(size_t i = 0; i < MemoryBuckets; i++) {
if(Memory[i] != 0)
SerialPrintf("Memory at 0x%p is not empty!", Memory + i);
}
SerialPrintf("[ Mem] %u MB of memory detected.\r\n", (MemorySize / 1024) / 1024);
}
void ListMemoryMap() {
SerialPrintf("BIOS-Provided memory map:\r\n");
SerialPrintf("[ Mem] BIOS-Provided memory map:\r\n");
for(MMapEnt* MapEntry = &bootldr.mmap; MapEntry < (size_t) &bootldr + bootldr.size; MapEntry++) {
for(MMapEnt* MapEntry = &bootldr.mmap; (size_t)MapEntry < (size_t) &bootldr + bootldr.size; MapEntry++) {
char EntryType[8] = {0};
switch(MMapEnt_Type(MapEntry)) {
case MMAP_FREE:
@ -73,62 +209,110 @@ void ListMemoryMap() {
break;
}
SerialPrintf("[ mem 0x%p-0x%p] %s\r\n", MMapEnt_Ptr(MapEntry), MMapEnt_Ptr(MapEntry) + MMapEnt_Size(MapEntry), EntryType);
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));
}
}
}
size_t AllocateFrame() {
size_t FreePage = SeekFrame();
SET_BIT(FreePage);
return FreePage;
}
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;
}
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;
AddRangeToBuddy(&HighBuddy, Base, Size);
}
SerialPrintf("Memory manager: Critical!\r\n");
return (size_t) -1;
if(MemoryLength < AlignUpwards((size_t)Base + Size, PAGE_SIZE) / PAGE_SIZE) {
MemoryLength = AlignUpwards((size_t)Base + Size, PAGE_SIZE) / PAGE_SIZE;
}
}
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();
directptr_t PhysAllocateLowMem(size_t Size) {
directptr_t Pointer = BuddyAllocate(&LowBuddy, Size);
ASSERT(Pointer != NULL, "PhysAllocateLowMem: Allocation failed!");
if(!(FirstPage == 0 && SecondPage == 1)) {
Passed = false;
SerialPrintf("First iteration: Failed, First page %x, Second page %x.\r\n", FirstPage, SecondPage);
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);
}
FreeFrame(SecondPage);
SecondPage = SeekFrame();
ASSERT(Pointer != NULL, "PhysAllocateMem: Unable to allocate memory!");
if(SecondPage != 1)
Passed = false;
return Pointer;
}
FreeFrame(FirstPage);
FirstPage = SeekFrame();
directptr_t PhysAllocateZeroMem(size_t Size) {
directptr_t Pointer = PhysAllocateMem(Size);
memset(Pointer, 0, Size);
return Pointer;
}
if(FirstPage != 0)
Passed = false;
directptr_t PhysAllocateLowZeroMem(size_t Size) {
directptr_t Pointer = PhysAllocateLowMem(Size);
memset(Pointer, 0, Size);
return Pointer;
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 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);
}
}

View 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
View 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!";
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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) {
@ -45,8 +63,8 @@ void InitPrint() {
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);
}
@ -70,7 +88,7 @@ static void DrawChar(const char character, size_t x, size_t y) {
// This one is crazy. Stick with me.
if((FONT[character][Row * Y + X] >> (Bit & 0x7)) & 1) { // Check the bit in the bitmap, if it's solid..
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
@ -267,7 +285,7 @@ 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]);
}
}
@ -276,15 +294,15 @@ void WriteStringWithFont(const char *inChar)
{
psf_t *font = (psf_t*) &_binary_font_psf_start;
int drawX, drawY, kx = 0, fontLine, bitMask, offset;
unsigned int drawX, drawY, kx = 0, fontLine, bitMask, offset;
int bytesPerLine = ( font -> glyphWidth + 7 ) / 8;
const unsigned int bytesPerLine = ( font -> glyphWidth + 7 ) / 8;
while(*inChar) {
unsigned char *glyph =
(unsigned char*) &_binary_font_psf_start
+ font->headerSize
+ (*inChar > 0 && *inChar < font->numGlyphs ? *inChar : 0) *
+ (*inChar > 0 && *inChar < (int)font->numGlyphs ? *inChar : 0) *
font->glyphSize;

View File

@ -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') {

View File

@ -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
View 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

Binary file not shown.

BIN
global/crt0.old Normal file

Binary file not shown.

22
global/crt0.s Normal file
View 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

Binary file not shown.

BIN
global/crtend.o Normal file

Binary file not shown.

BIN
global/crti.o Normal file

Binary file not shown.

13
global/crti.s Normal file
View 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

Binary file not shown.

9
global/crtn.s Normal file
View File

@ -0,0 +1,9 @@
.section .init
popq %rbp
ret
.section .fini
popq %rbp
ret

1
img/boot/config Normal file
View File

@ -0,0 +1 @@
kernel=exe

BIN
img/boot/exe Normal file

Binary file not shown.

View File

@ -1,4 +0,0 @@
menuentry "Sync" {
multiboot /boot/bootloader
module /boot/initrd
}

View File

@ -1,6 +1,7 @@
mmio = 0xfffffffff8000000;
fb = 0xfffffffffc000000;
memstart = 0x14400;
mmio = 0xfffffffff8000000;
fb = 0xfffffffffc000000;
PHDRS
{
@ -14,10 +15,13 @@ SECTIONS
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) : {
@ -26,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 Normal file

Binary file not shown.

BIN
mkbootimg.exe Normal file

Binary file not shown.

18
post.sh Normal file
View 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
View File

@ -0,0 +1,3 @@
#!/bin/sh
x86_64-elf-ld -r -b binary -o font.o font.psf
cmake -G"Unix Makefiles" .

1
run.bat Normal file
View File

@ -0,0 +1 @@
vboxmanage startvm "Chroma"