Showing preview only (457K chars total). Download the full file or copy to clipboard to get everything.
Repository: clstatham/k4dos
Branch: master
Commit: e8aab3ba0914
Files: 91
Total size: 431.2 KB
Directory structure:
gitextract_c29w2sxr/
├── .cargo/
│ ├── config.toml
│ ├── debug.toml
│ ├── linker.ld
│ ├── release.toml
│ ├── runner_debug.sh
│ ├── runner_release.sh
│ └── x86_64-kados.json
├── .gitignore
├── .vscode/
│ ├── launch.json
│ └── settings.json
├── Cargo.toml
├── LICENSE
├── README.md
├── build.rs
├── conf/
│ ├── grub.cfg
│ └── limine.cfg
├── deps.sh
├── kados.config
├── rust-toolchain.toml
├── src/
│ ├── arch/
│ │ ├── mod.rs
│ │ └── x86_64/
│ │ ├── cpu_local.rs
│ │ ├── gdt.rs
│ │ ├── idt.rs
│ │ ├── mod.rs
│ │ ├── syscall.rs
│ │ ├── task.rs
│ │ └── time.rs
│ ├── backtrace.rs
│ ├── fs/
│ │ ├── devfs/
│ │ │ ├── fb.rs
│ │ │ ├── input.rs
│ │ │ ├── mod.rs
│ │ │ ├── null.rs
│ │ │ ├── socket.rs
│ │ │ ├── tty.rs
│ │ │ └── urandom.rs
│ │ ├── initramfs/
│ │ │ ├── dir.rs
│ │ │ ├── file.rs
│ │ │ ├── mod.rs
│ │ │ ├── root.rs
│ │ │ └── symlink.rs
│ │ ├── mod.rs
│ │ ├── opened_file.rs
│ │ ├── path.rs
│ │ └── pipe.rs
│ ├── god_mode.rs
│ ├── graphics/
│ │ └── mod.rs
│ ├── logging.rs
│ ├── main.rs
│ ├── mem/
│ │ ├── addr.rs
│ │ ├── addr_space.rs
│ │ ├── allocator.rs
│ │ ├── consts.rs
│ │ ├── mod.rs
│ │ └── paging/
│ │ ├── mapper.rs
│ │ ├── mod.rs
│ │ ├── table.rs
│ │ └── units.rs
│ ├── serial.rs
│ ├── task/
│ │ ├── group.rs
│ │ ├── mod.rs
│ │ ├── scheduler.rs
│ │ ├── signal.rs
│ │ ├── vmem.rs
│ │ └── wait_queue.rs
│ ├── userland/
│ │ ├── buffer.rs
│ │ ├── elf.rs
│ │ ├── mod.rs
│ │ └── syscall/
│ │ ├── mod.rs
│ │ └── syscall_impl/
│ │ ├── fs.rs
│ │ ├── mem.rs
│ │ ├── mod.rs
│ │ ├── signal.rs
│ │ ├── sys.rs
│ │ ├── task.rs
│ │ └── time.rs
│ ├── util/
│ │ ├── ctypes.rs
│ │ ├── errno.rs
│ │ ├── error.rs
│ │ ├── lock.rs
│ │ ├── mod.rs
│ │ ├── ringbuffer.rs
│ │ └── stack.rs
│ └── vga_text.rs
└── userland/
├── .gitignore
├── .vscode/
│ └── settings.json
├── Cargo.toml
├── kados_syscall/
│ ├── .cargo/
│ │ └── config.toml
│ ├── Cargo.toml
│ └── src/
│ ├── consts.rs
│ └── lib.rs
└── rust-toolchain.toml
================================================
FILE CONTENTS
================================================
================================================
FILE: .cargo/config.toml
================================================
[build]
target = "x86_64-unknown-none"
rustflags = ["-Cforce-frame-pointers=yes"]
[unstable]
build-std = ["core", "compiler_builtins", "alloc"]
build-std-features = ["compiler-builtins-mem"]
[alias]
qemu = "run --release --config .cargo/release.toml"
qemu-debug = "run --config .cargo/debug.toml"
================================================
FILE: .cargo/debug.toml
================================================
[target.x86_64-unknown-none]
runner = ["bash", ".cargo/runner_debug.sh"]
================================================
FILE: .cargo/linker.ld
================================================
ENTRY(start)
OUTPUT_ARCH(i386:x86-64)
OUTPUT_FORMAT(elf64-x86-64)
KERNEL_BASE = 0xffffffff80000000;
SECTIONS {
. = KERNEL_BASE + SIZEOF_HEADERS;
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.rela : { *(.rela*) }
.rodata : { *(.rodata .rodata.*) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.eh_frame_hdr : {
PROVIDE(__eh_frame_hdr = .);
KEEP(*(.eh_frame_hdr))
PROVIDE(__eh_frame_hdr_end = .);
}
.eh_frame : {
PROVIDE(__eh_frame = .);
KEEP(*(.eh_frame))
PROVIDE(__eh_frame_end = .);
}
.gcc_except_table : { KEEP(*(.gcc_except_table .gcc_except_table.*)) }
. += CONSTANT(MAXPAGESIZE);
.plt : { *(.plt .plt.*) }
.text : { *(.text .text.*) }
. += CONSTANT(MAXPAGESIZE);
.tdata : { *(.tdata .tdata.*) }
.tbss : { *(.tbss .tbss.*) }
.data.rel.ro : { *(.data.rel.ro .data.rel.ro.*) }
.dynamic : { *(.dynamic) }
. = DATA_SEGMENT_RELRO_END(0, .);
.got : { *(.got .got.*) }
.got.plt : { *(.got.plt .got.plt.*) }
.data : { *(.data .data.*) }
.bss : { *(.bss .bss.*) *(COMMON) }
. = DATA_SEGMENT_END(.);
.comment 0 : { *(.comment) }
.debug 0 : { *(.debug) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_aranges 0 : { *(.debug_aranges) }
.debug_frame 0 : { *(.debug_frame) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_line 0 : { *(.debug_line) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
.debug_pubnames 0 : { *(.debug_pubnames) }
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
.debug_sfnames 0 : { *(.debug_sfnames) }
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_str 0 : { *(.debug_str) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
.debug_weaknames 0 : { *(.debug_weaknames) }
.line 0 : { *(.line) }
.shstrtab 0 : { *(.shstrtab) }
.strtab 0 : { *(.strtab) }
.symtab 0 : { *(.symtab) }
}
================================================
FILE: .cargo/release.toml
================================================
[target.x86_64-unknown-none]
runner = ["bash", ".cargo/runner_release.sh"]
================================================
FILE: .cargo/runner_debug.sh
================================================
#! /bin/bash
#
# This script will be executed by `cargo run`.
set -xe
LIMINE_GIT_URL="https://github.com/limine-bootloader/limine.git"
# Cargo passes the path to the built executable as the first argument.
KERNEL=$1
# Clone the `limine` repository if we don't have it yet.
if [ ! -d target/limine ]; then
git clone $LIMINE_GIT_URL --depth=1 --branch v3.0-branch-binary target/limine
fi
# Make sure we have an up-to-date version of the bootloader.
cd target/limine
git fetch
make
cd -
# Copy the needed files into an ISO image.
mkdir -p target/iso_root
cp $KERNEL conf/limine.cfg target/limine/limine{.sys,-cd.bin,-cd-efi.bin} target/iso_root
xorriso -as mkisofs \
-b limine-cd.bin \
-no-emul-boot -boot-load-size 4 -boot-info-table \
--efi-boot limine-cd-efi.bin \
-efi-boot-part --efi-boot-image --protective-msdos-label \
target/iso_root -o $KERNEL.iso
# For the image to be bootable on BIOS systems, we must run `limine-deploy` on it.
target/limine/limine-deploy $KERNEL.iso
# Run the created image with QEMU.
# -machine q35 -cpu EPYC
echo "Running in debug mode." >&2
qemu-system-x86_64 \
-machine q35 -cpu EPYC -M smm=off \
-D target/log.txt -d int,guest_errors -no-reboot -no-shutdown \
-s -S \
-serial stdio \
-serial file:target/fb_log.txt \
-m 4G \
-cdrom $KERNEL.iso >&2
================================================
FILE: .cargo/runner_release.sh
================================================
#! /bin/bash
#
# This script will be executed by `cargo run`.
set -xe
LIMINE_GIT_URL="https://github.com/limine-bootloader/limine.git"
# Cargo passes the path to the built executable as the first argument.
KERNEL=$1
# Clone the `limine` repository if we don't have it yet.
if [ ! -d target/limine ]; then
git clone $LIMINE_GIT_URL --depth=1 --branch v3.0-branch-binary target/limine
fi
# Make sure we have an up-to-date version of the bootloader.
cd target/limine
git fetch
make
cd -
# Copy the needed files into an ISO image.
mkdir -p target/iso_root
cp $KERNEL conf/limine.cfg target/limine/limine{.sys,-cd.bin,-cd-efi.bin} target/iso_root
xorriso -as mkisofs \
-b limine-cd.bin \
-no-emul-boot -boot-load-size 4 -boot-info-table \
--efi-boot limine-cd-efi.bin \
-efi-boot-part --efi-boot-image --protective-msdos-label \
target/iso_root -o $KERNEL.iso
# For the image to be bootable on BIOS systems, we must run `limine-deploy` on it.
target/limine/limine-deploy $KERNEL.iso
# Run the created image with QEMU.
# -machine q35 -cpu EPYC
echo "Running in release mode." >&2
qemu-system-x86_64 \
-M smm=off \
-machine q35 -cpu EPYC \
-D target/log.txt -d int,guest_errors -no-reboot -no-shutdown \
-s \
-serial stdio \
-serial file:target/fb_log.txt \
-m 4G \
-cdrom $KERNEL.iso >&2
================================================
FILE: .cargo/x86_64-kados.json
================================================
{
"llvm-target": "x86_64-unknown-none-elf",
"target-endian": "little",
"target-pointer-width": "64",
"target-c-int-width": "32",
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
"arch": "x86_64",
"os": "none",
"env": "",
"vendor": "unknown",
"linker": "rust-lld",
"linker-flavor": "ld.lld",
"pre-link-args": {
"ld.lld": [
"--script=.cargo/linker.ld"
]
},
"features": "-mmx,-sse,+soft-float",
"executables": true,
"relocation-model": "pic",
"code-model": "kernel",
"disable-redzone": true,
"frame-pointer": "always",
"no-default-libraries": true,
"position-independent-executables": false,
"tls-model": "global-dynamic"
}
================================================
FILE: .gitignore
================================================
/target
/initramfs
/initramfs_old
/extern
*.objdump
*.map
strace_vi.txt
kados.map
/extern_old
================================================
FILE: .vscode/launch.json
================================================
{
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "custom",
"name": "Attach to gdbserver",
"initCommands": [
"platform select remote-gdb-server"
],
"targetCreateCommands": [
"target create ${workspaceFolder}/target/iso_root/k4dos"
],
"processCreateCommands": [
"gdb-remote 127.0.0.1:1234"
]
},
]
}
================================================
FILE: .vscode/settings.json
================================================
{
"lldb.displayFormat": "auto",
"lldb.dereferencePointers": true,
"lldb.consoleMode": "commands",
"lldb.showDisassembly": "auto",
"rust-analyzer.check.command": "clippy",
"editor.formatOnSave": true,
"rust-analyzer.cargo.target": "x86_64-unknown-none",
}
================================================
FILE: Cargo.toml
================================================
[package]
name = "k4dos"
version = "0.1.0"
edition = "2024"
[[bin]]
name = "k4dos"
test = false
bench = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
limine = "0.3.1"
volatile = "0.2.6" # DO NOT CHANGE
spin = "0.9.8"
bit_field = "0.10.2"
x86 = "0.52.0"
x86_64 = "0.15.2"
log = "0.4"
pic8259 = "0.11"
bitflags = "2.6.0"
uart_16550 = "0.3.2"
crossbeam-utils = { version = "0.8.20", default-features = false }
atomic_refcell = "0.1.13"
buddy_system_allocator = { version = "0.11.0", features = [] }
pc-keyboard = "0.8.0"
xmas-elf = "0.8"
rustc-demangle = "0.1.24"
arrayvec = { version = "0.7.6", default-features = false }
x2apic = "0.4.3"
elfloader = "0.16.0"
bitvec = { version = "1.0.1", default-features = false }
embedded-graphics = "0.8.1"
smoltcp = { version = "0.12.0", default-features = false, features = [
"alloc",
"proto-ipv4",
"socket",
"socket-raw",
"socket-udp",
"socket-tcp",
"proto-dhcpv4",
"medium-ethernet",
] }
lazy_static = { version = "1.5.0", features = ["spin_no_std"] }
embedded-profiling = { version = "0.3.0", features = ["proc-macros"] }
[profile.release]
debug = 1
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2022 Connor Statham
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# k4dos
K4DOS is a hobby operating system written in Rust. It current supports x86_64 architecture and aims for Linux ABI compatibility (running unmodified Linux programs).
## k4dos running NetHack

## k4dos running FreeDOOM

## k4dos running [RustyRays](https://github.com/clstatham/rustyrays/tree/k4dos_port), my own ray tracer

## Building
I haven't set up a proper build system for this to work on other people's machines yet. Contact me or open a PR if you'd like to help with that.
For now, this repo exists to present the source code to others who might want to learn from it.
## License
MIT licensed (see LICENSE file)
================================================
FILE: build.rs
================================================
use std::{env, error::Error};
fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
// Get the name of the package.
let kernel_name = env::var("CARGO_PKG_NAME")?;
// let status = Command::new("./deps.sh")
// .args(["makeimg"])
// .status()
// .unwrap();
// assert!(status.success());
println!("cargo:rustc-link-arg-bin={kernel_name}=--script=.cargo/linker.ld");
// Add linker args.
println!("cargo:rustc-link-arg-bin={kernel_name}=--gc-sections");
// Have cargo rerun this script if the linker script or CARGO_PKG_ENV changes.
println!("cargo:rerun-if-changed=.cargo/linker.ld");
println!("cargo:rerun-if-env-changed=CARGO_PKG_NAME");
println!("cargo:rerun-if-changed=build.rs");
Ok(())
}
================================================
FILE: conf/grub.cfg
================================================
set timeout=0
set default=0
GRUB_TERMINAL=console
menuentry "K4DOS" {
multiboot2 /boot/k4dos
boot
}
================================================
FILE: conf/limine.cfg
================================================
TIMEOUT=0
VERBOSE=yes
: k4dos
PROTOCOL=limine
KASLR=no
RESOLUTION=640x400x32
KERNEL_PATH=boot:///k4dos
================================================
FILE: deps.sh
================================================
#!/bin/bash
set -e
if [[ -z "$@" ]]; then
echo "Usage: deps.sh [COMMANDS]..."
echo "Available commands:"
echo "download Downloads Busybox"
echo "menuconfig Configures Busybox with menuconfig"
echo "allnoconfig Configures Busybox with allnoconfig"
echo "defconfig Configures Busybox with its default config (currently doesn't build!)"
echo "clean Cleans the output directory"
echo "build Builds Busybox"
echo "makeimg Creates the initramfs image for K4DOS"
echo "kash Builds Kash, the K4DOS shell"
exit
fi
STARTDIR=$(pwd)
mkdir -p extern
cd extern
if [[ $@ =~ "download" ]];
then
echo
echo "!!!IMPORTANT!!!"
echo "If you just want a prebuilt image, go to the following link to download one and put it in a new folder in this directory called initramfs"
echo "The prebuilt image currently contains preconfigured and prebuilt distributions of Busybox, FreeDOOM, NetHack, and RustyRays."
echo "Busybox, FreeDOOM, Doom-Generic, and NetHack are subject to their own copyright and license terms."
echo "https://drive.google.com/file/d/1Yl8Ei1toRCmoHbNVxOxamXrGS_s4xvf6/view"
echo "Press ENTER to continue, or Ctrl-C to cancel."
read
echo "Downloading Busybox."
git clone git://busybox.net/busybox.git
echo "Installing musl with pacman and creating symlinks. (will sudo)"
sudo pacman -S musl
sudo ln -s /usr/bin/ar /usr/bin/musl-ar
sudo ln -s /usr/bin/strip /usr/bin/musl-strip
echo "Now run 'deps.sh menuconfig' and load kados.config, located in the same directory as this script"
fi
BUSYBOXDIR=$STARTDIR/extern/busybox
cd busybox
if [[ $@ =~ "menuconfig" ]];
then
make menuconfig
fi
if [[ $@ =~ "defconfig" ]];
then
make defconfig
fi
if [[ $@ =~ "allnoconfig" ]];
then
make allnoconfig
fi
if [[ $@ =~ "clean" ]];
then
make clean
fi
if [[ $@ =~ "build" ]];
then
time make -j6
make install
fi
if [[ $@ =~ "kash" ]];
then
cd $STARTDIR/userland/kash
cargo build
cd -
fi
if [[ $@ =~ "makeimg" ]];
then
cd $STARTDIR
mkdir -p initramfs/busybox_fs
cd $STARTDIR
cd initramfs/busybox_fs
rm -f ../initramfs_busybox
cp -r $BUSYBOXDIR/_install/* ./
cp -r $BUSYBOXDIR/busybox_unstripped ./bin/busybox
mkdir -p dev
find . | cpio -ov --format=newc > ../initramfs
fi
cd $STARTDIR
echo "Done."
================================================
FILE: kados.config
================================================
#
# Automatically generated make config: don't edit
# Busybox version: 1.37.0.git
# Sun Mar 12 20:07:49 2023
#
CONFIG_HAVE_DOT_CONFIG=y
#
# Settings
#
# CONFIG_DESKTOP is not set
# CONFIG_EXTRA_COMPAT is not set
# CONFIG_FEDORA_COMPAT is not set
# CONFIG_INCLUDE_SUSv2 is not set
# CONFIG_LONG_OPTS is not set
# CONFIG_SHOW_USAGE is not set
# CONFIG_FEATURE_VERBOSE_USAGE is not set
# CONFIG_FEATURE_COMPRESS_USAGE is not set
CONFIG_LFS=y
# CONFIG_PAM is not set
# CONFIG_FEATURE_DEVPTS is not set
# CONFIG_FEATURE_UTMP is not set
# CONFIG_FEATURE_WTMP is not set
# CONFIG_FEATURE_PIDFILE is not set
CONFIG_PID_FILE_PATH=""
# CONFIG_BUSYBOX is not set
# CONFIG_FEATURE_SHOW_SCRIPT is not set
# CONFIG_FEATURE_INSTALLER is not set
CONFIG_INSTALL_NO_USR=y
# CONFIG_FEATURE_SUID is not set
# CONFIG_FEATURE_SUID_CONFIG is not set
# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set
# CONFIG_FEATURE_PREFER_APPLETS is not set
CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe"
# CONFIG_SELINUX is not set
# CONFIG_FEATURE_CLEAN_UP is not set
# CONFIG_FEATURE_SYSLOG_INFO is not set
# CONFIG_FEATURE_SYSLOG is not set
#
# Build Options
#
CONFIG_STATIC=y
# CONFIG_PIE is not set
# CONFIG_NOMMU is not set
# CONFIG_BUILD_LIBBUSYBOX is not set
# CONFIG_FEATURE_LIBBUSYBOX_STATIC is not set
# CONFIG_FEATURE_INDIVIDUAL is not set
# CONFIG_FEATURE_SHARED_BUSYBOX is not set
CONFIG_CROSS_COMPILER_PREFIX="/usr/bin/musl-"
CONFIG_SYSROOT=""
CONFIG_EXTRA_CFLAGS=""
CONFIG_EXTRA_LDFLAGS=""
CONFIG_EXTRA_LDLIBS=""
# CONFIG_USE_PORTABLE_CODE is not set
# CONFIG_STACK_OPTIMIZATION_386 is not set
CONFIG_STATIC_LIBGCC=y
#
# Installation Options ("make install" behavior)
#
CONFIG_INSTALL_APPLET_SYMLINKS=y
# CONFIG_INSTALL_APPLET_HARDLINKS is not set
# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set
# CONFIG_INSTALL_APPLET_DONT is not set
# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set
# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set
# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set
CONFIG_PREFIX="./_install"
#
# Debugging Options
#
CONFIG_DEBUG=y
CONFIG_DEBUG_PESSIMIZE=y
# CONFIG_DEBUG_SANITIZE is not set
# CONFIG_UNIT_TEST is not set
# CONFIG_WERROR is not set
# CONFIG_WARN_SIMPLE_MSG is not set
CONFIG_NO_DEBUG_LIB=y
# CONFIG_DMALLOC is not set
# CONFIG_EFENCE is not set
#
# Library Tuning
#
# CONFIG_FEATURE_USE_BSS_TAIL is not set
# CONFIG_FLOAT_DURATION is not set
# CONFIG_FEATURE_RTMINMAX is not set
# CONFIG_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS is not set
CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
CONFIG_PASSWORD_MINLEN=6
CONFIG_MD5_SMALL=1
CONFIG_SHA1_SMALL=3
# CONFIG_SHA1_HWACCEL is not set
# CONFIG_SHA256_HWACCEL is not set
CONFIG_SHA3_SMALL=1
# CONFIG_FEATURE_NON_POSIX_CP is not set
# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set
# CONFIG_FEATURE_USE_SENDFILE is not set
CONFIG_FEATURE_COPYBUF_KB=4
# CONFIG_MONOTONIC_SYSCALL is not set
# CONFIG_IOCTL_HEX2STR_ERROR is not set
# CONFIG_FEATURE_EDITING is not set
CONFIG_FEATURE_EDITING_MAX_LEN=0
# CONFIG_FEATURE_EDITING_VI is not set
CONFIG_FEATURE_EDITING_HISTORY=0
# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set
# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set
# CONFIG_FEATURE_REVERSE_SEARCH is not set
# CONFIG_FEATURE_TAB_COMPLETION is not set
# CONFIG_FEATURE_USERNAME_COMPLETION is not set
# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set
# CONFIG_FEATURE_EDITING_WINCH is not set
# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set
# CONFIG_LOCALE_SUPPORT is not set
# CONFIG_UNICODE_SUPPORT is not set
# CONFIG_UNICODE_USING_LOCALE is not set
# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set
CONFIG_SUBST_WCHAR=0
CONFIG_LAST_SUPPORTED_WCHAR=0
# CONFIG_UNICODE_COMBINING_WCHARS is not set
# CONFIG_UNICODE_WIDE_WCHARS is not set
# CONFIG_UNICODE_BIDI_SUPPORT is not set
# CONFIG_UNICODE_NEUTRAL_TABLE is not set
# CONFIG_UNICODE_PRESERVE_BROKEN is not set
# CONFIG_LOOP_CONFIGURE is not set
# CONFIG_NO_LOOP_CONFIGURE is not set
CONFIG_TRY_LOOP_CONFIGURE=y
#
# Applets
#
#
# Archival Utilities
#
# CONFIG_FEATURE_SEAMLESS_XZ is not set
# CONFIG_FEATURE_SEAMLESS_LZMA is not set
# CONFIG_FEATURE_SEAMLESS_BZ2 is not set
# CONFIG_FEATURE_SEAMLESS_GZ is not set
# CONFIG_FEATURE_SEAMLESS_Z is not set
# CONFIG_AR is not set
# CONFIG_FEATURE_AR_LONG_FILENAMES is not set
# CONFIG_FEATURE_AR_CREATE is not set
# CONFIG_UNCOMPRESS is not set
# CONFIG_GUNZIP is not set
# CONFIG_ZCAT is not set
# CONFIG_FEATURE_GUNZIP_LONG_OPTIONS is not set
# CONFIG_BUNZIP2 is not set
# CONFIG_BZCAT is not set
# CONFIG_UNLZMA is not set
# CONFIG_LZCAT is not set
# CONFIG_LZMA is not set
# CONFIG_UNXZ is not set
# CONFIG_XZCAT is not set
# CONFIG_XZ is not set
# CONFIG_BZIP2 is not set
CONFIG_BZIP2_SMALL=0
# CONFIG_FEATURE_BZIP2_DECOMPRESS is not set
# CONFIG_CPIO is not set
# CONFIG_FEATURE_CPIO_O is not set
# CONFIG_FEATURE_CPIO_P is not set
# CONFIG_FEATURE_CPIO_IGNORE_DEVNO is not set
# CONFIG_FEATURE_CPIO_RENUMBER_INODES is not set
# CONFIG_DPKG is not set
# CONFIG_DPKG_DEB is not set
# CONFIG_GZIP is not set
# CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set
CONFIG_GZIP_FAST=0
# CONFIG_FEATURE_GZIP_LEVELS is not set
# CONFIG_FEATURE_GZIP_DECOMPRESS is not set
# CONFIG_LZOP is not set
# CONFIG_UNLZOP is not set
# CONFIG_LZOPCAT is not set
# CONFIG_LZOP_COMPR_HIGH is not set
# CONFIG_RPM is not set
# CONFIG_RPM2CPIO is not set
# CONFIG_TAR is not set
# CONFIG_FEATURE_TAR_LONG_OPTIONS is not set
# CONFIG_FEATURE_TAR_CREATE is not set
# CONFIG_FEATURE_TAR_AUTODETECT is not set
# CONFIG_FEATURE_TAR_FROM is not set
# CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY is not set
# CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set
# CONFIG_FEATURE_TAR_GNU_EXTENSIONS is not set
# CONFIG_FEATURE_TAR_TO_COMMAND is not set
# CONFIG_FEATURE_TAR_UNAME_GNAME is not set
# CONFIG_FEATURE_TAR_NOPRESERVE_TIME is not set
# CONFIG_FEATURE_TAR_SELINUX is not set
# CONFIG_UNZIP is not set
# CONFIG_FEATURE_UNZIP_CDF is not set
# CONFIG_FEATURE_UNZIP_BZIP2 is not set
# CONFIG_FEATURE_UNZIP_LZMA is not set
# CONFIG_FEATURE_UNZIP_XZ is not set
# CONFIG_FEATURE_LZMA_FAST is not set
#
# Coreutils
#
# CONFIG_FEATURE_VERBOSE is not set
#
# Common options for date and touch
#
# CONFIG_FEATURE_TIMEZONE is not set
#
# Common options for cp and mv
#
CONFIG_FEATURE_PRESERVE_HARDLINKS=y
#
# Common options for df, du, ls
#
CONFIG_FEATURE_HUMAN_READABLE=y
# CONFIG_BASENAME is not set
CONFIG_CAT=y
CONFIG_FEATURE_CATN=y
CONFIG_FEATURE_CATV=y
# CONFIG_CHGRP is not set
# CONFIG_CHMOD is not set
# CONFIG_CHOWN is not set
# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set
# CONFIG_CHROOT is not set
# CONFIG_CKSUM is not set
# CONFIG_CRC32 is not set
# CONFIG_COMM is not set
CONFIG_CP=y
# CONFIG_FEATURE_CP_LONG_OPTIONS is not set
# CONFIG_FEATURE_CP_REFLINK is not set
# CONFIG_CUT is not set
# CONFIG_FEATURE_CUT_REGEX is not set
# CONFIG_DATE is not set
# CONFIG_FEATURE_DATE_ISOFMT is not set
# CONFIG_FEATURE_DATE_NANO is not set
# CONFIG_FEATURE_DATE_COMPAT is not set
# CONFIG_DD is not set
# CONFIG_FEATURE_DD_SIGNAL_HANDLING is not set
# CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set
# CONFIG_FEATURE_DD_IBS_OBS is not set
# CONFIG_FEATURE_DD_STATUS is not set
# CONFIG_DF is not set
# CONFIG_FEATURE_DF_FANCY is not set
# CONFIG_FEATURE_SKIP_ROOTFS is not set
# CONFIG_DIRNAME is not set
# CONFIG_DOS2UNIX is not set
# CONFIG_UNIX2DOS is not set
# CONFIG_DU is not set
# CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K is not set
CONFIG_ECHO=y
CONFIG_FEATURE_FANCY_ECHO=y
# CONFIG_ENV is not set
# CONFIG_EXPAND is not set
# CONFIG_UNEXPAND is not set
# CONFIG_EXPR is not set
# CONFIG_EXPR_MATH_SUPPORT_64 is not set
# CONFIG_FACTOR is not set
# CONFIG_FALSE is not set
# CONFIG_FOLD is not set
# CONFIG_HEAD is not set
# CONFIG_FEATURE_FANCY_HEAD is not set
# CONFIG_HOSTID is not set
# CONFIG_ID is not set
# CONFIG_GROUPS is not set
# CONFIG_INSTALL is not set
# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set
# CONFIG_LINK is not set
CONFIG_LN=y
# CONFIG_LOGNAME is not set
CONFIG_LS=y
CONFIG_FEATURE_LS_FILETYPES=y
CONFIG_FEATURE_LS_FOLLOWLINKS=y
CONFIG_FEATURE_LS_RECURSIVE=y
CONFIG_FEATURE_LS_WIDTH=y
CONFIG_FEATURE_LS_SORTFILES=y
# CONFIG_FEATURE_LS_TIMESTAMPS is not set
# CONFIG_FEATURE_LS_USERNAME is not set
# CONFIG_FEATURE_LS_COLOR is not set
# CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set
# CONFIG_MD5SUM is not set
# CONFIG_SHA1SUM is not set
# CONFIG_SHA256SUM is not set
# CONFIG_SHA512SUM is not set
# CONFIG_SHA3SUM is not set
# CONFIG_FEATURE_MD5_SHA1_SUM_CHECK is not set
CONFIG_MKDIR=y
# CONFIG_MKFIFO is not set
# CONFIG_MKNOD is not set
# CONFIG_MKTEMP is not set
CONFIG_MV=y
# CONFIG_NICE is not set
# CONFIG_NL is not set
# CONFIG_NOHUP is not set
# CONFIG_NPROC is not set
# CONFIG_OD is not set
# CONFIG_PASTE is not set
# CONFIG_PRINTENV is not set
# CONFIG_PRINTF is not set
CONFIG_PWD=y
# CONFIG_READLINK is not set
# CONFIG_FEATURE_READLINK_FOLLOW is not set
# CONFIG_REALPATH is not set
CONFIG_RM=y
CONFIG_RMDIR=y
# CONFIG_SEQ is not set
# CONFIG_SHRED is not set
# CONFIG_SHUF is not set
# CONFIG_SLEEP is not set
# CONFIG_FEATURE_FANCY_SLEEP is not set
# CONFIG_SORT is not set
# CONFIG_FEATURE_SORT_BIG is not set
# CONFIG_FEATURE_SORT_OPTIMIZE_MEMORY is not set
# CONFIG_SPLIT is not set
# CONFIG_FEATURE_SPLIT_FANCY is not set
CONFIG_STAT=y
# CONFIG_FEATURE_STAT_FORMAT is not set
# CONFIG_FEATURE_STAT_FILESYSTEM is not set
# CONFIG_STTY is not set
# CONFIG_SUM is not set
# CONFIG_SYNC is not set
# CONFIG_FEATURE_SYNC_FANCY is not set
# CONFIG_FSYNC is not set
# CONFIG_TAC is not set
# CONFIG_TAIL is not set
# CONFIG_FEATURE_FANCY_TAIL is not set
# CONFIG_TEE is not set
# CONFIG_FEATURE_TEE_USE_BLOCK_IO is not set
# CONFIG_TEST is not set
# CONFIG_TEST1 is not set
# CONFIG_TEST2 is not set
# CONFIG_FEATURE_TEST_64 is not set
# CONFIG_TIMEOUT is not set
# CONFIG_TOUCH is not set
# CONFIG_FEATURE_TOUCH_SUSV3 is not set
# CONFIG_TR is not set
# CONFIG_FEATURE_TR_CLASSES is not set
# CONFIG_FEATURE_TR_EQUIV is not set
# CONFIG_TRUE is not set
# CONFIG_TRUNCATE is not set
# CONFIG_TSORT is not set
# CONFIG_TTY is not set
# CONFIG_UNAME is not set
CONFIG_UNAME_OSNAME=""
# CONFIG_BB_ARCH is not set
# CONFIG_UNIQ is not set
# CONFIG_UNLINK is not set
# CONFIG_USLEEP is not set
# CONFIG_UUDECODE is not set
# CONFIG_BASE32 is not set
# CONFIG_BASE64 is not set
# CONFIG_UUENCODE is not set
# CONFIG_WC is not set
# CONFIG_FEATURE_WC_LARGE is not set
# CONFIG_WHO is not set
# CONFIG_W is not set
# CONFIG_USERS is not set
# CONFIG_WHOAMI is not set
# CONFIG_YES is not set
#
# Console Utilities
#
# CONFIG_CHVT is not set
# CONFIG_CLEAR is not set
# CONFIG_DEALLOCVT is not set
# CONFIG_DUMPKMAP is not set
# CONFIG_FGCONSOLE is not set
# CONFIG_KBD_MODE is not set
# CONFIG_LOADFONT is not set
# CONFIG_SETFONT is not set
# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set
CONFIG_DEFAULT_SETFONT_DIR=""
# CONFIG_FEATURE_LOADFONT_PSF2 is not set
# CONFIG_FEATURE_LOADFONT_RAW is not set
# CONFIG_LOADKMAP is not set
# CONFIG_OPENVT is not set
# CONFIG_RESET is not set
# CONFIG_RESIZE is not set
# CONFIG_FEATURE_RESIZE_PRINT is not set
# CONFIG_SETCONSOLE is not set
# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set
# CONFIG_SETKEYCODES is not set
# CONFIG_SETLOGCONS is not set
# CONFIG_SHOWKEY is not set
#
# Debian Utilities
#
# CONFIG_PIPE_PROGRESS is not set
# CONFIG_RUN_PARTS is not set
# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set
# CONFIG_FEATURE_RUN_PARTS_FANCY is not set
# CONFIG_START_STOP_DAEMON is not set
# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set
# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set
# CONFIG_WHICH is not set
#
# klibc-utils
#
# CONFIG_MINIPS is not set
# CONFIG_NUKE is not set
# CONFIG_RESUME is not set
# CONFIG_RUN_INIT is not set
#
# Editors
#
# CONFIG_AWK is not set
# CONFIG_FEATURE_AWK_LIBM is not set
# CONFIG_FEATURE_AWK_GNU_EXTENSIONS is not set
# CONFIG_CMP is not set
# CONFIG_DIFF is not set
# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set
# CONFIG_FEATURE_DIFF_DIR is not set
# CONFIG_ED is not set
# CONFIG_PATCH is not set
# CONFIG_SED is not set
# CONFIG_VI is not set
CONFIG_FEATURE_VI_MAX_LEN=0
# CONFIG_FEATURE_VI_8BIT is not set
# CONFIG_FEATURE_VI_COLON is not set
# CONFIG_FEATURE_VI_COLON_EXPAND is not set
# CONFIG_FEATURE_VI_YANKMARK is not set
# CONFIG_FEATURE_VI_SEARCH is not set
# CONFIG_FEATURE_VI_REGEX_SEARCH is not set
# CONFIG_FEATURE_VI_USE_SIGNALS is not set
# CONFIG_FEATURE_VI_DOT_CMD is not set
# CONFIG_FEATURE_VI_READONLY is not set
# CONFIG_FEATURE_VI_SETOPTS is not set
# CONFIG_FEATURE_VI_SET is not set
# CONFIG_FEATURE_VI_WIN_RESIZE is not set
# CONFIG_FEATURE_VI_ASK_TERMINAL is not set
# CONFIG_FEATURE_VI_UNDO is not set
# CONFIG_FEATURE_VI_UNDO_QUEUE is not set
CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=0
# CONFIG_FEATURE_VI_VERBOSE_STATUS is not set
# CONFIG_FEATURE_ALLOW_EXEC is not set
#
# Finding Utilities
#
# CONFIG_FIND is not set
# CONFIG_FEATURE_FIND_PRINT0 is not set
# CONFIG_FEATURE_FIND_MTIME is not set
# CONFIG_FEATURE_FIND_ATIME is not set
# CONFIG_FEATURE_FIND_CTIME is not set
# CONFIG_FEATURE_FIND_MMIN is not set
# CONFIG_FEATURE_FIND_AMIN is not set
# CONFIG_FEATURE_FIND_CMIN is not set
# CONFIG_FEATURE_FIND_PERM is not set
# CONFIG_FEATURE_FIND_TYPE is not set
# CONFIG_FEATURE_FIND_EXECUTABLE is not set
# CONFIG_FEATURE_FIND_XDEV is not set
# CONFIG_FEATURE_FIND_MAXDEPTH is not set
# CONFIG_FEATURE_FIND_NEWER is not set
# CONFIG_FEATURE_FIND_INUM is not set
# CONFIG_FEATURE_FIND_SAMEFILE is not set
# CONFIG_FEATURE_FIND_EXEC is not set
# CONFIG_FEATURE_FIND_EXEC_PLUS is not set
# CONFIG_FEATURE_FIND_USER is not set
# CONFIG_FEATURE_FIND_GROUP is not set
# CONFIG_FEATURE_FIND_NOT is not set
# CONFIG_FEATURE_FIND_DEPTH is not set
# CONFIG_FEATURE_FIND_PAREN is not set
# CONFIG_FEATURE_FIND_SIZE is not set
# CONFIG_FEATURE_FIND_PRUNE is not set
# CONFIG_FEATURE_FIND_QUIT is not set
# CONFIG_FEATURE_FIND_DELETE is not set
# CONFIG_FEATURE_FIND_EMPTY is not set
# CONFIG_FEATURE_FIND_PATH is not set
# CONFIG_FEATURE_FIND_REGEX is not set
# CONFIG_FEATURE_FIND_CONTEXT is not set
# CONFIG_FEATURE_FIND_LINKS is not set
# CONFIG_GREP is not set
# CONFIG_EGREP is not set
# CONFIG_FGREP is not set
# CONFIG_FEATURE_GREP_CONTEXT is not set
# CONFIG_XARGS is not set
# CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION is not set
# CONFIG_FEATURE_XARGS_SUPPORT_QUOTES is not set
# CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT is not set
# CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM is not set
# CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR is not set
# CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL is not set
# CONFIG_FEATURE_XARGS_SUPPORT_ARGS_FILE is not set
#
# Init Utilities
#
# CONFIG_BOOTCHARTD is not set
# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set
# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set
# CONFIG_HALT is not set
# CONFIG_POWEROFF is not set
# CONFIG_REBOOT is not set
# CONFIG_FEATURE_WAIT_FOR_INIT is not set
# CONFIG_FEATURE_CALL_TELINIT is not set
CONFIG_TELINIT_PATH=""
# CONFIG_INIT is not set
# CONFIG_LINUXRC is not set
# CONFIG_FEATURE_USE_INITTAB is not set
# CONFIG_FEATURE_KILL_REMOVED is not set
CONFIG_FEATURE_KILL_DELAY=0
# CONFIG_FEATURE_INIT_SCTTY is not set
# CONFIG_FEATURE_INIT_SYSLOG is not set
# CONFIG_FEATURE_INIT_QUIET is not set
# CONFIG_FEATURE_INIT_COREDUMPS is not set
CONFIG_INIT_TERMINAL_TYPE=""
# CONFIG_FEATURE_INIT_MODIFY_CMDLINE is not set
#
# Login/Password Management Utilities
#
# CONFIG_FEATURE_SHADOWPASSWDS is not set
# CONFIG_USE_BB_PWD_GRP is not set
# CONFIG_USE_BB_SHADOW is not set
# CONFIG_USE_BB_CRYPT is not set
# CONFIG_USE_BB_CRYPT_SHA is not set
# CONFIG_ADD_SHELL is not set
# CONFIG_REMOVE_SHELL is not set
# CONFIG_ADDGROUP is not set
# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set
# CONFIG_ADDUSER is not set
# CONFIG_FEATURE_CHECK_NAMES is not set
CONFIG_LAST_ID=0
CONFIG_FIRST_SYSTEM_ID=0
CONFIG_LAST_SYSTEM_ID=0
# CONFIG_CHPASSWD is not set
CONFIG_FEATURE_DEFAULT_PASSWD_ALGO=""
# CONFIG_CRYPTPW is not set
# CONFIG_MKPASSWD is not set
# CONFIG_DELUSER is not set
# CONFIG_DELGROUP is not set
# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set
# CONFIG_GETTY is not set
# CONFIG_LOGIN is not set
# CONFIG_LOGIN_SESSION_AS_CHILD is not set
# CONFIG_LOGIN_SCRIPTS is not set
# CONFIG_FEATURE_NOLOGIN is not set
# CONFIG_FEATURE_SECURETTY is not set
# CONFIG_PASSWD is not set
# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set
# CONFIG_SU is not set
# CONFIG_FEATURE_SU_SYSLOG is not set
# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set
# CONFIG_FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY is not set
# CONFIG_SULOGIN is not set
# CONFIG_VLOCK is not set
#
# Linux Ext2 FS Progs
#
# CONFIG_CHATTR is not set
# CONFIG_FSCK is not set
# CONFIG_LSATTR is not set
# CONFIG_TUNE2FS is not set
#
# Linux Module Utilities
#
# CONFIG_MODPROBE_SMALL is not set
# CONFIG_DEPMOD is not set
# CONFIG_INSMOD is not set
# CONFIG_LSMOD is not set
# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set
# CONFIG_MODINFO is not set
# CONFIG_MODPROBE is not set
# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set
# CONFIG_RMMOD is not set
#
# Options common to multiple modutils
#
# CONFIG_FEATURE_CMDLINE_MODULE_OPTIONS is not set
# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set
# CONFIG_FEATURE_2_4_MODULES is not set
# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set
# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set
# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set
# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set
# CONFIG_FEATURE_MODUTILS_ALIAS is not set
# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set
CONFIG_DEFAULT_MODULES_DIR=""
CONFIG_DEFAULT_DEPMOD_FILE=""
#
# Linux System Utilities
#
# CONFIG_ACPID is not set
# CONFIG_FEATURE_ACPID_COMPAT is not set
# CONFIG_BLKDISCARD is not set
# CONFIG_BLKID is not set
# CONFIG_FEATURE_BLKID_TYPE is not set
# CONFIG_BLOCKDEV is not set
# CONFIG_CAL is not set
# CONFIG_CHRT is not set
# CONFIG_DMESG is not set
# CONFIG_FEATURE_DMESG_PRETTY is not set
# CONFIG_EJECT is not set
# CONFIG_FEATURE_EJECT_SCSI is not set
# CONFIG_FALLOCATE is not set
# CONFIG_FATATTR is not set
# CONFIG_FBSET is not set
# CONFIG_FEATURE_FBSET_FANCY is not set
# CONFIG_FEATURE_FBSET_READMODE is not set
# CONFIG_FDFORMAT is not set
# CONFIG_FDISK is not set
# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set
# CONFIG_FEATURE_FDISK_WRITABLE is not set
# CONFIG_FEATURE_AIX_LABEL is not set
# CONFIG_FEATURE_SGI_LABEL is not set
# CONFIG_FEATURE_SUN_LABEL is not set
# CONFIG_FEATURE_OSF_LABEL is not set
# CONFIG_FEATURE_GPT_LABEL is not set
# CONFIG_FEATURE_FDISK_ADVANCED is not set
# CONFIG_FINDFS is not set
# CONFIG_FLOCK is not set
# CONFIG_FDFLUSH is not set
# CONFIG_FREERAMDISK is not set
# CONFIG_FSCK_MINIX is not set
# CONFIG_FSFREEZE is not set
# CONFIG_FSTRIM is not set
# CONFIG_GETOPT is not set
# CONFIG_FEATURE_GETOPT_LONG is not set
# CONFIG_HEXDUMP is not set
# CONFIG_HD is not set
# CONFIG_XXD is not set
# CONFIG_HWCLOCK is not set
# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set
# CONFIG_IONICE is not set
# CONFIG_IPCRM is not set
# CONFIG_IPCS is not set
# CONFIG_LAST is not set
# CONFIG_FEATURE_LAST_FANCY is not set
# CONFIG_LOSETUP is not set
# CONFIG_LSPCI is not set
# CONFIG_LSUSB is not set
# CONFIG_MDEV is not set
# CONFIG_FEATURE_MDEV_CONF is not set
# CONFIG_FEATURE_MDEV_RENAME is not set
# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set
# CONFIG_FEATURE_MDEV_EXEC is not set
# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set
# CONFIG_FEATURE_MDEV_DAEMON is not set
# CONFIG_MESG is not set
# CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP is not set
# CONFIG_MKE2FS is not set
# CONFIG_MKFS_EXT2 is not set
# CONFIG_MKFS_MINIX is not set
# CONFIG_FEATURE_MINIX2 is not set
# CONFIG_MKFS_REISER is not set
# CONFIG_MKDOSFS is not set
# CONFIG_MKFS_VFAT is not set
# CONFIG_MKSWAP is not set
# CONFIG_FEATURE_MKSWAP_UUID is not set
# CONFIG_MORE is not set
# CONFIG_MOUNT is not set
# CONFIG_FEATURE_MOUNT_FAKE is not set
# CONFIG_FEATURE_MOUNT_VERBOSE is not set
# CONFIG_FEATURE_MOUNT_HELPERS is not set
# CONFIG_FEATURE_MOUNT_LABEL is not set
# CONFIG_FEATURE_MOUNT_NFS is not set
# CONFIG_FEATURE_MOUNT_CIFS is not set
# CONFIG_FEATURE_MOUNT_FLAGS is not set
# CONFIG_FEATURE_MOUNT_FSTAB is not set
# CONFIG_FEATURE_MOUNT_OTHERTAB is not set
# CONFIG_MOUNTPOINT is not set
CONFIG_NOLOGIN=y
# CONFIG_NOLOGIN_DEPENDENCIES is not set
# CONFIG_NSENTER is not set
# CONFIG_PIVOT_ROOT is not set
# CONFIG_RDATE is not set
# CONFIG_RDEV is not set
# CONFIG_READPROFILE is not set
# CONFIG_RENICE is not set
# CONFIG_REV is not set
# CONFIG_RTCWAKE is not set
# CONFIG_SCRIPT is not set
# CONFIG_SCRIPTREPLAY is not set
# CONFIG_SETARCH is not set
# CONFIG_LINUX32 is not set
# CONFIG_LINUX64 is not set
# CONFIG_SETPRIV is not set
# CONFIG_FEATURE_SETPRIV_DUMP is not set
# CONFIG_FEATURE_SETPRIV_CAPABILITIES is not set
# CONFIG_FEATURE_SETPRIV_CAPABILITY_NAMES is not set
# CONFIG_SETSID is not set
# CONFIG_SWAPON is not set
# CONFIG_FEATURE_SWAPON_DISCARD is not set
# CONFIG_FEATURE_SWAPON_PRI is not set
# CONFIG_SWAPOFF is not set
# CONFIG_FEATURE_SWAPONOFF_LABEL is not set
# CONFIG_SWITCH_ROOT is not set
# CONFIG_TASKSET is not set
# CONFIG_FEATURE_TASKSET_FANCY is not set
# CONFIG_FEATURE_TASKSET_CPULIST is not set
# CONFIG_UEVENT is not set
# CONFIG_UMOUNT is not set
# CONFIG_FEATURE_UMOUNT_ALL is not set
# CONFIG_UNSHARE is not set
# CONFIG_WALL is not set
# CONFIG_FEATURE_MOUNT_LOOP is not set
# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set
# CONFIG_FEATURE_MTAB_SUPPORT is not set
# CONFIG_VOLUMEID is not set
# CONFIG_FEATURE_VOLUMEID_BCACHE is not set
# CONFIG_FEATURE_VOLUMEID_BTRFS is not set
# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set
# CONFIG_FEATURE_VOLUMEID_EROFS is not set
# CONFIG_FEATURE_VOLUMEID_EXFAT is not set
# CONFIG_FEATURE_VOLUMEID_EXT is not set
# CONFIG_FEATURE_VOLUMEID_F2FS is not set
# CONFIG_FEATURE_VOLUMEID_FAT is not set
# CONFIG_FEATURE_VOLUMEID_HFS is not set
# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set
# CONFIG_FEATURE_VOLUMEID_JFS is not set
# CONFIG_FEATURE_VOLUMEID_LFS is not set
# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set
# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set
# CONFIG_FEATURE_VOLUMEID_LUKS is not set
# CONFIG_FEATURE_VOLUMEID_MINIX is not set
# CONFIG_FEATURE_VOLUMEID_NILFS is not set
# CONFIG_FEATURE_VOLUMEID_NTFS is not set
# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set
# CONFIG_FEATURE_VOLUMEID_REISERFS is not set
# CONFIG_FEATURE_VOLUMEID_ROMFS is not set
# CONFIG_FEATURE_VOLUMEID_SQUASHFS is not set
# CONFIG_FEATURE_VOLUMEID_SYSV is not set
# CONFIG_FEATURE_VOLUMEID_UBIFS is not set
# CONFIG_FEATURE_VOLUMEID_UDF is not set
# CONFIG_FEATURE_VOLUMEID_XFS is not set
#
# Miscellaneous Utilities
#
# CONFIG_ADJTIMEX is not set
# CONFIG_ASCII is not set
# CONFIG_BBCONFIG is not set
# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set
# CONFIG_BC is not set
# CONFIG_DC is not set
# CONFIG_FEATURE_DC_BIG is not set
# CONFIG_FEATURE_DC_LIBM is not set
# CONFIG_FEATURE_BC_INTERACTIVE is not set
# CONFIG_FEATURE_BC_LONG_OPTIONS is not set
# CONFIG_BEEP is not set
CONFIG_FEATURE_BEEP_FREQ=0
CONFIG_FEATURE_BEEP_LENGTH_MS=0
# CONFIG_CHAT is not set
# CONFIG_FEATURE_CHAT_NOFAIL is not set
# CONFIG_FEATURE_CHAT_TTY_HIFI is not set
# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set
# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set
# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set
# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set
# CONFIG_FEATURE_CHAT_CLR_ABORT is not set
# CONFIG_CONSPY is not set
# CONFIG_CROND is not set
# CONFIG_FEATURE_CROND_D is not set
# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set
# CONFIG_FEATURE_CROND_SPECIAL_TIMES is not set
CONFIG_FEATURE_CROND_DIR=""
# CONFIG_CRONTAB is not set
# CONFIG_DEVFSD is not set
# CONFIG_DEVFSD_MODLOAD is not set
# CONFIG_DEVFSD_FG_NP is not set
# CONFIG_DEVFSD_VERBOSE is not set
# CONFIG_FEATURE_DEVFS is not set
# CONFIG_DEVMEM is not set
# CONFIG_FBSPLASH is not set
# CONFIG_FLASH_ERASEALL is not set
# CONFIG_FLASH_LOCK is not set
# CONFIG_FLASH_UNLOCK is not set
# CONFIG_FLASHCP is not set
# CONFIG_HDPARM is not set
# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set
# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set
# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set
# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set
# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set
# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set
# CONFIG_HEXEDIT is not set
# CONFIG_I2CGET is not set
# CONFIG_I2CSET is not set
# CONFIG_I2CDUMP is not set
# CONFIG_I2CDETECT is not set
# CONFIG_I2CTRANSFER is not set
# CONFIG_INOTIFYD is not set
# CONFIG_LESS is not set
CONFIG_FEATURE_LESS_MAXLINES=0
# CONFIG_FEATURE_LESS_BRACKETS is not set
# CONFIG_FEATURE_LESS_FLAGS is not set
# CONFIG_FEATURE_LESS_TRUNCATE is not set
# CONFIG_FEATURE_LESS_MARKS is not set
# CONFIG_FEATURE_LESS_REGEXP is not set
# CONFIG_FEATURE_LESS_WINCH is not set
# CONFIG_FEATURE_LESS_ASK_TERMINAL is not set
# CONFIG_FEATURE_LESS_DASHCMD is not set
# CONFIG_FEATURE_LESS_LINENUMS is not set
# CONFIG_FEATURE_LESS_RAW is not set
# CONFIG_FEATURE_LESS_ENV is not set
# CONFIG_LSSCSI is not set
# CONFIG_MAKEDEVS is not set
# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
# CONFIG_FEATURE_MAKEDEVS_TABLE is not set
# CONFIG_MAN is not set
# CONFIG_MICROCOM is not set
CONFIG_MIM=y
# CONFIG_MT is not set
# CONFIG_NANDWRITE is not set
# CONFIG_NANDDUMP is not set
# CONFIG_PARTPROBE is not set
# CONFIG_RAIDAUTORUN is not set
CONFIG_READAHEAD=y
# CONFIG_RFKILL is not set
# CONFIG_RUNLEVEL is not set
# CONFIG_RX is not set
# CONFIG_SEEDRNG is not set
# CONFIG_SETFATTR is not set
# CONFIG_SETSERIAL is not set
# CONFIG_STRINGS is not set
# CONFIG_TIME is not set
# CONFIG_TREE is not set
# CONFIG_TS is not set
# CONFIG_TTYSIZE is not set
# CONFIG_UBIATTACH is not set
# CONFIG_UBIDETACH is not set
# CONFIG_UBIMKVOL is not set
# CONFIG_UBIRMVOL is not set
# CONFIG_UBIRSVOL is not set
# CONFIG_UBIUPDATEVOL is not set
# CONFIG_UBIRENAME is not set
# CONFIG_VOLNAME is not set
# CONFIG_WATCHDOG is not set
# CONFIG_FEATURE_WATCHDOG_OPEN_TWICE is not set
#
# Networking Utilities
#
# CONFIG_FEATURE_IPV6 is not set
# CONFIG_FEATURE_UNIX_LOCAL is not set
# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set
# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set
# CONFIG_FEATURE_ETC_NETWORKS is not set
# CONFIG_FEATURE_ETC_SERVICES is not set
# CONFIG_FEATURE_HWIB is not set
# CONFIG_FEATURE_TLS_SHA1 is not set
# CONFIG_ARP is not set
# CONFIG_ARPING is not set
# CONFIG_BRCTL is not set
# CONFIG_FEATURE_BRCTL_FANCY is not set
# CONFIG_FEATURE_BRCTL_SHOW is not set
# CONFIG_DNSD is not set
# CONFIG_ETHER_WAKE is not set
# CONFIG_FTPD is not set
# CONFIG_FEATURE_FTPD_WRITE is not set
# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set
# CONFIG_FEATURE_FTPD_AUTHENTICATION is not set
# CONFIG_FTPGET is not set
# CONFIG_FTPPUT is not set
# CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set
# CONFIG_HOSTNAME is not set
# CONFIG_DNSDOMAINNAME is not set
# CONFIG_HTTPD is not set
CONFIG_FEATURE_HTTPD_PORT_DEFAULT=0
# CONFIG_FEATURE_HTTPD_RANGES is not set
# CONFIG_FEATURE_HTTPD_SETUID is not set
# CONFIG_FEATURE_HTTPD_BASIC_AUTH is not set
# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set
# CONFIG_FEATURE_HTTPD_CGI is not set
# CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR is not set
# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set
# CONFIG_FEATURE_HTTPD_ENCODE_URL_STR is not set
# CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set
# CONFIG_FEATURE_HTTPD_PROXY is not set
# CONFIG_FEATURE_HTTPD_GZIP is not set
# CONFIG_FEATURE_HTTPD_ETAG is not set
# CONFIG_FEATURE_HTTPD_LAST_MODIFIED is not set
# CONFIG_FEATURE_HTTPD_DATE is not set
# CONFIG_FEATURE_HTTPD_ACL_IP is not set
# CONFIG_IFCONFIG is not set
# CONFIG_FEATURE_IFCONFIG_STATUS is not set
# CONFIG_FEATURE_IFCONFIG_SLIP is not set
# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set
# CONFIG_FEATURE_IFCONFIG_HW is not set
# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set
# CONFIG_IFENSLAVE is not set
# CONFIG_IFPLUGD is not set
# CONFIG_IFUP is not set
# CONFIG_IFDOWN is not set
CONFIG_IFUPDOWN_IFSTATE_PATH=""
# CONFIG_FEATURE_IFUPDOWN_IP is not set
# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set
# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set
# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set
# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set
# CONFIG_INETD is not set
# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set
# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set
# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set
# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set
# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set
# CONFIG_FEATURE_INETD_RPC is not set
# CONFIG_IP is not set
# CONFIG_IPADDR is not set
# CONFIG_IPLINK is not set
# CONFIG_IPROUTE is not set
# CONFIG_IPTUNNEL is not set
# CONFIG_IPRULE is not set
# CONFIG_IPNEIGH is not set
# CONFIG_FEATURE_IP_ADDRESS is not set
# CONFIG_FEATURE_IP_LINK is not set
# CONFIG_FEATURE_IP_ROUTE is not set
CONFIG_FEATURE_IP_ROUTE_DIR=""
# CONFIG_FEATURE_IP_TUNNEL is not set
# CONFIG_FEATURE_IP_RULE is not set
# CONFIG_FEATURE_IP_NEIGH is not set
# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set
# CONFIG_IPCALC is not set
# CONFIG_FEATURE_IPCALC_LONG_OPTIONS is not set
# CONFIG_FEATURE_IPCALC_FANCY is not set
# CONFIG_FAKEIDENTD is not set
# CONFIG_NAMEIF is not set
# CONFIG_FEATURE_NAMEIF_EXTENDED is not set
# CONFIG_NBDCLIENT is not set
# CONFIG_NC is not set
# CONFIG_NETCAT is not set
# CONFIG_NC_SERVER is not set
# CONFIG_NC_EXTRA is not set
# CONFIG_NC_110_COMPAT is not set
# CONFIG_NETSTAT is not set
# CONFIG_FEATURE_NETSTAT_WIDE is not set
# CONFIG_FEATURE_NETSTAT_PRG is not set
# CONFIG_NSLOOKUP is not set
# CONFIG_FEATURE_NSLOOKUP_BIG is not set
# CONFIG_FEATURE_NSLOOKUP_LONG_OPTIONS is not set
# CONFIG_NTPD is not set
# CONFIG_FEATURE_NTPD_SERVER is not set
# CONFIG_FEATURE_NTPD_CONF is not set
# CONFIG_FEATURE_NTP_AUTH is not set
# CONFIG_PING is not set
# CONFIG_PING6 is not set
# CONFIG_FEATURE_FANCY_PING is not set
# CONFIG_PSCAN is not set
# CONFIG_ROUTE is not set
# CONFIG_SLATTACH is not set
# CONFIG_SSL_CLIENT is not set
# CONFIG_TC is not set
# CONFIG_FEATURE_TC_INGRESS is not set
# CONFIG_TCPSVD is not set
# CONFIG_UDPSVD is not set
# CONFIG_TELNET is not set
# CONFIG_FEATURE_TELNET_TTYPE is not set
# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set
# CONFIG_FEATURE_TELNET_WIDTH is not set
# CONFIG_TELNETD is not set
# CONFIG_FEATURE_TELNETD_STANDALONE is not set
CONFIG_FEATURE_TELNETD_PORT_DEFAULT=0
# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set
# CONFIG_TFTP is not set
# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set
# CONFIG_FEATURE_TFTP_HPA_COMPAT is not set
# CONFIG_TFTPD is not set
# CONFIG_FEATURE_TFTP_GET is not set
# CONFIG_FEATURE_TFTP_PUT is not set
# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set
# CONFIG_TFTP_DEBUG is not set
# CONFIG_TLS is not set
# CONFIG_TRACEROUTE is not set
# CONFIG_TRACEROUTE6 is not set
# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set
# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set
# CONFIG_TUNCTL is not set
# CONFIG_FEATURE_TUNCTL_UG is not set
# CONFIG_VCONFIG is not set
# CONFIG_WGET is not set
# CONFIG_FEATURE_WGET_LONG_OPTIONS is not set
# CONFIG_FEATURE_WGET_STATUSBAR is not set
# CONFIG_FEATURE_WGET_FTP is not set
# CONFIG_FEATURE_WGET_AUTHENTICATION is not set
# CONFIG_FEATURE_WGET_TIMEOUT is not set
# CONFIG_FEATURE_WGET_HTTPS is not set
# CONFIG_FEATURE_WGET_OPENSSL is not set
# CONFIG_WHOIS is not set
# CONFIG_ZCIP is not set
# CONFIG_UDHCPD is not set
# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set
# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set
CONFIG_DHCPD_LEASES_FILE=""
# CONFIG_DUMPLEASES is not set
# CONFIG_DHCPRELAY is not set
# CONFIG_UDHCPC is not set
# CONFIG_FEATURE_UDHCPC_ARPING is not set
# CONFIG_FEATURE_UDHCPC_SANITIZEOPT is not set
CONFIG_UDHCPC_DEFAULT_SCRIPT=""
CONFIG_UDHCPC6_DEFAULT_SCRIPT=""
# CONFIG_UDHCPC6 is not set
# CONFIG_FEATURE_UDHCPC6_RFC3646 is not set
# CONFIG_FEATURE_UDHCPC6_RFC4704 is not set
# CONFIG_FEATURE_UDHCPC6_RFC4833 is not set
# CONFIG_FEATURE_UDHCPC6_RFC5970 is not set
CONFIG_UDHCPC_DEFAULT_INTERFACE=""
# CONFIG_FEATURE_UDHCP_PORT is not set
CONFIG_UDHCP_DEBUG=0
CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0
# CONFIG_FEATURE_UDHCP_RFC3397 is not set
# CONFIG_FEATURE_UDHCP_8021Q is not set
CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS=""
#
# Print Utilities
#
# CONFIG_LPD is not set
# CONFIG_LPR is not set
# CONFIG_LPQ is not set
#
# Mail Utilities
#
CONFIG_FEATURE_MIME_CHARSET=""
# CONFIG_MAKEMIME is not set
# CONFIG_POPMAILDIR is not set
# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set
# CONFIG_REFORMIME is not set
# CONFIG_FEATURE_REFORMIME_COMPAT is not set
# CONFIG_SENDMAIL is not set
#
# Process Utilities
#
# CONFIG_FEATURE_FAST_TOP is not set
# CONFIG_FEATURE_SHOW_THREADS is not set
# CONFIG_FREE is not set
# CONFIG_FUSER is not set
# CONFIG_IOSTAT is not set
# CONFIG_KILL is not set
# CONFIG_KILLALL is not set
# CONFIG_KILLALL5 is not set
# CONFIG_LSOF is not set
# CONFIG_MPSTAT is not set
# CONFIG_NMETER is not set
# CONFIG_PGREP is not set
# CONFIG_PKILL is not set
# CONFIG_PIDOF is not set
# CONFIG_FEATURE_PIDOF_SINGLE is not set
# CONFIG_FEATURE_PIDOF_OMIT is not set
# CONFIG_PMAP is not set
# CONFIG_POWERTOP is not set
# CONFIG_FEATURE_POWERTOP_INTERACTIVE is not set
# CONFIG_PS is not set
# CONFIG_FEATURE_PS_WIDE is not set
# CONFIG_FEATURE_PS_LONG is not set
# CONFIG_FEATURE_PS_TIME is not set
# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set
# CONFIG_PSTREE is not set
# CONFIG_PWDX is not set
# CONFIG_SMEMCAP is not set
# CONFIG_BB_SYSCTL is not set
# CONFIG_TOP is not set
# CONFIG_FEATURE_TOP_INTERACTIVE is not set
# CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE is not set
# CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS is not set
# CONFIG_FEATURE_TOP_SMP_CPU is not set
# CONFIG_FEATURE_TOP_DECIMALS is not set
# CONFIG_FEATURE_TOP_SMP_PROCESS is not set
# CONFIG_FEATURE_TOPMEM is not set
# CONFIG_UPTIME is not set
# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set
# CONFIG_WATCH is not set
#
# Runit Utilities
#
# CONFIG_CHPST is not set
# CONFIG_SETUIDGID is not set
# CONFIG_ENVUIDGID is not set
# CONFIG_ENVDIR is not set
# CONFIG_SOFTLIMIT is not set
# CONFIG_RUNSV is not set
# CONFIG_RUNSVDIR is not set
# CONFIG_FEATURE_RUNSVDIR_LOG is not set
# CONFIG_SV is not set
CONFIG_SV_DEFAULT_SERVICE_DIR=""
# CONFIG_SVC is not set
# CONFIG_SVOK is not set
# CONFIG_SVLOGD is not set
# CONFIG_CHCON is not set
# CONFIG_GETENFORCE is not set
# CONFIG_GETSEBOOL is not set
# CONFIG_LOAD_POLICY is not set
# CONFIG_MATCHPATHCON is not set
# CONFIG_RUNCON is not set
# CONFIG_SELINUXENABLED is not set
# CONFIG_SESTATUS is not set
# CONFIG_SETENFORCE is not set
# CONFIG_SETFILES is not set
# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set
# CONFIG_RESTORECON is not set
# CONFIG_SETSEBOOL is not set
#
# Shells
#
CONFIG_SH_IS_ASH=y
# CONFIG_SH_IS_HUSH is not set
# CONFIG_SH_IS_NONE is not set
# CONFIG_BASH_IS_ASH is not set
# CONFIG_BASH_IS_HUSH is not set
CONFIG_BASH_IS_NONE=y
CONFIG_SHELL_ASH=y
CONFIG_ASH=y
# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set
CONFIG_ASH_INTERNAL_GLOB=y
# CONFIG_ASH_BASH_COMPAT is not set
# CONFIG_ASH_BASH_SOURCE_CURDIR is not set
# CONFIG_ASH_BASH_NOT_FOUND_HOOK is not set
# CONFIG_ASH_JOB_CONTROL is not set
# CONFIG_ASH_ALIAS is not set
# CONFIG_ASH_RANDOM_SUPPORT is not set
# CONFIG_ASH_EXPAND_PRMT is not set
# CONFIG_ASH_IDLE_TIMEOUT is not set
# CONFIG_ASH_MAIL is not set
CONFIG_ASH_ECHO=y
# CONFIG_ASH_PRINTF is not set
# CONFIG_ASH_TEST is not set
# CONFIG_ASH_SLEEP is not set
# CONFIG_ASH_HELP is not set
# CONFIG_ASH_GETOPTS is not set
# CONFIG_ASH_CMDCMD is not set
# CONFIG_CTTYHACK is not set
# CONFIG_HUSH is not set
# CONFIG_SHELL_HUSH is not set
# CONFIG_HUSH_BASH_COMPAT is not set
# CONFIG_HUSH_BRACE_EXPANSION is not set
# CONFIG_HUSH_BASH_SOURCE_CURDIR is not set
# CONFIG_HUSH_LINENO_VAR is not set
# CONFIG_HUSH_INTERACTIVE is not set
# CONFIG_HUSH_SAVEHISTORY is not set
# CONFIG_HUSH_JOB is not set
# CONFIG_HUSH_TICK is not set
# CONFIG_HUSH_IF is not set
# CONFIG_HUSH_LOOPS is not set
# CONFIG_HUSH_CASE is not set
# CONFIG_HUSH_FUNCTIONS is not set
# CONFIG_HUSH_LOCAL is not set
# CONFIG_HUSH_RANDOM_SUPPORT is not set
# CONFIG_HUSH_MODE_X is not set
# CONFIG_HUSH_ECHO is not set
# CONFIG_HUSH_PRINTF is not set
# CONFIG_HUSH_TEST is not set
# CONFIG_HUSH_HELP is not set
# CONFIG_HUSH_EXPORT is not set
# CONFIG_HUSH_EXPORT_N is not set
# CONFIG_HUSH_READONLY is not set
# CONFIG_HUSH_KILL is not set
# CONFIG_HUSH_WAIT is not set
# CONFIG_HUSH_COMMAND is not set
# CONFIG_HUSH_TRAP is not set
# CONFIG_HUSH_TYPE is not set
# CONFIG_HUSH_TIMES is not set
# CONFIG_HUSH_READ is not set
# CONFIG_HUSH_SET is not set
# CONFIG_HUSH_UNSET is not set
# CONFIG_HUSH_ULIMIT is not set
# CONFIG_HUSH_UMASK is not set
# CONFIG_HUSH_GETOPTS is not set
# CONFIG_HUSH_MEMLEAK is not set
#
# Options common to all shells
#
# CONFIG_FEATURE_SH_MATH is not set
# CONFIG_FEATURE_SH_MATH_64 is not set
# CONFIG_FEATURE_SH_MATH_BASE is not set
# CONFIG_FEATURE_SH_EXTRA_QUIET is not set
# CONFIG_FEATURE_SH_STANDALONE is not set
CONFIG_FEATURE_SH_NOFORK=y
# CONFIG_FEATURE_SH_READ_FRAC is not set
# CONFIG_FEATURE_SH_HISTFILESIZE is not set
CONFIG_FEATURE_SH_EMBEDDED_SCRIPTS=y
#
# System Logging Utilities
#
# CONFIG_KLOGD is not set
# CONFIG_FEATURE_KLOGD_KLOGCTL is not set
# CONFIG_LOGGER is not set
# CONFIG_LOGREAD is not set
# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set
# CONFIG_SYSLOGD is not set
# CONFIG_FEATURE_ROTATE_LOGFILE is not set
# CONFIG_FEATURE_REMOTE_LOG is not set
# CONFIG_FEATURE_SYSLOGD_DUP is not set
# CONFIG_FEATURE_SYSLOGD_CFG is not set
# CONFIG_FEATURE_SYSLOGD_PRECISE_TIMESTAMPS is not set
CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0
# CONFIG_FEATURE_IPC_SYSLOG is not set
CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0
# CONFIG_FEATURE_KMSG_SYSLOG is not set
================================================
FILE: rust-toolchain.toml
================================================
[toolchain]
channel = "nightly"
targets = ["x86_64-unknown-none"]
components = ["rust-src"]
================================================
FILE: src/arch/mod.rs
================================================
pub mod x86_64;
pub use self::x86_64::*;
================================================
FILE: src/arch/x86_64/cpu_local.rs
================================================
use x86::msr::{rdmsr, IA32_GS_BASE};
use x86_64::structures::{gdt::GlobalDescriptorTable, tss::TaskStateSegment};
pub struct CpuLocalData {
pub kernel_sp: usize,
pub gdt: GlobalDescriptorTable,
}
#[repr(C, packed)]
pub struct Kpcr {
pub tss: TaskStateSegment,
pub cpu_local: &'static mut CpuLocalData,
pub user_rsp0_tmp: usize,
}
pub fn get_kpcr() -> &'static mut Kpcr {
unsafe { &mut *(rdmsr(IA32_GS_BASE) as *mut _) }
}
pub fn get_tss() -> &'static mut TaskStateSegment {
unsafe { &mut *(rdmsr(IA32_GS_BASE) as *mut _) }
}
================================================
FILE: src/arch/x86_64/gdt.rs
================================================
use core::alloc::Layout;
use alloc::alloc::alloc_zeroed;
use lazy_static::lazy_static;
use x86::msr::{wrmsr, IA32_GS_BASE};
use x86_64::{
instructions::tables::load_tss,
registers::segmentation::{Segment, CS, DS, ES, FS, GS, SS},
structures::{
gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector},
tss::TaskStateSegment,
},
};
use crate::mem::consts::KERNEL_STACK_SIZE;
use super::cpu_local::{get_kpcr, get_tss, CpuLocalData, Kpcr};
pub const KERNEL_CS_IDX: u16 = 1;
pub const KERNEL_DS_IDX: u16 = 2;
pub const TSS_IDX: u16 = 3;
pub const USER_DS_IDX: u16 = 5;
pub const USER_CS_IDX: u16 = 6;
static mut STACK: [u8; KERNEL_STACK_SIZE] = [0; KERNEL_STACK_SIZE];
lazy_static! {
static ref BOOT_GDT: (GlobalDescriptorTable, [SegmentSelector; 2]) = {
let mut gdt = GlobalDescriptorTable::new();
let kernel_code_sel = gdt.append(Descriptor::kernel_code_segment());
let kernel_data_sel = gdt.append(Descriptor::kernel_data_segment());
(gdt, [kernel_code_sel, kernel_data_sel])
};
}
pub fn init_boot() {
unsafe {
BOOT_GDT.0.load();
CS::set_reg(BOOT_GDT.1[0]);
DS::set_reg(BOOT_GDT.1[1]);
ES::set_reg(BOOT_GDT.1[1]);
FS::set_reg(BOOT_GDT.1[1]);
GS::set_reg(BOOT_GDT.1[1]);
SS::set_reg(BOOT_GDT.1[1]);
}
}
pub fn init() {
unsafe {
let kpcr_layout = Layout::new::<Kpcr>();
let kpcr_ptr = alloc_zeroed(kpcr_layout) as *mut Kpcr;
wrmsr(IA32_GS_BASE, kpcr_ptr as u64);
let tls_layout = Layout::new::<CpuLocalData>();
let tls_ptr = alloc_zeroed(tls_layout) as *mut CpuLocalData;
get_kpcr().cpu_local = &mut *tls_ptr;
}
let tss = get_tss();
*tss = TaskStateSegment::new();
tss.privilege_stack_table[0] = x86_64::VirtAddr::new(
unsafe {
#[allow(static_mut_refs)]
STACK.as_mut_ptr()
} as u64
+ KERNEL_STACK_SIZE as u64,
);
let gdt = &mut get_kpcr().cpu_local.gdt;
*gdt = GlobalDescriptorTable::new();
// kernel code
let kernel_cs_sel = gdt.append(Descriptor::kernel_code_segment());
// kernel data
let kernel_ds_sel = gdt.append(Descriptor::kernel_data_segment());
// TSS
let tss_sel = gdt.append(Descriptor::tss_segment(tss));
// user data (syscall)
let _user_ds_sel = gdt.append(Descriptor::user_data_segment());
// user code
let _user_cs_sel = gdt.append(Descriptor::user_code_segment());
gdt.load();
unsafe {
CS::set_reg(kernel_cs_sel);
DS::set_reg(kernel_ds_sel);
ES::set_reg(kernel_ds_sel);
SS::set_reg(kernel_ds_sel);
// FS::set_reg(kernel_ds_sel);
// GS::set_reg(kernel_ds_sel);
load_tss(tss_sel);
}
}
================================================
FILE: src/arch/x86_64/idt.rs
================================================
use lazy_static::lazy_static;
use pc_keyboard::{DecodedKey, HandleControl, Keyboard, ScancodeSet1, layouts::Us104Key};
use pic8259::ChainedPics;
use spin::Mutex;
use x86::{
io::outb,
msr::{IA32_FS_BASE, rdmsr},
};
use x86_64::{
instructions::port::Port,
registers::control::Cr3,
structures::idt::{InterruptDescriptorTable, PageFaultErrorCode},
};
use crate::{
backtrace,
fs::devfs::{input::KBD_DEVICE, tty::TTY},
mem::addr::VirtAddr,
task::get_scheduler,
util::IrqMutex,
};
pub const PIC_1_OFFSET: u8 = 32;
pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8;
pub static PICS: Mutex<ChainedPics> =
Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) });
pub const TIMER_IRQ: u8 = PIC_1_OFFSET;
pub const KEYBOARD_IRQ: u8 = PIC_1_OFFSET + 1;
pub const COM2_IRQ: u8 = PIC_1_OFFSET + 3;
lazy_static! {
pub static ref IDT: InterruptDescriptorTable = {
let mut idt = InterruptDescriptorTable::new();
#[allow(clippy::fn_to_numeric_cast)]
unsafe {
idt.divide_error.set_handler_addr(x86_64::VirtAddr::new(divide_error_handler as u64));
idt.debug.set_handler_addr(x86_64::VirtAddr::new(debug_handler as u64));
idt.non_maskable_interrupt.set_handler_addr(x86_64::VirtAddr::new(nmi_handler as u64));
idt.breakpoint.set_handler_addr(x86_64::VirtAddr::new(breakpoint_handler as u64));
idt.overflow.set_handler_addr(x86_64::VirtAddr::new(overflow_handler as u64));
idt.bound_range_exceeded
.set_handler_addr(x86_64::VirtAddr::new(bound_range_exceeded_handler as u64));
idt.invalid_opcode.set_handler_addr(x86_64::VirtAddr::new(invalid_opcode_handler as u64));
idt.device_not_available
.set_handler_addr(x86_64::VirtAddr::new(device_not_available_handler as u64));
idt.double_fault
.set_handler_addr(x86_64::VirtAddr::new(double_fault_handler as u64))
.set_stack_index(0);
// reserved: 0x09 coprocessor segment overrun exception
idt.invalid_tss.set_handler_addr(x86_64::VirtAddr::new(invalid_tss_handler as u64));
idt.segment_not_present
.set_handler_addr(x86_64::VirtAddr::new(segment_not_present_handler as u64));
idt.stack_segment_fault
.set_handler_addr(x86_64::VirtAddr::new(stack_segment_fault_handler as u64));
idt.general_protection_fault
.set_handler_addr(x86_64::VirtAddr::new(general_protection_fault_handler as u64));
idt.page_fault.set_handler_addr(x86_64::VirtAddr::new(page_fault_handler as u64));
// reserved: 0x0F
idt.x87_floating_point
.set_handler_addr(x86_64::VirtAddr::new(x87_floating_point_handler as u64));
idt.alignment_check.set_handler_addr(x86_64::VirtAddr::new(alignment_check_handler as u64));
idt.machine_check.set_handler_addr(x86_64::VirtAddr::new(machine_check_handler as u64));
idt.simd_floating_point
.set_handler_addr(x86_64::VirtAddr::new(simd_floating_point_handler as u64));
idt.virtualization.set_handler_addr(x86_64::VirtAddr::new(virtualization_handler as u64));
// reserved: 0x15 - 0x1C
idt.vmm_communication_exception
.set_handler_addr(x86_64::VirtAddr::new(vmm_communication_exception_handler as u64));
idt.security_exception
.set_handler_addr(x86_64::VirtAddr::new(security_exception_handler as u64));
idt[TIMER_IRQ].set_handler_addr(x86_64::VirtAddr::new(timer_handler as u64));
idt[KEYBOARD_IRQ].set_handler_addr(x86_64::VirtAddr::new(keyboard_handler as u64));
idt[COM2_IRQ].set_handler_addr(x86_64::VirtAddr::new(com2_handler as u64));
}
idt
};
}
#[derive(Copy, Clone, Debug, Default)]
#[repr(C, packed)]
pub struct InterruptFrame {
pub r15: usize,
pub r14: usize,
pub r13: usize,
pub r12: usize,
pub rbp: usize,
pub rbx: usize,
pub r11: usize,
pub r10: usize,
pub r9: usize,
pub r8: usize,
pub rsi: usize,
pub rdi: usize,
pub rdx: usize,
pub rcx: usize,
pub rax: usize,
pub rip: usize,
pub cs: usize,
pub rflags: usize,
pub rsp: usize,
pub ss: usize,
}
impl InterruptFrame {
#[inline(always)]
pub fn is_user_mode(&self) -> bool {
self.cs & 0x3 != 0
}
}
#[derive(Copy, Clone, Debug, Default)]
#[repr(C, packed)]
pub struct InterruptErrorFrame {
pub code: usize,
pub frame: InterruptFrame,
}
pub fn notify_eoi(index: u8) {
unsafe { PICS.lock().notify_end_of_interrupt(index) }
}
macro_rules! interrupt_handler {
($name:ident, $num:literal, $push_error:expr) => {
#[unsafe(naked)]
unsafe extern "C" fn $name() {
{
core::arch::naked_asm!(concat!(
$push_error,
"
test qword ptr [rsp + 16], 0x3
jz 2f
swapgs
2:
xchg [rsp], rax
", crate::push_regs!(),"
push rax
mov rdi, {num}
mov rsi, rsp
call x64_handle_interrupt
add rsp, 8
", crate::pop_regs!(),"
test qword ptr [rsp + 8], 0x3
jz 3f
swapgs
3:
iretq
"
),
num = const($num))
}
}
};
}
macro_rules! has_error {
() => {
""
};
}
macro_rules! no_error {
() => {
"push 0"
};
}
interrupt_handler!(divide_error_handler, 0x0, no_error!());
interrupt_handler!(debug_handler, 0x1, no_error!());
interrupt_handler!(nmi_handler, 0x2, no_error!());
interrupt_handler!(breakpoint_handler, 0x3, no_error!());
interrupt_handler!(overflow_handler, 0x4, no_error!());
interrupt_handler!(bound_range_exceeded_handler, 0x5, no_error!());
interrupt_handler!(invalid_opcode_handler, 0x6, no_error!());
interrupt_handler!(device_not_available_handler, 0x7, no_error!());
interrupt_handler!(double_fault_handler, 0x8, has_error!());
interrupt_handler!(invalid_tss_handler, 0xA, has_error!());
interrupt_handler!(segment_not_present_handler, 0xB, has_error!());
interrupt_handler!(stack_segment_fault_handler, 0xC, has_error!());
interrupt_handler!(general_protection_fault_handler, 0xD, has_error!());
interrupt_handler!(page_fault_handler, 0xE, has_error!());
interrupt_handler!(x87_floating_point_handler, 0x10, no_error!());
interrupt_handler!(alignment_check_handler, 0x11, has_error!());
interrupt_handler!(machine_check_handler, 0x12, no_error!());
interrupt_handler!(simd_floating_point_handler, 0x13, no_error!());
interrupt_handler!(virtualization_handler, 0x14, no_error!());
interrupt_handler!(vmm_communication_exception_handler, 0x1D, has_error!());
interrupt_handler!(security_exception_handler, 0x1E, has_error!());
interrupt_handler!(timer_handler, 32, no_error!());
interrupt_handler!(keyboard_handler, 33, no_error!());
interrupt_handler!(com2_handler, 35, no_error!());
use x86::irq::*;
#[unsafe(no_mangle)]
extern "C" fn x64_handle_interrupt(vector: u8, stack_frame: *mut InterruptErrorFrame) {
let stack_frame = unsafe { &mut *stack_frame };
let error_code = stack_frame.code;
match vector {
TIMER_IRQ => {
super::time::pit_irq();
let sched = get_scheduler();
notify_eoi(TIMER_IRQ);
sched.preempt();
}
KEYBOARD_IRQ => {
do_keyboard_input();
notify_eoi(KEYBOARD_IRQ);
}
COM2_IRQ => {
notify_eoi(COM2_IRQ);
}
DIVIDE_ERROR_VECTOR => {
log::error!("\nEXCEPTION: DIVIDE ERROR\n{:#x?}", stack_frame);
panic!("Divide error");
}
DEBUG_VECTOR => {
log::error!("\nEXCEPTION: DEBUG EXCEPTION\n{:#x?}", stack_frame);
}
NONMASKABLE_INTERRUPT_VECTOR => {
log::error!("\nEXCEPTION: NON-MASKABLE INTERRUPT\n{:#x?}", stack_frame);
panic!("Non-maskable interrupt");
}
OVERFLOW_VECTOR => {
log::error!("\nEXCEPTION: OVERFLOW\n{:#x?}", stack_frame);
panic!("Overflow");
}
BOUND_RANGE_EXCEEDED_VECTOR => {
log::error!("\nEXCEPTION: BOUND RANGE EXCEEDED\n{:#x?}", stack_frame);
panic!("Bound range exceeded");
}
INVALID_OPCODE_VECTOR => {
log::error!("\nEXCEPTION: INVALID OPCODE\n{:#x?}", stack_frame);
panic!("Invalid opcode");
}
DEVICE_NOT_AVAILABLE_VECTOR => {
log::error!("\nEXCEPTION: DEVICE NOT AVAILABLE\n{:#x?}", stack_frame);
panic!("Device not available");
}
DOUBLE_FAULT_VECTOR => {
log::error!(
"\nEXCEPTION: DOUBLE FAULT\n{:#x?}\nError code: {:#b}\ncr3: {:#x}",
stack_frame,
error_code,
Cr3::read_raw().0.start_address().as_u64()
);
panic!("Double fault");
}
INVALID_TSS_VECTOR => {
log::error!(
"\nEXCEPTION: INVALID TSS\n{:#x?}\nError code: {:#b}",
stack_frame,
error_code
);
panic!("Invalid TSS");
}
SEGMENT_NOT_PRESENT_VECTOR => {
log::error!(
"\nEXCEPTION: SEGMENT NOT PRESENT\n{:#x?}\nError code: {:#b}",
stack_frame,
error_code
);
panic!("Segment not present");
}
STACK_SEGEMENT_FAULT_VECTOR => {
log::error!(
"\nEXCEPTION: STACK SEGMENT FAULT\n{:#x?}\nError code: {:#b}",
stack_frame,
error_code
);
panic!("Stack segment fault");
}
GENERAL_PROTECTION_FAULT_VECTOR => {
log::error!(
"\nEXCEPTION: GENERAL PROTECTION FAULT\n{:#x?}\nError code: {:#b}",
stack_frame,
error_code
);
unsafe {
let fsbase = rdmsr(IA32_FS_BASE);
log::debug!("FSBASE: {:#x}", fsbase);
}
if stack_frame.frame.is_user_mode() {
backtrace::unwind_user_stack_from(stack_frame.frame.rbp, stack_frame.frame.rip);
get_scheduler().exit_current(1);
}
panic!("General Protection Fault");
}
PAGE_FAULT_VECTOR => {
let accessed_address = x86_64::registers::control::Cr2::read_raw();
let cr3 = x86_64::registers::control::Cr3::read_raw().0;
let error_code = PageFaultErrorCode::from_bits_truncate(error_code as u64);
let current = get_scheduler().current_task_opt();
if let Some(current) = current {
if let Err(e) = current.handle_page_fault(
unsafe { VirtAddr::new_unchecked(accessed_address as usize) },
*stack_frame,
error_code,
) {
log::error!(
"\nEXCEPTION: USER PAGE FAULT while accessing {:#x}\n\
error code: {:?}\ncr3: {:#x}\n{:#x?}",
accessed_address,
error_code,
cr3.start_address().as_u64(),
stack_frame,
);
let rip = stack_frame.frame.rip;
log::error!("Exception IP {:#x}", rip);
log::error!("Faulted access address {:#x}", accessed_address);
log::error!("Error: {:?}", e);
panic!("User page fault");
}
} else {
log::error!(
"\nEXCEPTION: KERNEL PAGE FAULT while accessing {:#x}\n\
error code: {:?}\ncr3: {:#x}\n{:#x?}",
accessed_address,
error_code,
cr3.start_address().as_u64(),
stack_frame,
);
let rip = stack_frame.frame.rip;
log::error!("Exception IP {:#x}", rip);
log::error!("Faulted access address {:#x}", accessed_address,);
panic!("Kernel page fault");
}
}
X87_FPU_VECTOR => {
log::error!("\nEXCEPTION: x87 FLOATING POINT\n{:#x?}", stack_frame);
panic!("x87 floating point exception");
}
ALIGNMENT_CHECK_VECTOR => {
log::error!(
"\nEXCEPTION: ALIGNMENT CHECK\n{:#x?}\nError code: {:#b}",
stack_frame,
error_code
);
panic!("Alignment check");
}
MACHINE_CHECK_VECTOR => {
log::error!("\nEXCEPTION: MACHINE CHECK\n{:#x?}", stack_frame);
panic!()
}
SIMD_FLOATING_POINT_VECTOR => {
log::error!("\nEXCEPTION: SIMD FLOATING POINT\n{:#x?}", stack_frame);
panic!("SIMD floating point exception");
}
VIRTUALIZATION_VECTOR => {
log::error!("\nEXCEPTION: VIRTUALIZATION\n{:#x?}", stack_frame);
panic!("Virtualization exception");
}
0x1D => {
log::error!(
"\nEXCEPTION: VMM COMMUNICATION EXCEPTION\n{:#x?}\nError code: {:#b}",
stack_frame,
error_code
);
panic!("VMM communication exception");
}
0x1E => {
log::error!(
"\nEXCEPTION: SECURITY EXCEPTION\n{:#x?}\nError code: {:#b}",
stack_frame,
error_code
);
panic!("Security exception");
}
_ => log::warn!("Unhandled interrupt: {}", vector),
}
}
pub const PIC_1_DATA_PORT: u8 = 0x21;
pub const PIC_2_DATA_PORT: u8 = 0xa1;
pub fn mask_irq(irq: u8) {
let irq = irq - PIC_1_OFFSET;
let port = if irq < 8 {
PIC_1_DATA_PORT
} else {
PIC_2_DATA_PORT
};
let irq = if irq < 8 { irq } else { irq - 8 };
let val = unsafe { x86::io::inb(port as u16) } | (1 << irq);
unsafe { outb(port as u16, val) };
}
pub fn unmask_irq(irq: u8) {
let irq = irq - PIC_1_OFFSET;
let port = if irq < 8 {
PIC_1_DATA_PORT
} else {
PIC_2_DATA_PORT
};
let irq = if irq < 8 { irq } else { irq - 8 };
let val = unsafe { x86::io::inb(port as u16) } & !(1 << irq);
unsafe { outb(port as u16, val) };
}
pub fn init() {
IDT.load();
unsafe {
PICS.lock().initialize();
}
unmask_irq(TIMER_IRQ);
unmask_irq(KEYBOARD_IRQ);
unmask_irq(COM2_IRQ);
}
fn do_keyboard_input() {
lazy_static! {
static ref KEYBOARD: IrqMutex<Keyboard<Us104Key, ScancodeSet1>> = IrqMutex::new(
Keyboard::new(ScancodeSet1::new(), Us104Key, HandleControl::Ignore)
);
}
let mut port = Port::new(0x60);
let scancode: u8 = unsafe { port.read() };
let mut keyboard = KEYBOARD.lock();
if let Ok(Some(key_evt)) = keyboard.add_byte(scancode) {
if let Some(kbd) = KBD_DEVICE.get() {
kbd.handle_kbd_irq(&key_evt);
}
if let Some(key) = keyboard.process_keyevent(key_evt) {
match key {
DecodedKey::Unicode(c) => {
TTY.get().unwrap().input_char(c as u8);
}
DecodedKey::RawKey(_code) => {}
}
}
}
}
================================================
FILE: src/arch/x86_64/mod.rs
================================================
use alloc::sync::Arc;
use limine::request::{
BootTimeRequest, FramebufferRequest, HhdmRequest, KernelFileRequest, MemoryMapRequest,
StackSizeRequest,
};
use spin::Once;
use x86::{
controlregs::{self, Cr0, Cr4},
cpuid::{CpuId, FeatureInfo},
};
use x86_64::instructions::interrupts;
use crate::{
backtrace,
fs::{
self,
initramfs::get_root,
opened_file::{OpenFlags, OpenedFile},
path::Path,
},
god_mode::GOD_MODE_FIFO,
graphics,
mem::{
self,
allocator::{KERNEL_FRAME_ALLOCATOR, KERNEL_PAGE_ALLOCATOR},
consts::KERNEL_STACK_SIZE,
},
serial::serial1_recv,
task::{current_task, get_scheduler, Task},
};
pub mod cpu_local;
pub mod gdt;
pub mod idt;
pub mod syscall;
pub mod task;
pub mod time;
static HHDM: HhdmRequest = HhdmRequest::new();
static _STACK: StackSizeRequest = StackSizeRequest::new().with_size(KERNEL_STACK_SIZE as u64);
static BOOT_TIME: BootTimeRequest = BootTimeRequest::new();
static FB_REQUEST: FramebufferRequest = FramebufferRequest::new();
static MEM_MAP: MemoryMapRequest = MemoryMapRequest::new();
static KERNEL_FILE: KernelFileRequest = KernelFileRequest::new();
pub static CPUID_FEATURE_INFO: Once<FeatureInfo> = Once::new();
pub fn get_cpuid_feature_info() -> &'static FeatureInfo {
CPUID_FEATURE_INFO.call_once(|| {
CpuId::new()
.get_feature_info()
.expect("Error getting CPUID feature info")
})
}
pub fn arch_main() {
interrupts::disable();
let kernel_file = KERNEL_FILE
.get_response()
.expect("Error getting kernel binary from Limine");
let kernel_file = kernel_file.file();
let kernel_file_base = kernel_file.addr();
let kernel_file_len = kernel_file.size() as usize;
let kernel_file_data =
unsafe { core::slice::from_raw_parts(kernel_file_base, kernel_file_len) };
backtrace::KERNEL_ELF.call_once(|| {
xmas_elf::ElfFile::new(kernel_file_data).expect("Error parsing kernel ELF file data")
});
crate::PHYSICAL_OFFSET.call_once(|| {
HHDM.get_response()
.expect("Error getting HHDM response from Limine")
.offset() as usize
});
let memmap = MEM_MAP
.get_response()
.expect("Error getting memory map response from Limine")
.entries();
crate::logging::init();
log::info!("Logger initialized.");
log::info!("Setting up time structures.");
let boot_time = BOOT_TIME
.get_response()
.expect("Error getting boot time response from Limine")
.boot_time();
time::init(boot_time.as_secs() as i64);
log::info!("Initializing FPU mechanisms.");
let features = get_cpuid_feature_info();
assert!(features.has_fxsave_fxstor(), "FXSAVE/FXRSTOR not available");
assert!(features.has_mmx(), "MMX not available");
assert!(features.has_fpu(), "FPU not available");
assert!(features.has_sse(), "SSE not available");
unsafe {
// enable FXSAVE and FXRSTOR
controlregs::cr4_write(controlregs::cr4() | Cr4::CR4_ENABLE_SSE | Cr4::CR4_UNMASKED_SSE);
log::trace!("CR4_ENABLE_SSE and CR4_UNMASKED_SSE set.");
// controlregs::xcr0_write(
// controlregs::xcr0()
// | Xcr0::XCR0_SSE_STATE
// | Xcr0::XCR0_FPU_MMX_STATE
// | Xcr0::XCR0_AVX_STATE,
// );
// log::trace!("XCR0_SSE_STATE, XCR0_FPU_MMX_STATE, and XCR0_AVX_STATE set.");
controlregs::cr0_write(controlregs::cr0() & !Cr0::CR0_EMULATE_COPROCESSOR);
log::trace!("CR0_EMULATE_COPROCESSOR cleared.");
controlregs::cr0_write(controlregs::cr0() | Cr0::CR0_MONITOR_COPROCESSOR);
log::trace!("CR0_MONITOR_COPROCESSOR set.");
}
log::info!("Initializing boot GDT.");
gdt::init_boot();
// let fb_tag = boot_info.framebuffer_tag().expect("No multiboot2 framebuffer tag found");
let fb_resp = FB_REQUEST
.get_response()
.expect("Error getting framebuffer response from Limine");
log::info!("Initializing kernel frame and page allocators.");
mem::allocator::init(memmap).expect("Error initializing kernel frame and page allocators");
log::info!("Remapping kernel to new page table.");
let kernel_addr_space = mem::remap_kernel().expect("Error remapping kernel");
log::info!("Setting up kernel heap.");
let _heap_mp = kernel_addr_space
.lock()
.with_mapper(|mut mapper| mem::init_heap(&mut mapper).expect("Error setting up heap"));
log::info!("Converting kernel frame and page allocators to use heap.");
{
KERNEL_FRAME_ALLOCATOR
.get()
.expect("Error getting kernel frame allocator")
.lock()
.convert_to_heap_allocated();
KERNEL_PAGE_ALLOCATOR
.get()
.expect("Error getting kernel page allocator")
.lock()
.convert_to_heap_allocated();
}
log::info!("Initializing VGA graphics.");
graphics::init(fb_resp).expect("Error initializing VGA graphics");
log::info!("Setting up syscalls.");
unsafe {
syscall::init();
}
log::info!("Loading GDT.");
gdt::init();
log::info!("Loading IDT.");
idt::init();
log::info!("Initializing filesystems.");
fs::initramfs::init().expect("Error initializing initramfs");
log::info!("Initializing task scheduler.");
crate::task::init();
log::info!("Starting init process.");
let sched = get_scheduler();
fs::devfs::init();
log::info!("Welcome to K4DOS!");
{
let task = Task::new_kernel(sched, poll_serial1, true);
sched.push_runnable(task, true);
}
// god_mode::init();
loop {
interrupts::enable_and_hlt();
}
}
pub fn startup_init() {
let exe = "/bin/sh";
let file = get_root()
.unwrap()
.lookup(Path::new(exe), true)
.unwrap()
.as_file()
.unwrap()
.clone();
let current = current_task();
let mut files = current.opened_files.lock();
let console = get_root()
.unwrap()
.lookup_path(Path::new("/dev/tty"), true)
.unwrap();
// stdin
files
.open_with_fd(
0,
Arc::new(OpenedFile::new(console.clone(), OpenFlags::O_RDONLY, 0)),
OpenFlags::O_RDONLY | OpenFlags::O_CLOEXEC,
)
.unwrap();
// stdout
files
.open_with_fd(
1,
Arc::new(OpenedFile::new(console.clone(), OpenFlags::O_WRONLY, 0)),
OpenFlags::O_WRONLY | OpenFlags::O_CLOEXEC,
)
.unwrap();
// stderr
files
.open_with_fd(
2,
Arc::new(OpenedFile::new(console, OpenFlags::O_WRONLY, 0)),
OpenFlags::O_WRONLY | OpenFlags::O_CLOEXEC,
)
.unwrap();
drop(files);
current
.exec(file, &[exe.as_bytes()], &[b"FOO=bar"])
.unwrap();
}
fn poll_serial1() {
loop {
let c = serial1_recv();
if let Some(c) = c {
// TTY.get().unwrap().input_char(c);
loop {
if let Ok(mut lock) = GOD_MODE_FIFO.get().unwrap().try_lock() {
lock.push_back(c);
drop(lock);
break;
}
// sched.preempt();
interrupts::enable_and_hlt();
}
}
interrupts::enable_and_hlt();
}
}
pub fn idle() {
loop {
interrupts::enable_and_hlt();
}
}
================================================
FILE: src/arch/x86_64/syscall.rs
================================================
use core::mem::offset_of;
use x86::msr::{rdmsr, wrmsr};
use crate::mem::kernel_addr_space_scope;
use crate::userland::syscall::{
QUIET_SYSCALLS, SyscallHandler, errno_to_isize, syscall_name_by_number,
};
use super::gdt::{KERNEL_CS_IDX, USER_DS_IDX};
use super::idt::InterruptFrame;
#[macro_export]
macro_rules! push_regs {
() => {
"
// push scratch regs
push rcx
push rdx
push rdi
push rsi
push r8
push r9
push r10
push r11
// push preserved regs
push rbx
push rbp
push r12
push r13
push r14
push r15
"
};
}
#[macro_export]
macro_rules! pop_regs {
() => {
"
// pop preserved regs
pop r15
pop r14
pop r13
pop r12
pop rbp
pop rbx
// pop scratch regs
pop r11
pop r10
pop r9
pop r8
pop rsi
pop rdi
pop rdx
pop rcx
pop rax
"
};
}
#[unsafe(naked)]
pub unsafe extern "C" fn syscall_entry() {
use x86_64::structures::tss::TaskStateSegment;
{
core::arch::naked_asm!(
concat!(
"
cli
swapgs
mov gs:[{off} + {sp}], rsp
mov rsp, gs:[{off} + {ksp}]
push qword ptr {ss_sel}
push qword ptr gs:[{off} + {sp}]
push r11
push qword ptr {cs_sel}
push rcx
push rax
",
push_regs!(),
"
mov rdi, rsp
cld
call x64_handle_syscall
cli
",
pop_regs!(),
"
test dword ptr [rsp + 4], 0xFFFF8000
jnz 2f
pop rcx
add rsp, 8
pop r11
pop qword ptr gs:[{off} + {sp}]
mov rsp, gs:[{off} + {sp}]
// pop rsp
cli
swapgs
sysretq
2:
xor rcx, rcx
xor r11, r11
cli
swapgs
iretq
"
),
off = const(0),
sp = const(offset_of!(crate::arch::cpu_local::Kpcr, user_rsp0_tmp)),
ksp = const(offset_of!(TaskStateSegment, privilege_stack_table)),
ss_sel = const((crate::arch::gdt::USER_DS_IDX << 3) | 3),
cs_sel = const((crate::arch::gdt::USER_CS_IDX << 3) | 3),
)
}
}
#[unsafe(no_mangle)]
unsafe extern "C" fn x64_handle_syscall(ctx: *mut InterruptFrame) -> isize {
let context = unsafe { core::ptr::read(ctx) };
handle_syscall(
context.rdi,
context.rsi,
context.rdx,
context.r10,
context.r8,
context.r9,
context.rax,
ctx,
)
}
#[allow(clippy::too_many_arguments)]
fn handle_syscall(
a1: usize,
a2: usize,
a3: usize,
a4: usize,
a5: usize,
a6: usize,
n: usize,
frame: *mut InterruptFrame,
) -> isize {
let mut handler = SyscallHandler {
frame: unsafe { &mut *frame },
};
let guard = kernel_addr_space_scope().unwrap();
let res = handler.dispatch(a1, a2, a3, a4, a5, a6, n);
drop(guard);
if let Err(ref err) = res {
if !QUIET_SYSCALLS.contains(&n) {
log::error!(
"Syscall handler for `{}` returned Err: {}",
syscall_name_by_number(n),
err
);
}
}
let retval = errno_to_isize(&res);
handler.frame.rax = retval as usize;
retval
}
/// # Safety
/// This writes several MSR registers.
pub unsafe fn init() {
let kernel_cs_offset = (KERNEL_CS_IDX as u64) << 3;
let user_ds_offset = (USER_DS_IDX as u64) << 3;
let mut star = 0u64;
star |= (user_ds_offset - 8) << 48;
star |= kernel_cs_offset << 32;
unsafe {
wrmsr(x86::msr::IA32_STAR, star);
wrmsr(x86::msr::IA32_LSTAR, syscall_entry as *const u8 as u64);
wrmsr(x86::msr::IA32_FMASK, 0x200);
wrmsr(x86::msr::IA32_CSTAR, 0);
wrmsr(x86::msr::IA32_EFER, rdmsr(x86::msr::IA32_EFER) | 1);
}
}
================================================
FILE: src/arch/x86_64/task.rs
================================================
use core::{alloc::Layout, ptr::Unique, slice::SlicePattern};
use alloc::{alloc::alloc_zeroed, boxed::Box, vec::Vec};
use x86::{
cpuid::CpuId,
msr::{IA32_FS_BASE, IA32_GS_BASE, rdmsr, wrmsr},
tlb,
};
use x86_64::instructions::interrupts;
use crate::{
fs::FileRef,
mem::{
addr::VirtAddr,
addr_space::AddressSpace,
allocator::alloc_kernel_frames,
consts::{KERNEL_STACK_SIZE, PAGE_SIZE, USER_STACK_BOTTOM, USER_STACK_TOP},
},
task::{
signal::Signal,
vmem::{MMapFlags, MMapKind, MMapProt, Vmem},
},
userland::elf::{self, AuxvType, SymTabEntry},
util::{KResult, stack::Stack},
};
use super::{
cpu_local::get_tss,
gdt::{KERNEL_CS_IDX, KERNEL_DS_IDX, USER_DS_IDX},
idt::{InterruptErrorFrame, InterruptFrame},
};
fn fxsave(fpu: &mut Box<[u8]>) {
unsafe {
core::arch::asm!("fxsave [{}]", in(reg) (**fpu).as_ptr(), in("rax") u64::MAX, in("rdx") u64::MAX)
}
}
fn fxrstor(fpu: &mut Box<[u8]>) {
unsafe {
core::arch::asm!("fxrstor [{}]", in(reg) (**fpu).as_ptr(), in("rax") u64::MAX, in("rdx") u64::MAX)
}
}
pub fn arch_context_switch(prev: &mut ArchTask, next: &mut ArchTask) {
unsafe {
// prev.fsbase = VirtAddr::new(rdmsr(IA32_FS_BASE) as usize);
// prev.gsbase = VirtAddr::new(rdmsr(IA32_GS_BASE) as usize);
wrmsr(IA32_FS_BASE, next.fsbase.value() as u64);
// swapgs();
wrmsr(IA32_GS_BASE, next.gsbase.value() as u64);
get_tss().privilege_stack_table[0] = x86_64::VirtAddr::new(
(next.kernel_stack.as_ptr() as usize + next.kernel_stack.len()) as u64,
);
// swapgs();
if let Some(fpu) = prev.fpu_storage.as_mut() {
fxsave(fpu);
}
if let Some(fpu) = next.fpu_storage.as_mut() {
fxrstor(fpu)
}
next.address_space.switch();
// interrupts::disable(); // why doesn't this work instead of the FIXME in fork()?
context_switch(&mut prev.context, next.context.as_ref())
}
}
#[unsafe(naked)]
unsafe extern "C" fn iretq_init() -> ! {
{
core::arch::naked_asm!(
"
cli
add rsp, 8
",
crate::pop_regs!(),
"
iretq
",
)
}
}
#[unsafe(naked)]
unsafe extern "C" fn fork_init() -> ! {
{
core::arch::naked_asm!(concat!(
"
cli
add rsp, 8
",
crate::pop_regs!(),
"
swapgs
iretq
"
),)
}
}
#[unsafe(naked)]
unsafe extern "C" fn context_switch(_prev: &mut Unique<Context>, _next: &Context) {
{
core::arch::naked_asm!(
"
pushfq
push rbp
push rbx
push r12
push r13
push r14
push r15
mov [rdi], rsp
mov rsp, rsi
pop r15
pop r14
pop r13
pop r12
pop rbx
pop rbp
popfq
ret
",
)
}
}
#[derive(Clone, Debug, Default)]
#[repr(C)]
pub struct Context {
r15: usize,
r14: usize,
r13: usize,
r12: usize,
rbx: usize,
rbp: usize,
rflags: usize,
rip: usize,
}
#[unsafe(naked)]
unsafe extern "C" fn exec_entry(rcx: usize, rsp: usize, r11: usize) -> ! {
{
core::arch::naked_asm!(
"
cli
swapgs
mov r11, rdx
mov rcx, rdi
mov rsp, rsi
mov r15, {user_ds}
mov ds, r15d
mov es, r15d
mov fs, r15d
mov gs, r15d
xor rax, rax
xor rbx, rbx
xor rdx, rdx
xor rsi, rsi
xor rbp, rbp
xor r8, r8
xor r9, r9
xor r10, r10
xor r12, r12
xor r13, r13
xor r14, r14
xor r15, r15
sysretq
",
user_ds = const(((USER_DS_IDX as u64) << 3) | 3),
)
}
}
#[repr(C)]
pub struct ArchTask {
context: Unique<Context>,
kernel_stack: Box<[u8]>,
user: bool,
pub(crate) address_space: AddressSpace,
fsbase: VirtAddr,
gsbase: VirtAddr,
fpu_storage: Option<Box<[u8]>>,
pub symtab: Option<Vec<SymTabEntry>>,
}
impl ArchTask {
pub fn new_idle() -> ArchTask {
ArchTask {
context: Unique::dangling(),
address_space: AddressSpace::current(),
kernel_stack: alloc::vec![0u8; KERNEL_STACK_SIZE].into_boxed_slice(),
user: false,
fsbase: VirtAddr::null(),
gsbase: VirtAddr::null(),
fpu_storage: None,
symtab: None,
}
}
pub fn new_kernel(entry_point: VirtAddr, enable_interrupts: bool) -> ArchTask {
let switch_stack = Self::alloc_switch_stack().unwrap();
let task_stack = unsafe {
alloc_zeroed(Layout::from_size_align_unchecked(
KERNEL_STACK_SIZE,
PAGE_SIZE,
))
.add(KERNEL_STACK_SIZE)
};
let address_space = AddressSpace::current();
let mut stack_ptr = switch_stack.value();
let mut stack = Stack::new(&mut stack_ptr);
let kframe = unsafe { stack.offset::<InterruptErrorFrame>() };
*kframe = InterruptErrorFrame::default();
kframe.frame.ss = (KERNEL_DS_IDX as usize) << 3;
kframe.frame.cs = (KERNEL_CS_IDX as usize) << 3;
kframe.frame.rip = entry_point.value();
kframe.frame.rsp = task_stack as usize;
kframe.frame.rflags = if enable_interrupts { 0x200 } else { 0 };
let context = unsafe { stack.offset::<Context>() };
*context = Context::default();
context.rip = iretq_init as usize;
Self {
context: unsafe { Unique::new_unchecked(context) },
address_space,
kernel_stack: alloc::vec![0u8; KERNEL_STACK_SIZE].into_boxed_slice(),
user: false,
fsbase: VirtAddr::null(),
gsbase: unsafe { VirtAddr::new(rdmsr(IA32_GS_BASE) as usize) },
fpu_storage: None,
symtab: None,
}
}
pub fn exec(
&mut self,
vmem: &mut Vmem,
file: FileRef,
argv: &[&[u8]],
envp: &[&[u8]],
) -> KResult<()> {
interrupts::disable();
let userland_entry = elf::load_elf(file)?;
self.kernel_stack = alloc::vec![0u8; KERNEL_STACK_SIZE].into_boxed_slice();
self.fsbase = userland_entry.fsbase.unwrap_or(VirtAddr::null());
self.gsbase = unsafe { VirtAddr::new_unchecked(rdmsr(IA32_GS_BASE) as usize) };
self.user = true;
self.address_space = userland_entry.addr_space;
*vmem = userland_entry.vmem;
self.address_space.switch();
// userland_entry
self.address_space.with_mapper(|mut mapper| {
vmem.map_area(
USER_STACK_BOTTOM,
USER_STACK_TOP,
MMapFlags::empty(),
MMapProt::PROT_READ | MMapProt::PROT_WRITE | MMapProt::PROT_EXEC,
MMapKind::Anonymous,
&mut mapper,
)
})?;
let stack_addr = USER_STACK_TOP - core::mem::size_of::<usize>();
let mut stack_addr = stack_addr.value();
let mut stack = Stack::new(&mut stack_addr);
fn push_strs(strs: &[&[u8]], stack: &mut Stack) -> Vec<usize> {
let mut tops = Vec::new();
for slice in strs.iter() {
unsafe {
stack.push(0u8);
stack.push_bytes(slice);
}
tops.push(stack.top());
}
tops
}
let envp_tops = push_strs(envp, &mut stack);
let argv_tops = push_strs(argv, &mut stack);
stack.align_down(16);
let size = envp.len() + 1 + argv.len() + 1 + 1;
if size % 2 == 1 {
unsafe {
stack.push(0u64);
}
}
unsafe {
stack.push(0usize);
stack.push(AuxvType::AtNull);
stack.push(userland_entry.hdr);
stack.push(0u64);
for envp_top in envp_tops.iter() {
stack.push(*envp_top);
}
stack.push(0u64);
for argv_top in argv_tops.iter() {
stack.push(*argv_top);
}
stack.push(argv_tops.len());
}
core::mem::drop(argv_tops);
core::mem::drop(envp_tops);
assert_eq!(stack.top() % 16, 0);
self.fpu_storage = Some(Self::alloc_fpu_storage());
self.context = Unique::dangling();
self.symtab = userland_entry.symtab;
unsafe {
exec_entry(userland_entry.entry_point.value(), stack.top(), 0x200);
}
}
pub fn fork(&mut self) -> KResult<Self> {
assert!(self.user, "Cannot fork a kernel task");
let address_space = self.address_space.fork(true)?;
unsafe { tlb::flush_all() };
let switch_stack = Self::alloc_switch_stack()?.as_raw_ptr_mut::<u8>();
let mut old_rsp = self.kernel_stack.as_ptr() as usize + self.kernel_stack.len();
let mut old_stack = Stack::new(&mut old_rsp);
let mut new_rsp = switch_stack as usize;
let mut new_stack = Stack::new(&mut new_rsp);
unsafe {
let new_frame = new_stack.offset::<InterruptErrorFrame>();
let old_frame = old_stack.offset::<InterruptErrorFrame>();
*new_frame = *old_frame;
new_frame.frame.rax = 0x0; // fork return value
// fixme: having interrupts enabled between the context switch and fork_init being called will clobber the stack
new_frame.frame.rflags = old_frame.frame.rflags & !0x200;
}
let context = unsafe { new_stack.offset::<Context>() };
*context = Context::default();
context.rip = fork_init as usize;
let mut fpu_storage = Self::alloc_fpu_storage();
fpu_storage.copy_from_slice(self.fpu_storage.as_ref().unwrap().as_slice());
Ok(Self {
context: unsafe { Unique::new_unchecked(context) },
address_space,
user: true,
kernel_stack: alloc::vec![0u8; KERNEL_STACK_SIZE].into_boxed_slice(),
fsbase: self.fsbase,
gsbase: self.gsbase,
fpu_storage: Some(fpu_storage),
symtab: self.symtab.clone(),
})
}
pub fn clone_process(
&self,
entry_point: VirtAddr,
user_stack: VirtAddr,
args: VirtAddr,
r8: usize,
r9: usize,
syscall_frame: &InterruptFrame,
) -> KResult<Self> {
assert!(self.user, "Cannot clone a kernel task");
let address_space = AddressSpace::current().fork(true)?;
let switch_stack = Self::alloc_switch_stack()?.as_raw_ptr_mut::<u8>();
let mut new_rsp = switch_stack as usize;
let mut new_stack = Stack::new(&mut new_rsp);
let new_frame = unsafe { new_stack.offset::<InterruptErrorFrame>() };
*new_frame = InterruptErrorFrame::default();
new_frame.frame.cs = syscall_frame.cs;
new_frame.frame.ss = syscall_frame.ss;
new_frame.frame.r8 = r8;
new_frame.frame.r9 = r9;
new_frame.frame.rdi = args.value();
new_frame.frame.rip = entry_point.value();
new_frame.frame.rsp = user_stack.value();
new_frame.frame.rflags = 0x200;
let context = unsafe { new_stack.offset::<Context>() };
*context = Context::default();
context.rip = fork_init as usize;
let mut fpu_storage = Self::alloc_fpu_storage();
fpu_storage.copy_from_slice(self.fpu_storage.as_ref().unwrap().as_slice());
Ok(Self {
context: unsafe { Unique::new_unchecked(context) },
address_space,
user: true,
fpu_storage: Some(fpu_storage),
gsbase: self.gsbase,
fsbase: self.fsbase,
kernel_stack: alloc::vec![0u8; KERNEL_STACK_SIZE].into_boxed_slice(),
symtab: self.symtab.clone(),
})
}
fn alloc_fpu_storage() -> Box<[u8]> {
unsafe {
let xsave_size = CpuId::new().get_extended_state_info().unwrap().xsave_size();
let layout = Layout::from_size_align(xsave_size as usize, 16).unwrap();
let ptr = alloc_zeroed(layout);
Box::from_raw(core::ptr::slice_from_raw_parts_mut(
ptr,
xsave_size as usize,
))
}
}
fn alloc_switch_stack() -> KResult<VirtAddr> {
Ok(alloc_kernel_frames(1)?.start_address().as_hhdm_virt() + PAGE_SIZE)
}
pub fn set_fsbase(&mut self, addr: VirtAddr) {
self.fsbase = addr;
unsafe {
wrmsr(IA32_FS_BASE, self.fsbase.value() as u64);
}
}
pub fn setup_signal_stack(
frame: &mut InterruptFrame,
signal: Signal,
handler: VirtAddr,
_syscall_result: isize,
) -> KResult<()> {
const TRAMPOLINE: &[u8] = &[
0xb8, 0x0f, 0x00, 0x00, 0x00, // mov eax, 15
0x0f, 0x05, // syscall
0x90, // nop (for alignment)
];
if frame.cs & 0x3 == 0 {
return Ok(());
}
let mut rsp = frame.rsp;
let mut stack = Stack::new(&mut rsp);
// red zone
stack.skip_by(128);
unsafe {
stack.push_bytes(TRAMPOLINE);
stack.push(stack.top());
}
frame.rip = handler.value();
frame.rsp = rsp;
frame.rdi = signal as usize;
Ok(())
}
pub fn setup_sigreturn_stack(
&self,
current_frame: &mut InterruptFrame,
signaled_frame: &InterruptFrame,
) {
*current_frame = *signaled_frame;
}
}
================================================
FILE: src/arch/x86_64/time.rs
================================================
use core::sync::atomic::{AtomicUsize, Ordering};
use x86::io::{inb, outb};
use crate::{userland::syscall::syscall_impl::time::TimeSpec, util::IrqMutex};
const PIT_FREQUENCY_HZ: usize = 1000;
pub const PIT_DIVIDEND: usize = 1193182;
static UPTIME_RAW: AtomicUsize = AtomicUsize::new(0);
static UPTIME_SEC: AtomicUsize = AtomicUsize::new(0);
pub static EPOCH: AtomicUsize = AtomicUsize::new(usize::MAX);
pub static RT_CLOCK: IrqMutex<TimeSpec> = IrqMutex::new(TimeSpec::zero());
pub fn get_uptime_ns() -> usize {
let ts = get_rt_clock();
(ts.tv_sec * 1000000000 + ts.tv_nsec) as usize
}
pub fn get_uptime_ms() -> usize {
get_uptime_ns() / 1000000
}
pub fn get_rt_clock() -> TimeSpec {
*RT_CLOCK.lock()
}
pub fn get_pit_count() -> u16 {
unsafe {
outb(0x43, 0);
let lower = inb(0x40) as u16;
let higher = inb(0x40) as u16;
(higher << 8) | lower
}
}
pub fn set_reload_value(new_count: u16) {
unsafe {
outb(0x43, 0x34);
outb(0x40, new_count as u8);
outb(0x40, (new_count >> 8) as u8);
}
}
pub fn set_pit_frequency(frequency: usize) {
let mut new_divisor = PIT_DIVIDEND / frequency;
if PIT_DIVIDEND % frequency > frequency / 2 {
new_divisor += 1;
}
set_reload_value(new_divisor as u16);
}
pub fn pit_irq() {
{
let interval = TimeSpec {
tv_sec: 0,
tv_nsec: (1000000000 / PIT_FREQUENCY_HZ) as isize,
};
let mut clk = RT_CLOCK.lock();
if clk.tv_nsec + interval.tv_nsec > 999999999 {
let diff = (clk.tv_nsec + interval.tv_nsec) - 1000000000;
clk.tv_nsec = diff;
clk.tv_sec += 1;
} else {
clk.tv_nsec += interval.tv_nsec;
}
}
let value = UPTIME_RAW.fetch_add(1, Ordering::Relaxed);
if value % PIT_FREQUENCY_HZ == 0 {
UPTIME_SEC.fetch_add(1, Ordering::Relaxed);
}
}
pub fn init(boot_time: i64) {
EPOCH.store(boot_time as usize, Ordering::SeqCst);
RT_CLOCK.lock().tv_sec = boot_time as isize;
set_pit_frequency(PIT_FREQUENCY_HZ);
}
================================================
FILE: src/backtrace.rs
================================================
use core::{alloc::Layout, mem::size_of, panic::PanicInfo};
use alloc::vec::Vec;
use spin::Once;
use x86_64::instructions::interrupts;
use xmas_elf::{
ElfFile,
sections::{SectionData, ShType},
symbol_table::Entry,
};
use crate::{
fb_println,
graphics::FRAMEBUFFER,
kerror,
mem::{addr::VirtAddr, addr_space::AddressSpace, consts::PAGE_SIZE},
task::get_scheduler,
userland::elf::SymTabEntry,
util::{KResult, SavedInterruptStatus},
};
pub static KERNEL_ELF: Once<ElfFile<'static>> = Once::new();
fn print_symbol(rip: usize, symtab: &Option<Vec<SymTabEntry>>, depth: usize) {
if let Some(symbol_table) = symtab {
let mut name = None;
for data in symbol_table {
let st_value = data.value as usize;
let st_size = data.size as usize;
if rip >= st_value && rip < (st_value + st_size) {
name = Some(data.name.clone());
}
}
if let Some(name) = name {
serial0_println!("{:>2}: 0x{:016x} - {}", depth, rip, name);
} else {
serial0_println!(
"{:>2}: 0x{:016x} - <unknown> (symbol not found)",
depth,
rip
);
}
} else {
serial0_println!("{:>2}: 0x{:016x} - <unknown> (no symbol table)", depth, rip);
}
}
pub fn unwind_user_stack_from(mut rbp: usize, mut rip: usize) {
let _guard = SavedInterruptStatus::save();
interrupts::disable();
let mut addr_space = AddressSpace::current();
if rbp == 0 {
serial0_println!("<empty backtrace>");
return;
}
let current = get_scheduler().current_task_opt();
let symtab = if let Some(current) = current {
let s = current.arch_mut().symtab.clone();
if s.is_none() {
serial0_println!(
"Warning: Couldn't find symbol table for pid {}",
current.pid().as_usize()
);
}
s
} else {
serial0_println!("Warning: Couldn't lock current scheduler task");
None
};
serial0_println!("---BEGIN BACKTRACE---");
print_symbol(rip, &symtab, 0);
for depth in 1..17 {
if let Some(rip_rbp) = rbp.checked_add(size_of::<usize>()) {
let rip_rbp = unsafe { VirtAddr::new_unchecked(rip_rbp) };
let translated = addr_space.with_mapper(|mapper| mapper.translate(rip_rbp));
if rip_rbp.value() < PAGE_SIZE || translated.is_none() {
serial0_println!("{:>2}: <guard page>", depth);
break;
}
rip = unsafe { rip_rbp.read::<usize>().unwrap_or(0) };
if rip == 0 || rbp == 0 {
break;
}
unsafe {
rbp = *(rbp as *const usize);
}
print_symbol(rip, &symtab, depth);
} else {
break;
}
}
serial0_println!("---END BACKTRACE---");
}
pub fn unwind_stack() -> KResult<()> {
let _guard = SavedInterruptStatus::save();
interrupts::disable();
let mut addr_space = AddressSpace::current();
let kernel_elf = KERNEL_ELF
.get()
.ok_or(kerror!("KERNEL_ELF not initialized"))?;
let mut symbol_table = None;
for section in kernel_elf.section_iter() {
if section.get_type() == Ok(ShType::SymTab) {
let section_data = section
.get_data(kernel_elf)
.map_err(|_| kerror!("Failed to get kernel section data"))?;
if let SectionData::SymbolTable64(symtab) = section_data {
symbol_table = Some(symtab);
}
}
}
let symbol_table = symbol_table.ok_or(kerror!("No symbol table available"))?;
let mut rbp: usize;
unsafe {
core::arch::asm!("mov {}, rbp", out(reg) rbp);
}
if rbp == 0 {
serial0_println!("<empty backtrace>");
return Ok(());
}
serial0_println!("---BEGIN BACKTRACE---");
for depth in 0..16 {
if let Some(rip_rbp) = rbp.checked_add(size_of::<usize>()) {
let rip_rbp = unsafe { VirtAddr::new_unchecked(rip_rbp) };
let translated = addr_space.with_mapper(|mapper| mapper.translate(rip_rbp));
if translated.is_none() {
serial0_println!("{:>2}: <guard page>", depth);
break;
}
let rip = unsafe { rip_rbp.read::<usize>().unwrap_or(0) };
if rip == 0 || rbp == 0 {
break;
}
unsafe {
rbp = *(rbp as *const usize);
}
let mut name = None;
for data in symbol_table {
let st_value = data.value() as usize;
let st_size = data.size() as usize;
if rip >= st_value && rip < (st_value + st_size) {
let mangled_name = data.get_name(kernel_elf).unwrap_or("<unknown>");
name = Some(rustc_demangle::demangle(mangled_name));
}
}
if let Some(name) = name {
serial0_println!("{:>2}: 0x{:016x} - {}", depth, rip, name);
} else {
serial0_println!("{:>2}: 0x{:016x} - <unknown>", depth, rip);
}
} else {
break;
}
}
serial0_println!("---END BACKTRACE---");
Ok(())
}
#[panic_handler]
fn rust_panic(info: &PanicInfo) -> ! {
interrupts::disable();
let panic_msg = info.message();
serial0_println!("Panicked at '{}'", panic_msg);
if FRAMEBUFFER.get().is_some() {
fb_println!("Panicked at '{}'", panic_msg);
}
if let Some(panic_location) = info.location() {
serial0_println!("{}", panic_location);
if FRAMEBUFFER.get().is_some() {
fb_println!("{}", panic_location);
}
}
match unwind_stack() {
Ok(()) => {}
Err(e) => crate::serial::_print0(format_args!("Error unwinding stack: {:?}\n", e.msg())),
}
crate::hcf();
}
#[allow(non_snake_case)]
#[unsafe(no_mangle)]
extern "C" fn _Unwind_Resume(unwind_context_ptr: usize) -> ! {
serial0_println!("{:#x}", unwind_context_ptr);
crate::hcf();
}
#[lang = "eh_personality"]
#[unsafe(no_mangle)]
extern "C" fn rust_eh_personality() -> ! {
serial0_println!("Poisoned function `rust_eh_personality` was called.");
crate::hcf()
}
#[alloc_error_handler]
fn handle_alloc_error(layout: Layout) -> ! {
panic!("Alloc Error for layout {:?}", layout)
}
================================================
FILE: src/fs/devfs/fb.rs
================================================
use alloc::sync::Arc;
use spin::Once;
use crate::{
fs::{initramfs::get_root, opened_file::OpenFlags, File, FsNode, INode},
graphics::fb,
kerror,
mem::addr::VirtAddr,
userland::buffer::{UserBuffer, UserBufferMut, UserBufferReader, UserBufferWriter},
util::KResult,
};
pub static DEV_FB0: Once<Arc<FbDevice>> = Once::new();
pub fn init() {
let fb0 = Arc::new(FbDevice);
get_root()
.unwrap()
.root_dir()
.lookup("dev")
.unwrap()
.as_dir()
.unwrap()
.insert(INode::File(fb0.clone()));
DEV_FB0.call_once(|| fb0);
}
pub struct FbDevice;
impl FsNode for FbDevice {
fn get_name(&self) -> alloc::string::String {
"fb0".into()
}
}
impl File for FbDevice {
fn read(&self, offset: usize, buf: UserBufferMut, _options: &OpenFlags) -> KResult<usize> {
assert_eq!(offset % 4, 0);
let buf_len = buf.len();
assert_eq!(buf_len % 4, 0);
let mut writer = UserBufferWriter::from_buf(buf);
let mut fb = fb();
let mem = fb.frame_mut();
let start = offset / 4;
let len = buf_len / 4;
let end = (start + len).min(mem.len());
let mem = mem[start..end].iter().flat_map(|pixel| pixel.to_le_bytes());
for byte in mem {
writer.write(byte)?;
}
Ok((end - start) * 4)
}
fn write(&self, offset: usize, buf: UserBuffer<'_>, _options: &OpenFlags) -> KResult<usize> {
assert_eq!(offset % 4, 0);
let buf_len = buf.len();
assert_eq!(buf_len % 4, 0);
let mut reader = UserBufferReader::from_buf(buf);
let mut fb = fb();
let mem = fb.frame_mut();
let mut i = 0;
while (offset / 4 + i) < mem.len() && i < buf_len / 4 {
let pixel = reader.read::<u32>()?;
// let pixel = u32::from_le_bytes([byte0, byte1, byte2, byte3]);
mem[offset / 4 + i] = pixel;
i += 1;
}
fb.present();
Ok(i * 4)
}
fn ioctl(&self, cmd: usize, arg: usize) -> KResult<isize> {
const FBIOGET_VSCREENINFO: usize = 0x4600;
// const FBIOGET_FSCREENINFO: usize = 0x4602;
match cmd {
FBIOGET_VSCREENINFO => {
let fb = fb();
let info = FbVarScreenInfo {
xres: fb.width() as u32,
yres: fb.height() as u32,
xres_virtual: fb.width() as u32,
yres_virtual: fb.height() as u32,
bpp: fb.bpp() as u32,
..FbVarScreenInfo::default()
};
unsafe { VirtAddr::new(arg).write_user(info) }?;
}
// FBIOGET_FSCREENINFO => {
// }
_ => return Err(kerror!(EINVAL, "ioctl(): unknown cmd")),
}
Ok(0)
}
}
#[repr(C)]
#[derive(Clone, Copy, Default)]
struct FbBitField {
offset: u32,
length: u32,
msb_right: u32,
}
#[repr(C)]
#[derive(Clone, Copy, Default)]
struct FbVarScreenInfo {
xres: u32,
yres: u32,
xres_virtual: u32,
yres_virtual: u32,
xoffset: u32,
yoffset: u32,
bpp: u32,
grayscale: u32,
red: FbBitField,
green: FbBitField,
blue: FbBitField,
transp: FbBitField,
nonstd: u32,
activate: u32,
height_mm: u32,
width_mm: u32,
accel_flags: u32,
pixclock: u32,
left_margin: u32,
right_margin: u32,
upper_margin: u32,
lower_margin: u32,
hsync_len: u32,
vsync_len: u32,
sync: u32,
vmode: u32,
rotate: u32,
colorspace: u32,
reserved: [u32; 4],
}
================================================
FILE: src/fs/devfs/input.rs
================================================
//! TODO: make this more like an actual linux keyboard device file
use alloc::sync::Arc;
use pc_keyboard::{KeyEvent, KeyState};
use spin::{mutex::SpinMutex, Once};
use crate::{
fs::{initramfs::get_root, opened_file::OpenFlags, File, FsNode, INode},
userland::buffer::{UserBufferMut, UserBufferWriter},
util::KResult,
};
pub static KBD_DEVICE: Once<Arc<KbdDevice>> = Once::new();
pub fn init() {
let kbd = Arc::new(KbdDevice::new());
get_root()
.unwrap()
.root_dir()
.lookup("dev")
.unwrap()
.as_dir()
.unwrap()
.insert(INode::File(kbd.clone()));
KBD_DEVICE.call_once(|| kbd);
}
pub struct KbdDevice {
keys_pressed: Arc<SpinMutex<[u8; 256]>>,
}
impl KbdDevice {
pub fn new() -> Self {
Self {
keys_pressed: Arc::new(SpinMutex::new([0u8; 256])),
}
}
pub fn handle_kbd_irq(&self, key_evt: &KeyEvent) {
match key_evt.state {
KeyState::Down => self.keys_pressed.lock()[key_evt.code as u8 as usize] = 1,
KeyState::Up => self.keys_pressed.lock()[key_evt.code as u8 as usize] = 0,
_ => {}
}
}
}
impl Default for KbdDevice {
fn default() -> Self {
Self::new()
}
}
impl FsNode for KbdDevice {
fn get_name(&self) -> alloc::string::String {
"kbd".into()
}
}
impl File for KbdDevice {
fn read(&self, _offset: usize, buf: UserBufferMut, _options: &OpenFlags) -> KResult<usize> {
let mut writer = UserBufferWriter::from_buf(buf);
let keys = *self.keys_pressed.lock();
writer.write(keys)
}
}
================================================
FILE: src/fs/devfs/mod.rs
================================================
pub mod fb;
pub mod input;
pub mod null;
pub mod socket;
pub mod tty;
pub mod urandom;
pub fn init() {
self::tty::init();
self::null::init();
self::urandom::init();
self::fb::init();
self::input::init();
self::socket::init();
}
================================================
FILE: src/fs/devfs/null.rs
================================================
use alloc::{borrow::ToOwned, sync::Arc};
use spin::Once;
use crate::{
fs::{
initramfs::get_root, opened_file::OpenFlags, File, FileMode, FsNode, INode, Stat, S_IFCHR,
},
userland::buffer::UserBufferWriter,
};
static DEV_NULL: Once<Arc<NullDevice>> = Once::new();
pub fn init() {
let null = Arc::new(NullDevice);
get_root()
.unwrap()
.root_dir()
.lookup("dev")
.unwrap()
.as_dir()
.unwrap()
.insert(INode::File(null.clone()));
DEV_NULL.call_once(|| null);
}
pub struct NullDevice;
impl FsNode for NullDevice {
fn get_name(&self) -> alloc::string::String {
"null".to_owned()
}
}
impl File for NullDevice {
fn write(
&self,
_offset: usize,
buf: crate::userland::buffer::UserBuffer<'_>,
_options: &OpenFlags,
) -> crate::util::KResult<usize> {
Ok(buf.len())
}
fn read(
&self,
_offset: usize,
buf: crate::userland::buffer::UserBufferMut,
_options: &OpenFlags,
) -> crate::util::KResult<usize> {
let mut writer = UserBufferWriter::from_buf(buf);
writer.write_bytes(&[0x05])?; // EOF
Ok(writer.written_len())
}
fn stat(&self) -> crate::util::KResult<Stat> {
Ok(Stat {
inode_no: 4,
mode: FileMode(S_IFCHR),
..Stat::zeroed()
})
}
}
================================================
FILE: src/fs/devfs/socket.rs
================================================
use core::sync::atomic::{AtomicUsize, Ordering};
use crate::{
fs::{File, FsNode},
kerror,
mem::addr::VirtAddr,
util::{KError, KResult},
};
pub fn init() {}
#[repr(C)]
#[non_exhaustive]
pub enum Domain {
Unix = 0,
Inet = 2,
}
impl TryFrom<usize> for Domain {
type Error = KError<'static>;
fn try_from(value: usize) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::Unix),
2 => Ok(Self::Inet),
_ => Err(kerror!(EINVAL, "invalid socket domain")),
}
}
}
#[repr(C)]
#[non_exhaustive]
pub enum SocketType {
Stream = 1,
Datagram = 2,
Raw = 3,
SeqPacket = 5,
Packet = 10,
}
impl TryFrom<usize> for SocketType {
type Error = KError<'static>;
fn try_from(value: usize) -> Result<Self, Self::Error> {
match value {
1 => Ok(Self::Stream),
2 => Ok(Self::Datagram),
3 => Ok(Self::Raw),
5 => Ok(Self::SeqPacket),
10 => Ok(Self::Packet),
_ => Err(kerror!(EINVAL, "invalid socket type")),
}
}
}
#[repr(C)]
#[non_exhaustive]
pub enum Protocol {
Ipv4 = 4,
Tcp = 6,
Udp = 17,
}
impl TryFrom<usize> for Protocol {
type Error = KError<'static>;
fn try_from(value: usize) -> Result<Self, Self::Error> {
match value {
4 => Ok(Self::Ipv4),
6 => Ok(Self::Tcp),
17 => Ok(Self::Udp),
_ => Err(kerror!(EINVAL, "invalid socket protocol")),
}
}
}
pub struct Socket {
pub id: usize,
// pub handle: SocketHandle,
pub domain: Domain,
pub typ: SocketType,
pub protocol: Protocol,
}
static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
impl Socket {
pub fn alloc_id() -> usize {
NEXT_ID.fetch_add(1, Ordering::SeqCst)
}
// pub fn new() -> Self {
// Self {
// id: Self::alloc_id(),
// handle: (),
// domain: (),
// typ: (),
// protocol: (),
// }
// }
}
impl FsNode for Socket {
fn get_name(&self) -> alloc::string::String {
alloc::format!("socket{}", self.id)
}
}
#[derive(Clone, Copy)]
#[repr(C, packed)]
pub struct SockAddrInet {
family: u16,
port: [u8; 2],
addr: [u8; 4],
zero: [u8; 8],
}
pub fn read_sockaddr(addr: VirtAddr, len: usize) -> KResult<SockAddrInet> {
let family = unsafe { addr.read_volatile::<u16>()? };
let sockaddr = match Domain::try_from(family as usize)? {
Domain::Inet => {
if len < core::mem::size_of::<SockAddrInet>() {
return Err(kerror!(EINVAL, "read_sockaddr(): buffer overflow"));
}
unsafe { addr.read_volatile::<SockAddrInet>()? }
}
Domain::Unix => {
todo!()
}
};
Ok(sockaddr)
}
pub fn write_sockaddr(
sockaddr: SockAddrInet,
dst: Option<VirtAddr>,
socklen: Option<VirtAddr>,
) -> KResult<()> {
if let Some(dst) = dst {
unsafe { dst.write_volatile(sockaddr) }?;
}
if let Some(socklen) = socklen {
unsafe { socklen.write_volatile(core::mem::size_of::<SockAddrInet>() as u32) }?;
}
Ok(())
}
impl File for Socket {
fn ioctl(&self, cmd: usize, _arg: usize) -> KResult<isize> {
const FIONBIO: usize = 0x5421;
match cmd {
FIONBIO => {
// todo: set/clear non block flag
}
_ => return Err(kerror!(EINVAL, "ioctl(): unknown cmd for socket")),
}
Ok(0)
}
}
================================================
FILE: src/fs/devfs/tty.rs
================================================
use core::fmt::Debug;
use alloc::{
borrow::ToOwned,
string::String,
sync::{Arc, Weak},
vec::Vec,
};
use bitflags::bitflags;
use spin::Once;
use crate::{
fb_print,
graphics::{self, render_text_buf},
kerror,
mem::addr::VirtAddr,
task::{current_task, get_scheduler, group::TaskGroup, signal::SIGINT, wait_queue::WaitQueue},
userland::buffer::{UserBuffer, UserBufferMut, UserBufferReader, UserBufferWriter},
util::{
ctypes::c_int, errno::Errno, error::KResult, lock::IrqMutex, ringbuffer::RingBuffer, KError,
},
vga_text,
};
use crate::fs::{
initramfs::{dir::InitRamFsDir, get_root},
opened_file::OpenFlags,
path::Path,
File, FileMode, FileRef, FsNode, INode, PollStatus, Stat, POLL_WAIT_QUEUE, S_IFCHR,
};
pub static TTY: Once<Arc<Tty>> = Once::new();
pub fn init() {
let tty = Arc::new(Tty::new("tty"));
TTY.call_once(|| tty.clone());
get_root()
.unwrap()
.lookup(Path::new("dev"), true)
.unwrap()
.as_dir()
.unwrap()
.insert(INode::File(tty));
}
bitflags! {
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct LFlag: u32 {
const ICANON = 0o0000002;
const ECHO = 0o0000010;
}
}
impl Default for LFlag {
fn default() -> Self {
Self::all()
}
}
bitflags! {
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct IFlag: u32 {
const IGNBRK = 0o0000001;
const BRKINT = 0o0000002;
const IGNPAR = 0o0000004;
const PARMRK = 0o0000010;
const INPCK = 0o0000020;
const ISTRIP = 0o0000040;
const INLCR = 0o0000100;
const IGNCR = 0o0000200;
const ICRNL = 0o0000400;
const IUCLC = 0o0001000;
const IXON = 0o0002000;
const IXANY = 0o0004000;
const IXOFF = 0o0010000;
const IMAXBEL = 0o0020000;
const IUTF8 = 0o0040000;
}
}
impl Default for IFlag {
fn default() -> Self {
Self::ICRNL
}
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct Termios {
iflag: IFlag,
oflag: u32,
cflag: u32,
lflag: LFlag,
cc: [u8; 0],
reserved: [u32; 3],
ispeed: u32,
ospeed: u32,
}
impl Termios {
pub fn is_cooked(&self) -> bool {
self.lflag.contains(LFlag::ICANON)
}
}
impl Default for Termios {
fn default() -> Self {
Termios {
iflag: IFlag::ICRNL,
lflag: LFlag::ICANON | LFlag::ECHO,
oflag: 0,
cflag: 0,
cc: [0; 0],
reserved: [0; 3],
ispeed: 0,
ospeed: 0,
}
}
}
impl Debug for Termios {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Termios")
.field("iflag", &self.iflag)
.field("lflag", &self.lflag)
.finish()
}
}
pub enum LineControl {
Backspace,
Echo(u8),
}
pub struct LineDiscipline {
wait_queue: WaitQueue,
current_line: IrqMutex<Vec<u8>>,
buf: IrqMutex<RingBuffer<u8, 4096>>,
termios: IrqMutex<Termios>,
foreground_group: IrqMutex<Weak<IrqMutex<TaskGroup>>>,
}
impl LineDiscipline {
pub fn new() -> Self {
Self {
wait_queue: WaitQueue::new(),
current_line: IrqMutex::new(Vec::new()),
buf: IrqMutex::new(RingBuffer::new()),
termios: IrqMutex::new(Termios::default()),
foreground_group: IrqMutex::new(Weak::new()),
}
}
pub fn is_readable(&self) -> bool {
self.buf.lock().is_readable()
}
pub fn is_writable(&self) -> bool {
self.buf.lock().is_writable()
}
pub fn foreground_group(&self) -> Option<Arc<IrqMutex<TaskGroup>>> {
self.foreground_group.lock().upgrade()
}
pub fn set_foreground_group(&self, pg: Weak<IrqMutex<TaskGroup>>) {
*self.foreground_group.lock() = pg;
}
fn _is_current_foreground(&self) -> bool {
let pg = &*self.foreground_group.lock();
current_task().belongs_to_group(pg) || pg.upgrade().is_none()
}
pub fn write<F>(&self, buf: UserBuffer<'_>, callback: F) -> KResult<usize>
where
F: Fn(LineControl),
{
let termios = self.termios.lock();
let mut current_line = self.current_line.lock();
let mut ringbuf = self.buf.lock();
let mut written_len = 0;
let mut reader = UserBufferReader::from_buf(buf);
while reader.remaining_len() > 0 {
let mut tmp = [0; 1];
let copied_len = reader.read_bytes(&mut tmp)?;
for ch in &tmp.as_slice()[..copied_len] {
match ch {
0x03 if termios.is_cooked() => {
if let Some(pg) = self.foreground_group() {
pg.lock().signal(SIGINT);
}
}
0x08 if termios.is_cooked() => {
if !current_line.is_empty() {
current_line.pop();
callback(LineControl::Backspace);
}
}
b'\r' if termios.iflag.contains(IFlag::ICRNL) => {
current_line.push(b'\n');
ringbuf.push_slice(¤t_line);
current_line.clear();
if termios.lflag.contains(LFlag::ECHO) {
callback(LineControl::Echo(b'\r'));
callback(LineControl::Echo(b'\n'));
}
}
b'\n' => {
current_line.push(b'\n');
ringbuf.push_slice(¤t_line);
current_line.clear();
if termios.lflag.contains(LFlag::ECHO) {
callback(LineControl::Echo(b'\n'));
}
}
ch if termios.is_cooked() => {
if 0x20 <= *ch && *ch < 0x7f {
current_line.push(*ch);
if termios.lflag.contains(LFlag::ECHO) {
callback(LineControl::Echo(*ch));
}
}
}
_ => {
ringbuf.push(*ch).ok();
}
}
written_len += 1;
}
}
get_scheduler().wake_all(&self.wait_queue);
Ok(written_len)
}
pub fn read(&self, dst: UserBufferMut<'_>, options: &OpenFlags) -> KResult<usize> {
let mut writer = UserBufferWriter::from_buf(dst);
let timeout = if options.contains(OpenFlags::O_NONBLOCK) {
Some(0)
} else {
None
};
self.wait_queue.sleep_signalable_until(timeout, || {
// todo: figure out how to get this working
// if !self.is_current_foreground() {
// return Ok(None)
// }
let mut buf_lock = self.buf.lock();
while writer.remaining_len() > 0 {
if let Some(slice) = buf_lock.pop_slice(writer.remaining_len()) {
writer.write_bytes(slice)?;
} else {
break;
}
}
if writer.written_len() > 0 {
Ok(Some(writer.written_len()))
} else {
Ok(None)
}
})
}
}
impl Default for LineDiscipline {
fn default() -> Self {
Self::new()
}
}
pub struct Tty {
name: String,
discipline: LineDiscipline,
}
impl Tty {
pub fn new(name: &str) -> Self {
Self {
name: name.to_owned(),
discipline: LineDiscipline::new(),
}
}
pub fn set_cooked_mode(&self, cooked: bool) {
if cooked {
self.discipline.termios.lock().lflag |= LFlag::ICANON | LFlag::ECHO;
} else {
self.discipline.termios.lock().lflag &= !(LFlag::ICANON | LFlag::ECHO);
}
}
pub fn input_char(&self, ch: u8) {
self.discipline
.write(UserBuffer::from_slice(&[ch]), |ctrl| match ctrl {
LineControl::Backspace => {
// serial1_print!("\x08 \x08");
graphics::backspace();
}
LineControl::Echo(ch) => {
self.write(0, UserBuffer::from_slice(&[ch]), &OpenFlags::empty())
.ok();
}
})
.ok();
}
pub fn set_foreground_group(&self, pg: Weak<IrqMutex<TaskGroup>>) {
self.discipline.set_foreground_group(pg)
}
}
impl FsNode for Tty {
fn get_name(&self) -> String {
self.name.clone()
}
}
const TCGETS: usize = 0x5401;
const TCSETS: usize = 0x5402;
const TCSETSW: usize = 0x5403;
const TIOCGPGRP: usize = 0x540f;
const TIOCSPGRP: usize = 0x5410;
const TIOCGWINSZ: usize = 0x5413;
#[repr(C)]
#[derive(Copy, Clone)]
struct WinSize {
ws_row: u16,
ws_col: u16,
ws_xpixel: u16,
ws_ypixel: u16,
}
impl File for Tty {
fn ioctl(&self, cmd: usize, arg: usize) -> KResult<isize> {
match cmd {
TCGETS => {
let termios = *self.discipline.termios.lock();
let arg = VirtAddr::new(arg);
unsafe { arg.write_user(termios) }?;
}
TCSETS | TCSETSW => {
let arg = VirtAddr::new(arg);
let termios = unsafe { arg.read_user::<Termios>()? };
*self.discipline.termios.lock() = termios;
}
TIOCGPGRP => {
let group = self
.discipline
.foreground_group()
.unwrap_or(current_task().group.borrow().upgrade().unwrap());
let id = group.lock().pgid();
let arg = VirtAddr::new(arg);
unsafe { arg.write_user(id) }?;
}
TIOCSPGRP => {
let arg = VirtAddr::new(arg);
let pgid = unsafe { arg.read_user::<c_int>()? };
let pg = get_scheduler().find_or_create_group(pgid);
self.discipline.set_foreground_group(Arc::downgrade(&pg));
}
TIOCGWINSZ => {
let winsize = WinSize {
ws_row: vga_text::BUFFER_HEIGHT as u16,
ws_col: vga_text::BUFFER_WIDTH as u16,
ws_xpixel: 0,
ws_ypixel: 0,
};
let arg = VirtAddr::new(arg);
unsafe { arg.write_user(winsize) }?;
}
_ => return Err(kerror!(ENOTTY, "ioctl(): command not found")),
}
Ok(0)
}
fn stat(&self) -> KResult<Stat> {
Ok(Stat {
inode_no: 3,
mode: FileMode::new(S_IFCHR | 0o666),
..Stat::zeroed()
})
}
fn read(&self, _offset: usize, buf: UserBufferMut, options: &OpenFlags) -> KResult<usize> {
let read_len = self.discipline.read(buf, options);
match read_len {
Ok(read_len) => {
if read_len > 0 {
get_scheduler().wake_all(&POLL_WAIT_QUEUE);
}
Ok(read_len)
}
Err(KError { errno, .. })
if options.contains(OpenFlags::O_NONBLOCK) && errno == Some(Errno::EINTR) =>
{
Ok(0)
}
Err(e) => Err(e),
}
}
fn write(&self, _offset: usize, buf: UserBuffer<'_>, _options: &OpenFlags) -> KResult<usize> {
// let mut tmp = [0; 1];
// let mut total_len = 0;
let reader = UserBufferReader::from_buf(buf);
let total_len = parse(reader)?;
if total_len > 0 {
render_text_buf();
get_scheduler().wake_all(&POLL_WAIT_QUEUE);
}
Ok(total_len)
}
fn poll(&self) -> KResult<PollStatus> {
let mut status = PollStatus::empty();
// if self.discipline.is_readable() {
status |= PollStatus::POLLIN;
// }
// if self.discipline.is_writable() {
status |= PollStatus::POLLOUT;
// }
Ok(status)
}
}
fn parse(mut reader: UserBufferReader) -> KResult<usize> {
let mut bytes = alloc::vec![0u8; reader.remaining_len()];
reader.read_bytes(&mut bytes)?;
let mut escape_codes = bytes.split(|b| *b == 0x1b);
if bytes[0] != 0x1b {
// print until the first escape code
if let Some(next) = escape_codes.next() {
fb_print!("{}", core::str::from_utf8(next).unwrap());
} else {
return Ok(0);
}
}
for chunk in escape_codes {
if chunk.is_empty() {
continue;
}
if chunk[0] != b'[' {
continue;
}
let chunk = &chunk[1..];
// iterate through the chunk until we find one of the ANSI "functions"
// const ANSI_FUNCTIONS: &[u8] = b"ABCDEFGHJKSTsufm";
const ANSI_FUNCTIONS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
let res = chunk
.iter()
.enumerate()
.find(|(_i, byte)| ANSI_FUNCTIONS.contains(*byte));
let (f_idx, function) = if let Some(res) = res {
res
} else {
unreachable!()
};
// get its arguments, if any
let arguments = chunk[..f_idx]
.split(|byte| *byte == b';')
.collect::<Vec<&[u8]>>();
let parse_usize = |arg: &[u8]| core::str::from_utf8(arg).unwrap().parse::<usize>();
let (x, y) = graphics::cursor_xy();
match *function {
b'A' => {
let n = parse_usize(arguments[0]).unwrap_or(1);
graphics::set_cursor_y(y.saturating_sub(n));
}
b'B' => {
let n = parse_usize(arguments[0]).unwrap_or(1);
graphics::set_cursor_y(y.saturating_add(n));
}
b'C' => {
let n = parse_usize(arguments[0]).unwrap_or(1);
graphics::set_cursor_x(x.saturating_add(n));
}
b'D' => {
let n = parse_usize(arguments[0]).unwrap_or(1);
graphics::set_cursor_x(x.saturating_sub(n));
}
b'E' => {
let n = parse_usize(arguments[0]).unwrap_or(1);
graphics::set_cursor_x(0);
graphics::set_cursor_y(y.saturating_add(n));
}
b'F' => {
let n = parse_usize(arguments[0]).unwrap_or(1);
graphics::set_cursor_x(0);
graphics::set_cursor_y(y.saturating_sub(n));
}
b'G' | b'f' => {
let n = parse_usize(arguments[0]).unwrap();
graphics::set_cursor_x(n);
}
b'H' => {
if arguments[0].is_empty() {
graphics::set_cursor_xy((0, 0));
} else {
let n = parse_usize(arguments[0]).unwrap_or(0);
let m = parse_usize(arguments[1]).unwrap_or(0);
graphics::set_cursor_xy((n, m));
}
}
b'J' => {
if arguments.is_empty() {
graphics::clear_until_end();
} else {
let n = parse_usize(arguments[0]).unwrap_or(0);
match n {
0 => graphics::clear_until_end(),
1 => graphics::clear_until_beginning(),
2 => graphics::clear_screen(),
3 => todo!("erase saved lines"),
_ => unimplemented!(),
}
}
}
b'K' => {
if arguments.is_empty() {
graphics::clear_until_eol();
} else {
let n = parse_usize(arguments[0]).unwrap_or(0);
match n {
0 => graphics::clear_until_eol(),
1 => graphics::clear_from_bol(),
2 => graphics::clear_line(),
_ => unimplemented!(),
}
}
}
b'S' => {
todo!("scroll up by N lines")
}
b'T' => {
todo!("scroll down by N ines")
}
b's' => {
todo!("save cursor position")
}
b'u' => {
todo!("restore cursor postion")
}
b'm' => {
// let arg0 = parse_usize(arguments[0]).unwrap() as u8;
// match arg0 {
// 0 => graphics::set_color_code(ColorCode::new(Color::White, Color::Black)),
// 1 => {} // bold
// 3 => {} // italic
// 4 => {} // underline
// 30..=37 => {
// let color = graphics::get_color_code();
// graphics::set_color_code(ColorCode::new(
// unsafe { core::mem::transmute(arg0 - 30) },
// color.background(),
// ));
// }
// 40..=47 => {
// let color = graphics::get_color_code();
// graphics::set_color_code(ColorCode::new(color.foreground(), unsafe {
// core::mem::transmute(arg0 - 40)
// }));
// }
// 90..=97 => {
// todo!("bright foreground color")
// }
// 100..=107 => {
// todo!("bright background color")
// }
// _ => todo!(
// "Unknown ANSI function: {}",
// core::str::from_utf8(chunk).unwrap()
// ),
// }
}
_function if chunk[0] == b'?' => {
let n = parse_usize(&arguments[0][1..]).unwrap();
match n {
/*
Save cursor as in DECSC, xterm. After
saving the cursor, switch to the Alternate Screen Buffer,
clearing it first.
*/
1049 => {}
n => unimplemented!("Unknown ANSI extension function: {}", n),
}
}
_ => {
unimplemented!(
"Unknown ANSI function: {}",
core::str::from_utf8(chunk).unwrap()
)
}
}
fb_print!("{}", core::str::from_utf8(&chunk[f_idx + 1..]).unwrap());
}
Ok(reader.read_len())
}
pub struct PtyMaster {
wait_queue: WaitQueue,
buf: IrqMutex<Vec<u8>>,
discipline: LineDiscipline,
}
impl PtyMaster {
pub fn new() -> KResult<(Arc<PtyMaster>, Arc<PtySlave>)> {
let master = Arc::new(PtyMaster {
wait_queue: WaitQueue::new(),
buf: IrqMutex::new(Vec::new()),
discipline: LineDiscipline::new(),
});
let slave = Arc::new(PtySlave::new(master.clone()));
Ok((master, slave))
}
}
impl FsNode for PtyMaster {
fn get_name(&self) -> String {
"tty0".to_owned()
}
}
impl File for PtyMaster {
fn read(&self, _offset: usize, buf: UserBufferMut<'_>, options: &OpenFlags) -> KResult<usize> {
let mut writer = UserBufferWriter::from_buf(buf);
let timeout = if options.contains(OpenFlags::O_NONBLOCK) {
Some(0)
} else {
None
};
let read_len = self.wait_queue.sleep_signalable_until(timeout, || {
let mut buf_lock = self.buf.lock();
if buf_lock.is_empty() {
return Ok(None);
}
let copy_len = core::cmp::min(buf_lock.len(), writer.remaining_len());
writer.write_bytes(&buf_lock[..copy_len])?;
buf_lock.drain(..copy_len);
Ok(Some(copy_len))
})?;
if read_len > 0 {
get_scheduler().wake_all(&POLL_WAIT_QUEUE);
}
Ok(read_len)
}
fn write(&self, _offset: usize, buf: UserBuffer<'_>, _options: &OpenFlags) -> KResult<usize> {
let written_len = self.discipline.write(buf, |ctrl| {
let mut master_buf = self.buf.lock();
match ctrl {
LineControl::Backspace => {
master_buf.extend_from_slice(b"\x08 \x08");
}
LineControl::Echo(ch) => {
master_buf.push(ch);
}
}
})?;
if written_len > 0 {
get_scheduler().wake_all(&POLL_WAIT_QUEUE);
}
Ok(written_len)
}
fn ioctl(&self, cmd: usize, _arg: usize) -> KResult<isize> {
log::warn!("ioctl(): unknown cmd for PtyMaster ({:#x})", cmd);
Ok(0)
}
fn stat(&self) -> KResult<Stat> {
Ok(Stat {
inode_no: 5,
mode: FileMode::new(S_IFCHR | 0o666),
..Stat::zeroed()
})
}
fn poll(&self) -> KResult<PollStatus> {
let mut status = PollStatus::empty();
if !self.buf.lock().is_empty() {
status |= PollStatus::POLLIN;
}
if self.discipline.is_writable() {
status |= PollStatus::POLLOUT;
}
Ok(status)
}
}
pub struct PtySlave {
master: Arc<PtyMaster>,
}
impl PtySlave {
pub fn new(master: Arc<PtyMaster>) -> Self {
Self { master }
}
}
impl FsNode for PtySlave {
fn get_name(&self) -> String {
"ttyS0".to_owned()
}
}
impl File for PtySlave {
fn read(&self, _offset: usize, buf: UserBufferMut, options: &OpenFlags) -> KResult<usize> {
let read_len = self.master.discipline.read(buf, options)?;
if read_len > 0 {
get_scheduler().wake_all(&POLL_WAIT_QUEUE);
}
Ok(read_len)
}
fn write(&self, _offset: usize, buf: UserBuffer<'_>, _options: &OpenFlags) -> KResult<usize> {
let mut written_len = 0;
let mut master_buf = self.master.buf.lock();
let mut reader = UserBufferReader::from_buf(buf);
while reader.remaining_len() > 0 {
let mut tmp = [0; 1];
let copied_len = reader.read_bytes(&mut tmp)?;
for ch in &tmp[..copied_len] {
match *ch {
b'\n' => {
master_buf.push(b'\r');
master_buf.push(b'\n');
}
_ => {
master_buf.push(*ch);
}
}
}
written_len += copied_len;
}
if written_len > 0 {
get_scheduler().wake_all(&POLL_WAIT_QUEUE);
}
Ok(written_len)
}
fn stat(&self) -> KResult<Stat> {
Ok(Stat {
inode_no: 6,
mode: FileMode::new(S_IFCHR | 0o666),
..Stat::zeroed()
})
}
fn ioctl(&self, cmd: usize, _arg: usize) -> KResult<isize> {
const TIOCSPTLCK: usize = 0x40045431;
match cmd {
TIOCSPTLCK => Ok(0),
_ => {
log::warn!("ioctl(): unknown cmd for PtySlave ({:#x})", cmd);
Ok(0)
}
}
}
fn poll(&self) -> KResult<PollStatus> {
let mut status = PollStatus::empty();
if self.master.discipline.is_readable() {
status |= PollStatus::POLLIN;
}
status |= PollStatus::POLLOUT;
Ok(status)
}
}
pub struct Ptmx {
pts_dir: Arc<InitRamFsDir>,
}
impl Ptmx {
pub fn new(pts_dir: Arc<InitRamFsDir>) -> Self {
Self { pts_dir }
}
}
impl FsNode for Ptmx {
fn get_name(&self) -> String {
todo!()
}
}
impl File for Ptmx {
fn open(&self, _options: &OpenFlags) -> KResult<Option<FileRef>> {
let (master, slave) = PtyMaster::new()?;
self.pts_dir.add_file(slave);
Ok(Some(master as FileRef))
}
fn stat(&self) -> KResult<Stat> {
Ok(Stat {
inode_no: 4,
mode: FileMode::new(S_IFCHR | 0o666),
..Stat::zeroed()
})
}
fn read(&self, _offset: usize, _buf: UserBufferMut, _options: &OpenFlags) -> KResult<usize> {
unreachable!()
}
fn write(&self, _offset: usize, _buf: UserBuffer<'_>, _options: &OpenFlags) -> KResult<usize> {
unreachable!()
}
fn poll(&self) -> KResult<PollStatus> {
Ok(PollStatus::empty())
}
}
================================================
FILE: src/fs/devfs/urandom.rs
================================================
use alloc::sync::Arc;
use x86::random::rdrand_slice;
use crate::{
fs::{initramfs::get_root, path::Path, File, FsNode, INode},
userland::buffer::UserBufferWriter,
};
pub fn init() {
get_root()
.unwrap()
.lookup(Path::new("dev"), true)
.unwrap()
.as_dir()
.unwrap()
.insert(INode::File(Arc::new(URandom)));
}
pub struct URandom;
impl FsNode for URandom {
fn get_name(&self) -> alloc::string::String {
"urandom".into()
}
}
impl File for URandom {
fn read(
&self,
_offset: usize,
buf: crate::userland::buffer::UserBufferMut,
_options: &crate::fs::opened_file::OpenFlags,
) -> crate::util::KResult<usize> {
let mut bytes = alloc::vec![0u8; buf.len()];
unsafe {
rdrand_slice(&mut bytes);
}
let mut writer = UserBufferWriter::from_buf(buf);
writer.write_bytes(&bytes)?;
Ok(writer.written_len())
}
}
================================================
FILE: src/fs/initramfs/dir.rs
================================================
use alloc::{
string::String,
sync::{Arc, Weak},
vec::Vec,
};
use crate::{
fs::{
alloc_inode_no, DirEntry, Directory, FileMode, FileRef, FileType, FsNode, INode, Stat,
S_IFDIR,
},
kerror,
util::{lock::IrqMutex, KResult},
};
pub struct DirInner {
pub children: Vec<INode>,
pub stat: Stat,
pub name: String,
}
pub struct InitRamFsDir {
pub(super) parent: Weak<InitRamFsDir>,
pub(super) inner: IrqMutex<DirInner>,
}
impl InitRamFsDir {
pub fn new(name: String, inode_no: usize) -> InitRamFsDir {
InitRamFsDir {
parent: Weak::new(),
inner: IrqMutex::new(DirInner {
name,
children: Vec::new(),
stat: Stat {
inode_no,
mode: FileMode::new(S_IFDIR | 0o755),
..Stat::zeroed()
},
}),
}
}
pub fn add_dir(&self, name: String) -> Arc<InitRamFsDir> {
let dir = Arc::new(InitRamFsDir::new(name, alloc_inode_no()));
self.inner.lock().children.push(INode::Dir(dir.clone()));
dir
}
pub fn add_file(&self, file: FileRef) {
self.inner.lock().children.push(INode::File(file.clone()));
}
pub fn parent_dir(&self) -> Option<Arc<InitRamFsDir>> {
self.parent.upgrade()
}
}
impl Directory for InitRamFsDir {
fn insert(&self, inode: INode) {
self.inner.lock().children.push(inode);
}
fn lookup(&self, name: &str) -> KResult<INode> {
let inode = self
.inner
.lock()
.children
.iter()
.find(|child| child.get_name() == *name)
.cloned()
.ok_or(kerror!(ENOENT, "lookup(): not found"))?;
Ok(inode)
}
fn stat(&self) -> KResult<Stat> {
Ok(self.inner.lock().stat)
}
fn readdir(&self, index: usize) -> KResult<Option<crate::fs::DirEntry>> {
let entry = self
.inner
.lock()
.children
.get(index)
.map(|entry| match entry {
INode::Pipe(_) => unreachable!("Pipes should be in PipeFs"),
INode::Dir(dir) => DirEntry {
inode_no: dir.stat().unwrap().inode_no,
file_type: FileType::Directory,
name: dir.get_name(),
},
INode::File(file) => DirEntry {
inode_no: file.stat().unwrap().inode_no,
file_type: FileType::Directory,
name: file.get_name(),
},
INode::Symlink(link) => DirEntry {
inode_no: link.stat().unwrap().inode_no,
file_type: FileType::Link,
name: link.get_name(),
},
});
Ok(entry)
}
fn unlink(&self, name: &str) -> KResult<()> {
self.inner
.lock()
.children
.retain(|child| child.get_name() != name);
Ok(())
}
}
impl FsNode for InitRamFsDir {
fn get_name(&self) -> String {
self.inner.lock().name.clone()
}
}
================================================
FILE: src/fs/initramfs/file.rs
================================================
use alloc::{string::String, vec, vec::Vec};
use crate::{
fs::{opened_file::OpenFlags, File, FileMode, FsNode, Stat, S_IFREG},
userland::buffer::{UserBuffer, UserBufferMut, UserBufferReader, UserBufferWriter},
util::{lock::IrqMutex, KResult},
};
pub struct InitRamFsFile {
pub name: IrqMutex<String>,
pub(super) data: IrqMutex<Vec<u8>>,
pub(super) stat: IrqMutex<Stat>,
}
impl InitRamFsFile {
pub fn new(name: String, inode_no: usize) -> InitRamFsFile {
InitRamFsFile {
name: IrqMutex::new(name),
data: IrqMutex::new(Vec::new()),
stat: IrqMutex::new(Stat {
inode_no,
mode: FileMode::new(S_IFREG | 0o644),
..Stat::zeroed()
}),
}
}
}
impl FsNode for InitRamFsFile {
fn get_name(&self) -> String {
self.name.lock().clone()
}
}
impl File for InitRamFsFile {
fn read(&self, offset: usize, buf: UserBufferMut<'_>, _options: &OpenFlags) -> KResult<usize> {
let lock = self.data.lock();
if offset > lock.len() {
return Ok(0);
}
let mut writer = UserBufferWriter::from_buf(buf);
writer.write_bytes(&lock[offset..])
}
fn write(&self, offset: usize, buf: UserBuffer<'_>, options: &OpenFlags) -> KResult<usize> {
let mut reader = UserBufferReader::from_buf(buf);
let mut data = self.data.lock();
let data_len = data.len();
if data.is_empty() {
data.extend_from_slice(&vec![0u8; offset + reader.remaining_len()]);
} else if offset + reader.remaining_len() < isize::MAX as usize
&& (offset + reader.remaining_len() > data_len || options.contains(OpenFlags::O_APPEND))
{
data.push(0u8);
}
reader.read_bytes(&mut data[offset..])
}
fn stat(&self) -> KResult<Stat> {
Ok(*self.stat.lock())
}
}
================================================
FILE: src/fs/initramfs/mod.rs
================================================
use core::iter::Peekable;
use alloc::{
string::{String, ToString},
sync::{Arc, Weak},
vec::Vec,
};
use spin::Once;
use crate::{
fs::{
DirRef, FileMode, FileSize, FsNode, INode, Stat,
initramfs::{
dir::{DirInner, InitRamFsDir},
file::InitRamFsFile,
symlink::InitRamFsSymlink,
},
path::{Components, Path, PathBuf},
},
kbail, kerror,
util::{IrqMutex, KResult, align_up},
};
use self::root::RootFs;
pub mod dir;
pub mod file;
pub mod root;
pub mod symlink;
pub struct ByteParser<'a> {
buffer: &'a [u8],
current: usize,
}
impl<'a> ByteParser<'a> {
pub fn new(buffer: &'a [u8]) -> ByteParser<'a> {
ByteParser { buffer, current: 0 }
}
pub fn remaining(&self) -> &[u8] {
&self.buffer[self.current..]
}
pub fn remaining_len(&self) -> usize {
self.buffer.len() - self.current
}
pub fn skip(&mut self, len: usize) -> KResult<()> {
if self.current + len > self.buffer.len() {
kbail!("skip(): out of bounds");
}
self.current += len;
Ok(())
}
pub fn skip_until_alignment(&mut self, align: usize) -> KResult<()> {
let next = align_up(self.current, align);
if next > self.buffer.len() {
kbail!("skip_until_alignment(): out of bounds");
}
self.current = next;
Ok(())
}
pub fn consume_bytes(&mut self, len: usize) -> KResult<&'a [u8]> {
if self.current + len > self.buffer.len() {
kbail!("consume_bytes(): out of bounds");
}
self.current += len;
Ok(&self.buffer[self.current - len..self.current])
}
}
fn parse_str_field(bytes: &[u8]) -> KResult<&str> {
core::str::from_utf8(bytes).map_err(|_e| kerror!("parse_str_field(): UTF-8 parsing error"))
}
fn parse_hex_field(bytes: &[u8]) -> KResult<usize> {
usize::from_str_radix(parse_str_field(bytes)?, 16)
.map_err(|_e| kerror!("parse_hex_field(): int parsing error"))
}
pub static INITRAM_FS: Once<Arc<InitRamFs>> = Once::new();
pub fn init() -> KResult<()> {
INITRAM_FS.call_once(|| {
let image = include_bytes!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/initramfs/initramfs.img"
));
if image.is_empty() {
panic!("initramfs not embedded");
}
log::info!("Parsing initramfs...");
Arc::new(InitRamFs::parse(image.as_slice()).expect("error parsing initramfs"))
});
Ok(())
}
pub fn get_root() -> Option<&'static RootFs> {
Some(&INITRAM_FS.get()?.root)
}
pub struct InitRamFs {
root: RootFs,
}
impl InitRamFs {
pub fn parse(fs_image: &[u8]) -> KResult<InitRamFs> {
let mut image = ByteParser::new(fs_image);
let mut n_files = 0;
let mut loaded_size = 0;
let root = Arc::new(InitRamFsDir::new(String::new(), 2));
loop {
if image.remaining_len() == 0 {
break;
}
let magic = image.consume_bytes(6).and_then(parse_hex_field)?;
if magic != 0x070701 {
log::error!(
"initramfs: invalid magic (expected {:#x}, got {:#x})",
0x070701,
magic
);
kbail!("parse(): invalid magic");
}
let ino = parse_hex_field(image.consume_bytes(8)?)?;
let mode = FileMode::new(parse_hex_field(image.consume_bytes(8)?)? as u32);
let _uid = parse_hex_field(image.consume_bytes(8)?)?;
let _gid = parse_hex_field(image.consume_bytes(8)?)?;
let _nlink = parse_hex_field(image.consume_bytes(8)?)?;
let _mtime = parse_hex_field(image.consume_bytes(8)?)?;
let filesize = parse_hex_field(image.consume_bytes(8)?)?;
let _dev_major = parse_hex_field(image.consume_bytes(8)?)?;
let _dev_minor = parse_hex_field(image.consume_bytes(8)?)?;
image.skip(16)?;
let path_len = parse_hex_field(image.consume_bytes(8)?)?;
if path_len == 0 {
kbail!("parse(): path_len is 0");
}
image.skip(8)?;
let mut path = parse_str_field(image.consume_bytes(path_len - 1)?)?;
if path.starts_with("./") {
path = &path[1..];
}
if path == "TRAILER!!!" {
break;
}
if path.is_empty() {
kbail!("parse(): empty path");
}
image.skip(1)?;
image.skip_until_alignment(4)?;
let components = Path::new(path).components().peekable();
fn walk(
mut components_peekable: Peekable<Components>,
dir: DirRef,
) -> Option<(DirRef, String)> {
let next = components_peekable.next();
next?;
if components_peekable.peek().is_none() {
return Some((dir, next.unwrap().to_string()));
}
let dir_clone = dir.clone();
if let Ok(child) = dir.lookup(next.unwrap()) {
if let INode::Dir(next_dir) = child {
return walk(components_peekable, next_dir.clone());
} else {
return Some((dir_clone, child.get_name()));
}
}
None
}
if path == "." {
image.skip_until_alignment(4)?;
continue;
}
let walk_result = walk(components, root.clone());
let (parent_dir, filename) = if let Some((parent, name)) = walk_result {
(parent, name)
} else {
image.consume_bytes(filesize)?;
image.skip_until_alignment(4)?;
continue;
};
let data = image.consume_bytes(filesize)?;
if mode.is_symbolic_link() {
let inode = INode::Symlink(Arc::new(InitRamFsSymlink {
name: filename.clone(),
dst: PathBuf::from(core::str::from_utf8(data).unwrap()),
stat: Stat {
inode_no: ino,
mode,
..Stat::zeroed()
},
}));
parent_dir.insert(inode);
} else if mode.is_directory() {
let inode = INode::Dir(Arc::new(InitRamFsDir {
parent: Weak::new(),
inner: IrqMutex::new(DirInner {
children: Vec::new(),
stat: Stat {
inode_no: ino,
mode,
..Stat::zeroed()
},
name: filename.clone(),
}),
}));
parent_dir.insert(inode);
} else if mode.is_regular_file() {
let file = InitRamFsFile {
name: IrqMutex::new(filename.clone()),
data: IrqMutex::new(data.to_vec()),
stat: IrqMutex::new(Stat {
inode_no: ino,
mode,
size: FileSize(filesize as isize),
..Stat::zeroed()
}),
};
parent_dir.insert(INode::File(Arc::new(file)));
}
image.skip_until_alignment(4)?;
n_files += 1;
loaded_size += data.len();
}
log::info!(
"initramfs: found {} files taking up {} bytes",
n_files,
loaded_size
);
Ok(InitRamFs {
root: RootFs::new(root),
})
}
}
================================================
FILE: src/fs/initramfs/root.rs
================================================
use alloc::{borrow::ToOwned, boxed::Box, string::String, sync::Arc};
use crate::{
fs::{
path::{Path, PathComponent},
pipe::PIPE_FS,
DirRef, INode,
},
kbail,
util::KResult,
};
use super::dir::InitRamFsDir;
const MAX_SYMLINK_FOLLOW_DEPTH: usize = 20;
#[derive(Clone)]
pub struct RootFs {
root_path: PathComponent,
cwd_path: PathComponent,
}
impl RootFs {
pub fn new(root: Arc<InitRamFsDir>) -> RootFs {
let root_path = PathComponent {
parent_dir: None,
name: Arc::new(String::new()),
inode: INode::Dir(root),
};
RootFs {
root_path: root_path.clone(),
cwd_path: root_path,
}
}
pub fn cwd_path(&self) -> &PathComponent {
&self.cwd_path
}
pub fn root_dir(&self) -> DirRef {
self.root_path.inode.as_dir().unwrap().clone()
}
pub fn cwd_dir(&self) -> DirRef {
self.cwd_path.inode.as_dir().unwrap().clone()
}
pub fn chdir(&mut self, path: &Path) -> KResult<()> {
self.cwd_path = self.lookup_path(path, true)?;
Ok(())
}
pub fn lookup(&self, path: &Path, follow_symlinks: bool) -> KResult<INode> {
if path.is_pipe() {
return PIPE_FS.lookup(path).map(INode::Pipe);
}
self.lookup_path(path, follow_symlinks)
.map(|cmp| cmp.inode.clone())
}
pub fn lookup_path(&self, path: &Path, follow_symlinks: bool) -> KResult<PathComponent> {
if path.is_empty() {
kbail!(ENOENT, "lookup_path(): empty path");
}
let lookup_from = if path.is_absolute() {
self.root_path.clone()
} else {
self.cwd_path.clone()
};
self.do_lookup_path(
&lookup_from,
path,
follow_symlinks,
MAX_SYMLINK_FOLLOW_DEPTH,
)
}
fn do_lookup_path(
&self,
lookup_from: &PathComponent,
path: &Path,
follow_symlinks: bool,
symlink_follow_limit: usize,
) -> KResult<PathComponent> {
let mut parent = lookup_from.clone();
let mut components = path.components().peekable();
while let Some(name) = components.next() {
let path_comp = match name {
"." => continue,
".." => parent
.parent_dir
.as_deref()
.unwrap_or(&self.root_path)
.clone(),
_ => {
let inode = parent.inode.as_dir()?.lookup(name)?;
PathComponent {
parent_dir: Some(Box::new(parent.clone())),
name: Arc::new(name.to_owned()),
inode,
}
}
};
if components.peek().is_some() {
parent = match &path_comp.inode {
INode::Dir(_) => path_comp,
INode::Pipe(_) => {
unreachable!("Pipes should be contained in PipeFs, not RootFs")
}
INode::Symlink(link) if follow_symlinks => {
if symlink_follow_limit == 0 {
kbail!(ELOOP, "lookup_path(): maximum symlink depth reached");
}
let dst = link.link_location()?;
let follow_from = if dst.is_absolute() {
&self.root_path
} else {
&parent
};
let dst_path = self.do_lookup_path(
follow_from,
&dst,
follow_symlinks,
symlink_follow_limit - 1,
)?;
match dst_path.inode {
INode::Dir(_) => dst_path,
_ => {
kbail!(ENOTDIR, "lookup_path(): not a directory");
}
}
}
INode::Symlink(_) => {
kbail!(ENOTDIR, "lookup_path(): not a directory");
}
INode::File(_) => {
kbail!(ENOTDIR, "lookup_path(): not a directory");
}
}
} else {
match &path_comp.inode {
INode::Symlink(link) if follow_symlinks => {
if symlink_follow_limit == 0 {
kbail!(ELOOP, "lookup_path(): maximum symlink depth reached");
}
let dst = link.link_location()?;
let follow_from = if dst.is_absolute() {
&self.root_path
} else {
&parent
};
return self.do_lookup_path(
follow_from,
&dst,
follow_symlinks,
symlink_follow_limit - 1,
);
}
_ => return Ok(path_comp),
}
}
}
Ok(parent)
}
}
================================================
FILE: src/fs/initramfs/symlink.rs
================================================
use alloc::string::String;
use crate::{
fs::{path::PathBuf, FsNode, Stat, Symlink},
util::KResult,
};
pub struct InitRamFsSymlink {
pub(crate) name: String,
pub(crate) dst: PathBuf,
pub(crate) stat: Stat,
}
impl Symlink for InitRamFsSymlink {
fn link_location(&self) -> KResult<PathBuf> {
Ok(self.dst.clone())
}
fn stat(&self) -> KResult<Stat> {
Ok(self.stat)
}
}
impl FsNode for InitRamFsSymlink {
fn get_name(&self) -> String {
self.name.clone()
}
}
================================================
FILE: src/fs/mod.rs
================================================
use core::sync::atomic::{AtomicUsize, Ordering};
use alloc::{string::String, sync::Arc};
use bitflags::bitflags;
use crate::{
kerror,
task::wait_queue::WaitQueue,
userland::buffer::{UserBuffer, UserBufferMut},
util::{ctypes::c_short, KResult},
};
use self::{opened_file::OpenFlags, path::PathBuf, pipe::Pipe};
pub mod devfs;
pub mod initramfs;
pub mod opened_file;
pub mod path;
pub mod pipe;
pub type FileRef = Arc<dyn File + Send + Sync>;
pub type DirRef = Arc<dyn Directory + Send + Sync>;
pub type SymlinkRef = Arc<dyn Symlink + Send + Sync>;
pub static POLL_WAIT_QUEUE: WaitQueue = WaitQueue::new();
pub fn alloc_inode_no() -> usize {
// Inode #1 is reserved for the root dir.
static NEXT_INODE_NO: AtomicUsize = AtomicUsize::new(2);
NEXT_INODE_NO.fetch_add(1, Ordering::AcqRel)
}
bitflags! {
#[derive(Debug)]
pub struct PollStatus: c_short {
const POLLIN = 0x001;
const POLLPRI = 0x002;
const POLLOUT = 0x004;
const POLLERR = 0x008;
const POLLHUP = 0x010;
const POLLNVAL = 0x020;
const POLLRDNORM = 0x040;
const POLLRDBAND = 0x080;
const POLLWRNORM = 0x100;
const POLLWRBAND = 0x200;
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(u8)]
#[non_exhaustive]
pub enum FileType {
Directory = 4,
Regular = 8,
Link = 10,
}
/// for readdir(3)
pub struct DirEntry {
pub inode_no: usize,
pub file_type: FileType,
pub name: String,
}
/// The device file's ID.
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct DevId(usize);
/// The number of hard links.
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct NLink(usize);
/// The file size in bytes.
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct FileSize(pub isize);
/// The user ID.
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct UId(u32);
/// The Group ID.
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct GId(u32);
/// The size in bytes of a block file file system I/O operations.
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct BlockSize(isize);
/// The number of blocks.
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct BlockCount(isize);
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct Time(isize);
#[derive(Debug, Copy, Clone)]
#[repr(C, packed)]
pub struct Stat {
pub dev: DevId,
pub inode_no: usize,
pub nlink: NLink,
pub mode: FileMode,
pub uid: UId,
pub gid: GId,
pub pad0: u32,
pub rdev: DevId,
pub size: FileSize,
pub blksize: BlockSize,
pub blocks: BlockCount,
pub atime: Time,
pub mtime: Time,
pub ctime: Time,
}
impl Stat {
pub fn zeroed() -> Stat {
Stat {
dev: DevId(0),
inode_no: 0,
mode: FileMode(0),
nlink: NLink(0),
uid: UId(0),
gid: GId(0),
pad0: 0,
rdev: DevId(0),
size: FileSize(0),
blksize: BlockSize(0),
blocks: BlockCount(0),
atime: Time(0),
mtime: Time(0),
ctime: Time(0),
}
}
}
pub const S_IFMT: u32 = 0o170000;
pub const S_IFCHR: u32 = 0o020000;
pub const S_IFDIR: u32 = 0o040000;
pub const S_IFREG: u32 = 0o100000;
pub const S_IFLNK: u32 = 0o120000;
pub const O_ACCMODE: u32 = 0o3;
// FIXME: OpenFlags also define these values.
#[allow(unused)]
pub const O_RDONLY: u32 = 0o0;
pub const O_WRONLY: u32 = 0o1;
pub const O_RDWR: u32 = 0o2;
#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct FileMode(u32);
impl FileMode {
pub fn new(val: u32) -> FileMode {
FileMode(val)
}
pub fn access_mode(self) -> u32 {
self.0 & O_ACCMODE
}
pub fn is_directory(self) -> bool {
(self.0 & S_IFMT) == S_IFDIR
}
pub fn is_regular_file(self) -> bool {
(self.0 & S_IFMT) == S_IFREG
}
pub fn is_symbolic_link(self) -> bool {
(self.0 & S_IFMT) == S_IFLNK
}
}
pub trait FsNode {
fn get_name(&self) -> String;
}
pub trait File: FsNode {
/// `open(2)`.
fn open(&self, _options: &OpenFlags) -> KResult<Option<FileRef>> {
Ok(None)
}
/// `stat(2)`.
fn stat(&self) -> KResult<Stat> {
Err(kerror!(EBADF, "stat(): not implemented"))
}
/// `readlink(2)`.
fn readlink(&self) -> KResult<PathBuf> {
// "EINVAL - The named file is not a symbolic link." -- readlink(2)
Err(kerror!(EINVAL, "readlink(): not a symbolic link"))
}
/// `poll(2)` and `select(2)`.
fn poll(&self) -> KResult<PollStatus> {
Err(kerror!(EBADF, "poll(): not implemented"))
}
/// `ioctl(2)`.
fn ioctl(&self, _cmd: usize, _arg: usize) -> KResult<isize> {
Err(kerror!(EBADF, "ioctl(): not implemented"))
}
/// `read(2)`.
fn read(&self, _offset: usize, _buf: UserBufferMut, _options: &OpenFlags) -> KResult<usize> {
Err(kerror!(EBADF, "read(): not implemented"))
}
/// `write(2)`.
fn write(&self, _offset: usize, _buf: UserBuffer<'_>, _options: &OpenFlags) -> KResult<usize> {
Err(kerror!(EBADF, "write(): not implemented"))
}
}
pub trait Symlink: FsNode {
fn link_location(&self) -> KResult<PathBuf>;
fn stat(&self) -> KResult<Stat>;
fn fsync(&self) -> KResult<()> {
Ok(())
}
}
pub trait Directory: FsNode {
fn insert(&self, inode: INode);
/// Looks for an existing file.
fn lookup(&self, name: &str) -> KResult<INode>;
/// `stat(2)`.
fn stat(&self) -> KResult<Stat>;
/// `fsync(2)`.
fn fsync(&self) -> KResult<()> {
Ok(())
}
/// `readlink(2)`.
fn readlink(&self) -> KResult<PathBuf> {
// "EINVAL - The named file is not a symbolic link." -- readlink(2)
Err(kerror!(EINVAL, "readlink(): not a symbolic link"))
}
fn readdir(&self, index: usize) -> KResult<Option<DirEntry>>;
fn unlink(&self, name: &str) -> KResult<()>;
}
#[derive(Clone)]
pub enum INode {
File(FileRef),
Dir(DirRef),
Symlink(SymlinkRef),
Pipe(Arc<Pipe>),
}
impl INode {
pub fn is_file(&self) -> bool {
matches!(self, INode::File(_))
}
pub fn is_dir(&self) -> bool {
matches!(self, INode::Dir(_))
}
pub fn is_symlink(&self) -> bool {
matches!(self, INode::Symlink(_))
}
pub fn is_pipe(&self) -> bool {
matches!(self, INode::Pipe(_))
}
pub fn as_file(&self) -> KResult<&FileRef> {
match self {
INode::File(file) => Ok(file),
_ => Err(kerror!(EINVAL, "as_file(): not a file")),
}
}
pub fn stat(&self) -> KResult<Stat> {
match self {
INode::Dir(d) => d.stat(),
INode::File(d) => d.stat(),
INode::Symlink(d) => d.stat(),
INode::Pipe(p) => p.stat(),
}
}
pub fn as_dir(&self) -> KResult<&DirRef> {
match self {
INode::Dir(d) => Ok(d),
_ => Err(kerror!(ENOTDIR, "as_dir(): not a directory")),
}
}
pub fn as_symlink(&self) -> KResult<&SymlinkRef> {
match self {
INode::Symlink(s) => Ok(s),
_ => Err(kerror!(EINVAL, "as_symlink(): not a symbolic link")),
}
}
pub fn as_pipe(&self) -> KResult<&Arc<Pipe>> {
match self {
INode::Pipe(p) => Ok(p),
_ => Err(kerror!(EINVAL, "as_pipe(): not a pipe")),
}
}
}
impl FsNode for INode {
fn get_name(&self) -> String {
match self {
INode::Dir(d) => d.get_name(),
INode::File(f) => f.get_name(),
INode::Symlink(l) => l.get_name(),
INode::Pipe(p) => p.get_name(),
}
}
}
================================================
FILE: src/fs/opened_file.rs
================================================
use core::{borrow::BorrowMut, ops::Deref};
use alloc::{sync::Arc, vec::Vec};
use atomic_refcell::AtomicRefCell;
use bitflags::bitflags;
use crossbeam_utils::atomic::AtomicCell;
use crate::{
kerror,
userland::buffer::{UserBuffer, UserBufferMut},
util::{ctypes::c_int, error::KResult},
};
use super::{
devfs::socket::Socket,
path::PathComponent,
pipe::{Pipe, PIPE_FS},
DirEntry, DirRef, FileRef, FsNode, INode, PollStatus,
};
const FD_MAX: c_int = 1024;
bitflags! {
#[derive(Clone, Copy, Debug)]
pub struct OpenFlags: i32 {
const O_RDONLY = 0o0;
const O_WRONLY = 0o1;
const O_RDWR = 0o2;
const O_CREAT = 0o0100;
const O_EXCL = 0o0200;
const O_NOCTTY = 0o0400;
const O_TRUNC = 0o01000;
const O_APPEND = 0o02000;
const O_NONBLOCK = 0o04000;
const O_DSYNC = 0o010000;
const O_SYNC = 0o04010000;
const O_RSYNC = 0o04010000;
const O_DIRECTORY = 0o0200000;
const O_NOFOLLOW = 0o0400000;
const O_CLOEXEC = 0o02000000;
const O_ASYNC = 0o020000;
const O_DIRECT = 0o040000;
const O_LARGEFILE = 0o0100000;
const O_NOATIME = 0o01000000;
const O_PATH = 0o010000000;
const O_TMPFILE = 0o020200000;
}
}
pub type FileDesc = c_int;
#[repr(C)]
pub struct OpenedFile {
path: PathComponent,
pos: AtomicCell<usize>,
options: AtomicRefCell<OpenFlags>,
}
impl OpenedFile {
pub fn new(path: PathComponent, options: OpenFlags, pos: usize) -> OpenedFile {
OpenedFile {
path,
pos: AtomicCell::new(pos),
options: AtomicRefCell::new(options),
}
}
pub fn as_file(&self) -> KResult<&FileRef> {
self.path.inode.as_file()
}
pub fn as_dir(&self) -> KResult<&DirRef> {
self.path.inode.as_dir()
}
pub fn pos(&self) -> usize {
self.pos.load()
}
pub fn options(&self) -> OpenFlags {
*self.options.borrow()
}
pub fn path(&self) -> &PathComponent {
&self.path
}
pub fn inode(&self) -> &INode {
&self.path.inode
}
pub fn read(&self, buf: UserBufferMut) -> KResult<usize> {
let options = self.options();
let pos = self.pos();
let read_len = self.as_file()?.read(pos, buf, &options)?;
self.pos.fetch_add(read_len);
Ok(read_len)
}
pub fn write(&self, buf: UserBuffer) -> KResult<usize> {
let options = self.options();
let pos = self.pos();
let written_len = self.as_file()?.write(pos, buf, &options)?;
self.pos.fetch_add(written_len);
Ok(written_len)
}
pub fn set_close_on_exec(&self, close_on_exec: bool) {
self.options()
.borrow_mut()
.set(OpenFlags::O_CLOEXEC, close_on_exec);
}
pub fn set_flags(&self, flags: OpenFlags) -> KResult<()> {
*self.options.borrow_mut() = flags;
Ok(())
}
pub fn get_flags(&self) -> OpenFlags {
*self.options.borrow()
}
pub fn poll(&self) -> KResult<PollStatus> {
self.as_file()?.poll()
}
pub fn ioctl(&self, cmd: usize, arg: usize) -> KResult<isize> {
self.as_file()?.ioctl(cmd, arg)
}
pub fn readdir(&self) -> KResult<Option<DirEntry>> {
let pos = self.pos();
let entry = self.as_dir()?.readdir(pos)?;
self.pos.fetch_add(1);
Ok(entry)
}
pub fn lseek(&self, offset: usize, whence: LseekWhence) -> KResult<usize> {
// We perform this check before we know we need something from the inode
// because this should only be called on files anyway.
let file = self.inode().as_file()?;
match whence {
LseekWhence::Set => self.pos.store(offset),
LseekWhence::Cur => _ = self.pos.fetch_add(offset),
LseekWhence::End => self.pos.store(file.stat()?.size.0 as usize - offset),
};
Ok(self.pos())
}
}
#[repr(usize)]
pub enum LseekWhence {
Set = 0,
Cur = 1,
End = 2,
}
impl From<usize> for LseekWhence {
fn from(value: usize) -> Self {
match value {
0 => LseekWhence::Set,
1 => LseekWhence::Cur,
2 => LseekWhence::End,
_ => panic!("Invalid LseekWhence"),
}
}
}
#[derive(Clone)]
pub struct LocalOpenedFile {
opened_file: Arc<OpenedFile>,
}
impl Deref for LocalOpenedFile {
type Target = OpenedFile;
fn deref(&self) -> &Self::Target {
&self.opened_file
}
}
#[derive(Clone)]
pub struct OpenedFileTable {
files: Vec<Option<LocalOpenedFile>>,
prev_fd: i32,
}
impl Default for OpenedFileTable {
fn default() -> Self {
Self::new()
}
}
impl OpenedFileTable {
pub fn new() -> OpenedFileTable {
OpenedFileTable {
files: Vec::new(),
prev_fd: 1,
}
}
pub fn get(&self, fd: FileDesc) -> KResult<LocalOpenedFile> {
match self.files.get(fd as usize) {
Some(Some(file)) => Ok(file.clone()),
_ => Err(kerror!(EBADF, "get(): file not opened")),
}
}
pub fn open(&mut self, path: PathComponent, options: OpenFlags) -> KResult<FileDesc> {
let fd = self.alloc_fd(None)?;
self.open_with_fd(fd, OpenedFile::new(path, options, 0).into(), options)?;
Ok(fd)
}
pub fn open_with_fd(
&mut self,
fd: FileDesc,
mut opened_file: Arc<OpenedFile>,
options: OpenFlags,
) -> KResult<()> {
if let INode::File(file) = &opened_file.path.inode {
if let Some(new_inode) = file.open(&options)? {
opened_file = Arc::new(OpenedFile::new(
PathComponent {
parent_dir: opened_file.path.parent_dir.clone(),
name: opened_file.path.name.clone(),
inode: INode::File(new_inode),
},
options,
0,
));
}
}
match self.files.get_mut(fd as usize) {
Some(Some(_)) => return Err(kerror!(EBADF, "open_with_fd(): file already opened")),
Some(entry @ None) => {
*entry = Some(LocalOpenedFile { opened_file });
}
None if fd >= FD_MAX => {
return Err(kerror!(
ENFILE,
"open_with_fd(): maximum file descriptor reached"
))
}
None => {
self.files.resize(fd as usize + 1, None);
self.files[fd as usize] = Some(LocalOpenedFile { opened_file })
}
}
Ok(())
}
fn alloc_fd(&mut self, gte: Option<i32>) -> KResult<FileDesc> {
let (mut i, gte) = match gte {
Some(gte) => (gte, gte),
None => ((self.prev_fd + 1) % FD_MAX, 0),
};
while i != self.prev_fd && i >= gte {
if matches!(self.files.get(i as usize), Some(None) | None) {
self.prev_fd = i;
return Ok(i);
}
i = (i + 1) % FD_MAX;
}
Err(kerror!(ENFILE, "alloc_fd(): cannot alloc file descriptor"))
}
pub fn close_all(&mut self) {
self.files.clear()
}
pub fn close_cloexec_files(&mut self) {
for opened_file in &mut self.files {
if matches!(
opened_file,
Some(LocalOpenedFile {
// close_on_exec: true,
// opened_file
..
})
) {
let cloexec = opened_file
.as_ref()
.unwrap()
.opened_file
.options()
.contains(OpenFlags::O_CLOEXEC);
if cloexec {
*opened_file = None;
}
}
}
}
pub fn close(&mut self, fd: FileDesc) -> KResult<()> {
match self.files.get_mut(fd as usize) {
Some(opened_file) => *opened_file = None,
_ => return Err(kerror!(EBADF, "close(): file not opened")),
}
Ok(())
}
pub fn dup(&mut self, fd: FileDesc, gte: Option<i32>, options: OpenFlags) -> KResult<FileDesc> {
let file = self.get(fd)?;
let new_fd = self.alloc_fd(gte)?;
self.open_with_fd(new_fd, file.opened_file, options)?;
Ok(new_fd)
}
pub fn dup2(&mut self, old_fd: FileDesc, new_fd: FileDesc) -> KResult<FileDesc> {
let old_file = self.get(old_fd)?;
let options = old_file.options();
self.open_with_fd(new_fd, old_file.opened_file, options)?;
Ok(new_fd)
}
pub fn open_socket(&mut self, domain: usize, typ: usize, protocol: usize) -> KResult<FileDesc> {
let fd = self.alloc_fd(None)?;
let socket = Arc::new(Socket {
domain: domain.try_into()?,
typ: typ.try_into()?,
protocol: protocol.try_into()?,
id: Socket::alloc_id(),
});
self.open_with_fd(
fd,
OpenedFile::new(
PathComponent {
parent_dir: None,
name: Arc::new(socket.get_name()),
inode: INode::File(socket.clone()),
},
OpenFlags::empty(),
0,
)
.into(),
OpenFlags::empty(),
)?;
Ok(fd)
}
pub fn open_pipe(&mut self, options: OpenFlags) -> KResult<Arc<Pipe>> {
let write_fd = self.alloc_fd(None)?;
let read_fd = self.alloc_fd(Some(write_fd + 1))?;
let pipe = Arc::new(Pipe::new(read_fd, write_fd));
PIPE_FS.insert(pipe.clone());
self.files.resize(read_fd as usize + 1, None);
self.open_with_fd(
write_fd,
OpenedFile::new(
PathComponent {
parent_dir: None,
name: Arc::new(pipe.get_name()),
inode: INode::Pipe(pipe.clone()),
},
options,
0,
)
.into(),
options,
)?;
self.open_with_fd(
read_fd,
OpenedFile::new(
PathComponent {
parent_dir: None,
name: Arc::new(pipe.get_name()),
inode: INode::Pipe(pipe.clone()),
},
options,
0,
)
.into(),
options,
)?;
Ok(pipe)
}
}
================================================
FILE: src/fs/path.rs
================================================
use alloc::{borrow::ToOwned, boxed::Box, string::String, sync::Arc};
use super::INode;
#[derive(Debug, Eq, PartialEq, Hash)]
pub struct Path {
path: str,
}
impl Path {
pub fn new(path: &str) -> &Path {
let path = if path == "/" {
path
} else {
path.trim_end_matches('/')
};
unsafe { &*(path as *const str as *const Path) }
}
pub fn as_str(&self) -> &str {
&self.path
}
pub fn is_empty(&self) -> bool {
self.path.is_empty()
}
pub fn is_absolute(&self) -> bool {
self.path.starts_with('/')
&& !self
.components()
.any(|comp| matches!(comp, ".." | "." | ""))
}
pub fn is_pipe(&self) -> bool {
self.path.starts_with("pipe:")
}
pub fn pipe_name(&self) -> Option<&str> {
if self.is_pipe() {
Some(&self.path[5..])
} else {
None
}
}
pub fn components(&self) -> Components<'_> {
let path = if self.path.starts_with('/') {
&self.path[1..]
} else {
&self.path
};
Components { path }
}
pub fn parent_and_basename(&self) -> Option<(&Path, &str)> {
if &self.path == "/" {
return None;
}
if let Some(slash_idx) = self.path.rfind('/') {
let parent_dir = if slash_idx == 0 {
Path::new("/")
} else {
Path::new(&self.path[..slash_idx])
};
let basename = &self.path[(slash_idx + 1)..];
Some((parent_dir, basename))
} else {
Some((Path::new("."), &self.path))
}
}
}
impl AsRef<Path> for Path {
fn as_ref(&self) -> &Path {
self
}
}
impl AsRef<Path> for str {
fn as_ref(&self) -> &Path {
Path::new(self)
}
}
impl core::fmt::Display for Path {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", &self.path)
}
}
pub struct Components<'a> {
path: &'a str,
}
impl<'a> Iterator for Components<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<Self::Item> {
if self.path.is_empty() {
return None;
}
let (path_str, next_start) = match self.path.find('/') {
Some(slash_idx) => (&self.path[..slash_idx], slash_idx + 1),
None => (self.path, self.path.len()),
};
self.path = &self.path[next_start..];
Some(path_str)
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct PathBuf {
path: String,
}
impl PathBuf {
pub fn new() -> PathBuf {
PathBuf {
path: String::new(),
}
}
pub fn as_path(&self) -> &Path {
Path::new(&self.path)
}
pub fn pop(&mut self) {
if let Some((index, _)) = self.path.char_indices().rfind(|(_, ch)| *ch == '/') {
self.path.truncate(index);
}
}
pub fn push<P: AsRef<Path>>(&mut self, path: P) {
let path = path.as_ref();
let path_str = if path.as_str() == "/" {
"/"
} else {
path.as_str().trim_end_matches('/')
};
if path.is_absolute() {
self.path = path_str.to_owned()
} else {
if self.path != "/" {
self.path.push('/');
}
self.path.push_str(path_str)
}
}
}
impl Default for PathBuf {
fn default() -> Self {
PathBuf::new()
}
}
impl core::ops::Deref for PathBuf {
type Target = Path;
fn deref(&self) -> &Self::Target {
self.as_path()
}
}
impl AsRef<Path> for PathBuf {
fn as_ref(&self) -> &Path {
self.as_path()
}
}
impl From<&Path> for PathBuf {
fn from(value: &Path) -> Self {
PathBuf {
path: value.path.to_owned(),
}
}
}
impl From<String> for PathBuf {
fn from(value: String) -> Self {
// TODO: check if this is a valid path
PathBuf { path: value }
}
}
impl From<&str> for PathBuf {
fn from(value: &str) -> Self {
// TODO: check if this is a valid path
PathBuf {
path: value.to_owned(),
}
}
}
#[derive(Clone)]
pub struct PathComponent {
pub parent_dir: Option<Box<PathComponent>>,
pub name: Arc<String>,
pub inode: INode,
}
impl PathComponent {
pub fn resolve_abs_path(&self) -> PathBuf {
let path = if self.parent_dir.is_some() {
let mut path = self.name.as_ref().to_owned();
let mut parent_dir = self.parent_dir.clone();
while let Some(ref path_comp) = parent_dir {
path = path_comp.name.as_ref().to_owned() + "/" + &path;
parent_dir = path_comp.parent_dir.clone();
}
debug_assert!(path.starts_with('/'));
path
} else {
"/".to_owned()
};
PathBuf::from(path)
}
}
================================================
FILE: src/fs/pipe.rs
================================================
use alloc::{format, sync::Arc, vec::Vec};
use crate::{
kerror,
task::wait_queue::WaitQueue,
userland::buffer::{UserBuffer, UserBufferMut, UserBufferReader, UserBufferWriter},
util::{ringbuffer::RingBuffer, IrqMutex, KResult},
};
use super::{opened_file::FileDesc, path::Path, File, FsNode};
pub static PIPE_FS: PipeFs = PipeFs::new();
pub struct Pipe {
wait_queue: WaitQueue,
ringbuffer: Arc<IrqMutex<RingBuffer<u8, 65536>>>,
read_fd: FileDesc,
write_fd: FileDesc,
}
impl Pipe {
pub fn new(read_fd: FileDesc, write_fd: FileDesc) -> Self {
Self {
wait_queue: WaitQueue::new(),
ringbuffer: Arc::new(IrqMutex::new(RingBuffer::new())),
read_fd,
write_fd,
}
}
pub fn read_pipe(&self, buf: UserBufferMut<'_>) -> KResult<usize> {
let mut writer = UserBufferWriter::from_buf(buf);
let mut ringbuffer = self.wait_queue.sleep_signalable_until(None, || {
let ringbuffer = self.ringbuffer.try_lock();
if let Ok(ringbuffer) = ringbuffer {
if ringbuffer.is_readable() {
Ok(Some(ringbuffer))
} else {
Ok(None)
}
} else {
Ok(None)
}
})?;
while let Some(byte) = ringbuffer.pop() {
writer.write(byte)?;
}
Ok(writer.written_len())
}
pub fn write_pipe(&self, buf: UserBuffer<'_>) -> KResult<usize> {
let mut reader = UserBufferReader::from_buf(buf);
let mut ringbuffer = self.wait_queue.sleep_signalable_until(None, || {
let ringbuffer = self.ringbuffer.try_lock();
if let Ok(ringbuffer) = ringbuffer {
if ringbuffer.is_writable() {
Ok(Some(ringbuffer))
} else {
Ok(None)
}
} else {
Ok(None)
}
})?;
while let Ok(byte) = reader.read::<u8>() {
ringbuffer.push(byte).ok();
}
Ok(reader.read_len())
}
pub fn read_fd(&self) -> FileDesc {
self.read_fd
}
pub fn write_fd(&self) -> FileDesc {
self.write_fd
}
}
impl FsNode for Pipe {
fn get_name(&self) -> alloc::string::String {
format!("pipe_{}_{}", self.write_fd, self.read_fd)
}
}
impl File for Pipe {
fn read(
&self,
_offset: usize,
buf: UserBufferMut,
_options: &super::opened_file::OpenFlags,
) -> KResult<usize> {
self.read_pipe(buf)
}
fn write(
&self,
_offset: usize,
buf: UserBuffer<'_>,
_options: &super::opened_file::OpenFlags,
) -> KResult<usize> {
self.write_pipe(buf)
}
}
pub struct PipeFs {
pipes: IrqMutex<Vec<Arc<Pipe>>>,
}
impl PipeFs {
#[allow(clippy::new_without_default)]
pub const fn new() -> Self {
Self {
pipes: IrqMutex::new(Vec::new()),
}
}
pub fn insert(&self, pipe: Arc<Pipe>) {
self.pipes.lock().push(pipe);
}
pub fn lookup(&self, path: &Path) -> KResult<Arc<Pipe>> {
self.pipes
.lock()
.iter()
.find(|pipe| pipe.get_name() == path.pipe_name().unwrap())
.cloned()
.ok_or(kerror!(ENOENT, "pipe does not exist"))
}
}
================================================
FILE: src/god_mode.rs
================================================
use alloc::{borrow::ToOwned, collections::VecDeque, string::String, sync::Arc};
use spin::Once;
use x86_64::instructions::interrupts;
use crate::{
mem::{
addr::PhysAddr,
allocator::{GLOBAL_ALLOC, KERNEL_FRAME_ALLOCATOR},
consts::{KERNEL_HEAP_SIZE, PAGE_SIZE},
},
task::{get_scheduler, Task, TaskId},
util::{align_down, BlockingMutex},
};
pub static GOD_MODE_TASK: Once<Arc<Task>> = Once::new();
pub static GOD_MODE_FIFO: Once<BlockingMutex<VecDeque<u8>>> = Once::new();
pub fn init() {
GOD_MODE_FIFO.call_once(|| BlockingMutex::new(VecDeque::new()));
let sched = get_scheduler();
GOD_MODE_TASK.call_once(|| Task::new_kernel(sched, god_mode_repl, true));
sched.push_runnable(GOD_MODE_TASK.get().unwrap().clone(), false);
}
fn read_cmd() -> String {
let mut cmd = String::new();
loop {
let mut lock = GOD_MODE_FIFO.get().unwrap().try_lock();
while let Ok(Some(ch)) = lock.as_mut().map(|lock| lock.pop_front()) {
if ch == b'\n' || ch == b'\r' {
drop(lock);
return cmd;
}
let st = core::str::from_utf8(&[ch]).unwrap().to_owned();
cmd.push_str(&st);
serial1_print!("{}", st);
}
drop(lock);
interrupts::enable_and_hlt();
}
}
pub fn god_mode_repl() {
loop {
serial1_print!("\ngodmode > ");
let cmd = read_cmd();
let mut args = cmd.split_whitespace();
let cmd = if let Some(cmd) = args.next() {
cmd
} else {
continue;
};
serial1_println!();
log::warn!("God said: {}", cmd);
match cmd {
"f" | "frames" => {
serial1_println!("Dumping free physical memory.");
let fa = KERNEL_FRAME_ALLOCATOR.get().unwrap().lock();
let mut total_space_pages = 0;
for area in fa.free_regions() {
total_space_pages += area.size_in_pages();
serial1_println!("Free chunk at {:?}", area);
}
serial1_println!("Total free pages: {}", total_space_pages);
serial1_println!("Total free bytes: {}", total_space_pages * PAGE_SIZE);
}
"vm" | "vmem" => {
let pid = if let Some(Ok(pid)) = args.next().map(|arg| arg.parse()) {
TaskId::new(pid)
} else {
serial1_println!("Invalid argument. Specify a PID to inspect vmem of.");
continue;
};
let sched = get_scheduler();
let task = if let Some(task) = sched.find_task(pid) {
task
} else {
serial1_println!("Invalid argument. PID not found.");
continue;
};
serial1_println!(
"Dumping virtual memory of pid {}. Check serial0 (stdio).",
pid.as_usize()
);
task.vmem().lock().log();
}
"x" | "examine" => {
let start = if let Some(Ok(start)) =
args.next().map(|arg| usize::from_str_radix(arg, 16))
{
align_down(start, PAGE_SIZE)
} else {
serial1_println!("Invalid argument. Specify the address to dump the frame of.");
continue;
};
let ptr = PhysAddr::new(start).as_hhdm_virt().as_raw_ptr::<u64>();
let max_i = PAGE_SIZE / core::mem::size_of::<u64>();
serial1_println!("Dumping frame at {:#x}.", start);
for i in 0..max_i / 4 {
let i = i * 4;
serial1_print!("{:#016x} >> ", start + i * core::mem::size_of::<u64>());
for j in 0..4 {
let offset = i + j;
serial1_print!("{:016x} ", unsafe { ptr.add(offset).read_volatile() });
}
serial1_println!();
}
}
"h" | "heap" => {
let lock = GLOBAL_ALLOC.try_lock();
if let Some(lock) = lock {
serial1_println!("Kernel heap size: {:#08x}", KERNEL_HEAP_SIZE);
serial1_println!(
"Kernel heap usage (actual): {:#08x} ({:.4}%)",
lock.stats_alloc_actual(),
lock.stats_alloc_actual() as f64 / KERNEL_HEAP_SIZE as f64 * 100.0
);
serial1_println!(
"Kernel heap usage (user): {:#08x} ({:.4}%)",
lock.stats_alloc_user(),
lock.stats_alloc_user() as f64 / KERNEL_HEAP_SIZE as f64 * 100.0
);
} else {
serial1_println!("Error locking global allocator.");
}
}
_ => {}
}
}
}
================================================
FILE: src/graphics/mod.rs
================================================
use core::ops::Add;
use alloc::{boxed::Box, vec::Vec};
use embedded_graphics::{
mono_font::{ascii::FONT_8X13, MonoFont, MonoTextStyle},
pixelcolor::Rgb888,
prelude::*,
text::{Alignment, Text},
};
use limine::response::FramebufferResponse;
use spin::Once;
use crate::{
mem::addr::VirtAddr,
util::{IrqMutex, IrqMutexGuard, KResult},
vga_text::{BUFFER_HEIGHT, BUFFER_WIDTH},
};
const FONT: MonoFont = FONT_8X13;
pub struct FrameBuffer {
back_buffer: Box<[u32]>,
start_addr: VirtAddr,
width: usize,
height: usize,
gitextract_c29w2sxr/
├── .cargo/
│ ├── config.toml
│ ├── debug.toml
│ ├── linker.ld
│ ├── release.toml
│ ├── runner_debug.sh
│ ├── runner_release.sh
│ └── x86_64-kados.json
├── .gitignore
├── .vscode/
│ ├── launch.json
│ └── settings.json
├── Cargo.toml
├── LICENSE
├── README.md
├── build.rs
├── conf/
│ ├── grub.cfg
│ └── limine.cfg
├── deps.sh
├── kados.config
├── rust-toolchain.toml
├── src/
│ ├── arch/
│ │ ├── mod.rs
│ │ └── x86_64/
│ │ ├── cpu_local.rs
│ │ ├── gdt.rs
│ │ ├── idt.rs
│ │ ├── mod.rs
│ │ ├── syscall.rs
│ │ ├── task.rs
│ │ └── time.rs
│ ├── backtrace.rs
│ ├── fs/
│ │ ├── devfs/
│ │ │ ├── fb.rs
│ │ │ ├── input.rs
│ │ │ ├── mod.rs
│ │ │ ├── null.rs
│ │ │ ├── socket.rs
│ │ │ ├── tty.rs
│ │ │ └── urandom.rs
│ │ ├── initramfs/
│ │ │ ├── dir.rs
│ │ │ ├── file.rs
│ │ │ ├── mod.rs
│ │ │ ├── root.rs
│ │ │ └── symlink.rs
│ │ ├── mod.rs
│ │ ├── opened_file.rs
│ │ ├── path.rs
│ │ └── pipe.rs
│ ├── god_mode.rs
│ ├── graphics/
│ │ └── mod.rs
│ ├── logging.rs
│ ├── main.rs
│ ├── mem/
│ │ ├── addr.rs
│ │ ├── addr_space.rs
│ │ ├── allocator.rs
│ │ ├── consts.rs
│ │ ├── mod.rs
│ │ └── paging/
│ │ ├── mapper.rs
│ │ ├── mod.rs
│ │ ├── table.rs
│ │ └── units.rs
│ ├── serial.rs
│ ├── task/
│ │ ├── group.rs
│ │ ├── mod.rs
│ │ ├── scheduler.rs
│ │ ├── signal.rs
│ │ ├── vmem.rs
│ │ └── wait_queue.rs
│ ├── userland/
│ │ ├── buffer.rs
│ │ ├── elf.rs
│ │ ├── mod.rs
│ │ └── syscall/
│ │ ├── mod.rs
│ │ └── syscall_impl/
│ │ ├── fs.rs
│ │ ├── mem.rs
│ │ ├── mod.rs
│ │ ├── signal.rs
│ │ ├── sys.rs
│ │ ├── task.rs
│ │ └── time.rs
│ ├── util/
│ │ ├── ctypes.rs
│ │ ├── errno.rs
│ │ ├── error.rs
│ │ ├── lock.rs
│ │ ├── mod.rs
│ │ ├── ringbuffer.rs
│ │ └── stack.rs
│ └── vga_text.rs
└── userland/
├── .gitignore
├── .vscode/
│ └── settings.json
├── Cargo.toml
├── kados_syscall/
│ ├── .cargo/
│ │ └── config.toml
│ ├── Cargo.toml
│ └── src/
│ ├── consts.rs
│ └── lib.rs
└── rust-toolchain.toml
SYMBOL INDEX (1334 symbols across 63 files)
FILE: build.rs
function main (line 3) | fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
FILE: src/arch/x86_64/cpu_local.rs
type CpuLocalData (line 4) | pub struct CpuLocalData {
type Kpcr (line 10) | pub struct Kpcr {
function get_kpcr (line 16) | pub fn get_kpcr() -> &'static mut Kpcr {
function get_tss (line 20) | pub fn get_tss() -> &'static mut TaskStateSegment {
FILE: src/arch/x86_64/gdt.rs
constant KERNEL_CS_IDX (line 20) | pub const KERNEL_CS_IDX: u16 = 1;
constant KERNEL_DS_IDX (line 21) | pub const KERNEL_DS_IDX: u16 = 2;
constant TSS_IDX (line 22) | pub const TSS_IDX: u16 = 3;
constant USER_DS_IDX (line 23) | pub const USER_DS_IDX: u16 = 5;
constant USER_CS_IDX (line 24) | pub const USER_CS_IDX: u16 = 6;
function init_boot (line 37) | pub fn init_boot() {
function init (line 51) | pub fn init() {
FILE: src/arch/x86_64/idt.rs
constant PIC_1_OFFSET (line 25) | pub const PIC_1_OFFSET: u8 = 32;
constant PIC_2_OFFSET (line 26) | pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8;
constant TIMER_IRQ (line 31) | pub const TIMER_IRQ: u8 = PIC_1_OFFSET;
constant KEYBOARD_IRQ (line 32) | pub const KEYBOARD_IRQ: u8 = PIC_1_OFFSET + 1;
constant COM2_IRQ (line 33) | pub const COM2_IRQ: u8 = PIC_1_OFFSET + 3;
type InterruptFrame (line 89) | pub struct InterruptFrame {
method is_user_mode (line 116) | pub fn is_user_mode(&self) -> bool {
type InterruptErrorFrame (line 123) | pub struct InterruptErrorFrame {
function notify_eoi (line 129) | pub fn notify_eoi(index: u8) {
function x64_handle_interrupt (line 214) | extern "C" fn x64_handle_interrupt(vector: u8, stack_frame: *mut Interru...
constant PIC_1_DATA_PORT (line 392) | pub const PIC_1_DATA_PORT: u8 = 0x21;
constant PIC_2_DATA_PORT (line 393) | pub const PIC_2_DATA_PORT: u8 = 0xa1;
function mask_irq (line 395) | pub fn mask_irq(irq: u8) {
function unmask_irq (line 407) | pub fn unmask_irq(irq: u8) {
function init (line 419) | pub fn init() {
function do_keyboard_input (line 430) | fn do_keyboard_input() {
FILE: src/arch/x86_64/mod.rs
function get_cpuid_feature_info (line 49) | pub fn get_cpuid_feature_info() -> &'static FeatureInfo {
function arch_main (line 57) | pub fn arch_main() {
function startup_init (line 190) | pub fn startup_init() {
function poll_serial1 (line 238) | fn poll_serial1() {
function idle (line 257) | pub fn idle() {
FILE: src/arch/x86_64/syscall.rs
function syscall_entry (line 66) | pub unsafe extern "C" fn syscall_entry() {
function x64_handle_syscall (line 123) | unsafe extern "C" fn x64_handle_syscall(ctx: *mut InterruptFrame) -> isi...
function handle_syscall (line 138) | fn handle_syscall(
function init (line 172) | pub unsafe fn init() {
FILE: src/arch/x86_64/task.rs
function fxsave (line 33) | fn fxsave(fpu: &mut Box<[u8]>) {
function fxrstor (line 39) | fn fxrstor(fpu: &mut Box<[u8]>) {
function arch_context_switch (line 45) | pub fn arch_context_switch(prev: &mut ArchTask, next: &mut ArchTask) {
function iretq_init (line 73) | unsafe extern "C" fn iretq_init() -> ! {
function fork_init (line 91) | unsafe extern "C" fn fork_init() -> ! {
function context_switch (line 110) | unsafe extern "C" fn context_switch(_prev: &mut Unique<Context>, _next: ...
type Context (line 142) | pub struct Context {
function exec_entry (line 156) | unsafe extern "C" fn exec_entry(rcx: usize, rsp: usize, r11: usize) -> ! {
type ArchTask (line 194) | pub struct ArchTask {
method new_idle (line 206) | pub fn new_idle() -> ArchTask {
method new_kernel (line 219) | pub fn new_kernel(entry_point: VirtAddr, enable_interrupts: bool) -> A...
method exec (line 257) | pub fn exec(
method fork (line 346) | pub fn fork(&mut self) -> KResult<Self> {
method clone_process (line 386) | pub fn clone_process(
method alloc_fpu_storage (line 436) | fn alloc_fpu_storage() -> Box<[u8]> {
method alloc_switch_stack (line 448) | fn alloc_switch_stack() -> KResult<VirtAddr> {
method set_fsbase (line 452) | pub fn set_fsbase(&mut self, addr: VirtAddr) {
method setup_signal_stack (line 459) | pub fn setup_signal_stack(
method setup_sigreturn_stack (line 490) | pub fn setup_sigreturn_stack(
FILE: src/arch/x86_64/time.rs
constant PIT_FREQUENCY_HZ (line 7) | const PIT_FREQUENCY_HZ: usize = 1000;
constant PIT_DIVIDEND (line 8) | pub const PIT_DIVIDEND: usize = 1193182;
function get_uptime_ns (line 16) | pub fn get_uptime_ns() -> usize {
function get_uptime_ms (line 21) | pub fn get_uptime_ms() -> usize {
function get_rt_clock (line 25) | pub fn get_rt_clock() -> TimeSpec {
function get_pit_count (line 29) | pub fn get_pit_count() -> u16 {
function set_reload_value (line 40) | pub fn set_reload_value(new_count: u16) {
function set_pit_frequency (line 48) | pub fn set_pit_frequency(frequency: usize) {
function pit_irq (line 58) | pub fn pit_irq() {
function init (line 83) | pub fn init(boot_time: i64) {
FILE: src/backtrace.rs
function print_symbol (line 24) | fn print_symbol(rip: usize, symtab: &Option<Vec<SymTabEntry>>, depth: us...
function unwind_user_stack_from (line 50) | pub fn unwind_user_stack_from(mut rbp: usize, mut rip: usize) {
function unwind_stack (line 103) | pub fn unwind_stack() -> KResult<()> {
function rust_panic (line 181) | fn rust_panic(info: &PanicInfo) -> ! {
function _Unwind_Resume (line 207) | extern "C" fn _Unwind_Resume(unwind_context_ptr: usize) -> ! {
function rust_eh_personality (line 214) | extern "C" fn rust_eh_personality() -> ! {
function handle_alloc_error (line 220) | fn handle_alloc_error(layout: Layout) -> ! {
FILE: src/fs/devfs/fb.rs
function init (line 15) | pub fn init() {
type FbDevice (line 28) | pub struct FbDevice;
method get_name (line 31) | fn get_name(&self) -> alloc::string::String {
method read (line 37) | fn read(&self, offset: usize, buf: UserBufferMut, _options: &OpenFlags) ...
method write (line 54) | fn write(&self, offset: usize, buf: UserBuffer<'_>, _options: &OpenFlags...
method ioctl (line 72) | fn ioctl(&self, cmd: usize, arg: usize) -> KResult<isize> {
type FbBitField (line 99) | struct FbBitField {
type FbVarScreenInfo (line 107) | struct FbVarScreenInfo {
FILE: src/fs/devfs/input.rs
function init (line 15) | pub fn init() {
type KbdDevice (line 28) | pub struct KbdDevice {
method new (line 33) | pub fn new() -> Self {
method handle_kbd_irq (line 39) | pub fn handle_kbd_irq(&self, key_evt: &KeyEvent) {
method default (line 49) | fn default() -> Self {
method get_name (line 55) | fn get_name(&self) -> alloc::string::String {
method read (line 61) | fn read(&self, _offset: usize, buf: UserBufferMut, _options: &OpenFlags)...
FILE: src/fs/devfs/mod.rs
function init (line 8) | pub fn init() {
FILE: src/fs/devfs/null.rs
function init (line 13) | pub fn init() {
type NullDevice (line 26) | pub struct NullDevice;
method get_name (line 29) | fn get_name(&self) -> alloc::string::String {
method write (line 35) | fn write(
method read (line 44) | fn read(
method stat (line 55) | fn stat(&self) -> crate::util::KResult<Stat> {
FILE: src/fs/devfs/socket.rs
function init (line 10) | pub fn init() {}
type Domain (line 14) | pub enum Domain {
type Error (line 20) | type Error = KError<'static>;
method try_from (line 21) | fn try_from(value: usize) -> Result<Self, Self::Error> {
type SocketType (line 32) | pub enum SocketType {
type Error (line 41) | type Error = KError<'static>;
method try_from (line 42) | fn try_from(value: usize) -> Result<Self, Self::Error> {
type Protocol (line 56) | pub enum Protocol {
type Error (line 63) | type Error = KError<'static>;
method try_from (line 64) | fn try_from(value: usize) -> Result<Self, Self::Error> {
type Socket (line 74) | pub struct Socket {
method alloc_id (line 85) | pub fn alloc_id() -> usize {
method get_name (line 101) | fn get_name(&self) -> alloc::string::String {
type SockAddrInet (line 108) | pub struct SockAddrInet {
function read_sockaddr (line 115) | pub fn read_sockaddr(addr: VirtAddr, len: usize) -> KResult<SockAddrInet> {
function write_sockaddr (line 132) | pub fn write_sockaddr(
method ioctl (line 147) | fn ioctl(&self, cmd: usize, _arg: usize) -> KResult<isize> {
FILE: src/fs/devfs/tty.rs
function init (line 35) | pub fn init() {
method default (line 57) | fn default() -> Self {
method default (line 85) | fn default() -> Self {
type Termios (line 92) | pub struct Termios {
method is_cooked (line 104) | pub fn is_cooked(&self) -> bool {
method default (line 110) | fn default() -> Self {
method fmt (line 126) | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
type LineControl (line 134) | pub enum LineControl {
type LineDiscipline (line 139) | pub struct LineDiscipline {
method new (line 148) | pub fn new() -> Self {
method is_readable (line 158) | pub fn is_readable(&self) -> bool {
method is_writable (line 162) | pub fn is_writable(&self) -> bool {
method foreground_group (line 166) | pub fn foreground_group(&self) -> Option<Arc<IrqMutex<TaskGroup>>> {
method set_foreground_group (line 170) | pub fn set_foreground_group(&self, pg: Weak<IrqMutex<TaskGroup>>) {
method _is_current_foreground (line 174) | fn _is_current_foreground(&self) -> bool {
method write (line 179) | pub fn write<F>(&self, buf: UserBuffer<'_>, callback: F) -> KResult<us...
method read (line 243) | pub fn read(&self, dst: UserBufferMut<'_>, options: &OpenFlags) -> KRe...
method default (line 275) | fn default() -> Self {
type Tty (line 280) | pub struct Tty {
method new (line 286) | pub fn new(name: &str) -> Self {
method set_cooked_mode (line 293) | pub fn set_cooked_mode(&self, cooked: bool) {
method input_char (line 301) | pub fn input_char(&self, ch: u8) {
method set_foreground_group (line 316) | pub fn set_foreground_group(&self, pg: Weak<IrqMutex<TaskGroup>>) {
method get_name (line 322) | fn get_name(&self) -> String {
constant TCGETS (line 326) | const TCGETS: usize = 0x5401;
constant TCSETS (line 327) | const TCSETS: usize = 0x5402;
constant TCSETSW (line 328) | const TCSETSW: usize = 0x5403;
constant TIOCGPGRP (line 330) | const TIOCGPGRP: usize = 0x540f;
constant TIOCSPGRP (line 331) | const TIOCSPGRP: usize = 0x5410;
constant TIOCGWINSZ (line 332) | const TIOCGWINSZ: usize = 0x5413;
type WinSize (line 336) | struct WinSize {
method ioctl (line 344) | fn ioctl(&self, cmd: usize, arg: usize) -> KResult<isize> {
method stat (line 387) | fn stat(&self) -> KResult<Stat> {
method read (line 395) | fn read(&self, _offset: usize, buf: UserBufferMut, options: &OpenFlags) ...
method write (line 413) | fn write(&self, _offset: usize, buf: UserBuffer<'_>, _options: &OpenFlag...
method poll (line 425) | fn poll(&self) -> KResult<PollStatus> {
function parse (line 437) | fn parse(mut reader: UserBufferReader) -> KResult<usize> {
type PtyMaster (line 615) | pub struct PtyMaster {
method new (line 622) | pub fn new() -> KResult<(Arc<PtyMaster>, Arc<PtySlave>)> {
method get_name (line 634) | fn get_name(&self) -> String {
method read (line 640) | fn read(&self, _offset: usize, buf: UserBufferMut<'_>, options: &OpenFla...
method write (line 666) | fn write(&self, _offset: usize, buf: UserBuffer<'_>, _options: &OpenFlag...
method ioctl (line 686) | fn ioctl(&self, cmd: usize, _arg: usize) -> KResult<isize> {
method stat (line 691) | fn stat(&self) -> KResult<Stat> {
method poll (line 699) | fn poll(&self) -> KResult<PollStatus> {
type PtySlave (line 712) | pub struct PtySlave {
method new (line 717) | pub fn new(master: Arc<PtyMaster>) -> Self {
method get_name (line 723) | fn get_name(&self) -> String {
method read (line 729) | fn read(&self, _offset: usize, buf: UserBufferMut, options: &OpenFlags) ...
method write (line 737) | fn write(&self, _offset: usize, buf: UserBuffer<'_>, _options: &OpenFlag...
method stat (line 766) | fn stat(&self) -> KResult<Stat> {
method ioctl (line 774) | fn ioctl(&self, cmd: usize, _arg: usize) -> KResult<isize> {
method poll (line 785) | fn poll(&self) -> KResult<PollStatus> {
type Ptmx (line 798) | pub struct Ptmx {
method new (line 803) | pub fn new(pts_dir: Arc<InitRamFsDir>) -> Self {
method get_name (line 809) | fn get_name(&self) -> String {
method open (line 815) | fn open(&self, _options: &OpenFlags) -> KResult<Option<FileRef>> {
method stat (line 821) | fn stat(&self) -> KResult<Stat> {
method read (line 829) | fn read(&self, _offset: usize, _buf: UserBufferMut, _options: &OpenFlags...
method write (line 833) | fn write(&self, _offset: usize, _buf: UserBuffer<'_>, _options: &OpenFla...
method poll (line 837) | fn poll(&self) -> KResult<PollStatus> {
FILE: src/fs/devfs/urandom.rs
function init (line 9) | pub fn init() {
type URandom (line 19) | pub struct URandom;
method get_name (line 22) | fn get_name(&self) -> alloc::string::String {
method read (line 28) | fn read(
FILE: src/fs/initramfs/dir.rs
type DirInner (line 16) | pub struct DirInner {
type InitRamFsDir (line 22) | pub struct InitRamFsDir {
method new (line 28) | pub fn new(name: String, inode_no: usize) -> InitRamFsDir {
method add_dir (line 43) | pub fn add_dir(&self, name: String) -> Arc<InitRamFsDir> {
method add_file (line 49) | pub fn add_file(&self, file: FileRef) {
method parent_dir (line 53) | pub fn parent_dir(&self) -> Option<Arc<InitRamFsDir>> {
method insert (line 59) | fn insert(&self, inode: INode) {
method lookup (line 63) | fn lookup(&self, name: &str) -> KResult<INode> {
method stat (line 75) | fn stat(&self) -> KResult<Stat> {
method readdir (line 79) | fn readdir(&self, index: usize) -> KResult<Option<crate::fs::DirEntry>> {
method unlink (line 107) | fn unlink(&self, name: &str) -> KResult<()> {
method get_name (line 117) | fn get_name(&self) -> String {
FILE: src/fs/initramfs/file.rs
type InitRamFsFile (line 9) | pub struct InitRamFsFile {
method new (line 16) | pub fn new(name: String, inode_no: usize) -> InitRamFsFile {
method get_name (line 30) | fn get_name(&self) -> String {
method read (line 36) | fn read(&self, offset: usize, buf: UserBufferMut<'_>, _options: &OpenFla...
method write (line 45) | fn write(&self, offset: usize, buf: UserBuffer<'_>, options: &OpenFlags)...
method stat (line 60) | fn stat(&self) -> KResult<Stat> {
FILE: src/fs/initramfs/mod.rs
type ByteParser (line 31) | pub struct ByteParser<'a> {
function new (line 37) | pub fn new(buffer: &'a [u8]) -> ByteParser<'a> {
function remaining (line 41) | pub fn remaining(&self) -> &[u8] {
function remaining_len (line 44) | pub fn remaining_len(&self) -> usize {
function skip (line 48) | pub fn skip(&mut self, len: usize) -> KResult<()> {
function skip_until_alignment (line 57) | pub fn skip_until_alignment(&mut self, align: usize) -> KResult<()> {
function consume_bytes (line 67) | pub fn consume_bytes(&mut self, len: usize) -> KResult<&'a [u8]> {
function parse_str_field (line 77) | fn parse_str_field(bytes: &[u8]) -> KResult<&str> {
function parse_hex_field (line 81) | fn parse_hex_field(bytes: &[u8]) -> KResult<usize> {
function init (line 88) | pub fn init() -> KResult<()> {
function get_root (line 104) | pub fn get_root() -> Option<&'static RootFs> {
type InitRamFs (line 108) | pub struct InitRamFs {
method parse (line 113) | pub fn parse(fs_image: &[u8]) -> KResult<InitRamFs> {
FILE: src/fs/initramfs/root.rs
constant MAX_SYMLINK_FOLLOW_DEPTH (line 15) | const MAX_SYMLINK_FOLLOW_DEPTH: usize = 20;
type RootFs (line 18) | pub struct RootFs {
method new (line 24) | pub fn new(root: Arc<InitRamFsDir>) -> RootFs {
method cwd_path (line 36) | pub fn cwd_path(&self) -> &PathComponent {
method root_dir (line 40) | pub fn root_dir(&self) -> DirRef {
method cwd_dir (line 44) | pub fn cwd_dir(&self) -> DirRef {
method chdir (line 48) | pub fn chdir(&mut self, path: &Path) -> KResult<()> {
method lookup (line 53) | pub fn lookup(&self, path: &Path, follow_symlinks: bool) -> KResult<IN...
method lookup_path (line 61) | pub fn lookup_path(&self, path: &Path, follow_symlinks: bool) -> KResu...
method do_lookup_path (line 80) | fn do_lookup_path(
FILE: src/fs/initramfs/symlink.rs
type InitRamFsSymlink (line 8) | pub struct InitRamFsSymlink {
method link_location (line 15) | fn link_location(&self) -> KResult<PathBuf> {
method stat (line 19) | fn stat(&self) -> KResult<Stat> {
method get_name (line 25) | fn get_name(&self) -> String {
FILE: src/fs/mod.rs
type FileRef (line 21) | pub type FileRef = Arc<dyn File + Send + Sync>;
type DirRef (line 22) | pub type DirRef = Arc<dyn Directory + Send + Sync>;
type SymlinkRef (line 23) | pub type SymlinkRef = Arc<dyn Symlink + Send + Sync>;
function alloc_inode_no (line 27) | pub fn alloc_inode_no() -> usize {
type FileType (line 53) | pub enum FileType {
type DirEntry (line 60) | pub struct DirEntry {
type DevId (line 69) | pub struct DevId(usize);
type NLink (line 74) | pub struct NLink(usize);
type FileSize (line 79) | pub struct FileSize(pub isize);
type UId (line 84) | pub struct UId(u32);
type GId (line 89) | pub struct GId(u32);
type BlockSize (line 94) | pub struct BlockSize(isize);
type BlockCount (line 99) | pub struct BlockCount(isize);
type Time (line 103) | pub struct Time(isize);
type Stat (line 107) | pub struct Stat {
method zeroed (line 125) | pub fn zeroed() -> Stat {
constant S_IFMT (line 145) | pub const S_IFMT: u32 = 0o170000;
constant S_IFCHR (line 146) | pub const S_IFCHR: u32 = 0o020000;
constant S_IFDIR (line 147) | pub const S_IFDIR: u32 = 0o040000;
constant S_IFREG (line 148) | pub const S_IFREG: u32 = 0o100000;
constant S_IFLNK (line 149) | pub const S_IFLNK: u32 = 0o120000;
constant O_ACCMODE (line 151) | pub const O_ACCMODE: u32 = 0o3;
constant O_RDONLY (line 155) | pub const O_RDONLY: u32 = 0o0;
constant O_WRONLY (line 156) | pub const O_WRONLY: u32 = 0o1;
constant O_RDWR (line 157) | pub const O_RDWR: u32 = 0o2;
type FileMode (line 161) | pub struct FileMode(u32);
method new (line 164) | pub fn new(val: u32) -> FileMode {
method access_mode (line 168) | pub fn access_mode(self) -> u32 {
method is_directory (line 172) | pub fn is_directory(self) -> bool {
method is_regular_file (line 176) | pub fn is_regular_file(self) -> bool {
method is_symbolic_link (line 180) | pub fn is_symbolic_link(self) -> bool {
type FsNode (line 185) | pub trait FsNode {
method get_name (line 186) | fn get_name(&self) -> String;
method get_name (line 321) | fn get_name(&self) -> String {
type File (line 189) | pub trait File: FsNode {
method open (line 191) | fn open(&self, _options: &OpenFlags) -> KResult<Option<FileRef>> {
method stat (line 196) | fn stat(&self) -> KResult<Stat> {
method readlink (line 201) | fn readlink(&self) -> KResult<PathBuf> {
method poll (line 207) | fn poll(&self) -> KResult<PollStatus> {
method ioctl (line 212) | fn ioctl(&self, _cmd: usize, _arg: usize) -> KResult<isize> {
method read (line 217) | fn read(&self, _offset: usize, _buf: UserBufferMut, _options: &OpenFla...
method write (line 222) | fn write(&self, _offset: usize, _buf: UserBuffer<'_>, _options: &OpenF...
type Symlink (line 227) | pub trait Symlink: FsNode {
method link_location (line 228) | fn link_location(&self) -> KResult<PathBuf>;
method stat (line 229) | fn stat(&self) -> KResult<Stat>;
method fsync (line 230) | fn fsync(&self) -> KResult<()> {
type Directory (line 235) | pub trait Directory: FsNode {
method insert (line 236) | fn insert(&self, inode: INode);
method lookup (line 239) | fn lookup(&self, name: &str) -> KResult<INode>;
method stat (line 241) | fn stat(&self) -> KResult<Stat>;
method fsync (line 243) | fn fsync(&self) -> KResult<()> {
method readlink (line 247) | fn readlink(&self) -> KResult<PathBuf> {
method readdir (line 252) | fn readdir(&self, index: usize) -> KResult<Option<DirEntry>>;
method unlink (line 254) | fn unlink(&self, name: &str) -> KResult<()>;
type INode (line 258) | pub enum INode {
method is_file (line 266) | pub fn is_file(&self) -> bool {
method is_dir (line 270) | pub fn is_dir(&self) -> bool {
method is_symlink (line 274) | pub fn is_symlink(&self) -> bool {
method is_pipe (line 278) | pub fn is_pipe(&self) -> bool {
method as_file (line 282) | pub fn as_file(&self) -> KResult<&FileRef> {
method stat (line 289) | pub fn stat(&self) -> KResult<Stat> {
method as_dir (line 298) | pub fn as_dir(&self) -> KResult<&DirRef> {
method as_symlink (line 305) | pub fn as_symlink(&self) -> KResult<&SymlinkRef> {
method as_pipe (line 312) | pub fn as_pipe(&self) -> KResult<&Arc<Pipe>> {
FILE: src/fs/opened_file.rs
constant FD_MAX (line 21) | const FD_MAX: c_int = 1024;
type FileDesc (line 50) | pub type FileDesc = c_int;
type OpenedFile (line 53) | pub struct OpenedFile {
method new (line 60) | pub fn new(path: PathComponent, options: OpenFlags, pos: usize) -> Ope...
method as_file (line 68) | pub fn as_file(&self) -> KResult<&FileRef> {
method as_dir (line 72) | pub fn as_dir(&self) -> KResult<&DirRef> {
method pos (line 76) | pub fn pos(&self) -> usize {
method options (line 80) | pub fn options(&self) -> OpenFlags {
method path (line 84) | pub fn path(&self) -> &PathComponent {
method inode (line 88) | pub fn inode(&self) -> &INode {
method read (line 92) | pub fn read(&self, buf: UserBufferMut) -> KResult<usize> {
method write (line 100) | pub fn write(&self, buf: UserBuffer) -> KResult<usize> {
method set_close_on_exec (line 108) | pub fn set_close_on_exec(&self, close_on_exec: bool) {
method set_flags (line 114) | pub fn set_flags(&self, flags: OpenFlags) -> KResult<()> {
method get_flags (line 120) | pub fn get_flags(&self) -> OpenFlags {
method poll (line 124) | pub fn poll(&self) -> KResult<PollStatus> {
method ioctl (line 128) | pub fn ioctl(&self, cmd: usize, arg: usize) -> KResult<isize> {
method readdir (line 132) | pub fn readdir(&self) -> KResult<Option<DirEntry>> {
method lseek (line 140) | pub fn lseek(&self, offset: usize, whence: LseekWhence) -> KResult<usi...
type LseekWhence (line 154) | pub enum LseekWhence {
method from (line 161) | fn from(value: usize) -> Self {
type LocalOpenedFile (line 172) | pub struct LocalOpenedFile {
type Target (line 177) | type Target = OpenedFile;
method deref (line 179) | fn deref(&self) -> &Self::Target {
type OpenedFileTable (line 185) | pub struct OpenedFileTable {
method new (line 197) | pub fn new() -> OpenedFileTable {
method get (line 204) | pub fn get(&self, fd: FileDesc) -> KResult<LocalOpenedFile> {
method open (line 211) | pub fn open(&mut self, path: PathComponent, options: OpenFlags) -> KRe...
method open_with_fd (line 217) | pub fn open_with_fd(
method alloc_fd (line 257) | fn alloc_fd(&mut self, gte: Option<i32>) -> KResult<FileDesc> {
method close_all (line 275) | pub fn close_all(&mut self) {
method close_cloexec_files (line 279) | pub fn close_cloexec_files(&mut self) {
method close (line 302) | pub fn close(&mut self, fd: FileDesc) -> KResult<()> {
method dup (line 310) | pub fn dup(&mut self, fd: FileDesc, gte: Option<i32>, options: OpenFla...
method dup2 (line 318) | pub fn dup2(&mut self, old_fd: FileDesc, new_fd: FileDesc) -> KResult<...
method open_socket (line 325) | pub fn open_socket(&mut self, domain: usize, typ: usize, protocol: usi...
method open_pipe (line 350) | pub fn open_pipe(&mut self, options: OpenFlags) -> KResult<Arc<Pipe>> {
method default (line 191) | fn default() -> Self {
FILE: src/fs/path.rs
type Path (line 6) | pub struct Path {
method new (line 11) | pub fn new(path: &str) -> &Path {
method as_str (line 20) | pub fn as_str(&self) -> &str {
method is_empty (line 24) | pub fn is_empty(&self) -> bool {
method is_absolute (line 28) | pub fn is_absolute(&self) -> bool {
method is_pipe (line 35) | pub fn is_pipe(&self) -> bool {
method pipe_name (line 39) | pub fn pipe_name(&self) -> Option<&str> {
method components (line 47) | pub fn components(&self) -> Components<'_> {
method parent_and_basename (line 57) | pub fn parent_and_basename(&self) -> Option<(&Path, &str)> {
method as_ref (line 78) | fn as_ref(&self) -> &Path {
method fmt (line 90) | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
function as_ref (line 84) | fn as_ref(&self) -> &Path {
type Components (line 95) | pub struct Components<'a> {
type Item (line 100) | type Item = &'a str;
method next (line 101) | fn next(&mut self) -> Option<Self::Item> {
type PathBuf (line 117) | pub struct PathBuf {
method new (line 122) | pub fn new() -> PathBuf {
method as_path (line 128) | pub fn as_path(&self) -> &Path {
method pop (line 132) | pub fn pop(&mut self) {
method push (line 138) | pub fn push<P: AsRef<Path>>(&mut self, path: P) {
type Target (line 164) | type Target = Path;
method deref (line 165) | fn deref(&self) -> &Self::Target {
method as_ref (line 171) | fn as_ref(&self) -> &Path {
method from (line 177) | fn from(value: &Path) -> Self {
method from (line 185) | fn from(value: String) -> Self {
method from (line 192) | fn from(value: &str) -> Self {
method default (line 158) | fn default() -> Self {
type PathComponent (line 201) | pub struct PathComponent {
method resolve_abs_path (line 208) | pub fn resolve_abs_path(&self) -> PathBuf {
FILE: src/fs/pipe.rs
type Pipe (line 14) | pub struct Pipe {
method new (line 22) | pub fn new(read_fd: FileDesc, write_fd: FileDesc) -> Self {
method read_pipe (line 31) | pub fn read_pipe(&self, buf: UserBufferMut<'_>) -> KResult<usize> {
method write_pipe (line 51) | pub fn write_pipe(&self, buf: UserBuffer<'_>) -> KResult<usize> {
method read_fd (line 71) | pub fn read_fd(&self) -> FileDesc {
method write_fd (line 75) | pub fn write_fd(&self) -> FileDesc {
method get_name (line 81) | fn get_name(&self) -> alloc::string::String {
method read (line 87) | fn read(
method write (line 96) | fn write(
type PipeFs (line 106) | pub struct PipeFs {
method new (line 112) | pub const fn new() -> Self {
method insert (line 118) | pub fn insert(&self, pipe: Arc<Pipe>) {
method lookup (line 122) | pub fn lookup(&self, path: &Path) -> KResult<Arc<Pipe>> {
FILE: src/god_mode.rs
function init (line 19) | pub fn init() {
function read_cmd (line 26) | fn read_cmd() -> String {
function god_mode_repl (line 44) | pub fn god_mode_repl() {
FILE: src/graphics/mod.rs
constant FONT (line 19) | const FONT: MonoFont = FONT_8X13;
type FrameBuffer (line 21) | pub struct FrameBuffer {
method width (line 34) | pub fn width(&self) -> usize {
method height (line 38) | pub fn height(&self) -> usize {
method bpp (line 42) | pub fn bpp(&self) -> usize {
method render_text_buf (line 46) | pub fn render_text_buf(&mut self) {
method clear_pixels (line 75) | pub fn clear_pixels(&mut self) {
method frame_mut (line 79) | pub fn frame_mut(&mut self) -> &mut [u32] {
method present (line 83) | pub fn present(&mut self) {
method write_byte (line 91) | pub fn write_byte(&mut self, byte: u8) {
method cursor_color_hook (line 111) | fn cursor_color_hook(&mut self) {}
method backspace (line 113) | pub fn backspace(&mut self) {
method write_string (line 121) | pub fn write_string(&mut self, s: &str) {
method new_line (line 127) | fn new_line(&mut self) {
method clear_row (line 145) | fn clear_row(&mut self, row: usize) {
method clear_until_end (line 151) | fn clear_until_end(&mut self) {
method clear_until_beginning (line 160) | fn clear_until_beginning(&mut self) {
method clear_until_eol (line 169) | fn clear_until_eol(&mut self) {
method clear_from_bol (line 175) | fn clear_from_bol(&mut self) {
method clear_line (line 181) | fn clear_line(&mut self) {
method clear_all (line 184) | fn clear_all(&mut self) {
method move_up (line 190) | fn move_up(&mut self) {
method move_down (line 200) | fn move_down(&mut self) {
method move_left (line 210) | fn move_left(&mut self) {
method move_right (line 214) | fn move_right(&mut self) {
method write_str (line 221) | fn write_str(&mut self, s: &str) -> core::fmt::Result {
type Color (line 228) | type Color = Rgb888;
type Error (line 229) | type Error = core::convert::Infallible;
method draw_iter (line 231) | fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
method clear (line 246) | fn clear(&mut self, color: Self::Color) -> Result<(), Self::Error> {
method size (line 253) | fn size(&self) -> embedded_graphics::prelude::Size {
function fb (line 260) | pub fn fb<'a>() -> IrqMutexGuard<'a, FrameBuffer> {
function clear_screen (line 264) | pub fn clear_screen() {
function backspace (line 268) | pub fn backspace() {
function set_cursor_x (line 272) | pub fn set_cursor_x(x: usize) {
function set_cursor_y (line 276) | pub fn set_cursor_y(y: usize) {
function set_cursor_xy (line 280) | pub fn set_cursor_xy(xy: (usize, usize)) {
function cursor_xy (line 285) | pub fn cursor_xy() -> (usize, usize) {
function write_byte (line 290) | pub fn write_byte(byte: u8) {
function clear_until_end (line 294) | pub fn clear_until_end() {
function clear_until_beginning (line 298) | pub fn clear_until_beginning() {
function clear_from_bol (line 302) | pub fn clear_from_bol() {
function clear_until_eol (line 306) | pub fn clear_until_eol() {
function clear_line (line 310) | pub fn clear_line() {
function move_up (line 314) | pub fn move_up() {
function move_down (line 318) | pub fn move_down() {
function move_left (line 322) | pub fn move_left() {
function move_right (line 326) | pub fn move_right() {
function render_text_buf (line 330) | pub fn render_text_buf() {
function _fb_print (line 351) | pub fn _fb_print(args: core::fmt::Arguments) {
function init (line 358) | pub fn init(fb_tag: &FramebufferResponse) -> KResult<()> {
FILE: src/logging.rs
type KaDOSLogger (line 8) | struct KaDOSLogger;
method enabled (line 11) | fn enabled(&self, _metadata: &log::Metadata) -> bool {
method log (line 15) | fn log(&self, record: &log::Record) {
method flush (line 40) | fn flush(&self) {}
type KaDOSProfiler (line 43) | struct KaDOSProfiler;
method read_clock (line 46) | fn read_clock(&self) -> embedded_profiling::EPInstant {
method log_snapshot (line 51) | fn log_snapshot(&self, snapshot: &embedded_profiling::EPSnapshot) {
function init (line 56) | pub fn init() {
FILE: src/main.rs
function phys_offset (line 43) | pub fn phys_offset() -> VirtAddr {
function start (line 48) | pub extern "C" fn start() -> ! {
function hcf (line 54) | pub fn hcf() -> ! {
FILE: src/mem/addr.rs
type PhysAddr (line 14) | pub struct PhysAddr {
method new_unchecked (line 40) | pub const unsafe fn new_unchecked(addr: usize) -> Self {
method new (line 45) | pub const fn new(addr: usize) -> Self {
method null (line 55) | pub const fn null() -> Self {
method is_null (line 60) | pub const fn is_null(&self) -> bool {
method is_canonical (line 65) | pub const fn is_canonical(&self) -> bool {
method value (line 70) | pub const fn value(&self) -> usize {
method as_hhdm_virt (line 75) | pub fn as_hhdm_virt(&self) -> VirtAddr {
method is_aligned (line 80) | pub fn is_aligned(&self, align: usize) -> bool {
method const_add (line 84) | pub const fn const_add(&self, offset: usize) -> Self {
method const_sub (line 88) | pub const fn const_sub(&self, offset: usize) -> Self {
method fmt (line 94) | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
method fmt (line 102) | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
method fmt (line 108) | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
method fmt (line 114) | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
method fmt (line 120) | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
method fmt (line 126) | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
type Output (line 132) | type Output = Self;
method add (line 133) | fn add(self, rhs: usize) -> Self::Output {
method add_assign (line 139) | fn add_assign(&mut self, rhs: usize) {
type Output (line 145) | type Output = Self;
method sub (line 146) | fn sub(self, rhs: usize) -> Self::Output {
method sub_assign (line 152) | fn sub_assign(&mut self, rhs: usize) {
type Output (line 158) | type Output = usize;
method sub (line 159) | fn sub(self, rhs: PhysAddr) -> Self::Output {
function canonicalize_physaddr (line 19) | pub const fn canonicalize_physaddr(addr: usize) -> usize {
function is_canonical_physaddr (line 24) | pub const fn is_canonical_physaddr(addr: usize) -> bool {
function canonicalize_virtaddr (line 29) | pub const fn canonicalize_virtaddr(addr: usize) -> usize {
function is_canonical_virtaddr (line 34) | pub const fn is_canonical_virtaddr(addr: usize) -> bool {
type VirtAddr (line 166) | pub struct VirtAddr {
method new_unchecked (line 172) | pub const unsafe fn new_unchecked(addr: usize) -> Self {
method new (line 177) | pub const fn new(addr: usize) -> Self {
method null (line 183) | pub const fn null() -> Self {
method is_null (line 188) | pub const fn is_null(&self) -> bool {
method is_canonical (line 193) | pub const fn is_canonical(&self) -> bool {
method value (line 198) | pub const fn value(&self) -> usize {
method const_add (line 203) | pub const fn const_add(&self, offset: usize) -> Self {
method const_sub (line 208) | pub const fn const_sub(&self, offset: usize) -> Self {
method as_raw_ptr (line 213) | pub const fn as_raw_ptr<T>(&self) -> *const T {
method as_raw_ptr_mut (line 218) | pub const fn as_raw_ptr_mut<T>(&self) -> *mut T {
method deref (line 223) | pub unsafe fn deref<T>(&self) -> KResult<&T> {
method deref_mut (line 229) | pub unsafe fn deref_mut<T>(&mut self) -> KResult<&mut T> {
method as_ptr (line 235) | pub const fn as_ptr<T>(self) -> UnsafePtr<T> {
method as_hhdm_phys (line 240) | pub fn as_hhdm_phys(&self) -> PhysAddr {
method align_ok (line 244) | pub const fn align_ok<T: Sized>(&self) -> KResult<()> {
method user_ok (line 258) | pub fn user_ok(&self) -> KResult<()> {
method read (line 272) | pub unsafe fn read<T: Sized + Copy>(&self) -> KResult<T> {
method read_volatile (line 277) | pub unsafe fn read_volatile<T: Sized + Copy>(&self) -> KResult<T> {
method read_user (line 282) | pub unsafe fn read_user<T: Sized + Copy>(&self) -> KResult<T> {
method read_bytes (line 289) | pub unsafe fn read_bytes(&self, buf: &mut [u8]) -> KResult<usize> {
method read_bytes_user (line 295) | pub unsafe fn read_bytes_user(&self, buf: &mut [u8]) -> KResult<usize> {
method write (line 303) | pub unsafe fn write<T: Sized + Copy>(&self, t: T) -> KResult<()> {
method write_volatile (line 309) | pub unsafe fn write_volatile<T: Sized + Copy>(&self, t: T) -> KResult<...
method write_user (line 315) | pub unsafe fn write_user<T: Sized + Copy>(&self, t: T) -> KResult<()> {
method write_bytes (line 323) | pub unsafe fn write_bytes(&self, bytes: &[u8]) -> KResult<usize> {
method write_bytes_user (line 334) | pub unsafe fn write_bytes_user(&self, bytes: &[u8]) -> KResult<usize> {
method fill (line 348) | pub unsafe fn fill(&self, value: u8, len: usize) -> KResult<usize> {
method align_down (line 357) | pub const fn align_down(&self, align: usize) -> Self {
method align_up (line 362) | pub const fn align_up(&self, align: usize) -> Self {
method p4_index (line 366) | pub fn p4_index(&self) -> usize {
method p3_index (line 369) | pub fn p3_index(&self) -> usize {
method p2_index (line 372) | pub fn p2_index(&self) -> usize {
method p1_index (line 375) | pub fn p1_index(&self) -> usize {
method fmt (line 381) | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
method fmt (line 390) | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
method fmt (line 397) | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
method fmt (line 404) | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
method fmt (line 411) | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
method fmt (line 418) | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
type Output (line 424) | type Output = Self;
method add (line 426) | fn add(self, rhs: usize) -> Self::Output {
method add_assign (line 433) | fn add_assign(&mut self, rhs: usize) {
type Output (line 439) | type Output = Self;
method sub (line 441) | fn sub(self, rhs: usize) -> Self::Output {
method sub_assign (line 448) | fn sub_assign(&mut self, rhs: usize) {
type Output (line 454) | type Output = usize;
method sub (line 456) | fn sub(self, rhs: VirtAddr) -> Self::Output {
type UnsafePtr (line 464) | pub struct UnsafePtr<T> {
function new (line 470) | pub const fn new(addr: VirtAddr) -> Self {
function from_ref (line 487) | pub fn from_ref(data: &T) -> Self {
function from_mut (line 491) | pub fn from_mut(data: &mut T) -> Self {
function from_raw_ptr (line 495) | pub fn from_raw_ptr(ptr: *mut T) -> Self {
function as_raw_ptr (line 499) | pub fn as_raw_ptr(&self) -> *const T {
function as_raw_ptr_mut (line 503) | pub fn as_raw_ptr_mut(&self) -> *mut T {
function deref (line 507) | pub unsafe fn deref(&self) -> &T {
function deref_mut (line 511) | pub unsafe fn deref_mut(&mut self) -> &mut T {
function as_ref (line 515) | pub unsafe fn as_ref(&self) -> Ref<'_, T> {
function as_mut (line 519) | pub unsafe fn as_mut(&mut self) -> Mut<'_, T> {
function cast (line 523) | pub fn cast<U>(self) -> UnsafePtr<U> {
function into_non_null (line 527) | pub fn into_non_null(self) -> NonNull<T> {
function read (line 535) | pub fn read(&self) -> KResult<T>
function read_volatile (line 542) | pub fn read_volatile(&self) -> KResult<T>
function fmt (line 551) | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
type UnsafeSlice (line 558) | pub struct UnsafeSlice<T> {
function new (line 565) | pub fn new(addr: VirtAddr, len: usize) -> Self {
function len (line 583) | pub fn len(&self) -> usize {
function is_empty (line 587) | pub fn is_empty(&self) -> bool {
function as_ptr (line 591) | pub fn as_ptr(&self) -> UnsafePtr<T> {
function as_slice (line 595) | pub unsafe fn as_slice(&self) -> &[T] {
function as_mut_slice (line 599) | pub unsafe fn as_mut_slice(&mut self) -> &mut [T] {
function into_raw_parts (line 603) | pub fn into_raw_parts(self) -> (VirtAddr, usize) {
type Ref (line 610) | pub struct Ref<'a, T> {
function new (line 616) | pub fn new(data: &'a T) -> Self {
function addr (line 623) | pub fn addr(&self) -> VirtAddr {
function deref (line 628) | pub fn deref(&self) -> &'a T {
function as_ptr (line 632) | pub fn as_ptr(&self) -> UnsafePtr<T> {
function as_raw_ptr (line 636) | pub fn as_raw_ptr(&self) -> *const T {
function as_raw_ptr_mut (line 640) | pub fn as_raw_ptr_mut(&self) -> *mut T {
type Target (line 646) | type Target = T;
method deref (line 648) | fn deref(&self) -> &Self::Target {
function fmt (line 654) | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
type Mut (line 661) | pub struct Mut<'a, T> {
function new (line 667) | pub fn new(data: &'a mut T) -> Self {
function addr (line 674) | pub fn addr(&self) -> VirtAddr {
function as_ptr (line 678) | pub fn as_ptr(&self) -> UnsafePtr<T> {
function deref (line 683) | pub fn deref(&self) -> &'a T {
function deref_mut (line 688) | pub fn deref_mut(&mut self) -> &'a mut T {
function as_raw_ptr (line 692) | pub fn as_raw_ptr(&self) -> *const T {
function as_raw_ptr_mut (line 696) | pub fn as_raw_ptr_mut(&self) -> *mut T {
function fmt (line 702) | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
type Target (line 708) | type Target = T;
method deref (line 710) | fn deref(&self) -> &Self::Target {
method deref_mut (line 716) | fn deref_mut(&mut self) -> &mut Self::Target {
type Slice (line 723) | pub struct Slice<'a, T> {
function new (line 730) | pub fn new(data: &'a [T]) -> Self {
function from_raw_parts (line 738) | pub unsafe fn from_raw_parts(addr: VirtAddr, len: usize) -> Self {
function addr (line 747) | pub fn addr(&self) -> VirtAddr {
function len (line 751) | pub fn len(&self) -> usize {
function is_empty (line 755) | pub fn is_empty(&self) -> bool {
function as_ptr (line 759) | pub fn as_ptr(&self) -> UnsafePtr<T> {
function as_slice (line 763) | pub fn as_slice(&self) -> &'a [T] {
function as_raw_ptr (line 767) | pub fn as_raw_ptr(&self) -> *const T {
function as_raw_ptr_mut (line 771) | pub fn as_raw_ptr_mut(&self) -> *mut T {
function fmt (line 777) | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
type Target (line 783) | type Target = [T];
method deref (line 785) | fn deref(&self) -> &Self::Target {
type Output (line 791) | type Output = T;
function index (line 793) | fn index(&self, index: usize) -> &Self::Output {
type SliceMut (line 800) | pub struct SliceMut<'a, T> {
function new (line 807) | pub fn new(data: &'a mut [T]) -> Self {
function from_raw_parts (line 815) | pub unsafe fn from_raw_parts(addr: VirtAddr, len: usize) -> Self {
function addr (line 824) | pub fn addr(&self) -> VirtAddr {
function len (line 828) | pub fn len(&self) -> usize {
function is_empty (line 832) | pub fn is_empty(&self) -> bool {
function as_ptr (line 836) | pub fn as_ptr(&self) -> UnsafePtr<T> {
function as_slice (line 840) | pub fn as_slice(&self) -> &'a [T] {
function as_mut_slice (line 844) | pub fn as_mut_slice(&mut self) -> &'a mut [T] {
function as_raw_ptr (line 848) | pub fn as_raw_ptr(&self) -> *const T {
function as_raw_ptr_mut (line 852) | pub fn as_raw_ptr_mut(&self) -> *mut T {
function fmt (line 858) | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
type Target (line 864) | type Target = [T];
method deref (line 866) | fn deref(&self) -> &Self::Target {
method deref_mut (line 872) | fn deref_mut(&mut self) -> &mut Self::Target {
type Output (line 878) | type Output = T;
function index (line 880) | fn index(&self, index: usize) -> &Self::Output {
function index_mut (line 886) | fn index_mut(&mut self, index: usize) -> &mut Self::Output {
FILE: src/mem/addr_space.rs
type AddressSpace (line 19) | pub struct AddressSpace {
method new (line 24) | pub fn new() -> KResult<Self> {
method current (line 65) | pub fn current() -> Self {
method cr3 (line 77) | pub fn cr3(&self) -> PhysAddr {
method switch (line 81) | pub fn switch(&self) {
method temporarily_switch (line 92) | pub fn temporarily_switch(&self) -> TmpAddrSpaceGuard {
method with_mapper (line 98) | pub fn with_mapper<R>(&mut self, f: impl FnOnce(Mapper) -> R) -> R {
method map_two (line 107) | pub fn map_two<R>(
method is_active (line 123) | pub fn is_active(&self) -> bool {
method fork (line 127) | pub fn fork(&mut self, set_cow: bool) -> KResult<AddressSpace> {
type TmpAddrSpaceGuard (line 189) | pub struct TmpAddrSpaceGuard {
method drop (line 194) | fn drop(&mut self) {
FILE: src/mem/allocator.rs
function alloc_kernel_frames (line 25) | pub fn alloc_kernel_frames(count: usize) -> KResult<AllocatedFrames> {
function alloc_kernel_frames_at (line 33) | pub fn alloc_kernel_frames_at(start: Frame, count: usize) -> KResult<All...
function alloc_kernel_pages (line 41) | pub fn alloc_kernel_pages(count: usize) -> KResult<AllocatedPages> {
function alloc_kernel_pages_at (line 49) | pub fn alloc_kernel_pages_at(start: Page, count: usize) -> KResult<Alloc...
function free_kernel_frames (line 57) | pub fn free_kernel_frames(frames: &mut AllocatedFrames, merge: bool) -> ...
function free_kernel_pages (line 66) | pub fn free_kernel_pages(pages: &mut AllocatedPages, merge: bool) -> KRe...
function init (line 75) | pub fn init(memmap: &[&Entry]) -> KResult<()> {
type StaticListOrVec (line 111) | pub enum StaticListOrVec<T: Clone, const STATIC_CAP: usize> {
function new_static (line 117) | pub const fn new_static() -> StaticListOrVec<T, STATIC_CAP> {
function new_vec (line 120) | pub const fn new_vec() -> StaticListOrVec<T, STATIC_CAP> {
function push (line 123) | pub fn push(&mut self, item: T) {
function remove (line 129) | pub fn remove(&mut self, index: usize) -> T {
function convert_to_vec (line 135) | pub fn convert_to_vec(&mut self) {
function iter (line 143) | pub fn iter(&self) -> impl Iterator<Item = &T> {
function iter_mut (line 149) | pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
function len (line 155) | pub fn len(&self) -> usize {
function is_empty (line 161) | pub fn is_empty(&self) -> bool {
function swap (line 167) | pub fn swap(&mut self, a: usize, b: usize) {
function get (line 173) | pub fn get(&self, index: usize) -> Option<&T> {
type Output (line 182) | type Output = T;
function index (line 183) | fn index(&self, index: usize) -> &Self::Output {
function index_mut (line 192) | fn index_mut(&mut self, index: usize) -> &mut Self::Output {
type Allocator (line 201) | pub struct Allocator<T: MemoryUnit> {
function new_static (line 206) | pub fn new_static() -> Self {
function new_vec (line 212) | pub fn new_vec() -> Self {
function convert_to_heap_allocated (line 218) | pub fn convert_to_heap_allocated(&mut self) {
function free_regions (line 222) | pub fn free_regions(&self) -> impl Iterator<Item = &MemoryRange<T>> {
function insert_free_region (line 226) | pub unsafe fn insert_free_region(&mut self, range: MemoryRange<T>) {
function allocate (line 230) | pub fn allocate(&mut self, count: usize) -> KResult<Allocated<T>> {
function allocate_at (line 252) | pub fn allocate_at(&mut self, start: T, count: usize) -> KResult<Allocat...
function free (line 282) | pub fn free(&mut self, allocated: &mut Allocated<T>, merge: bool) {
type FrameAllocator (line 301) | pub type FrameAllocator = Allocator<Frame>;
type PageAllocator (line 302) | pub type PageAllocator = Allocator<Page>;
FILE: src/mem/consts.rs
constant PAGE_SHIFT (line 3) | pub const PAGE_SHIFT: usize = 12;
constant PAGE_SIZE (line 4) | pub const PAGE_SIZE: usize = 0x1000;
constant PAGE_TABLE_ENTRIES (line 5) | pub const PAGE_TABLE_ENTRIES: usize = 512;
constant L4_SHIFT (line 6) | pub const L4_SHIFT: usize = 39;
constant L3_SHIFT (line 7) | pub const L3_SHIFT: usize = 30;
constant L2_SHIFT (line 8) | pub const L2_SHIFT: usize = 21;
constant L1_SHIFT (line 9) | pub const L1_SHIFT: usize = 12;
constant KERNEL_STACK_SIZE (line 11) | pub const KERNEL_STACK_SIZE: usize = PAGE_SIZE * 32;
constant USER_STACK_SIZE (line 12) | pub const USER_STACK_SIZE: usize = PAGE_SIZE * 64;
constant MAX_LOW_VADDR (line 16) | pub const MAX_LOW_VADDR: VirtAddr = unsafe { VirtAddr::new_unchecked(0x0...
constant MIN_HIGH_VADDR (line 20) | pub const MIN_HIGH_VADDR: VirtAddr = unsafe { VirtAddr::new_unchecked(0x...
constant USER_VALLOC_BASE (line 22) | pub const USER_VALLOC_BASE: VirtAddr = unsafe { VirtAddr::new_unchecked(...
constant USER_VALLOC_END (line 23) | pub const USER_VALLOC_END: VirtAddr = unsafe { VirtAddr::new_unchecked(0...
constant USER_STACK_TOP (line 24) | pub const USER_STACK_TOP: VirtAddr = unsafe { VirtAddr::new_unchecked(0x...
constant USER_STACK_BOTTOM (line 25) | pub const USER_STACK_BOTTOM: VirtAddr = USER_STACK_TOP.const_sub(USER_ST...
constant KERNEL_HEAP_START (line 27) | pub const KERNEL_HEAP_START: VirtAddr = unsafe { VirtAddr::new_unchecked...
constant KERNEL_HEAP_SIZE (line 28) | pub const KERNEL_HEAP_SIZE: usize = 1024 * 1024 * 1024;
FILE: src/mem/mod.rs
function remap_kernel (line 30) | pub fn remap_kernel() -> KResult<&'static IrqMutex<AddressSpace>> {
function init_heap (line 42) | pub fn init_heap(kernel_mapper: &mut Mapper) -> KResult<MappedPages> {
function kernel_addr_space_scope (line 60) | pub fn kernel_addr_space_scope() -> KResult<KernelAddrSpaceGuard> {
function with_kernel_addr_space (line 64) | pub fn with_kernel_addr_space<R, F: FnOnce() -> R>(f: F) -> R {
type KernelAddrSpaceGuard (line 70) | pub struct KernelAddrSpaceGuard {
method new (line 76) | pub fn new() -> KResult<Self> {
method drop (line 92) | fn drop(&mut self) {
FILE: src/mem/paging/mapper.rs
type PageFlush (line 19) | pub struct PageFlush(Page);
method new (line 22) | pub fn new(page: Page) -> Self {
method ignore (line 26) | pub fn ignore(self) {}
method flush (line 28) | pub fn flush(self) {
type Mapper (line 34) | pub struct Mapper<'a> {
function new (line 39) | pub fn new(p4: &'a mut PageTable) -> Self {
function into_inner (line 43) | pub fn into_inner(self) -> &'a mut PageTable {
function translate (line 47) | pub fn translate(&self, addr: VirtAddr) -> Option<(PhysAddr, PageTableFl...
function map_to_single (line 56) | pub fn map_to_single(
function map_to (line 93) | pub fn map_to(
function map (line 111) | pub fn map(&mut self, pages: AllocatedPages, flags: PageTableFlags) -> K...
function set_flags (line 116) | pub fn set_flags(&mut self, mp: &mut MappedPages, flags: PageTableFlags) {
function unmap (line 129) | pub unsafe fn unmap(&mut self, mp: MappedPages) -> (AllocatedPages, Allo...
function unmap_single (line 143) | pub unsafe fn unmap_single(&mut self, page: Page) -> Option<Frame> {
function set_flags_single (line 155) | pub unsafe fn set_flags_single(&mut self, page: Page, flags: PageTableFl...
FILE: src/mem/paging/table.rs
function frame_to_table (line 20) | fn frame_to_table(frame: Frame) -> *mut PageTable {
type PageTableEntry (line 27) | pub struct PageTableEntry {
constant ADDRESS_MASK (line 32) | const ADDRESS_MASK: usize = 0x000f_ffff_ffff_f000;
constant FLAGS_MASK (line 33) | const FLAGS_MASK: usize = 0x01ff;
method new (line 36) | pub const fn new() -> Self {
method is_unused (line 40) | pub const fn is_unused(&self) -> bool {
method set_unused (line 44) | pub fn set_unused(&mut self) {
method flags (line 48) | pub const fn flags(&self) -> PageTableFlags {
method addr (line 52) | pub fn addr(&self) -> PhysAddr {
method frame (line 56) | pub fn frame(&self) -> Option<Frame> {
method set_addr (line 66) | pub fn set_addr(&mut self, addr: PhysAddr, flags: PageTableFlags) {
method set_frame (line 72) | pub fn set_frame(&mut self, frame: Frame, flags: PageTableFlags) {
method set_flags (line 76) | pub fn set_flags(&mut self, flags: PageTableFlags) {
method fmt (line 83) | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
type PageTable (line 93) | pub struct PageTable {
method new (line 100) | pub const fn new() -> Self {
method zero (line 107) | pub fn zero(&mut self) {
method next_table (line 113) | pub fn next_table<'b>(&self, index: usize) -> Option<&'b PageTable> {
method next_table_mut (line 118) | pub fn next_table_mut<'b>(&self, index: usize) -> Option<&'b mut PageT...
method next_table_create (line 123) | pub fn next_table_create<'b>(
type Output (line 161) | type Output = PageTableEntry;
method index (line 162) | fn index(&self, index: usize) -> &Self::Output {
method index_mut (line 168) | fn index_mut(&mut self, index: usize) -> &mut Self::Output {
method fmt (line 174) | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
function active_table (line 189) | pub fn active_table() -> &'static mut PageTable {
FILE: src/mem/paging/units.rs
type PageIndex (line 17) | pub struct PageIndex(pub usize);
method new (line 21) | pub fn new(index: usize) -> Self {
method containing_physaddr (line 26) | pub fn containing_physaddr(paddr: PhysAddr) -> Self {
method containing_virtaddr (line 31) | pub fn containing_virtaddr(vaddr: VirtAddr) -> Self {
method as_physaddr (line 36) | pub fn as_physaddr(self) -> PhysAddr {
method as_virtaddr (line 41) | pub fn as_virtaddr(self) -> VirtAddr {
type Output (line 47) | type Output = Self;
method add (line 48) | fn add(self, rhs: usize) -> Self::Output {
type Output (line 54) | type Output = Self;
method sub (line 55) | fn sub(self, rhs: usize) -> Self::Output {
method add_assign (line 61) | fn add_assign(&mut self, rhs: usize) {
method sub_assign (line 67) | fn sub_assign(&mut self, rhs: usize) {
type MemoryUnit (line 72) | pub trait MemoryUnit:
method containing_address (line 93) | fn containing_address(addr: Self::Address) -> Self;
method at_index (line 94) | fn at_index(index: PageIndex) -> Self;
method start_address (line 95) | fn start_address(self) -> Self::Address;
method inclusive_end_address (line 96) | fn inclusive_end_address(self) -> Self::Address;
method index (line 97) | fn index(self) -> PageIndex;
type Address (line 107) | type Address = PhysAddr;
method containing_address (line 110) | fn containing_address(addr: PhysAddr) -> Self {
method at_index (line 117) | fn at_index(index: PageIndex) -> Self {
method start_address (line 122) | fn start_address(self) -> Self::Address {
method inclusive_end_address (line 127) | fn inclusive_end_address(self) -> Self::Address {
method index (line 132) | fn index(self) -> PageIndex {
type Address (line 175) | type Address = VirtAddr;
method containing_address (line 178) | fn containing_address(addr: VirtAddr) -> Self {
method at_index (line 185) | fn at_index(index: PageIndex) -> Self {
method start_address (line 190) | fn start_address(self) -> Self::Address {
method inclusive_end_address (line 195) | fn inclusive_end_address(self) -> Self::Address {
method index (line 200) | fn index(self) -> PageIndex {
type Frame (line 102) | pub struct Frame {
type Output (line 144) | type Output = Self;
method add (line 145) | fn add(self, rhs: usize) -> Self::Output {
type Output (line 151) | type Output = Self;
method sub (line 152) | fn sub(self, rhs: usize) -> Self::Output {
method add_assign (line 158) | fn add_assign(&mut self, rhs: usize) {
method sub_assign (line 164) | fn sub_assign(&mut self, rhs: usize) {
method fmt (line 138) | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
type Page (line 170) | pub struct Page {
type Output (line 212) | type Output = Self;
method add (line 213) | fn add(self, rhs: usize) -> Self::Output {
type Output (line 219) | type Output = Self;
method sub (line 220) | fn sub(self, rhs: usize) -> Self::Output {
method add_assign (line 226) | fn add_assign(&mut self, rhs: usize) {
method sub_assign (line 232) | fn sub_assign(&mut self, rhs: usize) {
method fmt (line 206) | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
type PageMergeError (line 238) | pub struct PageMergeError;
type MemoryRange (line 241) | pub struct MemoryRange<T: MemoryUnit> {
function new (line 248) | pub fn new(start: T, end: T) -> Self {
function empty (line 253) | pub fn empty() -> Self {
function start (line 261) | pub fn start(self) -> T {
function end (line 266) | pub fn end(self) -> T {
function size_in_pages (line 271) | pub fn size_in_pages(self) -> usize {
function size_in_bytes (line 279) | pub fn size_in_bytes(self) -> usize {
function is_empty (line 284) | pub fn is_empty(self) -> bool {
function start_address (line 289) | pub fn start_address(self) -> T::Address {
function end_address (line 294) | pub fn end_address(self) -> T::Address {
function inclusive_end_address (line 299) | pub fn inclusive_end_address(self) -> T::Address {
function merge_with (line 303) | pub fn merge_with(&mut self, other: Self) -> Result<(), PageMergeError> {
function overlaps (line 320) | pub fn overlaps(self, other: Self) -> bool {
function consumes (line 327) | pub fn consumes(self, other: Self) -> bool {
function contains (line 334) | pub fn contains(self, unit: T) -> bool {
function iter (line 341) | pub fn iter(self) -> MemoryRangeIter<T> {
type FrameRange (line 349) | pub type FrameRange = MemoryRange<Frame>;
type PageRange (line 350) | pub type PageRange = MemoryRange<Page>;
type MemoryRangeIter (line 352) | pub struct MemoryRangeIter<T: MemoryUnit> {
type Item (line 358) | type Item = T;
method next (line 359) | fn next(&mut self) -> Option<Self::Item> {
type Allocated (line 370) | pub struct Allocated<T: MemoryUnit> {
function assume_allocated (line 375) | pub unsafe fn assume_allocated(range: MemoryRange<T>) -> Self {
method fmt (line 381) | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
type AllocatedFrames (line 391) | pub type AllocatedFrames = Allocated<Frame>;
type AllocatedPages (line 392) | pub type AllocatedPages = Allocated<Page>;
type Target (line 395) | type Target = MemoryRange<T>;
function deref (line 396) | fn deref(&self) -> &Self::Target {
function deref_mut (line 402) | fn deref_mut(&mut self) -> &mut Self::Target {
type MappedPages (line 407) | pub struct MappedPages {
method assume_mapped (line 414) | pub unsafe fn assume_mapped(
method unmap (line 426) | pub unsafe fn unmap(self, table: &mut Mapper) -> (AllocatedPages, Allo...
method pages (line 430) | pub fn pages(&self) -> &AllocatedPages {
method frames (line 434) | pub fn frames(&self) -> &AllocatedFrames {
method flags (line 438) | pub fn flags(&self) -> PageTableFlags {
method fmt (line 444) | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
FILE: src/serial.rs
constant SERIAL0_IOPORT (line 8) | pub const SERIAL0_IOPORT: u16 = 0x3f8;
constant SERIAL1_IOPORT (line 9) | pub const SERIAL1_IOPORT: u16 = 0x2f8;
constant SERIAL2_IOPORT (line 10) | pub const SERIAL2_IOPORT: u16 = 0x3e8;
function _print0 (line 33) | pub fn _print0(args: ::core::fmt::Arguments) {
function _print1 (line 63) | pub fn _print1(args: ::core::fmt::Arguments) {
function serial1_recv (line 75) | pub fn serial1_recv() -> Option<u8> {
function _print2 (line 109) | pub fn _print2(args: ::core::fmt::Arguments) {
FILE: src/task/group.rs
type PgId (line 10) | pub type PgId = i32;
type TaskGroup (line 12) | pub struct TaskGroup {
method new (line 18) | pub(super) fn new(pgid: PgId) -> Arc<IrqMutex<TaskGroup>> {
method pgid (line 25) | pub fn pgid(&self) -> PgId {
method set_pgid (line 29) | pub fn set_pgid(&mut self, pgid: PgId) {
method add (line 33) | pub fn add(&mut self, task: Weak<Task>) {
method remove (line 37) | pub fn remove(&mut self, task: &Weak<Task>) {
method gc_dropped_processes (line 44) | pub fn gc_dropped_processes(&mut self) {
method signal (line 51) | pub fn signal(&mut self, signal: Signal) {
FILE: src/task/mod.rs
function init (line 45) | pub fn init() {
function get_scheduler (line 49) | pub fn get_scheduler() -> &'static Arc<Scheduler> {
function current_task (line 53) | pub fn current_task() -> Arc<Task> {
type TaskId (line 58) | pub struct TaskId(usize);
method new (line 61) | pub const fn new(pid: usize) -> Self {
method allocate (line 65) | fn allocate() -> Self {
method as_usize (line 70) | pub fn as_usize(&self) -> usize {
type TaskState (line 76) | pub enum TaskState {
type Task (line 82) | pub struct Task {
method new_idle (line 109) | pub fn new_idle(sched: &mut Scheduler) -> Arc<Task> {
method new_kernel (line 132) | pub fn new_kernel(sched: &Scheduler, entry_point: fn(), enable_interru...
method exec (line 158) | pub fn exec(&self, file: FileRef, argv: &[&[u8]], envp: &[&[u8]]) -> K...
method make_child (line 173) | pub fn make_child(&self, arch: UnsafeCell<ArchTask>) -> Arc<Task> {
method fork (line 201) | pub fn fork(&self) -> Arc<Task> {
method clone_process (line 206) | pub fn clone_process(
method add_child (line 245) | fn add_child(&self, child: Arc<Task>) {
method arch_mut (line 252) | pub fn arch_mut(&self) -> &mut ArchTask {
method pid (line 256) | pub fn pid(&self) -> TaskId {
method ppid (line 260) | pub fn ppid(&self) -> TaskId {
method pgid (line 268) | pub fn pgid(&self) -> Option<PgId> {
method get_state (line 272) | pub fn get_state(&self) -> TaskState {
method set_state (line 276) | pub fn set_state(&self, state: TaskState) {
method set_parent (line 284) | fn set_parent(&self, parent: Weak<Task>) {
method belongs_to_group (line 288) | pub fn belongs_to_group(&self, pg: &Weak<IrqMutex<TaskGroup>>) -> bool {
method get_opened_file_by_fd (line 292) | pub fn get_opened_file_by_fd(&self, fd: FileDesc) -> KResult<LocalOpen...
method vmem (line 296) | pub fn vmem(&self) -> Arc<IrqMutex<Vmem>> {
method handle_page_fault (line 300) | pub fn handle_page_fault(
method set_signal_mask (line 312) | pub fn set_signal_mask(
method has_pending_signals (line 339) | pub fn has_pending_signals(&self) -> bool {
FILE: src/task/scheduler.rs
type Scheduler (line 32) | pub struct Scheduler {
method new (line 50) | pub fn new() -> Arc<Self> {
method push_runnable (line 73) | pub fn push_runnable(&self, task: Arc<Task>, priority: bool) {
method push_waiting (line 88) | pub fn push_waiting(&self, task: Arc<Task>) {
method push_deadline_waiting (line 102) | pub fn push_deadline_waiting(&self, task: Arc<Task>, duration: usize) {
method check_deadline (line 115) | fn check_deadline(&self) {
method current_task_opt (line 132) | pub fn current_task_opt(&self) -> Option<Arc<Task>> {
method current_task (line 139) | pub fn current_task(&self) -> Arc<Task> {
method find_task (line 146) | pub fn find_task(&self, pid: TaskId) -> Option<Arc<Task>> {
method find_group (line 150) | pub fn find_group(&self, pgid: PgId) -> Option<Arc<IrqMutex<TaskGroup>...
method find_or_create_group (line 154) | pub fn find_or_create_group(&self, pgid: PgId) -> Arc<IrqMutex<TaskGro...
method exit_current (line 162) | pub fn exit_current(&self, status: c_int) {
method wake_all (line 191) | pub fn wake_all(&self, queue: &WaitQueue) {
method send_signal_to (line 198) | pub fn send_signal_to(&self, task: Arc<Task>, signal: Signal) {
method resume_task (line 203) | pub fn resume_task(&self, task: Arc<Task>) {
method try_delivering_signal (line 207) | pub fn try_delivering_signal(
method restore_signaled_user_stack (line 249) | pub fn restore_signaled_user_stack(&self, current_frame: &mut Interrup...
method reap_dead (line 258) | pub fn reap_dead(&self) {
method preempt (line 275) | pub fn preempt(&self) {
method sleep (line 294) | pub fn sleep(&self, duration: Option<usize>) -> KResult<()> {
function switch (line 312) | pub fn switch() {
function reap (line 384) | fn reap() {
function preempt (line 392) | fn preempt() {
FILE: src/task/signal.rs
type Signal (line 8) | pub type Signal = c_int;
constant SIGHUP (line 10) | pub const SIGHUP: Signal = 1;
constant SIGINT (line 12) | pub const SIGINT: Signal = 2;
constant SIGQUIT (line 14) | pub const SIGQUIT: Signal = 3;
constant SIGILL (line 16) | pub const SIGILL: Signal = 4;
constant SIGTRAP (line 18) | pub const SIGTRAP: Signal = 5;
constant SIGABRT (line 20) | pub const SIGABRT: Signal = 6;
constant SIGBUS (line 22) | pub const SIGBUS: Signal = 7;
constant SIGFPE (line 24) | pub const SIGFPE: Signal = 8;
constant SIGKILL (line 26) | pub const SIGKILL: Signal = 9;
constant SIGUSR1 (line 28) | pub const SIGUSR1: Signal = 10;
constant SIGSEGV (line 30) | pub const SIGSEGV: Signal = 11;
constant SIGUSR2 (line 32) | pub const SIGUSR2: Signal = 12;
constant SIGPIPE (line 34) | pub const SIGPIPE: Signal = 13;
constant SIGALRM (line 36) | pub const SIGALRM: Signal = 14;
constant SIGTERM (line 38) | pub const SIGTERM: Signal = 15;
constant SIGSTKFLT (line 40) | pub const SIGSTKFLT: Signal = 16;
constant SIGCHLD (line 42) | pub const SIGCHLD: Signal = 17;
constant SIGCONT (line 44) | pub const SIGCONT: Signal = 18;
constant SIGSTOP (line 46) | pub const SIGSTOP: Signal = 19;
constant SIGTSTP (line 48) | pub const SIGTSTP: Signal = 20;
constant SIGTTIN (line 50) | pub const SIGTTIN: Signal = 21;
constant SIGTTOU (line 52) | pub const SIGTTOU: Signal = 22;
constant SIGURG (line 54) | pub const SIGURG: Signal = 23;
constant SIGXCPU (line 56) | pub const SIGXCPU: Signal = 24;
constant SIGXFSZ (line 58) | pub const SIGXFSZ: Signal = 25;
constant SIGVTALRM (line 60) | pub const SIGVTALRM: Signal = 26;
constant SIGPROF (line 62) | pub const SIGPROF: Signal = 27;
constant SIGWINCH (line 64) | pub const SIGWINCH: Signal = 28;
constant SIGIO (line 66) | pub const SIGIO: Signal = 29;
constant SIGPWR (line 68) | pub const SIGPWR: Signal = 30;
constant SIGSYS (line 70) | pub const SIGSYS: Signal = 31;
constant SIGMAX (line 72) | const SIGMAX: c_int = 32;
constant SIG_DFL (line 74) | pub const SIG_DFL: usize = 0;
constant SIG_IGN (line 75) | pub const SIG_IGN: usize = 1;
constant SIG_ERR (line 76) | pub const SIG_ERR: usize = usize::MAX;
type SigAction (line 79) | pub enum SigAction {
constant DEFAULT_ACTIONS (line 85) | pub const DEFAULT_ACTIONS: [SigAction; SIGMAX as usize] = [
type SignalDelivery (line 121) | pub struct SignalDelivery {
method new (line 133) | pub fn new() -> SignalDelivery {
method get_action (line 140) | pub fn get_action(&self, signal: Signal) -> SigAction {
method set_action (line 144) | pub fn set_action(&mut self, signal: Signal, action: SigAction) -> KRe...
method is_pending (line 153) | pub fn is_pending(&self) -> bool {
method signal (line 157) | pub fn signal(&mut self, signal: Signal) {
method pop_pending (line 161) | pub fn pop_pending(&mut self) -> Option<(Signal, SigAction)> {
method default (line 127) | fn default() -> Self {
type SigSet (line 172) | pub type SigSet = BitArray<[u8; 8], LocalBits>;
type SignalMask (line 175) | pub enum SignalMask {
FILE: src/task/vmem.rs
method from (line 50) | fn from(e: MMapProt) -> Self {
type MMapKind (line 69) | pub enum MMapKind {
type VmemArea (line 79) | pub struct VmemArea {
method new (line 88) | pub const fn new(
method null (line 104) | pub const fn null() -> Self {
method contains_addr (line 114) | pub fn contains_addr(&self, addr: VirtAddr) -> bool {
method overlaps_range (line 118) | pub fn overlaps_range(&self, start: VirtAddr, end: VirtAddr) -> bool {
method start_address (line 122) | pub fn start_address(&self) -> VirtAddr {
method end_address (line 126) | pub fn end_address(&self) -> VirtAddr {
method size_in_bytes (line 130) | pub fn size_in_bytes(&self) -> usize {
method merge_with (line 134) | pub fn merge_with(&mut self, other: Self) -> KResult<()> {
type Vmem (line 152) | pub struct Vmem {
method new (line 159) | pub fn new() -> Self {
method area_containing_mut (line 174) | pub fn area_containing_mut(
method area_containing (line 184) | pub fn area_containing(&self, start_addr: VirtAddr, end_addr: VirtAddr...
method add_area (line 190) | pub fn add_area(
method merge_contiguous_chunks (line 215) | pub fn merge_contiguous_chunks(&mut self) {
method zero_memory (line 233) | fn zero_memory(&self, start_addr: VirtAddr, end_addr: VirtAddr) -> KRe...
method mprotect (line 238) | pub fn mprotect(
method mremap (line 251) | pub fn mremap(
method mmap (line 325) | pub fn mmap(
method find_free_space_above (line 410) | fn find_free_space_above(
method map_area (line 435) | pub fn map_area(
method do_unmap (line 463) | unsafe fn do_unmap(
method munmap (line 496) | pub fn munmap(
method clear (line 557) | pub fn clear(&mut self, active_mapper: &mut Mapper) {
method log (line 568) | pub fn log(&self) {
method fork_from (line 582) | pub fn fork_from(&mut self, parent: &Vmem) {
method handle_page_fault (line 592) | pub fn handle_page_fault(
method default (line 717) | fn default() -> Self {
FILE: src/task/wait_queue.rs
type WaitQueue (line 10) | pub struct WaitQueue {
method new (line 21) | pub const fn new() -> WaitQueue {
method sleep_signalable_until (line 27) | pub fn sleep_signalable_until<F, R>(
method default (line 15) | fn default() -> Self {
FILE: src/userland/buffer.rs
type Inner (line 13) | enum Inner<'a> {
type UserBuffer (line 18) | pub struct UserBuffer<'a> {
function from_vaddr (line 23) | pub fn from_vaddr(vaddr: VirtAddr, len: usize) -> UserBuffer<'static> {
function from_slice (line 29) | pub fn from_slice(slc: &'a [u8]) -> UserBuffer<'a> {
function len (line 36) | pub fn len(&self) -> usize {
type InnerMut (line 45) | enum InnerMut<'a> {
type UserBufferMut (line 50) | pub struct UserBufferMut<'a> {
function from_slice (line 55) | pub fn from_slice(slice: &'a mut [u8]) -> UserBufferMut<'a> {
function from_vaddr (line 61) | pub fn from_vaddr(vaddr: VirtAddr, len: usize) -> UserBufferMut<'static> {
function len (line 68) | pub fn len(&self) -> usize {
function user_strncpy_rust (line 76) | pub unsafe fn user_strncpy_rust(dst: *mut u8, src: *const u8, max_len: u...
type CStr (line 89) | pub struct CStr {
method new (line 94) | pub fn new(vaddr: VirtAddr, max_len: usize, is_user: bool) -> KResult<...
method as_bytes (line 109) | pub fn as_bytes(&self) -> &[u8] {
method as_str (line 113) | pub fn as_str(&self) -> &str {
type UserBufferReader (line 118) | pub struct UserBufferReader<'a> {
function from_vaddr (line 126) | pub fn from_vaddr(buf: VirtAddr, len: usize) -> UserBufferReader<'a> {
function from_buf (line 135) | pub fn from_buf(buf: UserBuffer<'a>) -> UserBufferReader<'a> {
function read_len (line 140) | pub fn read_len(&self) -> usize {
function skip (line 144) | pub fn skip(&mut self, len: usize) -> KResult<()> {
function read_bytes (line 150) | pub fn read_bytes(&mut self, dst: &mut [u8]) -> KResult<usize> {
function read (line 170) | pub fn read<T: Copy + Sized>(&mut self) -> KResult<T> {
function check_remaining_len (line 186) | fn check_remaining_len(&self, len: usize) -> KResult<()> {
function remaining_len (line 194) | pub fn remaining_len(&self) -> usize {
type UserBufferWriter (line 199) | pub struct UserBufferWriter<'a> {
function from_vaddr (line 207) | pub fn from_vaddr(buf: VirtAddr, len: usize) -> UserBufferWriter<'a> {
function from_buf (line 216) | pub fn from_buf(buf: UserBufferMut<'a>) -> UserBufferWriter<'a> {
function written_len (line 221) | pub fn written_len(&self) -> usize {
function write (line 225) | pub fn write<T: Copy + Sized>(&mut self, value: T) -> KResult<usize> {
function write_bytes (line 231) | pub fn write_bytes(&mut self, src: &[u8]) -> KResult<usize> {
function skip_until_alignment (line 251) | pub fn skip_until_alignment(&mut self, alignment: usize) -> KResult<()> {
function fill (line 258) | pub fn fill(&mut self, value: u8, len: usize) -> KResult<()> {
function write_bytes_or_zeros (line 274) | pub fn write_bytes_or_zeros(&mut self, buf: &[u8], max_len: usize) -> KR...
function check_remaining_len (line 282) | fn check_remaining_len(&self, len: usize) -> KResult<()> {
function remaining_len (line 290) | pub fn remaining_len(&self) -> usize {
FILE: src/userland/elf.rs
function gen_stack_canary (line 21) | pub fn gen_stack_canary() -> [u8; 16] {
type AuxvType (line 29) | pub enum AuxvType {
type SymTabEntry (line 38) | pub struct SymTabEntry {
type UserlandEntry (line 44) | pub struct UserlandEntry {
function load_elf (line 53) | pub fn load_elf(file: FileRef) -> KResult<UserlandEntry> {
type KadosElfLoader (line 169) | struct KadosElfLoader<'a> {
method allocate (line 179) | fn allocate(
method load (line 226) | fn load(
method tls (line 255) | fn tls(
method relocate (line 269) | fn relocate(
FILE: src/userland/syscall/mod.rs
function errno_to_isize (line 29) | pub fn errno_to_isize(res: &Result<isize, KError<'_>>) -> isize {
constant QUIET_SYSCALLS (line 39) | pub const QUIET_SYSCALLS: &[usize] = &[
type SyscallHandler (line 53) | pub struct SyscallHandler<'a> {
function dispatch (line 59) | pub fn dispatch(
function resolve_path (line 257) | fn resolve_path(uaddr: usize) -> KResult<PathBuf> {
function syscall_name_by_number (line 261) | pub fn syscall_name_by_number(n: usize) -> &'static str {
constant SYS_READ (line 604) | pub const SYS_READ: usize = 0;
constant SYS_WRITE (line 605) | pub const SYS_WRITE: usize = 1;
constant SYS_OPEN (line 606) | pub const SYS_OPEN: usize = 2;
constant SYS_CLOSE (line 607) | pub const SYS_CLOSE: usize = 3;
constant SYS_STAT (line 608) | pub const SYS_STAT: usize = 4;
constant SYS_FSTAT (line 609) | pub const SYS_FSTAT: usize = 5;
constant SYS_LSTAT (line 610) | pub const SYS_LSTAT: usize = 6;
constant SYS_POLL (line 611) | pub const SYS_POLL: usize = 7;
constant SYS_LSEEK (line 612) | pub const SYS_LSEEK: usize = 8;
constant SYS_MMAP (line 613) | pub const SYS_MMAP: usize = 9;
constant SYS_MPROTECT (line 614) | pub const SYS_MPROTECT: usize = 10;
constant SYS_MUNMAP (line 615) | pub const SYS_MUNMAP: usize = 11;
constant SYS_BRK (line 616) | pub const SYS_BRK: usize = 12;
constant SYS_RT_SIGACTION (line 617) | pub const SYS_RT_SIGACTION: usize = 13;
constant SYS_RT_SIGPROCMASK (line 618) | pub const SYS_RT_SIGPROCMASK: usize = 14;
constant SYS_RT_SIGRETURN (line 619) | pub const SYS_RT_SIGRETURN: usize = 15;
constant SYS_IOCTL (line 620) | pub const SYS_IOCTL: usize = 16;
constant SYS_READV (line 621) | pub const SYS_READV: usize = 19;
constant SYS_WRITEV (line 622) | pub const SYS_WRITEV: usize = 20;
constant SYS_PIPE (line 623) | pub const SYS_PIPE: usize = 22;
constant SYS_SELECT (line 624) | pub const SYS_SELECT: usize = 23;
constant SYS_MREMAP (line 625) | pub const SYS_MREMAP: usize = 25;
constant SYS_MADVISE (line 626) | pub const SYS_MADVISE: usize = 28;
constant SYS_DUP2 (line 627) | pub const SYS_DUP2: usize = 33;
constant SYS_NANOSLEEP (line 628) | pub const SYS_NANOSLEEP: usize = 35;
constant SYS_GETPID (line 629) | pub const SYS_GETPID: usize = 39;
constant SYS_SOCKET (line 630) | pub const SYS_SOCKET: usize = 41;
constant SYS_CONNECT (line 631) | pub const SYS_CONNECT: usize = 42;
constant SYS_ACCEPT (line 632) | pub const SYS_ACCEPT: usize = 43;
constant SYS_SENDTO (line 633) | pub const SYS_SENDTO: usize = 44;
constant SYS_RECVFROM (line 634) | pub const SYS_RECVFROM: usize = 45;
constant SYS_SHUTDOWN (line 635) | pub const SYS_SHUTDOWN: usize = 48;
constant SYS_BIND (line 636) | pub const SYS_BIND: usize = 49;
constant SYS_LISTEN (line 637) | pub const SYS_LISTEN: usize = 50;
constant SYS_GETSOCKNAME (line 638) | pub const SYS_GETSOCKNAME: usize = 51;
constant SYS_GETPEERNAME (line 639) | pub const SYS_GETPEERNAME: usize = 52;
constant SYS_SETSOCKOPT (line 640) | pub const SYS_SETSOCKOPT: usize = 54;
constant SYS_GETSOCKOPT (line 641) | pub const SYS_GETSOCKOPT: usize = 55;
constant SYS_CLONE (line 642) | pub const SYS_CLONE: usize = 56;
constant SYS_FORK (line 643) | pub const SYS_FORK: usize = 57;
constant SYS_EXECVE (line 644) | pub const SYS_EXECVE: usize = 59;
constant SYS_EXIT (line 645) | pub const SYS_EXIT: usize = 60;
constant SYS_WAIT4 (line 646) | pub const SYS_WAIT4: usize = 61;
constant SYS_KILL (line 647) | pub const SYS_KILL: usize = 62;
constant SYS_UNAME (line 648) | pub const SYS_UNAME: usize = 63;
constant SYS_FCNTL (line 649) | pub const SYS_FCNTL: usize = 72;
constant SYS_FSYNC (line 650) | pub const SYS_FSYNC: usize = 74;
constant SYS_GETCWD (line 651) | pub const SYS_GETCWD: usize = 79;
constant SYS_CHDIR (line 652) | pub const SYS_CHDIR: usize = 80;
constant SYS_MKDIR (line 653) | pub const SYS_MKDIR: usize = 83;
constant SYS_LINK (line 654) | pub const SYS_LINK: usize = 86;
constant SYS_UNLINK (line 655) | pub const SYS_UNLINK: usize = 87;
constant SYS_READLINK (line 656) | pub const SYS_READLINK: usize = 89;
constant SYS_CHMOD (line 657) | pub const SYS_CHMOD: usize = 90;
constant SYS_CHOWN (line 658) | pub const SYS_CHOWN: usize = 92;
constant SYS_GETUID (line 659) | pub const SYS_GETUID: usize = 102;
constant SYS_SYSLOG (line 660) | pub const SYS_SYSLOG: usize = 103;
constant SYS_SETUID (line 661) | pub const SYS_SETUID: usize = 105;
constant SYS_SETGID (line 662) | pub const SYS_SETGID: usize = 106;
constant SYS_GETEUID (line 663) | pub const SYS_GETEUID: usize = 107;
constant SYS_SETPGID (line 664) | pub const SYS_SETPGID: usize = 109;
constant SYS_GETPPID (line 665) | pub const SYS_GETPPID: usize = 110;
constant SYS_GETPGRP (line 666) | pub const SYS_GETPGRP: usize = 111;
constant SYS_GETPGID (line 667) | pub const SYS_GETPGID: usize = 121;
constant SYS_SETGROUPS (line 668) | pub const SYS_SETGROUPS: usize = 116;
constant SYS_ARCH_PRCTL (line 669) | pub const SYS_ARCH_PRCTL: usize = 158;
constant SYS_REBOOT (line 670) | pub const SYS_REBOOT: usize = 169;
constant SYS_GETTID (line 671) | pub const SYS_GETTID: usize = 186;
constant SYS_TKILL (line 672) | pub const SYS_TKILL: usize = 200;
constant SYS_GETDENTS64 (line 673) | pub const SYS_GETDENTS64: usize = 217;
constant SYS_SET_TID_ADDRESS (line 674) | pub const SYS_SET_TID_ADDRESS: usize = 218;
constant SYS_CLOCK_GETTIME (line 675) | pub const SYS_CLOCK_GETTIME: usize = 228;
constant SYS_EXIT_GROUP (line 676) | pub const SYS_EXIT_GROUP: usize = 231;
constant SYS_UTIMES (line 677) | pub const SYS_UTIMES: usize = 235;
constant SYS_LINKAT (line 678) | pub const SYS_LINKAT: usize = 265;
constant SYS_GETRANDOM (line 679) | pub const SYS_GETRANDOM: usize = 318;
FILE: src/userland/syscall/syscall_impl/fs.rs
constant F_DUPFD (line 30) | pub const F_DUPFD: c_int = 0;
constant F_GETFD (line 31) | pub const F_GETFD: c_int = 1;
constant F_SETFD (line 32) | pub const F_SETFD: c_int = 2;
constant F_GETFL (line 33) | pub const F_GETFL: c_int = 3;
constant F_SETFL (line 34) | pub const F_SETFL: c_int = 4;
constant F_SETLK (line 35) | pub const F_SETLK: c_int = 6;
constant F_LINUX_SPECIFIC_BASE (line 38) | pub const F_LINUX_SPECIFIC_BASE: c_int = 1024;
constant F_DUPFD_CLOEXEC (line 39) | pub const F_DUPFD_CLOEXEC: c_int = F_LINUX_SPECIFIC_BASE + 6;
function sys_fcntl (line 42) | pub fn sys_fcntl(&mut self, fd: FileDesc, cmd: c_int, arg: usize) -> KRe...
function sys_getcwd (line 70) | pub fn sys_getcwd(&mut self, buf: VirtAddr, len: usize) -> KResult<isize> {
function sys_getdents64 (line 86) | pub fn sys_getdents64(
function sys_chdir (line 118) | pub fn sys_chdir(&mut self, path: &Path) -> KResult<isize> {
function sys_ioctl (line 123) | pub fn sys_ioctl(&mut self, fd: FileDesc, cmd: usize, arg: usize) -> KRe...
function sys_getrandom (line 128) | pub fn sys_getrandom(&mut self, buf: VirtAddr, bufflen: usize) -> KResul...
function create (line 138) | fn create(path: &Path, _flags: OpenFlags, mode: FileMode) -> KResult<INo...
function sys_open (line 169) | pub fn sys_open(&mut self, path: &Path, flags: OpenFlags, mode: FileMode...
function sys_close (line 199) | pub fn sys_close(&mut self, fd: FileDesc) -> KResult<isize> {
function sys_mkdir (line 206) | pub fn sys_mkdir(&mut self, path: &Path, mode: FileMode) -> KResult<isiz...
function sys_pipe (line 215) | pub fn sys_pipe(&mut self, fds: VirtAddr) -> KResult<isize> {
function sys_unlink (line 233) | pub fn sys_unlink(&mut self, path: &Path) -> KResult<isize> {
function sys_poll (line 254) | pub fn sys_poll(&mut self, fds: VirtAddr, nfds: c_nfds, timeout: c_int) ...
function sys_read (line 300) | pub fn sys_read(&mut self, fd: FileDesc, vaddr: VirtAddr, len: usize) ->...
function sys_stat (line 308) | pub fn sys_stat(&mut self, path: &Path, buf: VirtAddr) -> KResult<isize> {
function sys_lstat (line 317) | pub fn sys_lstat(&mut self, path: &Path, buf: VirtAddr) -> KResult<isize> {
function sys_fstat (line 323) | pub fn sys_fstat(&mut self, fd: FileDesc, buf: VirtAddr) -> KResult<isiz...
function sys_write (line 330) | pub fn sys_write(&mut self, fd: FileDesc, addr: VirtAddr, len: usize) ->...
constant IOV_MAX (line 338) | pub const IOV_MAX: usize = 1024;
type IoVec (line 341) | pub struct IoVec {
function sys_readv (line 347) | pub fn sys_readv(
function sys_writev (line 381) | pub fn sys_writev(
function sys_lseek (line 415) | pub fn sys_lseek(
function sys_dup2 (line 425) | pub fn sys_dup2(&mut self, old_fd: FileDesc, new_fd: FileDesc) -> KResul...
function sys_socket (line 444) | pub fn sys_socket(&mut self, domain: usize, typ: usize, protocol: usize)...
function sys_setsockopt (line 451) | pub fn sys_setsockopt(
constant SOL_SOCKET (line 471) | const SOL_SOCKET: c_int = 1;
FILE: src/userland/syscall/syscall_impl/mem.rs
function sys_mmap (line 13) | pub fn sys_mmap(
function sys_mprotect (line 38) | pub fn sys_mprotect(&mut self, addr: VirtAddr, size: usize, prot: MMapPr...
function sys_munmap (line 52) | pub fn sys_munmap(&mut self, addr: VirtAddr, size: usize) -> KResult<isi...
function sys_mremap (line 60) | pub fn sys_mremap(&mut self, addr: VirtAddr, old_size: usize, size: usiz...
FILE: src/userland/syscall/syscall_impl/signal.rs
function sys_rt_sigprocmask (line 14) | pub fn sys_rt_sigprocmask(
function sys_rt_sigaction (line 37) | pub fn sys_rt_sigaction(
function sys_rt_sigreturn (line 76) | pub fn sys_rt_sigreturn(&mut self) -> KResult<isize> {
function sys_kill (line 81) | pub fn sys_kill(&mut self, pid: TaskId, signum: c_int) -> KResult<isize> {
FILE: src/userland/syscall/syscall_impl/sys.rs
constant UTS_FIELD_LEN (line 7) | const UTS_FIELD_LEN: usize = 65;
function sys_uname (line 10) | pub fn sys_uname(&mut self, buf: VirtAddr) -> KResult<isize> {
FILE: src/userland/syscall/syscall_impl/task.rs
constant ARG_MAX (line 18) | const ARG_MAX: usize = 512;
constant ARG_LEN_MAX (line 19) | const ARG_LEN_MAX: usize = 4096;
constant ENV_MAX (line 20) | const ENV_MAX: usize = 512;
constant ENV_LEN_MAX (line 21) | const ENV_LEN_MAX: usize = 4096;
function sys_arch_prctl (line 24) | pub fn sys_arch_prctl(&mut self, code: i32, uaddr: VirtAddr) -> KResult<...
function sys_fork (line 29) | pub fn sys_fork(&mut self) -> KResult<isize> {
function sys_clone (line 36) | pub fn sys_clone(
function sys_execve (line 49) | pub fn sys_execve(
function sys_exit (line 92) | pub fn sys_exit(&mut self, status: c_int) -> KResult<isize> {
function sys_set_tid_address (line 97) | pub fn sys_set_tid_address(&mut self, _addr: VirtAddr) -> KResult<isize> {
function sys_getpid (line 102) | pub fn sys_getpid(&mut self) -> KResult<isize> {
function sys_getppid (line 106) | pub fn sys_getppid(&mut self) -> KResult<isize> {
function sys_getpgid (line 110) | pub fn sys_getpgid(&mut self, pid: TaskId) -> KResult<isize> {
function sys_setpgid (line 122) | pub fn sys_setpgid(&mut self, pid: TaskId, pgid: PgId) -> KResult<isize> {
function sys_wait4 (line 154) | pub fn sys_wait4(
function sys_nanosleep (line 201) | pub fn sys_nanosleep(&mut self, req: VirtAddr, _rem: VirtAddr) -> KResul...
function sys_clock_gettime (line 219) | pub fn sys_clock_gettime(&mut self, clk_id: usize, tp: VirtAddr) -> KRes...
function arch_prctl (line 256) | fn arch_prctl(current_task: Arc<Task>, code: i32, addr: VirtAddr) -> KRe...
FILE: src/userland/syscall/syscall_impl/time.rs
constant ITIMER_REAL (line 1) | pub const ITIMER_REAL: usize = 0;
constant ITIMER_VIRTUAL (line 2) | pub const ITIMER_VIRTUAL: usize = 1;
constant ITIMER_PROF (line 3) | pub const ITIMER_PROF: usize = 2;
type TimeVal (line 7) | pub struct TimeVal {
type ITimerVal (line 14) | pub struct ITimerVal {
type TimeSpec (line 21) | pub struct TimeSpec {
method zero (line 27) | pub const fn zero() -> Self {
FILE: src/util/ctypes.rs
type c_int16 (line 2) | pub type c_int16 = i16;
type c_int32 (line 4) | pub type c_int32 = i32;
type c_int64 (line 6) | pub type c_int64 = i64;
type c_uint32 (line 8) | pub type c_uint32 = u32;
type c_uint64 (line 10) | pub type c_uint64 = u64;
type c_int (line 13) | pub type c_int = c_int32;
type c_uint (line 15) | pub type c_uint = c_uint32;
type c_short (line 17) | pub type c_short = c_int16;
type c_long (line 19) | pub type c_long = c_int64;
type c_ulong (line 21) | pub type c_ulong = c_uint64;
type c_time (line 24) | pub type c_time = c_int64;
type c_suseconds (line 26) | pub type c_suseconds = c_int64;
type c_clockid (line 28) | pub type c_clockid = c_int;
type c_nfds (line 30) | pub type c_nfds = c_ulong;
type c_size (line 32) | pub type c_size = c_ulong;
type c_off (line 34) | pub type c_off = c_uint64;
FILE: src/util/errno.rs
type Errno (line 5) | pub enum Errno {
FILE: src/util/error.rs
type KResult (line 5) | pub type KResult<T> = Result<T, KError<'static>>;
type KError (line 8) | pub struct KError<'a> {
function msg (line 14) | pub fn msg(&self) -> Option<core::fmt::Arguments<'a>> {
function errno (line 18) | pub fn errno(&self) -> Option<Errno> {
method fmt (line 24) | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
FILE: src/util/lock.rs
type SavedInterruptStatus (line 13) | pub struct SavedInterruptStatus {
method save (line 18) | pub fn save() -> SavedInterruptStatus {
method drop (line 26) | fn drop(&mut self) {
type BlockingMutex (line 31) | pub struct BlockingMutex<T: ?Sized> {
function new (line 37) | pub const fn new(value: T) -> BlockingMutex<T> {
function get_mut (line 46) | pub fn get_mut(&mut self) -> &mut T {
function try_lock (line 50) | pub fn try_lock(&self) -> KResult<BlockingMutexGuard<'_, T>> {
function lock (line 60) | pub fn lock(&self) -> KResult<BlockingMutexGuard<'_, T>> {
function is_locked (line 73) | pub fn is_locked(&self) -> bool {
function force_unlock (line 79) | pub unsafe fn force_unlock(&self) {
type BlockingMutexGuard (line 87) | pub struct BlockingMutexGuard<'a, T: ?Sized> {
method drop (line 92) | fn drop(&mut self) {
type Target (line 100) | type Target = T;
method deref (line 101) | fn deref(&self) -> &T {
method deref_mut (line 107) | fn deref_mut(&mut self) -> &mut T {
type IrqMutex (line 112) | pub struct IrqMutex<T: ?Sized> {
function new (line 117) | pub const fn new(value: T) -> IrqMutex<T> {
function get_mut (line 125) | pub fn get_mut(&mut self) -> &mut T {
function try_lock (line 129) | pub fn try_lock(&self) -> KResult<IrqMutexGuard<'_, T>> {
function lock (line 137) | pub fn lock(&self) -> IrqMutexGuard<'_, T> {
function is_locked (line 157) | pub fn is_locked(&self) -> bool {
function force_unlock (line 163) | pub unsafe fn force_unlock(&self) {
type IrqMutexGuard (line 171) | pub struct IrqMutexGuard<'a, T: ?Sized> {
method drop (line 177) | fn drop(&mut self) {
type Target (line 189) | type Target = T;
method deref (line 190) | fn deref(&self) -> &T {
method deref_mut (line 196) | fn deref_mut(&mut self) -> &mut T {
FILE: src/util/mod.rs
function align_down (line 13) | pub const fn align_down(val: usize, align: usize) -> usize {
function align_up (line 17) | pub const fn align_up(val: usize, align: usize) -> usize {
FILE: src/util/ringbuffer.rs
type RingBuffer (line 5) | pub struct RingBuffer<T, const CAP: usize> {
method default (line 13) | fn default() -> Self {
function new (line 24) | pub fn new() -> RingBuffer<T, CAP> {
function is_writable (line 28) | pub fn is_writable(&self) -> bool {
function is_readable (line 32) | pub fn is_readable(&self) -> bool {
function push (line 36) | pub fn push(&mut self, data: T) -> Result<(), T>
function pop (line 47) | pub fn pop(&mut self) -> Option<T>
function push_slice (line 54) | pub fn push_slice(&mut self, data: &[T]) -> usize
function pop_slice (line 85) | pub fn pop_slice(&mut self, len: usize) -> Option<&[T]> {
function slice (line 101) | fn slice(&self, range: Range<usize>) -> &[T] {
function slice_mut (line 109) | fn slice_mut(&mut self, range: Range<usize>) -> &mut [T] {
FILE: src/util/stack.rs
type Stack (line 5) | pub struct Stack<'a> {
function new (line 10) | pub fn new(ptr: &'a mut usize) -> Self {
function skip_by (line 14) | pub fn skip_by(&mut self, by: usize) {
function offset (line 18) | pub unsafe fn offset<'b, T: Sized>(&mut self) -> &'b mut T {
function top (line 23) | pub fn top(&self) -> usize {
function push_bytes (line 27) | pub unsafe fn push_bytes(&mut self, bytes: &[u8]) {
function push (line 33) | pub unsafe fn push<T: Sized>(&mut self, value: T) {
function pop_by (line 38) | pub fn pop_by(&mut self, by: usize) {
function pop_bytes (line 42) | pub unsafe fn pop_bytes(&mut self, len: usize) -> &[u8] {
function pop (line 48) | pub unsafe fn pop<'b, T: Sized>(&mut self) -> &'b mut T {
function align_down (line 54) | pub fn align_down(&mut self, align: usize) {
FILE: src/vga_text.rs
type Color (line 8) | pub enum Color {
type ColorCode (line 29) | pub struct ColorCode(u8);
method new (line 32) | pub fn new(foreground: Color, background: Color) -> ColorCode {
method background (line 36) | pub fn background(self) -> Color {
method foreground (line 40) | pub fn foreground(self) -> Color {
type ScreenChar (line 47) | struct ScreenChar {
constant VGA_BUFFER_START_PADDR (line 52) | pub const VGA_BUFFER_START_PADDR: usize = 0xb8000;
constant BUFFER_HEIGHT (line 53) | pub const BUFFER_HEIGHT: usize = 25;
constant BUFFER_WIDTH (line 54) | pub const BUFFER_WIDTH: usize = 80;
type Buffer (line 57) | struct Buffer {
type Writer (line 61) | pub struct Writer {
method write_byte (line 69) | pub fn write_byte(&mut self, byte: u8) {
method cursor_color_hook (line 93) | fn cursor_color_hook(&mut self) {
method backspace (line 107) | pub fn backspace(&mut self) {
method write_string (line 119) | pub fn write_string(&mut self, s: &str) {
method new_line (line 130) | fn new_line(&mut self) {
method clear_row (line 148) | fn clear_row(&mut self, row: usize) {
method clear_until_end (line 158) | fn clear_until_end(&mut self) {
method clear_until_beginning (line 171) | fn clear_until_beginning(&mut self) {
method clear_until_eol (line 184) | fn clear_until_eol(&mut self) {
method clear_from_bol (line 194) | fn clear_from_bol(&mut self) {
method clear_line (line 204) | fn clear_line(&mut self) {
method clear_all (line 207) | fn clear_all(&mut self) {
method move_up (line 213) | fn move_up(&mut self) {
method move_down (line 223) | fn move_down(&mut self) {
method move_left (line 233) | fn move_left(&mut self) {
method move_right (line 237) | fn move_right(&mut self) {
method write_str (line 244) | fn write_str(&mut self, s: &str) -> core::fmt::Result {
function clear_screen (line 259) | pub fn clear_screen() {
function backspace (line 263) | pub fn backspace() {
function set_color_code (line 267) | pub fn set_color_code(color_code: ColorCode) {
function get_color_code (line 271) | pub fn get_color_code() -> ColorCode {
function set_cursor_x (line 275) | pub fn set_cursor_x(x: usize) {
function set_cursor_y (line 279) | pub fn set_cursor_y(y: usize) {
function set_cursor_xy (line 283) | pub fn set_cursor_xy(xy: (usize, usize)) {
function cursor_xy (line 288) | pub fn cursor_xy() -> (usize, usize) {
function write_byte (line 293) | pub fn write_byte(byte: u8) {
function clear_until_end (line 297) | pub fn clear_until_end() {
function clear_until_beginning (line 301) | pub fn clear_until_beginning() {
function clear_from_bol (line 305) | pub fn clear_from_bol() {
function clear_until_eol (line 309) | pub fn clear_until_eol() {
function clear_line (line 313) | pub fn clear_line() {
function move_up (line 317) | pub fn move_up() {
function move_down (line 321) | pub fn move_down() {
function move_left (line 325) | pub fn move_left() {
function move_right (line 329) | pub fn move_right() {
function _vga_print (line 345) | pub fn _vga_print(args: core::fmt::Arguments) {
FILE: userland/kados_syscall/src/consts.rs
type Errno (line 5) | pub enum Errno {
type SyscallResult (line 59) | pub type SyscallResult = Result<usize, Errno>;
function syscall_result (line 62) | pub fn syscall_result(sys_res: isize) -> SyscallResult {
function syscall_name_by_number (line 70) | pub fn syscall_name_by_number(n: usize) -> &'static str {
constant SYS_READ (line 413) | pub const SYS_READ: usize = 0;
constant SYS_WRITE (line 414) | pub const SYS_WRITE: usize = 1;
constant SYS_OPEN (line 415) | pub const SYS_OPEN: usize = 2;
constant SYS_CLOSE (line 416) | pub const SYS_CLOSE: usize = 3;
constant SYS_STAT (line 417) | pub const SYS_STAT: usize = 4;
constant SYS_FSTAT (line 418) | pub const SYS_FSTAT: usize = 5;
constant SYS_LSTAT (line 419) | pub const SYS_LSTAT: usize = 6;
constant SYS_POLL (line 420) | pub const SYS_POLL: usize = 7;
constant SYS_MMAP (line 421) | pub const SYS_MMAP: usize = 9;
constant SYS_MPROTECT (line 422) | pub const SYS_MPROTECT: usize = 10;
constant SYS_MUNMAP (line 423) | pub const SYS_MUNMAP: usize = 11;
constant SYS_BRK (line 424) | pub const SYS_BRK: usize = 12;
constant SYS_RT_SIGACTION (line 425) | pub const SYS_RT_SIGACTION: usize = 13;
constant SYS_RT_SIGPROCMASK (line 426) | pub const SYS_RT_SIGPROCMASK: usize = 14;
constant SYS_RT_SIGRETURN (line 427) | pub const SYS_RT_SIGRETURN: usize = 15;
constant SYS_IOCTL (line 428) | pub const SYS_IOCTL: usize = 16;
constant SYS_WRITEV (line 429) | pub const SYS_WRITEV: usize = 20;
constant SYS_PIPE (line 430) | pub const SYS_PIPE: usize = 22;
constant SYS_SELECT (line 431) | pub const SYS_SELECT: usize = 23;
constant SYS_DUP2 (line 432) | pub const SYS_DUP2: usize = 33;
constant SYS_GETPID (line 433) | pub const SYS_GETPID: usize = 39;
constant SYS_SOCKET (line 434) | pub const SYS_SOCKET: usize = 41;
constant SYS_CONNECT (line 435) | pub const SYS_CONNECT: usize = 42;
constant SYS_ACCEPT (line 436) | pub const SYS_ACCEPT: usize = 43;
constant SYS_SENDTO (line 437) | pub const SYS_SENDTO: usize = 44;
constant SYS_RECVFROM (line 438) | pub const SYS_RECVFROM: usize = 45;
constant SYS_SHUTDOWN (line 439) | pub const SYS_SHUTDOWN: usize = 48;
constant SYS_BIND (line 440) | pub const SYS_BIND: usize = 49;
constant SYS_LISTEN (line 441) | pub const SYS_LISTEN: usize = 50;
constant SYS_GETSOCKNAME (line 442) | pub const SYS_GETSOCKNAME: usize = 51;
constant SYS_GETPEERNAME (line 443) | pub const SYS_GETPEERNAME: usize = 52;
constant SYS_GETSOCKOPT (line 444) | pub const SYS_GETSOCKOPT: usize = 55;
constant SYS_CLONE (line 445) | pub const SYS_CLONE: usize = 56;
constant SYS_FORK (line 446) | pub const SYS_FORK: usize = 57;
constant SYS_EXECVE (line 447) | pub const SYS_EXECVE: usize = 59;
constant SYS_EXIT (line 448) | pub const SYS_EXIT: usize = 60;
constant SYS_WAIT4 (line 449) | pub const SYS_WAIT4: usize = 61;
constant SYS_KILL (line 450) | pub const SYS_KILL: usize = 62;
constant SYS_UNAME (line 451) | pub const SYS_UNAME: usize = 63;
constant SYS_FCNTL (line 452) | pub const SYS_FCNTL: usize = 72;
constant SYS_FSYNC (line 453) | pub const SYS_FSYNC: usize = 74;
constant SYS_GETCWD (line 454) | pub const SYS_GETCWD: usize = 79;
constant SYS_CHDIR (line 455) | pub const SYS_CHDIR: usize = 80;
constant SYS_MKDIR (line 456) | pub const SYS_MKDIR: usize = 83;
constant SYS_LINK (line 457) | pub const SYS_LINK: usize = 86;
constant SYS_READLINK (line 458) | pub const SYS_READLINK: usize = 89;
constant SYS_CHMOD (line 459) | pub const SYS_CHMOD: usize = 90;
constant SYS_CHOWN (line 460) | pub const SYS_CHOWN: usize = 92;
constant SYS_GETUID (line 461) | pub const SYS_GETUID: usize = 102;
constant SYS_SYSLOG (line 462) | pub const SYS_SYSLOG: usize = 103;
constant SYS_SETUID (line 463) | pub const SYS_SETUID: usize = 105;
constant SYS_SETGID (line 464) | pub const SYS_SETGID: usize = 106;
constant SYS_GETEUID (line 465) | pub const SYS_GETEUID: usize = 107;
constant SYS_SETPGID (line 466) | pub const SYS_SETPGID: usize = 109;
constant SYS_GETPPID (line 467) | pub const SYS_GETPPID: usize = 110;
constant SYS_GETPGRP (line 468) | pub const SYS_GETPGRP: usize = 111;
constant SYS_GETPGID (line 469) | pub const SYS_GETPGID: usize = 121;
constant SYS_SETGROUPS (line 470) | pub const SYS_SETGROUPS: usize = 116;
constant SYS_ARCH_PRCTL (line 471) | pub const SYS_ARCH_PRCTL: usize = 158;
constant SYS_REBOOT (line 472) | pub const SYS_REBOOT: usize = 169;
constant SYS_GETTID (line 473) | pub const SYS_GETTID: usize = 186;
constant SYS_GETDENTS64 (line 474) | pub const SYS_GETDENTS64: usize = 217;
constant SYS_SET_TID_ADDRESS (line 475) | pub const SYS_SET_TID_ADDRESS: usize = 218;
constant SYS_CLOCK_GETTIME (line 476) | pub const SYS_CLOCK_GETTIME: usize = 228;
constant SYS_EXIT_GROUP (line 477) | pub const SYS_EXIT_GROUP: usize = 231;
constant SYS_UTIMES (line 478) | pub const SYS_UTIMES: usize = 235;
constant SYS_LINKAT (line 479) | pub const SYS_LINKAT: usize = 265;
constant SYS_GETRANDOM (line 480) | pub const SYS_GETRANDOM: usize = 318;
FILE: userland/kados_syscall/src/lib.rs
function syscall0 (line 10) | pub extern "C" fn syscall0(n: usize) -> isize {
function syscall1 (line 21) | pub extern "C" fn syscall1(n: usize, a1: usize) -> isize {
function syscall2 (line 32) | pub extern "C" fn syscall2(n: usize, a1: usize, a2: usize) -> isize {
function syscall3 (line 43) | pub extern "C" fn syscall3(n: usize, a1: usize, a2: usize, a3: usize) ->...
function syscall4 (line 54) | pub extern "C" fn syscall4(n: usize, a1: usize, a2: usize, a3: usize, a4...
function syscall5 (line 65) | pub extern "C" fn syscall5(
function syscall6 (line 83) | pub extern "C" fn syscall6(
function sys_arch_prctl (line 99) | pub fn sys_arch_prctl(code: i32, address: usize) -> SyscallResult {
function sys_set_tid_address (line 103) | pub fn sys_set_tid_address(address: usize) -> SyscallResult {
function sys_write (line 107) | pub fn sys_write(fd: i32, address: usize, len: usize) -> SyscallResult {
function sys_writev (line 111) | pub fn sys_writev(fd: i32, iov_base: usize, iov_count: usize) -> Syscall...
function sys_read (line 115) | pub fn sys_read(fd: i32, address: usize, len: usize) -> SyscallResult {
function sys_fork (line 119) | pub fn sys_fork() -> SyscallResult {
function sys_wait4 (line 123) | pub fn sys_wait4(pid: i32, status_addr: usize, options: i32, rusage_addr...
function sys_execve (line 133) | pub fn sys_execve(path_addr: usize, argv_addr: usize, envp_addr: usize) ...
function sys_getcwd (line 137) | pub fn sys_getcwd(buf_addr: usize, buf_len: usize) -> SyscallResult {
Condensed preview — 91 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (465K chars).
[
{
"path": ".cargo/config.toml",
"chars": 299,
"preview": "[build]\ntarget = \"x86_64-unknown-none\"\nrustflags = [\"-Cforce-frame-pointers=yes\"]\n\n[unstable]\nbuild-std = [\"core\", \"comp"
},
{
"path": ".cargo/debug.toml",
"chars": 73,
"preview": "[target.x86_64-unknown-none]\nrunner = [\"bash\", \".cargo/runner_debug.sh\"]\n"
},
{
"path": ".cargo/linker.ld",
"chars": 2687,
"preview": "\nENTRY(start)\nOUTPUT_ARCH(i386:x86-64)\nOUTPUT_FORMAT(elf64-x86-64)\n\nKERNEL_BASE = 0xffffffff80000000;\n\nSECTIONS {\n . "
},
{
"path": ".cargo/release.toml",
"chars": 75,
"preview": "[target.x86_64-unknown-none]\nrunner = [\"bash\", \".cargo/runner_release.sh\"]\n"
},
{
"path": ".cargo/runner_debug.sh",
"chars": 1476,
"preview": "#! /bin/bash\n#\n# This script will be executed by `cargo run`.\n\nset -xe\n\nLIMINE_GIT_URL=\"https://github.com/limine-bootlo"
},
{
"path": ".cargo/runner_release.sh",
"chars": 1481,
"preview": "#! /bin/bash\n#\n# This script will be executed by `cargo run`.\n\nset -xe\n\nLIMINE_GIT_URL=\"https://github.com/limine-bootlo"
},
{
"path": ".cargo/x86_64-kados.json",
"chars": 802,
"preview": "{\r\n \"llvm-target\": \"x86_64-unknown-none-elf\",\r\n \"target-endian\": \"little\",\r\n \"target-pointer-width\": \"64\",\r\n "
},
{
"path": ".gitignore",
"chars": 93,
"preview": "/target\n/initramfs\n/initramfs_old\n/extern\n*.objdump\n*.map\nstrace_vi.txt\nkados.map\n/extern_old"
},
{
"path": ".vscode/launch.json",
"chars": 502,
"preview": "{\n \"version\": \"0.2.0\",\n \"configurations\": [\n {\n \"type\": \"lldb\",\n \"request\": \"custom\","
},
{
"path": ".vscode/settings.json",
"chars": 282,
"preview": "{\n \"lldb.displayFormat\": \"auto\",\n \"lldb.dereferencePointers\": true,\n \"lldb.consoleMode\": \"commands\",\n \"lldb."
},
{
"path": "Cargo.toml",
"chars": 1199,
"preview": "[package]\nname = \"k4dos\"\nversion = \"0.1.0\"\nedition = \"2024\"\n\n[[bin]]\nname = \"k4dos\"\ntest = false\nbench = false\n\n# See mo"
},
{
"path": "LICENSE",
"chars": 1071,
"preview": "MIT License\n\nCopyright (c) 2022 Connor Statham\n\nPermission is hereby granted, free of charge, to any person obtaining a "
},
{
"path": "README.md",
"chars": 971,
"preview": "# k4dos\n\nK4DOS is a hobby operating system written in Rust. It current supports x86_64 architecture and aims for Linux A"
},
{
"path": "build.rs",
"chars": 769,
"preview": "use std::{env, error::Error};\n\nfn main() -> Result<(), Box<dyn Error + Send + Sync>> {\n // Get the name of the packag"
},
{
"path": "conf/grub.cfg",
"chars": 108,
"preview": "set timeout=0\nset default=0\nGRUB_TERMINAL=console\n\nmenuentry \"K4DOS\" {\n multiboot2 /boot/k4dos\n boot\n}"
},
{
"path": "conf/limine.cfg",
"chars": 103,
"preview": "TIMEOUT=0\nVERBOSE=yes\n\n: k4dos\nPROTOCOL=limine\nKASLR=no\nRESOLUTION=640x400x32\nKERNEL_PATH=boot:///k4dos"
},
{
"path": "deps.sh",
"chars": 2409,
"preview": "#!/bin/bash\n\nset -e\n\nif [[ -z \"$@\" ]]; then\n echo \"Usage: deps.sh [COMMANDS]...\"\n echo \"Available commands:\"\n e"
},
{
"path": "kados.config",
"chars": 38003,
"preview": "#\n# Automatically generated make config: don't edit\n# Busybox version: 1.37.0.git\n# Sun Mar 12 20:07:49 2023\n#\nCONFIG_HA"
},
{
"path": "rust-toolchain.toml",
"chars": 92,
"preview": "[toolchain]\nchannel = \"nightly\"\ntargets = [\"x86_64-unknown-none\"]\ncomponents = [\"rust-src\"]\n"
},
{
"path": "src/arch/mod.rs",
"chars": 42,
"preview": "pub mod x86_64;\n\npub use self::x86_64::*;\n"
},
{
"path": "src/arch/x86_64/cpu_local.rs",
"chars": 557,
"preview": "use x86::msr::{rdmsr, IA32_GS_BASE};\nuse x86_64::structures::{gdt::GlobalDescriptorTable, tss::TaskStateSegment};\n\npub s"
},
{
"path": "src/arch/x86_64/gdt.rs",
"chars": 2792,
"preview": "use core::alloc::Layout;\n\nuse alloc::alloc::alloc_zeroed;\n\nuse lazy_static::lazy_static;\nuse x86::msr::{wrmsr, IA32_GS_B"
},
{
"path": "src/arch/x86_64/idt.rs",
"chars": 15780,
"preview": "use lazy_static::lazy_static;\n\nuse pc_keyboard::{DecodedKey, HandleControl, Keyboard, ScancodeSet1, layouts::Us104Key};\n"
},
{
"path": "src/arch/x86_64/mod.rs",
"chars": 7580,
"preview": "use alloc::sync::Arc;\nuse limine::request::{\n BootTimeRequest, FramebufferRequest, HhdmRequest, KernelFileRequest, Me"
},
{
"path": "src/arch/x86_64/syscall.rs",
"chars": 4077,
"preview": "use core::mem::offset_of;\n\nuse x86::msr::{rdmsr, wrmsr};\n\nuse crate::mem::kernel_addr_space_scope;\nuse crate::userland::"
},
{
"path": "src/arch/x86_64/task.rs",
"chars": 13955,
"preview": "use core::{alloc::Layout, ptr::Unique, slice::SlicePattern};\n\nuse alloc::{alloc::alloc_zeroed, boxed::Box, vec::Vec};\nus"
},
{
"path": "src/arch/x86_64/time.rs",
"chars": 2111,
"preview": "use core::sync::atomic::{AtomicUsize, Ordering};\n\nuse x86::io::{inb, outb};\n\nuse crate::{userland::syscall::syscall_impl"
},
{
"path": "src/backtrace.rs",
"chars": 6537,
"preview": "use core::{alloc::Layout, mem::size_of, panic::PanicInfo};\n\nuse alloc::vec::Vec;\nuse spin::Once;\nuse x86_64::instruction"
},
{
"path": "src/fs/devfs/fb.rs",
"chars": 3642,
"preview": "use alloc::sync::Arc;\nuse spin::Once;\n\nuse crate::{\n fs::{initramfs::get_root, opened_file::OpenFlags, File, FsNode, "
},
{
"path": "src/fs/devfs/input.rs",
"chars": 1629,
"preview": "//! TODO: make this more like an actual linux keyboard device file\n\nuse alloc::sync::Arc;\nuse pc_keyboard::{KeyEvent, Ke"
},
{
"path": "src/fs/devfs/mod.rs",
"chars": 253,
"preview": "pub mod fb;\npub mod input;\npub mod null;\npub mod socket;\npub mod tty;\npub mod urandom;\n\npub fn init() {\n self::tty::i"
},
{
"path": "src/fs/devfs/null.rs",
"chars": 1415,
"preview": "use alloc::{borrow::ToOwned, sync::Arc};\nuse spin::Once;\n\nuse crate::{\n fs::{\n initramfs::get_root, opened_fil"
},
{
"path": "src/fs/devfs/socket.rs",
"chars": 3565,
"preview": "use core::sync::atomic::{AtomicUsize, Ordering};\n\nuse crate::{\n fs::{File, FsNode},\n kerror,\n mem::addr::VirtAd"
},
{
"path": "src/fs/devfs/tty.rs",
"chars": 25102,
"preview": "use core::fmt::Debug;\n\nuse alloc::{\n borrow::ToOwned,\n string::String,\n sync::{Arc, Weak},\n vec::Vec,\n};\n\nus"
},
{
"path": "src/fs/devfs/urandom.rs",
"chars": 977,
"preview": "use alloc::sync::Arc;\nuse x86::random::rdrand_slice;\n\nuse crate::{\n fs::{initramfs::get_root, path::Path, File, FsNod"
},
{
"path": "src/fs/initramfs/dir.rs",
"chars": 3205,
"preview": "use alloc::{\n string::String,\n sync::{Arc, Weak},\n vec::Vec,\n};\n\nuse crate::{\n fs::{\n alloc_inode_no,"
},
{
"path": "src/fs/initramfs/file.rs",
"chars": 1926,
"preview": "use alloc::{string::String, vec, vec::Vec};\n\nuse crate::{\n fs::{opened_file::OpenFlags, File, FileMode, FsNode, Stat,"
},
{
"path": "src/fs/initramfs/mod.rs",
"chars": 7933,
"preview": "use core::iter::Peekable;\n\nuse alloc::{\n string::{String, ToString},\n sync::{Arc, Weak},\n vec::Vec,\n};\nuse spin"
},
{
"path": "src/fs/initramfs/root.rs",
"chars": 5455,
"preview": "use alloc::{borrow::ToOwned, boxed::Box, string::String, sync::Arc};\n\nuse crate::{\n fs::{\n path::{Path, PathCo"
},
{
"path": "src/fs/initramfs/symlink.rs",
"chars": 525,
"preview": "use alloc::string::String;\n\nuse crate::{\n fs::{path::PathBuf, FsNode, Stat, Symlink},\n util::KResult,\n};\n\npub stru"
},
{
"path": "src/fs/mod.rs",
"chars": 7803,
"preview": "use core::sync::atomic::{AtomicUsize, Ordering};\n\nuse alloc::{string::String, sync::Arc};\nuse bitflags::bitflags;\n\nuse c"
},
{
"path": "src/fs/opened_file.rs",
"chars": 10783,
"preview": "use core::{borrow::BorrowMut, ops::Deref};\n\nuse alloc::{sync::Arc, vec::Vec};\nuse atomic_refcell::AtomicRefCell;\nuse bit"
},
{
"path": "src/fs/path.rs",
"chars": 5013,
"preview": "use alloc::{borrow::ToOwned, boxed::Box, string::String, sync::Arc};\n\nuse super::INode;\n\n#[derive(Debug, Eq, PartialEq, "
},
{
"path": "src/fs/pipe.rs",
"chars": 3414,
"preview": "use alloc::{format, sync::Arc, vec::Vec};\n\nuse crate::{\n kerror,\n task::wait_queue::WaitQueue,\n userland::buffe"
},
{
"path": "src/god_mode.rs",
"chars": 5106,
"preview": "use alloc::{borrow::ToOwned, collections::VecDeque, string::String, sync::Arc};\nuse spin::Once;\nuse x86_64::instructions"
},
{
"path": "src/graphics/mod.rs",
"chars": 9913,
"preview": "use core::ops::Add;\n\nuse alloc::{boxed::Box, vec::Vec};\nuse embedded_graphics::{\n mono_font::{ascii::FONT_8X13, MonoF"
},
{
"path": "src/logging.rs",
"chars": 2394,
"preview": "use log::Level;\nuse log::Log;\n\nuse crate::serial0_print;\nuse crate::serial0_println;\nuse crate::task::SCHEDULER;\n\nstruct"
},
{
"path": "src/main.rs",
"chars": 1026,
"preview": "#![no_std]\n#![no_main]\n#![feature(\n lang_items,\n abi_x86_interrupt,\n ptr_internals,\n slice_pattern,\n map_"
},
{
"path": "src/mem/addr.rs",
"chars": 21525,
"preview": "use core::fmt::{self};\nuse core::mem::align_of;\nuse core::ops::*;\nuse core::ptr::NonNull;\n\nuse crate::kbail;\nuse crate::"
},
{
"path": "src/mem/addr_space.rs",
"chars": 6216,
"preview": "use x86_64::{\n registers::control::{Cr3, Cr3Flags},\n structures::paging::{PageTableFlags, PhysFrame},\n};\n\nuse crat"
},
{
"path": "src/mem/allocator.rs",
"chars": 9895,
"preview": "use core::ops::{Index, IndexMut};\n\nuse alloc::vec::Vec;\nuse arrayvec::ArrayVec;\nuse buddy_system_allocator::LockedHeap;\n"
},
{
"path": "src/mem/consts.rs",
"chars": 1387,
"preview": "use super::addr::VirtAddr;\n\npub const PAGE_SHIFT: usize = 12;\npub const PAGE_SIZE: usize = 0x1000;\npub const PAGE_TABLE_"
},
{
"path": "src/mem/mod.rs",
"chars": 2637,
"preview": "use alloc::sync::Arc;\nuse paging::units::MemoryUnit;\nuse spin::Once;\nuse x86_64::structures::paging::PageTableFlags;\n\nus"
},
{
"path": "src/mem/paging/mapper.rs",
"chars": 5540,
"preview": "use x86::tlb;\nuse x86_64::structures::paging::PageTableFlags;\n\nuse crate::{\n mem::{\n addr::{PhysAddr, VirtAddr"
},
{
"path": "src/mem/paging/mod.rs",
"chars": 46,
"preview": "pub mod mapper;\npub mod table;\npub mod units;\n"
},
{
"path": "src/mem/paging/table.rs",
"chars": 5010,
"preview": "use core::{\n fmt::Debug,\n ops::{Index, IndexMut},\n};\n\nuse x86_64::{registers::control::Cr3, structures::paging::Pa"
},
{
"path": "src/mem/paging/units.rs",
"chars": 9656,
"preview": "use core::{\n fmt::Debug,\n ops::{Add, AddAssign, Sub, SubAssign},\n};\n\nuse x86_64::structures::paging::PageTableFlag"
},
{
"path": "src/serial.rs",
"chars": 3763,
"preview": "use lazy_static::lazy_static;\n\nuse uart_16550::SerialPort;\nuse x86::io::inb;\n\nuse crate::util::lock::IrqMutex;\n\npub cons"
},
{
"path": "src/task/group.rs",
"chars": 1265,
"preview": "use alloc::{\n sync::{Arc, Weak},\n vec::Vec,\n};\n\nuse crate::util::IrqMutex;\n\nuse super::{get_scheduler, signal::Sig"
},
{
"path": "src/task/mod.rs",
"chars": 10718,
"preview": "use core::{\n cell::UnsafeCell,\n sync::atomic::{AtomicUsize, Ordering},\n};\n\nuse alloc::{\n sync::{Arc, Weak},\n "
},
{
"path": "src/task/scheduler.rs",
"chars": 13291,
"preview": "use alloc::{\n collections::{BTreeMap, VecDeque},\n sync::Arc,\n vec::Vec,\n};\nuse spin::RwLock;\nuse x86_64::instru"
},
{
"path": "src/task/signal.rs",
"chars": 4475,
"preview": "use bitvec::prelude::*;\n\nuse crate::{\n kbail,\n util::{ctypes::c_int, error::KResult},\n};\n\npub type Signal = c_int;"
},
{
"path": "src/task/vmem.rs",
"chars": 23702,
"preview": "use core::sync::atomic::AtomicUsize;\n\nuse alloc::vec::Vec;\nuse x86::controlregs::cr3;\nuse x86_64::structures::{idt::Page"
},
{
"path": "src/task/wait_queue.rs",
"chars": 2188,
"preview": "use alloc::{collections::VecDeque, sync::Arc};\n\nuse crate::{\n arch, kbail,\n util::{IrqMutex, KResult},\n};\n\nuse sup"
},
{
"path": "src/userland/buffer.rs",
"chars": 8079,
"preview": "use core::{mem::size_of, ops::Add};\n\nuse alloc::string::{String, ToString};\n\nuse crate::{\n kbail, kerror,\n mem::{a"
},
{
"path": "src/userland/elf.rs",
"chars": 9523,
"preview": "use alloc::{borrow::ToOwned, string::String, vec::Vec};\nuse elfloader::{ElfBinary, ElfLoader, Entry};\nuse x86::random::r"
},
{
"path": "src/userland/mod.rs",
"chars": 46,
"preview": "pub mod buffer;\npub mod elf;\npub mod syscall;\n"
},
{
"path": "src/userland/syscall/mod.rs",
"chars": 21049,
"preview": "use alloc::borrow::ToOwned;\n\nuse crate::{\n arch::idt::InterruptFrame,\n fs::{\n opened_file::{FileDesc, OpenF"
},
{
"path": "src/userland/syscall/syscall_impl/fs.rs",
"chars": 15127,
"preview": "use core::{mem::size_of, ops::Add};\n\nuse alloc::{borrow::ToOwned, string::String, sync::Arc};\nuse x86::random::rdrand_sl"
},
{
"path": "src/userland/syscall/syscall_impl/mem.rs",
"chars": 2097,
"preview": "use crate::{\n fs::opened_file::FileDesc,\n mem::addr::VirtAddr,\n task::{\n current_task,\n vmem::{MM"
},
{
"path": "src/userland/syscall/syscall_impl/mod.rs",
"chars": 82,
"preview": "pub mod fs;\npub mod mem;\npub mod signal;\npub mod sys;\npub mod task;\npub mod time;\n"
},
{
"path": "src/userland/syscall/syscall_impl/signal.rs",
"chars": 2750,
"preview": "use crate::{\n kbail, kerror,\n mem::addr::VirtAddr,\n task::{\n current_task, get_scheduler,\n signal"
},
{
"path": "src/userland/syscall/syscall_impl/sys.rs",
"chars": 719,
"preview": "use crate::{\n mem::addr::VirtAddr,\n userland::{buffer::UserBufferWriter, syscall::SyscallHandler},\n util::KResu"
},
{
"path": "src/userland/syscall/syscall_impl/task.rs",
"chars": 8179,
"preview": "use core::{mem::size_of, ops::Add};\n\nuse alloc::{sync::Arc, vec::Vec};\nuse bitflags::bitflags;\n\nuse crate::{\n arch::t"
},
{
"path": "src/userland/syscall/syscall_impl/time.rs",
"chars": 598,
"preview": "pub const ITIMER_REAL: usize = 0;\npub const ITIMER_VIRTUAL: usize = 1;\npub const ITIMER_PROF: usize = 2;\n\n#[derive(Defau"
},
{
"path": "src/util/ctypes.rs",
"chars": 926,
"preview": "#[allow(non_camel_case_types)]\npub type c_int16 = i16;\n#[allow(non_camel_case_types)]\npub type c_int32 = i32;\n#[allow(no"
},
{
"path": "src/util/errno.rs",
"chars": 6725,
"preview": "#[derive(Debug, Copy, Clone, Eq, PartialEq)]\n#[repr(i32)]\n#[allow(unused)]\n#[allow(clippy::upper_case_acronyms)]\npub enu"
},
{
"path": "src/util/error.rs",
"chars": 1659,
"preview": "use core::fmt::{Debug, Display};\n\nuse super::errno::Errno;\n\npub type KResult<T> = Result<T, KError<'static>>;\n\n#[derive("
},
{
"path": "src/util/lock.rs",
"chars": 4800,
"preview": "use core::mem::ManuallyDrop;\nuse core::ops::{Deref, DerefMut};\n\nuse spin::mutex::{SpinMutex, SpinMutexGuard};\nuse x86::c"
},
{
"path": "src/util/mod.rs",
"chars": 357,
"preview": "#[macro_use]\npub mod error;\npub mod ctypes;\npub mod errno;\npub mod lock;\npub mod ringbuffer;\npub mod stack;\n\npub use sel"
},
{
"path": "src/util/ringbuffer.rs",
"chars": 3127,
"preview": "//! The ringbuffer from Kerla.\n\nuse core::{cmp::min, mem::MaybeUninit, ops::Range, slice};\n\npub struct RingBuffer<T, con"
},
{
"path": "src/util/stack.rs",
"chars": 1362,
"preview": "use core::mem::size_of;\n\nuse super::align_down;\n\npub struct Stack<'a> {\n ptr: &'a mut usize,\n}\n\nimpl<'a> Stack<'a> {\n"
},
{
"path": "src/vga_text.rs",
"chars": 8941,
"preview": "use core::ops::Add;\n\nuse lazy_static::lazy_static;\n\n#[allow(dead_code)]\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\n#[r"
},
{
"path": "userland/.gitignore",
"chars": 8,
"preview": "/target\n"
},
{
"path": "userland/.vscode/settings.json",
"chars": 66,
"preview": "{\n \"rust-analyzer.cargo.target\": \"x86_64-unknown-linux-musl\",\n}"
},
{
"path": "userland/Cargo.toml",
"chars": 63,
"preview": "[workspace]\nmembers = [\"kash\", \"kados_syscall\"]\nresolver = \"3\"\n"
},
{
"path": "userland/kados_syscall/.cargo/config.toml",
"chars": 152,
"preview": "[build]\ntarget = \"x86_64-unknown-linux-musl\"\n\n[target.'cfg(target_os = \"linux\")']\nrustflags = [\"-C\", \"linker=rust-lld\", "
},
{
"path": "userland/kados_syscall/Cargo.toml",
"chars": 182,
"preview": "[package]\nname = \"kados_syscall\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://do"
},
{
"path": "userland/kados_syscall/src/consts.rs",
"chars": 12968,
"preview": "#[derive(Debug, Copy, Clone, Eq, PartialEq)]\n#[repr(i32)]\n#[allow(unused)]\n#[allow(clippy::upper_case_acronyms)]\npub enu"
},
{
"path": "userland/kados_syscall/src/lib.rs",
"chars": 3537,
"preview": "use core::arch::asm;\n\nuse consts::*;\n\npub mod consts;\n\n#[no_mangle]\n#[inline(always)]\n#[allow(clippy::missing_safety_doc"
},
{
"path": "userland/rust-toolchain.toml",
"chars": 98,
"preview": "[toolchain]\nchannel = \"nightly\"\ntargets = [\"x86_64-unknown-linux-musl\"]\ncomponents = [\"rust-src\"]\n"
}
]
About this extraction
This page contains the full source code of the clstatham/k4dos GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 91 files (431.2 KB), approximately 118.2k tokens, and a symbol index with 1334 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.