mirror of
https://github.com/EnderIce2/Fennix.git
synced 2025-05-25 22:14:34 +00:00
Merge remote-tracking branch 'Userspace/master'
This commit is contained in:
commit
ad09129401
@ -1 +0,0 @@
|
||||
Subproject commit 961ddd0bd8dec37743395d2b7f8b896132e87b1d
|
7
Userspace/.gitignore
vendored
Normal file
7
Userspace/.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
*.o
|
||||
*.map
|
||||
*.fex
|
||||
out/
|
||||
cache/*
|
||||
!cache/.gitkeep
|
||||
.dccache
|
6
Userspace/.gitmodules
vendored
Normal file
6
Userspace/.gitmodules
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
[submodule "apps/user/games/doomgeneric"]
|
||||
path = apps/user/games/doomgeneric
|
||||
url = https://github.com/Fennix-Project/doomgeneric.git
|
||||
[submodule "musl"]
|
||||
path = musl
|
||||
url = https://github.com/Fennix-Project/musl.git
|
28
Userspace/.vscode/c_boilerplates.code-snippets
vendored
Normal file
28
Userspace/.vscode/c_boilerplates.code-snippets
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"Fennix Kernel Header": {
|
||||
"prefix": [
|
||||
"head",
|
||||
],
|
||||
"body": [
|
||||
"#ifndef __FENNIX_LIBC_${2:header}_H__",
|
||||
"#define __FENNIX_LIBC_${2:header}_H__",
|
||||
"",
|
||||
"#include <types.h>",
|
||||
"",
|
||||
"$0",
|
||||
"",
|
||||
"#endif // !__FENNIX_LIBC_${2:header}_H__",
|
||||
""
|
||||
],
|
||||
"description": "Create kernel header."
|
||||
},
|
||||
"Fennix Kernel brief": {
|
||||
"prefix": [
|
||||
"brief",
|
||||
],
|
||||
"body": [
|
||||
"/** @brief $0 */"
|
||||
],
|
||||
"description": "Create kernel documentation brief."
|
||||
}
|
||||
}
|
107
Userspace/.vscode/c_cpp_properties.json
vendored
Normal file
107
Userspace/.vscode/c_cpp_properties.json
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Fennix x64 (Linux, GCC, debug)",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/out/include/**",
|
||||
"${workspaceFolder}/libs/include/**",
|
||||
"${workspaceFolder}/libs/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/x86_64-fennix-gcc",
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "c++20",
|
||||
"intelliSenseMode": "gcc-x64",
|
||||
"configurationProvider": "ms-vscode.makefile-tools",
|
||||
"compilerArgs": [
|
||||
// Compiler flags
|
||||
"-fPIC",
|
||||
"-fPIE",
|
||||
"-pie",
|
||||
"-march=x86-64",
|
||||
"-pipe",
|
||||
"-ffunction-sections",
|
||||
"-fno-builtin",
|
||||
|
||||
// C++ flags
|
||||
"-fexceptions",
|
||||
|
||||
// Linker flags
|
||||
"-fPIC",
|
||||
"-fPIE",
|
||||
"-pie",
|
||||
"-nostdlib",
|
||||
"-nodefaultlibs",
|
||||
"-nolibc",
|
||||
"-zmax-page-size=0x1000",
|
||||
"-static",
|
||||
|
||||
// VSCode flags
|
||||
"-ffreestanding",
|
||||
"-nostdinc",
|
||||
"-nostdinc++"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Fennix x32 (Linux, GCC, debug)",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/out/include/**",
|
||||
"${workspaceFolder}/libs/include/**",
|
||||
"${workspaceFolder}/libs/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-fennix-gcc",
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "c++20",
|
||||
"intelliSenseMode": "gcc-x86",
|
||||
"configurationProvider": "ms-vscode.makefile-tools",
|
||||
"compilerArgs": [
|
||||
// Compiler flags
|
||||
"-fPIC",
|
||||
"-fPIE",
|
||||
"-pie",
|
||||
"-march=i386",
|
||||
"-pipe",
|
||||
"-ffunction-sections",
|
||||
"-fno-builtin",
|
||||
|
||||
// C++ flags
|
||||
"-fexceptions",
|
||||
|
||||
// Linker flags
|
||||
"-fPIC",
|
||||
"-fPIE",
|
||||
"-pie",
|
||||
"-nostdlib",
|
||||
"-nodefaultlibs",
|
||||
"-nolibc",
|
||||
"-zmax-page-size=0x1000",
|
||||
"-static",
|
||||
|
||||
// VSCode flags
|
||||
"-ffreestanding",
|
||||
"-nostdinc",
|
||||
"-nostdinc++"
|
||||
]
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
122
Userspace/.vscode/launch.json
vendored
Normal file
122
Userspace/.vscode/launch.json
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "/bin/init",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/out/bin/init",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"args": [],
|
||||
"targetArchitecture": "x64",
|
||||
"MIMode": "gdb",
|
||||
"miDebuggerPath": "/usr/bin/gdb",
|
||||
"miDebuggerArgs": "",
|
||||
"externalConsole": false,
|
||||
"additionalSOLibSearchPath": "${workspaceFolder}",
|
||||
"customLaunchSetupCommands": [
|
||||
{
|
||||
"text": "target remote localhost:1234",
|
||||
"description": "Connect to QEMU remote debugger"
|
||||
}
|
||||
],
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"text": "set breakpoint pending on",
|
||||
"description": "Make breakpoint pending on future shared library load."
|
||||
},
|
||||
{
|
||||
"text": "file ${workspaceFolder}/out/bin/init",
|
||||
"description": "Load binary."
|
||||
},
|
||||
{
|
||||
"text": "add-symbol-file ${workspaceFolder}/../Kernel/fennix.elf",
|
||||
"description": "Load kernel binary."
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "/lib/ld.so",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/out/lib/ld.so",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"args": [],
|
||||
"targetArchitecture": "x64",
|
||||
"MIMode": "gdb",
|
||||
"miDebuggerPath": "/usr/bin/gdb",
|
||||
"miDebuggerArgs": "",
|
||||
"externalConsole": false,
|
||||
"additionalSOLibSearchPath": "${workspaceFolder}",
|
||||
"customLaunchSetupCommands": [
|
||||
{
|
||||
"text": "target remote localhost:1234",
|
||||
"description": "Connect to QEMU remote debugger"
|
||||
}
|
||||
],
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"text": "set breakpoint pending on",
|
||||
"description": "Make breakpoint pending on future shared library load."
|
||||
},
|
||||
{
|
||||
"text": "file ${workspaceFolder}/out/lib/ld.so",
|
||||
"description": "Load binary."
|
||||
},
|
||||
{
|
||||
"text": "add-symbol-file ${workspaceFolder}/../Kernel/fennix.elf",
|
||||
"description": "Load kernel binary."
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "/usr/bin/doom",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/out/usr/bin/doom",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"args": [],
|
||||
"targetArchitecture": "x64",
|
||||
"MIMode": "gdb",
|
||||
"miDebuggerPath": "/usr/bin/gdb",
|
||||
"miDebuggerArgs": "",
|
||||
"externalConsole": false,
|
||||
"additionalSOLibSearchPath": "${workspaceFolder}",
|
||||
"customLaunchSetupCommands": [
|
||||
{
|
||||
"text": "target remote localhost:1234",
|
||||
"description": "Connect to QEMU remote debugger"
|
||||
}
|
||||
],
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"text": "set breakpoint pending on",
|
||||
"description": "Make breakpoint pending on future shared library load."
|
||||
},
|
||||
{
|
||||
"text": "file ${workspaceFolder}/out/usr/bin/doom",
|
||||
"description": "Load binary."
|
||||
},
|
||||
{
|
||||
"text": "add-symbol-file ${workspaceFolder}/../Kernel/fennix.elf",
|
||||
"description": "Load kernel binary."
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
2659
Userspace/Doxyfile
Normal file
2659
Userspace/Doxyfile
Normal file
File diff suppressed because it is too large
Load Diff
29
Userspace/LICENSE
Normal file
29
Userspace/LICENSE
Normal file
@ -0,0 +1,29 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2023, 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.
|
80
Userspace/Makefile
Normal file
80
Userspace/Makefile
Normal file
@ -0,0 +1,80 @@
|
||||
# Config file
|
||||
include ../Makefile.conf
|
||||
|
||||
cwd := $(CURDIR)
|
||||
PREFIX := $(cwd)/out/
|
||||
TARGET := x86_64-fennix
|
||||
|
||||
export CROSS_COMPILE := $(cwd)/../tools/cross/bin/$(TARGET)-
|
||||
export CC := $(cwd)/../tools/cross/bin/$(TARGET)-gcc
|
||||
export LD := $(cwd)/../tools/cross/bin/$(TARGET)-ld
|
||||
export AR := $(cwd)/../tools/cross/bin/$(TARGET)-ar
|
||||
export STRIP := $(cwd)/../tools/cross/bin/$(TARGET)-strip
|
||||
export RANLIB := $(cwd)/../tools/cross/bin/$(TARGET)-ranlib
|
||||
export LD_LIBRARY_PATH := $(cwd)/out/lib/
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
export CFLAGS := --sysroot=$(cwd)/out/ -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fverbose-asm
|
||||
export LDFLAGS := -ggdb3 -O0
|
||||
else
|
||||
export CFLAGS := --sysroot=$(cwd)/out/
|
||||
endif
|
||||
|
||||
ifeq ($(USERSPACE_STATIC_LIBS), 1)
|
||||
MUSL_CONFIGURE_FLAGS := --enable-static --disable-shared
|
||||
else
|
||||
MUSL_CONFIGURE_FLAGS := --enable-shared --enable-static
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
MUSL_CONFIGURE_FLAGS += --enable-debug
|
||||
endif
|
||||
|
||||
build_musl:
|
||||
ifeq ($(wildcard cache/musl),)
|
||||
mkdir -p cache/musl
|
||||
cd cache/musl && \
|
||||
../../musl/configure --prefix=$(PREFIX) \
|
||||
--target=$(TARGET) --includedir=$(PREFIX)/include \
|
||||
$(MUSL_CONFIGURE_FLAGS)
|
||||
make -C cache/musl -j$(shell nproc)
|
||||
endif
|
||||
$(info Installing musl libc)
|
||||
cd cache/musl && make TARGET=$(TARGET) install
|
||||
# cp out/lib/crt1.o out/lib/crt0.o
|
||||
cd out/lib && ln -s /lib/libc.so ./ld-musl-x86_64.so.1 && \
|
||||
ln -s /lib/libc.so ./ld.so
|
||||
mkdir -p out/include/fennix
|
||||
cp ../Kernel/include/interface/syscalls.h out/include/fennix/syscall.h
|
||||
|
||||
create_out:
|
||||
rm -rf out
|
||||
mkdir -p out
|
||||
mkdir -p out/bin
|
||||
mkdir -p out/lib
|
||||
mkdir -p out/include
|
||||
mkdir -p out/usr/bin
|
||||
mkdir -p out/usr/share
|
||||
mkdir -p out/usr/share/doc
|
||||
mkdir -p out/usr/share/info
|
||||
mkdir -p out/usr/include
|
||||
|
||||
build: create_out
|
||||
ifeq ($(USE_LIBC), internal)
|
||||
make -C libc build
|
||||
else ifeq ($(USE_LIBC), musl)
|
||||
$(MAKE) build_musl
|
||||
endif
|
||||
make -C libs build
|
||||
make -C apps build
|
||||
|
||||
prepare:
|
||||
$(info Nothing to prepare)
|
||||
|
||||
clean:
|
||||
rm -rf out cache
|
||||
mkdir -p cache
|
||||
touch cache/.gitkeep
|
||||
make -C libc clean
|
||||
make -C libs clean
|
||||
make -C apps clean
|
11
Userspace/README.md
Normal file
11
Userspace/README.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Userspace
|
||||
|
||||
This repo contains the userspace programs that are part of the Fennix operating system.
|
||||
|
||||
---
|
||||
|
||||
Use `Fennix` repo to build the operating system.
|
||||
|
||||
```bash
|
||||
git clone --recurse-submodules https://github.com/Fennix-Project/Fennix.git
|
||||
```
|
9
Userspace/apps/Makefile
Normal file
9
Userspace/apps/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
build:
|
||||
make -C base build
|
||||
make -C system build
|
||||
make -C user build
|
||||
|
||||
clean:
|
||||
make -C base clean
|
||||
make -C system clean
|
||||
make -C user clean
|
33
Userspace/apps/base/Makefile
Normal file
33
Userspace/apps/base/Makefile
Normal file
@ -0,0 +1,33 @@
|
||||
# Config file
|
||||
include ../../../Makefile.conf
|
||||
|
||||
cwd := $(CURDIR)
|
||||
CACHE_DIR := $(cwd)/../../cache
|
||||
PREFIX := $(cwd)/../../out/
|
||||
TARGET := x86_64-fennix
|
||||
|
||||
export CC := $(cwd)/../../../tools/cross/bin/$(TARGET)-gcc
|
||||
export LD := $(cwd)/../../../tools/cross/bin/$(TARGET)-ld
|
||||
export AR := $(cwd)/../../../tools/cross/bin/$(TARGET)-ar
|
||||
export STRIP := $(cwd)/../../../tools/cross/bin/$(TARGET)-strip
|
||||
export RANLIB := $(cwd)/../../../tools/cross/bin/$(TARGET)-ranlib
|
||||
export LD_LIBRARY_PATH := $(cwd)/../../out/lib/
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
export CFLAGS := --sysroot=$(cwd)/../../out/ -I$(cwd)/../../out/include/ -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fverbose-asm
|
||||
export LDFLAGS := -ggdb3 -O0
|
||||
else
|
||||
export CFLAGS := --sysroot=$(cwd)/../../out/ -I$(cwd)/../../out/include/
|
||||
endif
|
||||
|
||||
build:
|
||||
make -C utest build
|
||||
make -C cross_test build
|
||||
make -C echo build
|
||||
make -C fsh build
|
||||
|
||||
clean:
|
||||
make -C utest clean
|
||||
make -C cross_test clean
|
||||
make -C echo clean
|
||||
make -C fsh clean
|
16
Userspace/apps/base/cross_test/Makefile
Normal file
16
Userspace/apps/base/cross_test/Makefile
Normal file
@ -0,0 +1,16 @@
|
||||
WORKSPACE := ../../../
|
||||
|
||||
# Config file
|
||||
include ../$(WORKSPACE)Makefile.conf
|
||||
|
||||
FILENAME = utest_
|
||||
|
||||
CFLAGS = -static -g -ggdb3 -O0
|
||||
|
||||
build:
|
||||
$(info Compiling $(FILENAME)linux)
|
||||
gcc linux_glibc.c $(CFLAGS) -o $(WORKSPACE)out/bin/$(FILENAME)linux
|
||||
$(info Compiling $(FILENAME)win)
|
||||
x86_64-w64-mingw32-gcc win_mingw.c $(CFLAGS) -o $(WORKSPACE)out/bin/$(FILENAME)win.exe
|
||||
|
||||
clean:
|
22
Userspace/apps/base/cross_test/expected_glibc.txt
Normal file
22
Userspace/apps/base/cross_test/expected_glibc.txt
Normal file
@ -0,0 +1,22 @@
|
||||
$ setarch `uname -m` -R strace ./utest_linux
|
||||
|
||||
execve("./utest_linux", ["./utest_linux"], 0x7fffffffdec0 /* 56 vars */) = 0
|
||||
arch_prctl(0x3001 /* ARCH_??? */, 0x7fffffffde40) = -1 EINVAL (Invalid argument)
|
||||
brk(NULL) = 0x4cd000
|
||||
brk(0x4cddc0) = 0x4cddc0
|
||||
arch_prctl(ARCH_SET_FS, 0x4cd3c0) = 0
|
||||
set_tid_address(0x4cd690) = 68565
|
||||
set_robust_list(0x4cd6a0, 24) = 0
|
||||
rseq(0x4cdd60, 0x20, 0, 0x53053053) = 0
|
||||
uname({sysname="Fennix", nodename="fennix", ...}) = 0
|
||||
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
|
||||
readlink("/proc/self/exe", "/bin/utest_linux"..., 4096) = 50
|
||||
getrandom("\x1e\x3c\x20\xdd\x09\xe8\x46\x0d", 8, GRND_NONBLOCK) = 8
|
||||
brk(0x4eedc0) = 0x4eedc0
|
||||
brk(0x4ef000) = 0x4ef000
|
||||
mprotect(0x4c1000, 16384, PROT_READ) = 0
|
||||
newfstatat(1, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x1), ...}, AT_EMPTY_PATH) = 0
|
||||
write(1, "Hello, World!\n", 14Hello, World!
|
||||
) = 14
|
||||
exit_group(0) = ?
|
||||
+++ exited with 0 +++
|
97
Userspace/apps/base/cross_test/linux_glibc.c
Normal file
97
Userspace/apps/base/cross_test/linux_glibc.c
Normal file
@ -0,0 +1,97 @@
|
||||
#define _POSIX_SOURCE
|
||||
#define _DEFAULT_SOURCE
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <pty.h>
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#ifndef __GLIBC__
|
||||
#define __GLIBC__ 0
|
||||
#endif
|
||||
|
||||
#ifndef __GLIBC_MINOR__
|
||||
#define __GLIBC_MINOR__ 0
|
||||
#endif
|
||||
|
||||
int ptmx_test()
|
||||
{
|
||||
int masterFD;
|
||||
int slaveFD;
|
||||
char slaveName[100];
|
||||
|
||||
masterFD = open("/dev/ptmx", O_RDWR | O_NOCTTY);
|
||||
if (masterFD < 0)
|
||||
{
|
||||
perror("Failed to open /dev/ptmx");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (grantpt(masterFD) < 0)
|
||||
{
|
||||
perror("Failed to grantpt");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (unlockpt(masterFD) < 0)
|
||||
{
|
||||
perror("Failed to unlockpt");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ptsname_r(masterFD, slaveName, sizeof(slaveName)) != 0)
|
||||
{
|
||||
perror("Failed to get slave name");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Slave terminal: %s\n", slaveName);
|
||||
|
||||
slaveFD = open(slaveName, O_RDWR | O_NOCTTY);
|
||||
if (slaveFD < 0)
|
||||
{
|
||||
perror("Failed to open slave terminal");
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct termios t;
|
||||
tcgetattr(slaveFD, &t);
|
||||
cfmakeraw(&t);
|
||||
tcsetattr(slaveFD, TCSANOW, &t);
|
||||
|
||||
char *message = "Hello from master!\n";
|
||||
write(masterFD, message, strlen(message));
|
||||
|
||||
char buffer[100];
|
||||
int len = read(slaveFD, buffer, sizeof(buffer) - 1);
|
||||
if (len > 0)
|
||||
{
|
||||
buffer[len] = '\0';
|
||||
printf("Received from slave: %s\n", buffer);
|
||||
}
|
||||
|
||||
close(masterFD);
|
||||
close(slaveFD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[], char *envp[])
|
||||
{
|
||||
printf("glibc %d.%d: Hello, World!\n", __GLIBC__, __GLIBC_MINOR__);
|
||||
fflush(stdout);
|
||||
ptmx_test();
|
||||
return 0;
|
||||
}
|
9
Userspace/apps/base/cross_test/win_mingw.c
Normal file
9
Userspace/apps/base/cross_test/win_mingw.c
Normal file
@ -0,0 +1,9 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char *argv[], char *envp[])
|
||||
{
|
||||
printf("mingw: Hello, World!\n");
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
}
|
66
Userspace/apps/base/echo/Makefile
Normal file
66
Userspace/apps/base/echo/Makefile
Normal file
@ -0,0 +1,66 @@
|
||||
WORKSPACE := ../../../
|
||||
|
||||
# Config file
|
||||
include ../$(WORKSPACE)Makefile.conf
|
||||
|
||||
CC = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
|
||||
CPP = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)g++
|
||||
LD = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)ld
|
||||
AS = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)as
|
||||
OBJDUMP = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)objdump
|
||||
|
||||
GIT_COMMIT = $(shell git rev-parse HEAD)
|
||||
GIT_COMMIT_SHORT = $(shell git rev-parse --short HEAD)
|
||||
|
||||
ifeq ($(OSARCH), amd64)
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*")
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*")
|
||||
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*")
|
||||
else ifeq ($(OSARCH), i386)
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
|
||||
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
|
||||
else ifeq ($(OSARCH), aarch64)
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/amd64/*" -not -path "./arch/i386/*")
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/amd64/*" -not -path "./arch/i386/*")
|
||||
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/amd64/*" -not -path "./arch/i386/*")
|
||||
endif
|
||||
OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(ASM_SOURCES:.asm=.o) $(S_SOURCES:.S=.o) $(PSF_SOURCES:.psf=.o) $(BMP_SOURCES:.bmp=.o)
|
||||
|
||||
SYSROOT = --sysroot=$(WORKSPACE)out/
|
||||
FILENAME = echo
|
||||
|
||||
HEADERS = $(sort $(dir $(wildcard $(WORKSPACE)out/include/*)))
|
||||
|
||||
LDFLAGS =
|
||||
CFLAGS = -I$(WORKSPACE)out/include \
|
||||
-DGIT_COMMIT='"$(GIT_COMMIT)"' \
|
||||
-DGIT_COMMIT_SHORT='"$(GIT_COMMIT_SHORT)"'
|
||||
WARNCFLAG = -Wall -Wextra
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fverbose-asm
|
||||
LDFLAGS += -ggdb3 -O0
|
||||
endif
|
||||
|
||||
build: $(FILENAME)
|
||||
mv $(FILENAME) $(WORKSPACE)out/bin/$(FILENAME)
|
||||
|
||||
$(FILENAME): $(OBJ)
|
||||
$(info Linking $@)
|
||||
$(CC) $(LDFLAGS) $(SYSROOT) $(OBJ) -o $@
|
||||
|
||||
%.o: %.c $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
||||
|
||||
%.o: %.cpp $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fexceptions -c $< -o $@ -fno-rtti
|
||||
|
||||
%.o: %.S
|
||||
$(info Compiling $<)
|
||||
$(AS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ)
|
59
Userspace/apps/base/echo/echo.c
Normal file
59
Userspace/apps/base/echo/echo.c
Normal file
@ -0,0 +1,59 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int enableEscapes = 0;
|
||||
int disableNewline = 0;
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "neE")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'n':
|
||||
disableNewline = 1;
|
||||
break;
|
||||
case 'e':
|
||||
enableEscapes = 1;
|
||||
break;
|
||||
case 'E':
|
||||
enableEscapes = 0;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
(void)enableEscapes;
|
||||
|
||||
size_t totalLength = 0;
|
||||
for (int i = optind; i < argc; ++i)
|
||||
totalLength += strlen(argv[i]) + 1;
|
||||
|
||||
char *result = (char *)malloc(totalLength);
|
||||
if (!result)
|
||||
{
|
||||
perror("Memory allocation error");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
result[0] = '\0';
|
||||
|
||||
for (int i = optind; i < argc; ++i)
|
||||
{
|
||||
strcat(result, argv[i]);
|
||||
if (i < argc - 1)
|
||||
strcat(result, " ");
|
||||
}
|
||||
|
||||
printf("%s", result);
|
||||
|
||||
if (!disableNewline)
|
||||
printf("\n");
|
||||
|
||||
free(result);
|
||||
return 0;
|
||||
}
|
66
Userspace/apps/base/fsh/Makefile
Normal file
66
Userspace/apps/base/fsh/Makefile
Normal file
@ -0,0 +1,66 @@
|
||||
WORKSPACE := ../../../
|
||||
|
||||
# Config file
|
||||
include ../$(WORKSPACE)Makefile.conf
|
||||
|
||||
CC = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
|
||||
CPP = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)g++
|
||||
LD = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)ld
|
||||
AS = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)as
|
||||
OBJDUMP = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)objdump
|
||||
|
||||
GIT_COMMIT = $(shell git rev-parse HEAD)
|
||||
GIT_COMMIT_SHORT = $(shell git rev-parse --short HEAD)
|
||||
|
||||
ifeq ($(OSARCH), amd64)
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*")
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*")
|
||||
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*")
|
||||
else ifeq ($(OSARCH), i386)
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
|
||||
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
|
||||
else ifeq ($(OSARCH), aarch64)
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/amd64/*" -not -path "./arch/i386/*")
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/amd64/*" -not -path "./arch/i386/*")
|
||||
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/amd64/*" -not -path "./arch/i386/*")
|
||||
endif
|
||||
OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(ASM_SOURCES:.asm=.o) $(S_SOURCES:.S=.o) $(PSF_SOURCES:.psf=.o) $(BMP_SOURCES:.bmp=.o)
|
||||
|
||||
SYSROOT = --sysroot=$(WORKSPACE)out/
|
||||
FILENAME = sh
|
||||
|
||||
HEADERS = $(sort $(dir $(wildcard $(WORKSPACE)out/include/*)))
|
||||
|
||||
LDFLAGS =
|
||||
CFLAGS = -I$(WORKSPACE)out/include \
|
||||
-DGIT_COMMIT='"$(GIT_COMMIT)"' \
|
||||
-DGIT_COMMIT_SHORT='"$(GIT_COMMIT_SHORT)"'
|
||||
WARNCFLAG = -Wall -Wextra
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fverbose-asm
|
||||
LDFLAGS += -ggdb3 -O0
|
||||
endif
|
||||
|
||||
build: $(FILENAME)
|
||||
mv $(FILENAME) $(WORKSPACE)out/bin/$(FILENAME)
|
||||
|
||||
$(FILENAME): $(OBJ)
|
||||
$(info Linking $@)
|
||||
$(CC) $(LDFLAGS) $(SYSROOT) $(OBJ) -o $@
|
||||
|
||||
%.o: %.c $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
||||
|
||||
%.o: %.cpp $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fexceptions -c $< -o $@ -fno-rtti
|
||||
|
||||
%.o: %.S
|
||||
$(info Compiling $<)
|
||||
$(AS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ)
|
160
Userspace/apps/base/fsh/fsh.c
Normal file
160
Userspace/apps/base/fsh/fsh.c
Normal file
@ -0,0 +1,160 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#define _GNU_SOURCE
|
||||
#include <signal.h>
|
||||
#include <termios.h>
|
||||
#define _POSIX_SOURCE
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_COMMAND_LENGTH 1024
|
||||
#define MAX_ARGS 10
|
||||
|
||||
void DisableInputBuffering()
|
||||
{
|
||||
struct termios tty_attr;
|
||||
tcgetattr(STDIN_FILENO, &tty_attr);
|
||||
tty_attr.c_lflag &= ~(ICANON | ECHO);
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &tty_attr);
|
||||
}
|
||||
|
||||
void EnableInputBuffering()
|
||||
{
|
||||
struct termios tty_attr;
|
||||
tcgetattr(STDIN_FILENO, &tty_attr);
|
||||
tty_attr.c_lflag |= ICANON | ECHO;
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &tty_attr);
|
||||
}
|
||||
|
||||
void ReadLine(char *Buffer, size_t BufferSize)
|
||||
{
|
||||
size_t index = 0;
|
||||
int c;
|
||||
while (1)
|
||||
{
|
||||
c = getchar();
|
||||
if (c == EOF || c == '\n')
|
||||
{
|
||||
Buffer[index] = '\0';
|
||||
break;
|
||||
}
|
||||
else if (c == 127 || c == 8) // Backspace
|
||||
{
|
||||
if (index > 0)
|
||||
{
|
||||
printf("\b \b");
|
||||
index--;
|
||||
}
|
||||
}
|
||||
else if (c == 4) // Ctrl + D
|
||||
{
|
||||
if (index == 0)
|
||||
kill(getpid(), SIGQUIT);
|
||||
else
|
||||
putchar('\a');
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index < BufferSize - 1)
|
||||
{
|
||||
putchar(c);
|
||||
Buffer[index] = (char)c;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExecuteCommand(char *command)
|
||||
{
|
||||
char *args[MAX_ARGS];
|
||||
int i = 0;
|
||||
|
||||
char *token = strtok(command, " ");
|
||||
while (token != NULL && i < MAX_ARGS - 1)
|
||||
{
|
||||
args[i++] = token;
|
||||
token = strtok(NULL, " ");
|
||||
}
|
||||
args[i] = NULL;
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid == 0)
|
||||
{
|
||||
execvp(args[0], args);
|
||||
perror("execvp");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
else if (pid > 0)
|
||||
wait(NULL);
|
||||
else
|
||||
{
|
||||
perror("fork");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void HandleSignal(int signal)
|
||||
{
|
||||
if (signal == SIGQUIT)
|
||||
{
|
||||
EnableInputBuffering();
|
||||
printf("\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
else if (signal == SIGINT)
|
||||
{
|
||||
putchar('\n');
|
||||
}
|
||||
else if (signal == SIGHUP)
|
||||
{
|
||||
EnableInputBuffering();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
else if (signal == SIGCHLD)
|
||||
wait(NULL);
|
||||
else if (signal == SIGSEGV)
|
||||
{
|
||||
printf("Segmentation fault\n");
|
||||
while (1)
|
||||
sleep(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Signal %s(%d) received\n",
|
||||
strsignal(signal), signal);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
char command[MAX_COMMAND_LENGTH];
|
||||
for (int i = 0; i < NSIG; ++i)
|
||||
signal(i, HandleSignal);
|
||||
|
||||
char hostname[256];
|
||||
gethostname(hostname, sizeof(hostname));
|
||||
|
||||
while (1)
|
||||
{
|
||||
printf("\033[1;32m");
|
||||
printf("┌──(%s@%s)-[%s]\n", getenv("USER"), hostname, getenv("PWD"));
|
||||
printf("└$ ");
|
||||
printf("\033[0m");
|
||||
|
||||
DisableInputBuffering();
|
||||
ReadLine(command, sizeof(command));
|
||||
EnableInputBuffering();
|
||||
putchar('\n');
|
||||
|
||||
if (strcmp(command, "exit") == 0)
|
||||
break;
|
||||
|
||||
ExecuteCommand(command);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
66
Userspace/apps/base/utest/Makefile
Normal file
66
Userspace/apps/base/utest/Makefile
Normal file
@ -0,0 +1,66 @@
|
||||
WORKSPACE := ../../../
|
||||
|
||||
# Config file
|
||||
include ../$(WORKSPACE)Makefile.conf
|
||||
|
||||
CC = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
|
||||
CPP = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)g++
|
||||
LD = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)ld
|
||||
AS = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)as
|
||||
OBJDUMP = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)objdump
|
||||
|
||||
GIT_COMMIT = $(shell git rev-parse HEAD)
|
||||
GIT_COMMIT_SHORT = $(shell git rev-parse --short HEAD)
|
||||
|
||||
ifeq ($(OSARCH), amd64)
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*")
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*")
|
||||
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*")
|
||||
else ifeq ($(OSARCH), i386)
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
|
||||
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
|
||||
else ifeq ($(OSARCH), aarch64)
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/amd64/*" -not -path "./arch/i386/*")
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/amd64/*" -not -path "./arch/i386/*")
|
||||
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/amd64/*" -not -path "./arch/i386/*")
|
||||
endif
|
||||
OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(ASM_SOURCES:.asm=.o) $(S_SOURCES:.S=.o) $(PSF_SOURCES:.psf=.o) $(BMP_SOURCES:.bmp=.o)
|
||||
|
||||
SYSROOT = --sysroot=$(WORKSPACE)out/
|
||||
FILENAME = utest
|
||||
|
||||
HEADERS = $(sort $(dir $(wildcard $(WORKSPACE)out/include/*)))
|
||||
|
||||
LDFLAGS = -static
|
||||
CFLAGS = -I$(WORKSPACE)out/include \
|
||||
-DGIT_COMMIT='"$(GIT_COMMIT)"' \
|
||||
-DGIT_COMMIT_SHORT='"$(GIT_COMMIT_SHORT)"' -static
|
||||
WARNCFLAG = -Wall -Wextra
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fverbose-asm
|
||||
LDFLAGS += -ggdb3 -O0
|
||||
endif
|
||||
|
||||
build: $(FILENAME)
|
||||
mv $(FILENAME) $(WORKSPACE)out/bin/$(FILENAME)
|
||||
|
||||
$(FILENAME): $(OBJ)
|
||||
$(info Linking $@)
|
||||
$(CC) $(LDFLAGS) $(SYSROOT) $(OBJ) -o $@
|
||||
|
||||
%.o: %.c $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
||||
|
||||
%.o: %.cpp $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fexceptions -c $< -o $@ -fno-rtti
|
||||
|
||||
%.o: %.S
|
||||
$(info Compiling $<)
|
||||
$(AS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ)
|
953
Userspace/apps/base/utest/userspace_test.c
Normal file
953
Userspace/apps/base/utest/userspace_test.c
Normal file
@ -0,0 +1,953 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#define _POSIX_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/wait.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <fcntl.h>
|
||||
#include <pty.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <pwd.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define AT_NULL 0
|
||||
#define AT_IGNORE 1
|
||||
#define AT_EXECFD 2
|
||||
#define AT_PHDR 3
|
||||
#define AT_PHENT 4
|
||||
#define AT_PHNUM 5
|
||||
#define AT_PAGESZ 6
|
||||
#define AT_BASE 7
|
||||
#define AT_FLAGS 8
|
||||
#define AT_ENTRY 9
|
||||
#define AT_NOTELF 10
|
||||
#define AT_UID 11
|
||||
#define AT_EUID 12
|
||||
#define AT_GID 13
|
||||
#define AT_EGID 14
|
||||
#define AT_PLATFORM 15
|
||||
#define AT_HWCAP 16
|
||||
#define AT_CLKTCK 17
|
||||
#define AT_SECURE 23
|
||||
#define AT_BASE_PLATFORM 24
|
||||
#define AT_RANDOM 25
|
||||
#define AT_HWCAP2 26
|
||||
#define AT_EXECFN 31
|
||||
#define AT_SYSINFO 32
|
||||
#define AT_SYSINFO_EHDR 33
|
||||
#define AT_L1I_CACHESHAPE 34
|
||||
#define AT_L1D_CACHESHAPE 35
|
||||
#define AT_L2_CACHESHAPE 36
|
||||
#define AT_L3_CACHESHAPE 37
|
||||
#define AT_L1I_CACHESIZE 40
|
||||
#define AT_L1I_CACHEGEOMETRY 41
|
||||
#define AT_L1D_CACHESIZE 42
|
||||
#define AT_L1D_CACHEGEOMETRY 43
|
||||
#define AT_L2_CACHESIZE 44
|
||||
#define AT_L2_CACHEGEOMETRY 45
|
||||
#define AT_L3_CACHESIZE 46
|
||||
#define AT_L3_CACHEGEOMETRY 47
|
||||
#define AT_MINSIGSTKSZ 51
|
||||
|
||||
#define EVENT_SIZE (sizeof(struct inotify_event))
|
||||
#define BUF_LEN (1024 * (EVENT_SIZE + 16))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t a_type;
|
||||
union
|
||||
{
|
||||
uint32_t a_val;
|
||||
} a_un;
|
||||
} Elf32_auxv_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint64_t a_type;
|
||||
union
|
||||
{
|
||||
uint64_t a_val;
|
||||
} a_un;
|
||||
} Elf64_auxv_t;
|
||||
|
||||
#ifdef __LP64__
|
||||
#define Elf_auxv_t Elf64_auxv_t
|
||||
#else
|
||||
#define Elf_auxv_t Elf32_auxv_t
|
||||
#endif
|
||||
|
||||
#define loop \
|
||||
while (1) \
|
||||
;
|
||||
|
||||
#define __musl_SYS_brk 12
|
||||
|
||||
static __inline long __musl_syscall1(long n, long a1)
|
||||
{
|
||||
unsigned long ret;
|
||||
__asm__ __volatile__("syscall"
|
||||
: "=a"(ret)
|
||||
: "a"(n), "D"(a1)
|
||||
: "rcx", "r11", "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
long __musl_syscall_ret(unsigned long r)
|
||||
{
|
||||
if (r > -4096UL)
|
||||
{
|
||||
errno = -r;
|
||||
return -1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void test_unaligned()
|
||||
{
|
||||
printf("- Testing unaligned access\n");
|
||||
|
||||
int *ptr = (int *)malloc(sizeof(int));
|
||||
uintptr_t unaligned_addr = (uintptr_t)ptr + 1;
|
||||
*(int *)unaligned_addr = 42;
|
||||
printf("%p->%p: %d\n", (void *)ptr,
|
||||
(void *)unaligned_addr,
|
||||
*(int *)unaligned_addr);
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
struct passwd *p = NULL;
|
||||
void test_passwd()
|
||||
{
|
||||
printf("- Testing passwd\n");
|
||||
|
||||
p = getpwuid(getuid());
|
||||
if (p == NULL)
|
||||
{
|
||||
perror("getpwuid");
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("name: %s\n", p->pw_name);
|
||||
printf("passwd: %s\n", p->pw_passwd);
|
||||
printf("uid: %d\n", p->pw_uid);
|
||||
printf("gid: %d\n", p->pw_gid);
|
||||
printf("gecos: %s\n", p->pw_gecos);
|
||||
printf("dir: %s\n", p->pw_dir);
|
||||
printf("shell: %s\n", p->pw_shell);
|
||||
}
|
||||
}
|
||||
|
||||
static void *heap_end = NULL;
|
||||
void *__libc_sbrk(intptr_t increment)
|
||||
{
|
||||
if (heap_end == NULL)
|
||||
{
|
||||
heap_end = (void *)__musl_syscall1(__musl_SYS_brk, 0);
|
||||
printf("SYS_brk(0) = %p\n", heap_end);
|
||||
|
||||
heap_end = (void *)__musl_syscall1(__musl_SYS_brk, (long)heap_end + 0x2000);
|
||||
printf("Adding 0x2000 to heap_end: %p\n", heap_end);
|
||||
}
|
||||
|
||||
if (increment == 0)
|
||||
{
|
||||
printf("Returning heap_end: %p\n", heap_end);
|
||||
return heap_end;
|
||||
}
|
||||
|
||||
void *old_heap_end = heap_end;
|
||||
|
||||
long ret = __musl_syscall1(__musl_SYS_brk, (long)heap_end + increment);
|
||||
printf("SYS_brk(%p) = %p\n", (void *)((long)heap_end + increment), (void *)ret);
|
||||
if (ret == 0)
|
||||
{
|
||||
heap_end = (void *)__musl_syscall1(__musl_SYS_brk, 0);
|
||||
printf("SYS_brk(0) = %p\n", heap_end);
|
||||
return old_heap_end;
|
||||
}
|
||||
|
||||
return (void *)__musl_syscall_ret(ret);
|
||||
}
|
||||
|
||||
void test_brk()
|
||||
{
|
||||
printf("- Testing brk\n");
|
||||
|
||||
void *current_brk = __libc_sbrk(0);
|
||||
printf("Initial break address: %p\n", current_brk);
|
||||
|
||||
void *new_brk = __libc_sbrk(0x1000);
|
||||
if (new_brk == (void *)-1)
|
||||
{
|
||||
perror("Error extending heap");
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
return;
|
||||
}
|
||||
printf("Heap extended successfully.\n");
|
||||
|
||||
printf("New break address: %p\n", new_brk);
|
||||
|
||||
if (__libc_sbrk(current_brk - new_brk) == (void *)-1)
|
||||
{
|
||||
perror("Error reducing heap");
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Heap reduced successfully.\n");
|
||||
printf("Current break address after reduction: %p\n", __libc_sbrk(0));
|
||||
|
||||
void *extended_brk = __libc_sbrk(0x1000);
|
||||
if (extended_brk == (void *)-1)
|
||||
{
|
||||
perror("Error extending heap after reduction");
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Heap extended successfully after reduction.\n");
|
||||
printf("New break address after extension: %p\n", extended_brk);
|
||||
|
||||
__libc_sbrk(-0x1000);
|
||||
}
|
||||
|
||||
void test_time()
|
||||
{
|
||||
printf("- Testing time\n");
|
||||
|
||||
struct tm time = {0};
|
||||
int Year = 2024;
|
||||
int Month = 1;
|
||||
int Day = 1;
|
||||
int Hour = 0;
|
||||
int Minute = 0;
|
||||
int Second = 0;
|
||||
|
||||
time.tm_year = Year - 1900;
|
||||
time.tm_mon = Month - 1;
|
||||
time.tm_mday = Day;
|
||||
time.tm_hour = Hour;
|
||||
time.tm_min = Minute;
|
||||
time.tm_sec = Second;
|
||||
|
||||
if (time.tm_year < 0)
|
||||
time.tm_year = 0;
|
||||
|
||||
time_t t = mktime(&time);
|
||||
if (t != (time_t)-1)
|
||||
stime(&t);
|
||||
else
|
||||
{
|
||||
perror("mktime");
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
|
||||
void test_args(int argc, char *argv[], char *envp[])
|
||||
{
|
||||
printf("- Testing args\n");
|
||||
|
||||
printf("%p %p %p\n",
|
||||
(void *)(uintptr_t)&argc,
|
||||
(void *)&argv,
|
||||
(void *)&envp);
|
||||
|
||||
printf("I have %d arguments\n", argc);
|
||||
for (int i = 0; i < argc; i++)
|
||||
printf("argv[%d] = (%p) %s\n", i, argv[i], argv[i]);
|
||||
|
||||
int envc = 0;
|
||||
while (envp[envc] != NULL)
|
||||
envc++;
|
||||
|
||||
printf("I have %d environment variables\n", envc);
|
||||
for (int i = 0; i < envc; i++)
|
||||
printf("envp[%d] = (%p) %s\n", i, envp[i], envp[i]);
|
||||
|
||||
Elf64_auxv_t *auxv;
|
||||
char **e = envp;
|
||||
|
||||
while (*e++ != NULL)
|
||||
;
|
||||
|
||||
for (auxv = (Elf64_auxv_t *)e; auxv->a_type != AT_NULL; auxv++)
|
||||
printf("auxv: %ld %#lx\n", auxv->a_type, auxv->a_un.a_val);
|
||||
}
|
||||
|
||||
void test_stdio()
|
||||
{
|
||||
printf("- Testing stdin\n");
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid < 0)
|
||||
{
|
||||
perror("fork");
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
return;
|
||||
}
|
||||
else if (pid != 0)
|
||||
return;
|
||||
|
||||
printf("Type a character: ");
|
||||
char c = getchar();
|
||||
printf("You typed: %c (%#x)\n", c, c);
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
ssize_t read;
|
||||
printf("Type a line: ");
|
||||
read = getline(&line, &len, stdin);
|
||||
printf("You typed: %s (%ld bytes)\n", line, read);
|
||||
free(line);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
void test_file()
|
||||
{
|
||||
printf("- Testing file operations\n");
|
||||
|
||||
FILE *test = fopen("/etc/passwd", "r");
|
||||
if (test == NULL)
|
||||
{
|
||||
perror("fopen");
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("/etc/passwd contents: ");
|
||||
char ch;
|
||||
while (1)
|
||||
{
|
||||
ch = fgetc(test);
|
||||
if (ch == EOF)
|
||||
{
|
||||
printf("\n");
|
||||
break;
|
||||
}
|
||||
putchar(ch);
|
||||
}
|
||||
fclose(test);
|
||||
}
|
||||
|
||||
void test_stat()
|
||||
{
|
||||
printf("- Testing stat\n");
|
||||
|
||||
struct stat st;
|
||||
if (stat("/etc/passwd", &st) == -1)
|
||||
{
|
||||
perror("stat");
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("File size: %ld\n", st.st_size);
|
||||
printf("File mode: %o\n", st.st_mode);
|
||||
printf("File inode: %ld\n", st.st_ino);
|
||||
|
||||
int fd = open("/etc/passwd", O_RDONLY);
|
||||
if (fd == -1)
|
||||
{
|
||||
perror("open");
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fstat(fd, &st) == -1)
|
||||
{
|
||||
perror("fstat");
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("File size: %ld\n", st.st_size);
|
||||
printf("File mode: %o\n", st.st_mode);
|
||||
printf("File inode: %ld\n", st.st_ino);
|
||||
close(fd);
|
||||
|
||||
if (lstat("/etc/passwd", &st) == -1)
|
||||
{
|
||||
perror("lstat");
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("File size: %ld\n", st.st_size);
|
||||
printf("File mode: %o\n", st.st_mode);
|
||||
printf("File inode: %ld\n", st.st_ino);
|
||||
}
|
||||
|
||||
void test_ptmx()
|
||||
{
|
||||
printf("- Testing PTMX\n");
|
||||
|
||||
int master, slave;
|
||||
char buffer[256];
|
||||
|
||||
if (openpty(&master, &slave, NULL, NULL, NULL) == -1)
|
||||
{
|
||||
perror("openpty");
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
return;
|
||||
}
|
||||
|
||||
write(master, "Hello, pty!\n", 12);
|
||||
ssize_t bytesRead = read(slave, buffer, sizeof(buffer));
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
buffer[bytesRead] = '\0';
|
||||
printf("Received from pty: %s", buffer);
|
||||
}
|
||||
|
||||
close(master);
|
||||
close(slave);
|
||||
}
|
||||
|
||||
void test_system()
|
||||
{
|
||||
printf("- Testing system()\n");
|
||||
int ret = system("echo Hello, world!");
|
||||
printf("system() returned %d\n", ret);
|
||||
}
|
||||
|
||||
int sigRec = 0;
|
||||
void signalHandler(int signo)
|
||||
{
|
||||
printf("Signal %s received\n", strsignal(signo));
|
||||
sigRec++;
|
||||
}
|
||||
|
||||
int expect_sighup = 0;
|
||||
void sighupHandler(int)
|
||||
{
|
||||
if (expect_sighup == 0)
|
||||
assert(!"SIGHUP received");
|
||||
else
|
||||
printf("SIGHUP received\n");
|
||||
}
|
||||
|
||||
void __sig_mask_test()
|
||||
{
|
||||
printf("- Testing signal masking\n");
|
||||
signal(SIGHUP, sighupHandler);
|
||||
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGHUP);
|
||||
sigprocmask(SIG_BLOCK, &mask, NULL);
|
||||
|
||||
kill(getpid(), SIGHUP);
|
||||
sleep(1);
|
||||
|
||||
expect_sighup = 1;
|
||||
sigprocmask(SIG_UNBLOCK, &mask, NULL);
|
||||
sleep(1);
|
||||
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
expect_sighup = 0;
|
||||
kill(getpid(), SIGHUP);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
void __sig_mask_all()
|
||||
{
|
||||
printf("- Testing all signal masking\n");
|
||||
sigset_t mask;
|
||||
sigfillset(&mask);
|
||||
sigprocmask(SIG_BLOCK, &mask, NULL);
|
||||
sigprocmask(SIG_UNBLOCK, &mask, NULL);
|
||||
}
|
||||
|
||||
void test_signal()
|
||||
{
|
||||
__sig_mask_all();
|
||||
__sig_mask_test();
|
||||
|
||||
printf("- Testing Signals\n");
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = signalHandler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sigaction(SIGHUP, &sa, NULL);
|
||||
|
||||
signal(SIGUSR1, signalHandler);
|
||||
signal(SIGUSR2, signalHandler);
|
||||
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGINT);
|
||||
sigaddset(&mask, SIGQUIT);
|
||||
sigprocmask(SIG_BLOCK, &mask, NULL);
|
||||
|
||||
printf("Sending SIGUSR1...\n");
|
||||
kill(getpid(), SIGUSR1);
|
||||
printf("Sending SIGUSR2...\n");
|
||||
kill(getpid(), SIGUSR2);
|
||||
printf("Sending SIGHUP...\n");
|
||||
kill(getpid(), SIGHUP);
|
||||
printf("Sending SIGINT...\n");
|
||||
kill(getpid(), SIGINT);
|
||||
printf("Sending SIGQUIT...\n");
|
||||
kill(getpid(), SIGQUIT);
|
||||
|
||||
printf("Signals sent\n");
|
||||
while (sigRec < 2)
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
void test_execve_fork()
|
||||
{
|
||||
printf("- Testing execve and fork\n");
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) // Child process
|
||||
{
|
||||
pid_t pid2 = fork();
|
||||
if (pid2 == 0) // Child process
|
||||
{
|
||||
char *shebangArgs[] = {"/test.sh", NULL};
|
||||
execv(shebangArgs[0], shebangArgs);
|
||||
perror("execv");
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
printf("Creating shell process\n");
|
||||
char *args[] = {"/bin/echo", "Hello World from echo!", NULL};
|
||||
execv(args[0], args);
|
||||
perror("execv");
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
else if (pid > 0)
|
||||
{
|
||||
printf("Waiting for child process %d to exit\n", pid);
|
||||
int status;
|
||||
waitpid(pid, &status, 0);
|
||||
printf("status=%#x\n", status);
|
||||
int exited = WIFEXITED(status);
|
||||
if (exited)
|
||||
{
|
||||
int exitCode = WEXITSTATUS(status);
|
||||
if (exitCode != 0)
|
||||
printf("Child process exited with code: %d\n", exitCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Execution failed. (exited=%d, status=%#x)\n", exited, status);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("fork");
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void test_dirent()
|
||||
{
|
||||
printf("- Testing dirent\n");
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
|
||||
dir = opendir("/etc");
|
||||
if (dir == NULL)
|
||||
{
|
||||
perror("opendir");
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Contents of the directory:\n");
|
||||
|
||||
int i = 0;
|
||||
while ((entry = readdir(dir)) != NULL)
|
||||
{
|
||||
printf("%s ", entry->d_name);
|
||||
if (++i % 5 == 0)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
char *create_file()
|
||||
{
|
||||
FILE *fp;
|
||||
char *path;
|
||||
|
||||
if (p == NULL)
|
||||
{
|
||||
path = malloc(24);
|
||||
sprintf(path, "/tmp/watched_file.txt");
|
||||
fp = fopen(path, "w");
|
||||
}
|
||||
else
|
||||
{
|
||||
path = malloc(strlen(p->pw_dir) + 24);
|
||||
sprintf(path, "%s/watched_file.txt", p->pw_dir);
|
||||
fp = fopen(path, "w");
|
||||
}
|
||||
|
||||
if (fp == NULL)
|
||||
{
|
||||
perror("fopen");
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
return path;
|
||||
}
|
||||
fclose(fp);
|
||||
return path;
|
||||
}
|
||||
|
||||
char *create_directory()
|
||||
{
|
||||
char *path;
|
||||
|
||||
if (p == NULL)
|
||||
{
|
||||
path = malloc(24);
|
||||
sprintf(path, "/tmp/watched_directory");
|
||||
}
|
||||
else
|
||||
{
|
||||
path = malloc(strlen(p->pw_dir) + 24);
|
||||
sprintf(path, "%s/watched_directory", p->pw_dir);
|
||||
}
|
||||
|
||||
if (mkdir(path, 0777) < 0)
|
||||
{
|
||||
perror("mkdir");
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
return path;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
void test_watch_file()
|
||||
{
|
||||
printf("- Testing file watching\n");
|
||||
pid_t pid = fork();
|
||||
if (pid < 0)
|
||||
{
|
||||
perror("fork");
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
return;
|
||||
}
|
||||
else if (pid != 0)
|
||||
return;
|
||||
|
||||
char *path = create_file();
|
||||
int fd, wd;
|
||||
char *buffer = malloc(BUF_LEN);
|
||||
|
||||
fd = inotify_init();
|
||||
if (fd < 0)
|
||||
{
|
||||
perror("inotify_init");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
wd = inotify_add_watch(fd, path,
|
||||
IN_OPEN | IN_MODIFY | IN_CLOSE);
|
||||
if (wd < 0)
|
||||
{
|
||||
perror("inotify_add_watch");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("Watching for changes in file.txt...\n");
|
||||
|
||||
while (1)
|
||||
{
|
||||
ssize_t len = read(fd, buffer, BUF_LEN);
|
||||
if (len < 0)
|
||||
{
|
||||
perror("read");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
struct inotify_event *event = (struct inotify_event *)buffer;
|
||||
if (event->mask & IN_MODIFY)
|
||||
printf("File modified!\n");
|
||||
else if (event->mask & IN_OPEN)
|
||||
printf("File opened!\n");
|
||||
else if (event->mask & IN_CLOSE)
|
||||
printf("File closed!\n");
|
||||
else
|
||||
printf("Unknown event!\n");
|
||||
}
|
||||
|
||||
inotify_rm_watch(fd, wd);
|
||||
close(fd);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
void test_watch_directory()
|
||||
{
|
||||
printf("- Testing directory watching\n");
|
||||
pid_t pid = fork();
|
||||
if (pid < 0)
|
||||
{
|
||||
perror("fork");
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
return;
|
||||
}
|
||||
else if (pid != 0)
|
||||
return;
|
||||
|
||||
char *path = create_directory();
|
||||
int fd, wd;
|
||||
char *buffer = malloc(BUF_LEN);
|
||||
|
||||
fd = inotify_init();
|
||||
if (fd < 0)
|
||||
{
|
||||
perror("inotify_init");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
wd = inotify_add_watch(fd, path,
|
||||
IN_OPEN | IN_CREATE | IN_DELETE | IN_MODIFY);
|
||||
if (wd < 0)
|
||||
{
|
||||
perror("inotify_add_watch");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("Watching for changes in the directory...\n");
|
||||
while (1)
|
||||
{
|
||||
ssize_t len = read(fd, buffer, BUF_LEN);
|
||||
if (len < 0)
|
||||
{
|
||||
perror("read");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
struct inotify_event *event = (struct inotify_event *)buffer;
|
||||
if (event->mask & IN_CREATE)
|
||||
printf("File created: %s\n", event->name);
|
||||
else if (event->mask & IN_DELETE)
|
||||
printf("File deleted: %s\n", event->name);
|
||||
else if (event->mask & IN_MODIFY)
|
||||
printf("File modified: %s\n", event->name);
|
||||
else if (event->mask & IN_OPEN)
|
||||
printf("File opened: %s\n", event->name);
|
||||
else
|
||||
printf("Unknown event!\n");
|
||||
}
|
||||
|
||||
inotify_rm_watch(fd, wd);
|
||||
close(fd);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
void shutdown_linux()
|
||||
{
|
||||
printf("- Testing shutdown\n");
|
||||
sync();
|
||||
reboot(RB_POWER_OFF);
|
||||
}
|
||||
|
||||
void reboot_linux()
|
||||
{
|
||||
printf("- Testing reboot\n");
|
||||
sync();
|
||||
reboot(RB_AUTOBOOT);
|
||||
}
|
||||
|
||||
void test_stdin()
|
||||
{
|
||||
printf("- Testing stdin\n");
|
||||
|
||||
while (1)
|
||||
{
|
||||
printf("Input: ");
|
||||
fflush(stdout);
|
||||
char input[256];
|
||||
fgets(input, sizeof(input), stdin);
|
||||
printf("%s", input);
|
||||
}
|
||||
}
|
||||
|
||||
void self_fork_exec()
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
int pid = fork();
|
||||
|
||||
// if (pid >= 10)
|
||||
// {
|
||||
// printf("[%d] Forked %d times, exiting...\n", getpid(), pid);
|
||||
// kill(getpid(), SIGTERM);
|
||||
// }
|
||||
|
||||
if (pid != 0)
|
||||
continue;
|
||||
|
||||
printf("[%d] Executing utest(%d)...\n", getpid(), getppid());
|
||||
char *a[] = {"/bin/utest", "loop", NULL};
|
||||
int b = execv(a[0], a);
|
||||
printf("Failed to execute utest: %d\n", b);
|
||||
}
|
||||
}
|
||||
|
||||
void fork_bomb()
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
printf("[%d] Forking...\n", getpid());
|
||||
int pid = fork();
|
||||
if (pid != 0)
|
||||
printf("[%d] Forked\n", pid);
|
||||
else
|
||||
printf("[%d] Child\n", getpid());
|
||||
sleep(5);
|
||||
}
|
||||
}
|
||||
|
||||
void fork_bomb_syscall()
|
||||
{
|
||||
#ifdef __x86_64__
|
||||
while (1)
|
||||
{
|
||||
printf("[%d] Forking...\n", getpid());
|
||||
unsigned long pid;
|
||||
__asm__ __volatile__("syscall" : "=a"(pid)
|
||||
: "a"(57 /* x86_64 SYS_fork */)
|
||||
: "rcx", "r11", "memory");
|
||||
if (pid != 0)
|
||||
printf("[%ld] Forked\n", pid);
|
||||
else
|
||||
printf("[%d] Child\n", getpid());
|
||||
sleep(5);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[], char *envp[])
|
||||
{
|
||||
if (argv[1] != NULL && strcmp(argv[1], "loop") == 0)
|
||||
{
|
||||
printf("[%d] Looping...\n", getpid());
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
printf("- Testing userspace...\n");
|
||||
|
||||
// printf("Press RETURN to start tests...\n");
|
||||
// char key = 0;
|
||||
// while (key != '\n' && key != '\r')
|
||||
// key = getchar();
|
||||
|
||||
// self_fork_exec();
|
||||
// fork_bomb();
|
||||
// fork_bomb_syscall();
|
||||
|
||||
// test_stdin();
|
||||
// test_stdio();
|
||||
test_unaligned();
|
||||
test_passwd();
|
||||
test_brk();
|
||||
test_time();
|
||||
test_signal();
|
||||
test_ptmx();
|
||||
test_args(argc, argv, envp);
|
||||
test_system();
|
||||
test_file();
|
||||
test_stat();
|
||||
test_dirent();
|
||||
test_execve_fork();
|
||||
test_watch_file();
|
||||
test_watch_directory();
|
||||
// shutdown_linux();
|
||||
// reboot_linux();
|
||||
|
||||
int status = 0;
|
||||
pid_t wpid;
|
||||
|
||||
printf("Waiting for child processes to exit...\n");
|
||||
while ((wpid = wait(&status)) > 0)
|
||||
sleep(2);
|
||||
|
||||
sync();
|
||||
printf("Userspace tests complete!\n");
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid < 0)
|
||||
{
|
||||
perror("fork");
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
return 1;
|
||||
}
|
||||
else if (pid == 0)
|
||||
{
|
||||
printf("Starting utest_linux...\n");
|
||||
char *args[] = {"/bin/utest_linux", NULL};
|
||||
int ret = execv(args[0], args);
|
||||
perror("execv");
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
waitpid(pid, &status, 0);
|
||||
|
||||
// check if exited normally, or crashed
|
||||
if (WIFSIGNALED(status))
|
||||
{
|
||||
int signal = WTERMSIG(status);
|
||||
printf("utest_linux exited with signal: %s\n", strsignal(signal));
|
||||
return signal;
|
||||
}
|
||||
else if (WIFEXITED(status))
|
||||
{
|
||||
int exitCode = WEXITSTATUS(status);
|
||||
if (exitCode != 0)
|
||||
{
|
||||
printf("utest_linux exited with code: %d\n", exitCode);
|
||||
return exitCode;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("utest_linux exited abnormally\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
5
Userspace/apps/system/Makefile
Normal file
5
Userspace/apps/system/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
build:
|
||||
make -C init build
|
||||
|
||||
clean:
|
||||
make -C init clean
|
70
Userspace/apps/system/init/Makefile
Normal file
70
Userspace/apps/system/init/Makefile
Normal file
@ -0,0 +1,70 @@
|
||||
WORKSPACE := ../../../
|
||||
|
||||
# Config file
|
||||
include ../$(WORKSPACE)Makefile.conf
|
||||
|
||||
CC = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
|
||||
CPP = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)g++
|
||||
LD = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)ld
|
||||
AS = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)as
|
||||
OBJDUMP = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)objdump
|
||||
|
||||
GIT_COMMIT = $(shell git rev-parse HEAD)
|
||||
GIT_COMMIT_SHORT = $(shell git rev-parse --short HEAD)
|
||||
|
||||
ifeq ($(OSARCH), amd64)
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*")
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*")
|
||||
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*")
|
||||
else ifeq ($(OSARCH), i386)
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
|
||||
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
|
||||
else ifeq ($(OSARCH), aarch64)
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/amd64/*" -not -path "./arch/i386/*")
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/amd64/*" -not -path "./arch/i386/*")
|
||||
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/amd64/*" -not -path "./arch/i386/*")
|
||||
endif
|
||||
OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(ASM_SOURCES:.asm=.o) $(S_SOURCES:.S=.o) $(PSF_SOURCES:.psf=.o) $(BMP_SOURCES:.bmp=.o)
|
||||
|
||||
SYSROOT = --sysroot=$(WORKSPACE)out/
|
||||
FILENAME = init
|
||||
|
||||
HEADERS = $(sort $(dir $(wildcard $(WORKSPACE)out/include/*)))
|
||||
|
||||
LDFLAGS =
|
||||
CFLAGS = -I$(WORKSPACE)out/include \
|
||||
-DGIT_COMMIT='"$(GIT_COMMIT)"' \
|
||||
-DGIT_COMMIT_SHORT='"$(GIT_COMMIT_SHORT)"'
|
||||
WARNCFLAG = -Wall -Wextra
|
||||
|
||||
ifneq ($(OSARCH), aarch64)
|
||||
# CFLAGS += -fstack-protector-all -fstack-clash-protection
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fverbose-asm
|
||||
LDFLAGS += -ggdb3 -O0
|
||||
endif
|
||||
|
||||
build: $(FILENAME)
|
||||
mv $(FILENAME) $(WORKSPACE)out/bin/$(FILENAME)
|
||||
|
||||
$(FILENAME): $(OBJ)
|
||||
$(info Linking $@)
|
||||
$(CC) $(LDFLAGS) $(SYSROOT) $(OBJ) -o $@
|
||||
|
||||
%.o: %.c $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
||||
|
||||
%.o: %.cpp $(HEADERS)
|
||||
$(info Compiling $<)
|
||||
$(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fexceptions -c $< -o $@ -fno-rtti
|
||||
|
||||
%.o: %.S
|
||||
$(info Compiling $<)
|
||||
$(AS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ)
|
6
Userspace/apps/system/init/init.c
Normal file
6
Userspace/apps/system/init/init.c
Normal file
@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int, char *[], char *[])
|
||||
{
|
||||
return 0;
|
||||
}
|
5
Userspace/apps/user/Makefile
Normal file
5
Userspace/apps/user/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
build:
|
||||
make -C games build
|
||||
|
||||
clean:
|
||||
make -C games clean
|
5
Userspace/apps/user/games/Makefile
Normal file
5
Userspace/apps/user/games/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
build:
|
||||
make -C doomgeneric build
|
||||
|
||||
clean:
|
||||
make -C doomgeneric clean
|
1
Userspace/apps/user/games/doomgeneric
Submodule
1
Userspace/apps/user/games/doomgeneric
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit b961b5551b5d56cc82bf8b14d43d41f859744344
|
0
Userspace/cache/.gitkeep
vendored
Normal file
0
Userspace/cache/.gitkeep
vendored
Normal file
70
Userspace/libc/ElfInterpreter/Makefile
Normal file
70
Userspace/libc/ElfInterpreter/Makefile
Normal file
@ -0,0 +1,70 @@
|
||||
# Config file
|
||||
include ../../../Makefile.conf
|
||||
|
||||
NAME=ld
|
||||
|
||||
OBJECT_NAME=$(NAME).so
|
||||
SO_NAME=$(OBJECT_NAME)
|
||||
|
||||
OUTPUT_DIR=../../out/lib/
|
||||
SYSROOT = --sysroot=../../out/
|
||||
|
||||
CC = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
|
||||
AS = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)as
|
||||
AR = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)ar
|
||||
OBJDUMP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)objdump
|
||||
NASM = /usr/bin/nasm
|
||||
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c')
|
||||
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp')
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S')
|
||||
ASM_SOURCES = $(shell find ./ -type f -name '*.asm')
|
||||
OBJ = ${C_SOURCES:.c=.o} ${CPP_SOURCES:.cpp=.o} ${ASM_SOURCES:.asm=.o} ${S_SOURCES:.S=.o}
|
||||
|
||||
INCLUDE = ../include
|
||||
|
||||
SIMD_FLAGS := -mno-sse -mno-sse2 -mno-sse3 -mno-ssse3 -mno-sse4.1 -mno-sse4.2 -mno-sse4 -mno-avx -mno-avx2 -mno-avx512f
|
||||
|
||||
CFLAGS := -I$(INCLUDE) $(SIMD_FLAGS) -fPIC
|
||||
LDFLAGS := -nostartfiles -nostdlib -Wl,-soname,$(SO_NAME) $(SYSROOT) -fno-pie -fno-PIC
|
||||
|
||||
ifeq ($(OSARCH), amd64)
|
||||
ASM_ARCH := elf64
|
||||
LDFLAGS += -Ttext=0xFFFFFFFFF0001000
|
||||
CFLAGS += -m64
|
||||
else ifeq ($(OSARCH), i386)
|
||||
ASM_ARCH := elf32
|
||||
LDFLAGS += -fixme
|
||||
CFLAGS += -m32
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fverbose-asm
|
||||
LDFLAGS += -ggdb3 -O0
|
||||
endif
|
||||
|
||||
build: $(OBJECT_NAME)
|
||||
|
||||
$(OBJECT_NAME): $(OBJ)
|
||||
$(info Linking $@)
|
||||
$(CC) $(LDFLAGS) $(OBJ) -o $(OUTPUT_DIR)$@
|
||||
$(OBJDUMP) -d $(OUTPUT_DIR)$@ > file_dump.map
|
||||
|
||||
%.o: %.c
|
||||
$(info Compiling $<)
|
||||
$(CC) $(CFLAGS) -std=c17 -c $< -o $@
|
||||
|
||||
%.o: %.cpp
|
||||
$(info Compiling $<)
|
||||
$(CC) $(CFLAGS) -std=c++20 -c $< -o $@
|
||||
|
||||
%.o: %.S
|
||||
$(info Compiling $<)
|
||||
$(AS) -c $< -o $@
|
||||
|
||||
%.o: %.asm
|
||||
$(info Compiling $<)
|
||||
$(NASM) $< -f $(ASM_ARCH) -o $@
|
||||
|
||||
clean:
|
||||
rm -f file_dump.map $(OBJ)
|
296
Userspace/libc/ElfInterpreter/elf.h
Normal file
296
Userspace/libc/ElfInterpreter/elf.h
Normal file
@ -0,0 +1,296 @@
|
||||
#ifndef __FENNIX_LIB_ELF_LAZY_RESOLVE_H__
|
||||
#define __FENNIX_LIB_ELF_LAZY_RESOLVE_H__
|
||||
|
||||
typedef __UINT32_TYPE__ Elf32_Addr;
|
||||
typedef __UINT16_TYPE__ Elf32_Half;
|
||||
typedef __UINT32_TYPE__ Elf32_Off;
|
||||
typedef __INT32_TYPE__ Elf32_Sword;
|
||||
typedef __UINT32_TYPE__ Elf32_Word;
|
||||
|
||||
typedef __UINT64_TYPE__ Elf64_Addr;
|
||||
typedef __UINT16_TYPE__ Elf64_Half;
|
||||
typedef __INT16_TYPE__ Elf64_SHalf;
|
||||
typedef __UINT64_TYPE__ Elf64_Off;
|
||||
typedef __INT32_TYPE__ Elf64_Sword;
|
||||
typedef __UINT32_TYPE__ Elf64_Word;
|
||||
typedef __UINT64_TYPE__ Elf64_Xword;
|
||||
typedef __INT64_TYPE__ Elf64_Sxword;
|
||||
|
||||
enum SectionHeaderType
|
||||
{
|
||||
SHT_NULL = 0,
|
||||
SHT_PROGBITS = 1,
|
||||
SHT_SYMTAB = 2,
|
||||
SHT_STRTAB = 3,
|
||||
SHT_RELA = 4,
|
||||
SHT_HASH = 5,
|
||||
SHT_DYNAMIC = 6,
|
||||
SHT_NOTE = 7,
|
||||
SHT_NOBITS = 8,
|
||||
SHT_REL = 9,
|
||||
SHT_SHLIB = 10,
|
||||
SHT_DYNSYM = 11,
|
||||
SHT_INIT_ARRAY = 14,
|
||||
SHT_FINI_ARRAY = 15,
|
||||
SHT_PREINIT_ARRAY = 16,
|
||||
SHT_GROUP = 17,
|
||||
SHT_SYMTAB_SHNDX = 18,
|
||||
SHT_NUM = 19,
|
||||
SHT_LOOS = 0x60000000,
|
||||
SHT_GNU_ATTRIBUTES = 0x6ffffff5,
|
||||
SHT_GNU_HASH = 0x6ffffff6,
|
||||
SHT_GNU_LIBLIST = 0x6ffffff7,
|
||||
SHT_CHECKSUM = 0x6ffffff8,
|
||||
SHT_LOSUNW = 0x6ffffffa,
|
||||
SHT_SUNW_move = 0x6ffffffa,
|
||||
SHT_SUNW_COMDAT = 0x6ffffffb,
|
||||
SHT_SUNW_syminfo = 0x6ffffffc,
|
||||
SHT_GNU_verdef = 0x6ffffffd,
|
||||
SHT_GNU_verneed = 0x6ffffffe,
|
||||
SHT_GNU_versym = 0x6fffffff,
|
||||
SHT_HISUNW = 0x6fffffff,
|
||||
SHT_HIOS = 0x6fffffff,
|
||||
SHT_LOPROC = 0x70000000,
|
||||
SHT_HIPROC = 0x7fffffff,
|
||||
SHT_LOUSER = 0x80000000,
|
||||
SHT_HIUSER = 0x8fffffff
|
||||
};
|
||||
|
||||
#define ELF32_R_SYM(i) ((i) >> 8)
|
||||
#define ELF32_R_TYPE(i) ((unsigned char)(i))
|
||||
#define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t))
|
||||
|
||||
#define ELF64_R_SYM(i) ((i) >> 32)
|
||||
#define ELF64_R_TYPE(i) ((i)&0xffffffffL)
|
||||
#define ELF64_R_INFO(s, t) (((s) << 32) + ((t)&0xffffffffL))
|
||||
|
||||
#define EI_NIDENT 16
|
||||
|
||||
#define SHN_UNDEF 0
|
||||
#define SHN_ABS 0xfff1
|
||||
|
||||
enum DynamicTags
|
||||
{
|
||||
DT_NULL = 0,
|
||||
DT_NEEDED = 1,
|
||||
DT_PLTRELSZ = 2,
|
||||
DT_PLTGOT = 3,
|
||||
DT_HASH = 4,
|
||||
DT_STRTAB = 5,
|
||||
DT_SYMTAB = 6,
|
||||
DT_RELA = 7,
|
||||
DT_RELASZ = 8,
|
||||
DT_RELAENT = 9,
|
||||
DT_STRSZ = 10,
|
||||
DT_SYMENT = 11,
|
||||
DT_INIT = 12,
|
||||
DT_FINI = 13,
|
||||
DT_SONAME = 14,
|
||||
DT_RPATH = 15,
|
||||
DT_SYMBOLIC = 16,
|
||||
DT_REL = 17,
|
||||
DT_RELSZ = 18,
|
||||
DT_RELENT = 19,
|
||||
DT_PLTREL = 20,
|
||||
DT_DEBUG = 21,
|
||||
DT_TEXTREL = 22,
|
||||
DT_JMPREL = 23,
|
||||
DT_BIND_NOW = 24,
|
||||
DT_INIT_ARRAY = 25,
|
||||
DT_FINI_ARRAY = 26,
|
||||
DT_INIT_ARRAYSZ = 27,
|
||||
DT_FINI_ARRAYSZ = 28,
|
||||
DT_RUNPATH = 29,
|
||||
DT_FLAGS = 30,
|
||||
DT_ENCODING = 32,
|
||||
DT_PREINIT_ARRAY = 32,
|
||||
DT_PREINIT_ARRAYSZ = 33,
|
||||
DT_LOOS = 0x6000000d,
|
||||
DT_SUNW_RTLDINF = 0x6000000e,
|
||||
DT_HIOS = 0x6ffff000,
|
||||
DT_VALRNGLO = 0x6ffffd00,
|
||||
DT_CHECKSUM = 0x6ffffdf8,
|
||||
DT_PLTPADSZ = 0x6ffffdf9,
|
||||
DT_MOVEENT = 0x6ffffdfa,
|
||||
DT_MOVESZ = 0x6ffffdfb,
|
||||
DT_FEATURE_1 = 0x6ffffdfc,
|
||||
DT_POSFLAG_1 = 0x6ffffdfd,
|
||||
DT_SYMINSZ = 0x6ffffdfe,
|
||||
DT_SYMINENT = 0x6ffffdff,
|
||||
DT_VALRNGHI = 0x6ffffdff,
|
||||
DT_ADDRRNGLO = 0x6ffffe00,
|
||||
DT_CONFIG = 0x6ffffefa,
|
||||
DT_DEPAUDIT = 0x6ffffefb,
|
||||
DT_AUDIT = 0x6ffffefc,
|
||||
DT_PLTPAD = 0x6ffffefd,
|
||||
DT_MOVETAB = 0x6ffffefe,
|
||||
DT_SYMINFO = 0x6ffffeff,
|
||||
DT_ADDRRNGHI = 0x6ffffeff,
|
||||
DT_RELACOUNT = 0x6ffffff9,
|
||||
DT_RELCOUNT = 0x6ffffffa,
|
||||
DT_FLAGS_1 = 0x6ffffffb,
|
||||
DT_VERDEF = 0x6ffffffc,
|
||||
DT_VERDEFNUM = 0x6ffffffd,
|
||||
DT_VERNEED = 0x6ffffffe,
|
||||
DT_VERNEEDNUM = 0x6fffffff,
|
||||
DT_LOPROC = 0x70000000,
|
||||
DT_SPARC_REGISTER = 0x70000001,
|
||||
DT_AUXILIARY = 0x7ffffffd,
|
||||
DT_USED = 0x7ffffffe,
|
||||
DT_FILTER = 0x7fffffff,
|
||||
DT_HIPROC = 0x7fffffff
|
||||
};
|
||||
|
||||
enum SegmentTypes
|
||||
{
|
||||
PT_NULL = 0,
|
||||
PT_LOAD = 1,
|
||||
PT_DYNAMIC = 2,
|
||||
PT_INTERP = 3,
|
||||
PT_NOTE = 4,
|
||||
PT_SHLIB = 5,
|
||||
PT_PHDR = 6,
|
||||
PT_TLS = 7,
|
||||
PT_LOSUNW = 0x6ffffffa,
|
||||
PT_SUNWBSS = 0x6ffffffb,
|
||||
PT_SUNWSTACK = 0x6ffffffa,
|
||||
PT_HISUNW = 0x6fffffff,
|
||||
PT_LOPROC = 0x70000000,
|
||||
PT_HIPROC = 0x7fffffff
|
||||
};
|
||||
|
||||
enum RtT_Types
|
||||
{
|
||||
R_386_NONE = 0,
|
||||
R_386_32 = 1,
|
||||
R_386_PC32 = 2,
|
||||
|
||||
R_X86_64_NONE = 0,
|
||||
R_X86_64_64 = 1,
|
||||
R_X86_64_PC32 = 2,
|
||||
R_X86_64_GOT32 = 3,
|
||||
R_X86_64_PLT32 = 4,
|
||||
R_X86_64_COPY = 5,
|
||||
R_X86_64_GLOB_DAT = 6,
|
||||
R_X86_64_JUMP_SLOT = 7,
|
||||
R_X86_64_RELATIVE = 8,
|
||||
R_X86_64_GOTPCREL = 9,
|
||||
R_X86_64_32 = 10,
|
||||
R_X86_64_32S = 11,
|
||||
R_X86_64_16 = 12,
|
||||
};
|
||||
|
||||
typedef struct elf32_hdr
|
||||
{
|
||||
unsigned char e_ident[EI_NIDENT];
|
||||
Elf32_Half e_type;
|
||||
Elf32_Half e_machine;
|
||||
Elf32_Word e_version;
|
||||
Elf32_Addr e_entry;
|
||||
Elf32_Off e_phoff;
|
||||
Elf32_Off e_shoff;
|
||||
Elf32_Word e_flags;
|
||||
Elf32_Half e_ehsize;
|
||||
Elf32_Half e_phentsize;
|
||||
Elf32_Half e_phnum;
|
||||
Elf32_Half e_shentsize;
|
||||
Elf32_Half e_shnum;
|
||||
Elf32_Half e_shstrndx;
|
||||
} Elf32_Ehdr;
|
||||
|
||||
typedef struct elf64_hdr
|
||||
{
|
||||
unsigned char e_ident[EI_NIDENT];
|
||||
Elf64_Half e_type;
|
||||
Elf64_Half e_machine;
|
||||
Elf64_Word e_version;
|
||||
Elf64_Addr e_entry;
|
||||
Elf64_Off e_phoff;
|
||||
Elf64_Off e_shoff;
|
||||
Elf64_Word e_flags;
|
||||
Elf64_Half e_ehsize;
|
||||
Elf64_Half e_phentsize;
|
||||
Elf64_Half e_phnum;
|
||||
Elf64_Half e_shentsize;
|
||||
Elf64_Half e_shnum;
|
||||
Elf64_Half e_shstrndx;
|
||||
} Elf64_Ehdr;
|
||||
|
||||
typedef struct elf32_shdr
|
||||
{
|
||||
Elf32_Word sh_name;
|
||||
Elf32_Word sh_type;
|
||||
Elf32_Word sh_flags;
|
||||
Elf32_Addr sh_addr;
|
||||
Elf32_Off sh_offset;
|
||||
Elf32_Word sh_size;
|
||||
Elf32_Word sh_link;
|
||||
Elf32_Word sh_info;
|
||||
Elf32_Word sh_addralign;
|
||||
Elf32_Word sh_entsize;
|
||||
} Elf32_Shdr;
|
||||
|
||||
typedef struct elf64_shdr
|
||||
{
|
||||
Elf64_Word sh_name;
|
||||
Elf64_Word sh_type;
|
||||
Elf64_Xword sh_flags;
|
||||
Elf64_Addr sh_addr;
|
||||
Elf64_Off sh_offset;
|
||||
Elf64_Xword sh_size;
|
||||
Elf64_Word sh_link;
|
||||
Elf64_Word sh_info;
|
||||
Elf64_Xword sh_addralign;
|
||||
Elf64_Xword sh_entsize;
|
||||
} Elf64_Shdr;
|
||||
|
||||
struct Elf32_Dyn
|
||||
{
|
||||
Elf32_Sword d_tag;
|
||||
union
|
||||
{
|
||||
Elf32_Word d_val;
|
||||
Elf32_Addr d_ptr;
|
||||
} d_un;
|
||||
};
|
||||
|
||||
struct Elf64_Dyn
|
||||
{
|
||||
Elf64_Sxword d_tag;
|
||||
union
|
||||
{
|
||||
Elf64_Xword d_val;
|
||||
Elf64_Addr d_ptr;
|
||||
} d_un;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Elf64_Word p_type;
|
||||
Elf64_Word p_flags;
|
||||
Elf64_Off p_offset;
|
||||
Elf64_Addr p_vaddr;
|
||||
Elf64_Addr p_paddr;
|
||||
Elf64_Xword p_filesz;
|
||||
Elf64_Xword p_memsz;
|
||||
Elf64_Xword p_align;
|
||||
} Elf64_Phdr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Elf64_Addr r_offset;
|
||||
Elf64_Xword r_info;
|
||||
Elf64_Sxword r_addend;
|
||||
} Elf64_Rela;
|
||||
|
||||
typedef struct elf64_sym
|
||||
{
|
||||
Elf64_Word st_name;
|
||||
unsigned char st_info;
|
||||
unsigned char st_other;
|
||||
Elf64_Half st_shndx;
|
||||
Elf64_Addr st_value;
|
||||
Elf64_Xword st_size;
|
||||
} Elf64_Sym;
|
||||
|
||||
#endif // !__FENNIX_LIB_ELF_LAZY_RESOLVE_H__
|
227
Userspace/libc/ElfInterpreter/fcts.c
Normal file
227
Userspace/libc/ElfInterpreter/fcts.c
Normal file
@ -0,0 +1,227 @@
|
||||
#include "fcts.h"
|
||||
|
||||
#include "../../../Kernel/syscalls.h"
|
||||
#include "../../../Kernel/ipc.h"
|
||||
|
||||
uintptr_t RequestPages(size_t Count)
|
||||
{
|
||||
return syscall6(sc_mmap, NULL, Count * 0x1000,
|
||||
sc_PROT_READ | sc_PROT_WRITE,
|
||||
sc_MAP_ANONYMOUS | sc_MAP_PRIVATE,
|
||||
0, 0);
|
||||
}
|
||||
|
||||
int FreePages(uintptr_t Address, size_t Count)
|
||||
{
|
||||
return syscall2(sc_munmap, Address, Count * 0x1000);
|
||||
}
|
||||
|
||||
int abs(int i) { return i < 0 ? -i : i; }
|
||||
|
||||
void swap(char *x, char *y)
|
||||
{
|
||||
char t = *x;
|
||||
*x = *y;
|
||||
*y = t;
|
||||
}
|
||||
|
||||
char *reverse(char *Buffer, int i, int j)
|
||||
{
|
||||
while (i < j)
|
||||
swap(&Buffer[i++], &Buffer[j--]);
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
char *ltoa(long Value, char *Buffer, int Base)
|
||||
{
|
||||
if (Base < 2 || Base > 32)
|
||||
return Buffer;
|
||||
|
||||
long n = (long)abs((int)Value);
|
||||
int i = 0;
|
||||
|
||||
while (n)
|
||||
{
|
||||
int r = n % Base;
|
||||
if (r >= 10)
|
||||
Buffer[i++] = 65 + (r - 10);
|
||||
else
|
||||
Buffer[i++] = 48 + r;
|
||||
n = n / Base;
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
Buffer[i++] = '0';
|
||||
|
||||
if (Value < 0 && Base == 10)
|
||||
Buffer[i++] = '-';
|
||||
|
||||
Buffer[i] = '\0';
|
||||
return reverse(Buffer, 0, i - 1);
|
||||
}
|
||||
|
||||
void PutCharToKernelConsole(char c)
|
||||
{
|
||||
__asm__ __volatile__("syscall"
|
||||
:
|
||||
: "a"(1), "D"(c), "S"(0)
|
||||
: "rcx", "r11", "memory");
|
||||
}
|
||||
|
||||
void Print__(char *String)
|
||||
{
|
||||
for (short i = 0; String[i] != '\0'; i++)
|
||||
PutCharToKernelConsole(String[i]);
|
||||
}
|
||||
|
||||
void PrintNL__(char *String)
|
||||
{
|
||||
Print__(String);
|
||||
Print__("\n");
|
||||
}
|
||||
|
||||
void *memcpy(void *dest, const void *src, size_t n)
|
||||
{
|
||||
uint8_t *d = dest;
|
||||
const uint8_t *s = src;
|
||||
while (n--)
|
||||
*d++ = *s++;
|
||||
return dest;
|
||||
}
|
||||
|
||||
void *memset(void *s, int c, size_t n)
|
||||
{
|
||||
uint8_t *p = s;
|
||||
while (n--)
|
||||
*p++ = c;
|
||||
}
|
||||
|
||||
int strcmp(const char *l, const char *r)
|
||||
{
|
||||
for (; *l == *r && *l; l++, r++)
|
||||
;
|
||||
return *(unsigned char *)l - *(unsigned char *)r;
|
||||
}
|
||||
|
||||
struct Elf64_Dyn ELFGetDynamicTag(char *Path, enum DynamicTags Tag)
|
||||
{
|
||||
int fd = syscall2(sc_open, Path, (long)"r");
|
||||
if (fd < 0)
|
||||
syscall1(sc_exit, -0xF17E);
|
||||
|
||||
Elf64_Ehdr ELFHeader;
|
||||
syscall3(sc_read, fd, &ELFHeader, sizeof(Elf64_Ehdr));
|
||||
|
||||
Elf64_Phdr ItrProgramHeader;
|
||||
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
|
||||
{
|
||||
// memcpy(&ItrProgramHeader, (uint8_t *)ElfFile + ELFHeader.e_phoff + ELFHeader.e_phentsize * i, sizeof(Elf64_Phdr));
|
||||
syscall3(sc_lseek, fd, ELFHeader.e_phoff + ELFHeader.e_phentsize * i, sc_SEEK_SET);
|
||||
syscall3(sc_read, fd, &ItrProgramHeader, sizeof(Elf64_Phdr));
|
||||
if (ItrProgramHeader.p_type == PT_DYNAMIC)
|
||||
{
|
||||
struct Elf64_Dyn Dynamic; // = (struct Elf64_Dyn *)((uint8_t *)ElfFile + ItrProgramHeader.p_offset);
|
||||
syscall3(sc_lseek, fd, ItrProgramHeader.p_offset, sc_SEEK_SET);
|
||||
syscall3(sc_read, fd, &Dynamic, ItrProgramHeader.p_filesz);
|
||||
for (size_t i = 0; i < ItrProgramHeader.p_filesz / sizeof(struct Elf64_Dyn); i++)
|
||||
{
|
||||
if (Dynamic.d_tag == Tag || Dynamic.d_tag == DT_NULL)
|
||||
{
|
||||
syscall1(sc_close, fd);
|
||||
return Dynamic;
|
||||
}
|
||||
|
||||
syscall3(sc_lseek, fd, ItrProgramHeader.p_offset + (i + 1) * sizeof(struct Elf64_Dyn), sc_SEEK_SET);
|
||||
syscall3(sc_read, fd, &Dynamic, sizeof(struct Elf64_Dyn));
|
||||
}
|
||||
}
|
||||
}
|
||||
syscall1(sc_close, fd);
|
||||
return (struct Elf64_Dyn){0};
|
||||
}
|
||||
|
||||
Elf64_Shdr *GetELFSheader(Elf64_Ehdr *Header)
|
||||
{
|
||||
Elf64_Off SheaderOffset = Header->e_shoff;
|
||||
return (Elf64_Shdr *)((uintptr_t)Header + SheaderOffset);
|
||||
}
|
||||
|
||||
Elf64_Shdr *GetELFSection(Elf64_Ehdr *Header, uint64_t Index)
|
||||
{
|
||||
Elf64_Shdr *Sheader = GetELFSheader(Header);
|
||||
return &Sheader[Index];
|
||||
}
|
||||
|
||||
char *GetELFStringTable(Elf64_Ehdr *Header)
|
||||
{
|
||||
if (Header->e_shstrndx == SHN_UNDEF)
|
||||
return NULL;
|
||||
return (char *)Header + GetELFSection(Header, Header->e_shstrndx)->sh_offset;
|
||||
}
|
||||
|
||||
Elf64_Sym ELFLookupSymbol(char *Path, const char *Name)
|
||||
{
|
||||
int fd = syscall2(sc_open, Path, (long)"r");
|
||||
if (fd < 0)
|
||||
syscall1(sc_exit, -0xF17E);
|
||||
|
||||
Elf64_Ehdr ELFHeader;
|
||||
syscall3(sc_read, fd, &ELFHeader, sizeof(Elf64_Ehdr));
|
||||
|
||||
Elf64_Shdr SymbolTable;
|
||||
Elf64_Shdr StringTable;
|
||||
Elf64_Sym Symbol;
|
||||
char *String = NULL;
|
||||
|
||||
for (Elf64_Half i = 0; i < ELFHeader.e_shnum; i++)
|
||||
{
|
||||
Elf64_Shdr shdr;
|
||||
syscall3(sc_lseek, fd,
|
||||
ELFHeader.e_shoff + ELFHeader.e_shentsize * i,
|
||||
sc_SEEK_SET);
|
||||
syscall3(sc_read, fd, &shdr, sizeof(Elf64_Shdr));
|
||||
|
||||
switch (shdr.sh_type)
|
||||
{
|
||||
case SHT_SYMTAB:
|
||||
{
|
||||
SymbolTable = shdr;
|
||||
syscall3(sc_lseek, fd,
|
||||
ELFHeader.e_shoff + ELFHeader.e_shentsize * shdr.sh_link,
|
||||
sc_SEEK_SET);
|
||||
syscall3(sc_read, fd, &StringTable, sizeof(Elf64_Shdr));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SymbolTable.sh_size == 0 || StringTable.sh_size == 0)
|
||||
{
|
||||
syscall1(sc_close, fd);
|
||||
return (Elf64_Sym){0};
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < (SymbolTable.sh_size / sizeof(Elf64_Sym)); i++)
|
||||
{
|
||||
// Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
|
||||
// String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name);
|
||||
syscall3(sc_lseek, fd, SymbolTable.sh_offset + (i * sizeof(Elf64_Sym)), sc_SEEK_SET);
|
||||
syscall3(sc_read, fd, &Symbol, sizeof(Elf64_Sym));
|
||||
|
||||
syscall3(sc_lseek, fd, StringTable.sh_offset + Symbol.st_name, sc_SEEK_SET);
|
||||
syscall3(sc_read, fd, &String, sizeof(char *));
|
||||
|
||||
if (strcmp(String, Name) == 0)
|
||||
{
|
||||
syscall1(sc_close, fd);
|
||||
return Symbol;
|
||||
}
|
||||
}
|
||||
|
||||
syscall1(sc_close, fd);
|
||||
return (Elf64_Sym){0};
|
||||
}
|
31
Userspace/libc/ElfInterpreter/fcts.h
Normal file
31
Userspace/libc/ElfInterpreter/fcts.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef __FENNIX_LIBC_FUNCTIONS_H__
|
||||
#define __FENNIX_LIBC_FUNCTIONS_H__
|
||||
|
||||
#include <types.h>
|
||||
#include "elf.h"
|
||||
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
uintptr_t RequestPages(size_t Count);
|
||||
int FreePages(uintptr_t Address, size_t Count);
|
||||
int IPC(int Command, int Type, int ID, int Flags, void *Buffer, size_t Size);
|
||||
uintptr_t KernelCTL(int Command, uint64_t Arg1, uint64_t Arg2, uint64_t Arg3, uint64_t Arg4);
|
||||
int abs(int i);
|
||||
void swap(char *x, char *y);
|
||||
char *reverse(char *Buffer, int i, int j);
|
||||
char *ltoa(long Value, char *Buffer, int Base);
|
||||
void PutCharToKernelConsole(char c);
|
||||
void Print__(char *String);
|
||||
void PrintNL__(char *String);
|
||||
void *memcpy(void *dest, const void *src, size_t n);
|
||||
void *memset(void *s, int c, size_t n);
|
||||
int strcmp(const char *l, const char *r);
|
||||
|
||||
struct Elf64_Dyn ELFGetDynamicTag(char *Path, enum DynamicTags Tag);
|
||||
Elf64_Shdr *GetELFSheader(Elf64_Ehdr *Header);
|
||||
Elf64_Shdr *GetELFSection(Elf64_Ehdr *Header, uint64_t Index);
|
||||
char *GetELFStringTable(Elf64_Ehdr *Header);
|
||||
Elf64_Sym ELFLookupSymbol(char *Path, const char *Name);
|
||||
|
||||
#endif // !__FENNIX_LIBC_FUNCTIONS_H__
|
14
Userspace/libc/ElfInterpreter/hash.c
Normal file
14
Userspace/libc/ElfInterpreter/hash.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include "ld.h"
|
||||
|
||||
uint32_t ElfHash(const unsigned char *Name)
|
||||
{
|
||||
uint32_t i = 0, j;
|
||||
while (*Name)
|
||||
{
|
||||
i = (i << 4) + *Name++;
|
||||
if ((j = i & 0xF0000000) != 0)
|
||||
i ^= j >> 24;
|
||||
i &= ~j;
|
||||
}
|
||||
return i;
|
||||
}
|
324
Userspace/libc/ElfInterpreter/ld.c
Normal file
324
Userspace/libc/ElfInterpreter/ld.c
Normal file
@ -0,0 +1,324 @@
|
||||
#include "ld.h"
|
||||
#include "fcts.h"
|
||||
|
||||
#include "../../../Kernel/syscalls.h"
|
||||
#include "../../../Kernel/ipc.h"
|
||||
#include "elf.h"
|
||||
|
||||
#define Print(x) Print__(x)
|
||||
#define PrintNL(x) PrintNL__(x)
|
||||
|
||||
#if (1)
|
||||
#define PrintDbg(x) Print__(x)
|
||||
#define PrintDbgNL(x) PrintNL__(x)
|
||||
#define ltoaDbg(x, y, z) ltoa(x, y, z)
|
||||
#else
|
||||
#define PrintDbg(x)
|
||||
#define PrintDbgNL(x)
|
||||
#define ltoaDbg(x, y, z)
|
||||
#endif
|
||||
|
||||
struct InterpreterIPCDataLibrary
|
||||
{
|
||||
char Name[64];
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char Path[256];
|
||||
void *MemoryImage;
|
||||
struct InterpreterIPCDataLibrary Libraries[64];
|
||||
} InterpreterIPCData;
|
||||
|
||||
struct LibsCollection
|
||||
{
|
||||
char ParentName[32];
|
||||
char LibraryName[32];
|
||||
uintptr_t ParentMemoryImage;
|
||||
uintptr_t LibraryMemoryImage;
|
||||
struct LibsCollection *Next;
|
||||
char Valid;
|
||||
};
|
||||
|
||||
static char ParentPath[256];
|
||||
static char Lock = 0;
|
||||
|
||||
__attribute__((naked, used, no_stack_protector)) void ELF_LAZY_RESOLVE_STUB()
|
||||
{
|
||||
while (Lock == 1)
|
||||
;
|
||||
__asm__ __volatile__("mfence\n");
|
||||
Lock = 1;
|
||||
__asm__ __volatile__("pop %r11\n"
|
||||
"pop %r10\n"
|
||||
|
||||
"push %rdi\n"
|
||||
"push %rsi\n"
|
||||
"push %rdx\n"
|
||||
"push %rcx\n"
|
||||
"push %r8\n"
|
||||
"push %r9\n"
|
||||
|
||||
"mov %r11, %rdi\n" // Move the first argument to rdi (libs collection)
|
||||
"mov %r10, %rsi\n" // Move the second argument to rsi (rel index)
|
||||
|
||||
"call ELF_LAZY_RESOLVE_MAIN\n"
|
||||
|
||||
"mov %rax, %r11\n" // Move the return value to r11
|
||||
|
||||
"pop %r9\n"
|
||||
"pop %r8\n"
|
||||
"pop %rcx\n"
|
||||
"pop %rdx\n"
|
||||
"pop %rsi\n"
|
||||
"pop %rdi\n"
|
||||
|
||||
"jmp *%r11\n"); // Jump to the return value
|
||||
}
|
||||
|
||||
void (*ELF_LAZY_RESOLVE_MAIN(struct LibsCollection *Info, long RelIndex))()
|
||||
{
|
||||
if (!Info)
|
||||
goto FailEnd;
|
||||
|
||||
char DbgBuff[32];
|
||||
char LibraryPathBuffer[256];
|
||||
|
||||
struct LibsCollection *CurLib = Info;
|
||||
PrintDbgNL("_______");
|
||||
/* The last entry is the null entry (Valid == false)
|
||||
which determines the end of the list. */
|
||||
while (CurLib->Valid)
|
||||
{
|
||||
PrintDbg("-- ");
|
||||
PrintDbg(LibraryPathBuffer);
|
||||
PrintDbg(" ");
|
||||
ltoaDbg(RelIndex, DbgBuff, 10);
|
||||
PrintDbg(DbgBuff);
|
||||
PrintDbgNL(" --");
|
||||
uintptr_t lib_BaseAddress = __UINTPTR_MAX__;
|
||||
uintptr_t app_BaseAddress = __UINTPTR_MAX__;
|
||||
|
||||
Elf64_Ehdr lib_Header;
|
||||
Elf64_Ehdr app_Header;
|
||||
|
||||
int fd_lib = syscall2(sc_open, LibraryPathBuffer, "r");
|
||||
int fd_app = syscall2(sc_open, ParentPath, "r");
|
||||
|
||||
if (fd_lib < 0)
|
||||
{
|
||||
PrintNL("Failed to open library");
|
||||
goto RetryNextLib;
|
||||
}
|
||||
|
||||
if (fd_app < 0)
|
||||
{
|
||||
PrintNL("Failed to open application");
|
||||
goto RetryNextLib;
|
||||
}
|
||||
|
||||
syscall3(sc_read, fd_lib, &lib_Header, sizeof(Elf64_Ehdr));
|
||||
syscall3(sc_read, fd_app, &app_Header, sizeof(Elf64_Ehdr));
|
||||
|
||||
Elf64_Phdr ItrProgramHeader;
|
||||
|
||||
for (Elf64_Half i = 0; i < lib_Header.e_phnum; i++)
|
||||
{
|
||||
syscall3(sc_lseek, fd_lib,
|
||||
lib_Header.e_phoff +
|
||||
lib_Header.e_phentsize * i,
|
||||
sc_SEEK_SET);
|
||||
|
||||
syscall3(sc_read, fd_lib, &ItrProgramHeader, sizeof(Elf64_Phdr));
|
||||
|
||||
lib_BaseAddress = MIN(lib_BaseAddress, ItrProgramHeader.p_vaddr);
|
||||
}
|
||||
|
||||
for (Elf64_Half i = 0; i < app_Header.e_phnum; i++)
|
||||
{
|
||||
syscall3(sc_lseek, fd_app,
|
||||
app_Header.e_phoff +
|
||||
app_Header.e_phentsize * i,
|
||||
sc_SEEK_SET);
|
||||
|
||||
syscall3(sc_read, fd_app, &ItrProgramHeader, sizeof(Elf64_Phdr));
|
||||
|
||||
app_BaseAddress = MIN(app_BaseAddress, ItrProgramHeader.p_vaddr);
|
||||
}
|
||||
|
||||
struct Elf64_Dyn lib_JmpRel = ELFGetDynamicTag(LibraryPathBuffer, DT_JMPREL);
|
||||
struct Elf64_Dyn lib_SymTab = ELFGetDynamicTag(LibraryPathBuffer, DT_SYMTAB);
|
||||
struct Elf64_Dyn lib_StrTab = ELFGetDynamicTag(LibraryPathBuffer, DT_STRTAB);
|
||||
|
||||
struct Elf64_Dyn app_JmpRel = ELFGetDynamicTag(ParentPath, DT_JMPREL);
|
||||
struct Elf64_Dyn app_SymTab = ELFGetDynamicTag(ParentPath, DT_SYMTAB);
|
||||
struct Elf64_Dyn app_StrTab = ELFGetDynamicTag(ParentPath, DT_STRTAB);
|
||||
|
||||
if (!lib_JmpRel.d_tag == 0)
|
||||
{
|
||||
PrintNL("No DT_JMPREL");
|
||||
// goto RetryNextLib;
|
||||
}
|
||||
else if (RelIndex >= lib_JmpRel.d_un.d_val /
|
||||
sizeof(Elf64_Rela))
|
||||
{
|
||||
PrintNL("RelIndex is greater than the number of relocations");
|
||||
goto RetryNextLib;
|
||||
}
|
||||
|
||||
if (!lib_SymTab.d_tag == 0)
|
||||
{
|
||||
PrintNL("No DT_SYMTAB");
|
||||
goto RetryNextLib;
|
||||
}
|
||||
|
||||
if (!lib_StrTab.d_tag == 0)
|
||||
{
|
||||
PrintNL("No DT_STRTAB");
|
||||
goto RetryNextLib;
|
||||
}
|
||||
|
||||
if (!lib_SymTab.d_tag == 0 &&
|
||||
!lib_StrTab.d_tag == 0)
|
||||
goto RetryNextLib;
|
||||
|
||||
Elf64_Rela *_lib_JmpRel = (Elf64_Rela *)(CurLib->LibraryMemoryImage + (lib_JmpRel.d_un.d_ptr - lib_BaseAddress));
|
||||
Elf64_Sym *_lib_SymTab = (Elf64_Sym *)(CurLib->LibraryMemoryImage + (lib_SymTab.d_un.d_ptr - lib_BaseAddress));
|
||||
|
||||
Elf64_Rela *_app_JmpRel = (Elf64_Rela *)(CurLib->ParentMemoryImage + (app_JmpRel.d_un.d_ptr - app_BaseAddress));
|
||||
Elf64_Sym *_app_SymTab = (Elf64_Sym *)(CurLib->ParentMemoryImage + (app_SymTab.d_un.d_ptr - app_BaseAddress));
|
||||
|
||||
char *lib_DynStr = (char *)(CurLib->LibraryMemoryImage + (lib_StrTab.d_un.d_ptr - lib_BaseAddress));
|
||||
char *app_DynStr = (char *)(CurLib->ParentMemoryImage + (app_StrTab.d_un.d_ptr - app_BaseAddress));
|
||||
|
||||
Elf64_Rela *Rel = _app_JmpRel + RelIndex;
|
||||
Elf64_Addr *GOTEntry = (Elf64_Addr *)(Rel->r_offset);
|
||||
|
||||
int RelType = ELF64_R_TYPE(Rel->r_info);
|
||||
|
||||
switch (RelType)
|
||||
{
|
||||
case R_X86_64_NONE:
|
||||
{
|
||||
PrintDbgNL("R_X86_64_NONE");
|
||||
if (*GOTEntry == 0)
|
||||
{
|
||||
PrintDbgNL("GOTEntry is 0");
|
||||
break;
|
||||
}
|
||||
Lock = 0;
|
||||
return (void (*)()) * GOTEntry;
|
||||
}
|
||||
case R_X86_64_JUMP_SLOT:
|
||||
{
|
||||
PrintDbgNL("R_X86_64_JUMP_SLOT");
|
||||
int SymIndex = ELF64_R_SYM(Rel->r_info);
|
||||
Elf64_Sym *Sym = _app_SymTab + SymIndex;
|
||||
|
||||
if (Sym->st_name)
|
||||
{
|
||||
char *SymName = app_DynStr + Sym->st_name;
|
||||
PrintDbg("SymName: ");
|
||||
PrintDbgNL(SymName);
|
||||
|
||||
Elf64_Sym LibSym = ELFLookupSymbol(ParentPath, SymName);
|
||||
|
||||
PrintDbg("LibSym: 0x");
|
||||
ltoaDbg((long)LibSym.st_size, DbgBuff, 16);
|
||||
PrintDbgNL(DbgBuff);
|
||||
|
||||
if (LibSym.st_value)
|
||||
{
|
||||
*GOTEntry = (Elf64_Addr)(CurLib->LibraryMemoryImage + LibSym.st_value);
|
||||
|
||||
ltoa(*GOTEntry, DbgBuff, 16);
|
||||
PrintDbg("*GOTEntry: 0x");
|
||||
PrintDbgNL(DbgBuff);
|
||||
|
||||
Lock = 0;
|
||||
return (void (*)()) * GOTEntry;
|
||||
}
|
||||
PrintDbgNL("Not found in lib");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
ltoa(RelType, DbgBuff, 10);
|
||||
Print("RelType not supported ");
|
||||
PrintNL(DbgBuff);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RetryNextLib:
|
||||
PrintDbgNL("Retrying next lib");
|
||||
CurLib = CurLib->Next;
|
||||
}
|
||||
|
||||
FailEnd:
|
||||
Lock = 0;
|
||||
__asm__ __volatile__("mfence\n");
|
||||
|
||||
Print("Symbol index ");
|
||||
ltoa(RelIndex, DbgBuff, 10);
|
||||
Print(DbgBuff);
|
||||
PrintNL(" not found");
|
||||
int ExitCode = 0x51801;
|
||||
syscall1(sc_exit, ExitCode);
|
||||
while (1) // Make sure we don't return
|
||||
;
|
||||
}
|
||||
|
||||
/* Preload */
|
||||
int ld_main()
|
||||
{
|
||||
/* Prevent race condition. */
|
||||
// uintptr_t KCTL_ret = KernelCTL(KCTL_IS_CRITICAL, 0, 0, 0, 0);
|
||||
// do
|
||||
// {
|
||||
// syscall1(sys_Sleep, 250);
|
||||
// KCTL_ret = KernelCTL(KCTL_IS_CRITICAL, 0, 0, 0, 0);
|
||||
// } while (KCTL_ret == false);
|
||||
|
||||
// if (KCTL_ret == false)
|
||||
// return -1;
|
||||
|
||||
/* Everything is ok, continue. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ELFAddLazyResolverToGOT(void *MemoryImage, struct LibsCollection *Libs)
|
||||
{
|
||||
struct Elf64_Dyn Dyn = ELFGetDynamicTag(ParentPath, DT_PLTGOT);
|
||||
if (!Dyn.d_tag)
|
||||
return false;
|
||||
|
||||
Elf64_Addr *GOT = (Elf64_Addr *)Dyn.d_un.d_ptr;
|
||||
|
||||
GOT[1] = (uintptr_t)Libs;
|
||||
GOT[2] = (uintptr_t)ELF_LAZY_RESOLVE_STUB;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Actual load */
|
||||
int ld_load(int argc, char *argv[], char *envp[])
|
||||
{
|
||||
PrintDbgNL("Calling entry point");
|
||||
|
||||
// void *KP = syscall2(sc_open, ParentPath, (long)"r");
|
||||
// if (KP == NULL)
|
||||
// {
|
||||
// PrintNL("Failed to open file");
|
||||
// syscall1(sys_Exit, -0xF17E);
|
||||
// }
|
||||
|
||||
// Elf64_Ehdr ELFHeader;
|
||||
// syscall3(sc_read, KP, &ELFHeader, sizeof(Elf64_Ehdr));
|
||||
|
||||
// Elf64_Addr Entry = ELFHeader.e_entry;
|
||||
|
||||
// syscall1(sys_FileClose, KP);
|
||||
|
||||
// return ((int (*)(int, char *[], char *[]))Entry)(argc, argv, envp);
|
||||
}
|
8
Userspace/libc/ElfInterpreter/ld.h
Normal file
8
Userspace/libc/ElfInterpreter/ld.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef __FENNIX_LIBC_LD_H__
|
||||
#define __FENNIX_LIBC_LD_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
uint32_t ElfHash(const unsigned char *Name);
|
||||
|
||||
#endif // !__FENNIX_LIBC_LD_H__
|
36
Userspace/libc/ElfInterpreter/ldstart.c
Normal file
36
Userspace/libc/ElfInterpreter/ldstart.c
Normal file
@ -0,0 +1,36 @@
|
||||
void __attribute__((naked, used, no_stack_protector)) _start()
|
||||
{
|
||||
__asm__("movq $0, %rbp\n"
|
||||
"pushq %rbp\n"
|
||||
"pushq %rbp\n"
|
||||
"movq %rsp, %rbp\n"
|
||||
|
||||
"pushq %rcx\n"
|
||||
"pushq %rdx\n"
|
||||
"pushq %rsi\n"
|
||||
"pushq %rdi\n"
|
||||
|
||||
"call ld_main\n"
|
||||
"movl %eax, %edi\n" // Move return value to edi
|
||||
"cmp $0, %edi\n" // Check if return value is 0
|
||||
"jne _exit\n" // If not, jump to _exit
|
||||
|
||||
"popq %rdi\n"
|
||||
"popq %rsi\n"
|
||||
"popq %rdx\n"
|
||||
"popq %rcx\n"
|
||||
|
||||
"call ld_load\n"
|
||||
"movl %eax, %edi\n" // Move return value to edi
|
||||
"call _exit"); // Call _exit
|
||||
}
|
||||
|
||||
void _exit(int Code)
|
||||
{
|
||||
__asm__ __volatile__("syscall"
|
||||
:
|
||||
: "a"(0), "D"(Code)
|
||||
: "rcx", "r11", "memory");
|
||||
while (1)
|
||||
;
|
||||
}
|
250
Userspace/libc/ElfInterpreter/unused_code
Normal file
250
Userspace/libc/ElfInterpreter/unused_code
Normal file
@ -0,0 +1,250 @@
|
||||
|
||||
/* This function is a mess and needs to be cleaned up. */
|
||||
bool ELFDynamicReallocation(void *ElfFile, void *MemoryImage)
|
||||
{
|
||||
debug("ELF dynamic reallocation for image at %#lx.", ElfFile);
|
||||
|
||||
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)ElfFile;
|
||||
uintptr_t BaseAddress = UINTPTR_MAX;
|
||||
size_t ElfAppSize = 0;
|
||||
Elf64_Phdr ItrPhdr;
|
||||
|
||||
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
|
||||
{
|
||||
memcpy(&ItrPhdr,
|
||||
(uint8_t *)ElfFile + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
|
||||
sizeof(Elf64_Phdr));
|
||||
BaseAddress = MIN(BaseAddress, ItrPhdr.p_vaddr);
|
||||
}
|
||||
|
||||
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
|
||||
{
|
||||
memcpy(&ItrPhdr,
|
||||
(uint8_t *)ElfFile + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
|
||||
sizeof(Elf64_Phdr));
|
||||
uintptr_t SegmentEnd = ItrPhdr.p_vaddr - BaseAddress + ItrPhdr.p_memsz;
|
||||
ElfAppSize = MAX(ElfAppSize, SegmentEnd);
|
||||
}
|
||||
|
||||
debug("BaseAddress: %#lx Size: %ld", BaseAddress, ElfAppSize);
|
||||
|
||||
Elf64_Dyn *_GOTEntry = (Elf64_Dyn *)ELFGetDynamicTag(ElfFile, DT_PLTGOT);
|
||||
Elf64_Dyn *_Rela = ELFGetDynamicTag(ElfFile, DT_RELA);
|
||||
Elf64_Dyn *_RelaEnt = ELFGetDynamicTag(ElfFile, DT_RELAENT);
|
||||
Elf64_Dyn *_JmpRel = ELFGetDynamicTag(ElfFile, DT_JMPREL);
|
||||
Elf64_Dyn *_SymTab = ELFGetDynamicTag(ElfFile, DT_SYMTAB);
|
||||
Elf64_Dyn *_StrTab = ELFGetDynamicTag(ElfFile, DT_STRTAB);
|
||||
Elf64_Dyn *RelaSize = ELFGetDynamicTag(ElfFile, DT_RELASZ);
|
||||
Elf64_Dyn *PltRelSize = ELFGetDynamicTag(ElfFile, DT_PLTRELSZ);
|
||||
|
||||
Elf64_Addr *GOTEntry = (Elf64_Addr *)((uintptr_t)(_GOTEntry->d_un.d_ptr - BaseAddress) + (uintptr_t)MemoryImage);
|
||||
Elf64_Dyn *Rela = (Elf64_Dyn *)((uintptr_t)(_Rela->d_un.d_ptr - BaseAddress) + (uintptr_t)MemoryImage);
|
||||
Elf64_Dyn *RelaEnt = (Elf64_Dyn *)((uintptr_t)(_RelaEnt->d_un.d_ptr - BaseAddress) + (uintptr_t)MemoryImage);
|
||||
Elf64_Dyn *JmpRel = (Elf64_Dyn *)((uintptr_t)(_JmpRel->d_un.d_ptr - BaseAddress) + (uintptr_t)MemoryImage);
|
||||
Elf64_Dyn *SymTab = (Elf64_Dyn *)((uintptr_t)(_SymTab->d_un.d_ptr - BaseAddress) + (uintptr_t)MemoryImage);
|
||||
Elf64_Dyn *StrTab = (Elf64_Dyn *)((uintptr_t)(_StrTab->d_un.d_ptr - BaseAddress) + (uintptr_t)MemoryImage);
|
||||
|
||||
debug("GOTEntry: %#lx [%#lx]", _GOTEntry, GOTEntry);
|
||||
debug("Rela: %#lx [%#lx]", _Rela, Rela);
|
||||
debug("RelaEnt: %#lx [%#lx]", _RelaEnt, RelaEnt);
|
||||
debug("JmpRel: %#lx [%#lx]", _JmpRel, JmpRel);
|
||||
debug("SymTab: %#lx [%#lx]", _SymTab, SymTab);
|
||||
debug("StrTab: %#lx [%#lx]", _StrTab, StrTab);
|
||||
if (RelaSize)
|
||||
debug("RelaSize: %ld", RelaSize->d_un.d_val);
|
||||
if (PltRelSize)
|
||||
debug("PltRelSize: %ld", PltRelSize->d_un.d_val);
|
||||
|
||||
Elf64_Xword PltRelSizeVal = PltRelSize ? PltRelSize->d_un.d_val : 0;
|
||||
Elf64_Xword RelaSizeVal = RelaSize ? RelaSize->d_un.d_val : 0;
|
||||
|
||||
Elf64_Xword PltRelSizeValCount = PltRelSizeVal / sizeof(Elf64_Rela);
|
||||
Elf64_Xword RelaSizeValCount = RelaSizeVal / sizeof(Elf64_Rela);
|
||||
|
||||
debug("PltRelSizeVal: %ld", PltRelSizeVal);
|
||||
debug("RelaSizeVal: %ld", RelaSizeVal);
|
||||
debug("PltRelSizeValCount: %ld", PltRelSizeValCount);
|
||||
debug("RelaSizeValCount: %ld", RelaSizeValCount);
|
||||
|
||||
for (Elf64_Xword i = 0; i < PltRelSizeValCount; i++)
|
||||
{
|
||||
Elf64_Rela *RelaF = (Elf64_Rela *)((uintptr_t)JmpRel + i);
|
||||
Elf64_Xword RelaType = ELF64_R_TYPE(RelaF->r_info);
|
||||
debug("Itr %ld Type %ld", i, RelaType);
|
||||
|
||||
switch (RelaType)
|
||||
{
|
||||
case R_X86_64_NONE:
|
||||
{
|
||||
debug("No relocation needed");
|
||||
break;
|
||||
}
|
||||
case R_X86_64_JUMP_SLOT:
|
||||
{
|
||||
debug("Relocation for jump slot");
|
||||
Elf64_Xword SymIndex = ELF64_R_SYM(RelaF->r_info);
|
||||
Elf64_Sym *Sym = (Elf64_Sym *)((uintptr_t)SymTab + SymIndex);
|
||||
char *SymName = (char *)((uintptr_t)StrTab + Sym->st_name);
|
||||
debug("Symbol %s at %#lx", SymName, Sym->st_value);
|
||||
|
||||
Elf64_Addr *GOTEntry = (Elf64_Addr *)RelaF->r_offset;
|
||||
if (Sym->st_value)
|
||||
{
|
||||
fixme("Not implemented");
|
||||
*GOTEntry = (Elf64_Addr)ElfFile + Sym->st_value;
|
||||
}
|
||||
// else
|
||||
// *GOTEntry = (Elf64_Addr)ElfLazyResolver;
|
||||
|
||||
// Elf64_Sym *Sym = (Elf64_Sym *)((uintptr_t)ElfFile + (uintptr_t)SymTab + ELF64_R_SYM(RelaF->r_info) * sizeof(Elf64_Sym));
|
||||
// char *SymName = (char *)((uintptr_t)ElfFile + (uintptr_t)StrTab + Sym->st_name);
|
||||
// void *SymAddr = (void *)Lib->Address + Sym->st_value;
|
||||
// debug("Symbol %s at %#lx", SymName, SymAddr);
|
||||
// *(void **)(RelaF->r_offset + (uintptr_t)ElfFile) = SymAddr;
|
||||
break;
|
||||
}
|
||||
case R_X86_64_RELATIVE:
|
||||
{
|
||||
debug("Relative relocation");
|
||||
uintptr_t *Ptr = (uintptr_t *)((uintptr_t)ElfFile + RelaF->r_offset);
|
||||
*Ptr = (uintptr_t)MemoryImage + RelaF->r_addend;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
fixme("RelaType %d", RelaType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Elf64_Xword i = 0; i < RelaSizeValCount; i++)
|
||||
{
|
||||
Elf64_Rela *RelaF = (Elf64_Rela *)((uintptr_t)ElfFile + (uintptr_t)Rela + i);
|
||||
Elf64_Xword RelaType = ELF64_R_TYPE(RelaF->r_info);
|
||||
debug("Itr %ld Type %ld", i, RelaType);
|
||||
|
||||
switch (RelaType)
|
||||
{
|
||||
case R_X86_64_NONE:
|
||||
{
|
||||
debug("No relocation needed");
|
||||
break;
|
||||
}
|
||||
case R_X86_64_64:
|
||||
{
|
||||
debug("64-bit relocation");
|
||||
Elf64_Xword SymIndex = ELF64_R_SYM(RelaF->r_info);
|
||||
Elf64_Sym *Sym = (Elf64_Sym *)((uintptr_t)ElfFile + (uintptr_t)SymTab + SymIndex);
|
||||
char *SymName = (char *)((uintptr_t)ElfFile + (uintptr_t)StrTab + Sym->st_name);
|
||||
debug("Symbol %s at %#lx", SymName, Sym->st_value);
|
||||
|
||||
uintptr_t *Ptr = (uintptr_t *)((uintptr_t)ElfFile + RelaF->r_offset);
|
||||
*Ptr = (uintptr_t)MemoryImage + Sym->st_value + RelaF->r_addend;
|
||||
break;
|
||||
}
|
||||
case R_X86_64_GLOB_DAT:
|
||||
{
|
||||
debug("Global data relocation");
|
||||
Elf64_Xword SymIndex = ELF64_R_SYM(RelaF->r_info);
|
||||
Elf64_Sym *Sym = (Elf64_Sym *)((uintptr_t)ElfFile + (uintptr_t)SymTab + SymIndex);
|
||||
char *SymName = (char *)((uintptr_t)ElfFile + (uintptr_t)StrTab + Sym->st_name);
|
||||
debug("Symbol %s at %#lx", SymName, Sym->st_value);
|
||||
|
||||
uintptr_t *Ptr = (uintptr_t *)((uintptr_t)ElfFile + RelaF->r_offset);
|
||||
*Ptr = (uintptr_t)MemoryImage + Sym->st_value;
|
||||
break;
|
||||
}
|
||||
case R_X86_64_RELATIVE:
|
||||
{
|
||||
debug("Relative relocation");
|
||||
Elf64_Xword SymIndex = ELF64_R_SYM(RelaF->r_info);
|
||||
Elf64_Sym *Sym = (Elf64_Sym *)((uintptr_t)ElfFile + (uintptr_t)SymTab + SymIndex);
|
||||
char *SymName = (char *)((uintptr_t)ElfFile + (uintptr_t)StrTab + Sym->st_name);
|
||||
debug("Symbol %s at %#lx", SymName, Sym->st_value);
|
||||
|
||||
uintptr_t *Ptr = (uintptr_t *)((uintptr_t)ElfFile + RelaF->r_offset);
|
||||
*Ptr = (uintptr_t)MemoryImage + RelaF->r_addend;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
fixme("RelaType %d", RelaType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
ELFDynamicReallocation(ElfFile, MemoryImage);
|
||||
|
||||
LibAddressCollection *LibsForLazyResolver = (LibAddressCollection *)ELFBase.TmpMem->RequestPages(TO_PAGES(sizeof(LibAddressCollection)), true);
|
||||
memset(LibsForLazyResolver, 0, sizeof(LibAddressCollection));
|
||||
LibAddressCollection *LFLRTmp = LibsForLazyResolver;
|
||||
debug("LibsForLazyResolver: %#lx", LibsForLazyResolver);
|
||||
|
||||
if (NeededLibraries.size() > 0)
|
||||
{
|
||||
VirtualFileSystem::Node *ParentNode = ExFile->Node->Parent; // Working Directory
|
||||
if (ParentNode)
|
||||
{
|
||||
char *WorkingDirAbsolutePath = vfs->GetPathFromNode(ParentNode);
|
||||
debug("Working directory: \"%s\"", WorkingDirAbsolutePath);
|
||||
|
||||
int LibCount = 0;
|
||||
foreach (auto Library in NeededLibraries)
|
||||
{
|
||||
char LibPath[256];
|
||||
strcpy(LibPath, WorkingDirAbsolutePath);
|
||||
strcat(LibPath, "/");
|
||||
strcat(LibPath, Library);
|
||||
debug("Searching for \"%s\"...", LibPath);
|
||||
|
||||
bool AlreadyTried = false;
|
||||
|
||||
LibPathRetry:
|
||||
VirtualFileSystem::FILE *LibNode = vfs->Open(LibPath);
|
||||
|
||||
if (LibNode->Status != VirtualFileSystem::FileStatus::OK)
|
||||
{
|
||||
vfs->Close(LibNode);
|
||||
if (!AlreadyTried)
|
||||
{
|
||||
debug("Library \"%s\" not found, retrying... (%#x)", LibPath, LibNode->Status);
|
||||
memset(LibPath, 0, 256);
|
||||
strcpy(LibPath, "/lib/");
|
||||
strcat(LibPath, Library);
|
||||
AlreadyTried = true;
|
||||
goto LibPathRetry;
|
||||
}
|
||||
else
|
||||
warn("Failed to load library \"%s\" (%#x)", Library, LibNode->Status);
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("Library found \"%s\" (%#x)", LibPath, LibNode->Status);
|
||||
SharedLibraries *sl = AddLibrary(Library, (void *)LibNode->Node->Address, LibNode->Node->Length);
|
||||
strcpy(LFLRTmp->Name, Library);
|
||||
LFLRTmp->ElfFile = (uintptr_t *)sl->Address;
|
||||
LFLRTmp->MemoryImage = (uintptr_t *)sl->MemoryImage;
|
||||
LFLRTmp->ParentElfFile = (uintptr_t *)ElfFile;
|
||||
LFLRTmp->ParentMemoryImage = (uintptr_t *)MemoryImage;
|
||||
LFLRTmp->Valid = true;
|
||||
debug("LIBRARY: %s, %#lx, %#lx", Library, LFLRTmp->ElfFile, LFLRTmp->MemoryImage);
|
||||
|
||||
LFLRTmp->Next = (LibAddressCollection *)ELFBase.TmpMem->RequestPages(TO_PAGES(sizeof(LibAddressCollection)), true);
|
||||
LFLRTmp = LFLRTmp->Next;
|
||||
memset(LFLRTmp, 0, sizeof(LibAddressCollection));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Couldn't get the parent node from path %s", vfs->GetPathFromNode(ExFile->Node));
|
||||
}
|
||||
}
|
||||
|
||||
ELFAddLazyResolverToGOT(ElfFile, MemoryImage, LibsForLazyResolver);
|
||||
|
11
Userspace/libc/Makefile
Normal file
11
Userspace/libc/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
build:
|
||||
cp -r include/* ../out/include
|
||||
cp ../Kernel/include/interface/syscalls.h ../out/include/fennix/syscall.h
|
||||
make -C runtime build
|
||||
make -C src build
|
||||
make -C ElfInterpreter build
|
||||
|
||||
clean:
|
||||
make -C runtime clean
|
||||
make -C src clean
|
||||
make -C ElfInterpreter clean
|
4
Userspace/libc/include/assert.h
Normal file
4
Userspace/libc/include/assert.h
Normal file
@ -0,0 +1,4 @@
|
||||
#ifndef _ASSERT_H
|
||||
#define _ASSERT_H
|
||||
|
||||
#endif
|
69
Userspace/libc/include/aux.h
Normal file
69
Userspace/libc/include/aux.h
Normal file
@ -0,0 +1,69 @@
|
||||
#ifndef __FENNIX_LIBC_AUX_H__
|
||||
#define __FENNIX_LIBC_AUX_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#define AT_NULL 0
|
||||
#define AT_IGNORE 1
|
||||
#define AT_EXECFD 2
|
||||
#define AT_PHDR 3
|
||||
#define AT_PHENT 4
|
||||
#define AT_PHNUM 5
|
||||
#define AT_PAGESZ 6
|
||||
#define AT_BASE 7
|
||||
#define AT_FLAGS 8
|
||||
#define AT_ENTRY 9
|
||||
#define AT_NOTELF 10
|
||||
#define AT_UID 11
|
||||
#define AT_EUID 12
|
||||
#define AT_GID 13
|
||||
#define AT_EGID 14
|
||||
#define AT_PLATFORM 15
|
||||
#define AT_HWCAP 16
|
||||
#define AT_CLKTCK 17
|
||||
#define AT_SECURE 23
|
||||
#define AT_BASE_PLATFORM 24
|
||||
#define AT_RANDOM 25
|
||||
#define AT_HWCAP2 26
|
||||
#define AT_EXECFN 31
|
||||
#define AT_SYSINFO 32
|
||||
#define AT_SYSINFO_EHDR 33
|
||||
#define AT_L1I_CACHESHAPE 34
|
||||
#define AT_L1D_CACHESHAPE 35
|
||||
#define AT_L2_CACHESHAPE 36
|
||||
#define AT_L3_CACHESHAPE 37
|
||||
#define AT_L1I_CACHESIZE 40
|
||||
#define AT_L1I_CACHEGEOMETRY 41
|
||||
#define AT_L1D_CACHESIZE 42
|
||||
#define AT_L1D_CACHEGEOMETRY 43
|
||||
#define AT_L2_CACHESIZE 44
|
||||
#define AT_L2_CACHEGEOMETRY 45
|
||||
#define AT_L3_CACHESIZE 46
|
||||
#define AT_L3_CACHEGEOMETRY 47
|
||||
#define AT_MINSIGSTKSZ 51
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t a_type;
|
||||
union
|
||||
{
|
||||
uint32_t a_val;
|
||||
} a_un;
|
||||
} Elf32_auxv_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint64_t a_type;
|
||||
union
|
||||
{
|
||||
uint64_t a_val;
|
||||
} a_un;
|
||||
} Elf64_auxv_t;
|
||||
|
||||
#ifdef __LP64__
|
||||
#define Elf_auxv_t Elf64_auxv_t
|
||||
#else
|
||||
#define Elf_auxv_t Elf32_auxv_t
|
||||
#endif
|
||||
|
||||
#endif // !__FENNIX_LIBC_AUX_H__
|
6
Userspace/libc/include/bits/types/sigset_t.h
Normal file
6
Userspace/libc/include/bits/types/sigset_t.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef _BITS_TYPES_SIGSET_T_H
|
||||
#define _BITS_TYPES_SIGSET_T_H
|
||||
|
||||
typedef unsigned long sigset_t;
|
||||
|
||||
#endif // !_BITS_TYPES_SIGSET_T_H
|
9
Userspace/libc/include/bits/types/struct_sched_param.h
Normal file
9
Userspace/libc/include/bits/types/struct_sched_param.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef _BITS_TYPES_STRUCT_SCHED_PARAM_T_H
|
||||
#define _BITS_TYPES_STRUCT_SCHED_PARAM_T_H
|
||||
|
||||
struct sched_param
|
||||
{
|
||||
int sched_priority;
|
||||
};
|
||||
|
||||
#endif // !_BITS_TYPES_STRUCT_SCHED_PARAM_T_H
|
14
Userspace/libc/include/bits/waitstatus.h
Normal file
14
Userspace/libc/include/bits/waitstatus.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef _BITS_WAITSTATUS_H
|
||||
#define _BITS_WAITSTATUS_H
|
||||
|
||||
#define __W_CONTINUED 0xFFFF
|
||||
|
||||
#define __WEXITSTATUS(status) (((status)&0xFF00) >> 8)
|
||||
#define __WTERMSIG(status) ((status)&0x7F)
|
||||
#define __WSTOPSIG(status) __WEXITSTATUS(status)
|
||||
#define __WIFEXITED(status) (__WTERMSIG(status) == 0)
|
||||
#define __WIFSIGNALED(status) (((signed char)(((status)&0x7F) + 1) >> 1) > 0)
|
||||
#define __WIFSTOPPED(status) (((status)&0xFF) == 0x7F)
|
||||
#define __WIFCONTINUED(status) ((status) == __W_CONTINUED)
|
||||
|
||||
#endif
|
8
Userspace/libc/include/ctype.h
Normal file
8
Userspace/libc/include/ctype.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef _CTYPE_H
|
||||
#define _CTYPE_H
|
||||
|
||||
int tolower(int c);
|
||||
int toupper(int c);
|
||||
int isspace(int c);
|
||||
|
||||
#endif // !_CTYPE_H
|
11
Userspace/libc/include/dlfcn.h
Normal file
11
Userspace/libc/include/dlfcn.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef __FENNIX_LIBC_DLFCN_H__
|
||||
#define __FENNIX_LIBC_DLFCN_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
void *dlopen(const char *filename, int flags);
|
||||
void *dlsym(void *handle, const char *symbol);
|
||||
int dlclose(void *handle);
|
||||
char *dlerror(void);
|
||||
|
||||
#endif // !__FENNIX_LIBC_DLFCN_H__
|
137
Userspace/libc/include/errno.h
Normal file
137
Userspace/libc/include/errno.h
Normal file
@ -0,0 +1,137 @@
|
||||
#ifndef _ERRNO_H
|
||||
#define _ERRNO_H
|
||||
|
||||
#define EPERM 1 /* Operation not permitted */
|
||||
#define ENOENT 2 /* No such file or directory */
|
||||
#define ESRCH 3 /* No such process */
|
||||
#define EINTR 4 /* Interrupted system call */
|
||||
#define EIO 5 /* I/O error */
|
||||
#define ENXIO 6 /* No such device or address */
|
||||
#define E2BIG 7 /* Argument list too long */
|
||||
#define ENOEXEC 8 /* Exec format error */
|
||||
#define EBADF 9 /* Bad file number */
|
||||
#define ECHILD 10 /* No child processes */
|
||||
#define EAGAIN 11 /* Try again */
|
||||
#define ENOMEM 12 /* Out of memory */
|
||||
#define EACCES 13 /* Permission denied */
|
||||
#define EFAULT 14 /* Bad address */
|
||||
#define ENOTBLK 15 /* Block device required */
|
||||
#define EBUSY 16 /* Device or resource busy */
|
||||
#define EEXIST 17 /* File exists */
|
||||
#define EXDEV 18 /* Cross-device link */
|
||||
#define ENODEV 19 /* No such device */
|
||||
#define ENOTDIR 20 /* Not a directory */
|
||||
#define EISDIR 21 /* Is a directory */
|
||||
#define EINVAL 22 /* Invalid argument */
|
||||
#define ENFILE 23 /* File table overflow */
|
||||
#define EMFILE 24 /* Too many open files */
|
||||
#define ENOTTY 25 /* Not a typewriter */
|
||||
#define ETXTBSY 26 /* Text file busy */
|
||||
#define EFBIG 27 /* File too large */
|
||||
#define ENOSPC 28 /* No space left on device */
|
||||
#define ESPIPE 29 /* Illegal seek */
|
||||
#define EROFS 30 /* Read-only file system */
|
||||
#define EMLINK 31 /* Too many links */
|
||||
#define EPIPE 32 /* Broken pipe */
|
||||
#define EDOM 33 /* Math argument out of domain of func */
|
||||
#define ERANGE 34 /* Math result not representable */
|
||||
#define EDEADLK 35 /* Resource deadlock would occur */
|
||||
#define ENAMETOOLONG 36 /* File name too long */
|
||||
#define ENOLCK 37 /* No record locks available */
|
||||
#define ENOSYS 38 /* Function not implemented */
|
||||
#define ENOTEMPTY 39 /* Directory not empty */
|
||||
#define ELOOP 40 /* Too many symbolic links encountered */
|
||||
#define ENOMSG 42 /* No message of desired type */
|
||||
#define EIDRM 43 /* Identifier removed */
|
||||
#define ECHRNG 44 /* Channel number out of range */
|
||||
#define EL2NSYNC 45 /* Level 2 not synchronized */
|
||||
#define EL3HLT 46 /* Level 3 halted */
|
||||
#define EL3RST 47 /* Level 3 reset */
|
||||
#define ELNRNG 48 /* Link number out of range */
|
||||
#define EUNATCH 49 /* Protocol driver not attached */
|
||||
#define ENOCSI 50 /* No CSI structure available */
|
||||
#define EL2HLT 51 /* Level 2 halted */
|
||||
#define EBADE 52 /* Invalid exchange */
|
||||
#define EBADR 53 /* Invalid request descriptor */
|
||||
#define EXFULL 54 /* Exchange full */
|
||||
#define ENOANO 55 /* No anode */
|
||||
#define EBADRQC 56 /* Invalid request code */
|
||||
#define EBADSLT 57 /* Invalid slot */
|
||||
#define EBFONT 59 /* Bad font file format */
|
||||
#define ENOSTR 60 /* Device not a stream */
|
||||
#define ENODATA 61 /* No data available */
|
||||
#define ETIME 62 /* Timer expired */
|
||||
#define ENOSR 63 /* Out of streams resources */
|
||||
#define ENONET 64 /* Machine is not on the network */
|
||||
#define ENOPKG 65 /* Package not installed */
|
||||
#define EREMOTE 66 /* Object is remote */
|
||||
#define ENOLINK 67 /* Link has been severed */
|
||||
#define EADV 68 /* Advertise error */
|
||||
#define ESRMNT 69 /* Srmount error */
|
||||
#define ECOMM 70 /* Communication error on send */
|
||||
#define EPROTO 71 /* Protocol error */
|
||||
#define EMULTIHOP 72 /* Multihop attempted */
|
||||
#define EDOTDOT 73 /* RFS specific error */
|
||||
#define EBADMSG 74 /* Not a data message */
|
||||
#define EOVERFLOW 75 /* Value too large for defined data type */
|
||||
#define ENOTUNIQ 76 /* Name not unique on network */
|
||||
#define EBADFD 77 /* File descriptor in bad state */
|
||||
#define EREMCHG 78 /* Remote address changed */
|
||||
#define ELIBACC 79 /* Can not access a needed shared library */
|
||||
#define ELIBBAD 80 /* Accessing a corrupted shared library */
|
||||
#define ELIBSCN 81 /* .lib section in a.out corrupted */
|
||||
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
|
||||
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
|
||||
#define EILSEQ 84 /* Illegal byte sequence */
|
||||
#define ERESTART 85 /* Interrupted system call should be restarted */
|
||||
#define ESTRPIPE 86 /* Streams pipe error */
|
||||
#define EUSERS 87 /* Too many users */
|
||||
#define ENOTSOCK 88 /* Socket operation on non-socket */
|
||||
#define EDESTADDRREQ 89 /* Destination address required */
|
||||
#define EMSGSIZE 90 /* Message too long */
|
||||
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
|
||||
#define ENOPROTOOPT 92 /* Protocol not available */
|
||||
#define EPROTONOSUPPORT 93 /* Protocol not supported */
|
||||
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
|
||||
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
|
||||
#define EPFNOSUPPORT 96 /* Protocol family not supported */
|
||||
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
|
||||
#define EADDRINUSE 98 /* Address already in use */
|
||||
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
|
||||
#define ENETDOWN 100 /* Network is down */
|
||||
#define ENETUNREACH 101 /* Network is unreachable */
|
||||
#define ENETRESET 102 /* Network dropped connection because of reset */
|
||||
#define ECONNABORTED 103 /* Software caused connection abort */
|
||||
#define ECONNRESET 104 /* Connection reset by peer */
|
||||
#define ENOBUFS 105 /* No buffer space available */
|
||||
#define EISCONN 106 /* Transport endpoint is already connected */
|
||||
#define ENOTCONN 107 /* Transport endpoint is not connected */
|
||||
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
|
||||
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
|
||||
#define ETIMEDOUT 110 /* Connection timed out */
|
||||
#define ECONNREFUSED 111 /* Connection refused */
|
||||
#define EHOSTDOWN 112 /* Host is down */
|
||||
#define EHOSTUNREACH 113 /* No route to host */
|
||||
#define EALREADY 114 /* Operation already in progress */
|
||||
#define EINPROGRESS 115 /* Operation now in progress */
|
||||
#define ESTALE 116 /* Stale NFS file handle */
|
||||
#define EUCLEAN 117 /* Structure needs cleaning */
|
||||
#define ENOTNAM 118 /* Not a XENIX named type file */
|
||||
#define ENAVAIL 119 /* No XENIX semaphores available */
|
||||
#define EISNAM 120 /* Is a named type file */
|
||||
#define EREMOTEIO 121 /* Remote I/O error */
|
||||
#define EDQUOT 122 /* Quota exceeded */
|
||||
#define ENOMEDIUM 123 /* No medium found */
|
||||
#define EMEDIUMTYPE 124 /* Wrong medium type */
|
||||
#define ECANCELED 125 /* Operation Canceled */
|
||||
#define ENOKEY 126 /* Required key not available */
|
||||
#define EKEYEXPIRED 127 /* Key has expired */
|
||||
#define EKEYREVOKED 128 /* Key has been revoked */
|
||||
#define EKEYREJECTED 129 /* Key was rejected by service */
|
||||
#define EOWNERDEAD 130 /* Owner died */
|
||||
#define ENOTRECOVERABLE 131 /* State not recoverable */
|
||||
|
||||
extern int *__errno_location(void) __attribute__((const)) __attribute__ ((__nothrow__));
|
||||
#define errno (*__errno_location())
|
||||
|
||||
#endif
|
4
Userspace/libc/include/fcntl.h
Normal file
4
Userspace/libc/include/fcntl.h
Normal file
@ -0,0 +1,4 @@
|
||||
#ifndef _FNCTL_H
|
||||
#define _FNCTL_H
|
||||
|
||||
#endif // !_FNCTL_H
|
6
Userspace/libc/include/features.h
Normal file
6
Userspace/libc/include/features.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef _FEATURES_H
|
||||
#define _FEATURES_H
|
||||
|
||||
#define __FENNIX_LIBC__ 1
|
||||
|
||||
#endif
|
0
Userspace/libc/include/fennix/.gitkeep
Normal file
0
Userspace/libc/include/fennix/.gitkeep
Normal file
40
Userspace/libc/include/inttypes.h
Normal file
40
Userspace/libc/include/inttypes.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef _INTTYPES_H
|
||||
#define _INTTYPES_H
|
||||
|
||||
typedef __INT8_TYPE__ int8_t;
|
||||
typedef __INT16_TYPE__ int16_t;
|
||||
typedef __INT32_TYPE__ int32_t;
|
||||
typedef __INT64_TYPE__ int64_t;
|
||||
typedef __UINT8_TYPE__ uint8_t;
|
||||
typedef __UINT16_TYPE__ uint16_t;
|
||||
typedef __UINT32_TYPE__ uint32_t;
|
||||
typedef __UINT64_TYPE__ uint64_t;
|
||||
|
||||
typedef __INT_LEAST8_TYPE__ int_least8_t;
|
||||
typedef __INT_LEAST16_TYPE__ int_least16_t;
|
||||
typedef __INT_LEAST32_TYPE__ int_least32_t;
|
||||
typedef __INT_LEAST64_TYPE__ int_least64_t;
|
||||
typedef __UINT_LEAST8_TYPE__ uint_least8_t;
|
||||
typedef __UINT_LEAST16_TYPE__ uint_least16_t;
|
||||
typedef __UINT_LEAST32_TYPE__ uint_least32_t;
|
||||
typedef __UINT_LEAST64_TYPE__ uint_least64_t;
|
||||
|
||||
typedef __INT_FAST8_TYPE__ int_fast8_t;
|
||||
typedef __INT_FAST16_TYPE__ int_fast16_t;
|
||||
typedef __INT_FAST32_TYPE__ int_fast32_t;
|
||||
typedef __INT_FAST64_TYPE__ int_fast64_t;
|
||||
typedef __UINT_FAST8_TYPE__ uint_fast8_t;
|
||||
typedef __UINT_FAST16_TYPE__ uint_fast16_t;
|
||||
typedef __UINT_FAST32_TYPE__ uint_fast32_t;
|
||||
typedef __UINT_FAST64_TYPE__ uint_fast64_t;
|
||||
|
||||
typedef __INTPTR_TYPE__ intptr_t;
|
||||
typedef __UINTPTR_TYPE__ uintptr_t;
|
||||
|
||||
typedef __INTMAX_TYPE__ intmax_t;
|
||||
typedef __UINTMAX_TYPE__ uintmax_t;
|
||||
|
||||
typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
|
||||
#endif // !_INTTYPES_H
|
119
Userspace/libc/include/limits.h
Normal file
119
Userspace/libc/include/limits.h
Normal file
@ -0,0 +1,119 @@
|
||||
#ifndef _LIMITS_H
|
||||
#define _LIMITS_H
|
||||
|
||||
#undef CHAR_BIT
|
||||
#define CHAR_BIT __CHAR_BIT__
|
||||
|
||||
#ifndef MB_LEN_MAX
|
||||
#define MB_LEN_MAX 1
|
||||
#endif
|
||||
|
||||
#undef SCHAR_MIN
|
||||
#define SCHAR_MIN (-SCHAR_MAX - 1)
|
||||
#undef SCHAR_MAX
|
||||
#define SCHAR_MAX __SCHAR_MAX__
|
||||
|
||||
#undef UCHAR_MAX
|
||||
#if __SCHAR_MAX__ == __INT_MAX__
|
||||
#define UCHAR_MAX (SCHAR_MAX * 2U + 1U)
|
||||
#else
|
||||
#define UCHAR_MAX (SCHAR_MAX * 2 + 1)
|
||||
#endif
|
||||
|
||||
#ifdef __CHAR_UNSIGNED__
|
||||
#undef CHAR_MIN
|
||||
#if __SCHAR_MAX__ == __INT_MAX__
|
||||
#define CHAR_MIN 0U
|
||||
#else
|
||||
#define CHAR_MIN 0
|
||||
#endif
|
||||
#undef CHAR_MAX
|
||||
#define CHAR_MAX UCHAR_MAX
|
||||
#else
|
||||
#undef CHAR_MIN
|
||||
#define CHAR_MIN SCHAR_MIN
|
||||
#undef CHAR_MAX
|
||||
#define CHAR_MAX SCHAR_MAX
|
||||
#endif
|
||||
|
||||
#undef SHRT_MIN
|
||||
#define SHRT_MIN (-SHRT_MAX - 1)
|
||||
#undef SHRT_MAX
|
||||
#define SHRT_MAX __SHRT_MAX__
|
||||
|
||||
#undef USHRT_MAX
|
||||
#if __SHRT_MAX__ == __INT_MAX__
|
||||
#define USHRT_MAX (SHRT_MAX * 2U + 1U)
|
||||
#else
|
||||
#define USHRT_MAX (SHRT_MAX * 2 + 1)
|
||||
#endif
|
||||
|
||||
#undef INT_MIN
|
||||
#define INT_MIN (-INT_MAX - 1)
|
||||
#undef INT_MAX
|
||||
#define INT_MAX __INT_MAX__
|
||||
|
||||
#undef UINT_MAX
|
||||
#define UINT_MAX (INT_MAX * 2U + 1U)
|
||||
|
||||
#undef LONG_MIN
|
||||
#define LONG_MIN (-LONG_MAX - 1L)
|
||||
#undef LONG_MAX
|
||||
#define LONG_MAX __LONG_MAX__
|
||||
|
||||
#undef ULONG_MAX
|
||||
#define ULONG_MAX (LONG_MAX * 2UL + 1UL)
|
||||
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||
#undef LLONG_MIN
|
||||
#define LLONG_MIN (-LLONG_MAX - 1LL)
|
||||
#undef LLONG_MAX
|
||||
#define LLONG_MAX __LONG_LONG_MAX__
|
||||
|
||||
#undef ULLONG_MAX
|
||||
#define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL)
|
||||
#endif
|
||||
|
||||
#if defined(__GNU_LIBRARY__) ? defined(__USE_GNU) : !defined(__STRICT_ANSI__)
|
||||
#undef LONG_LONG_MIN
|
||||
#define LONG_LONG_MIN (-LONG_LONG_MAX - 1LL)
|
||||
#undef LONG_LONG_MAX
|
||||
#define LONG_LONG_MAX __LONG_LONG_MAX__
|
||||
|
||||
#undef ULONG_LONG_MAX
|
||||
#define ULONG_LONG_MAX (LONG_LONG_MAX * 2ULL + 1ULL)
|
||||
#endif
|
||||
|
||||
#if (defined __STDC_WANT_IEC_60559_BFP_EXT__ || (defined(__STDC_VERSION__) && __STDC_VERSION__ > 201710L))
|
||||
#undef CHAR_WIDTH
|
||||
#define CHAR_WIDTH __SCHAR_WIDTH__
|
||||
#undef SCHAR_WIDTH
|
||||
#define SCHAR_WIDTH __SCHAR_WIDTH__
|
||||
#undef UCHAR_WIDTH
|
||||
#define UCHAR_WIDTH __SCHAR_WIDTH__
|
||||
#undef SHRT_WIDTH
|
||||
#define SHRT_WIDTH __SHRT_WIDTH__
|
||||
#undef USHRT_WIDTH
|
||||
#define USHRT_WIDTH __SHRT_WIDTH__
|
||||
#undef INT_WIDTH
|
||||
#define INT_WIDTH __INT_WIDTH__
|
||||
#undef UINT_WIDTH
|
||||
#define UINT_WIDTH __INT_WIDTH__
|
||||
#undef LONG_WIDTH
|
||||
#define LONG_WIDTH __LONG_WIDTH__
|
||||
#undef ULONG_WIDTH
|
||||
#define ULONG_WIDTH __LONG_WIDTH__
|
||||
#undef LLONG_WIDTH
|
||||
#define LLONG_WIDTH __LONG_LONG_WIDTH__
|
||||
#undef ULLONG_WIDTH
|
||||
#define ULLONG_WIDTH __LONG_LONG_WIDTH__
|
||||
#endif
|
||||
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ > 201710L
|
||||
#undef BOOL_MAX
|
||||
#define BOOL_MAX 1
|
||||
#undef BOOL_WIDTH
|
||||
#define BOOL_WIDTH 1
|
||||
#endif
|
||||
|
||||
#endif // !_LIMITS_H
|
4
Userspace/libc/include/math.h
Normal file
4
Userspace/libc/include/math.h
Normal file
@ -0,0 +1,4 @@
|
||||
#ifndef _MATH_H
|
||||
#define _MATH_H
|
||||
|
||||
#endif // !_MATH_H
|
34
Userspace/libc/include/setjmp.h
Normal file
34
Userspace/libc/include/setjmp.h
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef _SETJMP_H
|
||||
#define _SETJMP_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint64_t r15;
|
||||
uint64_t r14;
|
||||
uint64_t r13;
|
||||
uint64_t r12;
|
||||
uint64_t r11;
|
||||
uint64_t r10;
|
||||
uint64_t r9;
|
||||
uint64_t r8;
|
||||
uint64_t rbp;
|
||||
uint64_t rsp;
|
||||
uint64_t rdi;
|
||||
uint64_t rsi;
|
||||
uint64_t rdx;
|
||||
uint64_t rcx;
|
||||
uint64_t rbx;
|
||||
uint64_t rax;
|
||||
uint64_t rip;
|
||||
uint64_t rflags;
|
||||
uint64_t cs;
|
||||
uint64_t fs;
|
||||
uint64_t gs;
|
||||
} jmp_buf[1];
|
||||
|
||||
int setjmp(jmp_buf env);
|
||||
__attribute__((noreturn)) void longjmp(jmp_buf env, int value);
|
||||
|
||||
#endif // !_SETJMP_H
|
102
Userspace/libc/include/signal.h
Normal file
102
Userspace/libc/include/signal.h
Normal file
@ -0,0 +1,102 @@
|
||||
#ifndef _SIGNAL_H
|
||||
#define _SIGNAL_H
|
||||
|
||||
#include <bits/types/sigset_t.h>
|
||||
|
||||
/* https://www-uxsup.csx.cam.ac.uk/courses/moved.Building/signals.pdf */
|
||||
/* https://man7.org/linux/man-pages/man7/signal.7.html */
|
||||
|
||||
/** @brief Hangup detected on controlling or death of controlling process */
|
||||
#define SIGHUP 1
|
||||
|
||||
/** @brief Interrupt from keyboard */
|
||||
#define SIGINT 2
|
||||
|
||||
/** @brief Quit from keyboard */
|
||||
#define SIGQUIT 3
|
||||
|
||||
/** @brief Illegal Instruction */
|
||||
#define SIGILL 4
|
||||
|
||||
/** @brief Trace/breakpoint trap */
|
||||
#define SIGTRAP 5
|
||||
|
||||
/** @brief Abort signal from abort(3) */
|
||||
#define SIGABRT 6
|
||||
|
||||
/** @brief Bus error (bad memory access) */
|
||||
#define SIGBUS 7
|
||||
|
||||
/** @brief Floating point exception */
|
||||
#define SIGFPE 8
|
||||
|
||||
/** @brief Kill signal */
|
||||
#define SIGKILL 9
|
||||
|
||||
/** @brief User-defined signal 1 */
|
||||
#define SIGUSR1 10
|
||||
|
||||
/** @brief Invalid memory reference */
|
||||
#define SIGSEGV 11
|
||||
|
||||
/** @brief User-defined signal 2 */
|
||||
#define SIGUSR2 12
|
||||
|
||||
/** @brief Broken pipe: write to pipe with no readers */
|
||||
#define SIGPIPE 13
|
||||
|
||||
/** @brief Timer signal from alarm(2) */
|
||||
#define SIGALRM 14
|
||||
|
||||
/** @brief Termination signal */
|
||||
#define SIGTERM 15
|
||||
|
||||
/** @brief Stack fault on coprocessor (unused) */
|
||||
#define SIGSTKFLT 16
|
||||
|
||||
/** @brief Child stopped or terminated */
|
||||
#define SIGCHLD 17
|
||||
|
||||
/** @brief Continue if stopped */
|
||||
#define SIGCONT 18
|
||||
|
||||
/** @brief Stop process */
|
||||
#define SIGSTOP 19
|
||||
|
||||
/** @brief Stop typed at terminal */
|
||||
#define SIGTSTP 20
|
||||
|
||||
/** @brief Terminal input for background process */
|
||||
#define SIGTTIN 21
|
||||
|
||||
/** @brief Terminal output for background process */
|
||||
#define SIGTTOU 22
|
||||
|
||||
/** @brief Urgent condition on socket */
|
||||
#define SIGURG 23
|
||||
|
||||
/** @brief CPU time limit exceeded */
|
||||
#define SIGXCPU 24
|
||||
|
||||
/** @brief File size limit exceeded */
|
||||
#define SIGXFSZ 25
|
||||
|
||||
/** @brief Virtual timer expired */
|
||||
#define SIGVTALRM 26
|
||||
|
||||
/** @brief Profiling timer expired */
|
||||
#define SIGPROF 27
|
||||
|
||||
/** @brief Window resize signal */
|
||||
#define SIGWINCH 28
|
||||
|
||||
/** @brief I/O now possible */
|
||||
#define SIGIO 29
|
||||
|
||||
/** @brief Power failure */
|
||||
#define SIGPWR 30
|
||||
|
||||
/** @brief Bad system call */
|
||||
#define SIGSYS 31
|
||||
|
||||
#endif // !_SIGNAL_H
|
45
Userspace/libc/include/spawn.h
Normal file
45
Userspace/libc/include/spawn.h
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef _SPAWN_H
|
||||
#define _SPAWN_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <bits/types/struct_sched_param.h>
|
||||
#include <bits/types/sigset_t.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
struct __spawn_action
|
||||
{
|
||||
int __stub;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
short int __flags;
|
||||
pid_t __pgrp;
|
||||
sigset_t __sd;
|
||||
sigset_t __ss;
|
||||
struct sched_param __sp;
|
||||
int __policy;
|
||||
int __pad[16];
|
||||
} posix_spawnattr_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int __allocated;
|
||||
int __used;
|
||||
struct __spawn_action *__actions;
|
||||
int __pad[16];
|
||||
} posix_spawn_file_actions_t;
|
||||
|
||||
int posix_spawn(pid_t *pid, const char *path,
|
||||
const posix_spawn_file_actions_t *file_actions,
|
||||
const posix_spawnattr_t *attrp,
|
||||
char *const argv[],
|
||||
char *const envp[]);
|
||||
|
||||
int posix_spawnp(pid_t *pid, const char *file,
|
||||
const posix_spawn_file_actions_t *file_actions,
|
||||
const posix_spawnattr_t *attrp,
|
||||
char *const argv[],
|
||||
char *const envp[]);
|
||||
|
||||
#endif // !_SPAWN_H
|
13
Userspace/libc/include/stdarg.h
Normal file
13
Userspace/libc/include/stdarg.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef _STDARG_H
|
||||
#define _STDARG_H
|
||||
|
||||
#ifndef __va_list__
|
||||
typedef __builtin_va_list va_list;
|
||||
#endif
|
||||
|
||||
#define va_start(ap, last) __builtin_va_start(ap, last)
|
||||
#define va_end(ap) __builtin_va_end(ap)
|
||||
#define va_arg(ap, type) __builtin_va_arg(ap, type)
|
||||
#define va_copy(dest, src) __builtin_va_copy(dest, src)
|
||||
|
||||
#endif // !_STDARG_H
|
47
Userspace/libc/include/stddef.h
Normal file
47
Userspace/libc/include/stddef.h
Normal file
@ -0,0 +1,47 @@
|
||||
#ifndef _STDDEF_H
|
||||
#define _STDDEF_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define NULL 0
|
||||
#else
|
||||
#define NULL ((void *)0)
|
||||
#define bool _Bool
|
||||
#endif
|
||||
|
||||
typedef __INT8_TYPE__ int8_t;
|
||||
typedef __INT16_TYPE__ int16_t;
|
||||
typedef __INT32_TYPE__ int32_t;
|
||||
typedef __INT64_TYPE__ int64_t;
|
||||
typedef __UINT8_TYPE__ uint8_t;
|
||||
typedef __UINT16_TYPE__ uint16_t;
|
||||
typedef __UINT32_TYPE__ uint32_t;
|
||||
typedef __UINT64_TYPE__ uint64_t;
|
||||
|
||||
typedef __INT_LEAST8_TYPE__ int_least8_t;
|
||||
typedef __INT_LEAST16_TYPE__ int_least16_t;
|
||||
typedef __INT_LEAST32_TYPE__ int_least32_t;
|
||||
typedef __INT_LEAST64_TYPE__ int_least64_t;
|
||||
typedef __UINT_LEAST8_TYPE__ uint_least8_t;
|
||||
typedef __UINT_LEAST16_TYPE__ uint_least16_t;
|
||||
typedef __UINT_LEAST32_TYPE__ uint_least32_t;
|
||||
typedef __UINT_LEAST64_TYPE__ uint_least64_t;
|
||||
|
||||
typedef __INT_FAST8_TYPE__ int_fast8_t;
|
||||
typedef __INT_FAST16_TYPE__ int_fast16_t;
|
||||
typedef __INT_FAST32_TYPE__ int_fast32_t;
|
||||
typedef __INT_FAST64_TYPE__ int_fast64_t;
|
||||
typedef __UINT_FAST8_TYPE__ uint_fast8_t;
|
||||
typedef __UINT_FAST16_TYPE__ uint_fast16_t;
|
||||
typedef __UINT_FAST32_TYPE__ uint_fast32_t;
|
||||
typedef __UINT_FAST64_TYPE__ uint_fast64_t;
|
||||
|
||||
typedef __INTPTR_TYPE__ intptr_t;
|
||||
typedef __UINTPTR_TYPE__ uintptr_t;
|
||||
|
||||
typedef __INTMAX_TYPE__ intmax_t;
|
||||
typedef __UINTMAX_TYPE__ uintmax_t;
|
||||
|
||||
typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
|
||||
#endif // !_STDDEF_H
|
6
Userspace/libc/include/stdint.h
Normal file
6
Userspace/libc/include/stdint.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef _STDINT_H
|
||||
#define _STDINT_H
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#endif // !_STDINT_H
|
87
Userspace/libc/include/stdio.h
Normal file
87
Userspace/libc/include/stdio.h
Normal file
@ -0,0 +1,87 @@
|
||||
#ifndef _STDIO_H
|
||||
#define _STDIO_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define SEEK_SET 0
|
||||
#define SEEK_CUR 1
|
||||
#define SEEK_END 2
|
||||
|
||||
/**
|
||||
* @brief EOF - End of file
|
||||
*
|
||||
* The value returned by several functions to indicate the end of file.
|
||||
*/
|
||||
#define EOF (-1)
|
||||
|
||||
struct _IO_marker
|
||||
{
|
||||
struct _IO_marker *_next;
|
||||
struct _IO_FILE *_sbuf;
|
||||
int _pos;
|
||||
};
|
||||
|
||||
struct _IO_FILE
|
||||
{
|
||||
int _flags;
|
||||
|
||||
char *_IO_read_ptr;
|
||||
char *_IO_read_end;
|
||||
char *_IO_read_base;
|
||||
char *_IO_write_base;
|
||||
char *_IO_write_ptr;
|
||||
char *_IO_write_end;
|
||||
char *_IO_buf_base;
|
||||
char *_IO_buf_end;
|
||||
|
||||
__off_t _offset;
|
||||
|
||||
struct _IO_marker *_markers;
|
||||
struct _IO_FILE *_chain;
|
||||
int _fileno;
|
||||
};
|
||||
|
||||
typedef struct _IO_FILE FILE;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
extern FILE *stdin;
|
||||
extern FILE *stdout;
|
||||
extern FILE *stderr;
|
||||
#define stdin stdin
|
||||
#define stdout stdout
|
||||
#define stderr stderr
|
||||
|
||||
FILE *freopen(const char *filename, const char *mode, FILE *stream);
|
||||
FILE *fopen(const char *filename, const char *mode);
|
||||
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
|
||||
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
|
||||
off_t fseek(FILE *stream, long offset, int whence);
|
||||
long ftell(FILE *stream);
|
||||
int fclose(FILE *fp);
|
||||
int fflush(FILE *stream);
|
||||
int fprintf(FILE *stream, const char *format, ...);
|
||||
int printf(const char *format, ...);
|
||||
void setbuf(FILE *stream, char *buf);
|
||||
int vfprintf(FILE *stream, const char *format, va_list arg);
|
||||
int vsscanf(const char *s, const char *format, va_list arg);
|
||||
int sscanf(const char *s, const char *format, ...);
|
||||
|
||||
int fputc(int c, FILE *stream);
|
||||
int putc(int c, FILE *stream);
|
||||
int fputs(const char *s, FILE *stream);
|
||||
int puts(const char *s);
|
||||
int putchar(int c);
|
||||
|
||||
int fgetc(FILE *stream);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
34
Userspace/libc/include/stdlib.h
Normal file
34
Userspace/libc/include/stdlib.h
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef _STDLIB_H
|
||||
#define _STDLIB_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#define EXIT_FAILURE 1
|
||||
#define EXIT_SUCCESS 0
|
||||
|
||||
void abort(void);
|
||||
int atexit(void (*function)(void));
|
||||
void exit(int status);
|
||||
int atoi(const char *nptr);
|
||||
char *getenv(const char *name);
|
||||
|
||||
void *malloc(size_t Size);
|
||||
void *realloc(void *Address, size_t Size);
|
||||
void *calloc(size_t Count, size_t Size);
|
||||
void free(void *Address);
|
||||
int system(const char *command);
|
||||
|
||||
double atof(const char *nptr);
|
||||
|
||||
extern void perror(const char *s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
30
Userspace/libc/include/string.h
Normal file
30
Userspace/libc/include/string.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef _STRING_H
|
||||
#define _STRING_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
size_t strlen(const char *str);
|
||||
int strcmp(const char *l, const char *r);
|
||||
int strncmp(const char *s1, const char *s2, size_t n);
|
||||
int strcasecmp(const char *s1, const char *s2);
|
||||
int strncasecmp(const char *string1, const char *string2, size_t count);
|
||||
char *strstr(const char *haystack, const char *needle);
|
||||
char *strncpy(char *destination, const char *source, unsigned long num);
|
||||
char *strdup(const char *s);
|
||||
char *strchr(char const *s, int c);
|
||||
char *strrchr(char const *s, int c);
|
||||
|
||||
void *memcpy(void *dest, const void *src, size_t n);
|
||||
void *memset(void *dest, int c, size_t n);
|
||||
void *memmove(void *dest, const void *src, size_t n);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
4
Userspace/libc/include/strings.h
Normal file
4
Userspace/libc/include/strings.h
Normal file
@ -0,0 +1,4 @@
|
||||
#ifndef _STRINGS_H
|
||||
#define _STRINGS_H
|
||||
|
||||
#endif // !_STRINGS_H
|
18
Userspace/libc/include/sys/stat.h
Normal file
18
Userspace/libc/include/sys/stat.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef _SYS_STAT_H
|
||||
#define _SYS_STAT_H
|
||||
|
||||
typedef unsigned int __dev_t;
|
||||
typedef unsigned short __ino_t;
|
||||
typedef unsigned short __mode_t;
|
||||
typedef long __off_t;
|
||||
|
||||
#define dev_t __dev_t
|
||||
#define ino_t __ino_t
|
||||
#define mode_t __mode_t
|
||||
#define off_t __off_t
|
||||
|
||||
int mkdir(const char *path, mode_t mode);
|
||||
int remove(const char *pathname);
|
||||
int rename(const char *oldpath, const char *newpath);
|
||||
|
||||
#endif
|
6
Userspace/libc/include/sys/time.h
Normal file
6
Userspace/libc/include/sys/time.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef _SYS_TIME_H
|
||||
#define _SYS_TIME_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#endif
|
37
Userspace/libc/include/sys/types.h
Normal file
37
Userspace/libc/include/sys/types.h
Normal file
@ -0,0 +1,37 @@
|
||||
#ifndef _SYS_TYPES_H
|
||||
#define _SYS_TYPES_H
|
||||
|
||||
#ifndef PUBLIC
|
||||
#define PUBLIC __attribute__((visibility("default")))
|
||||
#endif // !PUBLIC
|
||||
|
||||
#ifndef PRIVATE
|
||||
#define PRIVATE __attribute__((visibility("hidden")))
|
||||
#endif // !PRIVATE
|
||||
|
||||
typedef int __pid_t;
|
||||
typedef int __ssize_t;
|
||||
typedef unsigned int __id_t;
|
||||
typedef unsigned int __useconds_t;
|
||||
|
||||
#ifndef __pid_t_defined
|
||||
typedef __pid_t pid_t;
|
||||
#define __pid_t_defined
|
||||
#endif
|
||||
|
||||
#ifndef __id_t_defined
|
||||
typedef __id_t id_t;
|
||||
#define __id_t_defined
|
||||
#endif
|
||||
|
||||
#ifndef __useconds_t_defined
|
||||
typedef __useconds_t useconds_t;
|
||||
#define __useconds_t_defined
|
||||
#endif
|
||||
|
||||
#ifndef __ssize_t_defined
|
||||
typedef __ssize_t ssize_t;
|
||||
#define __ssize_t_defined
|
||||
#endif
|
||||
|
||||
#endif
|
108
Userspace/libc/include/sys/wait.h
Normal file
108
Userspace/libc/include/sys/wait.h
Normal file
@ -0,0 +1,108 @@
|
||||
#ifndef _SYS_WAIT_H
|
||||
#define _SYS_WAIT_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
P_ALL, /* Wait for any child. */
|
||||
P_PID, /* Wait for specified process. */
|
||||
P_PGID /* Wait for members of process group. */
|
||||
} idtype_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int stub;
|
||||
} siginfo_t;
|
||||
|
||||
#include <bits/waitstatus.h>
|
||||
|
||||
#define WCONTINUED 1
|
||||
#define WNOHANG 2
|
||||
#define WUNTRACED 4
|
||||
#define WEXITED 8
|
||||
#define WNOWAIT 16
|
||||
#define WSTOPPED 32
|
||||
|
||||
/**
|
||||
* @brief Macro for extracting the exit status from a status value.
|
||||
*
|
||||
* If the child process terminated normally by calling exit(3) or _exit(2),
|
||||
* the macro WEXITSTATUS() returns the low-order 8 bits of the status value.
|
||||
*
|
||||
* @param status The status value to extract the exit status from.
|
||||
* @return The exit status of the child process.
|
||||
*/
|
||||
#define WEXITSTATUS(status) __WEXITSTATUS(status)
|
||||
|
||||
/**
|
||||
* @brief Macro for extracting the termination signal from a status value.
|
||||
*
|
||||
* If the child process was terminated by a signal, the macro WTERMSIG()
|
||||
* returns the signal number of the terminating signal.
|
||||
*
|
||||
* @param status The status value to extract the termination signal from.
|
||||
* @return The termination signal of the child process.
|
||||
*/
|
||||
#define WTERMSIG(status) __WTERMSIG(status)
|
||||
|
||||
/**
|
||||
* @brief Macro for extracting the stop signal from a status value.
|
||||
*
|
||||
* If the child process was stopped by a signal, the macro WSTOPSIG()
|
||||
* returns the signal number of the stop signal.
|
||||
*
|
||||
* @param status The status value to extract the stop signal from.
|
||||
* @return The stop signal of the child process.
|
||||
*/
|
||||
#define WSTOPSIG(status) __WSTOPSIG(status)
|
||||
|
||||
/**
|
||||
* @brief Macro for testing whether a process exited normally.
|
||||
*
|
||||
* If the child process terminated normally by calling exit(3) or _exit(2),
|
||||
* the macro WIFEXITED() returns a nonzero value. Otherwise, it returns 0.
|
||||
*
|
||||
* @param status The status value to test.
|
||||
* @return A nonzero value if the child process exited normally, 0 otherwise.
|
||||
*/
|
||||
#define WIFEXITED(status) __WIFEXITED(status)
|
||||
|
||||
/**
|
||||
* @brief Macro for testing whether a process was terminated by a signal.
|
||||
*
|
||||
* If the child process was terminated by a signal, the macro WIFSIGNALED()
|
||||
* returns a nonzero value. Otherwise, it returns 0.
|
||||
*
|
||||
* @param status The status value to test.
|
||||
* @return A nonzero value if the child process was terminated by a signal, 0 otherwise.
|
||||
*/
|
||||
#define WIFSIGNALED(status) __WIFSIGNALED(status)
|
||||
|
||||
/**
|
||||
* @brief Macro for testing whether a process was stopped by a signal.
|
||||
*
|
||||
* If the child process was stopped by a signal, the macro WIFSTOPPED()
|
||||
* returns a nonzero value. Otherwise, it returns 0.
|
||||
*
|
||||
* @param status The status value to test.
|
||||
* @return A nonzero value if the child process was stopped by a signal, 0 otherwise.
|
||||
*/
|
||||
#define WIFSTOPPED(status) __WIFSTOPPED(status)
|
||||
|
||||
/**
|
||||
* @brief Macro for testing whether a stopped process was continued.
|
||||
*
|
||||
* If the child process was stopped and has been resumed by delivery of SIGCONT,
|
||||
* the macro WIFCONTINUED() returns a nonzero value. Otherwise, it returns 0.
|
||||
*
|
||||
* @param status The status value to test.
|
||||
* @return A nonzero value if the child process was continued, 0 otherwise.
|
||||
*/
|
||||
#define WIFCONTINUED(status) __WIFCONTINUED(status)
|
||||
|
||||
pid_t wait(int *wstatus);
|
||||
pid_t waitpid(pid_t pid, int *wstatus, int options);
|
||||
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
|
||||
|
||||
#endif
|
4
Userspace/libc/include/time.h
Normal file
4
Userspace/libc/include/time.h
Normal file
@ -0,0 +1,4 @@
|
||||
#ifndef _TIME_H
|
||||
#define _TIME_H
|
||||
|
||||
#endif
|
206
Userspace/libc/include/types.h
Normal file
206
Userspace/libc/include/types.h
Normal file
@ -0,0 +1,206 @@
|
||||
#ifndef __FENNIX_LIBC_TYPES_H__
|
||||
#define __FENNIX_LIBC_TYPES_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERNC extern "C"
|
||||
#define START_EXTERNC \
|
||||
EXTERNC \
|
||||
{
|
||||
#define END_EXTERNC \
|
||||
}
|
||||
#else
|
||||
#define EXTERNC
|
||||
#define START_EXTERNC
|
||||
#define END_EXTERNC
|
||||
#endif
|
||||
|
||||
#define asm __asm__
|
||||
#define asmv __asm__ volatile
|
||||
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define foreach for
|
||||
#define in :
|
||||
#endif
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
#define CONCAT(x, y) x##y
|
||||
|
||||
#define toupper(c) ((c)-0x20 * (((c) >= 'a') && ((c) <= 'z')))
|
||||
#define tolower(c) ((c) + 0x20 * (((c) >= 'A') && ((c) <= 'Z')))
|
||||
|
||||
#define ALIGN_UP(x, align) ((__typeof__(x))(((uint64_t)(x) + ((align)-1)) & (~((align)-1))))
|
||||
#define ALIGN_DOWN(x, align) ((__typeof__(x))((x) & (~((align)-1))))
|
||||
|
||||
#define offsetof(type, member) __builtin_offsetof(type, member)
|
||||
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
#define VPOKE(type, address) (*((volatile type *)(address)))
|
||||
#define POKE(type, address) (*((type *)(address)))
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
#ifdef __STDC__
|
||||
#ifdef __STDC_VERSION__
|
||||
#if (__STDC_VERSION__ >= 201710L)
|
||||
#define C_LANGUAGE_STANDARD 2018
|
||||
#elif (__STDC_VERSION__ >= 201112L)
|
||||
#define C_LANGUAGE_STANDARD 2011
|
||||
#elif (__STDC_VERSION__ >= 199901L)
|
||||
#define C_LANGUAGE_STANDARD 1999
|
||||
#elif (__STDC_VERSION__ >= 199409L)
|
||||
#define C_LANGUAGE_STANDARD 1995
|
||||
#endif
|
||||
#else
|
||||
#define C_LANGUAGE_STANDARD 1990
|
||||
#endif
|
||||
#else
|
||||
#define C_LANGUAGE_STANDARD 1972
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#ifdef __STDC__
|
||||
#ifdef __cplusplus
|
||||
#if (__cplusplus >= 202100L)
|
||||
#define CPP_LANGUAGE_STANDARD 2023
|
||||
#elif (__cplusplus >= 202002L)
|
||||
#define CPP_LANGUAGE_STANDARD 2020
|
||||
#elif (__cplusplus >= 201703L)
|
||||
#define CPP_LANGUAGE_STANDARD 2017
|
||||
#elif (__cplusplus >= 201402L)
|
||||
#define CPP_LANGUAGE_STANDARD 2014
|
||||
#elif (__cplusplus >= 201103L)
|
||||
#define CPP_LANGUAGE_STANDARD 2011
|
||||
#elif (__cplusplus >= 199711L)
|
||||
#define CPP_LANGUAGE_STANDARD 1998
|
||||
#endif
|
||||
#else
|
||||
#define CPP_LANGUAGE_STANDARD __cplusplus
|
||||
#endif
|
||||
#else
|
||||
#define CPP_LANGUAGE_STANDARD __cplusplus
|
||||
#endif
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
typedef __INT8_TYPE__ int8_t;
|
||||
typedef __INT16_TYPE__ int16_t;
|
||||
typedef __INT32_TYPE__ int32_t;
|
||||
typedef __INT64_TYPE__ int64_t;
|
||||
typedef __UINT8_TYPE__ uint8_t;
|
||||
typedef __UINT16_TYPE__ uint16_t;
|
||||
typedef __UINT32_TYPE__ uint32_t;
|
||||
typedef __UINT64_TYPE__ uint64_t;
|
||||
|
||||
typedef __INT_LEAST8_TYPE__ int_least8_t;
|
||||
typedef __INT_LEAST16_TYPE__ int_least16_t;
|
||||
typedef __INT_LEAST32_TYPE__ int_least32_t;
|
||||
typedef __INT_LEAST64_TYPE__ int_least64_t;
|
||||
typedef __UINT_LEAST8_TYPE__ uint_least8_t;
|
||||
typedef __UINT_LEAST16_TYPE__ uint_least16_t;
|
||||
typedef __UINT_LEAST32_TYPE__ uint_least32_t;
|
||||
typedef __UINT_LEAST64_TYPE__ uint_least64_t;
|
||||
|
||||
typedef __INT_FAST8_TYPE__ int_fast8_t;
|
||||
typedef __INT_FAST16_TYPE__ int_fast16_t;
|
||||
typedef __INT_FAST32_TYPE__ int_fast32_t;
|
||||
typedef __INT_FAST64_TYPE__ int_fast64_t;
|
||||
typedef __UINT_FAST8_TYPE__ uint_fast8_t;
|
||||
typedef __UINT_FAST16_TYPE__ uint_fast16_t;
|
||||
typedef __UINT_FAST32_TYPE__ uint_fast32_t;
|
||||
typedef __UINT_FAST64_TYPE__ uint_fast64_t;
|
||||
|
||||
typedef __INTPTR_TYPE__ intptr_t;
|
||||
typedef __UINTPTR_TYPE__ uintptr_t;
|
||||
|
||||
typedef __INTMAX_TYPE__ intmax_t;
|
||||
typedef __UINTMAX_TYPE__ uintmax_t;
|
||||
|
||||
typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
|
||||
#define INT8_MAX __INT8_MAX__
|
||||
#define INT8_MIN (-INT8_MAX - 1)
|
||||
#define UINT8_MAX __UINT8_MAX__
|
||||
#define INT16_MAX __INT16_MAX__
|
||||
#define INT16_MIN (-INT16_MAX - 1)
|
||||
#define UINT16_MAX __UINT16_MAX__
|
||||
#define INT32_MAX __INT32_MAX__
|
||||
#define INT32_MIN (-INT32_MAX - 1)
|
||||
#define UINT32_MAX __UINT32_MAX__
|
||||
#define INT64_MAX __INT64_MAX__
|
||||
#define INT64_MIN (-INT64_MAX - 1)
|
||||
#define UINT64_MAX __UINT64_MAX__
|
||||
|
||||
#define INT_LEAST8_MAX __INT_LEAST8_MAX__
|
||||
#define INT_LEAST8_MIN (-INT_LEAST8_MAX - 1)
|
||||
#define UINT_LEAST8_MAX __UINT_LEAST8_MAX__
|
||||
#define INT_LEAST16_MAX __INT_LEAST16_MAX__
|
||||
#define INT_LEAST16_MIN (-INT_LEAST16_MAX - 1)
|
||||
#define UINT_LEAST16_MAX __UINT_LEAST16_MAX__
|
||||
#define INT_LEAST32_MAX __INT_LEAST32_MAX__
|
||||
#define INT_LEAST32_MIN (-INT_LEAST32_MAX - 1)
|
||||
#define UINT_LEAST32_MAX __UINT_LEAST32_MAX__
|
||||
#define INT_LEAST64_MAX __INT_LEAST64_MAX__
|
||||
#define INT_LEAST64_MIN (-INT_LEAST64_MAX - 1)
|
||||
#define UINT_LEAST64_MAX __UINT_LEAST64_MAX__
|
||||
|
||||
#define INT_FAST8_MAX __INT_FAST8_MAX__
|
||||
#define INT_FAST8_MIN (-INT_FAST8_MAX - 1)
|
||||
#define UINT_FAST8_MAX __UINT_FAST8_MAX__
|
||||
#define INT_FAST16_MAX __INT_FAST16_MAX__
|
||||
#define INT_FAST16_MIN (-INT_FAST16_MAX - 1)
|
||||
#define UINT_FAST16_MAX __UINT_FAST16_MAX__
|
||||
#define INT_FAST32_MAX __INT_FAST32_MAX__
|
||||
#define INT_FAST32_MIN (-INT_FAST32_MAX - 1)
|
||||
#define UINT_FAST32_MAX __UINT_FAST32_MAX__
|
||||
#define INT_FAST64_MAX __INT_FAST64_MAX__
|
||||
#define INT_FAST64_MIN (-INT_FAST64_MAX - 1)
|
||||
#define UINT_FAST64_MAX __UINT_FAST64_MAX__
|
||||
|
||||
#define INTPTR_MAX __INTPTR_MAX__
|
||||
#define INTPTR_MIN (-INTPTR_MAX - 1)
|
||||
#define UINTPTR_MAX __UINTPTR_MAX__
|
||||
|
||||
#define INTMAX_MAX __INTMAX_MAX__
|
||||
#define INTMAX_MIN (-INTMAX_MAX - 1)
|
||||
#define UINTMAX_MAX __UINTMAX_MAX__
|
||||
|
||||
#define PTRDIFF_MAX __PTRDIFF_MAX__
|
||||
#define PTRDIFF_MIN (-PTRDIFF_MAX - 1)
|
||||
|
||||
#define SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__
|
||||
#define SIG_ATOMIC_MIN __SIG_ATOMIC_MIN__
|
||||
|
||||
#define SIZE_MAX __SIZE_MAX__
|
||||
|
||||
#define WCHAR_MAX __WCHAR_MAX__
|
||||
#define WCHAR_MIN __WCHAR_MIN__
|
||||
|
||||
#define WINT_MAX __WINT_MAX__
|
||||
#define WINT_MIN __WINT_MIN__
|
||||
|
||||
#define b4(x) ((x & 0x0F) << 4 | (x & 0xF0) >> 4)
|
||||
#define b8(x) ((x)&0xFF)
|
||||
#define b16(x) __builtin_bswap16(x)
|
||||
#define b32(x) __builtin_bswap32(x)
|
||||
#define b48(x) (((((x)&0x0000000000ff) << 40) | (((x)&0x00000000ff00) << 24) | (((x)&0x000000ff0000) << 8) | (((x)&0x0000ff000000) >> 8) | (((x)&0x00ff00000000) >> 24) | (((x)&0xff0000000000) >> 40)))
|
||||
#define b64(x) __builtin_bswap64(x)
|
||||
|
||||
#ifndef PUBLIC
|
||||
#define PUBLIC __attribute__((visibility("default")))
|
||||
#endif // !PUBLIC
|
||||
|
||||
#ifndef PRIVATE
|
||||
#define PRIVATE __attribute__((visibility("hidden")))
|
||||
#endif // !PRIVATE
|
||||
|
||||
#endif // !__FENNIX_LIBC_TYPES_H__
|
29
Userspace/libc/include/unistd.h
Normal file
29
Userspace/libc/include/unistd.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef _UNISTD_H
|
||||
#define _UNISTD_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
extern char **environ;
|
||||
|
||||
int execl(const char *pathname, const char *arg, ...);
|
||||
int execlp(const char *file, const char *arg, ...);
|
||||
int execle(const char *pathname, const char *arg, ...);
|
||||
int execv(const char *pathname, char *const argv[]);
|
||||
int execvp(const char *file, char *const argv[]);
|
||||
int execvpe(const char *file, char *const argv[], char *const envp[]);
|
||||
int execve(const char *pathname, char *const argv[], char *const envp[]);
|
||||
|
||||
pid_t fork(void);
|
||||
|
||||
unsigned int sleep(unsigned int seconds);
|
||||
int usleep(useconds_t usec);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
41
Userspace/libc/runtime/Makefile
Normal file
41
Userspace/libc/runtime/Makefile
Normal file
@ -0,0 +1,41 @@
|
||||
# Config file
|
||||
include ../../../Makefile.conf
|
||||
|
||||
CC = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
|
||||
AS = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)as
|
||||
NASM = /usr/bin/nasm
|
||||
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c')
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S')
|
||||
ASM_SOURCES = $(shell find ./ -type f -name '*.asm')
|
||||
OBJ = ${C_SOURCES:.c=.o} ${ASM_SOURCES:.asm=.o} ${S_SOURCES:.S=.o}
|
||||
|
||||
ifeq ($(OSARCH), amd64)
|
||||
ASM_ARCH := elf64
|
||||
else ifeq ($(OSARCH), i386)
|
||||
ASM_ARCH := elf32
|
||||
endif
|
||||
|
||||
CRTBEGIN_PATH = $(shell $(CC) -print-file-name=crtbegin.o)
|
||||
CRTEND_PATH = $(shell $(CC) -print-file-name=crtend.o)
|
||||
CRTI_PATH = $(shell $(CC) -print-file-name=crti.o)
|
||||
CRTN_PATH = $(shell $(CC) -print-file-name=crtn.o)
|
||||
|
||||
build: $(OBJ)
|
||||
mv $^ ../../out/lib/
|
||||
cp $(CRTBEGIN_PATH) $(CRTEND_PATH) $(CRTI_PATH) $(CRTN_PATH) ../../out/lib/
|
||||
|
||||
%.o: %.c
|
||||
$(info Compiling $<)
|
||||
$(CC) -nostdlib -mno-red-zone -std=c17 -c $< -o $@
|
||||
|
||||
%.o: %.asm
|
||||
$(info Compiling $<)
|
||||
$(NASM) $< -f $(ASM_ARCH) -o $@
|
||||
|
||||
%.o: %.S
|
||||
$(info Compiling $<)
|
||||
$(AS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
|
21
Userspace/libc/runtime/crt0.c
Normal file
21
Userspace/libc/runtime/crt0.c
Normal file
@ -0,0 +1,21 @@
|
||||
// https://wiki.osdev.org/Creating_a_C_Library
|
||||
#define asm __asm__ __volatile__
|
||||
__attribute__((naked, used, no_stack_protector, section(".text"))) void _start()
|
||||
{
|
||||
asm("movq $0, %rbp\n");
|
||||
asm("pushq %rbp\n");
|
||||
asm("pushq %rbp\n");
|
||||
asm("movq %rsp, %rbp\n");
|
||||
asm("pushq %rcx\n"
|
||||
"pushq %rdx\n"
|
||||
"pushq %rsi\n"
|
||||
"pushq %rdi\n");
|
||||
asm("call __libc_init\n");
|
||||
asm("popq %rdi\n"
|
||||
"popq %rsi\n"
|
||||
"popq %rdx\n"
|
||||
"popq %rcx\n");
|
||||
asm("call main\n");
|
||||
asm("movl %eax, %edi\n");
|
||||
asm("call _exit\n");
|
||||
}
|
21
Userspace/libc/runtime/crt1.c
Normal file
21
Userspace/libc/runtime/crt1.c
Normal file
@ -0,0 +1,21 @@
|
||||
// https://wiki.osdev.org/Creating_a_C_Library
|
||||
#define asm __asm__ __volatile__
|
||||
__attribute__((naked, used, no_stack_protector, section(".text"))) void _start()
|
||||
{
|
||||
asm("movq $0, %rbp\n");
|
||||
asm("pushq %rbp\n");
|
||||
asm("pushq %rbp\n");
|
||||
asm("movq %rsp, %rbp\n");
|
||||
asm("pushq %rcx\n"
|
||||
"pushq %rdx\n"
|
||||
"pushq %rsi\n"
|
||||
"pushq %rdi\n");
|
||||
asm("call __libc_init\n");
|
||||
asm("popq %rdi\n"
|
||||
"popq %rsi\n"
|
||||
"popq %rdx\n"
|
||||
"popq %rcx\n");
|
||||
asm("call main\n");
|
||||
asm("movl %eax, %edi\n");
|
||||
asm("call _exit\n");
|
||||
}
|
22
Userspace/libc/src/InitArray.c
Normal file
22
Userspace/libc/src/InitArray.c
Normal file
@ -0,0 +1,22 @@
|
||||
// extern void (*__preinit_array_start[])(void) __attribute__((weak));
|
||||
// extern void (*__preinit_array_end[])(void) __attribute__((weak));
|
||||
// extern void (*__init_array_start[])(void) __attribute__((weak));
|
||||
// extern void (*__init_array_end[])(void) __attribute__((weak));
|
||||
// extern void (*__fini_array_start []) (void) __attribute__((weak));
|
||||
// extern void (*__fini_array_end []) (void) __attribute__((weak));
|
||||
|
||||
typedef void (*fct)(void);
|
||||
extern fct __init_array_start[0], __init_array_end[0];
|
||||
extern fct __fini_array_start[0], __fini_array_end[0];
|
||||
|
||||
void __libc_init_array(void)
|
||||
{
|
||||
for (fct *func = __init_array_start; func != __init_array_end; func++)
|
||||
(*func)();
|
||||
}
|
||||
|
||||
void __libc_fini_array(void)
|
||||
{
|
||||
for (fct *func = __fini_array_start; func != __fini_array_end; func++)
|
||||
(*func)();
|
||||
}
|
35
Userspace/libc/src/Lock.cpp
Normal file
35
Userspace/libc/src/Lock.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
#include "lock.hpp"
|
||||
#include <stdio.h>
|
||||
|
||||
void LockClass::DeadLock(SpinLockData Lock)
|
||||
{
|
||||
fprintf(stdout, "Potential deadlock in lock '%s' held by '%s'! %ld locks in queue.",
|
||||
Lock.AttemptingToGet, Lock.CurrentHolder, Lock.Count);
|
||||
}
|
||||
|
||||
int LockClass::Lock(const char *FunctionName)
|
||||
{
|
||||
LockData.AttemptingToGet = FunctionName;
|
||||
Retry:
|
||||
unsigned int i = 0;
|
||||
while (__atomic_exchange_n(&IsLocked, true, __ATOMIC_ACQUIRE) && ++i < 0x10000000)
|
||||
;
|
||||
if (i >= 0x10000000)
|
||||
{
|
||||
DeadLock(LockData);
|
||||
goto Retry;
|
||||
}
|
||||
LockData.Count++;
|
||||
LockData.CurrentHolder = FunctionName;
|
||||
__sync_synchronize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LockClass::Unlock()
|
||||
{
|
||||
__sync_synchronize();
|
||||
__atomic_store_n(&IsLocked, false, __ATOMIC_RELEASE);
|
||||
LockData.Count--;
|
||||
IsLocked = false;
|
||||
return 0;
|
||||
}
|
59
Userspace/libc/src/Makefile
Normal file
59
Userspace/libc/src/Makefile
Normal file
@ -0,0 +1,59 @@
|
||||
# Config file
|
||||
include ../../../Makefile.conf
|
||||
|
||||
NAME=c
|
||||
|
||||
ifeq ($(USERSPACE_STATIC_LIBS), 1)
|
||||
OBJECT_NAME := lib$(NAME).a
|
||||
else
|
||||
OBJECT_NAME := lib$(NAME).so
|
||||
endif
|
||||
|
||||
OUTPUT_DIR=../../out/lib/
|
||||
SYSROOT = --sysroot=../../out/
|
||||
|
||||
CC = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
|
||||
AS = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)as
|
||||
AR = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)ar
|
||||
|
||||
C_SOURCES = $(shell find ./ -type f -name '*.c')
|
||||
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp')
|
||||
S_SOURCES = $(shell find ./ -type f -name '*.S')
|
||||
OBJ = ${C_SOURCES:.c=.o} ${CPP_SOURCES:.cpp=.o} ${S_SOURCES:.S=.o}
|
||||
|
||||
ifeq ($(OSARCH), amd64)
|
||||
ASM_ARCH := elf64
|
||||
else ifeq ($(OSARCH), i386)
|
||||
ASM_ARCH := elf32
|
||||
endif
|
||||
|
||||
CFLAGS := -fvisibility=hidden -fPIC -I../include -I../../out/include
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fverbose-asm
|
||||
endif
|
||||
|
||||
build: $(OBJECT_NAME)
|
||||
|
||||
$(OBJECT_NAME): $(OBJ)
|
||||
$(info Linking $@)
|
||||
ifeq ($(USERSPACE_STATIC_LIBS), 1)
|
||||
$(AR) rcs $(OUTPUT_DIR)$@ $(OBJ)
|
||||
else
|
||||
$(CC) -nostdlib -shared -fPIC -fPIE -Wl,-soname,$(OBJECT_NAME) $(SYSROOT) $(OBJ) -o $(OUTPUT_DIR)$@
|
||||
endif
|
||||
|
||||
%.o: %.c
|
||||
$(info Compiling $<)
|
||||
$(CC) $(CFLAGS) -std=c17 -c $< -o $@
|
||||
|
||||
%.o: %.cpp
|
||||
$(info Compiling $<)
|
||||
$(CC) $(CFLAGS) -std=c++20 -c $< -o $@
|
||||
|
||||
%.o: %.S
|
||||
$(info Compiling $<)
|
||||
$(AS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ)
|
23
Userspace/libc/src/Runtime.c
Normal file
23
Userspace/libc/src/Runtime.c
Normal file
@ -0,0 +1,23 @@
|
||||
#include <fennix/syscall.h>
|
||||
#include <sys/types.h> // For PUBLIC
|
||||
|
||||
extern void __libc_init_array(void);
|
||||
extern void __libc_fini_array(void);
|
||||
|
||||
extern void __libc_init_std(void);
|
||||
extern void __libc_fini_std(void);
|
||||
|
||||
PUBLIC void __libc_init(void)
|
||||
{
|
||||
__libc_init_array();
|
||||
__libc_init_std();
|
||||
}
|
||||
|
||||
PUBLIC void _exit(int Code)
|
||||
{
|
||||
__libc_fini_std();
|
||||
__libc_fini_array();
|
||||
syscall1(sc_exit, (long)Code);
|
||||
while (1)
|
||||
;
|
||||
}
|
23
Userspace/libc/src/dlfcn.c
Normal file
23
Userspace/libc/src/dlfcn.c
Normal file
@ -0,0 +1,23 @@
|
||||
#include <dlfcn.h>
|
||||
|
||||
static char *error = "Not implemented";
|
||||
|
||||
__attribute__((weak)) void *dlopen(const char *filename, int flags)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__attribute__((weak)) void *dlsym(void *handle, const char *symbol)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int dlclose(void *handle)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
__attribute__((weak)) char *dlerror(void)
|
||||
{
|
||||
return error;
|
||||
}
|
50
Userspace/libc/src/lock.hpp
Normal file
50
Userspace/libc/src/lock.hpp
Normal file
@ -0,0 +1,50 @@
|
||||
#ifndef __FENNIX_KERNEL_LOCK_H__
|
||||
#define __FENNIX_KERNEL_LOCK_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
/** @brief Please use this macro to create a new lock. */
|
||||
class LockClass
|
||||
{
|
||||
struct SpinLockData
|
||||
{
|
||||
uint64_t LockData = 0x0;
|
||||
const char *CurrentHolder = "(nul)";
|
||||
const char *AttemptingToGet = "(nul)";
|
||||
uint64_t Count = 0;
|
||||
};
|
||||
void DeadLock(SpinLockData Lock);
|
||||
|
||||
private:
|
||||
SpinLockData LockData;
|
||||
bool IsLocked = false;
|
||||
|
||||
public:
|
||||
SpinLockData *GetLockData() { return &LockData; }
|
||||
int Lock(const char *FunctionName);
|
||||
int Unlock();
|
||||
};
|
||||
|
||||
/** @brief Please use this macro to create a new smart lock. */
|
||||
class SmartLockClass
|
||||
{
|
||||
private:
|
||||
LockClass *LockPointer = nullptr;
|
||||
|
||||
public:
|
||||
SmartLockClass(LockClass &Lock, const char *FunctionName)
|
||||
{
|
||||
this->LockPointer = &Lock;
|
||||
this->LockPointer->Lock(FunctionName);
|
||||
}
|
||||
~SmartLockClass() { this->LockPointer->Unlock(); }
|
||||
};
|
||||
|
||||
/** @brief Create a new lock (can be used with SmartCriticalSection). */
|
||||
#define NewLock(Name) LockClass Name
|
||||
/** @brief Simple lock that is automatically released when the scope ends. */
|
||||
#define SmartLock(LockClassName) SmartLockClass CONCAT(lock##_, __COUNTER__)(LockClassName, __FUNCTION__)
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // !__FENNIX_KERNEL_LOCK_H__
|
5
Userspace/libc/src/main.c
Normal file
5
Userspace/libc/src/main.c
Normal file
@ -0,0 +1,5 @@
|
||||
/* TODO: Show a message or something */
|
||||
int _start()
|
||||
{
|
||||
return -1;
|
||||
}
|
30
Userspace/libc/src/mem/LibAllocImplementation.cpp
Normal file
30
Userspace/libc/src/mem/LibAllocImplementation.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
#include <types.h>
|
||||
#include "../lock.hpp"
|
||||
|
||||
#include "../../../../Kernel/syscalls.h"
|
||||
|
||||
NewLock(liballocLock);
|
||||
|
||||
extern "C" int liballoc_lock()
|
||||
{
|
||||
return liballocLock.Lock(__FUNCTION__);
|
||||
}
|
||||
|
||||
extern "C" int liballoc_unlock()
|
||||
{
|
||||
return liballocLock.Unlock();
|
||||
}
|
||||
|
||||
extern "C" void *liballoc_alloc(size_t Pages)
|
||||
{
|
||||
return (void *)syscall6(sc_mmap, NULL,
|
||||
Pages * 0x1000,
|
||||
sc_PROT_READ | sc_PROT_WRITE,
|
||||
sc_MAP_ANONYMOUS | sc_MAP_PRIVATE,
|
||||
-1, 0);
|
||||
}
|
||||
|
||||
extern "C" int liballoc_free(void *Address, size_t Pages)
|
||||
{
|
||||
return syscall2(sc_munmap, (uintptr_t)Address, Pages * 0x1000);
|
||||
}
|
789
Userspace/libc/src/mem/liballoc_1_1.c
Normal file
789
Userspace/libc/src/mem/liballoc_1_1.c
Normal file
@ -0,0 +1,789 @@
|
||||
#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
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
// #include <debug.h>
|
||||
|
||||
#define FLUSH() fflush(stdout)
|
||||
#define atexit(x) atexit(x)
|
||||
// #define printf(m, ...) trace(m, ##__VA_ARGS__)
|
||||
|
||||
#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;
|
||||
}
|
74
Userspace/libc/src/mem/liballoc_1_1.h
Normal file
74
Userspace/libc/src/mem/liballoc_1_1.h
Normal file
@ -0,0 +1,74 @@
|
||||
#ifndef _LIBALLOC_H
|
||||
#define _LIBALLOC_H
|
||||
|
||||
#include <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) __##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
|
1588
Userspace/libc/src/print/printf.c
Normal file
1588
Userspace/libc/src/print/printf.c
Normal file
File diff suppressed because it is too large
Load Diff
194
Userspace/libc/src/print/printf.h
Normal file
194
Userspace/libc/src/print/printf.h
Normal file
@ -0,0 +1,194 @@
|
||||
/**
|
||||
* @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 <types.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 __attribute__((visibility("default")))
|
||||
#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
|
||||
int putchar(int 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_
|
11
Userspace/libc/src/setjmp.c
Normal file
11
Userspace/libc/src/setjmp.c
Normal file
@ -0,0 +1,11 @@
|
||||
#include <setjmp.h>
|
||||
|
||||
PUBLIC int setjmp(jmp_buf env)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PUBLIC __attribute__((noreturn)) void longjmp(jmp_buf env, int value)
|
||||
{
|
||||
_exit(value);
|
||||
}
|
29
Userspace/libc/src/std/ctype.c
Normal file
29
Userspace/libc/src/std/ctype.c
Normal file
@ -0,0 +1,29 @@
|
||||
#include <ctype.h>
|
||||
|
||||
#include <sys/types.h> // For PUBLIC
|
||||
|
||||
PUBLIC int tolower(int c)
|
||||
{
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
{
|
||||
c -= 'A';
|
||||
c += 'a';
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
PUBLIC int toupper(int c)
|
||||
{
|
||||
if (c >= 'a' && c <= 'z')
|
||||
{
|
||||
c -= 'a';
|
||||
c += 'A';
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
PUBLIC int isspace(int c)
|
||||
{
|
||||
return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f' || c == '\v';
|
||||
}
|
10
Userspace/libc/src/std/errno.c
Normal file
10
Userspace/libc/src/std/errno.c
Normal file
@ -0,0 +1,10 @@
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/types.h> // For PUBLIC
|
||||
|
||||
int __local_stub_errno = 0;
|
||||
|
||||
PUBLIC int *__errno_location(void)
|
||||
{
|
||||
return &__local_stub_errno;
|
||||
}
|
132
Userspace/libc/src/std/io/file.c
Normal file
132
Userspace/libc/src/std/io/file.c
Normal file
@ -0,0 +1,132 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <fennix/syscall.h>
|
||||
#include <sys/types.h> // For PUBLIC
|
||||
|
||||
PUBLIC FILE *stdin = NULL;
|
||||
PUBLIC FILE *stdout = NULL;
|
||||
PUBLIC FILE *stderr = NULL;
|
||||
|
||||
PUBLIC FILE *freopen(const char *filename, const char *mode, FILE *stream)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PUBLIC FILE *fopen(const char *filename, const char *mode)
|
||||
{
|
||||
int fd = syscall2(sc_open, (uint64_t)filename, (uint64_t)mode);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
FILE *FilePtr = malloc(sizeof(FILE));
|
||||
FilePtr->_fileno = fd;
|
||||
return FilePtr;
|
||||
}
|
||||
|
||||
PUBLIC size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
|
||||
{
|
||||
if (ptr == NULL || stream == NULL || size == 0 || nmemb == 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
syscall3(sc_lseek, stream->_fileno, stream->_offset, SEEK_SET);
|
||||
return syscall3(sc_read, (uint64_t)stream->_fileno, (uint64_t)ptr, size * nmemb);
|
||||
}
|
||||
|
||||
PUBLIC size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
|
||||
{
|
||||
if (ptr == NULL || stream == NULL || size == 0 || nmemb == 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
syscall3(sc_lseek, stream->_fileno, stream->_offset, SEEK_SET);
|
||||
return syscall3(sc_write, (uint64_t)stream->_fileno, (uint64_t)ptr, size * nmemb);
|
||||
}
|
||||
|
||||
PUBLIC int fclose(FILE *fp)
|
||||
{
|
||||
if (fp == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return EOF;
|
||||
}
|
||||
|
||||
return syscall1(sc_close, fp->_fileno);
|
||||
}
|
||||
|
||||
PUBLIC off_t fseek(FILE *stream, off_t offset, int whence)
|
||||
{
|
||||
if (stream == NULL || whence < 0 || whence > 2)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
off_t new_offset = syscall3(sc_lseek, stream->_fileno, offset, whence);
|
||||
if (new_offset < 0)
|
||||
return -1;
|
||||
stream->_offset = new_offset;
|
||||
return new_offset;
|
||||
}
|
||||
|
||||
PUBLIC long ftell(FILE *stream)
|
||||
{
|
||||
return stream->_offset;
|
||||
}
|
||||
|
||||
PUBLIC int fflush(FILE *stream)
|
||||
{
|
||||
if (stream == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return EOF;
|
||||
}
|
||||
|
||||
errno = ENOSYS;
|
||||
return EOF;
|
||||
}
|
||||
|
||||
PUBLIC int fprintf(FILE *stream, const char *format, ...)
|
||||
{
|
||||
if (stream == NULL || format == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
const int ret = vfprintf(stream, format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
PUBLIC void setbuf(FILE *stream, char *buf)
|
||||
{
|
||||
}
|
||||
|
||||
PUBLIC int vfprintf(FILE *stream, const char *format, va_list arg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PUBLIC int vsscanf(const char *s, const char *format, va_list arg)
|
||||
{
|
||||
}
|
||||
|
||||
PUBLIC int sscanf(const char *s, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
const int ret = vsscanf(s, format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
9
Userspace/libc/src/std/io/get.c
Normal file
9
Userspace/libc/src/std/io/get.c
Normal file
@ -0,0 +1,9 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <fennix/syscall.h>
|
||||
|
||||
#include <sys/types.h> // For PUBLIC
|
||||
|
||||
PUBLIC int fgetc(FILE *stream)
|
||||
{
|
||||
}
|
34
Userspace/libc/src/std/io/put.c
Normal file
34
Userspace/libc/src/std/io/put.c
Normal file
@ -0,0 +1,34 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <fennix/syscall.h>
|
||||
|
||||
#include <sys/types.h> // For PUBLIC
|
||||
|
||||
PUBLIC int fputc(int c, FILE *stream)
|
||||
{
|
||||
// FIXME
|
||||
// if (stream == NULL)
|
||||
// {
|
||||
// errno = EBADF;
|
||||
// return EOF;
|
||||
// }
|
||||
char str[2] = {c, '\0'};
|
||||
// return syscall3(sys_KernelCTL, KCTL_PRINT, str, 0);
|
||||
}
|
||||
|
||||
PUBLIC int putc(int c, FILE *stream) { return fputc(c, stream); }
|
||||
|
||||
PUBLIC int fputs(const char *s, FILE *stream)
|
||||
{
|
||||
for (int i = 0; s[i] != '\0'; i++)
|
||||
fputc(s[i], stream);
|
||||
}
|
||||
|
||||
PUBLIC int puts(const char *s)
|
||||
{
|
||||
for (int i = 0; s[i] != '\0'; i++)
|
||||
fputc(s[i], stdout);
|
||||
}
|
||||
|
||||
PUBLIC int putchar(int c) { return fputc(c, stdout); }
|
||||
PUBLIC void perror(const char *s) { fputs(s, stderr); }
|
87
Userspace/libc/src/std/lib.c
Normal file
87
Userspace/libc/src/std/lib.c
Normal file
@ -0,0 +1,87 @@
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <fennix/syscall.h>
|
||||
|
||||
#include "../mem/liballoc_1_1.h"
|
||||
|
||||
PUBLIC void abort(void)
|
||||
{
|
||||
syscall1(sc_exit, -0xAB057);
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
PUBLIC int atexit(void (*function)(void))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
PUBLIC void exit(int status)
|
||||
{
|
||||
_exit(status);
|
||||
}
|
||||
|
||||
PUBLIC int atoi(const char *nptr)
|
||||
{
|
||||
uint64_t Length = strlen((char *)nptr);
|
||||
if (nptr)
|
||||
while (nptr[Length] != '\0')
|
||||
++Length;
|
||||
uint64_t OutBuffer = 0;
|
||||
uint64_t Power = 1;
|
||||
for (uint64_t i = Length; i > 0; --i)
|
||||
{
|
||||
OutBuffer += (nptr[i - 1] - 48) * Power;
|
||||
Power *= 10;
|
||||
}
|
||||
return OutBuffer;
|
||||
}
|
||||
|
||||
PUBLIC char **environ = NULL;
|
||||
|
||||
PUBLIC char *getenv(const char *name)
|
||||
{
|
||||
char **env = environ;
|
||||
if (env == NULL)
|
||||
return NULL;
|
||||
size_t len = strlen(name);
|
||||
while (*env != NULL)
|
||||
{
|
||||
if ((strncmp(*env, name, len) == 0) && ((*env)[len] == '='))
|
||||
return &(*env)[len + 1];
|
||||
++env;
|
||||
}
|
||||
}
|
||||
|
||||
PUBLIC void *malloc(size_t Size) { return PREFIX(malloc)(Size); }
|
||||
PUBLIC void *realloc(void *Address, size_t Size) { return PREFIX(realloc)(Address, Size); }
|
||||
PUBLIC void *calloc(size_t Count, size_t Size) { return PREFIX(calloc)(Count, Size); }
|
||||
PUBLIC void free(void *Address)
|
||||
{
|
||||
PREFIX(free)
|
||||
(Address);
|
||||
}
|
||||
|
||||
PUBLIC int system(const char *command)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
PUBLIC double atof(const char *nptr)
|
||||
{
|
||||
// FIXME: This is a very bad implementation of atof.
|
||||
uint64_t Length = strlen((char *)nptr);
|
||||
if (nptr)
|
||||
while (nptr[Length] != '\0')
|
||||
++Length;
|
||||
double OutBuffer = 0;
|
||||
double Power = 1;
|
||||
for (uint64_t i = Length; i > 0; --i)
|
||||
{
|
||||
OutBuffer += (nptr[i - 1] - 48) * Power;
|
||||
Power *= 10;
|
||||
}
|
||||
return OutBuffer;
|
||||
}
|
17
Userspace/libc/src/std/spawn.c
Normal file
17
Userspace/libc/src/std/spawn.c
Normal file
@ -0,0 +1,17 @@
|
||||
#include <spawn.h>
|
||||
|
||||
int posix_spawn(pid_t *pid, const char *path,
|
||||
const posix_spawn_file_actions_t *file_actions,
|
||||
const posix_spawnattr_t *attrp,
|
||||
char *const argv[],
|
||||
char *const envp[])
|
||||
{
|
||||
}
|
||||
|
||||
int posix_spawnp(pid_t *pid, const char *file,
|
||||
const posix_spawn_file_actions_t *file_actions,
|
||||
const posix_spawnattr_t *attrp,
|
||||
char *const argv[],
|
||||
char *const envp[])
|
||||
{
|
||||
}
|
13
Userspace/libc/src/std/std_init.c
Normal file
13
Userspace/libc/src/std/std_init.c
Normal file
@ -0,0 +1,13 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../../../Kernel/syscalls.h"
|
||||
|
||||
void __libc_init_std(void)
|
||||
{
|
||||
/* FIXME: Temporal workaround */
|
||||
// int IsCritical = syscall1(_KernelCTL, 6 /* KCTL_IS_CRITICAL */);
|
||||
}
|
||||
|
||||
void __libc_fini_std(void)
|
||||
{
|
||||
}
|
346
Userspace/libc/src/std/string/memop.c
Normal file
346
Userspace/libc/src/std/string/memop.c
Normal file
@ -0,0 +1,346 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include <sys/types.h> // For PUBLIC
|
||||
|
||||
/* Some of the functions are from musl library */
|
||||
/* https://www.musl-libc.org/ */
|
||||
/*
|
||||
Copyright © 2005-2020 Rich Felker, et al.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
PUBLIC void *memcpy(void *dest, const void *src, size_t n)
|
||||
{
|
||||
unsigned char *d = dest;
|
||||
const unsigned char *s = src;
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define LS >>
|
||||
#define RS <<
|
||||
#else
|
||||
#define LS <<
|
||||
#define RS >>
|
||||
#endif
|
||||
|
||||
typedef uint32_t __attribute__((__may_alias__)) u32;
|
||||
uint32_t w, x;
|
||||
|
||||
for (; (uintptr_t)s % 4 && n; n--)
|
||||
*d++ = *s++;
|
||||
|
||||
if ((uintptr_t)d % 4 == 0)
|
||||
{
|
||||
for (; n >= 16; s += 16, d += 16, n -= 16)
|
||||
{
|
||||
*(u32 *)(d + 0) = *(u32 *)(s + 0);
|
||||
*(u32 *)(d + 4) = *(u32 *)(s + 4);
|
||||
*(u32 *)(d + 8) = *(u32 *)(s + 8);
|
||||
*(u32 *)(d + 12) = *(u32 *)(s + 12);
|
||||
}
|
||||
if (n & 8)
|
||||
{
|
||||
*(u32 *)(d + 0) = *(u32 *)(s + 0);
|
||||
*(u32 *)(d + 4) = *(u32 *)(s + 4);
|
||||
d += 8;
|
||||
s += 8;
|
||||
}
|
||||
if (n & 4)
|
||||
{
|
||||
*(u32 *)(d + 0) = *(u32 *)(s + 0);
|
||||
d += 4;
|
||||
s += 4;
|
||||
}
|
||||
if (n & 2)
|
||||
{
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
}
|
||||
if (n & 1)
|
||||
{
|
||||
*d = *s;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
if (n >= 32)
|
||||
{
|
||||
switch ((uintptr_t)d % 4)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
w = *(u32 *)s;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
n -= 3;
|
||||
for (; n >= 17; s += 16, d += 16, n -= 16)
|
||||
{
|
||||
x = *(u32 *)(s + 1);
|
||||
*(u32 *)(d + 0) = (w LS 24) | (x RS 8);
|
||||
w = *(u32 *)(s + 5);
|
||||
*(u32 *)(d + 4) = (x LS 24) | (w RS 8);
|
||||
x = *(u32 *)(s + 9);
|
||||
*(u32 *)(d + 8) = (w LS 24) | (x RS 8);
|
||||
w = *(u32 *)(s + 13);
|
||||
*(u32 *)(d + 12) = (x LS 24) | (w RS 8);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
w = *(u32 *)s;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
n -= 2;
|
||||
for (; n >= 18; s += 16, d += 16, n -= 16)
|
||||
{
|
||||
x = *(u32 *)(s + 2);
|
||||
*(u32 *)(d + 0) = (w LS 16) | (x RS 16);
|
||||
w = *(u32 *)(s + 6);
|
||||
*(u32 *)(d + 4) = (x LS 16) | (w RS 16);
|
||||
x = *(u32 *)(s + 10);
|
||||
*(u32 *)(d + 8) = (w LS 16) | (x RS 16);
|
||||
w = *(u32 *)(s + 14);
|
||||
*(u32 *)(d + 12) = (x LS 16) | (w RS 16);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
w = *(u32 *)s;
|
||||
*d++ = *s++;
|
||||
n -= 1;
|
||||
for (; n >= 19; s += 16, d += 16, n -= 16)
|
||||
{
|
||||
x = *(u32 *)(s + 3);
|
||||
*(u32 *)(d + 0) = (w LS 8) | (x RS 24);
|
||||
w = *(u32 *)(s + 7);
|
||||
*(u32 *)(d + 4) = (x LS 8) | (w RS 24);
|
||||
x = *(u32 *)(s + 11);
|
||||
*(u32 *)(d + 8) = (w LS 8) | (x RS 24);
|
||||
w = *(u32 *)(s + 15);
|
||||
*(u32 *)(d + 12) = (x LS 8) | (w RS 24);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (n & 16)
|
||||
{
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
}
|
||||
|
||||
if (n & 8)
|
||||
{
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
}
|
||||
|
||||
if (n & 4)
|
||||
{
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
}
|
||||
|
||||
if (n & 2)
|
||||
{
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
}
|
||||
|
||||
if (n & 1)
|
||||
{
|
||||
*d = *s;
|
||||
}
|
||||
return dest;
|
||||
#endif
|
||||
|
||||
for (; n; n--)
|
||||
*d++ = *s++;
|
||||
return dest;
|
||||
}
|
||||
|
||||
PUBLIC void *memset(void *dest, int c, size_t n)
|
||||
{
|
||||
unsigned char *s = dest;
|
||||
size_t k;
|
||||
|
||||
if (!n)
|
||||
return dest;
|
||||
|
||||
s[0] = c;
|
||||
s[n - 1] = c;
|
||||
|
||||
if (n <= 2)
|
||||
return dest;
|
||||
|
||||
s[1] = c;
|
||||
s[2] = c;
|
||||
s[n - 2] = c;
|
||||
s[n - 3] = c;
|
||||
|
||||
if (n <= 6)
|
||||
return dest;
|
||||
|
||||
s[3] = c;
|
||||
s[n - 4] = c;
|
||||
|
||||
if (n <= 8)
|
||||
return dest;
|
||||
|
||||
k = -(uintptr_t)s & 3;
|
||||
s += k;
|
||||
n -= k;
|
||||
n &= -4;
|
||||
|
||||
#ifdef __GNUC__
|
||||
typedef uint32_t __attribute__((__may_alias__)) u32;
|
||||
typedef uint64_t __attribute__((__may_alias__)) u64;
|
||||
|
||||
u32 c32 = ((u32)-1) / 255 * (unsigned char)c;
|
||||
*(u32 *)(s + 0) = c32;
|
||||
*(u32 *)(s + n - 4) = c32;
|
||||
|
||||
if (n <= 8)
|
||||
return dest;
|
||||
|
||||
*(u32 *)(s + 4) = c32;
|
||||
*(u32 *)(s + 8) = c32;
|
||||
*(u32 *)(s + n - 12) = c32;
|
||||
*(u32 *)(s + n - 8) = c32;
|
||||
|
||||
if (n <= 24)
|
||||
return dest;
|
||||
|
||||
*(u32 *)(s + 12) = c32;
|
||||
*(u32 *)(s + 16) = c32;
|
||||
*(u32 *)(s + 20) = c32;
|
||||
*(u32 *)(s + 24) = c32;
|
||||
*(u32 *)(s + n - 28) = c32;
|
||||
*(u32 *)(s + n - 24) = c32;
|
||||
*(u32 *)(s + n - 20) = c32;
|
||||
*(u32 *)(s + n - 16) = c32;
|
||||
|
||||
k = 24 + ((uintptr_t)s & 4);
|
||||
s += k;
|
||||
n -= k;
|
||||
|
||||
u64 c64 = c32 | ((u64)c32 << 32);
|
||||
for (; n >= 32; n -= 32, s += 32)
|
||||
{
|
||||
*(u64 *)(s + 0) = c64;
|
||||
*(u64 *)(s + 8) = c64;
|
||||
*(u64 *)(s + 16) = c64;
|
||||
*(u64 *)(s + 24) = c64;
|
||||
}
|
||||
#else
|
||||
for (; n; n--, s++)
|
||||
*s = c;
|
||||
#endif
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
PUBLIC void *memmove(void *dest, const void *src, size_t n)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
typedef __attribute__((__may_alias__)) size_t WT;
|
||||
#define WS (sizeof(WT))
|
||||
#endif
|
||||
|
||||
char *d = dest;
|
||||
const char *s = src;
|
||||
|
||||
if (d == s)
|
||||
return d;
|
||||
|
||||
if ((uintptr_t)s - (uintptr_t)d - n <= -2 * n)
|
||||
return memcpy(d, s, n);
|
||||
|
||||
if (d < s)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
if ((uintptr_t)s % WS == (uintptr_t)d % WS)
|
||||
{
|
||||
while ((uintptr_t)d % WS)
|
||||
{
|
||||
if (!n--)
|
||||
return dest;
|
||||
|
||||
*d++ = *s++;
|
||||
}
|
||||
for (; n >= WS; n -= WS, d += WS, s += WS)
|
||||
*(WT *)d = *(WT *)s;
|
||||
}
|
||||
#endif
|
||||
for (; n; n--)
|
||||
*d++ = *s++;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
if ((uintptr_t)s % WS == (uintptr_t)d % WS)
|
||||
{
|
||||
while ((uintptr_t)(d + n) % WS)
|
||||
{
|
||||
if (!n--)
|
||||
return dest;
|
||||
|
||||
d[n] = s[n];
|
||||
}
|
||||
while (n >= WS)
|
||||
n -= WS, *(WT *)(d + n) = *(WT *)(s + n);
|
||||
}
|
||||
#endif
|
||||
while (n)
|
||||
n--, d[n] = s[n];
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
125
Userspace/libc/src/std/string/string.c
Normal file
125
Userspace/libc/src/std/string/string.c
Normal file
@ -0,0 +1,125 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "../../mem/liballoc_1_1.h"
|
||||
|
||||
PUBLIC size_t strlen(const char *str)
|
||||
{
|
||||
long unsigned i = 0;
|
||||
if (str)
|
||||
while (str[i] != '\0')
|
||||
++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
PUBLIC int strcmp(const char *l, const char *r)
|
||||
{
|
||||
for (; *l == *r && *l; l++, r++)
|
||||
;
|
||||
return *(unsigned char *)l - *(unsigned char *)r;
|
||||
}
|
||||
|
||||
PUBLIC int strncmp(const char *s1, const char *s2, size_t n)
|
||||
{
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
char c1 = s1[i], c2 = s2[i];
|
||||
if (c1 != c2)
|
||||
return c1 - c2;
|
||||
if (!c1)
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
PUBLIC int strcasecmp(const char *s1, const char *s2)
|
||||
{
|
||||
const unsigned char *p1 = (const unsigned char *)s1;
|
||||
const unsigned char *p2 = (const unsigned char *)s2;
|
||||
int result;
|
||||
if (p1 == p2)
|
||||
return 0;
|
||||
while ((result = tolower(*p1) - tolower(*p2++)) == 0)
|
||||
if (*p1++ == '\0')
|
||||
break;
|
||||
return result;
|
||||
}
|
||||
|
||||
PUBLIC int strncasecmp(const char *string1, const char *string2, size_t count)
|
||||
{
|
||||
if (count)
|
||||
{
|
||||
const unsigned char *s1 = (const unsigned char *)string1;
|
||||
const unsigned char *s2 = (const unsigned char *)string2;
|
||||
int result;
|
||||
do
|
||||
{
|
||||
if ((result = tolower(*s1) - tolower(*s2++)) != 0 || !*s1++)
|
||||
break;
|
||||
} while (--count);
|
||||
return result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
PUBLIC char *strstr(const char *haystack, const char *needle)
|
||||
{
|
||||
const char *a = haystack, *b = needle;
|
||||
while (1)
|
||||
{
|
||||
if (!*b)
|
||||
return (char *)haystack;
|
||||
if (!*a)
|
||||
return NULL;
|
||||
if (*a++ != *b++)
|
||||
{
|
||||
a = ++haystack;
|
||||
b = needle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PUBLIC char *strncpy(char *destination, const char *source, unsigned long num)
|
||||
{
|
||||
if (destination == NULL)
|
||||
return NULL;
|
||||
char *ptr = destination;
|
||||
while (*source && num--)
|
||||
{
|
||||
*destination = *source;
|
||||
destination++;
|
||||
source++;
|
||||
}
|
||||
*destination = '\0';
|
||||
return ptr;
|
||||
}
|
||||
|
||||
PUBLIC char *strdup(const char *s)
|
||||
{
|
||||
char *buf = (char *)__malloc(strlen((char *)s) + 1);
|
||||
strncpy(buf, s, strlen(s) + 1);
|
||||
return buf;
|
||||
}
|
||||
|
||||
PUBLIC char *strchr(char const *s, int c)
|
||||
{
|
||||
size_t len = strlen(s);
|
||||
for (size_t i = 0; i < len; i++)
|
||||
if (s[i] == c)
|
||||
return (char *)s + i;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PUBLIC char *strrchr(char const *s, int c)
|
||||
{
|
||||
size_t len = strlen(s);
|
||||
size_t pos = len;
|
||||
|
||||
while (s[pos] != c && pos-- != 0)
|
||||
;
|
||||
|
||||
if (pos == len)
|
||||
return NULL;
|
||||
|
||||
return (char *)s + pos;
|
||||
}
|
14
Userspace/libc/src/std/sys/wait.c
Normal file
14
Userspace/libc/src/std/sys/wait.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include <sys/wait.h>
|
||||
|
||||
PUBLIC pid_t wait(int *wstatus)
|
||||
{
|
||||
return waitpid(-1, &wstatus, 0);
|
||||
}
|
||||
|
||||
PUBLIC pid_t waitpid(pid_t pid, int *wstatus, int options)
|
||||
{
|
||||
}
|
||||
|
||||
PUBLIC int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options)
|
||||
{
|
||||
}
|
18
Userspace/libc/src/std/sys_stat.c
Normal file
18
Userspace/libc/src/std/sys_stat.c
Normal file
@ -0,0 +1,18 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <sys/types.h> // For PUBLIC
|
||||
|
||||
PUBLIC int mkdir(const char *path, mode_t mode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PUBLIC int remove(const char *pathname)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PUBLIC int rename(const char *oldpath, const char *newpath)
|
||||
{
|
||||
return 0;
|
||||
}
|
51
Userspace/libc/src/std/uni/exe.c
Normal file
51
Userspace/libc/src/std/uni/exe.c
Normal file
@ -0,0 +1,51 @@
|
||||
#include <unistd.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include "../../../Kernel/syscalls.h"
|
||||
|
||||
PUBLIC int execl(const char *pathname, const char *arg, ...)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
PUBLIC int execlp(const char *file, const char *arg, ...)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
PUBLIC int execle(const char *pathname, const char *arg, ...)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
PUBLIC int execv(const char *pathname, char *const argv[])
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
PUBLIC int execvp(const char *file, char *const argv[])
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
PUBLIC int execvpe(const char *file, char *const argv[], char *const envp[])
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
PUBLIC int execve(const char *pathname, char *const argv[], char *const envp[])
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
PUBLIC pid_t fork(void)
|
||||
{
|
||||
return syscall0(sc_fork);
|
||||
}
|
14
Userspace/libc/src/std/uni/sleep.c
Normal file
14
Userspace/libc/src/std/uni/sleep.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include <unistd.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include "../../../Kernel/syscalls.h"
|
||||
|
||||
PUBLIC unsigned int sleep(unsigned int seconds)
|
||||
{
|
||||
// return syscall1(sys_Sleep, seconds * 1000000);
|
||||
}
|
||||
|
||||
PUBLIC int usleep(useconds_t usec)
|
||||
{
|
||||
// return syscall1(sys_Sleep, usec);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user