Compare commits

...

46 Commits

Author SHA1 Message Date
0041300a00
style(kernel/elf): change code style
Some checks failed
Build OS / Build Cross-Compiler & Toolchain (push) Has been cancelled
Deploy Website / Deploy Website to GitHub Pages (push) Has been cancelled
Build OS / Analyze (c-cpp) (push) Has been cancelled
Build OS / Build OS (push) Has been cancelled
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 12:06:23 +00:00
fe6d7f4b08
fix(kernel/syscalls): remove unused variable 'vma' in linux_fchmod
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 11:01:57 +00:00
a1622cc885
ci: fix 'tmp_rootfs/sys/drv/': No such file or directory
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 10:53:38 +00:00
bd32020876
revert: last commit
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 10:53:07 +00:00
44323c85a3
ci: rootfs structure was not created
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 10:48:53 +00:00
027d77ed66
fix(devcontainer): move installation of autoconf and automake
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 09:15:39 +00:00
bbb70eb621
feat: add advanced options for Fennix boot menu in grub.cfg
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 07:13:13 +00:00
1593e3107d
fix(kernel/syscalls): convert error codes in linux_getdents64 to Linux
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 07:12:11 +00:00
1a48d05042
feat(kernel/syscalls): implement semi-stub linux_sysinfo
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 06:46:26 +00:00
75dd958316
feat(kernel/syscalls): implemented stub linux_syslog
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 06:32:51 +00:00
cccbfd2c95
build: add libstdc++ target
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 06:17:34 +00:00
bf20bd89ed
build(kernel): add -fdiagnostics-all-candidates flag
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 06:16:23 +00:00
c3fd55bb00
fix(devcontainer): set network mode to host
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 06:15:32 +00:00
c660a7fe4f
fix(kernel/elf): interpreter loading is now correctly implemented
ref: linux @ fs/binfmt_elf.c
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-04-03 06:15:12 +00:00
91ad0e14df
test(kernel): expand coroutine tests
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-31 09:39:22 +00:00
a6ca98987e
fix(kernel/scheduler): threads were skipped if one has affinity for other core
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-30 19:08:18 +00:00
f8f08a11db
refactor: add SYS_DEBUG_REPORT
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-30 18:42:04 +00:00
5d64c05446
feat(kernel): enhance chrono and thread
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-30 18:41:05 +00:00
a1064d8978
feat(kernel): add std::terminate() function
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-30 18:07:26 +00:00
6d01cf4e69
refactor(kernel): check for __cpp_impl_coroutine in <coroutine>
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-30 17:36:24 +00:00
ffd992cd74
refactor(kernel): improve future implementation
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-29 23:39:44 +00:00
8d71ed0ad5
refactor(kernel): remove 'foreach' macro
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-29 22:43:07 +00:00
93d897e95c
feat(kernel): update stl headers
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-29 18:27:57 +00:00
31181d5b5d
refactor(kernel/syscalls): improve linux_execve implementation
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 18:45:25 +00:00
2f18d390e4
fix(kernel/tty): add stub implementation for TIOCSCTTY ioctl
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 16:46:55 +00:00
5ffb0e704d
refactor(kernel/syscalls): add fixme comments for Ctrl+Alt+Del reboot commands
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 16:42:59 +00:00
ad0c1e15e0
fix(kernel/syscalls): add null check for argp in linux_ioctl function
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 16:41:58 +00:00
b74d4db23b
fix(kernel): update device file references from 'kcon' to 'console'
Feels more right to be 'console'.

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 16:09:16 +00:00
022d99f795
refactor(kernel): remove unused kernel argument from SpawnInit()
There is no reason to use this

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 16:04:46 +00:00
3482131b3f
fix(kernel/scheduler): use GetKernelProcess() for idle threads
This will make the init process to be pid 1

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 16:00:22 +00:00
0a32c19923
refactor(kernel): comment out printf declarations in <stdio.h> and include <printf.h> instead
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 15:56:09 +00:00
36c5c8ad67
fix(kernel/elf): segment mapping and handling of program headers were wrongly implemented
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 15:55:29 +00:00
6240d6638f
feat(kernel/syscalls): implement linux_chmod and linux_fchmod
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 15:52:50 +00:00
7491f19f9a
feat(kernel): implement handling symbolic links in paths
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 14:33:29 +00:00
13d52897b8
feat(kernel): update configuration
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 14:31:22 +00:00
4cc058ab42
feat(kernel/elf): add OS-specific segment types and GNU properties
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 02:09:00 +00:00
a7f754c5e8
fix(kernel): options were not properly parsed
Had to set the context.index to 0 because here argv[0] is not the program name.

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 01:07:27 +00:00
9304cafe0c
feat(kernel): update cargs to v1.2.0
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 00:46:34 +00:00
7b42b46942
style(kernel): tab spaces in cargs.c
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-27 00:13:03 +00:00
2ce0e0ed79
feat(kernel/syscalls): add SYS_DEBUG_REPORT syscall
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-26 23:25:16 +00:00
d69eb73a59
chore: update CHANGELOG.md
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-26 23:24:24 +00:00
aa8f415b98
ci: set fetch-depth to 0 for submodule checkout
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-26 23:24:01 +00:00
ec792f1fe2
docs: update contributing guidelines for commit messages and versioning
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-26 23:18:11 +00:00
4c31568329
fix(devcontainer): update XAUTHORITY source to use localEnv
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-26 23:00:29 +00:00
e9dd70c6c4
feat(kernel): add <utf8.h> header
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-26 23:00:10 +00:00
4e9d25143e
fix(kernel): add LD_LIBRARY_PATH
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-26 02:33:03 +00:00
96 changed files with 4776 additions and 1514 deletions

View File

@ -24,20 +24,6 @@ RUN apt-get -y install --no-install-recommends \
file \
python3-dev
# Required packages for building gcc & binutils
RUN <<EOF
wget https://launchpad.net/ubuntu/+archive/primary/+files/autoconf_2.69-11.1_all.deb -O /tmp/autoconf.deb
sudo dpkg --force-all -i /tmp/autoconf.deb
EOF
# Required packages for building gcc & binutils
RUN <<EOF
wget https://ftp.gnu.org/gnu/automake/automake-1.15.1.tar.gz -O /tmp/automake.tar.gz
tar -xzf /tmp/automake.tar.gz -C /tmp
cd /tmp/automake-1.15.1
./configure && make && sudo make install
EOF
# Required packages for building qemu
RUN apt-get -y install --no-install-recommends \
git \
@ -122,3 +108,20 @@ echo PATH=$PATH:/workspaces/Fennix/cross/bin >> /etc/profile
EOF
ENV CHMOD_KVM=1
# Remove autoconf & automake
RUN sudo apt-get -y remove autoconf automake
# Required packages for building gcc & binutils
RUN <<EOF
wget https://launchpad.net/ubuntu/+archive/primary/+files/autoconf_2.69-11.1_all.deb -O /tmp/autoconf.deb
sudo dpkg --force-all -i /tmp/autoconf.deb
EOF
# Required packages for building gcc & binutils
RUN <<EOF
wget https://ftp.gnu.org/gnu/automake/automake-1.15.1.tar.gz -O /tmp/automake.tar.gz
tar -xzf /tmp/automake.tar.gz -C /tmp
cd /tmp/automake-1.15.1
./configure && make && sudo make install
EOF

View File

@ -32,7 +32,7 @@
"type": "bind"
},
{
"source": "${env:XAUTHORITY}",
"source": "${localEnv:XAUTHORITY}",
"target": "/home/vscode/.Xauthority",
"type": "bind"
},
@ -43,6 +43,7 @@
}
],
"runArgs": [
"--privileged"
"--privileged",
"--network=host"
]
}

View File

@ -121,6 +121,7 @@ jobs:
- uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- name: Cache cross Folder
id: cache-cross

View File

@ -6,21 +6,45 @@ All notable changes to this project will be documented in this file.
### <!-- 0 -->🚀 Features
- *(coreutils)* Implement coreutils and compile it using cmake
- *(devcontainer)* Install meson in Dockerfile
- *(devcontainer)* Add libtool and libltdl-dev packages
- *(initrd)* Add /etc/hosts file
- *(kernel)* Add stub device /dev/fb0
- *(kernel)* Add SHA-512 implementation
- *(kernel)* Move kernel note to a separate file
- *(kernel)* Add hot and cold attributes to optimize function performance
- *(kernel)* Enable SIMD by default
- *(kernel)* Update limine
- *(kernel)* Add KERNEL_HHDM_OFFSET macro
- *(kernel)* Add <utf8.h> header
- *(kernel/api)* Implement i386 syscall wrappers
- *(kernel/api)* Implement arm syscall wrappers
- *(kernel/api)* Add fcntl.h
- *(kernel/driver)* Add ReloadDriver method to manage driver reloading
- *(kernel/driver)* Add CreateDeviceFile method
- *(kernel/driver)* Add CreateDeviceFile function in the API
- *(kernel/driver)* Implement built-in driver support
- *(kernel/driver)* Implement driver sha512 verification
- *(kernel/drivers)* Migrate drivers to the kernel
- *(kernel/drivers)* Add trusted drivers list
- *(kernel/pci)* Add device initialization method for PCI devices
- *(kernel/syscalls)* Implement sys_fork()
- *(kernel/syscalls)* Implement uname syscall
- *(kernel/syscalls)* Add fcntl() syscall
- *(userspace)* Add dummy libstdc++ library
- *(userspace/apps/sys/init)* Handle termination signals for graceful shutdown
- *(userspace/apps/test)* Update utest
- *(userspace/apps/test/libc_test)* Add more tests
- *(userspace/apps/test/libc_test)* Rewrite a lot of the code and improve debugging with vscode using .devcontainer
- *(userspace/apps/test/utest)* Add TestProcess function for executing test programs
- *(userspace/apps/usr)* Stub implementation for mdview
- *(userspace/coreutils)* Implement arch command
- *(userspace/coreutils)* Add test command
- *(userspace/coreutils)* Add stub "admin" command
- *(userspace/coreutils)* Add alias command
- *(userspace/coreutils)* Add stub "sh" command
- *(userspace/coreutils)* Improve fennix shell implementation
- *(userspace/libc)* Implement strcpy function
- *(userspace/libc)* Implement all <string.h> functions
- *(userspace/libc)* Complete <string.h> implementation
@ -44,25 +68,45 @@ All notable changes to this project will be documented in this file.
- *(userspace/libc)* Implementation <fenv.h> header
- *(userspace/libc)* Implement <math.h> header
- *(userspace/libc)* Add experimental __aeabi_dcmpun() function
- *(userspace/libc)* Define TIOC*WINSZ constants in <sys/ioctl.h>
- *(userspace/libc)* Add <regex.h> header
- *(userspace/libc)* Add <getopt.h> header
- *(userspace/libc)* Support for linux target
- *(userspace/libc)* Implement access()
- *(userspace/libc)* Implement brk(), chdir() and getcwd()
- *(userspace/libc)* Implement functions for porting apps
- *(userspace/libs)* Add libexpat, libffi and libxml2
- *(userspace/libs/libdemo)* Add template library
- *(userspace/libs/libm)* Add stub libm
- *(No Category)* Synchronize syscalls.h
- *(No Category)* Add /etc/hostname file
### <!-- 1 -->🐛 Bug Fixes
- *(devcontainer)* Qemu cannot access /dev/kvm "failed to initialize kvm: Permission denied"
- *(devcontainer)* Update XAUTHORITY source to use localEnv
- *(drivers)* Remove drivers that are now in kernel
- *(kernel)* Add TZ environment variable to init process
- *(kernel)* Fix empty initialization of std::string (str = "")
- *(kernel)* Crash on ACPI shutdown/reboot
- *(kernel)* Compilation issues due to header changes
- *(kernel)* Add LD_LIBRARY_PATH
- *(kernel/driver)* Remove unused device handling code in daemon
- *(kernel/driver)* Node device & offset were not set for new created files under /dev
- *(kernel/driver)* Set unused file system operation pointers to nullptr
- *(kernel/driver)* Filter out non-.drv files in driver loading
- *(kernel/pci)* Map BAR address using PWT and PCD flags
- *(kernel/pci)* Fix MapPCIAddresses when BAR size of zero
- *(kernel/syscalls)* Cast syscall arguments to scarg type for call_time
- *(kernel/tty)* Temporal removal of ICANON checking
- *(userspace)* Change version of libc and coreutils
- *(userspace/apps/test)* Fix noreturn compiler warning
- *(userspace/apps/test)* Update expected results for rounding and special functions
- *(userspace/apps/test)* Adjust fflush(stdout) calls for better output control
- *(userspace/apps/test)* Make gcc shut up about "infinite recursion detected"
- *(userspace/coreutils)* Handle combined uname options (-sv, -np, etc.)
- *(userspace/coreutils)* Fix test command to correctly detect the bracket
- *(userspace/libc)* Fix error handling in ioctl function
- *(userspace/libc)* Include <ctype.h> in stdlib.c
- *(userspace/libc)* Cast status to int in __check_errno for proper error handling
@ -76,20 +120,33 @@ All notable changes to this project will be documented in this file.
- *(userspace/libc)* Disable debug info in memory allocation functions
- *(userspace/libc)* Fix wrong implementation of ioctl()
- *(userspace/libc)* Add libgcc link to fix softfloat
- *(userspace/libc)* Fix puts() in interpreter
- *(userspace/libc)* Missing include <sys/ioctl.h>
- *(userspace/libc)* Remove stub macros in termios.c
- *(userspace/libc)* Implement gethostname()
- *(userspace/libc)* Implement uname()
- *(userspace/libc)* Add .gitkeep to arch directories
- *(userspace/libc)* Mark ABI and build ID notes as used to prevent optimization removal
- *(vscode)* Problem matcher lagging the interface
- *(No Category)* Fixme
- *(No Category)* Fixme
- *(No Category)* Correct project name references in license headers
- *(No Category)* Accidentally hit CTRL+Z
### <!-- 10 -->💼 Other
- *(devcontainer)* Improve Dev Container development
- *(devcontainer)* Potential fix for "failed to initialize kvm: Permission denied"
- *(devcontainer)* Install cmake too
- *(kernel)* Fix compiling issues on i386
- *(kernel)* Fix compiling issues on arm
- *(kernel)* Fix i386 build
- *(tools)* Rewrite makefile to be more efficient and easy to understand
- *(tools)* Fix gdb error 'Scripting in the "Python" language is not supported in this copy of GDB.'
- *(userspace)* Update vscode launch configuration and Makefiles for utest and libc_test
- *(userspace/coreutils)* Generate symlink "[" on install
- *(userspace/libc)* Correctly detect linux in cmake
- *(vscode)* Add separated tasks for building bootloader, kernel, drivers, userspace, and image
- *(No Category)* Initial commit
- *(No Category)* Delete README.md
@ -1696,17 +1753,26 @@ Use SetWorkingDirectory()
- *(No Category)* Add <sys/socket.h> for socket programming support
- *(No Category)* Implement strcoll()
- *(No Category)* Implement qsort, realloc and reallocarray functions in stdlib
- *(No Category)* Add Clean, Build & Run tasks for vscode
### <!-- 2 -->🚜 Refactor
- *(driver/api)* Fix formatting
- *(driver/api)* Delegate memory allocation and deallocation to DriverManager
- *(kernel)* Remove unused TaskingPanic() function
- *(kernel/pci)* Simplify PCI device initialization by delegating to PCIManager
- *(kernel/syscalls)* Simplify argument handling in HandleNativeSyscalls
- *(rootfs)* Change "initrd" to "rootfs"
- *(rootfs)* Reorganize file structure and remove unnecessary .gitkeep files
- *(tests)* Remove obsolete SIMD and web test files
- *(tools)* Update boot configurations
- *(userspace)* Move uname program to coreutils
- *(userspace)* Build using cmake
- *(userspace/apps/test)* :recycle: move all functions in one file
- *(userspace/apps/test/libc_test)* Remove deprecated string test files
- *(userspace/coreutils)* Improve uname command
- *(userspace/coreutils)* Change code style
- *(userspace/libc)* Replace syscall2 with call_kill in kill function
- *(userspace/libc)* Implement pthread_sigmask, sigaddset, sigfillset & sigprocmask
- *(userspace/libs)* Rename libdemo to libexample
@ -1714,6 +1780,7 @@ Use SetWorkingDirectory()
- *(No Category)* Fix build on i386
- *(No Category)* Fix softfloat on aarch64 and arm
- *(No Category)* Fix release building for aarch64 and arm
- *(No Category)* Sync headers
### <!-- 3 -->📚 Documentation
@ -1723,6 +1790,14 @@ Use SetWorkingDirectory()
- *(syscalls)* Add documentation for FBIOGET_SCREEN_INFO ioctl
- *(No Category)* Remove .dockerignore, Dockerfile, and compose.yaml
- *(No Category)* Update README.md
- *(No Category)* Update build instructions
- *(No Category)* Add note in echo.c PrintHelp()
- *(No Category)* Update contributing guidelines for commit messages and versioning
### <!-- 5 -->🎨 Styling
- *(kernel)* Format document
### <!-- 6 -->🧪 Testing
@ -1734,6 +1809,8 @@ Use SetWorkingDirectory()
### <!-- 7 -->⚙️ Miscellaneous Tasks
- *(devcontainer)* Rename dev container (libc_test)
- *(devcontainer)* Cleanup devcontainer.json file
- *(userspace/coreutils)* Update .gitignore
- *(userspace/libc)* Update vscode workspace config
- *(vscode)* Add conventional commit scopes for kernel
- *(vscode)* Add recommended extensions for improved development experience
@ -1798,6 +1875,9 @@ Use SetWorkingDirectory()
- *(No Category)* Fix ci
- *(No Category)* Fix limine in ci build
- *(No Category)* Add "push: never" to devcontainers/ci
- *(No Category)* Add git-cliff
- *(No Category)* Add CHANGELOG.md in artifacts
- *(No Category)* Separate github pages deploy workflow
<!-- generated by git-cliff -->

View File

