mirror of
https://github.com/EnderIce2/Fennix.git
synced 2025-05-28 15:34:31 +00:00
Merge remote-tracking branch 'Lynx/master'
This commit is contained in:
commit
3dc5986c90
1
Lynx
1
Lynx
@ -1 +0,0 @@
|
|||||||
Subproject commit 9365295da732292f600b37738120124c297f1346
|
|
7
Lynx/.gitignore
vendored
Normal file
7
Lynx/.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
*.o
|
||||||
|
efi-loader.bin
|
||||||
|
loader.bin
|
||||||
|
UEFI/gnu-efi
|
||||||
|
UEFI/include
|
||||||
|
UEFI/BOOTX64.EFI
|
||||||
|
UEFI/BOOTIA32.EFI
|
210
Lynx/.vscode/c_cpp_properties.json
vendored
Normal file
210
Lynx/.vscode/c_cpp_properties.json
vendored
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Fennix x64 (Linux, GCC, debug)",
|
||||||
|
"includePath": [
|
||||||
|
"${workspaceFolder}/UEFI/include"
|
||||||
|
],
|
||||||
|
"defines": [
|
||||||
|
"__debug_vscode__",
|
||||||
|
"KERNEL_NAME=\"Fennix\"",
|
||||||
|
"KERNEL_VERSION=\"1.0\"",
|
||||||
|
"GIT_COMMIT=\"0000000000000000000000000000000000000000\"",
|
||||||
|
"GIT_COMMIT_SHORT=\"0000000\"",
|
||||||
|
"a64",
|
||||||
|
"a86",
|
||||||
|
"DEBUG=\"1\""
|
||||||
|
],
|
||||||
|
"compilerPath": "${workspaceFolder}/../tools/cross/bin/amd64-elf-gcc",
|
||||||
|
"cStandard": "c17",
|
||||||
|
"cppStandard": "c++20",
|
||||||
|
"intelliSenseMode": "gcc-x64",
|
||||||
|
"configurationProvider": "ms-vscode.makefile-tools",
|
||||||
|
"compilerArgs": [
|
||||||
|
// Compiler flags
|
||||||
|
"-fno-pic",
|
||||||
|
"-fno-pie",
|
||||||
|
"-mno-red-zone",
|
||||||
|
"-march=core2",
|
||||||
|
"-pipe",
|
||||||
|
"-mcmodel=kernel",
|
||||||
|
"-fno-builtin",
|
||||||
|
|
||||||
|
// Warnings
|
||||||
|
"-Wall",
|
||||||
|
"-Wextra",
|
||||||
|
"-Wfloat-equal",
|
||||||
|
"-Wpointer-arith",
|
||||||
|
"-Wcast-align",
|
||||||
|
"-Wredundant-decls",
|
||||||
|
"-Winit-self",
|
||||||
|
"-Wswitch-default",
|
||||||
|
"-Wstrict-overflow=5",
|
||||||
|
"-Wconversion",
|
||||||
|
|
||||||
|
// C++ flags
|
||||||
|
"-fno-rtti",
|
||||||
|
"-fexceptions",
|
||||||
|
|
||||||
|
// Linker flags
|
||||||
|
"-T${workspaceFolder}/Architecture/amd64/linker.ld",
|
||||||
|
"-Wl,-static,--no-dynamic-linker,-ztext",
|
||||||
|
"-nostdlib",
|
||||||
|
"-nodefaultlibs",
|
||||||
|
"-nolibc",
|
||||||
|
"-zmax-page-size=0x1000",
|
||||||
|
"-shared",
|
||||||
|
|
||||||
|
// Debug flags
|
||||||
|
"-ggdb3",
|
||||||
|
"-O0",
|
||||||
|
"-fdiagnostics-color=always",
|
||||||
|
"-fverbose-asm",
|
||||||
|
"-fstack-usage",
|
||||||
|
"-fstack-check",
|
||||||
|
"-fsanitize=undefined",
|
||||||
|
|
||||||
|
// VSCode flags
|
||||||
|
"-ffreestanding",
|
||||||
|
"-nostdinc",
|
||||||
|
"-nostdinc++"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Fennix x32 (Linux, GCC, debug)",
|
||||||
|
"includePath": [
|
||||||
|
"${workspaceFolder}/UEFI/include"
|
||||||
|
],
|
||||||
|
"defines": [
|
||||||
|
"__debug_vscode__",
|
||||||
|
"KERNEL_NAME=\"Fennix\"",
|
||||||
|
"KERNEL_VERSION=\"1.0\"",
|
||||||
|
"GIT_COMMIT=\"0000000000000000000000000000000000000000\"",
|
||||||
|
"GIT_COMMIT_SHORT=\"0000000\"",
|
||||||
|
"a32",
|
||||||
|
"a86",
|
||||||
|
"DEBUG=\"1\""
|
||||||
|
],
|
||||||
|
"compilerPath": "${workspaceFolder}/../tools/cross/bin/i386-elf-gcc",
|
||||||
|
"cStandard": "c17",
|
||||||
|
"cppStandard": "c++20",
|
||||||
|
"intelliSenseMode": "gcc-x86",
|
||||||
|
"configurationProvider": "ms-vscode.makefile-tools",
|
||||||
|
"compilerArgs": [
|
||||||
|
// Compiler flags
|
||||||
|
"-fno-pic",
|
||||||
|
"-fno-pie",
|
||||||
|
"-mno-80387",
|
||||||
|
"-mno-mmx",
|
||||||
|
"-mno-3dnow",
|
||||||
|
"-mno-red-zone",
|
||||||
|
"-march=pentium",
|
||||||
|
"-pipe",
|
||||||
|
"-msoft-float",
|
||||||
|
"-fno-builtin",
|
||||||
|
|
||||||
|
// Warnings
|
||||||
|
"-Wall",
|
||||||
|
"-Wextra",
|
||||||
|
"-Wfloat-equal",
|
||||||
|
"-Wpointer-arith",
|
||||||
|
"-Wcast-align",
|
||||||
|
"-Wredundant-decls",
|
||||||
|
"-Winit-self",
|
||||||
|
"-Wswitch-default",
|
||||||
|
"-Wstrict-overflow=5",
|
||||||
|
"-Wconversion",
|
||||||
|
|
||||||
|
// C++ flags
|
||||||
|
"-fno-rtti",
|
||||||
|
"-fexceptions",
|
||||||
|
|
||||||
|
// Linker flags
|
||||||
|
"-T${workspaceFolder}/Architecture/i386/linker.ld",
|
||||||
|
"-Wl,-static,--no-dynamic-linker,-ztext",
|
||||||
|
"-nostdlib",
|
||||||
|
"-nodefaultlibs",
|
||||||
|
"-nolibc",
|
||||||
|
"-zmax-page-size=0x1000",
|
||||||
|
"-shared",
|
||||||
|
|
||||||
|
// Debug flags
|
||||||
|
"-ggdb3",
|
||||||
|
"-O0",
|
||||||
|
"-fdiagnostics-color=always",
|
||||||
|
"-fverbose-asm",
|
||||||
|
"-fstack-usage",
|
||||||
|
"-fstack-check",
|
||||||
|
"-fsanitize=undefined",
|
||||||
|
|
||||||
|
// VSCode flags
|
||||||
|
"-ffreestanding",
|
||||||
|
"-nostdinc",
|
||||||
|
"-nostdinc++"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Fennix Aarch64 (Linux, GCC, debug)",
|
||||||
|
"includePath": [
|
||||||
|
"${workspaceFolder}/UEFI/include"
|
||||||
|
],
|
||||||
|
"defines": [
|
||||||
|
"__debug_vscode__",
|
||||||
|
"KERNEL_NAME=\"Fennix\"",
|
||||||
|
"KERNEL_VERSION=\"1.0\"",
|
||||||
|
"GIT_COMMIT=\"0000000000000000000000000000000000000000\"",
|
||||||
|
"GIT_COMMIT_SHORT=\"0000000\"",
|
||||||
|
"aa64",
|
||||||
|
"DEBUG=\"1\""
|
||||||
|
],
|
||||||
|
"compilerPath": "${workspaceFolder}/../tools/cross/bin/aarch64-elf-gcc",
|
||||||
|
"cStandard": "c17",
|
||||||
|
"cppStandard": "c++20",
|
||||||
|
"intelliSenseMode": "linux-gcc-arm64",
|
||||||
|
"configurationProvider": "ms-vscode.makefile-tools",
|
||||||
|
"compilerArgs": [
|
||||||
|
// Compiler flags
|
||||||
|
"-pipe",
|
||||||
|
"-fno-builtin",
|
||||||
|
"-msoft-float",
|
||||||
|
"-fPIC",
|
||||||
|
"-Wstack-protector",
|
||||||
|
|
||||||
|
// Warnings
|
||||||
|
"-Wall",
|
||||||
|
"-Wextra",
|
||||||
|
"-Wfloat-equal",
|
||||||
|
"-Wpointer-arith",
|
||||||
|
"-Wcast-align",
|
||||||
|
"-Wredundant-decls",
|
||||||
|
"-Winit-self",
|
||||||
|
"-Wswitch-default",
|
||||||
|
"-Wstrict-overflow=5",
|
||||||
|
"-Wconversion",
|
||||||
|
|
||||||
|
// C++ flags
|
||||||
|
"-fno-rtti",
|
||||||
|
"-fexceptions",
|
||||||
|
|
||||||
|
// Linker flags
|
||||||
|
"-T${workspaceFolder}/Architecture/aarch64/linker.ld",
|
||||||
|
"-fPIC",
|
||||||
|
|
||||||
|
// Debug flags
|
||||||
|
"-ggdb3",
|
||||||
|
"-O0",
|
||||||
|
"-fdiagnostics-color=always",
|
||||||
|
"-fverbose-asm",
|
||||||
|
"-fstack-usage",
|
||||||
|
"-fstack-check",
|
||||||
|
"-fsanitize=undefined",
|
||||||
|
|
||||||
|
// VSCode flags
|
||||||
|
"-ffreestanding",
|
||||||
|
"-nostdinc",
|
||||||
|
"-nostdinc++"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 4
|
||||||
|
}
|
19
Lynx/.vscode/settings.json
vendored
Normal file
19
Lynx/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"C_Cpp.errorSquiggles": "Enabled",
|
||||||
|
"C_Cpp.autocompleteAddParentheses": true,
|
||||||
|
"C_Cpp.codeAnalysis.clangTidy.enabled": true,
|
||||||
|
"C_Cpp.clang_format_style": "Visual Studio",
|
||||||
|
"C_Cpp.default.intelliSenseMode": "gcc-x64",
|
||||||
|
"C_Cpp.default.cStandard": "c17",
|
||||||
|
"C_Cpp.default.cppStandard": "c++20",
|
||||||
|
"C_Cpp.intelliSenseMemoryLimit": 16384,
|
||||||
|
"editor.smoothScrolling": true,
|
||||||
|
"editor.cursorSmoothCaretAnimation": "on",
|
||||||
|
"C_Cpp.codeAnalysis.clangTidy.checks.disabled": [
|
||||||
|
"clang-analyzer-security.insecureAPI.strcpy",
|
||||||
|
"clang-diagnostic-unknown-warning-option",
|
||||||
|
"clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling",
|
||||||
|
"clang-diagnostic-implicit-exception-spec-mismatch",
|
||||||
|
"clang-diagnostic-unknown-attributes"
|
||||||
|
]
|
||||||
|
}
|
22
Lynx/BIOS/Makefile
Normal file
22
Lynx/BIOS/Makefile
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
include ../../Makefile.conf
|
||||||
|
|
||||||
|
NAME=loader.bin
|
||||||
|
NASM = /usr/bin/nasm
|
||||||
|
|
||||||
|
ASM_SOURCES = $(shell find ./ -type f -name '*.asm')
|
||||||
|
OBJ = $(ASM_SOURCES:.asm=.o)
|
||||||
|
|
||||||
|
prepare:
|
||||||
|
$(info Nothing to prepare)
|
||||||
|
|
||||||
|
$(NAME): $(OBJ)
|
||||||
|
cat boot.o second.o > $@
|
||||||
|
|
||||||
|
build: $(NAME)
|
||||||
|
|
||||||
|
%.o: %.asm
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(NASM) $< -f bin -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJ) $(NAME)
|
65
Lynx/BIOS/boot.asm
Normal file
65
Lynx/BIOS/boot.asm
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
[ORG 0x7C00]
|
||||||
|
[BITS 16]
|
||||||
|
|
||||||
|
start:
|
||||||
|
jmp 0x0000:Boot
|
||||||
|
nop
|
||||||
|
|
||||||
|
times 8-($-$$) db 0
|
||||||
|
PrimaryVolumeDescriptor dd 0
|
||||||
|
BootFileLocation dd 0
|
||||||
|
BootFileLength dd 0
|
||||||
|
Checksum dd 0
|
||||||
|
Reserved times 40 db 0
|
||||||
|
times 90-($-$$) db 0
|
||||||
|
|
||||||
|
%include "print.inc"
|
||||||
|
|
||||||
|
Boot:
|
||||||
|
cli
|
||||||
|
mov [BOOT_DISK], dl
|
||||||
|
xor ax, ax
|
||||||
|
mov ds, ax
|
||||||
|
mov ss, ax
|
||||||
|
mov sp, 0x9C00
|
||||||
|
|
||||||
|
mov si, ErrorText
|
||||||
|
call Print
|
||||||
|
hlt
|
||||||
|
jmp $
|
||||||
|
|
||||||
|
mov si, BootloaderText
|
||||||
|
call Print
|
||||||
|
call ReadDisk
|
||||||
|
jmp EX_ADDRESS
|
||||||
|
jmp $
|
||||||
|
|
||||||
|
ReadDisk:
|
||||||
|
sti
|
||||||
|
mov ah, 0x02
|
||||||
|
mov bx, EX_ADDRESS
|
||||||
|
mov al, 20 ; max 65
|
||||||
|
mov dl, [BOOT_DISK]
|
||||||
|
mov ch, 0x00
|
||||||
|
mov dh, 0x00
|
||||||
|
mov cl, 0x02
|
||||||
|
int 0x13
|
||||||
|
jc DiskError
|
||||||
|
cli
|
||||||
|
ret
|
||||||
|
|
||||||
|
DiskError:
|
||||||
|
cli
|
||||||
|
mov si, DiskReadingErrorMessage
|
||||||
|
call Print
|
||||||
|
jmp $
|
||||||
|
|
||||||
|
ErrorText db 'BIOS boot not implemented', 0
|
||||||
|
BootloaderText db 'Lynx Bootloader', 0
|
||||||
|
DiskReadingErrorMessage: db ' Disk Error', 0
|
||||||
|
EX_ADDRESS equ 0x8000
|
||||||
|
BOOT_DISK: db 0
|
||||||
|
|
||||||
|
times 510-($-$$) db 0
|
||||||
|
db 0x55
|
||||||
|
db 0xAA
|
9
Lynx/BIOS/print.inc
Normal file
9
Lynx/BIOS/print.inc
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
Print:
|
||||||
|
lodsb
|
||||||
|
or al, al
|
||||||
|
jz PrintDone
|
||||||
|
mov ah, 0eh
|
||||||
|
int 10h
|
||||||
|
jmp Print
|
||||||
|
PrintDone:
|
||||||
|
ret
|
9
Lynx/BIOS/second.asm
Normal file
9
Lynx/BIOS/second.asm
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
; TODO
|
||||||
|
init:
|
||||||
|
mov si, LoadingText
|
||||||
|
call Print
|
||||||
|
jmp $
|
||||||
|
|
||||||
|
%include "print.inc"
|
||||||
|
|
||||||
|
LoadingText db ' Loading...', 0
|
2659
Lynx/Doxyfile
Normal file
2659
Lynx/Doxyfile
Normal file
File diff suppressed because it is too large
Load Diff
29
Lynx/LICENSE
Normal file
29
Lynx/LICENSE
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2022, EnderIce2
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
14
Lynx/Makefile
Normal file
14
Lynx/Makefile
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
prepare:
|
||||||
|
make -C BIOS prepare
|
||||||
|
make -C UEFI prepare
|
||||||
|
|
||||||
|
build:
|
||||||
|
make -C BIOS build
|
||||||
|
make -C UEFI build
|
||||||
|
cp BIOS/loader.bin .
|
||||||
|
cp UEFI/efi-loader.bin .
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C BIOS clean
|
||||||
|
make -C UEFI clean
|
||||||
|
rm -f loader.bin efi-loader.bin
|
13
Lynx/README.md
Normal file
13
Lynx/README.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Lynx
|
||||||
|
|
||||||
|
Bootloader for [Fennix](https://github.com/Fennix-Project/Fennix).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Currently under development.
|
||||||
|
|
||||||
|
Use `Fennix` repo to build the operating system.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone --recurse-submodules https://github.com/Fennix-Project/Fennix.git
|
||||||
|
```
|
48
Lynx/UEFI/Makefile
Normal file
48
Lynx/UEFI/Makefile
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
include ../../Makefile.conf
|
||||||
|
|
||||||
|
NAME=efi-loader.bin
|
||||||
|
CC = gcc
|
||||||
|
LD = ld
|
||||||
|
OBJCOPY = objcopy
|
||||||
|
|
||||||
|
C_SOURCES = $(shell find ./src -type f -name '*.c')
|
||||||
|
CPP_SOURCES = $(shell find ./src -type f -name '*.cpp')
|
||||||
|
OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o)
|
||||||
|
|
||||||
|
GNUEFI_RELEASE_VERSION=3.0.14
|
||||||
|
|
||||||
|
gnuefi:
|
||||||
|
wget https://archive.org/download/gnu-efi-$(GNUEFI_RELEASE_VERSION).tar/gnu-efi-$(GNUEFI_RELEASE_VERSION).tar.bz2
|
||||||
|
tar -xf gnu-efi-$(GNUEFI_RELEASE_VERSION).tar.bz2
|
||||||
|
rm gnu-efi-$(GNUEFI_RELEASE_VERSION).tar.bz2
|
||||||
|
mv ./gnu-efi-$(GNUEFI_RELEASE_VERSION) ./gnu-efi
|
||||||
|
mkdir -p include
|
||||||
|
cp -a ./gnu-efi/inc/. ./include
|
||||||
|
make -C gnu-efi
|
||||||
|
|
||||||
|
prepare: gnuefi
|
||||||
|
|
||||||
|
build: $(NAME)
|
||||||
|
|
||||||
|
$(NAME): BOOTX64
|
||||||
|
dd if=/dev/zero of=$(NAME) bs=512 count=93750
|
||||||
|
mformat -i $(NAME) ::
|
||||||
|
mmd -i $(NAME) ::/EFI
|
||||||
|
mmd -i $(NAME) ::/EFI/BOOT
|
||||||
|
mcopy -i $(NAME) BOOTX64.EFI ::/EFI/BOOT
|
||||||
|
|
||||||
|
BOOTX64: $(OBJ)
|
||||||
|
$(LD) -shared -Bsymbolic -Lgnu-efi/x86_64/lib -Lgnu-efi/x86_64/gnuefi -Tgnu-efi/gnuefi/elf_x86_64_efi.lds gnu-efi/x86_64/gnuefi/crt0-efi-x86_64.o $(OBJ) -o tmp.so -lgnuefi -lefi
|
||||||
|
$(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel -j .rela -j .rel.* -j .rela.* -j .reloc --target efi-app-x86_64 --subsystem=10 tmp.so BOOTX64.EFI
|
||||||
|
rm tmp.so
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(CC) -Ignu-efi/inc -Ignu-efi/inc/x86_64 -Ignu-efi/inc/protocol -fpic -ffreestanding -fno-stack-protector -fno-stack-check -fshort-wchar -mno-red-zone -maccumulate-outgoing-args -c $< -o $@
|
||||||
|
|
||||||
|
%.o: %.cpp
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(CC) -Ignu-efi/inc -Ignu-efi/inc/x86_64 -Ignu-efi/inc/protocol -fpermissive -fpic -ffreestanding -fno-stack-protector -fno-stack-check -fshort-wchar -mno-red-zone -maccumulate-outgoing-args -c $< -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(NAME) $(OBJ) BOOTX64.EFI
|
28
Lynx/UEFI/src/Bitmap.cpp
Normal file
28
Lynx/UEFI/src/Bitmap.cpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include "bitmap.hpp"
|
||||||
|
|
||||||
|
bool Bitmap::operator[](uint64_t index) { return Get(index); }
|
||||||
|
|
||||||
|
bool Bitmap::Get(uint64_t index)
|
||||||
|
{
|
||||||
|
if (index > Size * 8)
|
||||||
|
return false;
|
||||||
|
uint64_t byteIndex = index / 8;
|
||||||
|
uint8_t bitIndex = index % 8;
|
||||||
|
uint8_t bitIndexer = 0b10000000 >> bitIndex;
|
||||||
|
if ((Buffer[byteIndex] & bitIndexer) > 0)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bitmap::Set(uint64_t index, bool value)
|
||||||
|
{
|
||||||
|
if (index > Size * 8)
|
||||||
|
return false;
|
||||||
|
uint64_t byteIndex = index / 8;
|
||||||
|
uint8_t bitIndex = index % 8;
|
||||||
|
uint8_t bitIndexer = 0b10000000 >> bitIndex;
|
||||||
|
Buffer[byteIndex] &= ~bitIndexer;
|
||||||
|
if (value)
|
||||||
|
Buffer[byteIndex] |= bitIndexer;
|
||||||
|
return true;
|
||||||
|
}
|
8
Lynx/UEFI/src/FileLoader.c
Normal file
8
Lynx/UEFI/src/FileLoader.c
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#include "FileLoader.h"
|
||||||
|
|
||||||
|
// https://wiki.osdev.org/Loading_files_under_UEFI
|
||||||
|
|
||||||
|
EFI_FILE *LoadFile(EFI_FILE *Directory, CHAR16 *Path, EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
5
Lynx/UEFI/src/FileLoader.h
Normal file
5
Lynx/UEFI/src/FileLoader.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
EFI_FILE *LoadFile(EFI_FILE *Directory, CHAR16 *Path, EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable);
|
89
Lynx/UEFI/src/Lynx.c
Normal file
89
Lynx/UEFI/src/Lynx.c
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#include "Memory/memory.hpp"
|
||||||
|
#include "FileLoader.h"
|
||||||
|
|
||||||
|
#include "printf.h"
|
||||||
|
|
||||||
|
void port_byte_out(short unsigned int port, unsigned char value)
|
||||||
|
{
|
||||||
|
__asm__ volatile("outb %0, %1"
|
||||||
|
:
|
||||||
|
: "a"(value), "Nd"(port));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char port_byte_in(short unsigned int port)
|
||||||
|
{
|
||||||
|
unsigned char ReturnValue;
|
||||||
|
__asm__ volatile("inb %1, %0"
|
||||||
|
: "=a"(ReturnValue)
|
||||||
|
: "Nd"(port));
|
||||||
|
return ReturnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int strlen(const char s[])
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
while (s[i] != '\0')
|
||||||
|
++i;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int init_serial()
|
||||||
|
{
|
||||||
|
// TODO: fix crash on virtualbox (or virtualbox is faulty???????????)
|
||||||
|
port_byte_out(0x3F8 + 1, 0x00);
|
||||||
|
port_byte_out(0x3F8 + 3, 0x80);
|
||||||
|
port_byte_out(0x3F8 + 0, 0x03);
|
||||||
|
port_byte_out(0x3F8 + 1, 0x00);
|
||||||
|
port_byte_out(0x3F8 + 3, 0x03);
|
||||||
|
port_byte_out(0x3F8 + 2, 0xC7);
|
||||||
|
port_byte_out(0x3F8 + 4, 0x0B);
|
||||||
|
port_byte_out(0x3F8 + 4, 0x1E);
|
||||||
|
port_byte_out(0x3F8 + 0, 0xAE);
|
||||||
|
if (port_byte_in(0x3F8 + 0) != 0xAE)
|
||||||
|
{
|
||||||
|
return -1; // serial port is faulty
|
||||||
|
}
|
||||||
|
port_byte_out(0x3F8 + 4, 0x0F);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printf(const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
printf_(format, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void putchar(char c)
|
||||||
|
{
|
||||||
|
while ((port_byte_in(0x3F8 + 5) & 0x20) == 0)
|
||||||
|
;
|
||||||
|
port_byte_out(0x3F8, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
|
||||||
|
{
|
||||||
|
InitializeLib(ImageHandle, SystemTable);
|
||||||
|
SystemTable->BootServices->SetWatchdogTimer(0, 0, 0, NULL);
|
||||||
|
Print(L"Lynx Bootloader © EnderIce2 2022\n");
|
||||||
|
Print(L"UEFI not implemented\n");
|
||||||
|
while (1)
|
||||||
|
asm("hlt");
|
||||||
|
InitializeMemoryManagement(ImageHandle, SystemTable);
|
||||||
|
EFI_FILE *Kernel = LoadFile(NULL, L"fennix.elf", ImageHandle, SystemTable);
|
||||||
|
|
||||||
|
if (Kernel == NULL)
|
||||||
|
{
|
||||||
|
Print(L"Kernel not found\n");
|
||||||
|
while (1)
|
||||||
|
asm("hlt");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
asm("hlt");
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
146
Lynx/UEFI/src/Memory/Memory.cpp
Normal file
146
Lynx/UEFI/src/Memory/Memory.cpp
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
#include "memory.hpp"
|
||||||
|
|
||||||
|
#include "liballoc_1_1.h"
|
||||||
|
|
||||||
|
extern "C" void printf(const char *format, ...);
|
||||||
|
|
||||||
|
extern uint64_t ImageBase, _text, _etext, _data, _edata, _data_size;
|
||||||
|
|
||||||
|
using namespace Memory;
|
||||||
|
|
||||||
|
Physical KernelAllocator;
|
||||||
|
PageTable *KernelPageTable = nullptr;
|
||||||
|
|
||||||
|
static void *memset(void *s, int c, size_t n)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
((char *)s)[i] = c;
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void InitializeMemoryManagement(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
|
||||||
|
{
|
||||||
|
printf("Initializing Physical Memory Manager\n");
|
||||||
|
KernelAllocator = Physical();
|
||||||
|
KernelAllocator.Init(ImageHandle, SystemTable);
|
||||||
|
printf("Memory Info: %dMB / %dMB (%dMB reserved)",
|
||||||
|
(KernelAllocator.GetUsedMemory() / 1024 / 1024),
|
||||||
|
(KernelAllocator.GetTotalMemory() / 1024 / 1024),
|
||||||
|
(KernelAllocator.GetReservedMemory() / 1024 / 1024));
|
||||||
|
|
||||||
|
KernelPageTable = (PageTable *)KernelAllocator.RequestPage();
|
||||||
|
memset(KernelPageTable, 0, PAGE_SIZE);
|
||||||
|
Virtual kva = Virtual(KernelPageTable);
|
||||||
|
printf("Mapping...\n");
|
||||||
|
|
||||||
|
uint64_t BootloaderStart = (uint64_t)&ImageBase;
|
||||||
|
uint64_t BootloaderTextEnd = (uint64_t)&_text;
|
||||||
|
uint64_t BootloaderDataEnd = (uint64_t)&_data;
|
||||||
|
uint64_t BootloaderEnd = (uint64_t)&ImageBase + (uint64_t)&_etext + (uint64_t)&_edata;
|
||||||
|
|
||||||
|
uint64_t VirtualOffsetNormalVMA = NORMAL_VMA_OFFSET;
|
||||||
|
uint64_t BaseKernelMapAddress = (uint64_t)0; // TODO: Info->Kernel.PhysicalBase;
|
||||||
|
|
||||||
|
EFI_MEMORY_DESCRIPTOR *memDesc = nullptr;
|
||||||
|
UINTN MapSize, MapKey;
|
||||||
|
UINTN DescriptorSize;
|
||||||
|
UINT32 DescriptorVersion;
|
||||||
|
{
|
||||||
|
SystemTable->BootServices->GetMemoryMap(&MapSize, memDesc, &MapKey, &DescriptorSize, &DescriptorVersion);
|
||||||
|
SystemTable->BootServices->AllocatePool(EfiLoaderData, MapSize, (void **)&memDesc);
|
||||||
|
SystemTable->BootServices->GetMemoryMap(&MapSize, memDesc, &MapKey, &DescriptorSize, &DescriptorVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint64_t t = 0; t < MapSize / DescriptorSize; t += PAGE_SIZE)
|
||||||
|
{
|
||||||
|
kva.Map((void *)t, (void *)t, PTFlag::RW);
|
||||||
|
kva.Map((void *)VirtualOffsetNormalVMA, (void *)t, PTFlag::RW);
|
||||||
|
VirtualOffsetNormalVMA += PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
|
||||||
|
UINTN SizeOfInfo, numModes = 0; //, MaximumSupportedMode = 0;
|
||||||
|
EFI_STATUS status;
|
||||||
|
EFI_GRAPHICS_OUTPUT_PROTOCOL *gop;
|
||||||
|
EFI_GUID gopGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
|
||||||
|
status = uefi_call_wrapper(BS->LocateProtocol, 3, &gopGuid, NULL, (void **)&gop);
|
||||||
|
if (EFI_ERROR(status))
|
||||||
|
{
|
||||||
|
printf("Unable to locate the Graphics Output Protocol.\n");
|
||||||
|
}
|
||||||
|
status = uefi_call_wrapper(gop->QueryMode, 4, gop, gop->Mode == NULL ? 0 : gop->Mode->Mode, &SizeOfInfo, &info);
|
||||||
|
if (status == EFI_NOT_STARTED)
|
||||||
|
{
|
||||||
|
printf("The EFI not started!\n");
|
||||||
|
status = uefi_call_wrapper(gop->SetMode, 2, gop, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mapping Framebuffer address */
|
||||||
|
int itrfb = 0;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
for (uint64_t fb_base = (uint64_t)gop->Mode->FrameBufferBase;
|
||||||
|
fb_base < ((uint64_t)gop->Mode->FrameBufferBase + ((gop->Mode->Info->PixelsPerScanLine) + PAGE_SIZE));
|
||||||
|
fb_base += PAGE_SIZE)
|
||||||
|
kva.Map((void *)fb_base, (void *)fb_base, PTFlag::RW | PTFlag::US);
|
||||||
|
itrfb++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Kernel mapping */
|
||||||
|
for (uint64_t k = BootloaderStart; k < BootloaderTextEnd; k += PAGE_SIZE)
|
||||||
|
{
|
||||||
|
kva.Map((void *)k, (void *)BaseKernelMapAddress, PTFlag::RW);
|
||||||
|
KernelAllocator.LockPage((void *)BaseKernelMapAddress);
|
||||||
|
BaseKernelMapAddress += PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint64_t k = BootloaderTextEnd; k < BootloaderDataEnd; k += PAGE_SIZE)
|
||||||
|
{
|
||||||
|
kva.Map((void *)k, (void *)BaseKernelMapAddress, PTFlag::RW);
|
||||||
|
KernelAllocator.LockPage((void *)BaseKernelMapAddress);
|
||||||
|
BaseKernelMapAddress += PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint64_t k = BootloaderDataEnd; k < BootloaderEnd; k += PAGE_SIZE)
|
||||||
|
{
|
||||||
|
kva.Map((void *)k, (void *)BaseKernelMapAddress, PTFlag::RW);
|
||||||
|
KernelAllocator.LockPage((void *)BaseKernelMapAddress);
|
||||||
|
BaseKernelMapAddress += PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\nStart: %#llx - Text End: %#llx - End: %#llx\nStart Physical: %#llx - End Physical: %#llx",
|
||||||
|
BootloaderStart, BootloaderTextEnd, BootloaderEnd, /* Info->Kernel.PhysicalBase */ 0, BaseKernelMapAddress - PAGE_SIZE);
|
||||||
|
|
||||||
|
/* BootloaderStart BootloaderTextEnd KernelRoDataEnd BootloaderEnd
|
||||||
|
Kernel Start & Text Start ------ Text End ------ Kernel Rodata End ------ Kernel Data End & Kernel End
|
||||||
|
*/
|
||||||
|
printf("Applying new page table from address %p", KernelPageTable);
|
||||||
|
__asm__ volatile("mov %0, %%cr3" ::"r"(KernelPageTable));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void *HeapMalloc(uint64_t Size) { return PREFIX(malloc)(Size); }
|
||||||
|
extern "C" void *HeapCalloc(uint64_t n, uint64_t Size) { return PREFIX(calloc)(n, Size); }
|
||||||
|
extern "C" void *HeapRealloc(void *Address, uint64_t Size) { return PREFIX(realloc)(Address, Size); }
|
||||||
|
extern "C" void HeapFree(void *Address)
|
||||||
|
{
|
||||||
|
PREFIX(free)
|
||||||
|
(Address);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *operator new(uint64_t Size) { return HeapMalloc(Size); }
|
||||||
|
void *operator new[](uint64_t Size) { return HeapMalloc(Size); }
|
||||||
|
void operator delete(void *Pointer) { HeapFree(Pointer); }
|
||||||
|
void operator delete[](void *Pointer) { HeapFree(Pointer); }
|
||||||
|
void operator delete(void *Pointer, long unsigned int Size) { HeapFree(Pointer); }
|
||||||
|
void operator delete[](void *Pointer, long unsigned int Size) { HeapFree(Pointer); }
|
||||||
|
|
||||||
|
EXTERNC int liballoc_lock() {}
|
||||||
|
EXTERNC int liballoc_unlock() {}
|
||||||
|
EXTERNC void *liballoc_alloc(size_t Pages) { return KernelAllocator.RequestPages(Pages); }
|
||||||
|
EXTERNC int liballoc_free(void *Address, size_t Pages)
|
||||||
|
{
|
||||||
|
KernelAllocator.FreePages(Address, Pages);
|
||||||
|
return 0;
|
||||||
|
}
|
284
Lynx/UEFI/src/Memory/PhysicalMemoryManager.cpp
Normal file
284
Lynx/UEFI/src/Memory/PhysicalMemoryManager.cpp
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
#include "memory.hpp"
|
||||||
|
|
||||||
|
extern "C" void printf(const char *format, ...);
|
||||||
|
|
||||||
|
namespace Memory
|
||||||
|
{
|
||||||
|
uint64_t Physical::GetTotalMemory()
|
||||||
|
{
|
||||||
|
return this->TotalMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t Physical::GetFreeMemory()
|
||||||
|
{
|
||||||
|
return this->FreeMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t Physical::GetReservedMemory()
|
||||||
|
{
|
||||||
|
return this->ReservedMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t Physical::GetUsedMemory()
|
||||||
|
{
|
||||||
|
return this->UsedMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Physical::SwapPage(void *Address)
|
||||||
|
{
|
||||||
|
printf("%p", Address);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Physical::SwapPages(void *Address, uint64_t PageCount)
|
||||||
|
{
|
||||||
|
for (uint64_t i = 0; i < PageCount; i++)
|
||||||
|
if (!this->SwapPage((void *)((uint64_t)Address + (i * PAGE_SIZE))))
|
||||||
|
return false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Physical::UnswapPage(void *Address)
|
||||||
|
{
|
||||||
|
printf("%p", Address);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Physical::UnswapPages(void *Address, uint64_t PageCount)
|
||||||
|
{
|
||||||
|
for (uint64_t i = 0; i < PageCount; i++)
|
||||||
|
if (!this->UnswapPage((void *)((uint64_t)Address + (i * PAGE_SIZE))))
|
||||||
|
return false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Physical::RequestPage()
|
||||||
|
{
|
||||||
|
for (; PageBitmapIndex < PageBitmap.Size * 8; PageBitmapIndex++)
|
||||||
|
{
|
||||||
|
if (PageBitmap[PageBitmapIndex] == true)
|
||||||
|
continue;
|
||||||
|
this->LockPage((void *)(PageBitmapIndex * PAGE_SIZE));
|
||||||
|
return (void *)(PageBitmapIndex * PAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->SwapPage((void *)(PageBitmapIndex * PAGE_SIZE)))
|
||||||
|
{
|
||||||
|
this->LockPage((void *)(PageBitmapIndex * PAGE_SIZE));
|
||||||
|
return (void *)(PageBitmapIndex * PAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Out of memory! (Free: %ldMB; Used: %ldMB; Reserved: %ldMB)", (FreeMemory / 1024 / 1024), (UsedMemory / 1024 / 1024), (ReservedMemory / 1024 / 1024));
|
||||||
|
while (1)
|
||||||
|
__asm__("hlt");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Physical::RequestPages(uint64_t Count)
|
||||||
|
{
|
||||||
|
for (; PageBitmapIndex < PageBitmap.Size * 8; PageBitmapIndex++)
|
||||||
|
{
|
||||||
|
if (PageBitmap[PageBitmapIndex] == true)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (uint64_t Index = PageBitmapIndex; Index < PageBitmap.Size * 8; Index++)
|
||||||
|
{
|
||||||
|
if (PageBitmap[Index] == true)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i < Count; i++)
|
||||||
|
if (PageBitmap[Index + i] == true)
|
||||||
|
goto NextPage;
|
||||||
|
|
||||||
|
this->LockPages((void *)(Index * PAGE_SIZE), Count);
|
||||||
|
return (void *)(Index * PAGE_SIZE);
|
||||||
|
|
||||||
|
NextPage:
|
||||||
|
Index += Count;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->SwapPages((void *)(PageBitmapIndex * PAGE_SIZE), Count))
|
||||||
|
{
|
||||||
|
this->LockPages((void *)(PageBitmapIndex * PAGE_SIZE), Count);
|
||||||
|
return (void *)(PageBitmapIndex * PAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Out of memory! (Free: %ldMB; Used: %ldMB; Reserved: %ldMB)", (FreeMemory / 1024 / 1024), (UsedMemory / 1024 / 1024), (ReservedMemory / 1024 / 1024));
|
||||||
|
while (1)
|
||||||
|
__asm__("hlt");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Physical::FreePage(void *Address)
|
||||||
|
{
|
||||||
|
if (Address == nullptr)
|
||||||
|
{
|
||||||
|
printf("Null pointer passed to FreePage.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint64_t Index = (uint64_t)Address / PAGE_SIZE;
|
||||||
|
if (PageBitmap[Index] == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (PageBitmap.Set(Index, false))
|
||||||
|
{
|
||||||
|
FreeMemory += PAGE_SIZE;
|
||||||
|
UsedMemory -= PAGE_SIZE;
|
||||||
|
if (PageBitmapIndex > Index)
|
||||||
|
PageBitmapIndex = Index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Physical::FreePages(void *Address, uint64_t Count)
|
||||||
|
{
|
||||||
|
if (Address == nullptr || Count == 0)
|
||||||
|
{
|
||||||
|
printf("%s%s passed to FreePages.", Address == nullptr ? "Null pointer" : "", Count == 0 ? "Zero count" : "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint64_t t = 0; t < Count; t++)
|
||||||
|
this->FreePage((void *)((uint64_t)Address + (t * PAGE_SIZE)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Physical::LockPage(void *Address)
|
||||||
|
{
|
||||||
|
if (Address == nullptr)
|
||||||
|
printf("Trying to lock null address.");
|
||||||
|
|
||||||
|
uint64_t Index = (uint64_t)Address / PAGE_SIZE;
|
||||||
|
if (PageBitmap[Index] == true)
|
||||||
|
return;
|
||||||
|
if (PageBitmap.Set(Index, true))
|
||||||
|
{
|
||||||
|
FreeMemory -= PAGE_SIZE;
|
||||||
|
UsedMemory += PAGE_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Physical::LockPages(void *Address, uint64_t PageCount)
|
||||||
|
{
|
||||||
|
if (Address == nullptr || PageCount == 0)
|
||||||
|
printf("Trying to lock %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : "");
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i < PageCount; i++)
|
||||||
|
this->LockPage((void *)((uint64_t)Address + (i * PAGE_SIZE)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Physical::ReservePage(void *Address)
|
||||||
|
{
|
||||||
|
if (Address == nullptr)
|
||||||
|
printf("Trying to reserve null address.");
|
||||||
|
|
||||||
|
uint64_t Index = (uint64_t)Address / PAGE_SIZE;
|
||||||
|
if (PageBitmap[Index] == true)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (PageBitmap.Set(Index, true))
|
||||||
|
{
|
||||||
|
FreeMemory -= PAGE_SIZE;
|
||||||
|
ReservedMemory += PAGE_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Physical::ReservePages(void *Address, uint64_t PageCount)
|
||||||
|
{
|
||||||
|
if (Address == nullptr || PageCount == 0)
|
||||||
|
printf("Trying to reserve %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : "");
|
||||||
|
|
||||||
|
for (uint64_t t = 0; t < PageCount; t++)
|
||||||
|
this->ReservePage((void *)((uint64_t)Address + (t * PAGE_SIZE)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Physical::UnreservePage(void *Address)
|
||||||
|
{
|
||||||
|
if (Address == nullptr)
|
||||||
|
printf("Trying to unreserve null address.");
|
||||||
|
|
||||||
|
uint64_t Index = (uint64_t)Address / PAGE_SIZE;
|
||||||
|
if (PageBitmap[Index] == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (PageBitmap.Set(Index, false))
|
||||||
|
{
|
||||||
|
FreeMemory += PAGE_SIZE;
|
||||||
|
ReservedMemory -= PAGE_SIZE;
|
||||||
|
if (PageBitmapIndex > Index)
|
||||||
|
PageBitmapIndex = Index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Physical::UnreservePages(void *Address, uint64_t PageCount)
|
||||||
|
{
|
||||||
|
if (Address == nullptr || PageCount == 0)
|
||||||
|
printf("Trying to unreserve %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : "");
|
||||||
|
|
||||||
|
for (uint64_t t = 0; t < PageCount; t++)
|
||||||
|
this->UnreservePage((void *)((uint64_t)Address + (t * PAGE_SIZE)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Physical::Init(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
|
||||||
|
{
|
||||||
|
printf("Initializing physical memory manager...\n");
|
||||||
|
EFI_MEMORY_DESCRIPTOR *memDesc = nullptr;
|
||||||
|
UINTN MapSize, MapKey;
|
||||||
|
UINTN DescriptorSize;
|
||||||
|
UINT32 DescriptorVersion;
|
||||||
|
{
|
||||||
|
SystemTable->BootServices->GetMemoryMap(&MapSize, memDesc, &MapKey, &DescriptorSize, &DescriptorVersion);
|
||||||
|
SystemTable->BootServices->AllocatePool(EfiLoaderData, MapSize, (void **)&memDesc);
|
||||||
|
SystemTable->BootServices->GetMemoryMap(&MapSize, memDesc, &MapKey, &DescriptorSize, &DescriptorVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t MemoryMapSize = MapSize / DescriptorSize;
|
||||||
|
static uint64_t MemorySizeBytes = 0;
|
||||||
|
|
||||||
|
void *LargestFreeMemorySegment = nullptr;
|
||||||
|
uint64_t LargestFreeMemorySegmentSize = 0;
|
||||||
|
uint64_t MemorySize = MapSize;
|
||||||
|
TotalMemory = MemorySize;
|
||||||
|
FreeMemory = MemorySize;
|
||||||
|
|
||||||
|
for (int i = 0; i < MemoryMapSize; i++)
|
||||||
|
{
|
||||||
|
EFI_MEMORY_DESCRIPTOR *Descriptor = (EFI_MEMORY_DESCRIPTOR *)((uint64_t)memDesc + (i * DescriptorSize));
|
||||||
|
MemorySizeBytes += Descriptor->NumberOfPages * 4096;
|
||||||
|
switch (Descriptor->Type)
|
||||||
|
{
|
||||||
|
case EfiConventionalMemory:
|
||||||
|
if ((Descriptor->NumberOfPages * 4096) > LargestFreeMemorySegmentSize)
|
||||||
|
{
|
||||||
|
LargestFreeMemorySegment = (void *)Descriptor->PhysicalStart;
|
||||||
|
LargestFreeMemorySegmentSize = Descriptor->NumberOfPages * 4096;
|
||||||
|
printf("Largest free memory segment: %p (%dKB)",
|
||||||
|
(void *)Descriptor->PhysicalStart,
|
||||||
|
((Descriptor->NumberOfPages * 4096) / 1024));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t BitmapSize = ALIGN_UP((MemorySize / 0x1000) / 8, 0x1000);
|
||||||
|
printf("Initializing Bitmap (%p %dKB)", LargestFreeMemorySegment, (BitmapSize / 1024));
|
||||||
|
|
||||||
|
PageBitmap.Size = BitmapSize;
|
||||||
|
PageBitmap.Buffer = (uint8_t *)LargestFreeMemorySegment;
|
||||||
|
for (uint64_t i = 0; i < BitmapSize; i++)
|
||||||
|
*(uint8_t *)(PageBitmap.Buffer + i) = 0;
|
||||||
|
|
||||||
|
this->ReservePages(0, MemorySize / PAGE_SIZE + 1);
|
||||||
|
for (uint64_t i = 0; i < MemoryMapSize; i++)
|
||||||
|
{
|
||||||
|
EFI_MEMORY_DESCRIPTOR *Descriptor = (EFI_MEMORY_DESCRIPTOR *)((uint64_t)memDesc + (i * DescriptorSize));
|
||||||
|
if (Descriptor->Type == EfiConventionalMemory)
|
||||||
|
this->UnreservePages((void *)Descriptor->PhysicalStart, (Descriptor->NumberOfPages * 4096) / PAGE_SIZE + 1);
|
||||||
|
}
|
||||||
|
this->ReservePages(0, 0x100); // Reserve between 0 and 0x100000
|
||||||
|
this->LockPages(PageBitmap.Buffer, PageBitmap.Size / PAGE_SIZE + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Physical::Physical() {}
|
||||||
|
Physical::~Physical() {}
|
||||||
|
}
|
119
Lynx/UEFI/src/Memory/VirtualMemoryManager.cpp
Normal file
119
Lynx/UEFI/src/Memory/VirtualMemoryManager.cpp
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
#include "memory.hpp"
|
||||||
|
|
||||||
|
extern "C" void printf(const char* format, ...);
|
||||||
|
|
||||||
|
void *memset(void *dest, int c, size_t n)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
((char *)dest)[i] = c;
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Memory
|
||||||
|
{
|
||||||
|
void Virtual::Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags)
|
||||||
|
{
|
||||||
|
if (!this->Table)
|
||||||
|
{
|
||||||
|
printf("No page table");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PageMapIndexer Index = PageMapIndexer((uint64_t)VirtualAddress);
|
||||||
|
PageDirectoryEntry PDE = this->Table->Entries[Index.PDP_i];
|
||||||
|
PageTable *PDP;
|
||||||
|
if (!PDE.GetFlag(PTFlag::P))
|
||||||
|
{
|
||||||
|
PDP = (PageTable *)KernelAllocator.RequestPage();
|
||||||
|
memset(PDP, 0, PAGE_SIZE);
|
||||||
|
PDE.SetAddress((uint64_t)PDP >> 12);
|
||||||
|
PDE.SetFlag(PTFlag::P, true);
|
||||||
|
PDE.AddFlag(Flags);
|
||||||
|
this->Table->Entries[Index.PDP_i] = PDE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
PDP = (PageTable *)((uint64_t)PDE.GetAddress() << 12);
|
||||||
|
|
||||||
|
PDE = PDP->Entries[Index.PD_i];
|
||||||
|
PageTable *PD;
|
||||||
|
if (!PDE.GetFlag(PTFlag::P))
|
||||||
|
{
|
||||||
|
PD = (PageTable *)KernelAllocator.RequestPage();
|
||||||
|
memset(PD, 0, PAGE_SIZE);
|
||||||
|
PDE.SetAddress((uint64_t)PD >> 12);
|
||||||
|
PDE.SetFlag(PTFlag::P, true);
|
||||||
|
PDE.AddFlag(Flags);
|
||||||
|
PDP->Entries[Index.PD_i] = PDE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
PD = (PageTable *)((uint64_t)PDE.GetAddress() << 12);
|
||||||
|
|
||||||
|
PDE = PD->Entries[Index.PT_i];
|
||||||
|
PageTable *PT;
|
||||||
|
if (!PDE.GetFlag(PTFlag::P))
|
||||||
|
{
|
||||||
|
PT = (PageTable *)KernelAllocator.RequestPage();
|
||||||
|
memset(PT, 0, PAGE_SIZE);
|
||||||
|
PDE.SetAddress((uint64_t)PT >> 12);
|
||||||
|
PDE.SetFlag(PTFlag::P, true);
|
||||||
|
PDE.AddFlag(Flags);
|
||||||
|
PD->Entries[Index.PT_i] = PDE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
PT = (PageTable *)((uint64_t)PDE.GetAddress() << 12);
|
||||||
|
|
||||||
|
PDE = PT->Entries[Index.P_i];
|
||||||
|
PDE.SetAddress((uint64_t)PhysicalAddress >> 12);
|
||||||
|
PDE.SetFlag(PTFlag::P, true);
|
||||||
|
PDE.AddFlag(Flags);
|
||||||
|
PT->Entries[Index.P_i] = PDE;
|
||||||
|
__asm__ volatile("invlpg (%0)"
|
||||||
|
:
|
||||||
|
: "r"(VirtualAddress)
|
||||||
|
: "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Virtual::Map(void *VirtualAddress, void *PhysicalAddress, uint64_t PageCount, uint64_t Flags)
|
||||||
|
{
|
||||||
|
for (uint64_t i = 0; i < PageCount; i++)
|
||||||
|
this->Map((void *)((uint64_t)VirtualAddress + (i * PAGE_SIZE)), (void *)((uint64_t)PhysicalAddress + (i * PAGE_SIZE)), Flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Virtual::Unmap(void *VirtualAddress)
|
||||||
|
{
|
||||||
|
if (!this->Table)
|
||||||
|
{
|
||||||
|
printf("No page table");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PageMapIndexer Index = PageMapIndexer((uint64_t)VirtualAddress);
|
||||||
|
PageDirectoryEntry PDE = this->Table->Entries[Index.PDP_i];
|
||||||
|
PDE.ClearFlags();
|
||||||
|
|
||||||
|
__asm__ volatile("invlpg (%0)"
|
||||||
|
:
|
||||||
|
: "r"(VirtualAddress)
|
||||||
|
: "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Virtual::Unmap(void *VirtualAddress, uint64_t PageCount)
|
||||||
|
{
|
||||||
|
for (uint64_t i = 0; i < PageCount; i++)
|
||||||
|
this->Unmap((void *)((uint64_t)VirtualAddress + (i * PAGE_SIZE)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Virtual::Virtual(PageTable *Table)
|
||||||
|
{
|
||||||
|
uint64_t cr3;
|
||||||
|
__asm__ volatile("mov %%cr3, %0"
|
||||||
|
: "=r"(cr3));
|
||||||
|
|
||||||
|
if (Table)
|
||||||
|
this->Table = Table;
|
||||||
|
else
|
||||||
|
this->Table = (PageTable *)cr3;
|
||||||
|
}
|
||||||
|
|
||||||
|
Virtual::~Virtual() {}
|
||||||
|
}
|
787
Lynx/UEFI/src/Memory/liballoc_1_1.c
Normal file
787
Lynx/UEFI/src/Memory/liballoc_1_1.c
Normal file
@ -0,0 +1,787 @@
|
|||||||
|
#include "liballoc_1_1.h"
|
||||||
|
|
||||||
|
/** Durand's Amazing Super Duper Memory functions. */
|
||||||
|
|
||||||
|
#define VERSION "1.1"
|
||||||
|
#define ALIGNMENT 16ul // 4ul ///< This is the byte alignment that memory must be allocated on. IMPORTANT for GTK and other stuff.
|
||||||
|
|
||||||
|
#define ALIGN_TYPE char /// unsigned char[16] /// unsigned short
|
||||||
|
#define ALIGN_INFO sizeof(ALIGN_TYPE) * 16 ///< Alignment information is stored right before the pointer. This is the number of bytes of information stored there.
|
||||||
|
|
||||||
|
#define USE_CASE1
|
||||||
|
#define USE_CASE2
|
||||||
|
#define USE_CASE3
|
||||||
|
#define USE_CASE4
|
||||||
|
#define USE_CASE5
|
||||||
|
|
||||||
|
/** This macro will conveniently align our pointer upwards */
|
||||||
|
#define ALIGN(ptr) \
|
||||||
|
if (ALIGNMENT > 1) \
|
||||||
|
{ \
|
||||||
|
uintptr_t diff; \
|
||||||
|
ptr = (void *)((uintptr_t)ptr + ALIGN_INFO); \
|
||||||
|
diff = (uintptr_t)ptr & (ALIGNMENT - 1); \
|
||||||
|
if (diff != 0) \
|
||||||
|
{ \
|
||||||
|
diff = ALIGNMENT - diff; \
|
||||||
|
ptr = (void *)((uintptr_t)ptr + diff); \
|
||||||
|
} \
|
||||||
|
*((ALIGN_TYPE *)((uintptr_t)ptr - ALIGN_INFO)) = \
|
||||||
|
diff + ALIGN_INFO; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UNALIGN(ptr) \
|
||||||
|
if (ALIGNMENT > 1) \
|
||||||
|
{ \
|
||||||
|
uintptr_t diff = *((ALIGN_TYPE *)((uintptr_t)ptr - ALIGN_INFO)); \
|
||||||
|
if (diff < (ALIGNMENT + ALIGN_INFO)) \
|
||||||
|
{ \
|
||||||
|
ptr = (void *)((uintptr_t)ptr - diff); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LIBALLOC_MAGIC 0xc001c0de
|
||||||
|
#define LIBALLOC_DEAD 0xdeaddead
|
||||||
|
|
||||||
|
// #define LIBALLOCDEBUG 1
|
||||||
|
#define LIBALLOCINFO 1
|
||||||
|
|
||||||
|
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||||
|
|
||||||
|
// #define FLUSH() fflush(stdout)
|
||||||
|
#define FLUSH()
|
||||||
|
#define atexit(x)
|
||||||
|
#define printf(m, ...)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** A structure found at the top of all system allocated
|
||||||
|
* memory blocks. It details the usage of the memory block.
|
||||||
|
*/
|
||||||
|
struct liballoc_major
|
||||||
|
{
|
||||||
|
struct liballoc_major *prev; ///< Linked list information.
|
||||||
|
struct liballoc_major *next; ///< Linked list information.
|
||||||
|
unsigned int pages; ///< The number of pages in the block.
|
||||||
|
unsigned int size; ///< The number of pages in the block.
|
||||||
|
unsigned int usage; ///< The number of bytes used in the block.
|
||||||
|
struct liballoc_minor *first; ///< A pointer to the first allocated memory in the block.
|
||||||
|
};
|
||||||
|
|
||||||
|
/** This is a structure found at the beginning of all
|
||||||
|
* sections in a major block which were allocated by a
|
||||||
|
* malloc, calloc, realloc call.
|
||||||
|
*/
|
||||||
|
struct liballoc_minor
|
||||||
|
{
|
||||||
|
struct liballoc_minor *prev; ///< Linked list information.
|
||||||
|
struct liballoc_minor *next; ///< Linked list information.
|
||||||
|
struct liballoc_major *block; ///< The owning block. A pointer to the major structure.
|
||||||
|
unsigned int magic; ///< A magic number to idenfity correctness.
|
||||||
|
unsigned int size; ///< The size of the memory allocated. Could be 1 byte or more.
|
||||||
|
unsigned int req_size; ///< The size of memory requested.
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct liballoc_major *l_memRoot = NULL; ///< The root memory block acquired from the system.
|
||||||
|
static struct liballoc_major *l_bestBet = NULL; ///< The major with the most free memory.
|
||||||
|
|
||||||
|
static unsigned int l_pageSize = 4096; ///< The size of an individual page. Set up in liballoc_init.
|
||||||
|
static unsigned int l_pageCount = 16; ///< The number of pages to request per chunk. Set up in liballoc_init.
|
||||||
|
static unsigned long long l_allocated = 0; ///< Running total of allocated memory.
|
||||||
|
static unsigned long long l_inuse = 0; ///< Running total of used memory.
|
||||||
|
|
||||||
|
static long long l_warningCount = 0; ///< Number of warnings encountered
|
||||||
|
static long long l_errorCount = 0; ///< Number of actual errors
|
||||||
|
static long long l_possibleOverruns = 0; ///< Number of possible overruns
|
||||||
|
|
||||||
|
// *********** HELPER FUNCTIONS *******************************
|
||||||
|
|
||||||
|
static void *liballoc_memset(void *s, int c, size_t n)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
((char *)s)[i] = c;
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
static void *liballoc_memcpy(void *s1, const void *s2, size_t n)
|
||||||
|
{
|
||||||
|
char *cdest;
|
||||||
|
char *csrc;
|
||||||
|
unsigned int *ldest = (unsigned int *)s1;
|
||||||
|
unsigned int *lsrc = (unsigned int *)s2;
|
||||||
|
|
||||||
|
while (n >= sizeof(unsigned int))
|
||||||
|
{
|
||||||
|
*ldest++ = *lsrc++;
|
||||||
|
n -= sizeof(unsigned int);
|
||||||
|
}
|
||||||
|
|
||||||
|
cdest = (char *)ldest;
|
||||||
|
csrc = (char *)lsrc;
|
||||||
|
|
||||||
|
while (n > 0)
|
||||||
|
{
|
||||||
|
*cdest++ = *csrc++;
|
||||||
|
n -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||||
|
static void liballoc_dump()
|
||||||
|
{
|
||||||
|
#ifdef LIBALLOCDEBUG
|
||||||
|
struct liballoc_major *maj = l_memRoot;
|
||||||
|
struct liballoc_minor *min = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
printf("liballoc: ------ Memory data ---------------\n");
|
||||||
|
printf("liballoc: System memory allocated: %i bytes\n", l_allocated);
|
||||||
|
printf("liballoc: Memory in used (malloc'ed): %i bytes\n", l_inuse);
|
||||||
|
printf("liballoc: Warning count: %i\n", l_warningCount);
|
||||||
|
printf("liballoc: Error count: %i\n", l_errorCount);
|
||||||
|
printf("liballoc: Possible overruns: %i\n", l_possibleOverruns);
|
||||||
|
|
||||||
|
#ifdef LIBALLOCDEBUG
|
||||||
|
while (maj != NULL)
|
||||||
|
{
|
||||||
|
printf("liballoc: %x: total = %i, used = %i\n",
|
||||||
|
maj,
|
||||||
|
maj->size,
|
||||||
|
maj->usage);
|
||||||
|
|
||||||
|
min = maj->first;
|
||||||
|
while (min != NULL)
|
||||||
|
{
|
||||||
|
printf("liballoc: %x: %i bytes\n",
|
||||||
|
min,
|
||||||
|
min->size);
|
||||||
|
min = min->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
maj = maj->next;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FLUSH();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ***************************************************************
|
||||||
|
|
||||||
|
static struct liballoc_major *allocate_new_page(unsigned int size)
|
||||||
|
{
|
||||||
|
unsigned int st;
|
||||||
|
struct liballoc_major *maj;
|
||||||
|
|
||||||
|
// This is how much space is required.
|
||||||
|
st = size + sizeof(struct liballoc_major);
|
||||||
|
st += sizeof(struct liballoc_minor);
|
||||||
|
|
||||||
|
// Perfect amount of space?
|
||||||
|
if ((st % l_pageSize) == 0)
|
||||||
|
st = st / (l_pageSize);
|
||||||
|
else
|
||||||
|
st = st / (l_pageSize) + 1;
|
||||||
|
// No, add the buffer.
|
||||||
|
|
||||||
|
// Make sure it's >= the minimum size.
|
||||||
|
if (st < l_pageCount)
|
||||||
|
st = l_pageCount;
|
||||||
|
|
||||||
|
maj = (struct liballoc_major *)liballoc_alloc(st);
|
||||||
|
|
||||||
|
if (maj == NULL)
|
||||||
|
{
|
||||||
|
l_warningCount += 1;
|
||||||
|
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||||
|
printf("liballoc: WARNING: liballoc_alloc( %i ) return NULL\n", st);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
return NULL; // uh oh, we ran out of memory.
|
||||||
|
}
|
||||||
|
|
||||||
|
maj->prev = NULL;
|
||||||
|
maj->next = NULL;
|
||||||
|
maj->pages = st;
|
||||||
|
maj->size = st * l_pageSize;
|
||||||
|
maj->usage = sizeof(struct liballoc_major);
|
||||||
|
maj->first = NULL;
|
||||||
|
|
||||||
|
l_allocated += maj->size;
|
||||||
|
|
||||||
|
#ifdef LIBALLOCDEBUG
|
||||||
|
printf("liballoc: Resource allocated %x of %i pages (%i bytes) for %i size.\n", maj, st, maj->size, size);
|
||||||
|
|
||||||
|
printf("liballoc: Total memory usage = %i KB\n", (int)((l_allocated / (1024))));
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return maj;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *PREFIX(malloc)(size_t req_size)
|
||||||
|
{
|
||||||
|
int startedBet = 0;
|
||||||
|
unsigned long long bestSize = 0;
|
||||||
|
void *p = NULL;
|
||||||
|
uintptr_t diff;
|
||||||
|
struct liballoc_major *maj;
|
||||||
|
struct liballoc_minor *min;
|
||||||
|
struct liballoc_minor *new_min;
|
||||||
|
unsigned long size = req_size;
|
||||||
|
|
||||||
|
// For alignment, we adjust size so there's enough space to align.
|
||||||
|
if (ALIGNMENT > 1)
|
||||||
|
{
|
||||||
|
size += ALIGNMENT + ALIGN_INFO;
|
||||||
|
}
|
||||||
|
// So, ideally, we really want an alignment of 0 or 1 in order
|
||||||
|
// to save space.
|
||||||
|
|
||||||
|
liballoc_lock();
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
l_warningCount += 1;
|
||||||
|
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||||
|
printf("liballoc: WARNING: alloc( 0 ) called from %x\n",
|
||||||
|
__builtin_return_address(0));
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
liballoc_unlock();
|
||||||
|
return PREFIX(malloc)(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (l_memRoot == NULL)
|
||||||
|
{
|
||||||
|
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||||
|
#ifdef LIBALLOCDEBUG
|
||||||
|
printf("liballoc: initialization of liballoc " VERSION "\n");
|
||||||
|
#endif
|
||||||
|
atexit(liballoc_dump);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// This is the first time we are being used.
|
||||||
|
l_memRoot = allocate_new_page(size);
|
||||||
|
if (l_memRoot == NULL)
|
||||||
|
{
|
||||||
|
liballoc_unlock();
|
||||||
|
#ifdef LIBALLOCDEBUG
|
||||||
|
printf("liballoc: initial l_memRoot initialization failed\n", p);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LIBALLOCDEBUG
|
||||||
|
printf("liballoc: set up first memory major %x\n", l_memRoot);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LIBALLOCDEBUG
|
||||||
|
printf("liballoc: %x PREFIX(malloc)( %i ): ",
|
||||||
|
__builtin_return_address(0),
|
||||||
|
size);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Now we need to bounce through every major and find enough space....
|
||||||
|
|
||||||
|
maj = l_memRoot;
|
||||||
|
startedBet = 0;
|
||||||
|
|
||||||
|
// Start at the best bet....
|
||||||
|
if (l_bestBet != NULL)
|
||||||
|
{
|
||||||
|
bestSize = l_bestBet->size - l_bestBet->usage;
|
||||||
|
|
||||||
|
if (bestSize > (size + sizeof(struct liballoc_minor)))
|
||||||
|
{
|
||||||
|
maj = l_bestBet;
|
||||||
|
startedBet = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (maj != NULL)
|
||||||
|
{
|
||||||
|
diff = maj->size - maj->usage;
|
||||||
|
// free memory in the block
|
||||||
|
|
||||||
|
if (bestSize < diff)
|
||||||
|
{
|
||||||
|
// Hmm.. this one has more memory then our bestBet. Remember!
|
||||||
|
l_bestBet = maj;
|
||||||
|
bestSize = diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_CASE1
|
||||||
|
|
||||||
|
// CASE 1: There is not enough space in this major block.
|
||||||
|
if (diff < (size + sizeof(struct liballoc_minor)))
|
||||||
|
{
|
||||||
|
#ifdef LIBALLOCDEBUG
|
||||||
|
printf("CASE 1: Insufficient space in block %x\n", maj);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Another major block next to this one?
|
||||||
|
if (maj->next != NULL)
|
||||||
|
{
|
||||||
|
maj = maj->next; // Hop to that one.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startedBet == 1) // If we started at the best bet,
|
||||||
|
{ // let's start all over again.
|
||||||
|
maj = l_memRoot;
|
||||||
|
startedBet = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new major block next to this one and...
|
||||||
|
maj->next = allocate_new_page(size); // next one will be okay.
|
||||||
|
if (maj->next == NULL)
|
||||||
|
break; // no more memory.
|
||||||
|
maj->next->prev = maj;
|
||||||
|
maj = maj->next;
|
||||||
|
|
||||||
|
// .. fall through to CASE 2 ..
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_CASE2
|
||||||
|
|
||||||
|
// CASE 2: It's a brand new block.
|
||||||
|
if (maj->first == NULL)
|
||||||
|
{
|
||||||
|
maj->first = (struct liballoc_minor *)((uintptr_t)maj + sizeof(struct liballoc_major));
|
||||||
|
|
||||||
|
maj->first->magic = LIBALLOC_MAGIC;
|
||||||
|
maj->first->prev = NULL;
|
||||||
|
maj->first->next = NULL;
|
||||||
|
maj->first->block = maj;
|
||||||
|
maj->first->size = size;
|
||||||
|
maj->first->req_size = req_size;
|
||||||
|
maj->usage += size + sizeof(struct liballoc_minor);
|
||||||
|
|
||||||
|
l_inuse += size;
|
||||||
|
|
||||||
|
p = (void *)((uintptr_t)(maj->first) + sizeof(struct liballoc_minor));
|
||||||
|
|
||||||
|
ALIGN(p);
|
||||||
|
|
||||||
|
#ifdef LIBALLOCDEBUG
|
||||||
|
printf("CASE 2: returning %x\n", p);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
liballoc_unlock(); // release the lock
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_CASE3
|
||||||
|
|
||||||
|
// CASE 3: Block in use and enough space at the start of the block.
|
||||||
|
diff = (uintptr_t)(maj->first);
|
||||||
|
diff -= (uintptr_t)maj;
|
||||||
|
diff -= sizeof(struct liballoc_major);
|
||||||
|
|
||||||
|
if (diff >= (size + sizeof(struct liballoc_minor)))
|
||||||
|
{
|
||||||
|
// Yes, space in front. Squeeze in.
|
||||||
|
maj->first->prev = (struct liballoc_minor *)((uintptr_t)maj + sizeof(struct liballoc_major));
|
||||||
|
maj->first->prev->next = maj->first;
|
||||||
|
maj->first = maj->first->prev;
|
||||||
|
|
||||||
|
maj->first->magic = LIBALLOC_MAGIC;
|
||||||
|
maj->first->prev = NULL;
|
||||||
|
maj->first->block = maj;
|
||||||
|
maj->first->size = size;
|
||||||
|
maj->first->req_size = req_size;
|
||||||
|
maj->usage += size + sizeof(struct liballoc_minor);
|
||||||
|
|
||||||
|
l_inuse += size;
|
||||||
|
|
||||||
|
p = (void *)((uintptr_t)(maj->first) + sizeof(struct liballoc_minor));
|
||||||
|
ALIGN(p);
|
||||||
|
|
||||||
|
#ifdef LIBALLOCDEBUG
|
||||||
|
printf("CASE 3: returning %x\n", p);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
liballoc_unlock(); // release the lock
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_CASE4
|
||||||
|
|
||||||
|
// CASE 4: There is enough space in this block. But is it contiguous?
|
||||||
|
min = maj->first;
|
||||||
|
|
||||||
|
// Looping within the block now...
|
||||||
|
while (min != NULL)
|
||||||
|
{
|
||||||
|
// CASE 4.1: End of minors in a block. Space from last and end?
|
||||||
|
if (min->next == NULL)
|
||||||
|
{
|
||||||
|
// the rest of this block is free... is it big enough?
|
||||||
|
diff = (uintptr_t)(maj) + maj->size;
|
||||||
|
diff -= (uintptr_t)min;
|
||||||
|
diff -= sizeof(struct liballoc_minor);
|
||||||
|
diff -= min->size;
|
||||||
|
// minus already existing usage..
|
||||||
|
|
||||||
|
if (diff >= (size + sizeof(struct liballoc_minor)))
|
||||||
|
{
|
||||||
|
// yay....
|
||||||
|
min->next = (struct liballoc_minor *)((uintptr_t)min + sizeof(struct liballoc_minor) + min->size);
|
||||||
|
min->next->prev = min;
|
||||||
|
min = min->next;
|
||||||
|
min->next = NULL;
|
||||||
|
min->magic = LIBALLOC_MAGIC;
|
||||||
|
min->block = maj;
|
||||||
|
min->size = size;
|
||||||
|
min->req_size = req_size;
|
||||||
|
maj->usage += size + sizeof(struct liballoc_minor);
|
||||||
|
|
||||||
|
l_inuse += size;
|
||||||
|
|
||||||
|
p = (void *)((uintptr_t)min + sizeof(struct liballoc_minor));
|
||||||
|
ALIGN(p);
|
||||||
|
|
||||||
|
#ifdef LIBALLOCDEBUG
|
||||||
|
printf("CASE 4.1: returning %x\n", p);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
liballoc_unlock(); // release the lock
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CASE 4.2: Is there space between two minors?
|
||||||
|
if (min->next != NULL)
|
||||||
|
{
|
||||||
|
// is the difference between here and next big enough?
|
||||||
|
diff = (uintptr_t)(min->next);
|
||||||
|
diff -= (uintptr_t)min;
|
||||||
|
diff -= sizeof(struct liballoc_minor);
|
||||||
|
diff -= min->size;
|
||||||
|
// minus our existing usage.
|
||||||
|
|
||||||
|
if (diff >= (size + sizeof(struct liballoc_minor)))
|
||||||
|
{
|
||||||
|
// yay......
|
||||||
|
new_min = (struct liballoc_minor *)((uintptr_t)min + sizeof(struct liballoc_minor) + min->size);
|
||||||
|
|
||||||
|
new_min->magic = LIBALLOC_MAGIC;
|
||||||
|
new_min->next = min->next;
|
||||||
|
new_min->prev = min;
|
||||||
|
new_min->size = size;
|
||||||
|
new_min->req_size = req_size;
|
||||||
|
new_min->block = maj;
|
||||||
|
min->next->prev = new_min;
|
||||||
|
min->next = new_min;
|
||||||
|
maj->usage += size + sizeof(struct liballoc_minor);
|
||||||
|
|
||||||
|
l_inuse += size;
|
||||||
|
|
||||||
|
p = (void *)((uintptr_t)new_min + sizeof(struct liballoc_minor));
|
||||||
|
ALIGN(p);
|
||||||
|
|
||||||
|
#ifdef LIBALLOCDEBUG
|
||||||
|
printf("CASE 4.2: returning %x\n", p);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
liballoc_unlock(); // release the lock
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
} // min->next != NULL
|
||||||
|
|
||||||
|
min = min->next;
|
||||||
|
} // while min != NULL ...
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_CASE5
|
||||||
|
|
||||||
|
// CASE 5: Block full! Ensure next block and loop.
|
||||||
|
if (maj->next == NULL)
|
||||||
|
{
|
||||||
|
#ifdef LIBALLOCDEBUG
|
||||||
|
printf("CASE 5: block full\n");
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (startedBet == 1)
|
||||||
|
{
|
||||||
|
maj = l_memRoot;
|
||||||
|
startedBet = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we've run out. we need more...
|
||||||
|
maj->next = allocate_new_page(size); // next one guaranteed to be okay
|
||||||
|
if (maj->next == NULL)
|
||||||
|
break; // uh oh, no more memory.....
|
||||||
|
maj->next->prev = maj;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
maj = maj->next;
|
||||||
|
} // while (maj != NULL)
|
||||||
|
|
||||||
|
liballoc_unlock(); // release the lock
|
||||||
|
|
||||||
|
#ifdef LIBALLOCDEBUG
|
||||||
|
printf("All cases exhausted. No memory available.\n");
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||||
|
printf("liballoc: WARNING: PREFIX(malloc)( %i ) returning NULL.\n", size);
|
||||||
|
liballoc_dump();
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PREFIX(free)(void *ptr)
|
||||||
|
{
|
||||||
|
struct liballoc_minor *min;
|
||||||
|
struct liballoc_major *maj;
|
||||||
|
|
||||||
|
if (ptr == NULL)
|
||||||
|
{
|
||||||
|
l_warningCount += 1;
|
||||||
|
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||||
|
printf("liballoc: WARNING: PREFIX(free)( NULL ) called from %x\n",
|
||||||
|
__builtin_return_address(0));
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UNALIGN(ptr);
|
||||||
|
|
||||||
|
liballoc_lock(); // lockit
|
||||||
|
|
||||||
|
min = (struct liballoc_minor *)((uintptr_t)ptr - sizeof(struct liballoc_minor));
|
||||||
|
|
||||||
|
if (min->magic != LIBALLOC_MAGIC)
|
||||||
|
{
|
||||||
|
l_errorCount += 1;
|
||||||
|
|
||||||
|
// Check for overrun errors. For all bytes of LIBALLOC_MAGIC
|
||||||
|
if (
|
||||||
|
((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF)) ||
|
||||||
|
((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF)) ||
|
||||||
|
((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF)))
|
||||||
|
{
|
||||||
|
l_possibleOverruns += 1;
|
||||||
|
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||||
|
printf("liballoc: ERROR: Possible 1-3 byte overrun for magic %x != %x\n",
|
||||||
|
min->magic,
|
||||||
|
LIBALLOC_MAGIC);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (min->magic == LIBALLOC_DEAD)
|
||||||
|
{
|
||||||
|
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||||
|
printf("liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n",
|
||||||
|
ptr,
|
||||||
|
__builtin_return_address(0));
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||||
|
printf("liballoc: ERROR: Bad PREFIX(free)( %x ) called from %x\n",
|
||||||
|
ptr,
|
||||||
|
__builtin_return_address(0));
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// being lied to...
|
||||||
|
liballoc_unlock(); // release the lock
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LIBALLOCDEBUG
|
||||||
|
printf("liballoc: %x PREFIX(free)( %x ): ",
|
||||||
|
__builtin_return_address(0),
|
||||||
|
ptr);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
maj = min->block;
|
||||||
|
|
||||||
|
l_inuse -= min->size;
|
||||||
|
|
||||||
|
maj->usage -= (min->size + sizeof(struct liballoc_minor));
|
||||||
|
min->magic = LIBALLOC_DEAD; // No mojo.
|
||||||
|
|
||||||
|
if (min->next != NULL)
|
||||||
|
min->next->prev = min->prev;
|
||||||
|
if (min->prev != NULL)
|
||||||
|
min->prev->next = min->next;
|
||||||
|
|
||||||
|
if (min->prev == NULL)
|
||||||
|
maj->first = min->next;
|
||||||
|
// Might empty the block. This was the first
|
||||||
|
// minor.
|
||||||
|
|
||||||
|
// We need to clean up after the majors now....
|
||||||
|
|
||||||
|
if (maj->first == NULL) // Block completely unused.
|
||||||
|
{
|
||||||
|
if (l_memRoot == maj)
|
||||||
|
l_memRoot = maj->next;
|
||||||
|
if (l_bestBet == maj)
|
||||||
|
l_bestBet = NULL;
|
||||||
|
if (maj->prev != NULL)
|
||||||
|
maj->prev->next = maj->next;
|
||||||
|
if (maj->next != NULL)
|
||||||
|
maj->next->prev = maj->prev;
|
||||||
|
l_allocated -= maj->size;
|
||||||
|
|
||||||
|
liballoc_free(maj, maj->pages);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (l_bestBet != NULL)
|
||||||
|
{
|
||||||
|
int bestSize = l_bestBet->size - l_bestBet->usage;
|
||||||
|
int majSize = maj->size - maj->usage;
|
||||||
|
|
||||||
|
if (majSize > bestSize)
|
||||||
|
l_bestBet = maj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LIBALLOCDEBUG
|
||||||
|
printf("OK\n");
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
liballoc_unlock(); // release the lock
|
||||||
|
}
|
||||||
|
|
||||||
|
void *PREFIX(calloc)(size_t nobj, size_t size)
|
||||||
|
{
|
||||||
|
int real_size;
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
real_size = nobj * size;
|
||||||
|
|
||||||
|
p = PREFIX(malloc)(real_size);
|
||||||
|
|
||||||
|
liballoc_memset(p, 0, real_size);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *PREFIX(realloc)(void *p, size_t size)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
struct liballoc_minor *min;
|
||||||
|
unsigned int real_size;
|
||||||
|
|
||||||
|
// Honour the case of size == 0 => free old and return NULL
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
PREFIX(free)
|
||||||
|
(p);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the case of a NULL pointer, return a simple malloc.
|
||||||
|
if (p == NULL)
|
||||||
|
return PREFIX(malloc)(size);
|
||||||
|
|
||||||
|
// Unalign the pointer if required.
|
||||||
|
ptr = p;
|
||||||
|
UNALIGN(ptr);
|
||||||
|
|
||||||
|
liballoc_lock(); // lockit
|
||||||
|
|
||||||
|
min = (struct liballoc_minor *)((uintptr_t)ptr - sizeof(struct liballoc_minor));
|
||||||
|
|
||||||
|
// Ensure it is a valid structure.
|
||||||
|
if (min->magic != LIBALLOC_MAGIC)
|
||||||
|
{
|
||||||
|
l_errorCount += 1;
|
||||||
|
|
||||||
|
// Check for overrun errors. For all bytes of LIBALLOC_MAGIC
|
||||||
|
if (
|
||||||
|
((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF)) ||
|
||||||
|
((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF)) ||
|
||||||
|
((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF)))
|
||||||
|
{
|
||||||
|
l_possibleOverruns += 1;
|
||||||
|
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||||
|
printf("liballoc: ERROR: Possible 1-3 byte overrun for magic %x != %x\n",
|
||||||
|
min->magic,
|
||||||
|
LIBALLOC_MAGIC);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (min->magic == LIBALLOC_DEAD)
|
||||||
|
{
|
||||||
|
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||||
|
printf("liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n",
|
||||||
|
ptr,
|
||||||
|
__builtin_return_address(0));
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
|
||||||
|
printf("liballoc: ERROR: Bad PREFIX(free)( %x ) called from %x\n",
|
||||||
|
ptr,
|
||||||
|
__builtin_return_address(0));
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// being lied to...
|
||||||
|
liballoc_unlock(); // release the lock
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Definitely a memory block.
|
||||||
|
|
||||||
|
real_size = min->req_size;
|
||||||
|
|
||||||
|
if (real_size >= size)
|
||||||
|
{
|
||||||
|
min->req_size = size;
|
||||||
|
liballoc_unlock();
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
liballoc_unlock();
|
||||||
|
|
||||||
|
// If we got here then we're reallocating to a block bigger than us.
|
||||||
|
ptr = PREFIX(malloc)(size); // We need to allocate new memory
|
||||||
|
liballoc_memcpy(ptr, p, real_size);
|
||||||
|
PREFIX(free)
|
||||||
|
(p);
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
90
Lynx/UEFI/src/Memory/liballoc_1_1.h
Normal file
90
Lynx/UEFI/src/Memory/liballoc_1_1.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
#ifndef _LIBALLOC_H
|
||||||
|
#define _LIBALLOC_H
|
||||||
|
|
||||||
|
#ifndef LYNX_LIBALLOC_TYPES_H
|
||||||
|
#define LYNX_LIBALLOC_TYPES_H
|
||||||
|
|
||||||
|
typedef __UINT8_TYPE__ uint8_t;
|
||||||
|
typedef __UINT16_TYPE__ uint16_t;
|
||||||
|
typedef __UINT32_TYPE__ uint32_t;
|
||||||
|
typedef __UINT64_TYPE__ uint64_t;
|
||||||
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
typedef __UINTPTR_TYPE__ uintptr_t;
|
||||||
|
#ifndef NULL
|
||||||
|
#define NULL ((void *)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ALIGN_UP(x, align) ((__typeof__(x))(((uint64_t)(x) + ((align)-1)) & (~((align)-1))))
|
||||||
|
#define ALIGN_DOWN(x, align) ((__typeof__(x))((x) & (~((align)-1))))
|
||||||
|
|
||||||
|
#endif // !LYNX_LIBALLOC_TYPES_H
|
||||||
|
|
||||||
|
/** \defgroup ALLOCHOOKS liballoc hooks
|
||||||
|
*
|
||||||
|
* These are the OS specific functions which need to
|
||||||
|
* be implemented on any platform that the library
|
||||||
|
* is expected to work on.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @{ */
|
||||||
|
|
||||||
|
// If we are told to not define our own size_t, then we skip the define.
|
||||||
|
//#define _HAVE_UINTPTR_T
|
||||||
|
// typedef unsigned long uintptr_t;
|
||||||
|
|
||||||
|
// This lets you prefix malloc and friends
|
||||||
|
#define PREFIX(func) kliballoc_##func
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** This function is supposed to lock the memory data structures. It
|
||||||
|
* could be as simple as disabling interrupts or acquiring a spinlock.
|
||||||
|
* It's up to you to decide.
|
||||||
|
*
|
||||||
|
* \return 0 if the lock was acquired successfully. Anything else is
|
||||||
|
* failure.
|
||||||
|
*/
|
||||||
|
extern int liballoc_lock();
|
||||||
|
|
||||||
|
/** This function unlocks what was previously locked by the liballoc_lock
|
||||||
|
* function. If it disabled interrupts, it enables interrupts. If it
|
||||||
|
* had acquiried a spinlock, it releases the spinlock. etc.
|
||||||
|
*
|
||||||
|
* \return 0 if the lock was successfully released.
|
||||||
|
*/
|
||||||
|
extern int liballoc_unlock();
|
||||||
|
|
||||||
|
/** This is the hook into the local system which allocates pages. It
|
||||||
|
* accepts an integer parameter which is the number of pages
|
||||||
|
* required. The page size was set up in the liballoc_init function.
|
||||||
|
*
|
||||||
|
* \return NULL if the pages were not allocated.
|
||||||
|
* \return A pointer to the allocated memory.
|
||||||
|
*/
|
||||||
|
extern void *liballoc_alloc(size_t);
|
||||||
|
|
||||||
|
/** This frees previously allocated memory. The void* parameter passed
|
||||||
|
* to the function is the exact same value returned from a previous
|
||||||
|
* liballoc_alloc call.
|
||||||
|
*
|
||||||
|
* The integer value is the number of pages to free.
|
||||||
|
*
|
||||||
|
* \return 0 if the memory was successfully freed.
|
||||||
|
*/
|
||||||
|
extern int liballoc_free(void *, size_t);
|
||||||
|
|
||||||
|
extern void *PREFIX(malloc)(size_t); ///< The standard function.
|
||||||
|
extern void *PREFIX(realloc)(void *, size_t); ///< The standard function.
|
||||||
|
extern void *PREFIX(calloc)(size_t, size_t); ///< The standard function.
|
||||||
|
extern void PREFIX(free)(void *); ///< The standard function.
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
#endif
|
433
Lynx/UEFI/src/Memory/memory.hpp
Normal file
433
Lynx/UEFI/src/Memory/memory.hpp
Normal file
@ -0,0 +1,433 @@
|
|||||||
|
#ifndef __FENNIX_KERNEL_INTERNAL_MEMORY_H__
|
||||||
|
#define __FENNIX_KERNEL_INTERNAL_MEMORY_H__
|
||||||
|
|
||||||
|
#ifndef LYNX_MEMORY_TYPES_H
|
||||||
|
#define LYNX_MEMORY_TYPES_H
|
||||||
|
|
||||||
|
typedef __UINT8_TYPE__ uint8_t;
|
||||||
|
typedef __UINT16_TYPE__ uint16_t;
|
||||||
|
typedef __UINT32_TYPE__ uint32_t;
|
||||||
|
typedef __UINT64_TYPE__ uint64_t;
|
||||||
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
typedef __UINTPTR_TYPE__ uintptr_t;
|
||||||
|
#ifndef NULL
|
||||||
|
#define NULL ((void *)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define EXTERNC extern "C"
|
||||||
|
#else
|
||||||
|
#define EXTERNC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ALIGN_UP(x, align) ((__typeof__(x))(((uint64_t)(x) + ((align)-1)) & (~((align)-1))))
|
||||||
|
#define ALIGN_DOWN(x, align) ((__typeof__(x))((x) & (~((align)-1))))
|
||||||
|
|
||||||
|
#endif // !LYNX_MEMORY_TYPES_H
|
||||||
|
|
||||||
|
#include "../bitmap.hpp"
|
||||||
|
|
||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
#define PAGE_SIZE 0x1000
|
||||||
|
|
||||||
|
// to pages
|
||||||
|
#define TO_PAGES(d) (d / PAGE_SIZE + 1)
|
||||||
|
// from pages
|
||||||
|
#define FROM_PAGES(d) (d * PAGE_SIZE - 1)
|
||||||
|
|
||||||
|
#define NORMAL_VMA_OFFSET 0xFFFF800000000000
|
||||||
|
#define KERNEL_VMA_OFFSET 0xFFFFFFFF80000000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief KERNEL_HEAP_BASE is the base address of the kernel heap
|
||||||
|
*/
|
||||||
|
#define KERNEL_HEAP_BASE 0xFFFFC00000000000
|
||||||
|
/**
|
||||||
|
* @brief USER_HEAP_BASE is the base address of the user heap allocated by the kernel
|
||||||
|
*/
|
||||||
|
#define USER_HEAP_BASE 0xFFFFD00000000000
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
namespace Memory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief https://wiki.osdev.org/images/4/41/64-bit_page_tables1.png
|
||||||
|
* @brief https://wiki.osdev.org/images/6/6b/64-bit_page_tables2.png
|
||||||
|
*/
|
||||||
|
enum PTFlag
|
||||||
|
{
|
||||||
|
/** @brief Present */
|
||||||
|
P = 1 << 0,
|
||||||
|
|
||||||
|
/** @brief Read/Write */
|
||||||
|
RW = 1 << 1,
|
||||||
|
|
||||||
|
/** @brief User/Supervisor */
|
||||||
|
US = 1 << 2,
|
||||||
|
|
||||||
|
/** @brief Write-Through */
|
||||||
|
PWT = 1 << 3,
|
||||||
|
|
||||||
|
/** @brief Cache Disable */
|
||||||
|
PCD = 1 << 4,
|
||||||
|
|
||||||
|
/** @brief Accessed */
|
||||||
|
A = 1 << 5,
|
||||||
|
|
||||||
|
/** @brief Dirty */
|
||||||
|
D = 1 << 6,
|
||||||
|
|
||||||
|
/** @brief Page Size */
|
||||||
|
PS = 1 << 7,
|
||||||
|
|
||||||
|
/** @brief Global */
|
||||||
|
G = 1 << 8,
|
||||||
|
|
||||||
|
/** @brief Available 0 */
|
||||||
|
AVL0 = 1 << 9,
|
||||||
|
|
||||||
|
/** @brief Available 1 */
|
||||||
|
AVL1 = 1 << 10,
|
||||||
|
|
||||||
|
/** @brief Available 2 */
|
||||||
|
AVL2 = 1 << 11,
|
||||||
|
|
||||||
|
/** @brief Page Attribute Table */
|
||||||
|
PAT = 1 << 12,
|
||||||
|
|
||||||
|
/** @brief Available 3 */
|
||||||
|
AVL3 = (uint64_t)1 << 52,
|
||||||
|
|
||||||
|
/** @brief Available 4 */
|
||||||
|
AVL4 = (uint64_t)1 << 53,
|
||||||
|
|
||||||
|
/** @brief Available 5 */
|
||||||
|
AVL5 = (uint64_t)1 << 54,
|
||||||
|
|
||||||
|
/** @brief Available 6 */
|
||||||
|
AVL6 = (uint64_t)1 << 55,
|
||||||
|
|
||||||
|
/** @brief Available 7 */
|
||||||
|
AVL7 = (uint64_t)1 << 56,
|
||||||
|
|
||||||
|
/** @brief Available 8 */
|
||||||
|
AVL8 = (uint64_t)1 << 57,
|
||||||
|
|
||||||
|
/** @brief Available 9 */
|
||||||
|
AVL9 = (uint64_t)1 << 58,
|
||||||
|
|
||||||
|
/** @brief Protection Key 0 */
|
||||||
|
PK0 = (uint64_t)1 << 59,
|
||||||
|
|
||||||
|
/** @brief Protection Key 1 */
|
||||||
|
PK1 = (uint64_t)1 << 60,
|
||||||
|
|
||||||
|
/** @brief Protection Key 2 */
|
||||||
|
PK2 = (uint64_t)1 << 61,
|
||||||
|
|
||||||
|
/** @brief Protection Key 3 */
|
||||||
|
PK3 = (uint64_t)1 << 62,
|
||||||
|
|
||||||
|
/** @brief Execute Disable */
|
||||||
|
XD = (uint64_t)1 << 63
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef union __attribute__((packed))
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
bool Present : 1;
|
||||||
|
bool ReadWrite : 1;
|
||||||
|
bool UserSupervisor : 1;
|
||||||
|
bool WriteThrough : 1;
|
||||||
|
bool CacheDisable : 1;
|
||||||
|
bool Accessed : 1;
|
||||||
|
bool Dirty : 1;
|
||||||
|
bool PageSize : 1;
|
||||||
|
bool Global : 1;
|
||||||
|
uint8_t Available1 : 3;
|
||||||
|
bool PageAttributeTable : 1;
|
||||||
|
uint64_t Reserved : 39;
|
||||||
|
uint32_t Available2 : 7;
|
||||||
|
uint16_t ProtectionKey : 4;
|
||||||
|
bool ExecuteDisable : 1;
|
||||||
|
};
|
||||||
|
uint64_t raw;
|
||||||
|
} PDEData;
|
||||||
|
|
||||||
|
struct __attribute__((packed)) PageDirectoryEntry
|
||||||
|
{
|
||||||
|
PDEData Value;
|
||||||
|
void AddFlag(uint64_t Flag) { this->Value.raw |= Flag; }
|
||||||
|
void RemoveFlags(uint64_t Flag) { this->Value.raw &= ~Flag; }
|
||||||
|
void ClearFlags() { this->Value.raw = 0; }
|
||||||
|
void SetFlag(uint64_t Flag, bool Enabled)
|
||||||
|
{
|
||||||
|
this->Value.raw &= ~Flag;
|
||||||
|
if (Enabled)
|
||||||
|
this->Value.raw |= Flag;
|
||||||
|
}
|
||||||
|
bool GetFlag(uint64_t Flag) { return (this->Value.raw & Flag) > 0 ? true : false; }
|
||||||
|
uint64_t GetFlag() { return this->Value.raw; }
|
||||||
|
void SetAddress(uint64_t Address)
|
||||||
|
{
|
||||||
|
#if defined(__amd64__)
|
||||||
|
Address &= 0x000000FFFFFFFFFF;
|
||||||
|
this->Value.raw &= 0xFFF0000000000FFF;
|
||||||
|
this->Value.raw |= (Address << 12);
|
||||||
|
#elif defined(__i386__)
|
||||||
|
Address &= 0x000FFFFF;
|
||||||
|
this->Value.raw &= 0xFFC00003;
|
||||||
|
this->Value.raw |= (Address << 12);
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
Address &= 0x000000FFFFFFFFFF;
|
||||||
|
this->Value.raw &= 0xFFF0000000000FFF;
|
||||||
|
this->Value.raw |= (Address << 12);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
uint64_t GetAddress()
|
||||||
|
{
|
||||||
|
#if defined(__amd64__)
|
||||||
|
return (this->Value.raw & 0x000FFFFFFFFFF000) >> 12;
|
||||||
|
#elif defined(__i386__)
|
||||||
|
return (this->Value.raw & 0x003FFFFF000) >> 12;
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
return (this->Value.raw & 0x000FFFFFFFFFF000) >> 12;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PageTable
|
||||||
|
{
|
||||||
|
PageDirectoryEntry Entries[512];
|
||||||
|
} __attribute__((aligned(0x1000)));
|
||||||
|
|
||||||
|
class Physical
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
uint64_t TotalMemory = 0;
|
||||||
|
uint64_t FreeMemory = 0;
|
||||||
|
uint64_t ReservedMemory = 0;
|
||||||
|
uint64_t UsedMemory = 0;
|
||||||
|
uint64_t PageBitmapIndex = 0;
|
||||||
|
Bitmap PageBitmap;
|
||||||
|
|
||||||
|
void ReservePage(void *Address);
|
||||||
|
void ReservePages(void *Address, uint64_t PageCount);
|
||||||
|
void UnreservePage(void *Address);
|
||||||
|
void UnreservePages(void *Address, uint64_t PageCount);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Get Total Memory
|
||||||
|
*
|
||||||
|
* @return uint64_t
|
||||||
|
*/
|
||||||
|
uint64_t GetTotalMemory();
|
||||||
|
/**
|
||||||
|
* @brief Get Free Memory
|
||||||
|
*
|
||||||
|
* @return uint64_t
|
||||||
|
*/
|
||||||
|
uint64_t GetFreeMemory();
|
||||||
|
/**
|
||||||
|
* @brief Get Reserved Memory
|
||||||
|
*
|
||||||
|
* @return uint64_t
|
||||||
|
*/
|
||||||
|
uint64_t GetReservedMemory();
|
||||||
|
/**
|
||||||
|
* @brief Get Used Memory
|
||||||
|
*
|
||||||
|
* @return uint64_t
|
||||||
|
*/
|
||||||
|
uint64_t GetUsedMemory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Swap page
|
||||||
|
*
|
||||||
|
* @param Address Address of the page
|
||||||
|
* @return true if swap was successful
|
||||||
|
* @return false if swap was unsuccessful
|
||||||
|
*/
|
||||||
|
bool SwapPage(void *Address);
|
||||||
|
/**
|
||||||
|
* @brief Swap pages
|
||||||
|
*
|
||||||
|
* @param Address Address of the pages
|
||||||
|
* @param PageCount Number of pages
|
||||||
|
* @return true if swap was successful
|
||||||
|
* @return false if swap was unsuccessful
|
||||||
|
*/
|
||||||
|
bool SwapPages(void *Address, uint64_t PageCount);
|
||||||
|
/**
|
||||||
|
* @brief Unswap page
|
||||||
|
*
|
||||||
|
* @param Address Address of the page
|
||||||
|
* @return true if unswap was successful
|
||||||
|
* @return false if unswap was unsuccessful
|
||||||
|
*/
|
||||||
|
bool UnswapPage(void *Address);
|
||||||
|
/**
|
||||||
|
* @brief Unswap pages
|
||||||
|
*
|
||||||
|
* @param Address Address of the pages
|
||||||
|
* @param PageCount Number of pages
|
||||||
|
* @return true if unswap was successful
|
||||||
|
* @return false if unswap was unsuccessful
|
||||||
|
*/
|
||||||
|
bool UnswapPages(void *Address, uint64_t PageCount);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Lock page
|
||||||
|
*
|
||||||
|
* @param Address Address of the page
|
||||||
|
*/
|
||||||
|
void LockPage(void *Address);
|
||||||
|
/**
|
||||||
|
* @brief Lock pages
|
||||||
|
*
|
||||||
|
* @param Address Address of the pages
|
||||||
|
* @param PageCount Number of pages
|
||||||
|
*/
|
||||||
|
void LockPages(void *Address, uint64_t PageCount);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Request page
|
||||||
|
*
|
||||||
|
* @return void* Allocated page address
|
||||||
|
*/
|
||||||
|
void *RequestPage();
|
||||||
|
/**
|
||||||
|
* @brief Request pages
|
||||||
|
*
|
||||||
|
* @param PageCount Number of pages
|
||||||
|
* @return void* Allocated pages address
|
||||||
|
*/
|
||||||
|
void *RequestPages(uint64_t Count);
|
||||||
|
/**
|
||||||
|
* @brief Free page
|
||||||
|
*
|
||||||
|
* @param Address Address of the page
|
||||||
|
*/
|
||||||
|
void FreePage(void *Address);
|
||||||
|
/**
|
||||||
|
* @brief Free pages
|
||||||
|
*
|
||||||
|
* @param Address Address of the pages
|
||||||
|
* @param PageCount Number of pages
|
||||||
|
*/
|
||||||
|
void FreePages(void *Address, uint64_t Count);
|
||||||
|
/** @brief Do not use. */
|
||||||
|
void Init(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable);
|
||||||
|
/** @brief Do not use. */
|
||||||
|
Physical();
|
||||||
|
/** @brief Do not use. */
|
||||||
|
~Physical();
|
||||||
|
};
|
||||||
|
|
||||||
|
class Virtual
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
PageTable *Table = nullptr;
|
||||||
|
|
||||||
|
class PageMapIndexer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uint64_t PDP_i;
|
||||||
|
uint64_t PD_i;
|
||||||
|
uint64_t PT_i;
|
||||||
|
uint64_t P_i;
|
||||||
|
|
||||||
|
PageMapIndexer(uint64_t VirtualAddress)
|
||||||
|
{
|
||||||
|
#if defined(__amd64__)
|
||||||
|
PDP_i = (VirtualAddress & ((uint64_t)0x1FF << 39)) >> 39;
|
||||||
|
PD_i = (VirtualAddress & ((uint64_t)0x1FF << 30)) >> 30;
|
||||||
|
PT_i = (VirtualAddress & ((uint64_t)0x1FF << 21)) >> 21;
|
||||||
|
P_i = (VirtualAddress & ((uint64_t)0x1FF << 12)) >> 12;
|
||||||
|
#elif defined(__i386__)
|
||||||
|
PD_i = (VirtualAddress & ((uint64_t)0x3FF << 22)) >> 22;
|
||||||
|
PT_i = (VirtualAddress & ((uint64_t)0x3FF << 12)) >> 12;
|
||||||
|
P_i = (VirtualAddress & ((uint64_t)0xFFF << 0)) >> 0;
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
PD_i = (VirtualAddress & ((uint64_t)0x1FF << 30)) >> 30;
|
||||||
|
PT_i = (VirtualAddress & ((uint64_t)0x1FF << 21)) >> 21;
|
||||||
|
P_i = (VirtualAddress & ((uint64_t)0x1FF << 12)) >> 12;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Map page.
|
||||||
|
*
|
||||||
|
* @param VirtualAddress Virtual address of the page.
|
||||||
|
* @param PhysicalAddress Physical address of the page.
|
||||||
|
* @param Flags Flags of the page. Check PTFlag enum.
|
||||||
|
*/
|
||||||
|
void Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags);
|
||||||
|
/**
|
||||||
|
* @brief Map multiple pages.
|
||||||
|
*
|
||||||
|
* @param VirtualAddress First virtual address of the page.
|
||||||
|
* @param PhysicalAddress First physical address of the page.
|
||||||
|
* @param PageCount Number of pages.
|
||||||
|
* @param Flags Flags of the page. Check PTFlag enum.
|
||||||
|
*/
|
||||||
|
void Map(void *VirtualAddress, void *PhysicalAddress, uint64_t PageCount, uint64_t Flags);
|
||||||
|
/**
|
||||||
|
* @brief Unmap page.
|
||||||
|
*
|
||||||
|
* @param VirtualAddress Virtual address of the page.
|
||||||
|
*/
|
||||||
|
void Unmap(void *VirtualAddress);
|
||||||
|
/**
|
||||||
|
* @brief Unmap multiple pages.
|
||||||
|
*
|
||||||
|
* @param VirtualAddress First virtual address of the page.
|
||||||
|
* @param PageCount Number of pages.
|
||||||
|
*/
|
||||||
|
void Unmap(void *VirtualAddress, uint64_t PageCount);
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Virtual object
|
||||||
|
*
|
||||||
|
* @param Table Page table. If null, it will use the current page table.
|
||||||
|
*/
|
||||||
|
Virtual(PageTable *Table = nullptr);
|
||||||
|
/**
|
||||||
|
* @brief Destroy the Virtual object
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
~Virtual();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void *operator new(uint64_t Size);
|
||||||
|
void *operator new[](uint64_t Size);
|
||||||
|
void operator delete(void *Pointer);
|
||||||
|
void operator delete[](void *Pointer);
|
||||||
|
void operator delete(void *Pointer, long unsigned int Size);
|
||||||
|
void operator delete[](void *Pointer, long unsigned int Size);
|
||||||
|
|
||||||
|
extern Memory::Physical KernelAllocator;
|
||||||
|
extern Memory::PageTable *KernelPageTable;
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
EXTERNC void InitializeMemoryManagement(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable);
|
||||||
|
|
||||||
|
EXTERNC void *HeapMalloc(uint64_t Size);
|
||||||
|
EXTERNC void *HeapCalloc(uint64_t n, uint64_t Size);
|
||||||
|
EXTERNC void *HeapRealloc(void *Address, uint64_t Size);
|
||||||
|
EXTERNC void HeapFree(void *Address);
|
||||||
|
|
||||||
|
#define kmalloc(Size) HeapMalloc(Size)
|
||||||
|
#define kcalloc(n, Size) HeapCalloc(n, Size)
|
||||||
|
#define krealloc(Address, Size) HeapRealloc(Address, Size)
|
||||||
|
#define kfree(Address) HeapFree(Address)
|
||||||
|
|
||||||
|
#endif // !__FENNIX_KERNEL_INTERNAL_MEMORY_H__
|
33
Lynx/UEFI/src/bitmap.hpp
Normal file
33
Lynx/UEFI/src/bitmap.hpp
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef LYNX_BITMAP_TYPES_H
|
||||||
|
#define LYNX_BITMAP_TYPES_H
|
||||||
|
|
||||||
|
typedef __UINT8_TYPE__ uint8_t;
|
||||||
|
typedef __UINT16_TYPE__ uint16_t;
|
||||||
|
typedef __UINT32_TYPE__ uint32_t;
|
||||||
|
typedef __UINT64_TYPE__ uint64_t;
|
||||||
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
typedef __UINTPTR_TYPE__ uintptr_t;
|
||||||
|
#ifndef NULL
|
||||||
|
#define NULL ((void *)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ALIGN_UP(x, align) ((__typeof__(x))(((uint64_t)(x) + ((align)-1)) & (~((align)-1))))
|
||||||
|
#define ALIGN_DOWN(x, align) ((__typeof__(x))((x) & (~((align)-1))))
|
||||||
|
|
||||||
|
#endif // !LYNX_BITMAP_TYPES_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
class Bitmap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
size_t Size;
|
||||||
|
uint8_t *Buffer;
|
||||||
|
bool operator[](uint64_t index);
|
||||||
|
bool Set(uint64_t index, bool value);
|
||||||
|
bool Get(uint64_t index);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
157
Lynx/UEFI/src/cxxabi.cpp
Normal file
157
Lynx/UEFI/src/cxxabi.cpp
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
#ifndef LYNX_CXXABI_TYPES_H
|
||||||
|
#define LYNX_CXXABI_TYPES_H
|
||||||
|
|
||||||
|
typedef __UINT8_TYPE__ uint8_t;
|
||||||
|
typedef __UINT16_TYPE__ uint16_t;
|
||||||
|
typedef __UINT32_TYPE__ uint32_t;
|
||||||
|
typedef __UINT64_TYPE__ uint64_t;
|
||||||
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
typedef __UINTPTR_TYPE__ uintptr_t;
|
||||||
|
#ifndef NULL
|
||||||
|
#define NULL ((void *)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ALIGN_UP(x, align) ((__typeof__(x))(((uint64_t)(x) + ((align)-1)) & (~((align)-1))))
|
||||||
|
#define ALIGN_DOWN(x, align) ((__typeof__(x))((x) & (~((align)-1))))
|
||||||
|
|
||||||
|
#endif // !LYNX_CXXABI_TYPES_H
|
||||||
|
|
||||||
|
extern "C" void printf(const char *format, ...);
|
||||||
|
|
||||||
|
// TODO: complete implementation for everything
|
||||||
|
// TODO: https://wiki.osdev.org/C%2B%2B
|
||||||
|
|
||||||
|
#define ATEXIT_MAX_FUNCS 128
|
||||||
|
|
||||||
|
typedef unsigned uarch_t;
|
||||||
|
|
||||||
|
struct atexit_func_entry_t
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Each member is at least 4 bytes large. Such that each entry is 12bytes.
|
||||||
|
* 128 * 12 = 1.5KB exact.
|
||||||
|
**/
|
||||||
|
void (*destructor_func)(void *);
|
||||||
|
void *obj_ptr;
|
||||||
|
void *dso_handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
_URC_NO_REASON = 0,
|
||||||
|
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
|
||||||
|
_URC_FATAL_PHASE2_ERROR = 2,
|
||||||
|
_URC_FATAL_PHASE1_ERROR = 3,
|
||||||
|
_URC_NORMAL_STOP = 4,
|
||||||
|
_URC_END_OF_STACK = 5,
|
||||||
|
_URC_HANDLER_FOUND = 6,
|
||||||
|
_URC_INSTALL_CONTEXT = 7,
|
||||||
|
_URC_CONTINUE_UNWIND = 8
|
||||||
|
} _Unwind_Reason_Code;
|
||||||
|
|
||||||
|
struct _Unwind_Context;
|
||||||
|
typedef unsigned _Unwind_Exception_Class __attribute__((__mode__(__DI__)));
|
||||||
|
typedef unsigned _Unwind_Word __attribute__((__mode__(__unwind_word__)));
|
||||||
|
typedef void (*_Unwind_Exception_Cleanup_Fn)(_Unwind_Reason_Code, struct _Unwind_Exception *);
|
||||||
|
typedef int _Unwind_Action;
|
||||||
|
|
||||||
|
struct _Unwind_Exception
|
||||||
|
{
|
||||||
|
_Unwind_Exception_Class exception_class;
|
||||||
|
_Unwind_Exception_Cleanup_Fn exception_cleanup;
|
||||||
|
#if !defined(__USING_SJLJ_EXCEPTIONS__) && defined(__SEH__)
|
||||||
|
_Unwind_Word private_[6];
|
||||||
|
#else
|
||||||
|
_Unwind_Word private_1;
|
||||||
|
_Unwind_Word private_2;
|
||||||
|
#endif
|
||||||
|
} __attribute__((__aligned__));
|
||||||
|
|
||||||
|
extern void *__dso_handle = 0;
|
||||||
|
atexit_func_entry_t __atexit_funcs[ATEXIT_MAX_FUNCS];
|
||||||
|
uarch_t __atexit_func_count = 0;
|
||||||
|
|
||||||
|
extern "C" int __cxa_atexit(void (*f)(void *), void *objptr, void *dso)
|
||||||
|
{
|
||||||
|
printf("__cxa_atexit( %p %p %p ) triggered.", f, objptr, dso);
|
||||||
|
if (__atexit_func_count >= ATEXIT_MAX_FUNCS)
|
||||||
|
return -1;
|
||||||
|
__atexit_funcs[__atexit_func_count].destructor_func = f;
|
||||||
|
__atexit_funcs[__atexit_func_count].obj_ptr = objptr;
|
||||||
|
__atexit_funcs[__atexit_func_count].dso_handle = dso;
|
||||||
|
__atexit_func_count++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void __cxa_finalize(void *f)
|
||||||
|
{
|
||||||
|
printf("__cxa_finalize( %p ) triggered.", f);
|
||||||
|
uarch_t i = __atexit_func_count;
|
||||||
|
if (!f)
|
||||||
|
{
|
||||||
|
while (i--)
|
||||||
|
if (__atexit_funcs[i].destructor_func)
|
||||||
|
(*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i--)
|
||||||
|
if (__atexit_funcs[i].destructor_func == f)
|
||||||
|
{
|
||||||
|
(*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr);
|
||||||
|
__atexit_funcs[i].destructor_func = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" _Unwind_Reason_Code __gxx_personality_v0(int version, _Unwind_Action actions, _Unwind_Exception_Class exception_class, _Unwind_Exception *ue_header, _Unwind_Context *context)
|
||||||
|
{
|
||||||
|
printf("__gxx_personality_v0( %d %p %p %p %p ) triggered.", version, actions, exception_class, ue_header, context);
|
||||||
|
return _URC_NO_REASON;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void _Unwind_Resume(struct _Unwind_Exception *exc) { printf("_Unwind_Resume( %p ) triggered.", exc); }
|
||||||
|
|
||||||
|
extern "C" void *__cxa_allocate_exception(uint64_t thrown_size) throw()
|
||||||
|
{
|
||||||
|
printf("__cxa_allocate_exception( %#llu ) triggered.", thrown_size);
|
||||||
|
return (void *)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void __cxa_throw(void *thrown_object, void *tinfo, void (*dest)(void *)) { printf("__cxa_throw( %p %p %p ) triggered.", thrown_object, tinfo, dest); }
|
||||||
|
|
||||||
|
extern "C" void __cxa_rethrow() { printf("__cxa_rethrow() triggered."); }
|
||||||
|
|
||||||
|
extern "C" void __cxa_pure_virtual() { printf("__cxa_pure_virtual() triggered."); }
|
||||||
|
|
||||||
|
extern "C" void __cxa_throw_bad_array_new_length() { printf("__cxa_throw_bad_array_new_length() triggered."); }
|
||||||
|
|
||||||
|
extern "C" void __cxa_free_exception(void *thrown_exception) { printf("__cxa_free_exception( %p ) triggered.", thrown_exception); }
|
||||||
|
|
||||||
|
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)
|
||||||
|
extern "C" void *__cxa_begin_catch(void *e) throw()
|
||||||
|
#else
|
||||||
|
extern "C" void *__cxa_begin_catch(void *e)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
printf("__cxa_begin_catch( %p ) triggered.", e);
|
||||||
|
return (void *)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void __cxa_end_catch() { printf("__cxa_end_catch() triggered."); }
|
||||||
|
|
||||||
|
__extension__ typedef int __guard __attribute__((mode(__DI__)));
|
||||||
|
|
||||||
|
extern "C" int __cxa_guard_acquire(__guard *g)
|
||||||
|
{
|
||||||
|
printf("__cxa_guard_acquire( %p ) triggered.", g);
|
||||||
|
return !*(char *)(g);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void __cxa_guard_release(__guard *g)
|
||||||
|
{
|
||||||
|
printf("__cxa_guard_release( %p ) triggered.", g);
|
||||||
|
*(char *)g = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void __cxa_guard_abort(__guard *g) { printf("__cxa_guard_abort( %p ) triggered.", g); }
|
1606
Lynx/UEFI/src/printf.c
Normal file
1606
Lynx/UEFI/src/printf.c
Normal file
File diff suppressed because it is too large
Load Diff
195
Lynx/UEFI/src/printf.h
Normal file
195
Lynx/UEFI/src/printf.h
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
/**
|
||||||
|
* @author (c) Eyal Rozenberg <eyalroz1@gmx.com>
|
||||||
|
* 2021-2022, Haifa, Palestine/Israel
|
||||||
|
* @author (c) Marco Paland (info@paland.com)
|
||||||
|
* 2014-2019, PALANDesign Hannover, Germany
|
||||||
|
*
|
||||||
|
* @note Others have made smaller contributions to this file: see the
|
||||||
|
* contributors page at https://github.com/eyalroz/printf/graphs/contributors
|
||||||
|
* or ask one of the authors.
|
||||||
|
*
|
||||||
|
* @brief Small stand-alone implementation of the printf family of functions
|
||||||
|
* (`(v)printf`, `(v)s(n)printf` etc., geared towards use on embedded systems with
|
||||||
|
* a very limited resources.
|
||||||
|
*
|
||||||
|
* @note the implementations are thread-safe; re-entrant; use no functions from
|
||||||
|
* the standard library; and do not dynamically allocate any memory.
|
||||||
|
*
|
||||||
|
* @license The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PRINTF_H_
|
||||||
|
#define PRINTF_H_
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define ATTR_PRINTF(one_based_format_index, first_arg) \
|
||||||
|
__attribute__((format(__printf__, (one_based_format_index), (first_arg))))
|
||||||
|
#define ATTR_VPRINTF(one_based_format_index) ATTR_PRINTF((one_based_format_index), 0)
|
||||||
|
#else
|
||||||
|
#define ATTR_PRINTF((one_based_format_index), (first_arg))
|
||||||
|
#define ATTR_VPRINTF(one_based_format_index)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PRINTF_ALIAS_STANDARD_FUNCTION_NAMES
|
||||||
|
#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES
|
||||||
|
#define printf_ printf
|
||||||
|
#define sprintf_ sprintf
|
||||||
|
#define vsprintf_ vsprintf
|
||||||
|
#define snprintf_ snprintf
|
||||||
|
#define vsnprintf_ vsnprintf
|
||||||
|
#define vprintf_ vprintf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// If you want to include this implementation file directly rather than
|
||||||
|
// link against, this will let you control the functions' visibility,
|
||||||
|
// e.g. make them static so as not to clash with other objects also
|
||||||
|
// using them.
|
||||||
|
#ifndef PRINTF_VISIBILITY
|
||||||
|
#define PRINTF_VISIBILITY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints/send a single character to some opaque output entity
|
||||||
|
*
|
||||||
|
* @note This function is not implemented by the library, only declared; you must provide an
|
||||||
|
* implementation if you wish to use the @ref printf / @ref vprintf function (and possibly
|
||||||
|
* for linking against the library, if your toolchain does not support discarding unused functions)
|
||||||
|
*
|
||||||
|
* @note The output could be as simple as a wrapper for the `write()` system call on a Unix-like
|
||||||
|
* system, or even libc's @ref putchar , for replicating actual functionality of libc's @ref printf
|
||||||
|
* function; but on an embedded system it may involve interaction with a special output device,
|
||||||
|
* like a UART, etc.
|
||||||
|
*
|
||||||
|
* @note in libc's @ref putchar, the parameter type is an int; this was intended to support the
|
||||||
|
* representation of either a proper character or EOF in a variable - but this is really not
|
||||||
|
* meaningful to pass into @ref putchar and is discouraged today. See further discussion in:
|
||||||
|
* @link https://stackoverflow.com/q/17452847/1593077
|
||||||
|
*
|
||||||
|
* @param c the single character to print
|
||||||
|
*/
|
||||||
|
PRINTF_VISIBILITY
|
||||||
|
void putchar(char c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An implementation of the C standard's printf/vprintf
|
||||||
|
*
|
||||||
|
* @note you must implement a @ref putchar_ function for using this function - it invokes @ref putchar_
|
||||||
|
* rather than directly performing any I/O (which insulates it from any dependence on the operating system
|
||||||
|
* and external libraries).
|
||||||
|
*
|
||||||
|
* @param format A string specifying the format of the output, with %-marked specifiers of how to interpret
|
||||||
|
* additional arguments.
|
||||||
|
* @param arg Additional arguments to the function, one for each %-specifier in @p format string
|
||||||
|
* @return The number of characters written into @p s, not counting the terminating null character
|
||||||
|
*/
|
||||||
|
///@{
|
||||||
|
PRINTF_VISIBILITY
|
||||||
|
int printf_(const char *format, ...) ATTR_PRINTF(1, 2);
|
||||||
|
PRINTF_VISIBILITY
|
||||||
|
int vprintf_(const char *format, va_list arg) ATTR_VPRINTF(1);
|
||||||
|
///@}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An implementation of the C standard's sprintf/vsprintf
|
||||||
|
*
|
||||||
|
* @note For security considerations (the potential for exceeding the buffer bounds), please consider using
|
||||||
|
* the size-constrained variant, @ref snprintf / @ref vsnprintf , instead.
|
||||||
|
*
|
||||||
|
* @param s An array in which to store the formatted string. It must be large enough to fit the formatted
|
||||||
|
* output!
|
||||||
|
* @param format A string specifying the format of the output, with %-marked specifiers of how to interpret
|
||||||
|
* additional arguments.
|
||||||
|
* @param arg Additional arguments to the function, one for each specifier in @p format
|
||||||
|
* @return The number of characters written into @p s, not counting the terminating null character
|
||||||
|
*/
|
||||||
|
///@{
|
||||||
|
PRINTF_VISIBILITY
|
||||||
|
int sprintf_(char *s, const char *format, ...) ATTR_PRINTF(2, 3);
|
||||||
|
PRINTF_VISIBILITY
|
||||||
|
int vsprintf_(char *s, const char *format, va_list arg) ATTR_VPRINTF(2);
|
||||||
|
///@}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An implementation of the C standard's snprintf/vsnprintf
|
||||||
|
*
|
||||||
|
* @param s An array in which to store the formatted string. It must be large enough to fit either the
|
||||||
|
* entire formatted output, or at least @p n characters. Alternatively, it can be NULL, in which case
|
||||||
|
* nothing will be printed, and only the number of characters which _could_ have been printed is
|
||||||
|
* tallied and returned.
|
||||||
|
* @param n The maximum number of characters to write to the array, including a terminating null character
|
||||||
|
* @param format A string specifying the format of the output, with %-marked specifiers of how to interpret
|
||||||
|
* additional arguments.
|
||||||
|
* @param arg Additional arguments to the function, one for each specifier in @p format
|
||||||
|
* @return The number of characters that COULD have been written into @p s, not counting the terminating
|
||||||
|
* null character. A value equal or larger than @p n indicates truncation. Only when the returned value
|
||||||
|
* is non-negative and less than @p n, the null-terminated string has been fully and successfully printed.
|
||||||
|
*/
|
||||||
|
///@{
|
||||||
|
PRINTF_VISIBILITY
|
||||||
|
int snprintf_(char *s, size_t count, const char *format, ...) ATTR_PRINTF(3, 4);
|
||||||
|
PRINTF_VISIBILITY
|
||||||
|
int vsnprintf_(char *s, size_t count, const char *format, va_list arg) ATTR_VPRINTF(3);
|
||||||
|
///@}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* printf/vprintf with user-specified output function
|
||||||
|
*
|
||||||
|
* An alternative to @ref printf_, in which the output function is specified dynamically
|
||||||
|
* (rather than @ref putchar_ being used)
|
||||||
|
*
|
||||||
|
* @param out An output function which takes one character and a type-erased additional parameters
|
||||||
|
* @param extra_arg The type-erased argument to pass to the output function @p out with each call
|
||||||
|
* @param format A string specifying the format of the output, with %-marked specifiers of how to interpret
|
||||||
|
* additional arguments.
|
||||||
|
* @param arg Additional arguments to the function, one for each specifier in @p format
|
||||||
|
* @return The number of characters for which the output f unction was invoked, not counting the terminating null character
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
PRINTF_VISIBILITY
|
||||||
|
int fctprintf(void (*out)(char c, void *extra_arg), void *extra_arg, const char *format, ...) ATTR_PRINTF(3, 4);
|
||||||
|
PRINTF_VISIBILITY
|
||||||
|
int vfctprintf(void (*out)(char c, void *extra_arg), void *extra_arg, const char *format, va_list arg) ATTR_VPRINTF(3);
|
||||||
|
|
||||||
|
#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES
|
||||||
|
#undef printf_
|
||||||
|
#undef sprintf_
|
||||||
|
#undef vsprintf_
|
||||||
|
#undef snprintf_
|
||||||
|
#undef vsnprintf_
|
||||||
|
#undef vprintf_
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // PRINTF_H_
|
17
Lynx/UEFI/types.h
Normal file
17
Lynx/UEFI/types.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#ifndef LYNX_TYPES_H
|
||||||
|
#define LYNX_TYPES_H
|
||||||
|
|
||||||
|
typedef __UINT8_TYPE__ uint8_t;
|
||||||
|
typedef __UINT16_TYPE__ uint16_t;
|
||||||
|
typedef __UINT32_TYPE__ uint32_t;
|
||||||
|
typedef __UINT64_TYPE__ uint64_t;
|
||||||
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
typedef __UINTPTR_TYPE__ uintptr_t;
|
||||||
|
#ifndef NULL
|
||||||
|
#define NULL ((void *)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ALIGN_UP(x, align) ((__typeof__(x))(((uint64_t)(x) + ((align)-1)) & (~((align)-1))))
|
||||||
|
#define ALIGN_DOWN(x, align) ((__typeof__(x))((x) & (~((align)-1))))
|
||||||
|
|
||||||
|
#endif // !LYNX_TYPES_H
|
Loading…
x
Reference in New Issue
Block a user