mirror of
https://github.com/EnderIce2/Fennix.git
synced 2025-05-25 22:14:34 +00:00
Compare commits
46 Commits
92fe4bdd81
...
0041300a00
Author | SHA1 | Date | |
---|---|---|---|
0041300a00 | |||
fe6d7f4b08 | |||
a1622cc885 | |||
bd32020876 | |||
44323c85a3 | |||
027d77ed66 | |||
bbb70eb621 | |||
1593e3107d | |||
1a48d05042 | |||
75dd958316 | |||
cccbfd2c95 | |||
bf20bd89ed | |||
c3fd55bb00 | |||
c660a7fe4f | |||
91ad0e14df | |||
a6ca98987e | |||
f8f08a11db | |||
5d64c05446 | |||
a1064d8978 | |||
6d01cf4e69 | |||
ffd992cd74 | |||
8d71ed0ad5 | |||
93d897e95c | |||
31181d5b5d | |||
2f18d390e4 | |||
5ffb0e704d | |||
ad0c1e15e0 | |||
b74d4db23b | |||
022d99f795 | |||
3482131b3f | |||
0a32c19923 | |||
36c5c8ad67 | |||
6240d6638f | |||
7491f19f9a | |||
13d52897b8 | |||
4cc058ab42 | |||
a7f754c5e8 | |||
9304cafe0c | |||
7b42b46942 | |||
2ce0e0ed79 | |||
d69eb73a59 | |||
aa8f415b98 | |||
ec792f1fe2 | |||
4c31568329 | |||
e9dd70c6c4 | |||
4e9d25143e |
@ -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
|
||||
|
@ -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"
|
||||
]
|
||||
}
|
||||
|
1
.github/workflows/makefile.yml
vendored
1
.github/workflows/makefile.yml
vendored
@ -121,6 +121,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Cache cross Folder
|
||||
id: cache-cross
|
||||
|
80
CHANGELOG.md
80
CHANGELOG.md
@ -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 -->
|
||||
|
@ -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.
|
||||
|
||||
|
@ -674,6 +674,8 @@ typedef enum
|
||||
*/
|
||||
SYS_API_VERSION = 0,
|
||||
|
||||
SYS_DEBUG_REPORT = 1,
|
||||
|
||||
/* I/O */
|
||||
|
||||
/**
|
||||
|
@ -34,7 +34,10 @@
|
||||
"kernel",
|
||||
"kernel/pci",
|
||||
"kernel/driver",
|
||||
"kernel/drivers"
|
||||
"kernel/drivers",
|
||||
"kernel/elf",
|
||||
"kernel/scheduler",
|
||||
"kernel/tty"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -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 $<)
|
||||
|
@ -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)));
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 |
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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__
|
||||
|
@ -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__
|
||||
|
@ -674,6 +674,8 @@ typedef enum
|
||||
*/
|
||||
SYS_API_VERSION = 0,
|
||||
|
||||
SYS_DEBUG_REPORT = 1,
|
||||
|
||||
/* I/O */
|
||||
|
||||
/**
|
||||
|
@ -33,7 +33,7 @@ struct KernelConfig
|
||||
bool SchedulerType;
|
||||
char DriverDirectory[256];
|
||||
char InitPath[256];
|
||||
bool UseLinuxSyscalls;
|
||||
bool LinuxSubsystem;
|
||||
bool InterruptsOnCrash;
|
||||
int Cores;
|
||||
int IOAPICInterruptCore;
|
||||
|
@ -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
1718
Kernel/include/utf8.h
Normal file
File diff suppressed because it is too large
Load Diff
126
Kernel/include_std/chrono
Normal file
126
Kernel/include_std/chrono
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
|
68
Kernel/include_std/cstdint
Normal file
68
Kernel/include_std/cstdint
Normal 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)
|
||||
}
|
@ -16,4 +16,9 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <convert.h>
|
||||
|
||||
namespace std
|
||||
{
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
279
Kernel/include_std/future
Normal 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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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
79
Kernel/include_std/ratio
Normal 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;
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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))));
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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))
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
27
Kernel/library/libstdc++/exception.cpp
Normal file
27
Kernel/library/libstdc++/exception.cpp
Normal 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();
|
||||
}
|
||||
}
|
27
Kernel/library/std/future.cpp
Normal file
27
Kernel/library/std/future.cpp
Normal 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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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__
|
||||
|
@ -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},
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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())
|
||||
|
159
Kernel/tests/stl/future_test.cpp
Normal file
159
Kernel/tests/stl/future_test.cpp
Normal 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);
|
||||
// }
|
||||
}
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
1
Makefile
1
Makefile
@ -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
|
||||
|
@ -674,6 +674,8 @@ typedef enum
|
||||
*/
|
||||
SYS_API_VERSION = 0,
|
||||
|
||||
SYS_DEBUG_REPORT = 1,
|
||||
|
||||
/* I/O */
|
||||
|
||||
/**
|
||||
|
@ -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 */
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user