@ -62,6 +62,8 @@ Follow the coding style used in the repository to ensure consistency. Adhere to:
- Start function and global declaration names with an uppercase letter.
- Start local variable names with a lowercase letter.
- Maintain consistent formatting and commenting guidelines.
- Commit messages must follow [Conventional Commits](https://conventionalcommits.org).
- Release versions must follow [Semantic Versioning](https://semver.org).
Refer to the [style guide document](STYLE_GUIDE.md) if available.

View File

@ -674,6 +674,8 @@ typedef enum
*/
SYS_API_VERSION = 0,
SYS_DEBUG_REPORT = 1,
/* I/O */
/**

View File

@ -34,7 +34,10 @@
"kernel",
"kernel/pci",
"kernel/driver",
"kernel/drivers"
"kernel/drivers",
"kernel/elf",
"kernel/scheduler",
"kernel/tty"
]
}
}

View File

@ -68,6 +68,7 @@ ifeq ($(DEBUG), 1)
# CFLAGS += -pg
# CFLAGS += -finstrument-functions
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage -fsanitize=undefined
CXXFLAGS += -fdiagnostics-all-candidates
ifeq ($(OSARCH), amd64)
CFLAGS += -fverbose-asm
endif # amd64
@ -111,7 +112,7 @@ $(KERNEL_FILENAME): $(OBJ)
# https://gcc.gnu.org/projects/cxx-status.html
%.o: %.cpp $(HEADERS)
$(info Compiling $<)
$(__CONF_CXX) $(CFLAGS) -fcoroutines $(CFLAG_STACK_PROTECTOR) $(WARNCFLAG) -std=c++20 -c $< -o $@ -fno-rtti
$(__CONF_CXX) $(CFLAGS) $(CXXFLAGS) -fcoroutines $(CFLAG_STACK_PROTECTOR) $(WARNCFLAG) -std=c++20 -c $< -o $@ -fno-rtti
%.o: %.S
$(info Compiling $<)

View File

@ -571,7 +571,7 @@ namespace v0
__PCIArray *head = nullptr;
__PCIArray *array = nullptr;
foreach (auto &dev in Devices)
for (auto &dev : Devices)
{
/* TODO: optimize memory allocation */
PCI::PCIDevice *dptr = (PCI::PCIDevice *)vma->RequestPages(TO_PAGES(sizeof(PCI::PCIDevice)));

View File

@ -110,7 +110,7 @@ namespace Driver
return;
}
foreach (const auto &drvNode in drvDirNode->Children)
for (const auto &drvNode : drvDirNode->Children)
{
debug("Checking driver %s", drvNode->Path.c_str());
if (!drvNode->IsRegularFile())
@ -169,7 +169,7 @@ namespace Driver
return;
}
foreach (auto &var in Drivers)
for (auto &var : Drivers)
{
DriverObject &Drv = var.second;
@ -224,7 +224,7 @@ namespace Driver
void Manager::UnloadAllDrivers()
{
foreach (auto &var in Drivers)
for (auto &var : Drivers)
{
DriverObject *Drv = &var.second;
if (!Drv->Initialized)
@ -240,7 +240,7 @@ namespace Driver
if (!Drv->InterruptHandlers->empty())
{
foreach (auto &rInt in * Drv->InterruptHandlers)
for (auto &rInt : *Drv->InterruptHandlers)
{
Interrupts::RemoveHandler((void (*)(CPU::TrapFrame *))rInt.second);
}
@ -256,7 +256,7 @@ namespace Driver
if (Drivers.size() == 0)
return;
foreach (auto Driver in Drivers)
for (auto Driver : Drivers)
{
if (!Driver.second.Initialized)
continue;
@ -517,11 +517,11 @@ namespace Driver
{
AssertReturnError(pltrelSize != nullptr, -ENOEXEC);
std::vector<Elf64_Dyn> symtab = Execute::ELFGetDynamicTag_x86_64(File, DT_SYMTAB);
std::vector<Elf64_Dyn> symtab = Execute::ELFGetDynamicTag(File, DT_SYMTAB);
Elf64_Sym *symbols = (Elf64_Sym *)((uintptr_t)Drv.BaseAddress + symtab[0].d_un.d_ptr);
std::vector<Elf64_Dyn> StrTab = Execute::ELFGetDynamicTag_x86_64(File, DT_STRTAB);
char *DynStr = (char *)((uintptr_t)Drv.BaseAddress + StrTab[0].d_un.d_ptr);
std::vector<Elf64_Dyn> StrTab = Execute::ELFGetDynamicTag(File, DT_STRTAB);
char *dynStr = (char *)((uintptr_t)Drv.BaseAddress + StrTab[0].d_un.d_ptr);
Elf64_Rela *rela = (Elf64_Rela *)(Drv.BaseAddress + dyn->d_un.d_ptr);
for (size_t i = 0; i < (pltrelSize->d_un.d_val / sizeof(Elf64_Rela)); i++)
@ -536,7 +536,7 @@ namespace Driver
Elf64_Xword symIndex = ELF64_R_SYM(r->r_info);
Elf64_Sym *sym = symbols + symIndex;
const char *symName = DynStr + sym->st_name;
const char *symName = dynStr + sym->st_name;
debug("Resolving symbol %s", symName);
*reloc = (uintptr_t)GetSymbolByName(symName, driverInfo.Version.APIVersion);

View File

@ -191,7 +191,7 @@ namespace Interrupts
void *ctx, bool Critical)
{
/* Just log a warning if the interrupt is already registered. */
foreach (auto ev in RegisteredEvents)
for (auto ev : RegisteredEvents)
{
if (ev.IRQ == InterruptNumber &&
ev.Callback == Callback)
@ -279,7 +279,7 @@ namespace Interrupts
{ return a.Priority < b.Priority; });
#ifdef DEBUG
foreach (auto ev in RegisteredEvents)
for (auto ev : RegisteredEvents)
{
void *fct = ev.IsHandler
? ev.Data
@ -421,7 +421,7 @@ namespace Interrupts
Handler::Handler(int InterruptNumber, bool Critical)
{
foreach (auto ev in RegisteredEvents)
for (auto ev : RegisteredEvents)
{
if (ev.IRQ == InterruptNumber)
{

View File

@ -79,7 +79,7 @@ namespace Memory
this->Expanded = Parent->Expanded;
std::list<AllocatedPages> ParentAllocatedPages = Parent->GetAllocatedPages();
foreach (auto Page in ParentAllocatedPages)
for (auto Page : ParentAllocatedPages)
{
void *NewPhysical = vma->RequestPages(1);
debug("Forking address %#lx to %#lx", Page.PhysicalAddress, NewPhysical);

View File

@ -82,7 +82,7 @@ namespace Memory
func("%#lx, %lld", Address, Count);
SmartLock(MgrLock);
foreach (auto &apl in AllocatedPagesList)
for (auto &apl : AllocatedPagesList)
{
if (apl.VirtualAddress != Address)
continue;
@ -128,7 +128,7 @@ namespace Memory
/* No need to remap pages, the page table will be destroyed */
Virtual vmm(this->Table);
foreach (auto ap in AllocatedPagesList)
for (auto ap : AllocatedPagesList)
{
KernelAllocator.FreePages(ap.PhysicalAddress, ap.PageCount);

View File

@ -29,7 +29,7 @@ namespace Memory
{
SmartLock(MgrLock);
uint64_t Size = 0;
foreach (auto ap in AllocatedPagesList)
for (auto ap : AllocatedPagesList)
Size += ap.PageCount;
return FROM_PAGES(Size);
}
@ -214,7 +214,7 @@ namespace Memory
return false;
}
foreach (auto sr in SharedRegions)
for (auto sr : SharedRegions)
{
uintptr_t Start = (uintptr_t)sr.Address;
uintptr_t End = (uintptr_t)sr.Address + sr.Length;
@ -263,7 +263,7 @@ namespace Memory
void VirtualMemoryArea::FreeAllPages()
{
SmartLock(MgrLock);
foreach (auto ap in AllocatedPagesList)
for (auto ap : AllocatedPagesList)
{
KernelAllocator.FreePages(ap.Address, ap.PageCount);
Virtual vmm(this->Table);
@ -287,7 +287,7 @@ namespace Memory
Virtual vmm(this->Table);
SmartLock(MgrLock);
foreach (auto &ap in Parent->AllocatedPagesList)
for (auto &ap : Parent->AllocatedPagesList)
{
if (ap.Protected)
{
@ -339,7 +339,7 @@ namespace Memory
(uintptr_t)ap.Address + (ap.PageCount * PAGE_SIZE));
}
foreach (auto &sr in Parent->SharedRegions)
for (auto &sr : Parent->SharedRegions)
{
MgrLock.Unlock();
void *Address = this->CreateCoWRegion(sr.Address, sr.Length,
@ -496,7 +496,7 @@ namespace Memory
/* No need to remap pages, the page table will be destroyed */
SmartLock(MgrLock);
foreach (auto ap in AllocatedPagesList)
for (auto ap : AllocatedPagesList)
KernelAllocator.FreePages(ap.Address, ap.PageCount);
}
}

View File

@ -489,12 +489,12 @@ nsa void DisplayProcessScreen(CPU::ExceptionFrame *Frame, bool IgnoreReady = tru
bool pRdy = false;
bool showNote = false;
/* FIXME: This is slow */
foreach (auto Process in Plist)
for (auto Process : Plist)
{
bool ignore = true;
if (Process->State == Tasking::Ready && IgnoreReady)
{
foreach (auto Thread in Process->Threads)
for (auto Thread : Process->Threads)
{
if (Thread->State == Tasking::Ready)
continue;
@ -522,7 +522,7 @@ nsa void DisplayProcessScreen(CPU::ExceptionFrame *Frame, bool IgnoreReady = tru
: "none");
bool tRdy = false;
foreach (auto Thread in Process->Threads)
for (auto Thread : Process->Threads)
{
if (Thread->State == Tasking::Ready && IgnoreReady)
{

View File

@ -1079,7 +1079,7 @@ namespace PCI
std::list<PCIDevice> Manager::FindPCIDevice(uint8_t Class, uint8_t Subclass, uint8_t ProgIF)
{
std::list<PCIDevice> DeviceFound;
foreach (auto dev in Devices)
for (auto dev : Devices)
{
if (dev.Header->Class == Class &&
dev.Header->Subclass == Subclass &&
@ -1094,7 +1094,7 @@ namespace PCI
std::list<PCIDevice> Manager::FindPCIDevice(uint16_t VendorID, uint16_t DeviceID)
{
std::list<PCIDevice> DeviceFound;
foreach (auto dev in Devices)
for (auto dev : Devices)
{
if (dev.Header->VendorID == VendorID &&
dev.Header->DeviceID == DeviceID)
@ -1109,11 +1109,11 @@ namespace PCI
std::list<uint16_t> DeviceIDs)
{
std::list<PCIDevice> DeviceFound;
foreach (auto dev in Devices)
for (auto dev : Devices)
{
foreach (auto VendorID in VendorIDs)
for (auto VendorID : VendorIDs)
{
foreach (auto DeviceID in DeviceIDs)
for (auto DeviceID : DeviceIDs)
{
if (dev.Header->VendorID == VendorID &&
dev.Header->DeviceID == DeviceID)

View File

@ -67,8 +67,7 @@ namespace Random
if (RDRANDFlag)
{
uint16_t RDRANDValue = 0;
asmv("1: rdrand %0; jnc 1b"
: "=r"(RDRANDValue));
asmv("1: rdrand %0; jnc 1b" : "=r"(RDRANDValue));
return RDRANDValue;
}
@ -84,8 +83,7 @@ namespace Random
if (RDRANDFlag)
{
uint32_t RDRANDValue = 0;
asmv("1: rdrand %0; jnc 1b"
: "=r"(RDRANDValue));
asmv("1: rdrand %0; jnc 1b" : "=r"(RDRANDValue));
return RDRANDValue;
}
@ -101,8 +99,7 @@ namespace Random
if (RDRANDFlag)
{
uintptr_t RDRANDValue = 0;
asmv("1: rdrand %0; jnc 1b"
: "=r"(RDRANDValue));
asmv("1: rdrand %0; jnc 1b" : "=r"(RDRANDValue));
return RDRANDValue;
}

View File

@ -324,7 +324,7 @@ namespace SymbolResolver
debug("- %#lx", this);
debug("Freeing %d symbols",
this->SymTable.size());
foreach (auto tbl in this->SymTable)
for (auto tbl : this->SymTable)
delete[] tbl.FunctionName;
}
}

View File

@ -64,7 +64,7 @@ extern "C" uintptr_t SystemCallsHandler(SyscallsFrame *Frame)
Tasking::TaskInfo *Ttinfo = &thisThread->Info;
uintptr_t ret;
if (Config.UseLinuxSyscalls)
if (Config.LinuxSubsystem)
{
ret = HandleLinuxSyscalls(Frame);
goto Ret;

View File

@ -156,7 +156,7 @@ namespace Driver::TeleTypeDevices
S_IRGRP |
S_IFCHR;
ids.kcon = DriverManager->CreateDeviceFile(DriverID, "kcon", mode, &ops);
ids.kcon = DriverManager->CreateDeviceFile(DriverID, "console", mode, &ops);
/* c rw- rw- rw- */
mode = S_IRUSR | S_IWUSR |

View File

@ -966,7 +966,7 @@ namespace Driver::AHCI
// ctx->Device->Header->Command |= PCI::PCI_COMMAND_INTX_DISABLE;
// std::list<PCI::PCIDevice> Devices = PCIManager->FindPCIDevice(VendorIDs, DeviceIDs);
// foreach (auto dev in Devices)
// for (auto dev : Devices)
// Interrupts::RemoveHandler(OnInterruptReceived, iLine(dev));
return 0;
}

View File

@ -28,78 +28,84 @@ namespace Execute
BinaryType GetBinaryType(FileNode *Node)
{
debug("Checking binary type of %s", Node->Path.c_str());
BinaryType Type;
BinaryType type;
if (Node == nullptr)
ReturnLogError((BinaryType)-ENOENT, "Node is null");
Elf32_Ehdr ELFHeader;
Node->Read(&ELFHeader, sizeof(Elf32_Ehdr), 0);
Elf_Ehdr ehdr;
Node->Read(&ehdr, sizeof(Elf_Ehdr), 0);
mach_header MachHeader;
Node->Read(&MachHeader, sizeof(mach_header), 0);
mach_header mach;
Node->Read(&mach, sizeof(mach_header), 0);
IMAGE_DOS_HEADER MZHeader;
Node->Read(&MZHeader, sizeof(IMAGE_DOS_HEADER), 0);
IMAGE_DOS_HEADER mz;
Node->Read(&mz, sizeof(IMAGE_DOS_HEADER), 0);
/* Check ELF header. */
if (ELFHeader.e_ident[EI_MAG0] == ELFMAG0 &&
ELFHeader.e_ident[EI_MAG1] == ELFMAG1 &&
ELFHeader.e_ident[EI_MAG2] == ELFMAG2 &&
ELFHeader.e_ident[EI_MAG3] == ELFMAG3)
if (ehdr.e_ident[EI_MAG0] == ELFMAG0 &&
ehdr.e_ident[EI_MAG1] == ELFMAG1 &&
ehdr.e_ident[EI_MAG2] == ELFMAG2 &&
ehdr.e_ident[EI_MAG3] == ELFMAG3)
{
debug("Image - ELF");
Type = BinaryType::BinTypeELF;
type = BinaryType::BinTypeELF;
goto Success;
}
if (MachHeader.magic == MH_MAGIC || MachHeader.magic == MH_CIGAM)
if (mach.magic == MH_MAGIC || mach.magic == MH_CIGAM)
{
debug("Image - Mach-O");
Type = BinaryType::BinTypeMachO;
type = BinaryType::BinTypeMachO;
goto Success;
}
/* Check MZ header. */
else if (MZHeader.e_magic == IMAGE_DOS_SIGNATURE)
else if (mz.e_magic == IMAGE_DOS_SIGNATURE)
{
IMAGE_NT_HEADERS PEHeader;
Node->Read(&PEHeader, sizeof(IMAGE_NT_HEADERS), MZHeader.e_lfanew);
IMAGE_NT_HEADERS pe;
Node->Read(&pe, sizeof(IMAGE_NT_HEADERS), mz.e_lfanew);
IMAGE_OS2_HEADER NEHeader;
Node->Read(&NEHeader, sizeof(IMAGE_OS2_HEADER), MZHeader.e_lfanew);
IMAGE_OS2_HEADER ne;
Node->Read(&ne, sizeof(IMAGE_OS2_HEADER), mz.e_lfanew);
/* TODO: LE, EDOS */
if (PEHeader.Signature == IMAGE_NT_SIGNATURE)
if (pe.Signature == IMAGE_NT_SIGNATURE)
{
debug("Image - PE");
Type = BinaryType::BinTypePE;
type = BinaryType::BinTypePE;
goto Success;
}
else if (NEHeader.ne_magic == IMAGE_OS2_SIGNATURE)
else if (ne.ne_magic == IMAGE_OS2_SIGNATURE)
{
debug("Image - NE");
Type = BinaryType::BinTypeNE;
type = BinaryType::BinTypeNE;
goto Success;
}
else
{
debug("Image - MZ");
Type = BinaryType::BinTypeMZ;
type = BinaryType::BinTypeMZ;
goto Success;
}
}
/* ... */
Type = BinaryType::BinTypeUnknown;
type = BinaryType::BinTypeUnknown;
Success:
return Type;
return type;
}
BinaryType GetBinaryType(std::string Path)
{
FileNode *node = fs->GetByPath(Path.c_str(), nullptr);
if (node->IsSymbolicLink())
{
char buffer[512];
node->ReadLink(buffer, sizeof(buffer));
node = fs->GetByPath(buffer, node->Parent);
}
debug("Checking binary type of %s (returning %p)", Path.c_str(), node);
assert(node != nullptr);
return GetBinaryType(node);

File diff suppressed because it is too large Load Diff

View File

@ -25,52 +25,52 @@ namespace Execute
{
bool ELFIs64(void *Header)
{
Elf32_Ehdr *ELFHeader = (Elf32_Ehdr *)Header;
if (ELFHeader->e_ident[EI_CLASS] == ELFCLASS64)
Elf_Ehdr *ehdr = (Elf_Ehdr *)Header;
if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
return true;
return false;
}
/* Originally from https://wiki.osdev.org/ELF_Tutorial */
Elf64_Shdr *GetELFSheader(Elf64_Ehdr *Header)
Elf_Shdr *GetELFSheader(Elf_Ehdr *Header)
{
return (Elf64_Shdr *)((uintptr_t)Header + Header->e_shoff);
return (Elf_Shdr *)((uintptr_t)Header + Header->e_shoff);
}
Elf64_Shdr *GetELFSection(Elf64_Ehdr *Header, uint64_t Index)
Elf_Shdr *GetELFSection(Elf_Ehdr *Header, uintptr_t Index)
{
return &GetELFSheader(Header)[Index];
}
char *GetELFStringTable(Elf64_Ehdr *Header)
char *GetELFStringTable(Elf_Ehdr *Header)
{
if (Header->e_shstrndx == SHN_UNDEF)
return nullptr;
return (char *)Header + GetELFSection(Header, Header->e_shstrndx)->sh_offset;
}
char *ELFLookupString(Elf64_Ehdr *Header, uintptr_t Offset)
char *ELFLookupString(Elf_Ehdr *Header, uintptr_t Offset)
{
char *StringTable = GetELFStringTable(Header);
if (StringTable == nullptr)
char *table = GetELFStringTable(Header);
if (table == nullptr)
return nullptr;
return StringTable + Offset;
return table + Offset;
}
Elf64_Sym *ELFLookupSymbol(Elf64_Ehdr *Header, std::string Name)
Elf_Sym *ELFLookupSymbol(Elf_Ehdr *Header, std::string Name)
{
Elf64_Shdr *SymbolTable = nullptr;
Elf64_Shdr *StringTable = nullptr;
Elf_Shdr *symTable = nullptr;
Elf_Shdr *stringTable = nullptr;
for (Elf64_Half i = 0; i < Header->e_shnum; i++)
for (Elf_Half i = 0; i < Header->e_shnum; i++)
{
Elf64_Shdr *shdr = GetELFSection(Header, i);
Elf_Shdr *shdr = GetELFSection(Header, i);
switch (shdr->sh_type)
{
case SHT_SYMTAB:
SymbolTable = shdr;
StringTable = GetELFSection(Header, shdr->sh_link);
symTable = shdr;
stringTable = GetELFSection(Header, shdr->sh_link);
break;
default:
{
@ -79,117 +79,108 @@ namespace Execute
}
}
if (SymbolTable == nullptr || StringTable == nullptr)
if (symTable == nullptr || stringTable == nullptr)
return nullptr;
for (size_t i = 0; i < (SymbolTable->sh_size / sizeof(Elf64_Sym)); i++)
for (size_t i = 0; i < (symTable->sh_size / sizeof(Elf_Sym)); i++)
{
Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
char *String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name);
Elf_Sym *sym = (Elf_Sym *)((uintptr_t)Header + symTable->sh_offset + (i * sizeof(Elf_Sym)));
char *String = (char *)((uintptr_t)Header + stringTable->sh_offset + sym->st_name);
if (strcmp(String, Name.c_str()) == 0)
return Symbol;
return sym;
}
return nullptr;
}
Elf64_Sym ELFLookupSymbol(FileNode *fd, std::string Name)
Elf_Sym ELFLookupSymbol(FileNode *fd, std::string Name)
{
#if defined(__amd64__)
Elf64_Ehdr Header{};
fd->Read(&Header, sizeof(Elf64_Ehdr), 0);
Elf_Ehdr ehdr{};
fd->Read(&ehdr, sizeof(Elf_Ehdr), 0);
Elf64_Shdr SymbolTable{};
Elf64_Shdr StringTable{};
Elf_Shdr symTable{};
Elf_Shdr stringTable{};
for (Elf64_Half i = 0; i < Header.e_shnum; i++)
for (Elf64_Half i = 0; i < ehdr.e_shnum; i++)
{
Elf64_Shdr shdr;
fd->Read(&shdr, sizeof(Elf64_Shdr), Header.e_shoff + (i * sizeof(Elf64_Shdr)));
Elf_Shdr shdr;
fd->Read(&shdr, sizeof(Elf_Shdr), ehdr.e_shoff + (i * sizeof(Elf_Shdr)));
switch (shdr.sh_type)
{
case SHT_SYMTAB:
SymbolTable = shdr;
fd->Read(&StringTable, sizeof(Elf64_Shdr), Header.e_shoff + (shdr.sh_link * sizeof(Elf64_Shdr)));
symTable = shdr;
fd->Read(&stringTable, sizeof(Elf_Shdr), ehdr.e_shoff + (shdr.sh_link * sizeof(Elf_Shdr)));
break;
default:
{
break;
}
}
}
if (SymbolTable.sh_name == 0 || StringTable.sh_name == 0)
if (symTable.sh_name == 0 || stringTable.sh_name == 0)
{
error("Symbol table not found.");
return {};
}
for (size_t i = 0; i < (SymbolTable.sh_size / sizeof(Elf64_Sym)); i++)
for (size_t i = 0; i < (symTable.sh_size / sizeof(Elf_Sym)); i++)
{
// Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
Elf64_Sym Symbol;
fd->Read(&Symbol, sizeof(Elf64_Sym), SymbolTable.sh_offset + (i * sizeof(Elf64_Sym)));
// Elf_Sym *sym = (Elf_Sym *)((uintptr_t)Header + symTable->sh_offset + (i * sizeof(Elf_Sym)));
Elf_Sym sym;
fd->Read(&sym, sizeof(Elf_Sym), symTable.sh_offset + (i * sizeof(Elf_Sym)));
// char *String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name);
char String[256];
fd->Read(&String, sizeof(String), StringTable.sh_offset + Symbol.st_name);
// char *str = (char *)((uintptr_t)Header + stringTable->sh_offset + sym->st_name);
char str[256];
fd->Read(&str, sizeof(str), stringTable.sh_offset + sym.st_name);
if (strcmp(String, Name.c_str()) == 0)
return Symbol;
if (strcmp(str, Name.c_str()) == 0)
return sym;
}
error("Symbol not found.");
#endif
return {};
}
uintptr_t ELFGetSymbolValue(Elf64_Ehdr *Header, uint64_t Table, uint64_t Index)
uintptr_t ELFGetSymbolValue(Elf_Ehdr *Header, uintptr_t Table, uintptr_t Index)
{
#if defined(__amd64__)
if (Table == SHN_UNDEF || Index == SHN_UNDEF)
return 0;
Elf64_Shdr *SymbolTable = GetELFSection(Header, Table);
uint64_t STEntries = SymbolTable->sh_size / SymbolTable->sh_entsize;
if (Index >= STEntries)
Elf_Shdr *symTable = GetELFSection(Header, Table);
uintptr_t entries = symTable->sh_size / symTable->sh_entsize;
if (Index >= entries)
{
error("Symbol index out of range %d-%u.", Table, Index);
return 0xdead;
return -1;
}
uint64_t SymbolAddress = (uint64_t)Header + SymbolTable->sh_offset;
Elf64_Sym *Symbol = &((Elf64_Sym *)SymbolAddress)[Index];
uintptr_t symbolPtr = (uintptr_t)Header + symTable->sh_offset;
Elf_Sym *sym = &((Elf_Sym *)symbolPtr)[Index];
if (Symbol->st_shndx == SHN_UNDEF)
if (sym->st_shndx == SHN_UNDEF)
{
Elf64_Shdr *StringTable = GetELFSection(Header, SymbolTable->sh_link);
const char *Name = (const char *)Header + StringTable->sh_offset + Symbol->st_name;
Elf_Shdr *stringTable = GetELFSection(Header, symTable->sh_link);
const char *name = (const char *)Header + stringTable->sh_offset + sym->st_name;
void *Target = (void *)ELFLookupSymbol(Header, Name)->st_value;
if (Target == nullptr)
void *target = (void *)ELFLookupSymbol(Header, name)->st_value;
if (target == nullptr)
{
if (ELF64_ST_BIND(Symbol->st_info) & STB_WEAK)
if (ELF64_ST_BIND(sym->st_info) & STB_WEAK)
return 0;
else
{
error("Undefined external symbol \"%s\".", Name);
return 0xdead;
error("Undefined external symbol \"%s\".", name);
return -1;
}
}
else
return (uintptr_t)Target;
return (uintptr_t)target;
}
else if (Symbol->st_shndx == SHN_ABS)
return Symbol->st_value;
else if (sym->st_shndx == SHN_ABS)
return sym->st_value;
else
{
Elf64_Shdr *Target = GetELFSection(Header, Symbol->st_shndx);
return (uintptr_t)Header + Symbol->st_value + Target->sh_offset;
Elf_Shdr *shdr = GetELFSection(Header, sym->st_shndx);
return (uintptr_t)Header + sym->st_value + shdr->sh_offset;
}
#elif defined(__i386__)
return 0xdead;
#elif defined(__aarch64__)
return 0xdead;
#endif
}
}

View File

@ -25,77 +25,72 @@ namespace Execute
{
/* Originally from https://wiki.osdev.org/ELF_Tutorial */
void ELFLoadRel(void *BaseImage,
const char *Name,
Tasking::PCB *Process)
void ELFLoadRel(void *BaseImage, const char *Name, Tasking::PCB *Process)
{
#if defined(__amd64__)
UNUSED(Name);
debug("Relocatable");
/* TODO: I have to fully implement this, but for now I will leave it as it is now. */
warn("Relocatable ELF is not fully supported yet");
Elf64_Shdr *shdr = GetELFSheader(((Elf64_Ehdr *)BaseImage));
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)BaseImage)->e_shnum; i++)
Elf_Shdr *shdr = GetELFSheader(((Elf_Ehdr *)BaseImage));
for (Elf_Half i = 0; i < ((Elf_Ehdr *)BaseImage)->e_shnum; i++)
{
Elf64_Shdr *Section = &shdr[i];
if (Section->sh_type == SHT_NOBITS)
Elf_Shdr *section = &shdr[i];
if (section->sh_type == SHT_NOBITS)
{
if (!Section->sh_size)
if (!section->sh_size)
continue;
if (Section->sh_flags & SHF_ALLOC)
if (section->sh_flags & SHF_ALLOC)
{
void *Buffer = KernelAllocator.RequestPages(TO_PAGES(Section->sh_size + 1));
memset(Buffer, 0, Section->sh_size);
void *buffer = KernelAllocator.RequestPages(TO_PAGES(section->sh_size + 1));
memset(buffer, 0, section->sh_size);
Memory::Virtual(Process->PageTable).Map((void *)Buffer, (void *)Buffer, Section->sh_size, Memory::PTFlag::RW | Memory::PTFlag::US);
Memory::Virtual(Process->PageTable).Map((void *)buffer, (void *)buffer, section->sh_size, Memory::PTFlag::RW | Memory::PTFlag::US);
Section->sh_offset = (uintptr_t)Buffer - (uintptr_t)BaseImage;
debug("Section %ld", Section->sh_size);
section->sh_offset = (uintptr_t)buffer - (uintptr_t)BaseImage;
debug("Section %ld", section->sh_size);
}
}
}
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)BaseImage)->e_shnum; i++)
for (Elf_Half i = 0; i < ((Elf_Ehdr *)BaseImage)->e_shnum; i++)
{
Elf64_Shdr *Section = &shdr[i];
if (Section->sh_type == SHT_REL)
Elf_Shdr *section = &shdr[i];
if (section->sh_type == SHT_REL)
{
for (size_t Index = 0; Index < Section->sh_size / Section->sh_entsize; Index++)
for (size_t i = 0; i < section->sh_size / section->sh_entsize; i++)
{
Elf64_Rel *RelTable = &((Elf64_Rel *)((uintptr_t)BaseImage + Section->sh_offset))[Index];
Elf64_Shdr *Target = GetELFSection(((Elf64_Ehdr *)BaseImage), Section->sh_info);
Elf_Rel *rel = &((Elf_Rel *)((uintptr_t)BaseImage + section->sh_offset))[i];
Elf_Shdr *target = GetELFSection(((Elf_Ehdr *)BaseImage), section->sh_info);
uintptr_t *RelAddress = (uintptr_t *)(((uintptr_t)BaseImage + Target->sh_offset) + RelTable->r_offset);
uint64_t SymbolValue = 0;
uintptr_t *relPtr = (uintptr_t *)(((uintptr_t)BaseImage + target->sh_offset) + rel->r_offset);
uintptr_t value = 0;
if (ELF64_R_SYM(RelTable->r_info) != SHN_UNDEF)
if (ELF64_R_SYM(rel->r_info) != SHN_UNDEF)
{
SymbolValue = ELFGetSymbolValue(((Elf64_Ehdr *)BaseImage), Section->sh_link, ELF64_R_SYM(RelTable->r_info));
if (SymbolValue == 0xdead)
value = ELFGetSymbolValue(((Elf_Ehdr *)BaseImage), section->sh_link, ELF64_R_SYM(rel->r_info));
if (value == (uintptr_t)-1)
return;
}
switch (ELF64_R_TYPE(RelTable->r_info))
switch (ELF64_R_TYPE(rel->r_info))
{
case R_386_NONE:
break;
case R_386_32:
*RelAddress = DO_64_64(SymbolValue, *RelAddress);
*relPtr = DO_64_64(value, *relPtr);
break;
case R_386_PC32:
*RelAddress = DO_64_PC32(SymbolValue, *RelAddress, (uintptr_t)RelAddress);
*relPtr = DO_64_PC32(value, *relPtr, (uintptr_t)relPtr);
break;
default:
{
error("Unsupported relocation type: %d", ELF64_R_TYPE(RelTable->r_info));
error("Unsupported relocation type: %d", ELF64_R_TYPE(rel->r_info));
return;
}
}
debug("Symbol value: %#lx", SymbolValue);
debug("Symbol value: %#lx", value);
}
}
}
#elif defined(__i386__)
#endif
}
}

View File

@ -21,42 +21,31 @@
namespace Execute
{
std::vector<Elf64_Dyn> ELFGetDynamicTag_x86_64(FileNode *fd,
DynamicArrayTags Tag)
std::vector<Elf_Dyn> ELFGetDynamicTag(FileNode *fd, DynamicArrayTags Tag)
{
#if defined(__amd64__) || defined(__aarch64__)
std::vector<Elf64_Dyn> Ret;
std::vector<Elf_Dyn> ret;
std::vector<Elf_Phdr> phdrs = ELFGetSymbolType(fd, PT_DYNAMIC);
Elf64_Ehdr ELFHeader{};
fd->Read(&ELFHeader, sizeof(Elf64_Ehdr), 0);
std::vector<Elf64_Phdr> DYNAMICPhdrs = ELFGetSymbolType_x86_64(fd, PT_DYNAMIC);
if (DYNAMICPhdrs.size() < 1)
if (phdrs.size() < 1)
{
error("No dynamic phdrs found.");
return Ret;
debug("No dynamic phdrs found.");
return ret;
}
foreach (auto Phdr in DYNAMICPhdrs)
for (auto phdr : phdrs)
{
Elf64_Dyn Dynamic{};
for (size_t i = 0; i < Phdr.p_filesz / sizeof(Elf64_Dyn); i++)
Elf_Dyn dyn{};
for (size_t i = 0; i < phdr.p_filesz / sizeof(Elf_Dyn); i++)
{
fd->Read(&Dynamic, sizeof(Elf64_Dyn), Phdr.p_offset + (i * sizeof(Elf64_Dyn)));
if (Dynamic.d_tag != Tag)
fd->Read(&dyn, sizeof(Elf_Dyn), phdr.p_offset + (i * sizeof(Elf_Dyn)));
if (dyn.d_tag != Tag)
continue;
debug("Found dynamic tag %d at %#lx [d_val: %#lx]",
Tag, &Dynamic, Dynamic.d_un.d_val);
Ret.push_back(Dynamic);
debug("Found dynamic tag %d at %#lx [d_val: %#lx]", Tag, &dyn, dyn.d_un.d_val);
ret.push_back(dyn);
}
}
return Ret;
#elif defined(__i386__)
return {};
#endif
return ret;
}
}

View File

@ -21,33 +21,28 @@
namespace Execute
{
std::vector<Elf64_Shdr> ELFGetSections_x86_64(FileNode *fd,
const char *SectionName)
std::vector<Elf_Shdr> ELFGetSections(FileNode *fd, const char *SectionName)
{
#if defined(__amd64__) || defined(__aarch64__)
std::vector<Elf64_Shdr> Ret;
std::vector<Elf_Shdr> ret;
Elf64_Ehdr ELFHeader{};
fd->Read(&ELFHeader, sizeof(Elf64_Ehdr), 0);
Elf_Ehdr ehdr{};
fd->Read(&ehdr, sizeof(Elf_Ehdr), 0);
Elf64_Shdr *SectionHeaders = new Elf64_Shdr[ELFHeader.e_shnum];
fd->Read(SectionHeaders, sizeof(Elf64_Shdr) * ELFHeader.e_shnum, ELFHeader.e_shoff);
Elf_Shdr *sections = new Elf_Shdr[ehdr.e_shnum];
fd->Read(sections, sizeof(Elf_Shdr) * ehdr.e_shnum, ehdr.e_shoff);
char *SectionNames = new char[SectionHeaders[ELFHeader.e_shstrndx].sh_size];
fd->Read(SectionNames, SectionHeaders[ELFHeader.e_shstrndx].sh_size, SectionHeaders[ELFHeader.e_shstrndx].sh_offset);
char *sectionNames = new char[sections[ehdr.e_shstrndx].sh_size];
fd->Read(sectionNames, sections[ehdr.e_shstrndx].sh_size, sections[ehdr.e_shstrndx].sh_offset);
for (Elf64_Half i = 0; i < ELFHeader.e_shnum; ++i)
for (Elf_Half i = 0; i < ehdr.e_shnum; ++i)
{
const char *Name = SectionNames + SectionHeaders[i].sh_name;
const char *Name = sectionNames + sections[i].sh_name;
if (strcmp(Name, SectionName) == 0)
Ret.push_back(SectionHeaders[i]);
ret.push_back(sections[i]);
}
delete[] SectionHeaders;
delete[] SectionNames;
return Ret;
#elif defined(__i386__)
return {};
#endif
delete[] sections;
delete[] sectionNames;
return ret;
}
}

View File

@ -21,31 +21,26 @@
namespace Execute
{
std::vector<Elf64_Phdr> ELFGetSymbolType_x86_64(FileNode *fd,
SegmentTypes Tag)
std::vector<Elf_Phdr> ELFGetSymbolType(FileNode *fd, SegmentTypes Tag)
{
#if defined(__amd64__) || defined(__aarch64__)
std::vector<Elf64_Phdr> Ret;
std::vector<Elf_Phdr> ret;
Elf64_Ehdr ELFHeader{};
fd->Read(&ELFHeader, sizeof(Elf64_Ehdr), 0);
Elf_Ehdr ehdr{};
fd->Read(&ehdr, sizeof(Elf_Ehdr), 0);
Elf64_Phdr ProgramHeaders{};
fd->Read(&ProgramHeaders, sizeof(Elf64_Phdr), ELFHeader.e_phoff);
Elf_Phdr phdr{};
fd->Read(&phdr, sizeof(Elf_Phdr), ehdr.e_phoff);
off_t currentOffset = ELFHeader.e_phoff;
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
off_t off = ehdr.e_phoff;
for (Elf_Half i = 0; i < ehdr.e_phnum; i++)
{
if (ProgramHeaders.p_type == Tag)
Ret.push_back(ProgramHeaders);
if (phdr.p_type == Tag)
ret.push_back(phdr);
currentOffset += sizeof(Elf64_Phdr);
fd->Read(&ProgramHeaders, sizeof(Elf64_Phdr), currentOffset);
off += sizeof(Elf_Phdr);
fd->Read(&phdr, sizeof(Elf_Phdr), off);
}
return Ret;
#elif defined(__i386__)
return {};
#endif
return ret;
}
}

View File

@ -40,9 +40,20 @@ namespace Execute
return -ENOENT;
if (!fd->IsRegularFile())
return -ENOEXEC;
{
if (fd->IsSymbolicLink())
{
char buffer[512];
fd->ReadLink(buffer, sizeof(buffer));
fd = fs->GetByPath(buffer, fd->Parent);
if (fd == nullptr)
return -ENOENT;
}
else
return -ENOEXEC;
}
switch (GetBinaryType(Path))
switch (GetBinaryType(fd))
{
case BinaryType::BinTypeELF:
{
@ -101,7 +112,7 @@ namespace Execute
CriticalSection cs;
Process = Parent;
foreach (auto tcb in Process->Threads)
for (auto tcb : Process->Threads)
{
debug("Deleting thread %d", tcb->ID);
// delete tcb;
@ -142,7 +153,7 @@ namespace Execute
if (unlikely(SearchNode == nullptr))
return false;
foreach (const auto &ffd in pfdt->FileMap)
for (const auto &ffd : pfdt->FileMap)
{
if (ffd.second.Flags & O_CLOEXEC)
continue;
@ -162,13 +173,13 @@ namespace Execute
Process->tty = KernelConsole::CurrentTerminal.load();
if (!ForkStdio(Parent->stdin))
fdt->usr_open("/dev/kcon", O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
fdt->usr_open("/dev/console", O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if (!ForkStdio(Parent->stdout))
fdt->usr_open("/dev/kcon", O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
fdt->usr_open("/dev/console", O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if (!ForkStdio(Parent->stderr))
fdt->usr_open("/dev/kcon", O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
fdt->usr_open("/dev/console", O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
TCB *Thread = nullptr;
{

View File

@ -33,10 +33,14 @@ SOFTWARE.
#ifndef CAG_LIBRARY_H
#define CAG_LIBRARY_H
#include <types.h>
typedef unsigned int FILE; // TODO: Implement FILE
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
/**
* The following defines CAG_EXPORT and CAG_IMPORT which are required to export
* shared library functions.
*/
#if defined(_WIN32) || defined(__CYGWIN__)
#define CAG_EXPORT __declspec(dllexport)
#define CAG_IMPORT __declspec(dllimport)
@ -48,6 +52,10 @@ typedef unsigned int FILE; // TODO: Implement FILE
#define CAG_IMPORT
#endif
/**
* This block defines CAG_PUBLIC, which only uses CAG_EXPORT and CAG_IMPORT if
* the cargs is compiled as a shared library.
*/
#if defined(CAG_SHARED)
#if defined(CAG_EXPORTS)
#define CAG_PUBLIC CAG_EXPORT
@ -58,6 +66,16 @@ typedef unsigned int FILE; // TODO: Implement FILE
#define CAG_PUBLIC
#endif
/**
* This block defines CAG_DEPRECATED which can be used to deprecate library
* functions including a comment on the deprecation.
*/
#if (!__cplusplus && __STDC_VERSION__ >= 202311L) || (__cplusplus >= 201402L)
#define CAG_DEPRECATED(comment) [[deprecated(comment)]]
#else
#define CAG_DEPRECATED(comment)
#endif
#ifdef __cplusplus
extern "C"
{
@ -88,29 +106,24 @@ extern "C"
char **argv;
int index;
int inner_index;
int error_index;
char error_letter;
bool forced_end;
char identifier;
char *value;
} cag_option_context;
/**
* Prototype for printer used in cag_option_printer. For example fprintf have
* same prototype
*/
typedef int (*cag_printer)(void *ctx, const char *fmt, ...);
/**
* This is just a small macro which calculates the size of an array.
*/
#define CAG_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
/**
* @brief Prints all options to the terminal.
*
* This function prints all options to the terminal. This can be used to
* generate the output for a "--help" option.
*
* @param options The options which will be printed.
* @param option_count The option count which will be printed.
* @param destination The destination where the output will be printed.
*/
CAG_PUBLIC void cag_option_print(const cag_option *options, size_t option_count,
FILE *destination);
/**
* @brief Prepare argument options context for parsing.
*
@ -125,8 +138,8 @@ extern "C"
* @param argc The amount of arguments the user supplied in the main function.
* @param argv A pointer to the arguments of the main function.
*/
CAG_PUBLIC void cag_option_prepare(cag_option_context *context,
const cag_option *options, size_t option_count, int argc, char **argv);
CAG_PUBLIC void cag_option_init(cag_option_context *context,
const cag_option *options, size_t option_count, int argc, char **argv);
/**
* @brief Fetches an option from the argument list.
@ -154,7 +167,7 @@ extern "C"
* @param context The context from which the option was fetched.
* @return Returns the identifier of the option.
*/
CAG_PUBLIC char cag_option_get(const cag_option_context *context);
CAG_PUBLIC char cag_option_get_identifier(const cag_option_context *context);
/**
* @brief Gets the value from the option.
@ -180,8 +193,107 @@ extern "C"
*/
CAG_PUBLIC int cag_option_get_index(const cag_option_context *context);
/**
* @brief Retrieves the index of an invalid option.
*
* This function retrieves the index of an invalid option if the provided option
* does not match any of the options specified in the `cag_option` list. This is
* particularly useful when detailed information about an invalid option is
* required.
*
* @param context Pointer to the context from which the option was fetched.
* @return Returns the index of the invalid option, or -1 if it is not invalid.
*/
CAG_PUBLIC int cag_option_get_error_index(const cag_option_context *context);
/**
* @brief Retrieves the letter character of the invalid option.
*
* This function retrieves the character of the invalid option character
* if the provided option does not match any of the options specified in the
* `cag_option` list.
*
* @param context Pointer to the context from which the option was fetched.
* @return Returns the letter that was unknown, or 0 otherwise.
*/
CAG_PUBLIC char cag_option_get_error_letter(const cag_option_context *context);
/**
* @brief Prints the error associated with the invalid option to the specified
* destination.
*
* This function prints information about the error associated with the invalid
* option to the specified destination (such as a file stream). It helps in
* displaying the error of the current context.
*
* @param context Pointer to the context from which the option was fetched.
* @param destination Pointer to the file stream where the error information
* will be printed.
*/
#ifndef CAG_NO_FILE
CAG_PUBLIC void cag_option_print_error(const cag_option_context *context,
FILE *destination);
#endif
/**
* @brief Prints the error associated with the invalid option using user
* callback.
*
* This function prints information about the error associated with the invalid
* option using user callback. Callback prototype is same with fprintf. It helps
* in displaying the error of the current context.
*
* @param context Pointer to the context from which the option was fetched.
* @param printer The printer callback function. For example fprintf.
* @param printer_ctx The parameter for printer callback. For example fprintf
* could use parameter stderr.
*/
CAG_PUBLIC void cag_option_printer_error(const cag_option_context *context,
cag_printer printer, void *printer_ctx);
/**
* @brief Prints all options to the terminal.
*
* This function prints all options to the terminal. This can be used to
* generate the output for a "--help" option.
*
* @param options The options which will be printed.
* @param option_count The option count which will be printed.
* @param destination The destination where the output will be printed.
*/
#ifndef CAG_NO_FILE
CAG_PUBLIC void cag_option_print(const cag_option *options, size_t option_count,
FILE *destination);
#endif
/**
* @brief Prints all options using user callback.
*
* This function prints all options using user callback. This can be used to
* generate the output for a "--help" option.
* Using user callback is useful in tiny system without FILE support
*
* @param options The options which will be printed.
* @param option_count The option count which will be printed.
* @param destination The destination where the output will be printed.
* @param printer The printer callback function. For example fprintf.
* @param printer_ctx The parameter for printer callback. For example fprintf
* could use parameter stderr.
*/
CAG_PUBLIC void cag_option_printer(const cag_option *options,
size_t option_count, cag_printer printer, void *printer_ctx);
CAG_DEPRECATED(
"cag_option_prepare has been deprecated. Use cag_option_init instead.")
CAG_PUBLIC void cag_option_prepare(cag_option_context *context,
const cag_option *options, size_t option_count, int argc, char **argv);
CAG_DEPRECATED(
"cag_option_get has been deprecated. Use cag_option_get_identifier instead.")
CAG_PUBLIC char cag_option_get(const cag_option_context *context);
#ifdef __cplusplus
} // extern "C"
#endif
#endif
#endif

View File

@ -241,8 +241,14 @@ enum SegmentTypes
PT_SHLIB = 5,
PT_PHDR = 6,
PT_TLS = 7,
PT_LOOS = 0x60000000, /* OS-specific */
PT_HIOS = 0x6fffffff, /* OS-specific */
PT_LOPROC = 0x70000000,
PT_HIPROC = 0x7fffffff,
PT_GNU_EH_FRAME = (PT_LOOS + 0x474e550),
PT_GNU_STACK = (PT_LOOS + 0x474e551),
PT_GNU_RELRO = (PT_LOOS + 0x474e552),
PT_GNU_PROPERTY = (PT_LOOS + 0x474e553)
};
enum DynamicArrayTags
@ -683,6 +689,8 @@ enum SpecialSections
#define NT_MIPS_MSA 0x802
#define NT_VERSION 1
#define NT_GNU_PROPERTY_TYPE_0 5
typedef struct elf32_hdr
{
unsigned char e_ident[EI_NIDENT];
@ -962,6 +970,9 @@ typedef Elf64_Rel Elf_Rel;
typedef Elf64_Sym Elf_Sym;
typedef Elf64_Dyn Elf_Dyn;
typedef Elf64_Rela Elf_Rela;
typedef Elf64_Nhdr Elf_Nhdr;
typedef Elf64_Prstatus Elf_Prstatus;
typedef Elf64_Prpsinfo Elf_Prpsinfo;
#elif defined(__i386__) || defined(__arm__)
typedef Elf32_Addr Elf_Addr;
typedef Elf32_Half Elf_Half;
@ -976,6 +987,9 @@ typedef Elf32_Rel Elf_Rel;
typedef Elf32_Sym Elf_Sym;
typedef Elf32_Dyn Elf_Dyn;
typedef Elf32_Rela Elf_Rela;
typedef Elf32_Nhdr Elf_Nhdr;
typedef Elf32_Prstatus Elf_Prstatus;
typedef Elf32_Prpsinfo Elf_Prpsinfo;
#endif
#endif // !__FENNIX_KERNEL_ELF_H__

View File

@ -39,23 +39,6 @@ namespace Execute
BinTypeUnknown
};
struct SharedLibrary
{
char Identifier[64];
char Path[256];
uint64_t Timeout;
int RefCount;
uintptr_t MemoryImage;
size_t Length;
};
struct MmImage
{
void *Physical;
void *Virtual;
};
class ELFObject
{
private:
@ -66,20 +49,15 @@ namespace Execute
Tasking::IP ip;
void *ELFProgramHeaders;
void GenerateAuxiliaryVector_x86_32(Memory::VirtualMemoryArea *vma,
FileNode *fd, Elf32_Ehdr ELFHeader,
uint32_t EntryPoint,
uint32_t BaseAddress);
void GenerateAuxiliaryVector(Memory::VirtualMemoryArea *vma,
FileNode *fd, Elf_Ehdr ELFHeader,
uintptr_t EntryPoint,
uintptr_t BaseAddress);
void GenerateAuxiliaryVector_x86_64(Memory::VirtualMemoryArea *vma,
FileNode *fd, Elf64_Ehdr ELFHeader,
uint64_t EntryPoint,
uint64_t BaseAddress);
void LoadSegments(FileNode *fd, Tasking::PCB *TargetProcess, Elf_Ehdr &ELFHeader, uintptr_t &BaseAddress);
void LoadExec_x86_32(FileNode *fd, Tasking::PCB *TargetProcess);
void LoadExec_x86_64(FileNode *fd, Tasking::PCB *TargetProcess);
void LoadDyn_x86_32(FileNode *fd, Tasking::PCB *TargetProcess);
void LoadDyn_x86_64(FileNode *fd, Tasking::PCB *TargetProcess);
void LoadExec(FileNode *fd, Tasking::PCB *TargetProcess);
void LoadDyn(FileNode *fd, Tasking::PCB *TargetProcess);
bool LoadInterpreter(FileNode *fd, Tasking::PCB *TargetProcess);
public:
@ -105,22 +83,17 @@ namespace Execute
bool Critical = false);
bool ELFIs64(void *Header);
Elf64_Shdr *GetELFSheader(Elf64_Ehdr *Header);
Elf64_Shdr *GetELFSection(Elf64_Ehdr *Header, uint64_t Index);
char *GetELFStringTable(Elf64_Ehdr *Header);
char *ELFLookupString(Elf64_Ehdr *Header, uintptr_t Offset);
Elf64_Sym *ELFLookupSymbol(Elf64_Ehdr *Header, std::string Name);
Elf64_Sym ELFLookupSymbol(FileNode *fd, std::string Name);
uintptr_t ELFGetSymbolValue(Elf64_Ehdr *Header, uint64_t Table, uint64_t Index);
Elf_Shdr *GetELFSheader(Elf_Ehdr *Header);
Elf_Shdr *GetELFSection(Elf_Ehdr *Header, uintptr_t Index);
char *GetELFStringTable(Elf_Ehdr *Header);
char *ELFLookupString(Elf_Ehdr *Header, uintptr_t Offset);
Elf_Sym *ELFLookupSymbol(Elf_Ehdr *Header, std::string Name);
Elf_Sym ELFLookupSymbol(FileNode *fd, std::string Name);
uintptr_t ELFGetSymbolValue(Elf_Ehdr *Header, uintptr_t Table, uintptr_t Index);
std::vector<Elf64_Phdr> ELFGetSymbolType_x86_64(FileNode *fd, SegmentTypes Tag);
std::vector<Elf32_Phdr> ELFGetSymbolType_x86_32(FileNode *fd, SegmentTypes Tag);
std::vector<Elf64_Shdr> ELFGetSections_x86_64(FileNode *fd, std::string SectionName);
std::vector<Elf32_Shdr> ELFGetSections_x86_32(FileNode *fd, std::string SectionName);
std::vector<Elf64_Dyn> ELFGetDynamicTag_x86_64(FileNode *fd, DynamicArrayTags Tag);
std::vector<Elf32_Dyn> ELFGetDynamicTag_x86_32(FileNode *fd, DynamicArrayTags Tag);
std::vector<Elf_Phdr> ELFGetSymbolType(FileNode *fd, SegmentTypes Tag);
std::vector<Elf_Shdr> ELFGetSections(FileNode *fd, std::string SectionName);
std::vector<Elf_Dyn> ELFGetDynamicTag(FileNode *fd, DynamicArrayTags Tag);
}
#endif // !__FENNIX_KERNEL_FILE_EXECUTE_H__

View File

@ -674,6 +674,8 @@ typedef enum
*/
SYS_API_VERSION = 0,
SYS_DEBUG_REPORT = 1,
/* I/O */
/**

View File

@ -33,7 +33,7 @@ struct KernelConfig
bool SchedulerType;
char DriverDirectory[256];
char InitPath[256];
bool UseLinuxSyscalls;
bool LinuxSubsystem;
bool InterruptsOnCrash;
int Cores;
int IOAPICInterruptCore;

View File

@ -54,9 +54,6 @@
#define ilp inf_loop; /* Used for debugging */
#ifdef __cplusplus
#define foreach for
#define in :
#define forItr(itr, container) \
for (auto itr = container.begin(); \
itr != container.end(); ++itr)

1718
Kernel/include/utf8.h Normal file

File diff suppressed because it is too large Load Diff

126
Kernel/include_std/chrono Normal file
View File

@ -0,0 +1,126 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <ratio>
#include <type_traits>
namespace std
{
namespace chrono
{
template <class Rep, class Period = std::ratio<1>>
class duration
{
private:
Rep rep_;
std::ratio<Period::num, Period::denom> period_;
public:
constexpr duration() = default;
duration(const duration &) = default;
template <class Rep2>
constexpr explicit duration(const Rep2 &r) { rep_ = r; }
template <class Rep2, class Period2>
constexpr duration(const duration<Rep2, Period2> &d);
duration &operator=(const duration &other) = default;
constexpr Rep count() const { return rep_; }
static constexpr duration zero() noexcept;
static constexpr duration min() noexcept;
static constexpr duration max() noexcept;
constexpr std::common_type_t<duration> operator+() const;
constexpr std::common_type_t<duration> operator-() const;
constexpr duration operator++(int) { return duration(rep_++); }
constexpr duration operator--(int) { return duration(rep_--); }
constexpr duration &operator++()
{
++rep_;
return *this;
}
constexpr duration &operator--()
{
--rep_;
return *this;
}
constexpr duration &operator+=(const duration &d)
{
rep_ += d.count();
return *this;
}
constexpr duration &operator-=(const duration &d)
{
rep_ -= d.count();
return *this;
}
constexpr duration &operator*=(const Rep &rhs)
{
rep_ *= rhs;
return *this;
}
constexpr duration &operator/=(const Rep &rhs)
{
rep_ /= rhs;
return *this;
}
constexpr duration &operator%=(const Rep &rhs)
{
rep_ %= rhs;
return *this;
}
constexpr duration &operator%=(const duration &rhs)
{
rep_ %= rhs.count();
return *this;
}
};
template <class Clock, class Duration = typename Clock::duration>
class time_point;
using nanoseconds = std::chrono::duration<int64_t, std::nano>;
using microseconds = std::chrono::duration<int64_t, std::micro>;
using milliseconds = std::chrono::duration<int64_t, std::milli>;
using seconds = std::chrono::duration<int64_t>;
using minutes = std::chrono::duration<int64_t, std::ratio<60>>;
using hours = std::chrono::duration<int64_t, std::ratio<3600>>;
using days = std::chrono::duration<int64_t, std::ratio<86400>>;
using weeks = std::chrono::duration<int64_t, std::ratio<604800>>;
using months = std::chrono::duration<int64_t, std::ratio<2629746>>;
using years = std::chrono::duration<int64_t, std::ratio<31556952>>;
template <class ToDuration, class Rep, class Period>
constexpr ToDuration duration_cast(const std::chrono::duration<Rep, Period> &d)
{
return ToDuration(d.count());
}
}
}

View File

@ -15,9 +15,14 @@
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#ifndef __cpp_impl_coroutine
#error "kernel requires -fcoroutines"
#endif
namespace std
{
#if __cpp_impl_coroutine
namespace detail
{
template <class, class...>
@ -183,7 +188,4 @@ namespace std
constexpr void await_suspend(coroutine_handle<>) const noexcept {}
constexpr void await_resume() const noexcept {}
};
#else
#error "kernel requires -fcoroutines"
#endif
}

View File

@ -0,0 +1,68 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
namespace std
{
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;
#define INT8_C(val) static_cast<int_least8_t>(val)
#define INT16_C(val) static_cast<int_least16_t>(val)
#define INT32_C(val) static_cast<int_least32_t>(val)
#define INT64_C(val) static_cast<int_least64_t>(val)
#define INTMAX_C(val) static_cast<intmax_t>(val)
#define UINT8_C(val) static_cast<unsigned int_least8_t>(val)
#define UINT16_C(val) static_cast<unsigned int_least16_t>(val)
#define UINT32_C(val) static_cast<unsigned int_least32_t>(val)
#define UINT64_C(val) static_cast<unsigned int_least64_t>(val)
#define UINTMAX_C(val) static_cast<uintmax_t>(val)
}

View File

@ -16,4 +16,9 @@
*/
#pragma once
#include <convert.h>
namespace std
{
}

View File

@ -15,8 +15,7 @@
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_KERNEL_EXCEPTION_H__
#define __FENNIX_KERNEL_EXCEPTION_H__
#pragma once
#include <types.h>
@ -36,12 +35,15 @@ namespace std
typedef void (*unexpected_handler)();
[[noreturn]] void terminate() noexcept;
std::terminate_handler set_terminate(std::terminate_handler f) noexcept;
std::terminate_handler get_terminate() noexcept;
terminate_handler set_terminate(terminate_handler f) noexcept;
terminate_handler get_terminate() noexcept;
[[noreturn]] void unexpected();
std::unexpected_handler set_unexpected(std::unexpected_handler f) noexcept;
std::unexpected_handler get_unexpected() noexcept;
}
unexpected_handler set_unexpected(unexpected_handler f) noexcept;
unexpected_handler get_unexpected() noexcept;
#endif // !__FENNIX_KERNEL_EXCEPTION_H__
using exception_ptr = uintptr_t;
template <class E>
std::exception_ptr make_exception_ptr(E e) noexcept;
}

View File

@ -259,4 +259,10 @@ namespace std
return lhs < rhs;
}
};
template <class F, class... Args>
constexpr typename std::result_of<F()>::type bind(F &&f, Args &&...args);
template <class R, class F, class... Args>
constexpr R bind(F &&f, Args &&...args);
}

279
Kernel/include_std/future Normal file
View File

@ -0,0 +1,279 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <atomic>
#include <chrono>
#include <exception>
#include <mutex>
#include <thread>
#include <type_traits>
#include <system_error>
#include <utility>
#include <cstdint>
#include <memory>
namespace std
{
enum class future_errc
{
broken_promise = 0,
future_already_retrieved = 1,
promise_already_satisfied = 2,
no_state = 3
};
enum class launch : std::uint_least8_t
{
async = 0,
deferred = 1,
};
enum class future_status
{
ready,
timeout,
deferred
};
template <>
struct is_error_code_enum<future_errc> : public true_type
{
};
error_condition make_error_condition(future_errc e) noexcept;
const error_category &future_category() noexcept;
inline std::error_code make_error_code(future_errc e) noexcept
{
return std::error_code(static_cast<int>(e), future_category());
}
class future_error;
template <class R>
class promise;
template <class R>
class promise<R &>;
template <>
class promise<void>;
template <class R>
void swap(promise<R> &x, promise<R> &y) noexcept;
template <class R, class Alloc>
struct uses_allocator<promise<R>, Alloc>;
template <class R>
class future;
template <class R>
class future<R &>;
template <>
class future<void>;
template <class R>
class shared_future;
template <class R>
class shared_future<R &>;
template <>
class shared_future<void>;
template <class>
class packaged_task; // not defined
template <class R, class... ArgTypes>
class packaged_task<R(ArgTypes...)>;
template <class R, class... ArgTypes>
void swap(packaged_task<R(ArgTypes...)> &, packaged_task<R(ArgTypes...)> &) noexcept;
template <class Fn, class... Args>
future<typename result_of<Fn(Args...)>::type> async(launch policy, Fn &&fn, Args &&...args)
{
using ReturnType = std::invoke_result_t<std::decay_t<Fn>, std::decay_t<Args>...>;
if (policy == std::launch::async)
{
auto task = std::make_shared<std::packaged_task<ReturnType()>>(
std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...));
std::future<ReturnType> future = task->get_future();
std::thread([task]()
{ (*task)(); })
.detach();
return future;
}
else if (policy == std::launch::deferred)
{
return std::async(std::launch::deferred, std::forward<Fn>(fn), std::forward<Args>(args)...);
}
else
{
throw std::invalid_argument("Invalid launch policy");
}
}
template <class Fn, class... Args>
future<typename result_of<Fn(Args...)>::type> async(Fn &&fn, Args &&...args)
{
return async(std::launch::async /* | std::launch::deferred*/, std::forward<Fn>(fn), std::forward<Args>(args)...);
}
class future_error : public logic_error
{
private:
error_code ec_;
public:
future_error(const future_error &other) noexcept;
explicit future_error(std::future_errc ec);
future_error &operator=(const future_error &other) noexcept;
const std::error_code &code() const noexcept;
virtual const char *what() const noexcept;
};
template <class R>
class promise
{
private:
public:
promise() = default;
template <class Allocator>
promise(allocator_arg_t, const Allocator &a);
promise(promise &&rhs) noexcept = default;
promise(const promise &) = delete;
~promise() = default;
promise &operator=(promise &&rhs) noexcept;
promise &operator=(const promise &) = delete;
void swap(promise &other) noexcept;
future<R> get_future();
void set_value(const R &value);
void set_value(R &&value);
void set_value(R &value);
void set_value();
void set_exception(exception_ptr p);
void set_value_at_thread_exit(const R &value);
void set_value_at_thread_exit(R &&value);
void set_value_at_thread_exit(R &value);
void set_value_at_thread_exit();
void set_exception_at_thread_exit(exception_ptr p);
};
template <class R>
void swap(promise<R> &x, promise<R> &y) noexcept;
template <class R, class Alloc>
struct uses_allocator<promise<R>, Alloc>;
template <class R>
class future
{
public:
future() noexcept;
future(future &&) noexcept;
future(const future &) = delete;
~future();
future &operator=(const future &) = delete;
future &operator=(future &&) noexcept;
shared_future<R> share() noexcept;
R get();
// R &get();
// void get();
bool valid() const noexcept;
void wait() const;
template <class Rep, class Period>
future_status wait_for(const chrono::duration<Rep, Period> &rel_time) const;
template <class Clock, class Duration>
future_status wait_until(const chrono::time_point<Clock, Duration> &abs_time) const;
};
template <class R>
class shared_future
{
public:
shared_future() noexcept;
shared_future(const shared_future &rhs) noexcept;
shared_future(future<R> &&) noexcept;
shared_future(shared_future &&rhs) noexcept;
~shared_future();
shared_future &operator=(const shared_future &rhs) noexcept;
shared_future &operator=(shared_future &&rhs) noexcept;
const R &get() const;
// R &get() const;
// void get() const;
bool valid() const noexcept;
void wait() const;
template <class Rep, class Period>
future_status wait_for(const chrono::duration<Rep, Period> &rel_time) const;
template <class Clock, class Duration>
future_status wait_until(const chrono::time_point<Clock, Duration> &abs_time) const;
};
template <class>
class packaged_task;
template <class R, class... ArgTypes>
class packaged_task<R(ArgTypes...)>
{
public:
packaged_task() noexcept;
template <class F>
explicit packaged_task(F &&f);
~packaged_task();
packaged_task(const packaged_task &) = delete;
packaged_task &operator=(const packaged_task &) = delete;
packaged_task(packaged_task &&rhs) noexcept;
packaged_task &operator=(packaged_task &&rhs) noexcept;
void swap(packaged_task &other) noexcept;
bool valid() const noexcept;
future<R> get_future();
void operator()(ArgTypes...);
void make_ready_at_thread_exit(ArgTypes...);
void reset();
};
template <class R, class... ArgTypes>
packaged_task(R (*)(ArgTypes...)) -> packaged_task<R(ArgTypes...)>;
// template <class F>
// packaged_task(F) -> packaged_task<???>;
template <class R, class... ArgTypes>
void swap(packaged_task<R(ArgTypes...)> &x, packaged_task<R(ArgTypes...)> &y) noexcept;
}

View File

@ -216,7 +216,7 @@ namespace std
list(std::initializer_list<T> init, const Allocator &alloc = Allocator())
{
foreach (const_reference value in init)
for (const_reference value : init)
push_back(value);
}
@ -250,7 +250,7 @@ namespace std
list &operator=(std::initializer_list<T> ilist)
{
clear();
foreach (const_reference value in ilist)
for (const_reference value : ilist)
push_back(value);
return *this;
}
@ -273,7 +273,7 @@ namespace std
void assign(std::initializer_list<T> ilist)
{
clear();
foreach (const_reference value in ilist)
for (const_reference value : ilist)
push_back(value);
}
@ -443,7 +443,7 @@ namespace std
iterator insert(const_iterator pos, std::initializer_list<T> ilist)
{
iterator ret;
foreach (const_reference value in ilist)
for (const_reference value : ilist)
ret = insert(pos, value);
return ret;
}

View File

@ -28,7 +28,7 @@
namespace std
{
namespace __memory__detail
namespace detail
{
template <class>
constexpr bool is_unbounded_array_v = false;
@ -516,14 +516,14 @@ namespace std
}
template <class T>
std::enable_if_t<__memory__detail::is_unbounded_array_v<T>, std::unique_ptr<T>>
std::enable_if_t<detail::is_unbounded_array_v<T>, std::unique_ptr<T>>
make_unique(std::size_t n)
{
return std::unique_ptr<T>(new std::remove_extent_t<T>[n]());
}
template <class T, class... Args>
std::enable_if_t<__memory__detail::is_bounded_array_v<T>> make_unique(Args &&...) = delete;
std::enable_if_t<detail::is_bounded_array_v<T>> make_unique(Args &&...) = delete;
template <class T>
requires(!std::is_array_v<T>)
@ -603,4 +603,162 @@ namespace std
{
lhs.swap(rhs);
}
template <class T, class Alloc>
struct uses_allocator : std::integral_constant<bool, false>
{
};
template <class T, class Alloc>
constexpr bool uses_allocator_v = uses_allocator<T, Alloc>::value;
struct allocator_arg_t
{
explicit allocator_arg_t() = default;
};
constexpr std::allocator_arg_t allocator_arg{};
template <class T>
class auto_ptr;
template <>
class auto_ptr<void>;
template <class T>
class weak_ptr;
template <class T>
class shared_ptr
{
public:
using weak_type = std::weak_ptr<T>;
using element_type = std::remove_extent_t<T>;
constexpr shared_ptr() noexcept;
constexpr shared_ptr(std::nullptr_t) noexcept;
template <class Y>
explicit shared_ptr(Y *ptr);
template <class Y, class Deleter>
shared_ptr(Y *ptr, Deleter d);
template <class Deleter>
shared_ptr(std::nullptr_t ptr, Deleter d);
template <class Y, class Deleter, class Alloc>
shared_ptr(Y *ptr, Deleter d, Alloc alloc);
template <class Deleter, class Alloc>
shared_ptr(std::nullptr_t ptr, Deleter d, Alloc alloc);
template <class Y>
shared_ptr(const shared_ptr<Y> &r, element_type *ptr) noexcept;
template <class Y>
shared_ptr(shared_ptr<Y> &&r, element_type *ptr) noexcept;
shared_ptr(const shared_ptr &r) noexcept;
template <class Y>
shared_ptr(const shared_ptr<Y> &r) noexcept;
shared_ptr(shared_ptr &&r) noexcept;
template <class Y>
shared_ptr(shared_ptr<Y> &&r) noexcept;
template <class Y>
explicit shared_ptr(const std::weak_ptr<Y> &r);
template <class Y>
shared_ptr(std::auto_ptr<Y> &&r);
template <class Y, class Deleter>
shared_ptr(std::unique_ptr<Y, Deleter> &&r);
~shared_ptr();
shared_ptr &operator=(const shared_ptr &r) noexcept;
template <class Y>
shared_ptr &operator=(const shared_ptr<Y> &r) noexcept;
shared_ptr &operator=(shared_ptr &&r) noexcept;
template <class Y>
shared_ptr &operator=(shared_ptr<Y> &&r) noexcept;
template <class Y>
shared_ptr &operator=(std::auto_ptr<Y> &&r);
template <class Y, class Deleter>
shared_ptr &operator=(std::unique_ptr<Y, Deleter> &&r);
void reset() noexcept;
template <class Y>
void reset(Y *ptr);
template <class Y, class Deleter>
void reset(Y *ptr, Deleter d);
template <class Y, class Deleter, class Alloc>
void reset(Y *ptr, Deleter d, Alloc alloc);
void swap(shared_ptr &r) noexcept;
T *get() const noexcept;
// element_type *get() const noexcept;
T &operator*() const noexcept;
T *operator->() const noexcept;
element_type &operator[](std::ptrdiff_t idx) const;
long use_count() const noexcept;
bool unique() const noexcept;
explicit operator bool() const noexcept { return get() != nullptr; }
template <class Y>
bool owner_before(const shared_ptr<Y> &other) const noexcept;
template <class Y>
bool owner_before(const std::weak_ptr<Y> &other) const noexcept;
std::size_t owner_hash() const noexcept;
template <class Y>
bool owner_equal(const std::shared_ptr<Y> &other) const noexcept;
template <class Y>
bool owner_equal(const std::weak_ptr<Y> &other) const noexcept;
};
template <class T, class... Args>
shared_ptr<T> make_shared(Args &&...args);
template <class T>
shared_ptr<T> make_shared(std::size_t N);
template <class T>
shared_ptr<T> make_shared();
template <class T>
shared_ptr<T> make_shared(std::size_t N, const std::remove_extent_t<T> &u);
template <class T>
shared_ptr<T> make_shared(const std::remove_extent_t<T> &u);
template <class T>
shared_ptr<T> make_shared_for_overwrite();
template <class T>
shared_ptr<T> make_shared_for_overwrite(std::size_t N);
}

79
Kernel/include_std/ratio Normal file
View File

@ -0,0 +1,79 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <types.h>
namespace std
{
template <intmax_t Num, intmax_t Denom = 1>
class ratio
{
public:
typedef ratio<Num, Denom> type;
static constexpr intmax_t num = Num;
static constexpr intmax_t denom = Denom;
};
template <class R1, class R2>
using ratio_add = ratio<R1::num * R2::denom + R2::num * R1::denom, R1::denom * R2::denom>;
template <class R1, class R2>
using ratio_subtract = ratio<R1::num * R2::denom - R2::num * R1::denom, R1::denom * R2::denom>;
template <class R1, class R2>
using ratio_multiply = ratio<R1::num * R2::num, R1::denom * R2::denom>;
template <class R1, class R2>
using ratio_divide = ratio<R1::num * R2::denom, R1::denom * R2::num>;
template <class R1, class R2>
struct ratio_equal;
template <class R1, class R2>
struct ratio_not_equal;
template <class R1, class R2>
struct ratio_less;
template <class R1, class R2>
struct ratio_less_equal;
template <class R1, class R2>
struct ratio_greater;
template <class R1, class R2>
struct ratio_greater_equal;
// typedef ratio<1, 1000000000000000000000000000000> quecto;
// typedef ratio<1, 1000000000000000000000000000> ronto;
// typedef ratio<1, 1000000000000000000000000> yocto;
// typedef ratio<1, 1000000000000000000000> zepto;
typedef ratio<1, 1000000000000000000> atto;
typedef ratio<1, 1000000000000000> femto;
typedef ratio<1, 1000000000000> pico;
typedef ratio<1, 1000000000> nano;
typedef ratio<1, 1000000> micro;
typedef ratio<1, 1000> milli;
typedef ratio<1, 100> centi;
typedef ratio<1, 10> deci;
typedef ratio<10, 1> deca;
typedef ratio<100, 1> hecto;
typedef ratio<1000, 1> kilo;
typedef ratio<1000000, 1> mega;
typedef ratio<1000000000, 1> giga;
typedef ratio<1000000000000, 1> tera;
typedef ratio<1000000000000000, 1> peta;
typedef ratio<1000000000000000000, 1> exa;
// typedef ratio<1000000000000000000000, 1> zetta;
// typedef ratio<1000000000000000000000000, 1> yotta;
// typedef ratio<1000000000000000000000000000, 1> ronna;
// typedef ratio<1000000000000000000000000000000, 1> quetta;
}

View File

@ -19,6 +19,7 @@
#include <convert.h>
#include <cassert>
#include <cstring>
#include <new>
namespace std
@ -116,4 +117,13 @@ namespace std
out_of_range &operator=(out_of_range &&) = default;
virtual ~out_of_range() = default;
};
class invalid_argument : public logic_error
{
public:
// invalid_argument(const std::string &what_arg) = default;
invalid_argument(const char *what_arg) : logic_error(what_arg) {}
invalid_argument(const invalid_argument &other) = default;
invalid_argument &operator=(const invalid_argument &other) = default;
};
}

View File

@ -37,12 +37,13 @@ extern FILE *stderr;
#define stdout stdout
#define stderr stderr
int printf(const char *format, ...) __attribute__((format(__printf__, (1), (2))));
int vprintf(const char *format, va_list arg) __attribute__((format(__printf__, ((1)), (0))));
int sprintf(char *s, const char *format, ...) __attribute__((format(__printf__, (2), (3))));
int vsprintf(char *s, const char *format, va_list arg) __attribute__((format(__printf__, ((2)), (0))));
int snprintf(char *s, size_t count, const char *format, ...) __attribute__((format(__printf__, (3), (4))));
int vsnprintf(char *s, size_t count, const char *format, va_list arg) __attribute__((format(__printf__, ((3)), (0))));
#include <printf.h>
// int printf(const char *format, ...) __attribute__((format(__printf__, (1), (2))));
// int vprintf(const char *format, va_list arg) __attribute__((format(__printf__, ((1)), (0))));
// int sprintf(char *s, const char *format, ...) __attribute__((format(__printf__, (2), (3))));
// int vsprintf(char *s, const char *format, va_list arg) __attribute__((format(__printf__, ((2)), (0))));
// int snprintf(char *s, size_t count, const char *format, ...) __attribute__((format(__printf__, (3), (4))));
// int vsnprintf(char *s, size_t count, const char *format, va_list arg) __attribute__((format(__printf__, ((3)), (0))));
int asprintf(char **strp, const char *fmt, ...) __attribute__((format(__printf__, (2), (3))));
int vasprintf(char **strp, const char *fmt, va_list ap) __attribute__((format(__printf__, ((2)), (0))));

View File

@ -17,8 +17,92 @@
#pragma once
#include <interface/errno.h>
namespace std
{
enum class errc
{
address_family_not_supported = EAFNOSUPPORT,
address_in_use = EADDRINUSE,
address_not_available = EADDRNOTAVAIL,
already_connected = EISCONN,
argument_list_too_long = E2BIG,
argument_out_of_domain = EDOM,
bad_address = EFAULT,
bad_file_descriptor = EBADF,
bad_message = EBADMSG,
broken_pipe = EPIPE,
connection_aborted = ECONNABORTED,
connection_already_in_progress = EALREADY,
connection_refused = ECONNREFUSED,
connection_reset = ECONNRESET,
cross_device_link = EXDEV,
destination_address_required = EDESTADDRREQ,
device_or_resource_busy = EBUSY,
directory_not_empty = ENOTEMPTY,
executable_format_error = ENOEXEC,
file_exists = EEXIST,
file_too_large = EFBIG,
filename_too_long = ENAMETOOLONG,
function_not_supported = ENOSYS,
host_unreachable = EHOSTUNREACH,
identifier_removed = EIDRM,
illegal_byte_sequence = EILSEQ,
inappropriate_io_control_operation = ENOTTY,
interrupted = EINTR,
invalid_argument = EINVAL,
invalid_seek = ESPIPE,
io_error = EIO,
is_a_directory = EISDIR,
message_size = EMSGSIZE,
network_down = ENETDOWN,
network_reset = ENETRESET,
network_unreachable = ENETUNREACH,
no_buffer_space = ENOBUFS,
no_child_process = ECHILD,
no_link = ENOLINK,
no_lock_available = ENOLCK,
no_message_available = ENODATA,
no_message = ENOMSG,
no_protocol_option = ENOPROTOOPT,
no_space_on_device = ENOSPC,
no_stream_resources = ENOSR,
no_such_device_or_address = ENXIO,
no_such_device = ENODEV,
no_such_file_or_directory = ENOENT,
no_such_process = ESRCH,
not_a_directory = ENOTDIR,
not_a_socket = ENOTSOCK,
not_a_stream = ENOSTR,
not_connected = ENOTCONN,
not_enough_memory = ENOMEM,
not_supported = ENOTSUP,
operation_canceled = ECANCELED,
operation_in_progress = EINPROGRESS,
operation_not_permitted = EPERM,
operation_not_supported = EOPNOTSUPP,
operation_would_block = EWOULDBLOCK,
owner_dead = EOWNERDEAD,
permission_denied = EACCES,
protocol_error = EPROTO,
protocol_not_supported = EPROTONOSUPPORT,
read_only_file_system = EROFS,
resource_deadlock_would_occur = EDEADLK,
resource_unavailable_try_again = EAGAIN,
result_out_of_range = ERANGE,
state_not_recoverable = ENOTRECOVERABLE,
stream_timeout = ETIME,
text_file_busy = ETXTBSY,
timed_out = ETIMEDOUT,
too_many_files_open_in_system = ENFILE,
too_many_files_open = EMFILE,
too_many_links = EMLINK,
too_many_symbolic_link_levels = ELOOP,
value_too_large = EOVERFLOW,
wrong_protocol_type = EPROTOTYPE
};
class error_category
{
/* https://en.cppreference.com/w/cpp/error/error_category */
@ -55,4 +139,14 @@ namespace std
/* https://en.cppreference.com/w/cpp/error/error_code */
};
class error_condition;
template <class T>
struct is_error_code_enum : std::integral_constant<bool, false>
{
};
template <class T>
constexpr bool is_error_code_enum_v = is_error_code_enum<T>::value;
}

View File

@ -21,6 +21,7 @@
#include <task.hpp>
#include <debug.h>
#include <smp.hpp>
#include <chrono>
extern Tasking::Task *TaskManager;
@ -32,6 +33,8 @@ namespace std
Tasking::TCB *Task = nullptr;
public:
using id = Tasking::TCB *;
thread() = default;
thread(const thread &) = delete;
thread(thread &&) = delete;
@ -78,4 +81,20 @@ namespace std
return Task;
}
};
namespace this_thread
{
thread::id get_id() noexcept;
void yield() noexcept;
template <class Clock, class Duration>
void sleep_until(const chrono::time_point<Clock, Duration> &abs_time);
template <class Rep, class Period>
void sleep_for(const chrono::duration<Rep, Period> &rel_time)
{
TaskManager->Sleep(chrono::duration_cast<std::chrono::milliseconds>(rel_time).count());
}
}
}

View File

@ -290,7 +290,7 @@ namespace std
reinterpret_cast<T>(t);
f(0);
p + t;
} > {};
}>{};
template <class T>
constexpr bool is_integral_v = is_integral<T>::value;
@ -659,4 +659,38 @@ namespace std
template <class... T>
using common_type_t = typename common_type<T...>::type;
namespace detail
{
template <class T>
constexpr T &&__result_of_forward(std::remove_reference_t<T> &t) noexcept
{
return static_cast<T &&>(t);
}
template <class F, class... ArgTypes>
auto INVOKE(F &&f, ArgTypes &&...args)
-> decltype(__result_of_forward<F>(f)(__result_of_forward<ArgTypes>(args)...))
{
return __result_of_forward<F>(f)(__result_of_forward<ArgTypes>(args)...);
}
}
template <class>
class result_of;
template <class F, class... ArgTypes>
struct result_of<F(ArgTypes...)>
{
using type = decltype(detail::INVOKE(std::declval<F>(), std::declval<ArgTypes>()...));
};
template <class F, class... ArgTypes>
struct invoke_result;
template <class T>
using result_of_t = typename result_of<T>::type;
template <class F, class... ArgTypes>
using invoke_result_t = typename invoke_result<F, ArgTypes...>::type;
}

View File

@ -477,7 +477,7 @@ namespace std
void clear() noexcept
{
foreach (auto &bucket in buckets)
for (auto &bucket : buckets)
bucket.clear();
elementsCount = 0;
}
@ -589,7 +589,7 @@ namespace std
void insert(std::initializer_list<value_type> ilist)
{
foreach (const auto &value in ilist)
for (const auto &value : ilist)
insert(value);
}

View File

@ -43,7 +43,7 @@ struct KernelConfig Config = {
.SchedulerType = Multi,
.DriverDirectory = {'/', 's', 'y', 's', '/', 'd', 'r', 'v', '\0'},
.InitPath = {'/', 's', 'y', 's', '/', 'b', 'i', 'n', '/', 'i', 'n', 'i', 't', '\0'},
.UseLinuxSyscalls = false,
.LinuxSubsystem = false,
.InterruptsOnCrash = true,
.Cores = 0,
.IOAPICInterruptCore = 0,

View File

@ -65,7 +65,7 @@ static struct cag_option ConfigOptions[] = {
.access_letters = "yY",
.access_name = "linux",
.value_name = "BOOL",
.description = "Use Linux syscalls by default"},
.description = "Use Linux Subsystem"},
{.identifier = 'l',
.access_letters = NULL,
@ -99,21 +99,11 @@ static struct cag_option ConfigOptions[] = {
void ParseConfig(char *ConfigString, KernelConfig *ModConfig)
{
if (ConfigString == NULL ||
strlen(ConfigString) == 0)
{
KPrint("Empty kernel parameters!");
assert(ConfigString != NULL && ModConfig != NULL);
if (strlen(ConfigString) == 0)
return;
}
if (ModConfig == NULL)
{
KPrint("ModConfig is NULL!");
return;
}
KPrint("Kernel parameters: %s", ConfigString);
debug("Kernel parameters: %s", ConfigString);
char *argv[32];
int argc = 0;
@ -126,16 +116,14 @@ void ParseConfig(char *ConfigString, KernelConfig *ModConfig)
debug("argc = %d", argc);
#endif
char identifier;
const char *value;
cag_option_context context;
cag_option_init(&context, ConfigOptions, CAG_ARRAY_SIZE(ConfigOptions), argc, argv);
context.index = 0; /* We don't have the standard argv[0] == <program name> */
cag_option_prepare(&context, ConfigOptions,
CAG_ARRAY_SIZE(ConfigOptions), argc, argv);
const char *value;
while (cag_option_fetch(&context))
{
identifier = cag_option_get(&context);
char identifier = cag_option_get_identifier(&context);
switch (identifier)
{
case 'a':
@ -216,9 +204,9 @@ void ParseConfig(char *ConfigString, KernelConfig *ModConfig)
{
value = cag_option_get_value(&context);
strcmp(value, "true") == 0
? ModConfig->UseLinuxSyscalls = true
: ModConfig->UseLinuxSyscalls = false;
KPrint("Use Linux syscalls by default: %s", value);
? ModConfig->LinuxSubsystem = true
: ModConfig->LinuxSubsystem = false;
KPrint("Use Linux Subsystem by default: %s", value);
break;
}
case 'o':
@ -257,18 +245,17 @@ void ParseConfig(char *ConfigString, KernelConfig *ModConfig)
}
case 'h':
{
KPrint("\n---------------------------------------------------------------------------\nUsage: fennix.elf [OPTION]...\nKernel configuration.");
cag_option_print(ConfigOptions, CAG_ARRAY_SIZE(ConfigOptions),
nullptr);
KPrint("Usage: fennix.elf [OPTION]...");
KPrint("Fennix Kernel v%s", KERNEL_VERSION);
cag_option_print(ConfigOptions, CAG_ARRAY_SIZE(ConfigOptions), nullptr);
KPrint("\x1b[1;31;41mSystem Halted.");
CPU::Stop();
}
case '?':
default:
{
KPrint("\x1b[31mUnknown option: %c", identifier);
cag_option_print_error(&context, stdout);
break;
}
}
}
debug("Config loaded");
}

View File

@ -33,21 +33,21 @@
cold int SpawnInit()
{
const char *envp[6] = {
const char *envp[] = {
"PATH=/bin:/usr/bin",
"LD_LIBRARY_PATH=/sys/lib:/usr/lib",
"TERM=tty",
"HOME=/root",
"USER=root",
"TZ=UTC",
nullptr};
const char *argv[4] = {
const char *argv[] = {
Config.InitPath,
"--kernel",
nullptr};
Tasking::TaskCompatibility compat = Tasking::Native;
if (Config.UseLinuxSyscalls)
if (Config.LinuxSubsystem)
compat = Tasking::Linux;
return Execute::Spawn(Config.InitPath, argv, envp,

View File

@ -27,7 +27,7 @@ using namespace Tasking;
void cmd_killall(const char *args)
{
foreach (auto Proc in TaskManager->GetProcessList())
for (auto Proc : TaskManager->GetProcessList())
{
if (strcmp(Proc->Name, args) == 0)
{

View File

@ -27,7 +27,7 @@ using namespace vfs;
void cmd_lsacpi(const char *)
{
ACPI::ACPI *acpi = (ACPI::ACPI *)PowerManager->GetACPI();
foreach (auto Table in acpi->Tables)
for (auto Table : acpi->Tables)
{
printf("%#lx: %.4s [%.6s:%.8s] %d bytes\n",
(uintptr_t)Table.second,

View File

@ -26,7 +26,7 @@ void cmd_lsmod(const char *)
printf("DRIVER | ID | INIT | MEMORY\n");
foreach (auto &drv in drivers)
for (auto &drv : drivers)
{
printf("%-15s | %5ld | %s | %ld KiB\n",
drv.second.Name,

View File

@ -29,7 +29,7 @@ void cmd_lspci(const char *args)
{
if (IF_ARG("-i") || IF_ARG("--info"))
{
foreach (auto Device in PCIManager->GetDevices())
for (auto Device : PCIManager->GetDevices())
{
const char *HdrType;
switch (Device.Header->HeaderType)
@ -65,7 +65,7 @@ void cmd_lspci(const char *args)
}
}
foreach (auto Device in PCIManager->GetDevices())
for (auto Device : PCIManager->GetDevices())
{
printf("%02x:%02x.%d: %s: %s %s\n",
Device.Bus,

View File

@ -35,7 +35,7 @@ void cmd_modinfo(const char *args)
if (drivers.find(id) == drivers.end())
{
bool found = false;
foreach (auto var in drivers)
for (auto var : drivers)
{
if (strcmp(var.second.Name, args) == 0)
{
@ -70,7 +70,7 @@ void cmd_modinfo(const char *args)
printf(" Path: %s\n", drv.Path.c_str());
printf(" Used Memory: %ld KiB\n", TO_KiB(drv.vma->GetAllocatedMemorySize()));
printf(" Used IRQs:%s\n", drv.InterruptHandlers->empty() ? " none" : "");
foreach (auto var in *drv.InterruptHandlers)
for (auto var : *drv.InterruptHandlers)
{
printf(" IRQ%-2d: %#lx\n",
var.first, (uintptr_t)var.second);

View File

@ -28,6 +28,6 @@ using namespace Tasking;
void cmd_ps(const char *)
{
printf("PID Name\n");
foreach (auto p in TaskManager->GetProcessList())
for (auto p : TaskManager->GetProcessList())
printf("%d %s\n", p->ID, p->Name);
}

View File

@ -43,7 +43,7 @@ const char *TaskStateStrings[] = {
void cmd_top(const char *)
{
printf("PID Name State Priority Memory Usage CPU Usage\n");
foreach (auto Proc in TaskManager->GetProcessList())
for (auto Proc : TaskManager->GetProcessList())
{
#if defined(__amd64__)
printf("%-4d %-20s %s %d %ld KiB %ld\n",
@ -57,7 +57,7 @@ void cmd_top(const char *)
Proc->Info.UserTime + Proc->Info.KernelTime);
#endif
foreach (auto Thrd in Proc->Threads)
for (auto Thrd : Proc->Threads)
{
#if defined(__amd64__)
printf(" %-4d %-20s %s %d %ld KiB %ld\n",

View File

@ -23,7 +23,7 @@
void tree_loop(FileNode *rootNode, int depth = 0)
{
// foreach (auto Child in rootNode->GetChildren(true))
// for (auto Child : rootNode->GetChildren(true))
// {
// Display->UpdateBuffer();
// if (Child->Stat.IsType(DIRECTORY) || Child->Stat.IsType(MOUNTPOINT))

View File

@ -600,7 +600,7 @@ void KShellThread()
}
Tasking::TaskCompatibility compat = Tasking::Native;
if (Config.UseLinuxSyscalls)
if (Config.LinuxSubsystem)
compat = Tasking::Linux;
int ret = Execute::Spawn((char *)path.c_str(), argv, envp,

View File

@ -27,486 +27,587 @@ SOFTWARE.
#include <assert.h>
#include <cargs.h>
#include <convert.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#define CAG_OPTION_PRINT_DISTANCE 4
#define CAG_OPTION_PRINT_MIN_INDENTION 20
static void cag_option_print_value(const cag_option *option,
size_t *accessor_length, FILE *destination)
size_t *accessor_length, cag_printer printer, void *printer_ctx)
{
if (option->value_name != NULL)
{
*accessor_length += fprintf(destination, "=%s", option->value_name);
}
if (option->value_name != NULL)
{
*accessor_length += printer(printer_ctx, "=%s", option->value_name);
}
}
static void cag_option_print_letters(const cag_option *option, bool *first,
size_t *accessor_length, FILE *destination)
size_t *accessor_length, cag_printer printer, void *printer_ctx)
{
const char *access_letter;
access_letter = option->access_letters;
if (access_letter != NULL)
{
while (*access_letter)
{
if (*first)
{
*accessor_length += fprintf(destination, "-%c", *access_letter);
*first = false;
}
else
{
*accessor_length += fprintf(destination, ", -%c", *access_letter);
}
++access_letter;
}
}
const char *access_letter;
access_letter = option->access_letters;
if (access_letter != NULL)
{
while (*access_letter)
{
if (*first)
{
*accessor_length += printer(printer_ctx, "-%c", *access_letter);
*first = false;
}
else
{
*accessor_length += printer(printer_ctx, ", -%c", *access_letter);
}
++access_letter;
}
}
}
static void cag_option_print_name(const cag_option *option, bool *first,
size_t *accessor_length, FILE *destination)
size_t *accessor_length, cag_printer printer, void *printer_ctx)
{
if (option->access_name != NULL)
{
if (*first)
{
*accessor_length += fprintf(destination, "--%s", option->access_name);
}
else
{
*accessor_length += fprintf(destination, ", --%s", option->access_name);
}
}
if (option->access_name != NULL)
{
if (*first)
{
*accessor_length += printer(printer_ctx, "--%s", option->access_name);
*first = false;
}
else
{
*accessor_length += printer(printer_ctx, ", --%s", option->access_name);
}
}
}
static size_t cag_option_get_print_indention(const cag_option *options,
size_t option_count)
size_t option_count)
{
size_t option_index, indention, result;
const cag_option *option;
size_t option_index, indention, result;
const cag_option *option;
result = CAG_OPTION_PRINT_MIN_INDENTION;
result = CAG_OPTION_PRINT_MIN_INDENTION;
for (option_index = 0; option_index < option_count; ++option_index)
{
indention = CAG_OPTION_PRINT_DISTANCE;
option = &options[option_index];
if (option->access_letters != NULL && *option->access_letters)
{
indention += strlen(option->access_letters) * 4 - 2;
if (option->access_name != NULL)
{
indention += strlen(option->access_name) + 4;
}
}
else if (option->access_name != NULL)
{
indention += strlen(option->access_name) + 2;
}
for (option_index = 0; option_index < option_count; ++option_index)
{
indention = CAG_OPTION_PRINT_DISTANCE;
option = &options[option_index];
if (option->access_letters != NULL && *option->access_letters)
{
indention += strlen(option->access_letters) * 4 - 2;
if (option->access_name != NULL)
{
indention += strlen(option->access_name) + 4;
}
}
else if (option->access_name != NULL)
{
indention += strlen(option->access_name) + 2;
}
if (option->value_name != NULL)
{
indention += strlen(option->value_name) + 1;
}
if (option->value_name != NULL)
{
indention += strlen(option->value_name) + 1;
}
if (indention > result)
{
result = indention;
}
}
if (indention > result)
{
result = indention;
}
}
return result;
return result;
}
void cag_option_print(const cag_option *options, size_t option_count,
FILE *destination)
void cag_option_init(cag_option_context *context, const cag_option *options,
size_t option_count, int argc, char **argv)
{
size_t option_index, indention, i, accessor_length;
const cag_option *option;
bool first;
indention = cag_option_get_print_indention(options, option_count);
for (option_index = 0; option_index < option_count; ++option_index)
{
option = &options[option_index];
accessor_length = 0;
first = true;
fputs(" ", destination);
cag_option_print_letters(option, &first, &accessor_length, destination);
cag_option_print_name(option, &first, &accessor_length, destination);
cag_option_print_value(option, &accessor_length, destination);
for (i = accessor_length; i < indention; ++i)
{
fputs(" ", destination);
}
fputs(" ", destination);
fputs(option->description, destination);
fprintf(destination, "\n");
}
}
void cag_option_prepare(cag_option_context *context, const cag_option *options,
size_t option_count, int argc, char **argv)
{
// This just initialized the values to the beginning of all the arguments.
context->options = options;
context->option_count = option_count;
context->argc = argc;
context->argv = argv;
context->index = 1;
context->inner_index = 0;
context->forced_end = false;
// This just initialized the values to the beginning of all the arguments.
context->options = options;
context->option_count = option_count;
context->argc = argc;
context->argv = argv;
context->index = 1;
context->inner_index = 0;
context->forced_end = false;
context->error_index = -1;
context->error_letter = 0;
}
static const cag_option *cag_option_find_by_name(cag_option_context *context,
char *name, size_t name_size)
char *name, size_t name_size)
{
const cag_option *option;
size_t i;
const cag_option *option;
size_t i;
// We loop over all the available options and stop as soon as we have found
// one. We don't use any hash map table, since there won't be that many
// arguments anyway.
for (i = 0; i < context->option_count; ++i)
{
option = &context->options[i];
// We loop over all the available options and stop as soon as we have found
// one. We don't use any hash map table, since there won't be that many
// arguments anyway.
for (i = 0; i < context->option_count; ++i)
{
option = &context->options[i];
// The option might not have an item name, we can just skip those.
if (option->access_name == NULL)
{
continue;
}
// The option might not have an item name, we can just skip those.
if (option->access_name == NULL)
{
continue;
}
// Try to compare the name of the access name. We can use the name_size or
// this comparison, since we are guaranteed to have null-terminated access
// names.
if (strncmp(option->access_name, name, name_size) == 0)
{
return option;
}
}
// Try to compare the name of the access name. We can use the name_size or
// this comparison, since we are guaranteed to have null-terminated access
// names.
if (strncmp(option->access_name, name, name_size) == 0 && option->access_name[name_size] == '\0')
{
return option;
}
}
return NULL;
return NULL;
}
static const cag_option *cag_option_find_by_letter(cag_option_context *context,
char letter)
char letter)
{
const cag_option *option;
size_t i;
const cag_option *option;
size_t i;
// We loop over all the available options and stop as soon as we have found
// one. We don't use any look up table, since there won't be that many
// arguments anyway.
for (i = 0; i < context->option_count; ++i)
{
option = &context->options[i];
// We loop over all the available options and stop as soon as we have found
// one. We don't use any look up table, since there won't be that many
// arguments anyway.
for (i = 0; i < context->option_count; ++i)
{
option = &context->options[i];
// If this option doesn't have any access letters we will skip them.
if (option->access_letters == NULL)
{
continue;
}
// If this option doesn't have any access letters we will skip them.
if (option->access_letters == NULL)
{
continue;
}
// Verify whether this option has the access letter in it's access letter
// string. If it does, then this is our option.
if (strchr(option->access_letters, letter) != NULL)
{
return option;
}
}
// Verify whether this option has the access letter in it's access letter
// string. If it does, then this is our option.
if (strchr(option->access_letters, letter) != NULL)
{
return option;
}
}
return NULL;
return NULL;
}
static void cag_option_parse_value(cag_option_context *context,
const cag_option *option, char **c)
const cag_option *option, char **c)
{
// And now let's check whether this option is supposed to have a value, which
// is the case if there is a value name set. The value can be either submitted
// with a '=' sign or a space, which means we would have to jump over to the
// next argv index. This is somewhat ugly, but we do it to behave the same as
// the other option parsers.
if (option->value_name != NULL)
{
if (**c == '=')
{
context->value = ++(*c);
}
else
{
// If the next index is larger or equal to the argument count, then the
// parameter for this option is missing. The user will know about this,
// since the value pointer of the context will be NULL because we don't
// set it here in that case.
if (context->argc > context->index + 1)
{
// We consider this argv to be the value, no matter what the contents
// are.
++context->index;
*c = context->argv[context->index];
context->value = *c;
}
}
// And now let's check whether this option is supposed to have a value, which
// is the case if there is a value name set. The value can be either submitted
// with a '=' sign or a space, which means we would have to jump over to the
// next argv index. This is somewhat ugly, but we do it to behave the same as
// the other option parsers.
if (option->value_name != NULL)
{
if (**c == '=')
{
context->value = ++(*c);
}
else
{
// If the next index is larger or equal to the argument count, then the
// parameter for this option is missing. The user will know about this,
// since the value pointer of the context will be NULL because we don't
// set it here in that case.
if (context->argc > context->index + 1)
{
// We consider this argv to be the value, no matter what the contents
// are.
++context->index;
*c = context->argv[context->index];
context->value = *c;
}
}
// Move c to the end of the value, to not confuse the caller about our
// position.
while (**c)
{
++(*c);
}
}
// Move c to the end of the value, to not confuse the caller about our
// position.
while (**c)
{
++(*c);
}
}
}
static void cag_option_parse_access_name(cag_option_context *context, char **c)
{
const cag_option *option;
char *n;
const cag_option *option;
char *n;
// Now we need to extract the access name, which is any symbol up to a '=' or
// a '\0'.
n = *c;
while (**c && **c != '=')
{
++*c;
}
// Now we need to extract the access name, which is any symbol up to a '=' or
// a '\0'.
n = *c;
while (**c && **c != '=')
{
++*c;
}
// Now this will obviously always be true, but we are paranoid. Sometimes. It
// doesn't hurt to check.
assert(*c >= n);
// Now this will obviously always be true, but we are paranoid. Sometimes. It
// doesn't hurt to check.
assert(*c >= n);
// Figure out which option this name belongs to. This might return NULL if the
// name is not registered, which means the user supplied an unknown option. In
// that case we return true to indicate that we finished with this option. We
// have to skip the value parsing since we don't know whether the user thinks
// this option has one or not. Since we don't set any identifier specifically,
// it will remain '?' within the context.
option = cag_option_find_by_name(context, n, (size_t)(*c - n));
if (option == NULL)
{
// Since this option is invalid, we will move on to the next index. There is
// nothing we can do about this.
++context->index;
return;
}
// Figure out which option this name belongs to. This might return NULL if the
// name is not registered, which means the user supplied an unknown option. In
// that case we return true to indicate that we finished with this option. We
// have to skip the value parsing since we don't know whether the user thinks
// this option has one or not. Since we don't set any identifier specifically,
// it will remain '?' within the context.
option = cag_option_find_by_name(context, n, (size_t)(*c - n));
if (option != NULL)
{
// We found an option and now we can specify the identifier within the
// context.
context->identifier = option->identifier;
// We found an option and now we can specify the identifier within the
// context.
context->identifier = option->identifier;
// And now we try to parse the value. This function will also check whether
// this option is actually supposed to have a value.
cag_option_parse_value(context, option, c);
}
else
{
// Remember the error index so that we can print a error message.
context->error_index = context->index;
}
// And now we try to parse the value. This function will also check whether
// this option is actually supposed to have a value.
cag_option_parse_value(context, option, c);
// And finally we move on to the next index.
++context->index;
// And finally we move on to the next index.
++context->index;
}
static void cag_option_parse_access_letter(cag_option_context *context,
char **c)
char **c)
{
const cag_option *option;
char *n = *c;
char *v;
const cag_option *option;
char *n, *v, letter;
// Figure out which option this letter belongs to. This might return NULL if
// the letter is not registered, which means the user supplied an unknown
// option. In that case we return true to indicate that we finished with this
// option. We have to skip the value parsing since we don't know whether the
// user thinks this option has one or not. Since we don't set any identifier
// specifically, it will remain '?' within the context.
option = cag_option_find_by_letter(context, n[context->inner_index]);
if (option == NULL)
{
++context->index;
context->inner_index = 0;
return;
}
n = *c;
// We found an option and now we can specify the identifier within the
// context.
context->identifier = option->identifier;
// Figure out which option this letter belongs to. This might return NULL if
// the letter is not registered, which means the user supplied an unknown
// option. In that case we return true to indicate that we finished with this
// option. We have to skip the value parsing since we don't know whether the
// user thinks this option has one or not. Since we don't set any identifier
// specifically, it will remain '?' within the context.
letter = n[context->inner_index];
option = cag_option_find_by_letter(context, letter);
v = &n[++context->inner_index];
if (option == NULL)
{
context->error_index = context->index;
context->error_letter = letter;
}
else
{
// We found an option and now we can specify the identifier within the
// context.
context->identifier = option->identifier;
// And now we try to parse the value. This function will also check whether
// this option is actually supposed to have a value.
v = &n[++context->inner_index];
cag_option_parse_value(context, option, &v);
// And now we try to parse the value. This function will also check whether
// this option is actually supposed to have a value.
cag_option_parse_value(context, option, &v);
}
// Check whether we reached the end of this option argument.
if (*v == '\0')
{
++context->index;
context->inner_index = 0;
}
// Check whether we reached the end of this option argument.
if (*v == '\0')
{
++context->index;
context->inner_index = 0;
}
}
static void cag_option_shift(cag_option_context *context, int start, int option,
int end)
int end)
{
char *tmp;
int a_index, shift_index, shift_count, left_index, right_index;
char *tmp;
int a_index, shift_index, left_shift, right_shift, target_index, source_index;
shift_count = option - start;
// The block between start and option will be shifted to the end, and the
// order of everything will be preserved. Left shift is the amount of indexes
// the block between option and end will shift towards the start, and right
// shift is the amount of indexes the block between start and option will be
// shifted towards the end.
left_shift = option - start;
right_shift = end - option;
// There is no shift is required if the start and the option have the same
// index.
if (shift_count == 0)
{
return;
}
// There is no shift is required if the start and the option have the same
// index.
if (left_shift == 0)
{
return;
}
// Lets loop through the option strings first, which we will move towards the
// beginning.
for (a_index = option; a_index < end; ++a_index)
{
// First remember the current option value, because we will have to save
// that later at the beginning.
tmp = context->argv[a_index];
// Let's loop through the option strings first, which we will move towards the
// beginning.
for (a_index = option; a_index < end; ++a_index)
{
// First remember the current option value, because we will have to save
// that later at the beginning.
tmp = context->argv[a_index];
// Let's loop over all option values and shift them one towards the end.
// This will override the option value we just stored temporarily.
for (shift_index = 0; shift_index < shift_count; ++shift_index)
{
left_index = a_index - shift_index;
right_index = a_index - shift_index - 1;
context->argv[left_index] = context->argv[right_index];
}
// Let's loop over all option values and shift them one towards the end.
// This will override the option value we just stored temporarily.
for (shift_index = 0; shift_index < left_shift; ++shift_index)
{
target_index = a_index - shift_index;
source_index = a_index - shift_index - 1;
context->argv[target_index] = context->argv[source_index];
}
// Now restore the saved option value at the beginning.
context->argv[a_index - shift_count] = tmp;
}
// Now restore the saved option value at the beginning.
context->argv[a_index - left_shift] = tmp;
}
// The new index will be before all non-option values, in such a way that they
// all will be moved again in the next fetch call.
context->index = end - shift_count;
// The new index will be before all non-option values, in such a way that they
// all will be moved again in the next fetch call.
context->index = end - left_shift;
// The error index may have changed, we need to fix that as well.
if (context->error_index >= start)
{
if (context->error_index < option)
{
context->error_index += right_shift;
}
else if (context->error_index < end)
{
context->error_index -= left_shift;
}
}
}
static bool cag_option_is_argument_string(const char *c)
{
return *c == '-' && *(c + 1) != '\0';
return *c == '-' && *(c + 1) != '\0';
}
static int cag_option_find_next(cag_option_context *context)
{
int next_index, next_option_index;
char *c;
// Prepare to search the next option at the next index.
int next_index;
char *c;
// Prepare to search the next option at the next index.
next_index = context->index;
next_option_index = next_index;
next_index = context->index;
// Grab a pointer to the string and verify that it is not the end. If it is
// the end, we have to return false to indicate that we finished.
c = context->argv[next_option_index];
if (context->forced_end || c == NULL || (uintptr_t)c == (uintptr_t)0xfffffffffffff000 /* TODO: workaround */)
{
return -1;
}
// Let's verify that it is not the end If it is
// the end we have to return -1 to indicate that we finished.
if (next_index >= context->argc)
{
return -1;
}
// Check whether it is a '-'. We need to find the next option - and an option
// always starts with a '-'. If there is a string "-\0", we don't consider it
// as an option neither.
while (!cag_option_is_argument_string(c))
{
c = context->argv[++next_option_index];
if (c == NULL)
{
// We reached the end and did not find any argument anymore. Let's tell
// our caller that we reached the end.
return -1;
}
}
// Grab a pointer to the argument string.
c = context->argv[next_index];
if (context->forced_end || c == NULL)
{
return -1;
}
// Indicate that we found an option which can be processed. The index of the
// next option will be returned.
return next_option_index;
// Check whether it is a '-'. We need to find the next option - and an option
// always starts with a '-'. If there is a string "-\0", we don't consider it
// as an option neither.
while (!cag_option_is_argument_string(c))
{
if (++next_index >= context->argc)
{
// We reached the end and did not find any argument anymore. Let's tell
// our caller that we reached the end.
return -1;
}
c = context->argv[next_index];
if (c == NULL)
{
return -1;
}
}
// Indicate that we found an option which can be processed. The index of the
// next option will be returned.
return next_index;
}
bool cag_option_fetch(cag_option_context *context)
{
char *c;
int old_index, new_index;
char *c;
int old_index, new_index;
// Reset our identifier to a question mark, which indicates an "unknown"
// option. The value is set to NULL, to make sure we are not carrying the
// parameter from the previous option to this one.
context->identifier = '?';
context->value = NULL;
// Reset our identifier to a question mark, which indicates an "unknown"
// option. The value is set to NULL, to make sure we are not carrying the
// parameter from the previous option to this one.
context->identifier = '?';
context->value = NULL;
context->error_index = -1;
context->error_letter = 0;
// Check whether there are any options left to parse and remember the old
// index as well as the new index. In the end we will move the option junk to
// the beginning, so that non option arguments can be read.
old_index = context->index;
new_index = cag_option_find_next(context);
if (new_index >= 0)
{
context->index = new_index;
}
else
{
return false;
}
// Check whether there are any options left to parse and remember the old
// index as well as the new index. In the end we will move the option junk to
// the beginning, so that non option arguments can be read.
old_index = context->index;
new_index = cag_option_find_next(context);
if (new_index >= 0)
{
context->index = new_index;
}
else
{
return false;
}
// Grab a pointer to the beginning of the option. At this point, the next
// character must be a '-', since if it was not the prepare function would
// have returned false. We will skip that symbol and proceed.
c = context->argv[context->index];
assert(*c == '-');
++c;
// Grab a pointer to the beginning of the option. At this point, the next
// character must be a '-', since if it was not the prepare function would
// have returned false. We will skip that symbol and proceed.
c = context->argv[context->index];
assert(*c == '-');
++c;
// Check whether this is a long option, starting with a double "--".
if (*c == '-')
{
++c;
// Check whether this is a long option, starting with a double "--".
if (*c == '-')
{
++c;
// This might be a double "--" which indicates the end of options. If this
// is the case, we will not move to the next index. That ensures that
// another call to the fetch function will not skip the "--".
if (*c == '\0')
{
context->forced_end = true;
}
else
{
// We parse now the access name. All information about it will be written
// to the context.
cag_option_parse_access_name(context, &c);
}
}
else
{
// This is no long option, so we can just parse an access letter.
cag_option_parse_access_letter(context, &c);
}
// This might be a double "--" which indicates the end of options. If this
// is the case, we will not move to the next index. That ensures that
// another call to the fetch function will not skip the "--".
if (*c == '\0')
{
context->forced_end = true;
}
else
{
// We parse now the access name. All information about it will be written
// to the context.
cag_option_parse_access_name(context, &c);
}
}
else
{
// This is no long option, so we can just parse an access letter.
cag_option_parse_access_letter(context, &c);
}
// Move the items so that the options come first followed by non-option
// arguments.
cag_option_shift(context, old_index, new_index, context->index);
// Move the items so that the options come first followed by non-option
// arguments.
cag_option_shift(context, old_index, new_index, context->index);
return context->forced_end == false;
return context->forced_end == false;
}
char cag_option_get(const cag_option_context *context)
char cag_option_get_identifier(const cag_option_context *context)
{
// We just return the identifier here.
return context->identifier;
// We just return the identifier here.
return context->identifier;
}
const char *cag_option_get_value(const cag_option_context *context)
{
// We just return the internal value pointer of the context.
return context->value;
// We just return the internal value pointer of the context.
return context->value;
}
int cag_option_get_index(const cag_option_context *context)
{
// Either we point to a value item,
return context->index;
}
// Either we point to a value item,
return context->index;
}
CAG_PUBLIC int cag_option_get_error_index(const cag_option_context *context)
{
// This is set
return context->error_index;
}
CAG_PUBLIC char cag_option_get_error_letter(const cag_option_context *context)
{
// This is set to the unknown option letter if it was parsed.
return context->error_letter;
}
CAG_PUBLIC void cag_option_printer_error(const cag_option_context *context,
cag_printer printer, void *printer_ctx)
{
int error_index;
char error_letter;
error_index = cag_option_get_error_index(context);
if (error_index < 0)
{
return;
}
error_letter = cag_option_get_error_letter(context);
if (error_letter)
{
printer(printer_ctx, "Unknown option '%c' in '%s'.\n", error_letter,
context->argv[error_index]);
}
else
{
printer(printer_ctx, "Unknown option '%s'.\n", context->argv[error_index]);
}
}
CAG_PUBLIC void cag_option_printer(const cag_option *options,
size_t option_count, cag_printer printer, void *printer_ctx)
{
size_t option_index, indention, i, accessor_length;
const cag_option *option;
bool first;
indention = cag_option_get_print_indention(options, option_count);
for (option_index = 0; option_index < option_count; ++option_index)
{
option = &options[option_index];
accessor_length = 0;
first = true;
printer(printer_ctx, " ");
cag_option_print_letters(option, &first, &accessor_length, printer,
printer_ctx);
cag_option_print_name(option, &first, &accessor_length, printer,
printer_ctx);
cag_option_print_value(option, &accessor_length, printer, printer_ctx);
for (i = accessor_length; i < indention; ++i)
{
printer(printer_ctx, " ");
}
printer(printer_ctx, " %s\n", option->description);
}
}
#ifndef CAG_NO_FILE
CAG_PUBLIC void cag_option_print_error(const cag_option_context *context,
FILE *destination)
{
cag_option_printer_error(context, (cag_printer)fprintf, destination);
}
#endif
#ifndef CAG_NO_FILE
void cag_option_print(const cag_option *options, size_t option_count,
FILE *destination)
{
cag_option_printer(options, option_count, (cag_printer)fprintf, destination);
}
#endif
void cag_option_prepare(cag_option_context *context, const cag_option *options,
size_t option_count, int argc, char **argv)
{
cag_option_init(context, options, option_count, argc, argv);
}
char cag_option_get(const cag_option_context *context)
{
return cag_option_get_identifier(context);
}

View File

@ -0,0 +1,27 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <exception>
#include <cpu.hpp>
namespace std
{
[[noreturn]] void terminate() noexcept
{
CPU::Stop();
}
}

View File

@ -0,0 +1,27 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <future>
namespace std
{
const error_category &future_category() noexcept
{
static const error_category cat;
return cat;
}
}

View File

@ -88,22 +88,22 @@ namespace NetworkEthernet
switch (b16(Packet->Header.Type))
{
case TYPE_IPV4:
foreach (auto e in RegisteredEvents)
for (auto e : RegisteredEvents)
if (e.Type == TYPE_IPV4)
Reply = e.Ptr->OnEthernetPacketReceived((uint8_t *)Packet->Data, Length);
break;
case TYPE_ARP:
foreach (auto e in RegisteredEvents)
for (auto e : RegisteredEvents)
if (e.Type == TYPE_ARP)
Reply = e.Ptr->OnEthernetPacketReceived((uint8_t *)Packet->Data, Length);
break;
case TYPE_RARP:
foreach (auto e in RegisteredEvents)
for (auto e : RegisteredEvents)
if (e.Type == TYPE_RARP)
Reply = e.Ptr->OnEthernetPacketReceived((uint8_t *)Packet->Data, Length);
break;
case TYPE_IPV6:
foreach (auto e in RegisteredEvents)
for (auto e : RegisteredEvents)
if (e.Type == TYPE_IPV6)
Reply = e.Ptr->OnEthernetPacketReceived((uint8_t *)Packet->Data, Length);
break;

View File

@ -86,7 +86,7 @@ namespace NetworkIPv4
if (TotalLength > Length)
TotalLength = Length;
foreach (auto Event in RegisteredEvents)
for (auto Event : RegisteredEvents)
if (Packet->Header.Protocol == Event->GetProtocol())
{
InternetProtocol SourceIP;

View File

@ -40,7 +40,7 @@ namespace NetworkInterfaceManager
/* KernelCallback */
// if (DriverManager->GetModules().size() > 0)
// {
// foreach (auto Driver in DriverManager->GetModules())
// for (auto Driver : DriverManager->GetModules())
// if (((FexExtended *)Driver.ExtendedHeaderAddress)->Driver.Type == FexDriverType::FexDriverType_Network)
// this->FetchNetworkCards(Driver.modUniqueID);
// }
@ -81,7 +81,7 @@ namespace NetworkInterfaceManager
Iface->DriverID = modUniqueID;
Interfaces.push_back(Iface);
foreach (auto var in RegisteredEvents)
for (auto var : RegisteredEvents)
var->OnInterfaceAdded(Iface);
debug("Network Card: %s; MAC: %#lx", Iface->Name, Iface->MAC.ToHex());
@ -97,7 +97,7 @@ namespace NetworkInterfaceManager
{
thisThread->SetPriority(Tasking::TaskPriority::Critical);
DeviceInterface *DefaultDevice = nullptr;
foreach (auto inf in Interfaces)
for (auto inf : Interfaces)
{
if (inf)
{
@ -183,7 +183,7 @@ namespace NetworkInterfaceManager
void NetworkInterface::DrvSend(unsigned int DriverID, unsigned char *Data, unsigned short Size)
{
// foreach (auto inf in this->Interfaces)
// for (auto inf : this->Interfaces)
// if (inf->DriverID == DriverID)
// NIManager->Send(inf, Data, Size);
assert(!"Function not implemented");
@ -191,7 +191,7 @@ namespace NetworkInterfaceManager
void NetworkInterface::DrvReceive(unsigned int DriverID, unsigned char *Data, unsigned short Size)
{
// foreach (auto inf in this->Interfaces)
// for (auto inf : this->Interfaces)
// if (inf->DriverID == DriverID)
// NIManager->Receive(inf, Data, Size);
assert(!"Function not implemented");
@ -210,13 +210,13 @@ namespace NetworkInterfaceManager
// DriverManager->IOCB(Interface->DriverID, &cb);
vma->FreePages(DataToBeSent, TO_PAGES(Length + 1));
foreach (auto ev in RegisteredEvents)
for (auto ev : RegisteredEvents)
ev->OnInterfaceSent(Interface, Data, Length);
}
void NetworkInterface::Receive(DeviceInterface *Interface, uint8_t *Data, size_t Length)
{
foreach (auto re in RegisteredEvents)
for (auto re : RegisteredEvents)
re->OnInterfaceReceived(Interface, Data, Length);
}

View File

@ -109,7 +109,7 @@ namespace NetworkUDP
Socket *GoodSocket = nullptr;
foreach (auto &var in RegisteredEvents)
for (auto &var : RegisteredEvents)
{
netdbg("UDP->SKT[]: LP:%d | LIP:%s | RP:%d | RIP:%s | LST:%d",
b16(var.UDPSocket->LocalPort),

View File

@ -161,6 +161,7 @@ namespace vfs
}
Inode *Node = NULL;
bool readSymlinks = true; /* FIXME: implement */
do
{
auto it = DeviceMap.find(__Parent->Node->Device);
@ -170,6 +171,22 @@ namespace vfs
if (it->second.fsi->Ops.Lookup == NULL)
ReturnLogError(nullptr, "Lookup not supported for %d", it->first);
if (readSymlinks && __Parent->IsSymbolicLink())
{
if (it->second.fsi->Ops.ReadLink == NULL)
ReturnLogError(nullptr, "Readlink not supported for %d", it->first);
char buffer[256];
int ret = it->second.fsi->Ops.ReadLink(__Parent->Node, buffer, sizeof(buffer));
if (ret < 0)
ReturnLogError(nullptr, "Readlink for \"%s\"(%d) failed with %d", __Parent->Path.c_str(), it->first, ret);
FileNode *target = this->GetByPath(buffer, __Parent->Parent ? __Parent->Parent : __Parent);
if (target == nullptr)
ReturnLogError(nullptr, "Failed to find target for \"%s\"", __Parent->Path.c_str());
__Parent = target;
}
std::string segmentName(segment.begin, segment.size);
int ret = it->second.fsi->Ops.Lookup(__Parent->Node, segmentName.c_str(), &Node);
if (ret < 0)

View File

@ -389,7 +389,7 @@ namespace vfs
Size = strlen(node->Header->link);
strncpy(Buffer, node->Header->link, Size);
debug("Read %d bytes from %d", Size, Node->Index);
debug("Read %d bytes from %d: \"%s\"", Size, Node->Index, Buffer);
return Size;
}

View File

@ -86,7 +86,7 @@ namespace vfs
struct kdirent *ent = nullptr;
vfsInode *Node = (vfsInode *)_Node;
off_t entries = 0;
foreach (const auto &Root in Node->Children)
for (const auto &Root : Node->Children)
{
if (entries >= Entries)
break;

View File

@ -193,6 +193,18 @@
#define linux_RUSAGE_CHILDREN (-1)
#define linux_RUSAGE_THREAD 1
#define linux_SYSLOG_ACTION_CLOSE 0
#define linux_SYSLOG_ACTION_OPEN 1
#define linux_SYSLOG_ACTION_READ 2
#define linux_SYSLOG_ACTION_READ_ALL 3
#define linux_SYSLOG_ACTION_READ_CLEAR 4
#define linux_SYSLOG_ACTION_CLEAR 5
#define linux_SYSLOG_ACTION_CONSOLE_OFF 6
#define linux_SYSLOG_ACTION_CONSOLE_ON 7
#define linux_SYSLOG_ACTION_CONSOLE_LEVEL 8
#define linux_SYSLOG_ACTION_SIZE_UNREAD 9
#define linux_SYSLOG_ACTION_SIZE_BUFFER 10
typedef long __kernel_long_t;
typedef unsigned long __kernel_ulong_t;
typedef long __kernel_old_time_t;
@ -416,4 +428,23 @@ typedef struct cpu_set_t
#define CPU_SET(i, set) CPU_BIT_OP(i, sizeof(cpu_set_t), set, |=)
#define CPU_ZERO(set) (memset((set), 0, sizeof(cpu_set_t)))
/* taken from https://man7.org/linux/man-pages/man2/sysinfo.2.html */
struct sysinfo
{
long uptime; /* Seconds since boot */
unsigned long loads[3]; /* 1, 5, and 15 minute load averages */
unsigned long totalram; /* Total usable main memory size */
unsigned long freeram; /* Available memory size */
unsigned long sharedram; /* Amount of shared memory */
unsigned long bufferram; /* Memory used by buffers */
unsigned long totalswap; /* Total swap space size */
unsigned long freeswap; /* Swap space still available */
unsigned short procs; /* Number of current processes */
unsigned long totalhigh; /* Total high memory size */
unsigned long freehigh; /* Available high memory size */
unsigned int mem_unit; /* Memory unit size in bytes */
char _f[20 - 2 * sizeof(long) - sizeof(int)]; /* Padding to 64 bytes */
};
#endif // !__FENNIX_KERNEL_LINUX_DEFS_H__

View File

@ -540,7 +540,7 @@ int ConvertSignalToLinux(signal_t sig)
if (sig >= SIGRTMIN && sig <= SIGRTMAX)
return sig; /* We ignore for now */
foreach (auto &mapping in signalMapping)
for (auto &mapping : signalMapping)
{
if (mapping.nativeSignal == sig)
{
@ -560,7 +560,7 @@ signal_t ConvertSignalToNative(int sig)
if (sig >= linux_SIGRTMIN && sig <= linux_SIGRTMAX)
return (signal_t)sig; /* We ignore for now */
foreach (auto &mapping in signalMapping)
for (auto &mapping : signalMapping)
{
if (mapping.linuxSignal == sig)
{
@ -1109,10 +1109,7 @@ static int linux_mprotect(SysFrm *, void *addr, size_t len, int prot)
CPU::x32::invlpg(addr);
#elif defined(__aarch64__)
asmv("dsb sy");
asmv("tlbi vae1is, %0"
:
: "r"(addr)
: "memory");
asmv("tlbi vae1is, %0" : : "r"(addr) : "memory");
asmv("dsb sy");
asmv("isb");
#endif
@ -1149,9 +1146,13 @@ static int linux_ioctl(SysFrm *, int fd, unsigned long request, void *argp)
vfs::FileDescriptorTable *fdt = pcb->FileDescriptors;
Memory::VirtualMemoryArea *vma = pcb->vma;
auto pArgp = vma->UserCheckAndGetAddress(argp);
if (pArgp == nullptr)
return -linux_EFAULT;
void *pArgp = nullptr;
if (argp != nullptr)
{
pArgp = vma->UserCheckAndGetAddress(argp);
if (pArgp == nullptr)
return -linux_EFAULT;
}
int ret = ConvertErrnoToLinux(fdt->usr_ioctl(fd, request, pArgp));
return ret;
@ -1613,9 +1614,7 @@ static pid_t linux_vfork(SysFrm *sf)
return (int)NewProcess->ID;
}
__no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathname,
char *const argv[],
char *const envp[])
__no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathname, char *const argv[], char *const envp[])
{
/* FIXME: exec doesn't follow the UNIX standard
The pid, open files, etc. should be preserved */
@ -1761,13 +1760,66 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn
}
safeArgv[i] = nullptr;
return ConvertErrnoToLinux(linux_execve(sf, safeArgv[0],
(char *const *)safeArgv,
(char *const *)safeEnvp));
debug("calling linux_execve with %s", safeArgv[0]);
PCB *newPcb = TaskManager->CreateProcess(pcb, safeArgv[0], Tasking::TaskExecutionMode::User, false, pcb->Security.Real.UserID, pcb->Security.Real.GroupID);
if (!newPcb)
{
error("Failed to create process for interpreter");
return -linux_EAGAIN;
}
newPcb->Security = pcb->Security;
newPcb->Info = pcb->Info;
newPcb->FileDescriptors = pcb->FileDescriptors;
newPcb->CWD = pcb->CWD;
newPcb->PageTable = pcb->PageTable;
newPcb->vma = pcb->vma;
newPcb->ProgramBreak = pcb->ProgramBreak;
char **newArgv = (char **)newPcb->vma->RequestPages(TO_PAGES(i * sizeof(char *)));
char **newEnvp = (char **)newPcb->vma->RequestPages(TO_PAGES(envpLen * sizeof(char *)));
for (int j = 0; j < i; j++)
{
size_t len = strlen(safeArgv[j]);
char *newArg = (char *)newPcb->vma->RequestPages(TO_PAGES(len));
memcpy(newArg, safeArgv[j], len);
newArg[len] = '\0';
newArgv[j] = newArg;
}
newArgv[i] = nullptr;
for (int j = 0; j < envpLen; j++)
{
size_t len = strlen(safeEnvp[j]);
char *newEnv = (char *)newPcb->vma->RequestPages(TO_PAGES(len));
memcpy(newEnv, safeEnvp[j], len);
newEnv[len] = '\0';
newEnvp[j] = newEnv;
}
newEnvp[envpLen] = nullptr;
int ret = Execute::Spawn((char *)safeArgv[0], (const char **)newArgv, (const char **)newEnvp,
newPcb, true, newPcb->Info.Compatibility);
if (ret < 0)
{
error("Failed to spawn interpreter");
return ConvertErrnoToLinux(ret);
}
GetCurrentCPU()->CurrentProcess = newPcb;
GetCurrentCPU()->CurrentThread = newPcb->Threads[0];
while (true)
newPcb->GetContext()->Yield();
__builtin_unreachable();
}
if (pcb->Linux.vforked)
{
debug("vforked: %s", pPathname);
CriticalSection cs;
pcb->Linux.CallingThread->SetState(Tasking::Ready);
@ -1776,14 +1828,11 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn
pcb->PageTable = KernelPageTable->Fork();
pcb->vma = new Memory::VirtualMemoryArea(pcb->PageTable);
pcb->ProgramBreak = new Memory::ProgramBreak(pcb->PageTable, pcb->vma);
// tcb->Stack = new Memory::StackGuard(true, pcb->vma);
}
int ret = Execute::Spawn((char *)pPathname,
(const char **)safeArgv,
(const char **)safeEnvp,
pcb, true,
pcb->Info.Compatibility);
debug("spawn(%s %#lx %#lx %#lx %d %d)", pPathname, safeArgv, safeEnvp, pcb, true, pcb->Info.Compatibility);
int ret = Execute::Spawn((char *)pPathname, (const char **)safeArgv, (const char **)safeEnvp,
pcb, true, pcb->Info.Compatibility);
if (ret < 0)
{
@ -1986,7 +2035,7 @@ static pid_t linux_wait4(SysFrm *, pid_t pid, int *wstatus,
}
#ifdef DEBUG
foreach (auto child in pcb->Children)
for (auto child : pcb->Children)
debug("Child: %s(%d)", child->Name, child->ID);
#endif
@ -2073,7 +2122,7 @@ static int linux_kill(SysFrm *, pid_t pid, int sig)
bool found = false;
signal_t nSig = ConvertSignalToNative(sig);
assert(nSig != SIGNULL);
foreach (auto proc in pcb->GetContext()->GetProcessList())
for (auto proc : pcb->GetContext()->GetProcessList())
{
if (proc->Security.ProcessGroupID == thisProcess->Security.ProcessGroupID)
{
@ -2136,9 +2185,7 @@ static int linux_uname(SysFrm *, struct utsname *buf)
FileNode *rn = fs->GetByPath("/sys/cfg/cross/linux", pcb->Info.RootNode);
if (rn)
{
struct kstat st
{
};
struct kstat st{};
rn->Stat(&st);
char *sh = new char[st.Size];
@ -2368,6 +2415,56 @@ static ssize_t linux_readlink(SysFrm *, const char *pathname,
return ConvertErrnoToLinux(node->ReadLink(pBuf, bufsiz));
}
static int linux_fchmod(SysFrm *, int fd, mode_t mode)
{
PCB *pcb = thisProcess;
vfs::FileDescriptorTable *fdt = pcb->FileDescriptors;
if (fdt->FileMap.find(fd) == fdt->FileMap.end())
return -linux_EBADF;
struct kstat stat;
int ret = fdt->usr_fstat(fd, &stat);
if (ret < 0)
return ret;
if (stat.UserID != pcb->Security.Effective.UserID)
return -linux_EPERM;
/* TODO: check if FS is read-only: -linux_EROFS */
mode_t current = pcb->FileDescriptors->FileMap[fd].Mode;
mode_t newMode = (current & ~07777) | (mode & 07777);
/* TODO: add CAP_FSETID check */
if (stat.GroupID != pcb->Security.Effective.GroupID)
newMode &= ~S_ISGID;
/* FIXME: actually write to FS; maybe with fdt->usr_chmod or similar? */
pcb->FileDescriptors->FileMap[fd].Mode = newMode;
return 0;
}
static int linux_chmod(SysFrm *sf, const char *pathname, mode_t mode)
{
PCB *pcb = thisProcess;
Memory::VirtualMemoryArea *vma = pcb->vma;
const char *pPathname = vma->UserCheckAndGetAddress(pathname);
if (pPathname == nullptr)
return -linux_EFAULT;
FileNode *node = fs->GetByPath(pPathname, pcb->CWD);
if (!node)
return -linux_ENOENT;
vfs::FileDescriptorTable *fdt = pcb->FileDescriptors;
int fd = fdt->usr_open(pPathname, O_RDONLY, 0);
int ret = linux_fchmod(sf, fd, mode);
fdt->usr_close(fd);
return ret;
}
static mode_t linux_umask(SysFrm *, mode_t mask)
{
PCB *pcb = thisProcess;
@ -2409,7 +2506,7 @@ static int linux_getrusage(SysFrm *, int who, struct rusage *usage)
size_t uTime = 0;
size_t _maxrss = 0;
foreach (auto child in pcb->Children)
for (auto child : pcb->Children)
{
kTime += child->Info.KernelTime;
uTime += child->Info.UserTime;
@ -2449,6 +2546,90 @@ static int linux_getrusage(SysFrm *, int who, struct rusage *usage)
return 0;
}
static int linux_sysinfo(SysFrm *, struct sysinfo *info)
{
PCB *pcb = thisProcess;
Memory::VirtualMemoryArea *vma = pcb->vma;
auto pInfo = vma->UserCheckAndGetAddress(info);
if (pInfo == nullptr)
return -linux_EFAULT;
uint64_t nano = TimeManager->GetNanosecondsSinceClassCreation();
if (nano != 0)
nano /= 10000000;
pInfo->uptime = nano;
pInfo->loads[0] = 0;
pInfo->loads[1] = 0;
pInfo->loads[2] = 0;
pInfo->totalram = KernelAllocator.GetTotalMemory() - KernelAllocator.GetReservedMemory();
pInfo->freeram = KernelAllocator.GetFreeMemory();
pInfo->sharedram = 0;
pInfo->bufferram = 0;
pInfo->totalswap = 0;
pInfo->freeswap = 0;
pInfo->procs = TaskManager->GetProcessList().size();
pInfo->totalhigh = 0;
pInfo->freehigh = 0;
pInfo->mem_unit = 1;
if (sizeof(pInfo->_f) != 0)
memset(pInfo->_f, 0, sizeof(pInfo->_f));
return 0;
}
static int linux_syslog(SysFrm *, int type, char *bufp, int size)
{
PCB *pcb = thisProcess;
Memory::VirtualMemoryArea *vma = pcb->vma;
auto pbufp = vma->UserCheckAndGetAddress(bufp);
if (pbufp == nullptr)
return -linux_EFAULT;
switch (type)
{
case linux_SYSLOG_ACTION_CLOSE:
/* NOP */
return 0;
case linux_SYSLOG_ACTION_OPEN:
/* NOP */
return 0;
case linux_SYSLOG_ACTION_READ:
{
fixme("SYSLOG_ACTION_READ not implemented");
const char dummy[12] = "stub string";
memcpy(pbufp, dummy, sizeof(dummy));
return sizeof(dummy);
}
case linux_SYSLOG_ACTION_READ_ALL:
{
fixme("SYSLOG_ACTION_READ_ALL not implemented");
const char dummy[12] = "stub string";
memcpy(pbufp, dummy, sizeof(dummy));
return sizeof(dummy);
}
case linux_SYSLOG_ACTION_READ_CLEAR:
{
fixme("SYSLOG_ACTION_READ_CLEAR not implemented");
const char dummy[12] = "stub string";
memcpy(pbufp, dummy, sizeof(dummy));
return sizeof(dummy);
}
case linux_SYSLOG_ACTION_CLEAR:
case linux_SYSLOG_ACTION_CONSOLE_OFF:
case linux_SYSLOG_ACTION_CONSOLE_ON:
case linux_SYSLOG_ACTION_CONSOLE_LEVEL:
case linux_SYSLOG_ACTION_SIZE_UNREAD:
case linux_SYSLOG_ACTION_SIZE_BUFFER:
default:
break;
}
fixme("stub syslog");
return 0;
}
static uid_t linux_getuid(SysFrm *)
{
return thisProcess->Security.Real.UserID;
@ -2639,7 +2820,15 @@ static int linux_reboot(SysFrm *, int magic, int magic2, int cmd, void *arg)
break;
}
case linux_LINUX_REBOOT_CMD_CAD_ON:
{
fixme("Enable reboot on Ctrl+Alt+Del");
return 0;
}
case linux_LINUX_REBOOT_CMD_CAD_OFF:
{
fixme("Disable reboot on Ctrl+Alt+Del");
return 0;
}
case linux_LINUX_REBOOT_CMD_SW_SUSPEND:
case linux_LINUX_REBOOT_CMD_KEXEC:
{
@ -2951,7 +3140,7 @@ __no_sanitize("undefined") static ssize_t linux_getdents64(SysFrm *,
}
}
#endif
return ret;
return ConvertErrnoToLinux(ret);
}
static int linux_clock_gettime(SysFrm *, clockid_t clockid, struct timespec *tp)
@ -3075,7 +3264,7 @@ static int linux_tgkill(SysFrm *sf, pid_t tgid, pid_t tid, int sig)
debug("Invalid tgid %d tid %d", tgid, tid);
tcb = nullptr;
foreach (auto t in thisProcess->Threads)
for (auto t : thisProcess->Threads)
{
if (t->Linux.tgid == tgid)
{
@ -3462,8 +3651,8 @@ static SyscallData LinuxSyscallsTableAMD64[] = {
[__NR_amd64_unlink] = {"unlink", (void *)nullptr},
[__NR_amd64_symlink] = {"symlink", (void *)nullptr},
[__NR_amd64_readlink] = {"readlink", (void *)linux_readlink},
[__NR_amd64_chmod] = {"chmod", (void *)nullptr},
[__NR_amd64_fchmod] = {"fchmod", (void *)nullptr},
[__NR_amd64_chmod] = {"chmod", (void *)linux_chmod},
[__NR_amd64_fchmod] = {"fchmod", (void *)linux_fchmod},
[__NR_amd64_chown] = {"chown", (void *)nullptr},
[__NR_amd64_fchown] = {"fchown", (void *)nullptr},
[__NR_amd64_lchown] = {"lchown", (void *)nullptr},
@ -3471,11 +3660,11 @@ static SyscallData LinuxSyscallsTableAMD64[] = {
[__NR_amd64_gettimeofday] = {"gettimeofday", (void *)nullptr},
[__NR_amd64_getrlimit] = {"getrlimit", (void *)nullptr},
[__NR_amd64_getrusage] = {"getrusage", (void *)linux_getrusage},
[__NR_amd64_sysinfo] = {"sysinfo", (void *)nullptr},
[__NR_amd64_sysinfo] = {"sysinfo", (void *)linux_sysinfo},
[__NR_amd64_times] = {"times", (void *)nullptr},
[__NR_amd64_ptrace] = {"ptrace", (void *)nullptr},
[__NR_amd64_getuid] = {"getuid", (void *)linux_getuid},
[__NR_amd64_syslog] = {"syslog", (void *)nullptr},
[__NR_amd64_syslog] = {"syslog", (void *)linux_syslog},
[__NR_amd64_getgid] = {"getgid", (void *)linux_getgid},
[__NR_amd64_setuid] = {"setuid", (void *)nullptr},
[__NR_amd64_setgid] = {"setgid", (void *)nullptr},
@ -3837,7 +4026,7 @@ static SyscallData LinuxSyscallsTableI386[] = {
[__NR_i386_chdir] = {"chdir", (void *)linux_chdir},
[__NR_i386_time] = {"time", (void *)nullptr},
[__NR_i386_mknod] = {"mknod", (void *)nullptr},
[__NR_i386_chmod] = {"chmod", (void *)nullptr},
[__NR_i386_chmod] = {"chmod", (void *)linux_chmod},
[__NR_i386_lchown] = {"lchown", (void *)nullptr},
[__NR_i386_break] = {"break", (void *)nullptr},
[__NR_i386_oldstat] = {"oldstat", (void *)nullptr},
@ -3916,7 +4105,7 @@ static SyscallData LinuxSyscallsTableI386[] = {
[__NR_i386_munmap] = {"munmap", (void *)linux_munmap},
[__NR_i386_truncate] = {"truncate", (void *)nullptr},
[__NR_i386_ftruncate] = {"ftruncate", (void *)nullptr},
[__NR_i386_fchmod] = {"fchmod", (void *)nullptr},
[__NR_i386_fchmod] = {"fchmod", (void *)linux_fchmod},
[__NR_i386_fchown] = {"fchown", (void *)nullptr},
[__NR_i386_getpriority] = {"getpriority", (void *)nullptr},
[__NR_i386_setpriority] = {"setpriority", (void *)nullptr},
@ -3925,7 +4114,7 @@ static SyscallData LinuxSyscallsTableI386[] = {
[__NR_i386_fstatfs] = {"fstatfs", (void *)nullptr},
[__NR_i386_ioperm] = {"ioperm", (void *)nullptr},
[__NR_i386_socketcall] = {"socketcall", (void *)nullptr},
[__NR_i386_syslog] = {"syslog", (void *)nullptr},
[__NR_i386_syslog] = {"syslog", (void *)linux_syslog},
[__NR_i386_setitimer] = {"setitimer", (void *)linux_setitimer},
[__NR_i386_getitimer] = {"getitimer", (void *)nullptr},
[__NR_i386_stat] = {"stat", (void *)linux_stat},
@ -3938,7 +4127,7 @@ static SyscallData LinuxSyscallsTableI386[] = {
[__NR_i386_vm86old] = {"vm86old", (void *)nullptr},
[__NR_i386_wait4] = {"wait4", (void *)linux_wait4},
[__NR_i386_swapoff] = {"swapoff", (void *)nullptr},
[__NR_i386_sysinfo] = {"sysinfo", (void *)nullptr},
[__NR_i386_sysinfo] = {"sysinfo", (void *)linux_sysinfo},
[__NR_i386_ipc] = {"ipc", (void *)nullptr},
[__NR_i386_fsync] = {"fsync", (void *)nullptr},
[__NR_i386_sigreturn] = {"sigreturn", (void *)nullptr},

View File

@ -36,7 +36,7 @@ using Tasking::PCB;
using Tasking::TCB;
static int sys_api_version(SysFrm *Frame, int version) { return 0; }
static int sys_dummy(SysFrm *Frame) { return 0; }
static int sys_debug_report(SysFrm *Frame) { return 0; }
static ssize_t sys_read(SysFrm *Frame, int fildes, void *buf, size_t nbyte)
{
@ -264,74 +264,77 @@ static int sys_uname(SysFrm *Frame, struct kutsname *buf)
static SyscallData scTbl[SYS_MAX] = {};
__constructor void __init_native_syscalls(void)
{
#define init_syscall(name, func) \
scTbl[name] = {#name, (void *)func}
/* Initialization */
scTbl[SYS_API_VERSION] = {"SYS_API_VERSION", (void *)sys_api_version};
scTbl[1] = {"dummy", (void *)sys_dummy};
init_syscall(SYS_API_VERSION, sys_api_version);
init_syscall(SYS_DEBUG_REPORT, sys_debug_report);
/* I/O */
scTbl[SYS_READ] = {"SYS_READ", (void *)sys_read};
scTbl[SYS_PREAD] = {"SYS_PREAD", (void *)sys_pread};
scTbl[SYS_WRITE] = {"SYS_WRITE", (void *)sys_write};
scTbl[SYS_PWRITE] = {"SYS_PWRITE", (void *)sys_pwrite};
scTbl[SYS_OPEN] = {"SYS_OPEN", (void *)sys_open};
scTbl[SYS_CLOSE] = {"SYS_CLOSE", (void *)sys_close};
scTbl[SYS_IOCTL] = {"SYS_IOCTL", (void *)sys_ioctl};
scTbl[SYS_FCNTL] = {"SYS_FCNTL", (void *)sys_fcntl};
init_syscall(SYS_READ, sys_read);
init_syscall(SYS_PREAD, sys_pread);
init_syscall(SYS_WRITE, sys_write);
init_syscall(SYS_PWRITE, sys_pwrite);
init_syscall(SYS_OPEN, sys_open);
init_syscall(SYS_CLOSE, sys_close);
init_syscall(SYS_IOCTL, sys_ioctl);
init_syscall(SYS_FCNTL, sys_fcntl);
/* File Status */
scTbl[SYS_STAT] = {"SYS_STAT", (void *)sys_stat};
scTbl[SYS_FSTAT] = {"SYS_FSTAT", (void *)sys_fstat};
scTbl[SYS_LSTAT] = {"SYS_LSTAT", (void *)sys_lstat};
scTbl[SYS_ACCESS] = {"SYS_ACCESS", (void *)sys_access};
scTbl[SYS_TRUNCATE] = {"SYS_TRUNCATE", (void *)sys_truncate};
scTbl[SYS_FTRUNCATE] = {"SYS_FTRUNCATE", (void *)sys_ftruncate};
scTbl[SYS_TELL] = {"SYS_TELL", (void *)sys_tell};
scTbl[SYS_SEEK] = {"SYS_SEEK", (void *)sys_seek};
init_syscall(SYS_STAT, sys_stat);
init_syscall(SYS_FSTAT, sys_fstat);
init_syscall(SYS_LSTAT, sys_lstat);
init_syscall(SYS_ACCESS, sys_access);
init_syscall(SYS_TRUNCATE, sys_truncate);
init_syscall(SYS_FTRUNCATE, sys_ftruncate);
init_syscall(SYS_TELL, sys_tell);
init_syscall(SYS_SEEK, sys_seek);
/* Process Control */
scTbl[SYS_EXIT] = {"SYS_EXIT", (void *)sys_exit};
scTbl[SYS_FORK] = {"SYS_FORK", (void *)sys_fork};
scTbl[SYS_EXECVE] = {"SYS_EXECVE", (void *)sys_execve};
scTbl[SYS_GETPID] = {"SYS_GETPID", (void *)sys_getpid};
scTbl[SYS_GETPPID] = {"SYS_GETPPID", (void *)sys_getppid};
scTbl[SYS_WAITPID] = {"SYS_WAITPID", (void *)sys_waitpid};
scTbl[SYS_KILL] = {"SYS_KILL", (void *)sys_kill};
scTbl[SYS_PRCTL] = {"SYS_PRCTL", (void *)sys_prctl};
init_syscall(SYS_EXIT, sys_exit);
init_syscall(SYS_FORK, sys_fork);
init_syscall(SYS_EXECVE, sys_execve);
init_syscall(SYS_GETPID, sys_getpid);
init_syscall(SYS_GETPPID, sys_getppid);
init_syscall(SYS_WAITPID, sys_waitpid);
init_syscall(SYS_KILL, sys_kill);
init_syscall(SYS_PRCTL, sys_prctl);
/* Memory */
scTbl[SYS_BRK] = {"SYS_BRK", (void *)sys_brk};
scTbl[SYS_MMAP] = {"SYS_MMAP", (void *)sys_mmap};
scTbl[SYS_MUNMAP] = {"SYS_MUNMAP", (void *)sys_munmap};
scTbl[SYS_MPROTECT] = {"SYS_MPROTECT", (void *)sys_mprotect};
scTbl[SYS_MADVISE] = {"SYS_MADVISE", (void *)sys_madvise};
init_syscall(SYS_BRK, sys_brk);
init_syscall(SYS_MMAP, sys_mmap);
init_syscall(SYS_MUNMAP, sys_munmap);
init_syscall(SYS_MPROTECT, sys_mprotect);
init_syscall(SYS_MADVISE, sys_madvise);
/* Communication */
scTbl[SYS_PIPE] = {"SYS_PIPE", (void *)sys_pipe};
scTbl[SYS_DUP] = {"SYS_DUP", (void *)sys_dup};
scTbl[SYS_DUP2] = {"SYS_DUP2", (void *)sys_dup2};
scTbl[SYS_SOCKET] = {"SYS_SOCKET", (void *)sys_socket};
scTbl[SYS_BIND] = {"SYS_BIND", (void *)sys_bind};
scTbl[SYS_CONNECT] = {"SYS_CONNECT", (void *)sys_connect};
scTbl[SYS_LISTEN] = {"SYS_LISTEN", (void *)sys_listen};
scTbl[SYS_ACCEPT] = {"SYS_ACCEPT", (void *)sys_accept};
scTbl[SYS_SEND] = {"SYS_SEND", (void *)sys_send};
scTbl[SYS_RECV] = {"SYS_RECV", (void *)sys_recv};
scTbl[SYS_SHUTDOWN] = {"SYS_SHUTDOWN", (void *)sys_shutdown};
init_syscall(SYS_PIPE, sys_pipe);
init_syscall(SYS_DUP, sys_dup);
init_syscall(SYS_DUP2, sys_dup2);
init_syscall(SYS_SOCKET, sys_socket);
init_syscall(SYS_BIND, sys_bind);
init_syscall(SYS_CONNECT, sys_connect);
init_syscall(SYS_LISTEN, sys_listen);
init_syscall(SYS_ACCEPT, sys_accept);
init_syscall(SYS_SEND, sys_send);
init_syscall(SYS_RECV, sys_recv);
init_syscall(SYS_SHUTDOWN, sys_shutdown);
/* Time */
scTbl[SYS_TIME] = {"SYS_TIME", (void *)sys_time};
scTbl[SYS_CLOCK_GETTIME] = {"SYS_CLOCK_GETTIME", (void *)sys_clock_gettime};
scTbl[SYS_CLOCK_SETTIME] = {"SYS_CLOCK_SETTIME", (void *)sys_clock_settime};
scTbl[SYS_NANOSLEEP] = {"SYS_NANOSLEEP", (void *)sys_nanosleep};
init_syscall(SYS_TIME, sys_time);
init_syscall(SYS_CLOCK_GETTIME, sys_clock_gettime);
init_syscall(SYS_CLOCK_SETTIME, sys_clock_settime);
init_syscall(SYS_NANOSLEEP, sys_nanosleep);
/* Miscellaneous */
scTbl[SYS_GETCWD] = {"SYS_GETCWD", (void *)sys_getcwd};
scTbl[SYS_CHDIR] = {"SYS_CHDIR", (void *)sys_chdir};
scTbl[SYS_MKDIR] = {"SYS_MKDIR", (void *)sys_mkdir};
scTbl[SYS_RMDIR] = {"SYS_RMDIR", (void *)sys_rmdir};
scTbl[SYS_UNLINK] = {"SYS_UNLINK", (void *)sys_unlink};
scTbl[SYS_RENAME] = {"SYS_RENAME", (void *)sys_rename};
scTbl[SYS_UNAME] = {"SYS_UNAME", (void *)sys_uname};
init_syscall(SYS_GETCWD, sys_getcwd);
init_syscall(SYS_CHDIR, sys_chdir);
init_syscall(SYS_MKDIR, sys_mkdir);
init_syscall(SYS_RMDIR, sys_rmdir);
init_syscall(SYS_UNLINK, sys_unlink);
init_syscall(SYS_RENAME, sys_rename);
init_syscall(SYS_UNAME, sys_uname);
}
uintptr_t HandleNativeSyscalls(SysFrm *Frame)

View File

@ -178,7 +178,7 @@ int sys_kill(SysFrm *Frame, pid_t pid, int sig)
if (pid == 0)
{
bool found = false;
foreach (auto proc in pcb->GetContext()->GetProcessList())
for (auto proc : pcb->GetContext()->GetProcessList())
{
if (proc->Security.ProcessGroupID == thisProcess->Security.ProcessGroupID)
{

View File

@ -113,6 +113,12 @@ namespace Tasking
trace("Setting exe %s to %s",
this->Name, path);
Executable = fs->GetByPath(path, ProcDirectory);
if (Executable->IsSymbolicLink())
{
char buffer[512];
Executable->ReadLink(buffer, sizeof(buffer));
Executable = fs->GetByPath(buffer, Executable->Parent);
}
FileNode *exe = fs->GetByPath("exe", ProcDirectory);
if (exe)
fs->Remove(exe);
@ -289,7 +295,7 @@ namespace Tasking
}
/* Exit all children processes */
foreach (auto pcb in this->Children)
for (auto pcb : this->Children)
{
if (pcb == nullptr)
{
@ -303,7 +309,7 @@ namespace Tasking
}
/* Exit all threads */
foreach (auto tcb in this->Threads)
for (auto tcb : this->Threads)
{
if (tcb == nullptr)
{

View File

@ -140,7 +140,7 @@ namespace Tasking::Scheduler
return true;
}
foreach (TCB *Thread in Process->Threads)
for (TCB *Thread : Process->Threads)
{
if (Thread->State == Terminated)
RemoveThread(Thread);
@ -151,7 +151,7 @@ namespace Tasking::Scheduler
PCB *Custom::GetProcessByID(TID ID)
{
foreach (auto p in ProcessList)
for (auto p : ProcessList)
{
if (p->ID == ID)
return p;
@ -164,7 +164,7 @@ namespace Tasking::Scheduler
if (unlikely(Parent == nullptr))
return nullptr;
foreach (auto t in Parent->Threads)
for (auto t : Parent->Threads)
{
if (t->ID == ID)
return t;
@ -174,8 +174,7 @@ namespace Tasking::Scheduler
void Custom::StartIdleProcess()
{
IdleProcess = ctx->CreateProcess(nullptr, (char *)"Idle",
TaskExecutionMode::Kernel, true);
IdleProcess = ctx->GetKernelProcess();
for (int i = 0; i < SMP::CPUCores; i++)
{
TCB *thd = ctx->CreateThread(IdleProcess, IP(__custom_sched_idle_loop));
@ -306,11 +305,11 @@ namespace Tasking::Scheduler
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
fnp_schedbg("%d processes", ProcessList.size());
#ifdef DEBUG_FIND_NEW_PROCESS
foreach (auto process in ProcessList)
for (auto process : ProcessList)
fnp_schedbg("Process %d %s", process->ID,
process->Name);
#endif
foreach (auto process in ProcessList)
for (auto process : ProcessList)
{
switch (process->State.load())
{
@ -331,7 +330,7 @@ namespace Tasking::Scheduler
continue;
}
foreach (auto thread in process->Threads)
for (auto thread : process->Threads)
{
if (thread->State.load() != TaskState::Ready)
continue;
@ -378,7 +377,10 @@ namespace Tasking::Scheduler
}
if (nextThread->Info.Affinity[CurrentCPU->ID] == false)
continue;
{
TempIndex++;
goto RetryAnotherThread;
}
CurrentCPU->CurrentThread = nextThread;
gnat_schedbg("[thd 0 -> end] Scheduling thread %d parent of %s->%d Procs %d",
@ -402,7 +404,7 @@ namespace Tasking::Scheduler
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
bool Skip = true;
foreach (auto process in ProcessList)
for (auto process : ProcessList)
{
if (process == CurrentCPU->CurrentProcess.load())
{
@ -423,7 +425,7 @@ namespace Tasking::Scheduler
continue;
}
foreach (auto thread in process->Threads)
for (auto thread : process->Threads)
{
if (thread->State.load() != TaskState::Ready)
{
@ -449,7 +451,7 @@ namespace Tasking::Scheduler
{
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
foreach (auto process in ProcessList)
for (auto process : ProcessList)
{
if (process->State.load() != TaskState::Ready)
{
@ -457,7 +459,7 @@ namespace Tasking::Scheduler
continue;
}
foreach (auto thread in process->Threads)
for (auto thread : process->Threads)
{
if (thread->State.load() != TaskState::Ready)
{
@ -480,7 +482,7 @@ namespace Tasking::Scheduler
nsa NIF void Custom::UpdateProcessState()
{
foreach (auto process in ProcessList)
for (auto process : ProcessList)
{
if (process->State.load() == TaskState::Terminated)
continue;
@ -492,7 +494,7 @@ namespace Tasking::Scheduler
}
bool AllThreadsSleeping = true;
foreach (auto thread in process->Threads)
for (auto thread : process->Threads)
{
if (thread->State.load() == TaskState::Terminated)
continue;
@ -513,7 +515,7 @@ namespace Tasking::Scheduler
nsa NIF void Custom::WakeUpThreads()
{
foreach (auto process in ProcessList)
for (auto process : ProcessList)
{
Tasking::TaskState pState = process->State.load();
if (pState != TaskState::Ready &&
@ -521,7 +523,7 @@ namespace Tasking::Scheduler
pState != TaskState::Blocked)
continue;
foreach (auto thread in process->Threads)
for (auto thread : process->Threads)
{
if (likely(thread->State.load() != TaskState::Sleeping))
continue;
@ -547,7 +549,7 @@ namespace Tasking::Scheduler
nsa NIF void Custom::CleanupTerminated()
{
foreach (auto pcb in ProcessList)
for (auto pcb : ProcessList)
{
if (pcb->State.load() == TaskState::Terminated)
{
@ -556,7 +558,7 @@ namespace Tasking::Scheduler
continue;
}
foreach (TCB *tcb in pcb->Threads)
for (TCB *tcb : pcb->Threads)
{
if (tcb->State == Terminated)
delete tcb;
@ -737,9 +739,9 @@ namespace Tasking::Scheduler
Custom::~Custom()
{
foreach (PCB *Process in ProcessList)
for (PCB *Process : ProcessList)
{
foreach (TCB *Thread in Process->Threads)
for (TCB *Thread : Process->Threads)
{
if (Thread == GetCurrentCPU()->CurrentThread.load())
continue;
@ -757,7 +759,7 @@ namespace Tasking::Scheduler
{
trace("Waiting for %d processes to terminate", this->GetProcessList().size());
int NotTerminated = 0;
foreach (PCB *Process in this->GetProcessList())
for (PCB *Process : this->GetProcessList())
{
trace("Process %s(%d) is still running (or waiting to be removed state %#lx)",
Process->Name, Process->ID, Process->State);

View File

@ -176,7 +176,7 @@ static const struct
signal_disposition_t GetDefaultSignalDisposition(signal_t sig)
{
foreach (auto var in SignalDisposition)
for (auto var : SignalDisposition)
{
if (var.Signal == sig)
return var.Disposition;
@ -519,7 +519,7 @@ namespace Tasking
debug("Signal %s(%d) completed", sigStr[sig], sig);
if (Disposition[sig] != SIG_IGN)
{
foreach (auto info in Watchers)
for (auto info : Watchers)
{
Signal *who = (Signal *)info.val.sival_ptr;
assert(who != nullptr);

View File

@ -201,7 +201,7 @@ namespace Tasking
GetCurrentProcess()->Name, GetCurrentProcess()->ID,
GetCurrentThread()->Name, GetCurrentThread()->ID);
foreach (auto pcb in((Scheduler::Base *)Scheduler)->GetProcessList())
for (auto pcb : ((Scheduler::Base *)Scheduler)->GetProcessList())
{
if (pcb->State == TaskState::Terminated ||
pcb->State == TaskState::Zombie)

View File

@ -268,7 +268,7 @@ namespace Tasking
auxv_array.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
/* Store auxillary vector */
foreach (AuxiliaryVector av in auxv_array)
for (AuxiliaryVector av : auxv_array)
{
/* Subtract the size of the auxillary vector */
Stack64 -= sizeof(Elf_auxv_t) / sizeof(uintptr_t);

View File

@ -24,6 +24,7 @@
#include "../kernel.h"
#include <coroutine>
#include <thread>
/* https://gist.github.com/Qix-/caa277fbf1a4e6ca55a27f2242df3b9a */
@ -58,7 +59,7 @@ struct resumable::promise_type
auto initial_suspend() { return std::suspend_always(); }
auto final_suspend() noexcept { return std::suspend_always(); }
void return_void() {}
void unhandled_exception() { assert(!"std::terminate();"); }
void unhandled_exception() { std::terminate(); }
};
resumable foo()
@ -70,6 +71,122 @@ resumable foo()
/* ===================================================================== */
struct Generator
{
struct promise_type
{
int current_value;
Generator get_return_object()
{
return Generator{std::coroutine_handle<promise_type>::from_promise(*this)};
}
std::suspend_always initial_suspend()
{
return {};
}
std::suspend_always final_suspend() noexcept
{
return {};
}
void return_void()
{
}
std::suspend_always yield_value(int value)
{
current_value = value;
return {};
}
void unhandled_exception()
{
std::terminate();
}
};
std::coroutine_handle<promise_type> handle;
Generator(std::coroutine_handle<promise_type> h) : handle(h) {}
~Generator()
{
if (handle)
handle.destroy();
}
bool next()
{
if (!handle || handle.done())
return false;
handle.resume();
return true;
}
int value() const
{
int ret = handle.promise().current_value;
return ret;
}
};
Generator CountToThree()
{
debug("1");
co_yield 1;
debug("2");
co_yield 2;
debug("3");
co_yield 3;
debug("end");
}
/* ===================================================================== */
struct Task
{
struct promise_type
{
Task get_return_object() { return Task{std::coroutine_handle<promise_type>::from_promise(*this)}; }
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() { std::terminate(); }
};
std::coroutine_handle<promise_type> handle;
Task(std::coroutine_handle<promise_type> h) : handle(h) {}
~Task()
{
if (handle)
handle.destroy();
}
};
struct Awaiter
{
bool await_ready() { return false; }
void await_suspend(std::coroutine_handle<> h)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
h.resume();
}
void await_resume() {}
};
Task AsyncFunc()
{
debug("waiting");
co_await Awaiter{};
debug("done");
}
/* ===================================================================== */
class SyscallAwaitable
{
public:
@ -120,7 +237,7 @@ public:
void unhandled_exception()
{
assert("std::terminate();");
std::terminate();
}
};
@ -146,6 +263,17 @@ void coroutineTest()
auto task = perform_syscall();
task.handle.resume();
/* async task */
AsyncFunc();
/* generator */
auto gen = CountToThree();
while (gen.next())
{
auto a = gen.value();
debug("%d", a);
}
/* Example of coroutine */
auto p = foo();
while (p.resume())

View File

@ -0,0 +1,159 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <future>
#include <thread>
#include <assert.h>
void test_stl_future()
{
// {
// std::packaged_task<int()> task([]
// { return 7; });
// std::future<int> f1 = task.get_future();
// std::thread t(std::move(task));
// std::future<int> f2 = std::async(std::launch::async, []
// { return 8; });
// std::promise<int> p;
// std::future<int> f3 = p.get_future();
// std::thread([&p]
// { p.set_value_at_thread_exit(9); })
// .detach();
// debug("Waiting for futures...");
// f1.wait();
// f2.wait();
// f3.wait();
// debug("results: %d %d %d", f1.get(), f2.get(), f3.get());
// t.join();
// }
// {
// std::future<int> f = std::async(std::launch::async, []
// {
// for (uint64_t i = 0; i < 100000; ++i);
// return 1; });
// debug("waiting for future");
// int result = f.get();
// debug("future result is %d", result);
// }
// {
// std::promise<int> p;
// std::future<int> f = p.get_future();
// assert(f.valid());
// p.set_value(42);
// assert(f.get() == 42);
// try
// {
// f.get();
// assert(false);
// }
// catch (const std::future_error &e)
// {
// // assert(e.code() == std::future_errc::future_already_retrieved);
// }
// }
// {
// auto future = std::async([]()
// { return 42; });
// assert(future.get() == 42);
// }
// {
// std::promise<int> p;
// std::future<int> f = p.get_future();
// std::shared_future<int> sf = f.share();
// p.set_value(42);
// assert(sf.get() == 42);
// assert(sf.get() == 42);
// }
// {
// std::promise<int> p;
// std::future<int> f = p.get_future();
// auto status = f.wait_for(std::chrono::milliseconds(100));
// assert(status == std::future_status::timeout);
// p.set_value(42);
// status = f.wait_for(std::chrono::milliseconds(100));
// assert(status == std::future_status::ready);
// }
// {
// auto future = std::async(std::launch::async, []()
// { return 42; });
// assert(future.get() == 42);
// auto deferred = std::async(std::launch::deferred, []()
// { return 42; });
// assert(deferred.get() == 42);
// }
// {
// std::promise<int> p1, p2;
// std::future<int> f1 = p1.get_future();
// std::future<int> f2 = p2.get_future();
// p1.set_value(42);
// p2.set_value(24);
// assert(f1.get() == 42);
// assert(f2.get() == 24);
// }
// {
// std::promise<int> p;
// std::future<int> f1 = p.get_future();
// std::future<int> f2 = std::move(f1);
// p.set_value(42);
// assert(f2.get() == 42);
// }
// {
// std::promise<int> p;
// std::shared_future<int> sf = p.get_future().share();
// std::atomic<int> sum{0};
// std::vector<std::thread> threads;
// for (int i = 0; i < 10; ++i)
// {
// threads.emplace_back([&sf, &sum]()
// { sum += sf.get(); });
// }
// p.set_value(42);
// for (auto &t : threads)
// {
// t.join();
// }
// assert(sum == 420);
// }
}

View File

@ -25,6 +25,7 @@ void test_stl_vector();
void test_stl_bitset();
void test_stl_string();
void test_stl_unordered_map() {}
void test_stl_future();
void Test_stl()
{
@ -36,6 +37,7 @@ void Test_stl()
test_stl_bitset();
test_stl_string();
test_stl_unordered_map();
test_stl_future();
}
#endif // DEBUG
#endif // DEBUG

View File

@ -31,7 +31,7 @@ void killChildren(Tasking::PCB *pcb)
std::vector<Tasking::PCB *> children = pcb->Children;
foreach (auto child in children)
for (auto child : children)
{
if (child->State.load() == Tasking::Terminated)
{

View File

@ -131,7 +131,7 @@ void TaskMgr()
// Display->SetBufferCursor(0, 0);
printf("\eF02C21Task Manager\n");
static uint64_t OldSystemTime = 0;
foreach (auto Proc in TaskManager->GetProcessList())
for (auto Proc : TaskManager->GetProcessList())
{
if (!Proc)
continue;
@ -150,7 +150,7 @@ void TaskMgr()
#warning "aarch64 not implemented"
#endif
foreach (auto Thd in Proc->Threads)
for (auto Thd : Proc->Threads)
{
if (!Thd)
continue;

View File

@ -24,7 +24,7 @@
void TreeFS(FileNode *node, int Depth)
{
return;
// foreach (auto Chld in node->GetChildren(true))
// for (auto Chld : node->GetChildren(true))
// {
// printf("%*c %s\eFFFFFF\n", Depth, ' ', Chld->FileName);

View File

@ -176,7 +176,11 @@ namespace KernelConsole
debug("returning sid %d", thisProcess->Security.SessionID);
return 0;
}
case TIOCSCTTY:
{
fixme("stub ioctl TIOCSCTTY");
return 0;
}
default:
{
debug("Unknown ioctl %#lx", Request);

View File

@ -59,6 +59,10 @@ Make sure to read and comply with these licenses before using or redistributing
- **License:** Unlicense
- **Location(s):** [Userspace/libc/src/arith64.c](Userspace/libc/src/arith64.c)
## utf8.h
- **License:** Unlicense
- **Location(s):** [Kernel/include/utf8.h](Kernel/include/utf8.h)
---
Please refer to the respective license files for the full text of each license.

View File

@ -160,6 +160,7 @@ ci-setup:
ci-build:
# Prepare
$(MAKE) prepare
$(MAKE) mkdir_rootfs
$(MAKE) --quiet -C tools do_limine
# amd64
sed -i 's/.*OSARCH = .*/OSARCH = amd64/' ./config.mk && cat config.mk | grep OSARCH

View File

@ -674,6 +674,8 @@ typedef enum
*/
SYS_API_VERSION = 0,
SYS_DEBUG_REPORT = 1,
/* I/O */
/**

View File

@ -22,6 +22,8 @@
#include <stddef.h>
#include <limits.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
@ -359,15 +361,63 @@ void ProcessNeededLibraries(Elf_Dyn *elem, ElfInfo *Info)
ElfInfo *info = NULL;
char fullLibPath[PATH_MAX];
strcpy(fullLibPath, "/lib/");
strcat(fullLibPath, libPath);
/* TODO: more checks and also check environment variables */
if (sysdep(Access)(fullLibPath, F_OK) != 0)
int found = 0;
char *ldLibPath = getenv("LD_LIBRARY_PATH");
if (ldLibPath)
{
printf("dl: Can't access %s\n", fullLibPath);
char *pathCopy = strdup(ldLibPath);
char *path = strtok(pathCopy, ":");
while (path)
{
strcpy(fullLibPath, path);
if (fullLibPath[strlen(fullLibPath) - 1] != '/')
strcat(fullLibPath, "/");
strcat(fullLibPath, libPath);
if (sysdep(Access)(fullLibPath, F_OK) == 0)
{
found = 1;
break;
}
path = strtok(NULL, ":");
}
free(pathCopy);
if (found)
goto load_lib;
}
const char *standardPaths[] = {
"/sys/lib/",
"/usr/lib/",
"/lib/",
"/usr/local/lib/",
"/usr/local/lib64/",
"/usr/lib64/",
"/lib64/"};
for (size_t i = 0; i < sizeof(standardPaths) / sizeof(standardPaths[0]); i++)
{
strcpy(fullLibPath, standardPaths[i]);
strcat(fullLibPath, libPath);
if (sysdep(Access)(fullLibPath, F_OK) == 0)
{
found = 1;
break;
}
}
if (!found)
{
printf("dl: Library %s not found in search paths\n", libPath);
return;
}
load_lib:
int fd = sysdep(Open)(fullLibPath, O_RDONLY, 0644);
int status = LoadElf(fd, fullLibPath, &info);
elem->d_un.d_ptr = (uintptr_t)info; /* if LoadElf fails, info will still be NULL */

View File

@ -169,11 +169,14 @@ __do_gcc:
--enable-libgm2 \
--enable-libssp \
--enable-libstdcxx \
--disable-hosted-libstdcxx \
&& \
$(MAKE) --quiet all-gcc -j$(shell nproc) && \
$(MAKE) --quiet all-target-libgcc -j$(shell nproc) && \
$(MAKE) --quiet all-target-libstdc++-v3 -j$(shell nproc) && \
$(MAKE) --quiet install-gcc -j$(shell nproc) && \
$(MAKE) --quiet install-target-libgcc -j$(shell nproc)
$(MAKE) --quiet install-target-libgcc -j$(shell nproc) && \
$(MAKE) --quiet install-target-libstdc++-v3 -j$(shell nproc)
do_binutils:
$(MAKE) __do_binutils BUILD_TARGET="x86_64-fennix"

View File

@ -14,6 +14,34 @@ menuentry "Fennix" {
boot
}
submenu "Advanced Options..." {
menuentry "Fennix (Linux Subsystem)" {
load_video
clear
echo "Loading kernel in Linux Subsystem mode"
multiboot2 /fennix.elf --init=/bin/init --linux=true
echo "Loading rootfs"
module2 /rootfs.tar rootfs
echo "Booting..."
boot
}
menuentry "Fennix (Recovery)" {
load_video
clear
echo "Loading kernel in recovery mode"
multiboot2 /fennix.elf
echo "Loading rootfs"
module2 /rootfs.tar rootfs
echo "Booting..."
boot
}
}
menuentry ' ' {
exit 1
}
menuentry 'Boot from next volume' {
exit 1
}