├── qemu_trace ├── initramfs ├── test.txt └── sys │ └── mouse_pointer.bmp ├── kernel ├── src │ ├── fs │ │ ├── file │ │ │ ├── mod.rs │ │ │ └── bitmap.rs │ │ ├── fat │ │ │ ├── file_allocation_table.rs │ │ │ ├── fs_info_sector.rs │ │ │ ├── dir_entry.rs │ │ │ ├── boot_sector.rs │ │ │ └── mod.rs │ │ ├── mod.rs │ │ └── exec.rs │ ├── sync │ │ ├── mod.rs │ │ ├── pin.rs │ │ ├── volatile.rs │ │ └── mutex.rs │ ├── util │ │ ├── mod.rs │ │ ├── audio.rs │ │ ├── slice.rs │ │ ├── time.rs │ │ ├── keyboard │ │ │ ├── key_event.rs │ │ │ ├── scan_code.rs │ │ │ └── mod.rs │ │ ├── cstring.rs │ │ ├── range.rs │ │ ├── bits.rs │ │ ├── mmio.rs │ │ ├── random.rs │ │ ├── lifo.rs │ │ └── fifo.rs │ ├── debug │ │ ├── qemu.rs │ │ ├── mod.rs │ │ └── logger.rs │ ├── device │ │ ├── usb │ │ │ └── mod.rs │ │ ├── mod.rs │ │ ├── urandom.rs │ │ ├── zakki.rs │ │ └── speaker.rs │ ├── arch │ │ ├── x86_64 │ │ │ ├── registers │ │ │ │ ├── mod.rs │ │ │ │ ├── msi.rs │ │ │ │ ├── control.rs │ │ │ │ ├── model_specific.rs │ │ │ │ └── segment.rs │ │ │ ├── apic.rs │ │ │ ├── tsc.rs │ │ │ ├── tss.rs │ │ │ └── mod.rs │ │ └── mod.rs │ ├── test.rs │ ├── panic.rs │ ├── env.rs │ ├── graphics │ │ ├── mod.rs │ │ ├── color.rs │ │ └── font.rs │ ├── mem │ │ └── mod.rs │ ├── net │ │ ├── icmp.rs │ │ ├── udp.rs │ │ └── arp.rs │ ├── error.rs │ └── task │ │ └── async_task.rs ├── rust-toolchain.toml ├── .cargo │ └── config.toml └── Cargo.toml ├── .prettierrc ├── common ├── rust-toolchain.toml ├── Cargo.toml └── src │ ├── lib.rs │ ├── kernel_config.rs │ ├── boot_info.rs │ ├── mem_desc.rs │ └── graphic_info.rs ├── apps ├── imgvw │ ├── rust-toolchain.toml │ ├── Makefile │ ├── .cargo │ │ └── config.toml │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── lifegame │ ├── rust-toolchain.toml │ ├── Makefile │ ├── Cargo.toml │ └── .cargo │ │ └── config.toml ├── mandelbrot │ ├── rust-toolchain.toml │ ├── Makefile │ ├── .cargo │ │ └── config.toml │ └── Cargo.toml ├── cd │ ├── Makefile │ └── main.c ├── ls │ ├── Makefile │ └── main.c ├── sh │ ├── Makefile │ └── main.c ├── bfi │ ├── Makefile │ └── main.c ├── cat │ ├── Makefile │ └── main.c ├── fib │ ├── Makefile │ └── main.c ├── test │ ├── Makefile │ └── main.c ├── hexdump │ ├── Makefile │ └── main.c ├── lspci │ ├── Makefile │ └── main.c ├── lsusb │ ├── Makefile │ └── main.c ├── uname │ ├── Makefile │ └── uname.c ├── uptime │ ├── Makefile │ └── main.c ├── write │ ├── Makefile │ └── main.c ├── game2048 │ └── Makefile ├── libc │ ├── ctype.h │ ├── sys │ │ ├── stat.h │ │ ├── stat.c │ │ └── socket.h │ ├── stat.h │ ├── main.c │ ├── utsname.h │ ├── ctype.c │ ├── stdlib.h │ ├── window.h │ ├── Makefile │ ├── string.h │ ├── stdio.h │ ├── iomsg.h │ ├── stdlib.c │ ├── syscalls.h │ ├── syscalls.c │ ├── window.c │ └── stdio.c ├── doom │ └── Makefile ├── libc-rs │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ └── lib.rs ├── Makefile.rust.common └── Makefile.common ├── bootloader ├── rust-toolchain.toml ├── .cargo │ └── config.toml ├── Cargo.toml └── src │ └── config.rs ├── third-party ├── OVMF_CODE.fd └── License.txt ├── Cargo.toml ├── .gitignore ├── .editorconfig ├── .gitmodules ├── .vscode ├── settings.json └── launch.json ├── LICENSE └── README.md /qemu_trace: -------------------------------------------------------------------------------- 1 | #usb_xhci_* 2 | -------------------------------------------------------------------------------- /initramfs/test.txt: -------------------------------------------------------------------------------- 1 | hello world! 2 | -------------------------------------------------------------------------------- /kernel/src/fs/file/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod bitmap; 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "editorconfig": true 3 | } 4 | -------------------------------------------------------------------------------- /common/rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly" 3 | -------------------------------------------------------------------------------- /kernel/rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly" 3 | -------------------------------------------------------------------------------- /apps/imgvw/rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly" 3 | -------------------------------------------------------------------------------- /apps/lifegame/rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly" 3 | -------------------------------------------------------------------------------- /bootloader/rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly" 3 | -------------------------------------------------------------------------------- /apps/imgvw/Makefile: -------------------------------------------------------------------------------- 1 | FILE_NAME := imgvw 2 | include ../Makefile.rust.common 3 | -------------------------------------------------------------------------------- /apps/mandelbrot/rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly" 3 | -------------------------------------------------------------------------------- /kernel/src/sync/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod mutex; 2 | pub mod pin; 3 | pub mod volatile; 4 | -------------------------------------------------------------------------------- /apps/lifegame/Makefile: -------------------------------------------------------------------------------- 1 | FILE_NAME := lifegame 2 | include ../Makefile.rust.common 3 | -------------------------------------------------------------------------------- /apps/mandelbrot/Makefile: -------------------------------------------------------------------------------- 1 | FILE_NAME := mandelbrot 2 | include ../Makefile.rust.common 3 | -------------------------------------------------------------------------------- /third-party/OVMF_CODE.fd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zakki0925224/myos-x86_64/HEAD/third-party/OVMF_CODE.fd -------------------------------------------------------------------------------- /initramfs/sys/mouse_pointer.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zakki0925224/myos-x86_64/HEAD/initramfs/sys/mouse_pointer.bmp -------------------------------------------------------------------------------- /apps/cd/Makefile: -------------------------------------------------------------------------------- 1 | SRC_FILES := main.c 2 | OBJ_FILES := $(SRC_FILES:.c=.o) 3 | OUT_FILE := ../bin/cd 4 | 5 | include ../Makefile.common 6 | -------------------------------------------------------------------------------- /apps/ls/Makefile: -------------------------------------------------------------------------------- 1 | SRC_FILES := main.c 2 | OBJ_FILES := $(SRC_FILES:.c=.o) 3 | OUT_FILE := ../bin/ls 4 | 5 | include ../Makefile.common 6 | -------------------------------------------------------------------------------- /apps/sh/Makefile: -------------------------------------------------------------------------------- 1 | SRC_FILES := main.c 2 | OBJ_FILES := $(SRC_FILES:.c=.o) 3 | OUT_FILE := ../bin/sh 4 | 5 | include ../Makefile.common 6 | -------------------------------------------------------------------------------- /apps/bfi/Makefile: -------------------------------------------------------------------------------- 1 | SRC_FILES := main.c 2 | OBJ_FILES := $(SRC_FILES:.c=.o) 3 | OUT_FILE := ../bin/bfi 4 | 5 | include ../Makefile.common 6 | -------------------------------------------------------------------------------- /apps/cat/Makefile: -------------------------------------------------------------------------------- 1 | SRC_FILES := main.c 2 | OBJ_FILES := $(SRC_FILES:.c=.o) 3 | OUT_FILE := ../bin/cat 4 | 5 | include ../Makefile.common 6 | -------------------------------------------------------------------------------- /apps/fib/Makefile: -------------------------------------------------------------------------------- 1 | SRC_FILES := main.c 2 | OBJ_FILES := $(SRC_FILES:.c=.o) 3 | OUT_FILE := ../bin/fib 4 | 5 | include ../Makefile.common 6 | -------------------------------------------------------------------------------- /apps/test/Makefile: -------------------------------------------------------------------------------- 1 | SRC_FILES := main.c 2 | OBJ_FILES := $(SRC_FILES:.c=.o) 3 | OUT_FILE := ../bin/test 4 | 5 | include ../Makefile.common 6 | -------------------------------------------------------------------------------- /apps/hexdump/Makefile: -------------------------------------------------------------------------------- 1 | SRC_FILES := main.c 2 | OBJ_FILES := $(SRC_FILES:.c=.o) 3 | OUT_FILE := ../bin/hexdump 4 | 5 | include ../Makefile.common 6 | -------------------------------------------------------------------------------- /apps/lspci/Makefile: -------------------------------------------------------------------------------- 1 | SRC_FILES := main.c 2 | OBJ_FILES := $(SRC_FILES:.c=.o) 3 | OUT_FILE := ../bin/lspci 4 | 5 | include ../Makefile.common 6 | -------------------------------------------------------------------------------- /apps/lsusb/Makefile: -------------------------------------------------------------------------------- 1 | SRC_FILES := main.c 2 | OBJ_FILES := $(SRC_FILES:.c=.o) 3 | OUT_FILE := ../bin/lsusb 4 | 5 | include ../Makefile.common 6 | -------------------------------------------------------------------------------- /apps/uname/Makefile: -------------------------------------------------------------------------------- 1 | SRC_FILES := uname.c 2 | OBJ_FILES := $(SRC_FILES:.c=.o) 3 | OUT_FILE := ../bin/uname 4 | 5 | include ../Makefile.common 6 | -------------------------------------------------------------------------------- /apps/uptime/Makefile: -------------------------------------------------------------------------------- 1 | SRC_FILES := main.c 2 | OBJ_FILES := $(SRC_FILES:.c=.o) 3 | OUT_FILE := ../bin/uptime 4 | 5 | include ../Makefile.common 6 | -------------------------------------------------------------------------------- /apps/write/Makefile: -------------------------------------------------------------------------------- 1 | SRC_FILES := main.c 2 | OBJ_FILES := $(SRC_FILES:.c=.o) 3 | OUT_FILE := ../bin/write 4 | 5 | include ../Makefile.common 6 | -------------------------------------------------------------------------------- /apps/game2048/Makefile: -------------------------------------------------------------------------------- 1 | SRC_FILES := main.c 2 | OBJ_FILES := $(SRC_FILES:.c=.o) 3 | OUT_FILE := ../bin/game2048 4 | 5 | include ../Makefile.common 6 | -------------------------------------------------------------------------------- /common/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "common" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["Zakki "] 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /apps/libc/ctype.h: -------------------------------------------------------------------------------- 1 | #ifndef _CTYPE_H 2 | #define _CTYPE_H 3 | 4 | extern int toupper(int c); 5 | extern int tolower(int c); 6 | extern int isspace(int c); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /apps/libc/sys/stat.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYS_STAT_H 2 | #define _SYS_STAT_H 3 | 4 | #include 5 | 6 | extern int mkdir(const char* path, __mode_t mode); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = ["bootloader", "common", "kernel"] 4 | exclude = ["apps/libc-rs", "apps/mandelbrot", "apps/imgvw", "apps/lifegame"] 5 | -------------------------------------------------------------------------------- /apps/libc/stat.h: -------------------------------------------------------------------------------- 1 | #ifndef _STAT_H 2 | #define _STAT_H 3 | 4 | #include 5 | 6 | typedef struct 7 | { 8 | size_t size; 9 | } f_stat; 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /common/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | pub mod boot_info; 4 | pub mod elf; 5 | pub mod graphic_info; 6 | pub mod kernel_config; 7 | pub mod mem_desc; 8 | 9 | extern crate alloc; 10 | -------------------------------------------------------------------------------- /apps/lifegame/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lifegame" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | embedded-graphics = "0.8.1" 8 | libc-rs = { path = "../libc-rs" } 9 | -------------------------------------------------------------------------------- /bootloader/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [unstable] 2 | build-std = ["core", "compiler_builtins", "alloc"] 3 | build-std-features = ["compiler-builtins-mem"] 4 | 5 | [build] 6 | target = "x86_64-unknown-uefi" 7 | -------------------------------------------------------------------------------- /apps/imgvw/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [unstable] 2 | build-std = ["core", "compiler_builtins", "alloc"] 3 | build-std-features = ["compiler-builtins-mem"] 4 | 5 | [build] 6 | target = "../../build-target/x86_64-app.json" 7 | -------------------------------------------------------------------------------- /common/src/kernel_config.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | pub struct KernelConfig<'a> { 3 | pub init_cwd_path: &'a str, 4 | pub init_app_exec_args: Option<&'a str>, 5 | pub mouse_pointer_bmp_path: &'a str, 6 | } 7 | -------------------------------------------------------------------------------- /kernel/src/fs/fat/file_allocation_table.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 2 | pub enum ClusterType { 3 | Free, 4 | Reserved, 5 | Data(usize), 6 | Bad(usize), 7 | EndOfChain, 8 | } 9 | -------------------------------------------------------------------------------- /apps/lifegame/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [unstable] 2 | build-std = ["core", "compiler_builtins", "alloc"] 3 | build-std-features = ["compiler-builtins-mem"] 4 | 5 | [build] 6 | target = "../../build-target/x86_64-app.json" 7 | -------------------------------------------------------------------------------- /apps/mandelbrot/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [unstable] 2 | build-std = ["core", "compiler_builtins", "alloc"] 3 | build-std-features = ["compiler-builtins-mem"] 4 | 5 | [build] 6 | target = "../../build-target/x86_64-app.json" 7 | -------------------------------------------------------------------------------- /apps/libc/sys/stat.c: -------------------------------------------------------------------------------- 1 | #include "stat.h" 2 | 3 | #include 4 | 5 | #include "stdio.h" 6 | 7 | int mkdir(const char* path, __mode_t mode) { 8 | printf("[DEBUG]mkdir called\n"); 9 | return -1; 10 | } 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | build 3 | dump 4 | qemu_debug.log 5 | apps/bin 6 | third-party/font.psf 7 | third-party/OVMF_VARS.fd 8 | third-party/doom1.wad 9 | initramfs/apps 10 | initramfs/doom1.wad 11 | 12 | *.elf 13 | *.o 14 | *.so 15 | *.a 16 | -------------------------------------------------------------------------------- /apps/doom/Makefile: -------------------------------------------------------------------------------- 1 | DOOM_DIR = ../../third-party/doom-for-myos 2 | DOOM_MAKEFILE = $(DOOM_DIR)/Makefile.myos 3 | 4 | all: 5 | $(MAKE) -f $(DOOM_MAKEFILE) all 6 | 7 | clean: 8 | $(MAKE) -f $(DOOM_MAKEFILE) clean 9 | 10 | .PHONY: all clean 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [{Makefile,**.mk}] 12 | indent_style = tab 13 | -------------------------------------------------------------------------------- /apps/mandelbrot/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mandelbrot" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["Zakki "] 6 | 7 | [dependencies] 8 | embedded-graphics = "0.8.1" 9 | libc-rs = { path = "../libc-rs" } 10 | -------------------------------------------------------------------------------- /kernel/src/util/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod ansi; 2 | pub mod audio; 3 | pub mod bits; 4 | pub mod cstring; 5 | pub mod fifo; 6 | pub mod keyboard; 7 | pub mod lifo; 8 | pub mod mmio; 9 | pub mod random; 10 | pub mod range; 11 | pub mod slice; 12 | pub mod time; 13 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "third-party/qemu"] 2 | path = third-party/qemu 3 | url = https://gitlab.com/qemu-project/qemu.git 4 | [submodule "third-party/doom-for-myos"] 5 | path = third-party/doom-for-myos 6 | url = https://github.com/Zakki0925224/doom-for-myos.git 7 | -------------------------------------------------------------------------------- /apps/imgvw/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "imgvw" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["Zakki "] 6 | 7 | [dependencies] 8 | embedded-graphics = "0.8.1" 9 | libc-rs = { path = "../libc-rs" } 10 | tinygif = "0.0.4" 11 | -------------------------------------------------------------------------------- /apps/libc/main.c: -------------------------------------------------------------------------------- 1 | #pragma GCC diagnostic push 2 | #pragma GCC diagnostic ignored "-Wimplicit-function-declaration" 3 | 4 | #include "stdio.h" 5 | 6 | void _start(int argc, char const* argv[]) { 7 | exit((uint64_t)main(argc, argv)); 8 | } 9 | 10 | #pragma GCC diagnostic pop 11 | -------------------------------------------------------------------------------- /kernel/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [unstable] 2 | build-std = ["core", "compiler_builtins", "alloc"] 3 | build-std-features = ["compiler-builtins-mem"] 4 | 5 | [build] 6 | target = "../build-target/x86_64-kernel.json" 7 | 8 | [target.'cfg(target_os = "none")'] 9 | runner = "python3 ../task.py test" 10 | -------------------------------------------------------------------------------- /apps/cd/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char* argv[]) { 5 | if (argc < 2) { 6 | return 0; 7 | } 8 | 9 | if (sys_chdir(argv[1]) == -1) { 10 | printf("cd: failed to change directory\n"); 11 | return -1; 12 | } 13 | 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /bootloader/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bootloader" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["Zakki "] 6 | 7 | [dependencies] 8 | common = { path = "../common" } 9 | uefi = { version = "0.35.0", features = ["alloc", "global_allocator", "panic_handler", "logger"] } 10 | log = "0.4.26" 11 | -------------------------------------------------------------------------------- /kernel/src/fs/fat/fs_info_sector.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | #[repr(C)] 3 | pub struct FsInfoSector { 4 | sign0: u32, 5 | reserved0: [u8; 480], 6 | sign1: u32, 7 | free_cnt: [u8; 4], // free clusters count 8 | next_free: [u8; 4], // next free cluster number 9 | reserved1: [u8; 12], 10 | sign2: u32, 11 | } 12 | -------------------------------------------------------------------------------- /apps/fib/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int fib(int n) { 4 | if (n <= 1) { 5 | return n; 6 | } 7 | 8 | return fib(n - 1) + fib(n - 2); 9 | } 10 | 11 | int main(void) { 12 | for (int i = 0; i < 50; i++) { 13 | printf("%d, ", fib(i)); 14 | } 15 | printf("\n"); 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /apps/libc/utsname.h: -------------------------------------------------------------------------------- 1 | #ifndef _UTSNAME_H 2 | #define _UTSNAME_H 3 | 4 | #define UTS_LEN 64 5 | 6 | typedef struct 7 | { 8 | char sysname[UTS_LEN]; 9 | char nodename[UTS_LEN]; 10 | char release[UTS_LEN]; 11 | char version[UTS_LEN]; 12 | char machine[UTS_LEN]; 13 | char domainname[UTS_LEN]; 14 | } utsname; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /kernel/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kernel" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["Zakki "] 6 | description = "A hobby operating system written in Rust." 7 | 8 | [dependencies] 9 | common = { path = "../common" } 10 | libc-rs = { path = "../apps/libc-rs", features = ["kernel"] } 11 | pci-ids = "0.2.5" 12 | -------------------------------------------------------------------------------- /kernel/src/debug/qemu.rs: -------------------------------------------------------------------------------- 1 | use crate::{arch::IoPortAddress, kwarn}; 2 | 3 | pub const EXIT_SUCCESS: u32 = 0x10; 4 | pub const EXIT_FAILURE: u32 = 0x11; 5 | 6 | pub fn exit(exit_code: u32) { 7 | // ISA debug exit 8 | IoPortAddress::new(0xf4).out32(exit_code); 9 | 10 | // if QEMU, unreachable 11 | kwarn!("Failed to exit QEMU"); 12 | } 13 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.check.allTargets": false, 3 | "rust-analyzer.linkedProjects": [ 4 | "./kernel/Cargo.toml", 5 | "./bootloader/Cargo.toml", 6 | "./common/Cargo.toml", 7 | "./apps/libc-rs/Cargo.toml", 8 | "./apps/mandelbrot/Cargo.toml", 9 | "./apps/imgvw/Cargo.toml", 10 | "./apps/lifegame/Cargo.toml" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /kernel/src/device/usb/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::{device::usb::usb_bus::UsbDeviceAttachInfo, error::Result}; 2 | 3 | pub mod hid_keyboard; 4 | pub mod hid_tablet; 5 | pub mod usb_bus; 6 | pub mod xhc; 7 | 8 | pub trait UsbDeviceDriverFunction { 9 | fn configure(&mut self, attach_info: &mut UsbDeviceAttachInfo) -> Result<()>; 10 | fn poll(&mut self, attach_info: &mut UsbDeviceAttachInfo) -> Result<()>; 11 | } 12 | -------------------------------------------------------------------------------- /apps/libc-rs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libc-rs" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["Zakki "] 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | [dependencies] 9 | linked_list_allocator = "0.10.5" 10 | 11 | [build-dependencies] 12 | bindgen = "0.72.0" 13 | 14 | [features] 15 | default = [] 16 | kernel = [] 17 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/registers/mod.rs: -------------------------------------------------------------------------------- 1 | pub use control::*; 2 | pub use model_specific::*; 3 | pub use msi::*; 4 | pub use segment::*; 5 | pub use status::*; 6 | 7 | mod control; 8 | mod model_specific; 9 | mod msi; 10 | pub mod segment; 11 | mod status; 12 | 13 | pub trait Register { 14 | fn read() -> Self; 15 | fn write(&self); 16 | fn raw(&self) -> T; 17 | fn set_raw(&mut self, value: T); 18 | } 19 | -------------------------------------------------------------------------------- /apps/libc/ctype.c: -------------------------------------------------------------------------------- 1 | #include "ctype.h" 2 | 3 | int toupper(int c) { 4 | if (c >= 'a' && c <= 'z') { 5 | return (c - 'a' + 'A'); 6 | } 7 | 8 | return c; 9 | } 10 | 11 | int tolower(int c) { 12 | if (c >= 'A' && c <= 'Z') { 13 | return (c - 'A' + 'a'); 14 | } 15 | 16 | return c; 17 | } 18 | 19 | int isspace(int c) { 20 | return ((c == ' ') || (c == '\n') || (c == '\t')); 21 | } 22 | -------------------------------------------------------------------------------- /common/src/boot_info.rs: -------------------------------------------------------------------------------- 1 | use crate::{graphic_info::GraphicInfo, kernel_config::KernelConfig, mem_desc::MemoryDescriptor}; 2 | 3 | #[derive(Debug)] 4 | #[repr(C)] 5 | pub struct BootInfo<'a> { 6 | pub mem_map: &'a [MemoryDescriptor], 7 | pub graphic_info: GraphicInfo, 8 | pub initramfs_start_virt_addr: u64, 9 | pub initramfs_page_cnt: usize, 10 | pub rsdp_virt_addr: Option, 11 | pub kernel_config: KernelConfig<'a>, 12 | } 13 | -------------------------------------------------------------------------------- /apps/libc/stdlib.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDLIB_H 2 | #define _STDLIB_H 3 | 4 | #include 5 | 6 | extern int abs(int i); 7 | extern void* malloc(size_t len); 8 | extern int atoi(const char* str); 9 | extern double atof(const char* nptr); 10 | extern void free(void* ptr); 11 | extern void* calloc(size_t count, size_t size); 12 | extern void* realloc(void* ptr, size_t size); 13 | extern int system(const char* command); 14 | extern int remove(const char* filepath); 15 | extern int rename(const char* old, const char* _new); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/apic.rs: -------------------------------------------------------------------------------- 1 | use crate::{arch::VirtualAddress, sync::volatile::Volatile, util::mmio::Mmio}; 2 | 3 | pub fn local_apic_id() -> u8 { 4 | let reg: Mmio> = 5 | unsafe { Mmio::from_raw(VirtualAddress::new(0xfee00020).as_ptr_mut()) }; 6 | (reg.as_ref().read() >> 24) as u8 7 | } 8 | 9 | pub fn notify_end_of_int() { 10 | let mut reg: Mmio> = 11 | unsafe { Mmio::from_raw(VirtualAddress::new(0xfee000b0).as_ptr_mut()) }; 12 | unsafe { 13 | reg.get_unchecked_mut().write(0); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /kernel/src/util/audio.rs: -------------------------------------------------------------------------------- 1 | use core::num::NonZeroU8; 2 | 3 | #[repr(u32)] 4 | #[derive(Copy, Clone)] 5 | pub enum Pitch { 6 | C = 65, 7 | Cs = 69, 8 | D = 73, 9 | Ds = 78, 10 | E = 82, 11 | F = 87, 12 | Fs = 92, 13 | G = 98, 14 | Gs = 104, 15 | A = 110, 16 | As = 117, 17 | B = 123, 18 | } 19 | 20 | impl Pitch { 21 | pub fn to_freq(&self, octave: NonZeroU8) -> u32 { 22 | let base_freq = *self as u32; 23 | let octave_mul = 1u32 << (octave.get() - 1); 24 | base_freq * octave_mul 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /kernel/src/util/slice.rs: -------------------------------------------------------------------------------- 1 | use crate::error::{Error, Result}; 2 | use core::slice; 3 | 4 | pub unsafe trait Sliceable: Sized + Clone + Copy { 5 | fn as_slice(&self) -> &[u8] { 6 | unsafe { slice::from_raw_parts(self as *const Self as *const u8, size_of::()) } 7 | } 8 | 9 | fn copy_from_slice(data: &[u8]) -> Result { 10 | if size_of::() > data.len() { 11 | Err(Error::Failed("data is too short")) 12 | } else { 13 | Ok(unsafe { *(data.as_ptr() as *const Self) }) 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /apps/Makefile.rust.common: -------------------------------------------------------------------------------- 1 | OUT_FILE := ../bin/$(FILE_NAME) 2 | TARGET := x86_64-app 3 | LIBC_DIR := ../libc 4 | LIBC_A := $(LIBC_DIR)/libc_with_main.a 5 | 6 | RUST_FILES := $(shell find src -type f -name "*.rs") Cargo.toml 7 | ifneq ($(wildcard build.rs),) 8 | RUST_FILES += build.rs 9 | endif 10 | 11 | all: $(OUT_FILE) 12 | 13 | $(OUT_FILE): $(RUST_FILES) $(LIBC_A) 14 | cargo build --release 15 | mkdir -p ../bin 16 | cp target/$(TARGET)/release/$(FILE_NAME) $(OUT_FILE) 17 | 18 | $(LIBC_A): 19 | $(MAKE) -C $(LIBC_DIR) app 20 | 21 | clean: 22 | cargo clean 23 | rm -f $(OUT_FILE) 24 | 25 | .PHONY: clean all 26 | -------------------------------------------------------------------------------- /kernel/src/test.rs: -------------------------------------------------------------------------------- 1 | #[allow(dead_code)] 2 | pub trait Testable { 3 | fn run(&self); 4 | } 5 | 6 | impl Testable for T { 7 | fn run(&self) { 8 | use crate::{print, println}; 9 | 10 | print!("{}...", core::any::type_name::()); 11 | self(); 12 | println!("[ok]"); 13 | } 14 | } 15 | 16 | #[cfg(test)] 17 | pub fn test_runner(tests: &[&dyn Testable]) { 18 | use crate::{debug::qemu, println}; 19 | 20 | println!("Running {} tests", tests.len()); 21 | for test in tests { 22 | test.run(); 23 | } 24 | 25 | qemu::exit(qemu::EXIT_SUCCESS); 26 | } 27 | -------------------------------------------------------------------------------- /apps/Makefile.common: -------------------------------------------------------------------------------- 1 | CC := gcc 2 | CFLAGS := -I ../libc -Werror -g -m64 -nostdlib -fno-builtin -fno-stack-protector -mcmodel=large -mno-mmx -mno-sse -msoft-float -std=c11 3 | 4 | LD := ld.lld 5 | LDFLAGS := -z norelro --static --image-base=0xffff800000000000 6 | 7 | LIBC_DIR := ../libc 8 | LIBC := $(LIBC_DIR)/libc_with_main.a 9 | 10 | $(OUT_FILE): $(OBJ_FILES) $(LIBC) 11 | mkdir -p ../bin 12 | $(LD) $(OBJ_FILES) $(LIBC) -o $@ $(LDFLAGS) 13 | 14 | $(LIBC): 15 | $(MAKE) -C $(LIBC_DIR) app 16 | 17 | %.o: %.c 18 | $(CC) -c $< -o $@ $(CFLAGS) 19 | 20 | clean: 21 | rm -f $(OUT_FILE) $(OBJ_FILES) 22 | 23 | all: $(OUT_FILE) 24 | 25 | .PHONY: clean all 26 | -------------------------------------------------------------------------------- /kernel/src/util/time.rs: -------------------------------------------------------------------------------- 1 | use crate::{arch::x86_64, device, task::async_task}; 2 | use core::time::Duration; 3 | 4 | pub fn global_uptime() -> Duration { 5 | device::local_apic_timer::global_uptime() 6 | } 7 | 8 | pub fn sleep(duration: Duration) { 9 | let target_time = global_uptime() + duration; 10 | 11 | while global_uptime() < target_time { 12 | x86_64::stihlt(); 13 | } 14 | } 15 | 16 | pub async fn sleep_async(duration: Duration) { 17 | let target_time = global_uptime() + duration; 18 | 19 | while global_uptime() < target_time { 20 | x86_64::stihlt(); 21 | async_task::exec_yield().await; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /apps/libc/window.h: -------------------------------------------------------------------------------- 1 | #ifndef _WINDOW_H 2 | #define _WINDOW_H 3 | 4 | #include 5 | #include 6 | 7 | #define PIXEL_FORMAT_RGB 0 8 | #define PIXEL_FORMAT_BGR 1 9 | #define PIXEL_FORMAT_BGRA 2 10 | 11 | typedef struct 12 | { 13 | int layer_id; 14 | } component_descriptor; 15 | 16 | extern int remove_component(component_descriptor* cdesc); 17 | extern component_descriptor* create_component_window(const char* title, size_t x_pos, size_t y_pos, size_t width, size_t height); 18 | extern component_descriptor* create_component_image(component_descriptor* cdesc, size_t image_width, size_t image_height, uint8_t pixel_format, const void* framebuf); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /apps/libc/Makefile: -------------------------------------------------------------------------------- 1 | SRC_FILES := stdio.c stdlib.c string.c syscalls.c printf.c window.c ctype.c sys/stat.c 2 | OBJ_FILES := $(SRC_FILES:.c=.o) 3 | LIB_FILE := libc.a 4 | 5 | MAIN_OBJ := main.o 6 | LIB_WITH_MAIN := libc_with_main.a 7 | 8 | CC := gcc 9 | CFLAGS := -Werror -g -m64 -nostdlib -fno-builtin -fno-stack-protector -std=c11 10 | 11 | $(LIB_FILE): $(OBJ_FILES) 12 | ar rcs $@ $^ 13 | nm $@ 14 | 15 | $(LIB_WITH_MAIN): $(OBJ_FILES) $(MAIN_OBJ) 16 | ar rcs $@ $^ 17 | nm $@ 18 | 19 | app: $(LIB_WITH_MAIN) 20 | 21 | %.o: %.c 22 | $(CC) -c $< -o $@ $(CFLAGS) 23 | 24 | clean: 25 | rm -f $(OBJ_FILES) $(MAIN_OBJ) $(LIB_FILE) $(LIB_WITH_MAIN) 26 | 27 | all: $(LIB_FILE) 28 | 29 | .PHONY: clean all app 30 | -------------------------------------------------------------------------------- /apps/cat/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char* argv[]) { 5 | if (argc < 2) { 6 | return 0; 7 | } 8 | 9 | FILE* file = fopen(argv[1], "r"); 10 | if (file == NULL) { 11 | printf("cat: failed to open the file\n"); 12 | return -1; 13 | } 14 | 15 | size_t file_size = file->stat->size; 16 | char* buf = (char*)malloc(file_size); 17 | if (buf == NULL) { 18 | printf("cat: failed to allocate memory\n"); 19 | fclose(file); 20 | return -1; 21 | } 22 | fread(buf, 1, file_size, file); 23 | 24 | printf("%s\n", buf); 25 | fclose(file); 26 | free(buf); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /kernel/src/panic.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | arch::x86_64, 3 | debug::qemu::{self, EXIT_FAILURE}, 4 | device::panic_screen, 5 | kerror, 6 | }; 7 | use core::panic::PanicInfo; 8 | 9 | #[panic_handler] 10 | fn panic(info: &PanicInfo) -> ! { 11 | kerror!("{:?}", info.message()); 12 | kerror!("{:?}", info.location()); 13 | 14 | // prevent overwriting by graphics::frame_buf 15 | x86_64::disabled_int(|| { 16 | panic_screen::write_fmt(format_args!("{:?}\n", info.message())).unwrap(); 17 | panic_screen::write_fmt(format_args!("{:?}\n", info.location())).unwrap(); 18 | 19 | qemu::exit(EXIT_FAILURE); 20 | loop {} 21 | }); 22 | 23 | unreachable!(); 24 | } 25 | -------------------------------------------------------------------------------- /apps/lspci/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char* argv[]) { 5 | FILE* file = fopen("/dev/pci-bus", "r"); 6 | 7 | if (file == NULL) { 8 | printf("lspci: failed to open the file\n"); 9 | return -1; 10 | } 11 | 12 | size_t file_size = file->stat->size; 13 | 14 | char* f_buf = (char*)malloc(file_size + 1); 15 | if (f_buf == NULL) { 16 | printf("lspci: failed to allocate memory\n"); 17 | fclose(file); 18 | return -1; 19 | } 20 | 21 | fread(f_buf, 1, file_size, file); 22 | fclose(file); 23 | 24 | f_buf[file_size] = '\0'; 25 | printf("%s\n", f_buf); 26 | 27 | free(f_buf); 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /apps/lsusb/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char* argv[]) { 5 | FILE* file = fopen("/dev/usb-bus", "r"); 6 | 7 | if (file == NULL) { 8 | printf("lsusb: failed to open the file\n"); 9 | return -1; 10 | } 11 | 12 | size_t file_size = file->stat->size; 13 | 14 | char* f_buf = (char*)malloc(file_size + 1); 15 | if (f_buf == NULL) { 16 | printf("lsusb: failed to allocate memory\n"); 17 | fclose(file); 18 | return -1; 19 | } 20 | 21 | fread(f_buf, 1, file_size, file); 22 | fclose(file); 23 | 24 | f_buf[file_size] = '\0'; 25 | printf("%s\n", f_buf); 26 | 27 | free(f_buf); 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /kernel/src/util/keyboard/key_event.rs: -------------------------------------------------------------------------------- 1 | use super::scan_code::KeyCode; 2 | 3 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 4 | pub enum KeyState { 5 | Pressed, 6 | Released, 7 | } 8 | 9 | #[derive(Debug, Clone, Copy)] 10 | pub struct ModifierKeysState { 11 | pub shift: bool, 12 | pub ctrl: bool, 13 | pub gui: bool, 14 | pub alt: bool, 15 | } 16 | 17 | impl ModifierKeysState { 18 | pub const fn default() -> Self { 19 | Self { 20 | shift: false, 21 | ctrl: false, 22 | gui: false, 23 | alt: false, 24 | } 25 | } 26 | } 27 | 28 | #[derive(Debug, Clone, Copy)] 29 | pub struct KeyEvent { 30 | pub code: KeyCode, 31 | pub state: KeyState, 32 | pub c: Option, 33 | } 34 | -------------------------------------------------------------------------------- /bootloader/src/config.rs: -------------------------------------------------------------------------------- 1 | use common::kernel_config::KernelConfig; 2 | 3 | #[derive(Debug)] 4 | pub struct BootConfig<'a> { 5 | pub kernel_path: &'a str, 6 | pub initramfs_path: &'a str, 7 | pub resolution: (usize, usize), 8 | } 9 | 10 | impl Default for BootConfig<'_> { 11 | fn default() -> Self { 12 | Self { 13 | kernel_path: "\\EFI\\myos\\kernel.elf", 14 | initramfs_path: "initramfs.img", 15 | resolution: (800, 600), 16 | } 17 | } 18 | } 19 | 20 | pub const KERNEL_CONFIG: KernelConfig = KernelConfig { 21 | init_cwd_path: "/mnt/initramfs", 22 | init_app_exec_args: Some("/mnt/initramfs/apps/bin/sh /mnt/initramfs/apps/bin"), 23 | mouse_pointer_bmp_path: "/mnt/initramfs/sys/mouse_pointer.bmp", 24 | }; 25 | -------------------------------------------------------------------------------- /apps/libc/sys/socket.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYS_SOCKET_H 2 | #define _SYS_SOCKET_H 3 | 4 | #include 5 | 6 | typedef uint16_t sa_family_t; 7 | 8 | struct sockaddr { 9 | sa_family_t sa_family; 10 | char sa_data[14]; 11 | }; 12 | 13 | typedef uint16_t in_port_t; 14 | typedef uint32_t in_addr_t; 15 | 16 | struct in_addr { 17 | in_addr_t s_addr; 18 | }; 19 | 20 | struct sockaddr_in { 21 | sa_family_t sin_family; 22 | in_port_t sin_port; 23 | struct in_addr sin_addr; 24 | char sin_zero[8]; 25 | }; 26 | 27 | struct in6_addr { 28 | uint8_t s6_addr[16]; 29 | }; 30 | 31 | struct sockaddr_in6 { 32 | sa_family_t sin6_family; 33 | in_port_t sin6_port; 34 | uint32_t sin6_flowinfo; 35 | struct in6_addr sin6_addr; 36 | uint32_t sin6_scope_id; 37 | }; 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /apps/uptime/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define MS_IN_A_DAY (24 * 60 * 60 * 1000) 6 | #define MS_IN_A_HOUR (60 * 60 * 1000) 7 | #define MS_IN_A_MINUTE (60 * 1000) 8 | #define MS_IN_A_SECOND 1000 9 | 10 | int main(int argc, char* argv[]) { 11 | uint64_t uptime_ms = sys_uptime(); 12 | uint64_t days = uptime_ms / MS_IN_A_DAY; 13 | uint64_t hours = (uptime_ms % MS_IN_A_DAY) / MS_IN_A_HOUR; 14 | uint64_t minutes = (uptime_ms % MS_IN_A_HOUR) / MS_IN_A_MINUTE; 15 | uint64_t seconds = (uptime_ms % MS_IN_A_MINUTE) / MS_IN_A_SECOND; 16 | uint64_t milliseconds = (uptime_ms % MS_IN_A_SECOND); 17 | 18 | printf("%d ms\n", uptime_ms); 19 | printf("%d days %d hours %d minutes %d seconds %d milliseconds\n", days, hours, minutes, seconds, milliseconds); 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /apps/write/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char* argv[]) { 6 | if (argc < 3) { 7 | return 0; 8 | } 9 | 10 | FILE* file = fopen(argv[1], "w"); 11 | if (file == NULL) { 12 | printf("write: failed to open the file\n"); 13 | return -1; 14 | } 15 | 16 | if (fwrite(argv[2], 1, strlen(argv[2]), file) != strlen(argv[2])) { 17 | printf("write: failed to write to the file\n"); 18 | fclose(file); 19 | return -1; 20 | } 21 | 22 | if (fflush(file) == -1) { 23 | printf("write: failed to flush the file\n"); 24 | fclose(file); 25 | return -1; 26 | } 27 | 28 | if (fclose(file) == -1) { 29 | printf("write: failed to close the file\n"); 30 | return -1; 31 | } 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /kernel/src/fs/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | arch::VirtualAddress, 3 | error::Result, 4 | fs::{ 5 | fat::{volume::FatVolume, Fat}, 6 | vfs::FileSystem, 7 | }, 8 | kinfo, 9 | }; 10 | use common::kernel_config::KernelConfig; 11 | 12 | pub mod exec; 13 | pub mod fat; 14 | pub mod file; 15 | pub mod path; 16 | pub mod vfs; 17 | 18 | pub fn init(initramfs_virt_addr: VirtualAddress, kernel_config: &KernelConfig) -> Result<()> { 19 | vfs::init()?; 20 | kinfo!("fs: VFS initialized"); 21 | 22 | let fat_volume = FatVolume::new(initramfs_virt_addr); 23 | let fat_fs = Fat::new(fat_volume); 24 | 25 | vfs::mount_fs(&"/mnt/initramfs".into(), FileSystem::Fat(fat_fs))?; 26 | kinfo!("fs: Mounted initramfs to VFS"); 27 | 28 | let dirname = kernel_config.init_cwd_path.into(); 29 | vfs::chdir(&dirname)?; 30 | 31 | Ok(()) 32 | } 33 | -------------------------------------------------------------------------------- /kernel/src/sync/pin.rs: -------------------------------------------------------------------------------- 1 | use crate::error::{Error, Result}; 2 | use core::{pin::Pin, slice}; 3 | 4 | pub unsafe trait IntoPinnedMutableSlice: Sized + Copy + Clone { 5 | fn as_mut_slice(self: Pin<&mut Self>) -> Pin<&mut [u8]> { 6 | Pin::new(unsafe { 7 | slice::from_raw_parts_mut( 8 | self.get_unchecked_mut() as *mut Self as *mut u8, 9 | size_of::(), 10 | ) 11 | }) 12 | } 13 | 14 | fn as_mut_slice_sized(self: Pin<&mut Self>, size: usize) -> Result> { 15 | if size > size_of::() { 16 | Err(Error::Failed("Size exceeds the size of the type")) 17 | } else { 18 | Ok(Pin::new(unsafe { 19 | slice::from_raw_parts_mut(self.get_unchecked_mut() as *mut Self as *mut u8, size) 20 | })) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /kernel/src/util/cstring.rs: -------------------------------------------------------------------------------- 1 | use alloc::{ 2 | ffi::CString, 3 | slice, 4 | string::{String, ToString}, 5 | vec::Vec, 6 | }; 7 | 8 | pub unsafe fn from_cstring_ptr(s_ptr: *const u8) -> String { 9 | // check len 10 | let mut len = 0; 11 | let mut ptr = s_ptr; 12 | while *ptr != 0 { 13 | ptr = ptr.offset(1); 14 | len += 1; 15 | } 16 | 17 | let s_slice = slice::from_raw_parts(s_ptr, len); 18 | String::from_utf8_lossy(s_slice).to_string() 19 | } 20 | 21 | pub fn from_slice(s: &[u8]) -> String { 22 | let mut len = 0; 23 | 24 | while len < s.len() && s[len] != 0 { 25 | len += 1; 26 | } 27 | 28 | let s_slice = &s[..len]; 29 | String::from_utf8_lossy(s_slice).to_string() 30 | } 31 | 32 | pub fn into_cstring_bytes_with_nul(s: &str) -> Vec { 33 | assert!(!s.contains('\0')); 34 | CString::new(s).unwrap().into_bytes_with_nul() 35 | } 36 | -------------------------------------------------------------------------------- /kernel/src/util/range.rs: -------------------------------------------------------------------------------- 1 | use crate::error::{Error, Result}; 2 | use core::ops::RangeInclusive; 3 | 4 | pub fn map_value_range_inclusive( 5 | from: RangeInclusive, 6 | to: RangeInclusive, 7 | value: i64, 8 | ) -> Result { 9 | if !from.contains(&value) { 10 | return Err(Error::Failed("Value out of range")); 11 | } 12 | 13 | let from_left = (value - *from.start()) as i128; 14 | let from_width = (from.end() - from.start()) as i128; 15 | let to_width = (to.end() - to.start()) as i128; 16 | 17 | if from_width == 0 { 18 | Ok(*to.start()) 19 | } else { 20 | let to_left = from_left * to_width / from_width; 21 | to_left 22 | .try_into() 23 | .or(Err(Error::Failed( 24 | "Failed to convert to_left to the result type", 25 | ))) 26 | .map(|to_left: i64| to.start() + to_left) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/tsc.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | arch::x86_64::{self, acpi, cpu}, 3 | error::{Error, Result}, 4 | kdebug, 5 | }; 6 | 7 | fn is_available() -> bool { 8 | let info = cpu::version_info(); 9 | info.feature_tsc 10 | } 11 | 12 | fn calc_freq() -> Result { 13 | if !is_available() { 14 | return Err(Error::Failed("TSC not available")); 15 | } 16 | 17 | let start = x86_64::rdtsc(); 18 | acpi::pm_timer_wait_ms(1)?; 19 | let end = x86_64::rdtsc(); 20 | Ok((end - start) * 1000) 21 | } 22 | 23 | pub fn check_available() { 24 | let tsc_freq = calc_freq().unwrap(); 25 | kdebug!("tsc: Timer frequency: {}Hz (variant)", tsc_freq); 26 | } 27 | 28 | pub fn wait_ms(ms: u64) -> Result<()> { 29 | let current_tsc_freq = calc_freq()?; 30 | let start = x86_64::rdtsc(); 31 | let end = start + (current_tsc_freq / 1000) * ms; 32 | while x86_64::rdtsc() < end {} 33 | Ok(()) 34 | } 35 | -------------------------------------------------------------------------------- /common/src/mem_desc.rs: -------------------------------------------------------------------------------- 1 | pub const UEFI_PAGE_SIZE: usize = 0x1000; 2 | 3 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] 4 | pub enum MemoryType { 5 | Reserved, 6 | LoaderCode, 7 | LoaderData, 8 | BootServicesCode, 9 | BootServicesData, 10 | RuntimeServicesCode, 11 | RuntimeServicesData, 12 | Conventional, 13 | Unusable, 14 | AcpiReclaim, 15 | AcpiNonVolatile, 16 | Mmio, 17 | MmioPortSpace, 18 | PalCode, 19 | PersistentMemory, 20 | Other(u32), 21 | } 22 | 23 | impl MemoryType { 24 | pub fn is_available_memory(&self) -> bool { 25 | *self == Self::BootServicesCode 26 | || *self == Self::BootServicesData 27 | || *self == Self::Conventional 28 | } 29 | } 30 | 31 | #[derive(Debug, Copy, Clone)] 32 | pub struct MemoryDescriptor { 33 | pub ty: MemoryType, 34 | pub phys_start: u64, 35 | pub virt_start: u64, 36 | pub page_cnt: u64, 37 | pub attr: u64, 38 | } 39 | -------------------------------------------------------------------------------- /apps/ls/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static char cwdenames[1280] = {0}; 5 | 6 | int main(int argc, char* argv[]) { 7 | char* path; 8 | 9 | if (argc > 1) { 10 | path = argv[1]; 11 | } else { 12 | path = "."; 13 | } 14 | 15 | if (sys_getenames(path, cwdenames, sizeof(cwdenames)) == -1) { 16 | printf("ls: failed to get entry names\n"); 17 | return -1; 18 | } 19 | 20 | char old_c = '\0'; 21 | 22 | for (int i = 0; i < (int)sizeof(cwdenames); i++) { 23 | char c = cwdenames[i]; 24 | 25 | // end of name list 26 | if (old_c == '\0' && c == '\0' && i > 0) { 27 | break; 28 | } 29 | 30 | if (c == '\0') { 31 | printf(" "); 32 | } else { 33 | printf("%c", c); 34 | } 35 | 36 | old_c = cwdenames[i]; 37 | 38 | // clear 39 | cwdenames[i] = '\0'; 40 | } 41 | printf("\n"); 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /kernel/src/fs/exec.rs: -------------------------------------------------------------------------------- 1 | use super::{path::Path, vfs}; 2 | use crate::{debug::dwarf, error::Result, kerror, kinfo, task}; 3 | use common::elf::Elf64; 4 | 5 | pub fn exec_elf(elf_path: &Path, args: &[&str], enable_debug: bool) -> Result<()> { 6 | let fd_num = vfs::open_file(elf_path, false)?; 7 | let elf_data = vfs::read_file(fd_num)?; 8 | let elf64 = match Elf64::new(&elf_data) { 9 | Ok(e) => e, 10 | Err(err) => return Err(err.into()), 11 | }; 12 | 13 | vfs::close_file(fd_num)?; 14 | 15 | let dwarf = if enable_debug { 16 | match dwarf::parse(&elf64) { 17 | Ok(d) => Some(d), 18 | Err(err) => { 19 | kerror!("exec: Failed to parse DWARF: {:?}", err); 20 | None 21 | } 22 | } 23 | } else { 24 | None 25 | }; 26 | 27 | let exit_code = task::scheduler::exec_user_task(elf64, elf_path, args, dwarf)?; 28 | kinfo!("exec: Exited (code: {})", exit_code); 29 | 30 | Ok(()) 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2022 Zakki 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. 8 | -------------------------------------------------------------------------------- /kernel/src/util/bits.rs: -------------------------------------------------------------------------------- 1 | use core::cmp::min; 2 | 3 | pub fn extract_bits(value: T, shift: usize, width: usize) -> T 4 | where 5 | T: TryFrom + From, 6 | u64: TryInto + From, 7 | { 8 | let mask = (1u64 << min(63, width)) - 1; 9 | let value = u64::from(value); 10 | let value = value.checked_shr(shift as u32).unwrap_or(0) & mask; 11 | TryInto::try_into(value).unwrap_or_else(|_| T::from(0u8)) 12 | } 13 | 14 | pub fn extract_bits_from_le_bytes(bytes: &[u8], shift: usize, width: usize) -> Option { 15 | if width == 0 { 16 | return None; 17 | } 18 | 19 | let byte_range = (shift / 8)..((shift + width + 7) / 8); 20 | let mut value = 0u64; 21 | let bit_shift = shift - byte_range.start * 8; 22 | bytes.get(byte_range).map(|bytes_in_range| { 23 | for (i, v) in bytes_in_range.iter().enumerate() { 24 | let v = *v as u128; 25 | value |= ((v << (i * 8)) >> bit_shift) as u64; 26 | } 27 | 28 | extract_bits(value, 0, width) 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /apps/libc/string.h: -------------------------------------------------------------------------------- 1 | #ifndef _STRING_H 2 | #define _STRING_H 3 | 4 | #include 5 | 6 | extern int strcmp(const char* s1, const char* s2); 7 | extern size_t strlen(const char* str); 8 | extern int split(char* str, const char regex, char** buf, size_t buflen); 9 | extern char* concatenate(const char* strs[], int len, const char* delimiter); 10 | extern void replace(char* src, const char target, const char replace); 11 | extern int is_ascii(const char c); 12 | extern void* memcpy(void* dest, const void* src, size_t len); 13 | extern void* memset(void* dest, int val, size_t len); 14 | extern void* memmove(void* dest, const void* src, size_t len); 15 | extern int strcasecmp(const char* s1, const char* s2); 16 | extern int strncasecmp(const char* s1, const char* s2, size_t n); 17 | extern char* strchr(const char* s1, int i); 18 | extern char* strrchr(const char* s, int i); 19 | extern int strncmp(const char* s1, const char* s2, size_t n); 20 | extern char* strncpy(char* dst, const char* src, size_t n); 21 | extern char* strdup(const char* s); 22 | extern char* strstr(const char* s1, const char* s2); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /kernel/src/sync/volatile.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | mem::MaybeUninit, 3 | ptr::{read_volatile, write_volatile}, 4 | }; 5 | 6 | #[repr(transparent)] 7 | #[derive(Debug)] 8 | pub struct Volatile(T); 9 | 10 | impl Default for Volatile { 11 | fn default() -> Self { 12 | Self(T::default()) 13 | } 14 | } 15 | 16 | impl Clone for Volatile { 17 | fn clone(&self) -> Self { 18 | let this = MaybeUninit::uninit(); 19 | let mut this: Self = unsafe { this.assume_init() }; 20 | this.write(self.read()); 21 | this 22 | } 23 | } 24 | 25 | impl Volatile { 26 | pub fn read(&self) -> T { 27 | unsafe { read_volatile(&self.0) } 28 | } 29 | 30 | pub fn write(&mut self, value: T) { 31 | unsafe { write_volatile(&mut self.0, value) } 32 | } 33 | } 34 | 35 | #[test_case] 36 | fn read_write() { 37 | let mut v: Volatile = Volatile::default(); 38 | assert_eq!(v.read(), 0); 39 | v.write(0x1234); 40 | assert_eq!(v.read(), 0x1234); 41 | v.write(0x5678); 42 | assert_eq!(v.read(), 0x5678); 43 | } 44 | -------------------------------------------------------------------------------- /kernel/src/env.rs: -------------------------------------------------------------------------------- 1 | use crate::println; 2 | 3 | pub const OS_NAME: &str = "myos"; 4 | pub const ENV_AUTHORS: &str = env!("CARGO_PKG_AUTHORS"); 5 | pub const ENV_DESCRIPTION: &str = env!("CARGO_PKG_DESCRIPTION"); 6 | pub const ENV_VERSION: &str = env!("CARGO_PKG_VERSION"); 7 | 8 | pub const ASCII_ART: &str = 9 | " ___ __ __ _ _ \n / _ \\ / / / / | || | \n _ __ ___ _ _ ___ ___ ______ __ __| (_) | / /_ / /_ | || |_ \n | '_ ` _ \\ | | | | / _ \\ / __||______|\\ \\/ / > _ < | '_ \\ | '_ \\|__ _|\n | | | | | || |_| || (_) |\\__ \\ > < | (_) || (_) || (_) | | | \n |_| |_| |_| \\__, | \\___/ |___/ /_/\\_\\ \\___/ \\___/ \\___/ |_| \n __/ | ______ \n |___/ |______| "; 10 | 11 | pub fn print_info() { 12 | println!("{}", ASCII_ART); 13 | println!("{}", OS_NAME); 14 | println!("Version: {}", ENV_VERSION); 15 | println!("Authors: {}", ENV_AUTHORS); 16 | println!("Description: {}", ENV_DESCRIPTION); 17 | } 18 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Kernel debug", 6 | "type": "cppdbg", 7 | "request": "launch", 8 | "miDebuggerServerAddress": "localhost:3333", 9 | "miDebuggerArgs": "${workspaceFolder}/build/kernel.elf", 10 | "miDebuggerPath": "rust-gdb", 11 | "program": "${workspaceFolder}/build/kernel.elf", 12 | "stopAtEntry": false, 13 | "cwd": "${workspaceFolder}", 14 | "environment": [], 15 | "externalConsole": true, 16 | "MIMode": "gdb", 17 | "setupCommands": [ 18 | { 19 | "description": "Enable pretty-printing for gdb", 20 | "text": "-enable-pretty-printing", 21 | "ignoreFailures": true 22 | }, 23 | { 24 | "text": "break kernel_entry" 25 | } 26 | ], 27 | "logging": { 28 | "engineLogging": true, 29 | "trace": true, 30 | "traceResponse": true 31 | } 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /apps/libc/stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDIO_H 2 | #define _STDIO_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "stat.h" 9 | 10 | #define SEEK_SET 0 11 | #define SEEK_CUR 1 12 | #define SEEK_END 2 13 | 14 | #define EOF (-1) 15 | 16 | typedef struct 17 | { 18 | int fd; 19 | f_stat* stat; 20 | char* buf; 21 | long int pos; 22 | } FILE; 23 | 24 | // printf.c 25 | extern int printf(const char* fmt, ...); 26 | 27 | extern void exit(int status); 28 | extern int fprintf(FILE* stream, const char* fmt, ...); 29 | extern int snprintf(char* buf, size_t size, const char* format, ...); 30 | extern FILE* fopen(const char* filepath, const char* mode); 31 | extern int fclose(FILE* stream); 32 | extern long int ftell(FILE* stream); 33 | extern int fflush(FILE* __stream); 34 | extern int puts(const char* c); 35 | extern int putchar(int c); 36 | extern char getchar(void); 37 | extern int vfprintf(FILE* stream, const char* fmt, va_list ap); 38 | extern int sscanf(const char* buf, const char* fmt, ...); 39 | extern size_t fread(void* buf, size_t size, size_t count, FILE* stream); 40 | extern int fseek(FILE* stream, long int offset, int whence); 41 | extern size_t fwrite(const void* buf, size_t size, size_t count, FILE* stream); 42 | extern int vsnprintf(char* buf, size_t bufsize, const char* format, va_list arg); 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /apps/libc/iomsg.h: -------------------------------------------------------------------------------- 1 | #ifndef _IOMSG_H 2 | #define _IOMSG_H 3 | 4 | #include 5 | #include 6 | 7 | #define IOMSG_CMD_REMOVE_COMPONENT 0x80000000 8 | #define IOMSG_CMD_CREATE_COMPONENT_WINDOW 0x80000001 9 | #define IOMSG_CMD_CREATE_COMPONENT_IMAGE 0x80000002 10 | 11 | typedef struct { 12 | uint32_t cmd_id; 13 | uint32_t payload_size; 14 | } iomsg_header; 15 | 16 | typedef struct { 17 | iomsg_header header; 18 | } __attribute__((aligned(8))) _iomsg_with_header_only; 19 | 20 | typedef struct { 21 | iomsg_header header; 22 | int layer_id; 23 | } __attribute__((aligned(8))) _iomsg_with_layer_id; 24 | 25 | typedef _iomsg_with_layer_id iomsg_remove_component; 26 | typedef _iomsg_with_header_only iomsg_reply_remove_component; 27 | 28 | typedef struct { 29 | iomsg_header header; 30 | size_t x_pos; 31 | size_t y_pos; 32 | size_t width; 33 | size_t height; 34 | char title[]; 35 | } __attribute__((aligned(8))) iomsg_create_component_window; 36 | typedef _iomsg_with_layer_id iomsg_reply_create_component; 37 | 38 | typedef struct { 39 | iomsg_header header; 40 | int layer_id; 41 | char _reserved0[4]; 42 | size_t image_width; 43 | size_t image_height; 44 | uint8_t pixel_format; 45 | char _reserved1[7]; 46 | const void* framebuf; 47 | } __attribute__((aligned(8))) iomsg_create_component_image; 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /common/src/graphic_info.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 2 | #[repr(u8)] 3 | pub enum PixelFormat { 4 | Rgb = 0, 5 | Bgr = 1, 6 | Bgra = 2, 7 | } 8 | 9 | impl From for PixelFormat { 10 | fn from(value: u8) -> Self { 11 | match value { 12 | 0 => Self::Rgb, 13 | 1 => Self::Bgr, 14 | 2 => Self::Bgra, 15 | _ => panic!("Invalid pixel format"), 16 | } 17 | } 18 | } 19 | 20 | #[derive(Debug, Clone, Copy)] 21 | #[repr(C)] 22 | pub struct GraphicInfo { 23 | pub resolution: (usize, usize), 24 | pub format: PixelFormat, 25 | pub stride: usize, 26 | pub framebuf_addr: u64, 27 | pub framebuf_size: usize, 28 | } 29 | 30 | impl GraphicInfo { 31 | pub fn fill_screen(&self, r: u8, g: u8, b: u8) { 32 | let (w, h) = self.resolution; 33 | let framebuf_slice = unsafe { 34 | core::slice::from_raw_parts_mut(self.framebuf_addr as *mut u32, h * self.stride) 35 | }; 36 | 37 | let pixel = match self.format { 38 | PixelFormat::Rgb => ((b as u32) << 16) | ((g as u32) << 8) | (r as u32), 39 | PixelFormat::Bgr => ((r as u32) << 16) | ((g as u32) << 8) | (b as u32), 40 | _ => panic!("Unsupported pixel format"), 41 | }; 42 | 43 | for y in 0..h { 44 | for x in 0..w { 45 | framebuf_slice[y * self.stride + x] = pixel; 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /kernel/src/device/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::error::Result; 2 | use alloc::vec::Vec; 3 | 4 | pub mod local_apic_timer; 5 | pub mod panic_screen; 6 | pub mod pci_bus; 7 | pub mod ps2_keyboard; 8 | pub mod ps2_mouse; 9 | pub mod rtl8139; 10 | pub mod speaker; 11 | pub mod tty; 12 | pub mod uart; 13 | pub mod urandom; 14 | pub mod usb; 15 | pub mod zakki; 16 | 17 | #[derive(Debug, Clone)] 18 | pub struct DeviceDriverInfo { 19 | pub name: &'static str, 20 | pub attached: bool, 21 | } 22 | 23 | impl DeviceDriverInfo { 24 | pub const fn new(name: &'static str) -> Self { 25 | Self { 26 | name, 27 | attached: false, 28 | } 29 | } 30 | } 31 | 32 | pub trait DeviceDriverFunction { 33 | type AttachInput; 34 | type PollNormalOutput; 35 | type PollInterruptOutput; 36 | 37 | fn get_device_driver_info(&self) -> Result; 38 | // check and find device 39 | fn probe(&mut self) -> Result<()>; 40 | // initialize device 41 | fn attach(&mut self, arg: Self::AttachInput) -> Result<()>; 42 | // normal polling 43 | fn poll_normal(&mut self) -> Result; 44 | // interrupt polling 45 | fn poll_int(&mut self) -> Result; 46 | // open device 47 | fn open(&mut self) -> Result<()>; 48 | // close device 49 | fn close(&mut self) -> Result<()>; 50 | // read data from device 51 | fn read(&mut self) -> Result>; 52 | // write data to device 53 | fn write(&mut self, data: &[u8]) -> Result<()>; 54 | } 55 | -------------------------------------------------------------------------------- /kernel/src/graphics/mod.rs: -------------------------------------------------------------------------------- 1 | use self::color::ColorCode; 2 | use crate::{error::Result, kinfo}; 3 | use alloc::string::String; 4 | use common::graphic_info::GraphicInfo; 5 | 6 | pub mod color; 7 | pub mod draw; 8 | pub mod font; 9 | pub mod frame_buf; 10 | pub mod frame_buf_console; 11 | pub mod multi_layer; 12 | pub mod simple_window_manager; 13 | 14 | pub fn init( 15 | graphic_info: &GraphicInfo, 16 | console_back_color: ColorCode, 17 | console_fore_color: ColorCode, 18 | ) -> Result<()> { 19 | frame_buf::init(graphic_info)?; 20 | frame_buf_console::init(console_back_color, console_fore_color)?; 21 | 22 | kinfo!("graphics: Frame buffer initialized"); 23 | Ok(()) 24 | } 25 | 26 | pub fn enable_shadow_buf() -> Result<()> { 27 | frame_buf::enable_shadow_buf()?; 28 | 29 | kinfo!("graphics: Shadow buffer enabled"); 30 | Ok(()) 31 | } 32 | 33 | pub fn init_layer_man(graphic_info: &GraphicInfo) -> Result<()> { 34 | let (res_x, res_y) = graphic_info.resolution; 35 | let console_layer = multi_layer::create_layer((0, 0), (res_x, res_y - 30))?; 36 | let console_layer_id = console_layer.id; 37 | 38 | multi_layer::push_layer(console_layer)?; 39 | frame_buf_console::set_target_layer_id(console_layer_id)?; 40 | 41 | kinfo!("graphics: Layer manager initialized"); 42 | Ok(()) 43 | } 44 | 45 | pub fn init_simple_wm(mouse_pointer_bmp_path: String) -> Result<()> { 46 | simple_window_manager::init(mouse_pointer_bmp_path)?; 47 | simple_window_manager::create_taskbar()?; 48 | 49 | kinfo!("graphics: Simple window manager initialized"); 50 | Ok(()) 51 | } 52 | -------------------------------------------------------------------------------- /apps/libc/stdlib.c: -------------------------------------------------------------------------------- 1 | #include "stdlib.h" 2 | 3 | #include 4 | 5 | #include "stdio.h" // for printf 6 | #include "string.h" 7 | #include "syscalls.h" 8 | 9 | int abs(int i) { 10 | return i < 0 ? -i : i; 11 | } 12 | 13 | void* malloc(size_t len) { 14 | return sys_sbrk(len); 15 | } 16 | 17 | int atoi(const char* str) { 18 | printf("[DEBUG]atoi called\n"); 19 | return -1; 20 | } 21 | 22 | double atof(const char* nptr) { 23 | printf("[DEBUG]atof called\n"); 24 | return -1.0; 25 | } 26 | 27 | void free(void* ptr) { 28 | printf("[DEBUG]free called\n"); 29 | } 30 | 31 | void* calloc(size_t count, size_t size) { 32 | // printf("[DEBUG]calloc called\n"); 33 | void* ptr = malloc(count * size); 34 | if (ptr == NULL) 35 | return NULL; 36 | 37 | memset(ptr, 0, count * size); 38 | return ptr; 39 | } 40 | 41 | void* realloc(void* ptr, size_t size) { 42 | // printf("[DEBUG]realloc called\n"); 43 | if (ptr == NULL) { 44 | return malloc(size); 45 | } 46 | 47 | size_t old_size = sys_sbrksz(ptr); 48 | if (old_size == 0) 49 | return NULL; 50 | 51 | void* new_ptr = malloc(size); 52 | if (new_ptr == NULL) 53 | return NULL; 54 | 55 | memcpy(new_ptr, ptr, old_size > size ? size : old_size); 56 | free(ptr); 57 | return new_ptr; 58 | } 59 | 60 | int system(const char* command) { 61 | printf("[DEBUG]system called (command: %s)\n", command); 62 | return -1; 63 | } 64 | 65 | int remove(const char* filepath) { 66 | printf("[DEBUG]remove called\n"); 67 | return -1; 68 | } 69 | 70 | int rename(const char* old, const char* _new) { 71 | printf("[DEBUG]rename called\n"); 72 | return -1; 73 | } 74 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/registers/msi.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Copy, Default)] 2 | #[repr(transparent)] 3 | pub struct MsiMessageAddressField(u32); 4 | 5 | impl MsiMessageAddressField { 6 | pub fn new(dest_mode: bool, redirection_hint_indication: bool, dest_id: u8) -> Self { 7 | let mut field; 8 | 9 | field = (dest_mode as u32) << 2; 10 | field = (field & !0x8) | ((redirection_hint_indication as u32) << 3); 11 | field = (field & !0xf_f000) | ((dest_id as u32) << 12); 12 | field = (field & !0xfff0_0000) | (0xfee << 20); 13 | 14 | Self(field) 15 | } 16 | } 17 | 18 | #[derive(Debug, Clone, Copy)] 19 | #[repr(u8)] 20 | pub enum DeliveryMode { 21 | Fixed = 0, 22 | LowestPriority = 1, 23 | Smi = 2, 24 | Nmi = 4, 25 | Init = 5, 26 | ExtInt = 7, 27 | } 28 | 29 | #[derive(Debug, Clone, Copy)] 30 | #[repr(u8)] 31 | pub enum Level { 32 | Deassert = 0, 33 | Assert = 1, 34 | } 35 | 36 | #[derive(Debug, Clone, Copy)] 37 | #[repr(u8)] 38 | pub enum TriggerMode { 39 | Edge = 0, 40 | Level = 1, 41 | } 42 | 43 | #[derive(Debug, Clone, Copy, Default)] 44 | #[repr(transparent)] 45 | pub struct MsiMessageDataField(u32); 46 | 47 | impl MsiMessageDataField { 48 | pub fn new( 49 | vector: u8, 50 | delivery_mode: DeliveryMode, 51 | level: Level, 52 | trigger_mode: TriggerMode, 53 | ) -> Self { 54 | let mut field; 55 | 56 | field = vector as u32; 57 | field = (field & !0x700) | ((delivery_mode as u32) << 8); 58 | field = (field & !0x4000) | ((level as u32) << 11); 59 | field = (field & !0x8000) | ((trigger_mode as u32) << 12); 60 | 61 | Self(field) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /apps/hexdump/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char* argv[]) { 5 | if (argc < 2) { 6 | return 0; 7 | } 8 | 9 | FILE* file = fopen(argv[1], "r"); 10 | if (file == NULL) { 11 | printf("hexdump: failed to open the file\n"); 12 | return -1; 13 | } 14 | 15 | size_t file_size = file->stat->size; 16 | 17 | char* f_buf = (char*)malloc(file_size); 18 | if (f_buf == NULL) { 19 | printf("hexdump: failed to allocate memory\n"); 20 | fclose(file); 21 | return -1; 22 | } 23 | 24 | fread(f_buf, 1, file_size, file); 25 | fclose(file); 26 | 27 | for (int i = 0; i < ((int)file_size + 15) / 16; i++) { 28 | int j = i * 16; 29 | int j_end = j + 16; 30 | 31 | if (j_end > (int)file_size) { 32 | j_end = (int)file_size; 33 | } 34 | 35 | printf("%08x ", i * 16); 36 | 37 | for (; j < j_end; j++) { 38 | if (j % 2 == 0) { 39 | printf(" "); 40 | } 41 | 42 | printf("%02x ", f_buf[j]); 43 | } 44 | 45 | if (j_end < 16) { 46 | for (int k = 0; k < 16 - j_end; k++) { 47 | printf(" "); 48 | } 49 | printf(" "); 50 | } 51 | 52 | printf(" |"); 53 | for (int j = i * 16; j < j_end; j++) { 54 | // printable characters 55 | if (f_buf[j] >= 0x20 && f_buf[j] <= 0x7e) { 56 | printf("%c", f_buf[j]); 57 | } else { 58 | printf("."); 59 | } 60 | } 61 | printf("|\n"); 62 | } 63 | 64 | printf("\n"); 65 | free(f_buf); 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /apps/test/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int test_udp() { 7 | int sockfd = sys_socket(SOCKET_DOMAIN_AF_INET, SOCKET_TYPE_SOCK_DGRAM, SOCKET_PROTO_UDP); 8 | if (sockfd < 0) { 9 | printf("Failed to create socket\n"); 10 | return -1; 11 | } 12 | 13 | struct sockaddr_in addr; 14 | memset(&addr, 0, sizeof(addr)); 15 | addr.sin_family = SOCKET_DOMAIN_AF_INET; 16 | addr.sin_port = 0; // auto-assign 17 | addr.sin_addr.s_addr = 0; 18 | 19 | if (sys_bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { 20 | printf("Failed to bind socket\n"); 21 | return -1; 22 | } 23 | 24 | // test data 25 | const char* test_msg = "Hello from myos UDP socket!"; 26 | 27 | struct sockaddr_in dest_addr; 28 | memset(&dest_addr, 0, sizeof(dest_addr)); 29 | dest_addr.sin_family = SOCKET_DOMAIN_AF_INET; 30 | dest_addr.sin_port = 1234; 31 | dest_addr.sin_addr.s_addr = (192 << 24) | (168 << 16) | (100 << 8) | 1; 32 | 33 | int ret = sys_sendto(sockfd, test_msg, strlen(test_msg) + 1, 0, 34 | (struct sockaddr*)&dest_addr, sizeof(dest_addr)); 35 | if (ret < 0) { 36 | printf("Failed to sendto\n"); 37 | return -1; 38 | } 39 | 40 | char recv_buf[256]; 41 | memset(recv_buf, 0, sizeof(recv_buf)); 42 | struct sockaddr_in src_addr; 43 | memset(&src_addr, 0, sizeof(src_addr)); 44 | int recv_len = 0; 45 | // wait 46 | while (recv_len <= 0) { 47 | recv_len = sys_recvfrom(sockfd, recv_buf, sizeof(recv_buf), 0, 48 | (struct sockaddr*)&src_addr, sizeof(src_addr)); 49 | } 50 | printf("Received %d bytes from host: %s\n", recv_len, recv_buf); 51 | 52 | return 0; 53 | } 54 | 55 | int main(int argc, const char* argv[]) { 56 | return test_udp(); 57 | } 58 | -------------------------------------------------------------------------------- /kernel/src/mem/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | error::Result, 3 | kinfo, 4 | mem::paging::{EntryMode, PageWriteThroughLevel, ReadWrite, PAGE_SIZE}, 5 | println, 6 | }; 7 | use common::mem_desc::MemoryDescriptor; 8 | 9 | pub mod allocator; 10 | pub mod bitmap; 11 | pub mod paging; 12 | 13 | pub fn init(mem_map: &[MemoryDescriptor]) -> Result<()> { 14 | bitmap::init(mem_map)?; 15 | kinfo!("mem: Bitmap memory manager initialized"); 16 | 17 | let start = PAGE_SIZE as u64; 18 | let end = bitmap::get_total_mem_size()? as u64; 19 | 20 | paging::create_new_page_table( 21 | start.into(), 22 | end.into(), 23 | start.into(), 24 | ReadWrite::Write, 25 | EntryMode::Supervisor, 26 | PageWriteThroughLevel::WriteBack, 27 | )?; 28 | 29 | allocator::init_heap()?; 30 | kinfo!("mem: Heap allocator initialized"); 31 | 32 | Ok(()) 33 | } 34 | 35 | pub fn free() { 36 | fn format_size(size: usize) -> (f64, &'static str) { 37 | const KIB: usize = 1024; 38 | const MIB: usize = 1024 * KIB; 39 | const GIB: usize = 1024 * MIB; 40 | 41 | if size >= GIB { 42 | (size as f64 / GIB as f64, "GiB") 43 | } else if size >= MIB { 44 | (size as f64 / MIB as f64, "MiB") 45 | } else if size >= KIB { 46 | (size as f64 / KIB as f64, "KiB") 47 | } else { 48 | (size as f64, "B") 49 | } 50 | } 51 | 52 | let (used, max) = bitmap::get_mem_size().unwrap_or((0, 0)); 53 | let (used_value, used_unit) = format_size(used); 54 | let (max_value, max_unit) = format_size(max); 55 | 56 | println!( 57 | "Memory used: {:.2}{}({}B) / {:.2}{}({}B) ({:.2}%)", 58 | used_value, 59 | used_unit, 60 | used, 61 | max_value, 62 | max_unit, 63 | max, 64 | (used as f64 / max as f64) * 100f64 65 | ); 66 | } 67 | -------------------------------------------------------------------------------- /apps/uname/uname.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, const char* argv[]) { 8 | utsname* buf = (utsname*)malloc(sizeof(utsname)); 9 | if (buf == NULL) { 10 | return -1; 11 | } 12 | 13 | sys_uname(buf); 14 | 15 | if (argc == 1) { 16 | printf("%s", buf->sysname); 17 | return 0; 18 | } 19 | 20 | if (strcmp(argv[1], "--help") == 0) { 21 | printf("Usage: uname [OPTION]...\n"); 22 | printf("Print certain system information. With no OPTION, same as -s.\n\n"); 23 | printf(" -a\tprint all information\n"); 24 | printf(" -s\tprint the kernel name\n"); 25 | printf(" -n\tprint the network node hostname\n"); 26 | printf(" -r\tprint the kernel release\n"); 27 | printf(" -v\tprint the kernel version\n"); 28 | printf(" -m\tprint the machine hardware name\n"); 29 | printf(" -d\tprint the domain name\n"); 30 | return 0; 31 | } 32 | 33 | for (int i = 1; i < argc; i++) { 34 | if (strcmp(argv[i], "-a") == 0) { 35 | printf("%s %s %s %s %s %s", buf->sysname, buf->nodename, buf->release, buf->version, buf->machine, buf->domainname); 36 | return 0; 37 | } 38 | } 39 | 40 | for (int i = 1; i < argc; i++) { 41 | if (strcmp(argv[i], "-s") == 0) { 42 | printf("%s ", buf->sysname); 43 | } else if (strcmp(argv[i], "-n") == 0) { 44 | printf("%s ", buf->nodename); 45 | } else if (strcmp(argv[i], "-r") == 0) { 46 | printf("%s ", buf->release); 47 | } else if (strcmp(argv[i], "-v") == 0) { 48 | printf("%s ", buf->version); 49 | } else if (strcmp(argv[i], "-m") == 0) { 50 | printf("%s ", buf->machine); 51 | } else if (strcmp(argv[i], "-d") == 0) { 52 | printf("%s ", buf->domainname); 53 | } 54 | } 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /apps/libc-rs/build.rs: -------------------------------------------------------------------------------- 1 | use std::{fs, path::PathBuf, process::Command}; 2 | 3 | fn find_headers_recursively(dir: PathBuf) -> Vec { 4 | let mut headers = Vec::new(); 5 | 6 | for entry in fs::read_dir(&dir).expect("Failed to read directory") { 7 | let entry = entry.expect("Failed to read directory entry"); 8 | let path = entry.path(); 9 | 10 | if path.is_dir() { 11 | headers.extend(find_headers_recursively(path)); 12 | } else if let Some(ext) = path.extension() { 13 | if ext == "h" { 14 | headers.push(path); 15 | } 16 | } 17 | } 18 | 19 | headers 20 | } 21 | 22 | fn main() { 23 | let is_for_kernel = std::env::var("CARGO_FEATURE_KERNEL").is_ok(); 24 | 25 | let out_dir = std::env::var("OUT_DIR").unwrap(); 26 | let out_path = std::path::PathBuf::from(out_dir); 27 | 28 | let libc_path = PathBuf::from("../libc"); 29 | 30 | println!( 31 | "cargo:rerun-if-changed={}", 32 | libc_path.join("Makefile").display() 33 | ); 34 | 35 | let headers = find_headers_recursively(libc_path.clone()); 36 | if headers.is_empty() { 37 | Command::new("make") 38 | .arg("-C") 39 | .arg("../libc") 40 | .status() 41 | .expect("Failed to run make"); 42 | } 43 | 44 | let libc_abs_path = libc_path 45 | .canonicalize() 46 | .expect("Failed to get absolute path"); 47 | println!("cargo:rustc-link-search={}", libc_abs_path.display()); 48 | if !is_for_kernel { 49 | println!("cargo:rustc-link-lib=static=c_with_main"); 50 | } 51 | 52 | let headers = find_headers_recursively(libc_path); 53 | let mut builder = bindgen::Builder::default(); 54 | 55 | for header in headers { 56 | println!("cargo:rerun-if-changed={}", header.display()); 57 | builder = builder.header(header.to_str().unwrap()); 58 | } 59 | 60 | let bindings = builder 61 | .use_core() 62 | .generate() 63 | .expect("Failed to generate bindings"); 64 | bindings 65 | .write_to_file(out_path.join("bindings.rs")) 66 | .expect("Failed to write bindings"); 67 | } 68 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/tss.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | error::Result, 3 | mem::{self, paging::PAGE_SIZE}, 4 | }; 5 | use core::mem::size_of; 6 | 7 | static mut TSS: TaskStateSegment = TaskStateSegment::new(); 8 | 9 | #[derive(Debug, Clone, Copy)] 10 | #[repr(packed)] 11 | pub struct TaskStateSegmentDescriptor { 12 | limit_low: u16, 13 | base_low: u16, 14 | base_mid_low: u8, 15 | attr: u16, 16 | base_mid_high: u8, 17 | base_high: u32, 18 | _reserved: u32, 19 | } 20 | 21 | impl TaskStateSegmentDescriptor { 22 | pub const fn new() -> Self { 23 | Self { 24 | limit_low: 0, 25 | base_low: 0, 26 | base_mid_low: 0, 27 | attr: 0, 28 | base_mid_high: 0, 29 | base_high: 0, 30 | _reserved: 0, 31 | } 32 | } 33 | 34 | pub fn set(&mut self, base: u64) { 35 | self.set_base(base); 36 | self.limit_low = size_of::() as u16 - 1; 37 | self.attr = 0b1000_0000_1000_1001; 38 | } 39 | 40 | pub fn set_base(&mut self, base: u64) { 41 | self.base_low = base as u16; 42 | self.base_mid_low = (base >> 16) as u8; 43 | self.base_mid_high = (base >> 24) as u8; 44 | self.base_high = (base >> 32) as u32; 45 | } 46 | } 47 | 48 | #[repr(packed)] 49 | struct TaskStateSegment { 50 | reserved0: u32, 51 | rsp: [u64; 3], 52 | ist: [u64; 8], 53 | reserved1: [u16; 5], 54 | io_map_base_addr: u16, 55 | } 56 | 57 | impl TaskStateSegment { 58 | pub const fn new() -> Self { 59 | Self { 60 | reserved0: 0, 61 | rsp: [0; 3], 62 | ist: [0; 8], 63 | reserved1: [0; 5], 64 | io_map_base_addr: 0, 65 | } 66 | } 67 | 68 | pub fn init(&mut self) -> Result<()> { 69 | let frame_len = 8; 70 | 71 | let rsp0 = mem::bitmap::alloc_mem_frame(frame_len)? 72 | .frame_start_virt_addr()? 73 | .offset(frame_len * PAGE_SIZE) 74 | .get(); 75 | self.rsp[0] = rsp0; 76 | 77 | Ok(()) 78 | } 79 | } 80 | 81 | // return tss addr 82 | pub fn init() -> Result { 83 | unsafe { 84 | TSS.init()?; 85 | Ok((&TSS as *const _) as u64) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /kernel/src/graphics/color.rs: -------------------------------------------------------------------------------- 1 | use common::graphic_info::PixelFormat; 2 | 3 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 4 | #[repr(C)] 5 | pub struct ColorCode { 6 | pub r: u8, 7 | pub g: u8, 8 | pub b: u8, 9 | pub a: u8, 10 | } 11 | 12 | impl ColorCode { 13 | pub const BLACK: Self = Self::new_rgb(0, 0, 0); 14 | pub const RED: Self = Self::new_rgb(255, 0, 0); 15 | pub const GREEN: Self = Self::new_rgb(0, 255, 0); 16 | pub const YELLOW: Self = Self::new_rgb(255, 255, 0); 17 | pub const BLUE: Self = Self::new_rgb(0, 0, 255); 18 | pub const MAGENTA: Self = Self::new_rgb(255, 0, 255); 19 | pub const CYAN: Self = Self::new_rgb(0, 255, 255); 20 | pub const WHITE: Self = Self::new_rgb(255, 255, 255); 21 | 22 | pub const fn default() -> Self { 23 | Self { 24 | r: 0, 25 | g: 0, 26 | b: 0, 27 | a: 0, 28 | } 29 | } 30 | 31 | pub const fn new_rgb(r: u8, g: u8, b: u8) -> Self { 32 | Self { r, g, b, a: 0 } 33 | } 34 | 35 | pub const fn new_rgba(r: u8, g: u8, b: u8, a: u8) -> Self { 36 | Self { r, g, b, a } 37 | } 38 | 39 | pub fn from_pixel_data(data: &[u8], pixel_format: PixelFormat) -> Self { 40 | match pixel_format { 41 | PixelFormat::Bgr => Self { 42 | r: data[2], 43 | g: data[1], 44 | b: data[0], 45 | a: 0, 46 | }, 47 | PixelFormat::Rgb => Self { 48 | r: data[0], 49 | g: data[1], 50 | b: data[2], 51 | a: 0, 52 | }, 53 | PixelFormat::Bgra => Self { 54 | r: data[2], 55 | g: data[1], 56 | b: data[0], 57 | a: data[3], 58 | }, 59 | } 60 | } 61 | 62 | pub fn to_color_code(&self, pixel_format: PixelFormat) -> u32 { 63 | match pixel_format { 64 | PixelFormat::Bgr => (self.r as u32) << 16 | (self.g as u32) << 8 | (self.b as u32) << 0, 65 | PixelFormat::Rgb => (self.r as u32) << 0 | (self.g as u32) << 8 | (self.b as u32) << 16, 66 | PixelFormat::Bgra => { 67 | (self.r as u32) << 16 68 | | (self.g as u32) << 8 69 | | (self.b as u32) << 0 70 | | (self.a as u32) << 24 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /apps/libc/syscalls.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYSCALLS_H 2 | #define _SYSCALLS_H 3 | 4 | #include 5 | #include 6 | 7 | #include "iomsg.h" 8 | #include "stat.h" 9 | #include "sys/socket.h" 10 | #include "utsname.h" 11 | 12 | // syscall numbers 13 | #define SN_READ 0 14 | #define SN_WRITE 1 15 | #define SN_OPEN 2 16 | #define SN_CLOSE 3 17 | #define SN_EXIT 4 18 | #define SN_SBRK 5 19 | #define SN_UNAME 6 20 | #define SN_BREAK 7 21 | #define SN_STAT 8 22 | #define SN_UPTIME 9 23 | #define SN_EXEC 10 24 | #define SN_GETCWD 11 25 | #define SN_CHDIR 12 26 | // 13 27 | // 14 28 | #define SN_SBRKSZ 15 29 | // 16 30 | #define SN_GETENAMES 17 31 | #define SN_IOMSG 18 32 | #define SN_SOCKET 19 33 | #define SN_BIND 20 34 | #define SN_SENDTO 21 35 | #define SN_RECVFROM 22 36 | 37 | // defined file descriptor numbers 38 | #define FDN_STDIN 0 39 | #define FDN_STDOUT 1 40 | #define FDN_STDERR 2 41 | 42 | // sys_open flags 43 | #define OPEN_FLAG_NONE 0x0 44 | #define OPEN_FLAG_CREATE 0x1 45 | 46 | // sys_exec flags 47 | #define EXEC_FLAG_NONE 0x0 48 | #define EXEC_FLAG_DEBUG 0x1 49 | 50 | // sys_socket args 51 | #define SOCKET_DOMAIN_AF_INET 1 52 | #define SOCKET_TYPE_SOCK_DGRAM 1 53 | #define SOCKET_TYPE_SOCK_STREAM 2 54 | #define SOCKET_PROTO_UDP 17 55 | 56 | extern int sys_read(int fd, void* buf, size_t buf_len); 57 | extern int sys_write(int fd, const void* buf, size_t buf_len); 58 | extern int sys_open(const char* filepath, int flags); 59 | extern int sys_close(int fd); 60 | extern void sys_exit(int status); 61 | extern void* sys_sbrk(size_t len); 62 | extern int sys_uname(utsname* buf); 63 | extern void sys_break(void); 64 | extern int sys_stat(int fd, f_stat* buf); 65 | extern uint64_t sys_uptime(void); 66 | extern int sys_exec(const char* args, int flags); 67 | extern int sys_getcwd(char* buf, size_t buf_len); 68 | extern int sys_chdir(const char* path); 69 | extern size_t sys_sbrksz(const void* target); 70 | extern int sys_getenames(const char* path, char* buf, size_t buf_len); 71 | extern int sys_iomsg(const void* msgbuf, void* replymsgbuf, size_t replymsgbuf_len); 72 | extern int sys_socket(int domain, int type, int protocol); 73 | extern int sys_bind(int sockfd, const struct sockaddr* addr, size_t addrlen); 74 | extern int sys_sendto(int sockfd, const void* buf, size_t len, int flags, const struct sockaddr* dest_addr, size_t addrlen); 75 | extern int sys_recvfrom(int sockfd, void* buf, size_t len, int flags, struct sockaddr* src_addr, size_t addrlen); 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /kernel/src/fs/file/bitmap.rs: -------------------------------------------------------------------------------- 1 | use crate::graphics::color::ColorCode; 2 | use alloc::vec::Vec; 3 | use core::mem::size_of; 4 | 5 | const MAGIC: [u8; 2] = *b"BM"; 6 | 7 | #[derive(Debug)] 8 | #[repr(C, packed)] 9 | pub struct ImageHeader { 10 | pub magic: [u8; 2], 11 | pub file_size: u32, 12 | reserved: [u16; 2], 13 | pub offset: u32, 14 | } 15 | 16 | #[repr(C, packed)] 17 | pub struct InfoHeader { 18 | pub header_size: u32, 19 | pub width: i32, 20 | pub height: i32, 21 | pub planes: u16, 22 | pub bits_per_pixel: u16, 23 | pub compression: u32, 24 | pub image_size: u32, 25 | pub x_pixels_per_meter: i32, 26 | pub y_pixels_per_meter: i32, 27 | pub colors_used: u32, 28 | pub colors_important: u32, 29 | } 30 | 31 | // TODO: supported RGB (24bits) bitmap only 32 | pub struct BitmapImage<'a> { 33 | data: &'a [u8], 34 | } 35 | 36 | impl<'a> BitmapImage<'a> { 37 | pub fn new(data: &'a [u8]) -> Self { 38 | Self { data } 39 | } 40 | 41 | pub fn header(&self) -> &ImageHeader { 42 | unsafe { &*(self.data.as_ptr() as *const ImageHeader) } 43 | } 44 | 45 | pub fn info_header(&self) -> &InfoHeader { 46 | let offset = size_of::(); 47 | unsafe { &*(self.data.as_ptr().add(offset) as *const InfoHeader) } 48 | } 49 | 50 | pub fn is_valid(&self) -> bool { 51 | self.header().magic == MAGIC 52 | } 53 | 54 | pub fn bitmap(&self) -> &[u8] { 55 | let offset = self.header().offset as usize; 56 | &self.data[offset..] 57 | } 58 | 59 | pub fn bitmap_to_color_code(&self) -> Vec { 60 | let bitmap = self.bitmap(); 61 | let info_header = self.info_header(); 62 | let width = info_header.width.abs() as usize; 63 | let height = info_header.height.abs() as usize; 64 | let bits_per_pixel = info_header.bits_per_pixel as usize / 8; 65 | let padding = (4 - (width * bits_per_pixel) % 4) % 4; 66 | let mut data = Vec::new(); 67 | 68 | for y in 0..height { 69 | for x in 0..width { 70 | let offset = (height - y - 1) as usize 71 | * (width * bits_per_pixel + padding) as usize 72 | + x as usize * bits_per_pixel as usize; 73 | let b = bitmap[offset]; 74 | let g = bitmap[offset + 1]; 75 | let r = bitmap[offset + 2]; 76 | data.push(ColorCode::new_rgb(r, g, b)); 77 | } 78 | } 79 | 80 | data 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /kernel/src/util/keyboard/scan_code.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 2 | #[allow(dead_code)] 3 | pub enum KeyCode { 4 | Esc, 5 | F1, 6 | F2, 7 | F3, 8 | F4, 9 | F5, 10 | F6, 11 | F7, 12 | F8, 13 | F9, 14 | F10, 15 | F11, 16 | F12, 17 | PrintScreen, 18 | ScrollLock, 19 | Pause, 20 | Insert, 21 | Home, 22 | PageUp, 23 | Delete, 24 | End, 25 | PageDown, 26 | CursorRight, 27 | CursorLeft, 28 | CursorDown, 29 | CursorUp, 30 | NumLock, 31 | KpDivide, 32 | KpMultiply, 33 | KpSubtract, 34 | KpAdd, 35 | KpEnter, 36 | Kp1, 37 | Kp2, 38 | Kp3, 39 | Kp4, 40 | Kp5, 41 | Kp6, 42 | Kp7, 43 | Kp8, 44 | Kp9, 45 | Kp0, 46 | KpPeriod, 47 | LCtrl, 48 | LGui, 49 | LAlt, 50 | Space, 51 | RGui, 52 | RAlt, 53 | Apps, 54 | RCtrl, 55 | LShift, 56 | CapsLock, 57 | Tab, 58 | Backspace, 59 | Enter, 60 | RShift, 61 | Num1, 62 | Num2, 63 | Num3, 64 | Num4, 65 | Num5, 66 | Num6, 67 | Num7, 68 | Num8, 69 | Num9, 70 | Num0, 71 | A, 72 | B, 73 | C, 74 | D, 75 | E, 76 | F, 77 | G, 78 | H, 79 | I, 80 | J, 81 | K, 82 | L, 83 | M, 84 | N, 85 | O, 86 | P, 87 | Q, 88 | R, 89 | S, 90 | T, 91 | U, 92 | V, 93 | W, 94 | X, 95 | Y, 96 | Z, 97 | Backtick, 98 | Subtract, 99 | Equal, 100 | BracketLeft, 101 | BracketRight, 102 | Backslash, 103 | Semicolon, 104 | Quote, 105 | Comma, 106 | Period, 107 | Slash, 108 | } 109 | 110 | impl KeyCode { 111 | pub fn is_shift(&self) -> bool { 112 | *self == Self::LShift || *self == Self::RShift 113 | } 114 | 115 | pub fn is_ctrl(&self) -> bool { 116 | *self == Self::LCtrl || *self == Self::RCtrl 117 | } 118 | 119 | pub fn is_gui(&self) -> bool { 120 | *self == Self::LGui || *self == Self::RGui 121 | } 122 | 123 | pub fn is_alt(&self) -> bool { 124 | *self == Self::LAlt || *self == Self::RAlt 125 | } 126 | } 127 | 128 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 129 | pub struct ScanCode { 130 | pub key_code: KeyCode, 131 | pub c: Option, 132 | pub on_shift_c: Option, 133 | pub ps2_scan_code_pressed: [u8; 6], 134 | pub ps2_scan_code_released: [u8; 6], 135 | pub usb_hid_usage_id: u8, 136 | } 137 | -------------------------------------------------------------------------------- /third-party/License.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Intel Corporation. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in 11 | the documentation and/or other materials provided with the 12 | distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 17 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 18 | COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 19 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | POSSIBILITY OF SUCH DAMAGE. 26 | 27 | 28 | Some files are subject to the following license, the MIT license. Those files 29 | are located in: 30 | - OvmfPkg/Include/IndustryStandard/Xen/ 31 | - OvmfPkg/XenBusDxe/ 32 | - OvmfPkg/XenPvBlkDxe/ 33 | 34 | Permission is hereby granted, free of charge, to any person obtaining a copy 35 | of this software and associated documentation files (the "Software"), to deal 36 | in the Software without restriction, including without limitation the rights 37 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 38 | copies of the Software, and to permit persons to whom the Software is 39 | furnished to do so, subject to the following conditions: 40 | 41 | The above copyright notice and this permission notice shall be included in 42 | all copies or substantial portions of the Software. 43 | 44 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 45 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 46 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 47 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 48 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 49 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 50 | THE SOFTWARE. 51 | -------------------------------------------------------------------------------- /kernel/src/util/mmio.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | arch::VirtualAddress, 3 | mem::paging::{self, *}, 4 | }; 5 | use alloc::boxed::Box; 6 | use core::{ 7 | marker::PhantomPinned, 8 | mem::{ManuallyDrop, MaybeUninit}, 9 | pin::Pin, 10 | }; 11 | 12 | #[derive(Debug)] 13 | pub struct Mmio { 14 | inner: ManuallyDrop>>, 15 | } 16 | 17 | impl AsRef for Mmio { 18 | fn as_ref(&self) -> &T { 19 | self.inner.as_ref().get_ref() 20 | } 21 | } 22 | 23 | impl AsMut for Mmio { 24 | fn as_mut(&mut self) -> &mut T { 25 | self.inner.as_mut().get_mut() 26 | } 27 | } 28 | 29 | impl Mmio { 30 | pub unsafe fn from_raw(ptr: *mut T) -> Self { 31 | Self { 32 | inner: ManuallyDrop::new(Box::into_pin(Box::from_raw(ptr))), 33 | } 34 | } 35 | 36 | pub unsafe fn get_unchecked_mut(&mut self) -> &mut T { 37 | self.inner.as_mut().get_unchecked_mut() 38 | } 39 | } 40 | 41 | #[repr(align(4096))] 42 | pub struct IoBoxInner { 43 | data: T, 44 | _pinned: PhantomPinned, 45 | } 46 | 47 | impl IoBoxInner { 48 | pub fn new(data: T) -> Self { 49 | Self { 50 | data, 51 | _pinned: PhantomPinned, 52 | } 53 | } 54 | } 55 | 56 | pub struct IoBox { 57 | inner: Pin>>, 58 | } 59 | 60 | impl AsRef for IoBox { 61 | fn as_ref(&self) -> &T { 62 | &self.inner.as_ref().get_ref().data 63 | } 64 | } 65 | 66 | impl Default for IoBox { 67 | fn default() -> Self { 68 | Self::new() 69 | } 70 | } 71 | 72 | impl IoBox { 73 | pub fn new() -> Self { 74 | let inner = Box::pin(IoBoxInner::new(unsafe { 75 | MaybeUninit::::zeroed().assume_init() 76 | })); 77 | 78 | let me = Self { inner }; 79 | 80 | // disable cache 81 | let start: VirtualAddress = (me.as_ref() as *const T as u64).into(); 82 | paging::update_mapping(&MappingInfo { 83 | start, 84 | end: start.offset(size_of::().div_ceil(PAGE_SIZE)), 85 | phys_addr: start.get_phys_addr().unwrap(), 86 | rw: ReadWrite::Write, 87 | us: EntryMode::Supervisor, 88 | pwt: PageWriteThroughLevel::WriteThrough, 89 | pcd: true, // page cache disable 90 | }) 91 | .unwrap(); 92 | 93 | me 94 | } 95 | 96 | pub unsafe fn get_unchecked_mut(&mut self) -> &mut T { 97 | &mut self.inner.as_mut().get_unchecked_mut().data 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /kernel/src/util/random.rs: -------------------------------------------------------------------------------- 1 | use alloc::vec::Vec; 2 | 3 | fn xorshift64(seed: u64) -> u64 { 4 | let mut x = seed; 5 | x ^= x << 13; 6 | x ^= x >> 7; 7 | x ^= x << 17; 8 | x 9 | } 10 | 11 | fn pcg32(state: &mut u64, inc: u64) -> u32 { 12 | let oldstate = *state; 13 | *state = oldstate 14 | .wrapping_mul(6364136223846793005u64) 15 | .wrapping_add(inc | 1); 16 | let xorshifted = (((oldstate >> 18) ^ oldstate) >> 27) as u32; 17 | let rot = (oldstate >> 59) as u32; 18 | (xorshifted >> rot) | (xorshifted << ((!rot).wrapping_add(1) & 31)) 19 | } 20 | 21 | struct XorShift64 { 22 | seed: u64, 23 | } 24 | 25 | impl XorShift64 { 26 | fn new(seed: u64) -> Self { 27 | Self { 28 | seed: if seed == 0 { 1 } else { seed }, 29 | } 30 | } 31 | 32 | fn next(&mut self) -> u64 { 33 | self.seed = xorshift64(self.seed); 34 | self.seed 35 | } 36 | 37 | fn next_bytes(&mut self, buf: &mut [u8]) { 38 | // skip 39 | for _ in 0..8 { 40 | let _ = self.next(); 41 | } 42 | 43 | let mut i = 0; 44 | while i < buf.len() { 45 | let value = self.next(); 46 | let bytes = value.to_le_bytes(); 47 | 48 | for &byte in &bytes { 49 | if i < buf.len() { 50 | buf[i] = byte; 51 | i += 1; 52 | } else { 53 | break; 54 | } 55 | } 56 | } 57 | } 58 | } 59 | 60 | struct Pcg32 { 61 | state: u64, 62 | inc: u64, 63 | } 64 | 65 | impl Pcg32 { 66 | fn new(seed: u64) -> Self { 67 | let mut rng = Self { 68 | state: 0, 69 | inc: (seed << 1) | 1, 70 | }; 71 | rng.state = seed.wrapping_add(rng.inc); 72 | let _ = pcg32(&mut rng.state, rng.inc); 73 | rng 74 | } 75 | 76 | fn next(&mut self) -> u32 { 77 | pcg32(&mut self.state, self.inc) 78 | } 79 | 80 | fn next_bytes(&mut self, buf: &mut [u8]) { 81 | let mut i = 0; 82 | while i < buf.len() { 83 | let value = self.next(); 84 | let bytes = value.to_le_bytes(); 85 | 86 | for &byte in &bytes { 87 | if i < buf.len() { 88 | buf[i] = byte; 89 | i += 1; 90 | } else { 91 | break; 92 | } 93 | } 94 | } 95 | } 96 | } 97 | 98 | pub fn random_bytes_xorshift64(len: usize, seed: u64) -> Vec { 99 | let mut rng = XorShift64::new(seed); 100 | let mut bytes = Vec::with_capacity(len); 101 | bytes.resize(len, 0); 102 | rng.next_bytes(&mut bytes); 103 | bytes 104 | } 105 | 106 | pub fn random_bytes_pcg32(len: usize, seed: u64) -> Vec { 107 | let mut rng = Pcg32::new(seed); 108 | let mut bytes = Vec::with_capacity(len); 109 | bytes.resize(len, 0); 110 | rng.next_bytes(&mut bytes); 111 | bytes 112 | } 113 | -------------------------------------------------------------------------------- /kernel/src/util/keyboard/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::util::keyboard::{key_event::*, scan_code::ScanCode}; 2 | use alloc::collections::btree_map::BTreeMap; 3 | 4 | pub mod key_event; 5 | pub mod key_map; 6 | pub mod scan_code; 7 | 8 | pub fn get_key_event_from_ps2( 9 | key_map: &BTreeMap<[u8; 6], ScanCode>, 10 | mod_keys_state: &mut ModifierKeysState, 11 | code: [u8; 6], 12 | ) -> Option { 13 | let scan_code = key_map.get(&code)?; 14 | 15 | let key_code = scan_code.key_code; 16 | let key_state = match scan_code { 17 | sc if sc.ps2_scan_code_pressed == code => KeyState::Pressed, 18 | sc if sc.ps2_scan_code_released == code => KeyState::Released, 19 | _ => unreachable!(), 20 | }; 21 | 22 | // update state 23 | if key_code.is_shift() { 24 | mod_keys_state.shift = key_state == KeyState::Pressed; 25 | } else if key_code.is_ctrl() { 26 | mod_keys_state.ctrl = key_state == KeyState::Pressed; 27 | } else if key_code.is_gui() { 28 | mod_keys_state.gui = key_state == KeyState::Pressed; 29 | } else if key_code.is_alt() { 30 | mod_keys_state.alt = key_state == KeyState::Pressed; 31 | } 32 | 33 | if key_state == KeyState::Released { 34 | return None; 35 | } 36 | 37 | let mut c = if mod_keys_state.shift { 38 | scan_code.on_shift_c 39 | } else { 40 | scan_code.c 41 | }; 42 | 43 | if c.is_some() && mod_keys_state.ctrl { 44 | match c.unwrap() as u8 { 45 | 0x40..=0x5f => { 46 | c = Some((c.unwrap() as u8 - 0x40) as char); 47 | } 48 | 0x60..=0x7f => { 49 | c = Some((c.unwrap() as u8 - 0x60) as char); 50 | } 51 | _ => (), 52 | } 53 | } 54 | 55 | let key_event = KeyEvent { 56 | code: key_code, 57 | state: key_state, 58 | c, 59 | }; 60 | Some(key_event) 61 | } 62 | 63 | pub fn get_key_event_from_usb_hid( 64 | key_map: &BTreeMap, 65 | mod_keys_state: &ModifierKeysState, 66 | key_state: KeyState, 67 | usage_id: u8, 68 | ) -> Option { 69 | let scan_code = key_map.get(&usage_id)?; 70 | 71 | let key_code = scan_code.key_code; 72 | assert!(usage_id == scan_code.usb_hid_usage_id); 73 | 74 | if key_state == KeyState::Released { 75 | return None; 76 | } 77 | 78 | let mut c = if mod_keys_state.shift { 79 | scan_code.on_shift_c 80 | } else { 81 | scan_code.c 82 | }; 83 | 84 | if c.is_some() && mod_keys_state.ctrl { 85 | match c.unwrap() as u8 { 86 | 0x40..=0x5f => { 87 | c = Some((c.unwrap() as u8 - 0x40) as char); 88 | } 89 | 0x60..=0x7f => { 90 | c = Some((c.unwrap() as u8 - 0x60) as char); 91 | } 92 | _ => (), 93 | } 94 | } 95 | 96 | let key_event = KeyEvent { 97 | code: key_code, 98 | state: key_state, 99 | c, 100 | }; 101 | Some(key_event) 102 | } 103 | -------------------------------------------------------------------------------- /kernel/src/net/icmp.rs: -------------------------------------------------------------------------------- 1 | use crate::error::{Error, Result}; 2 | use alloc::vec::Vec; 3 | use core::fmt::Debug; 4 | 5 | #[derive(Debug, Clone, Copy)] 6 | pub enum IcmpType { 7 | EchoReply, 8 | EchoRequest, 9 | Other(u8), 10 | } 11 | 12 | impl From for u8 { 13 | fn from(ty: IcmpType) -> Self { 14 | match ty { 15 | IcmpType::EchoReply => 0, 16 | IcmpType::EchoRequest => 8, 17 | IcmpType::Other(x) => x, 18 | } 19 | } 20 | } 21 | 22 | impl From for IcmpType { 23 | fn from(data: u8) -> Self { 24 | match data { 25 | 0 => IcmpType::EchoReply, 26 | 8 => IcmpType::EchoRequest, 27 | _ => IcmpType::Other(data), 28 | } 29 | } 30 | } 31 | 32 | #[derive(Debug, Clone)] 33 | pub struct IcmpPacket { 34 | pub ty: IcmpType, 35 | code: u8, 36 | checksum: u16, 37 | id: u16, 38 | seq: u16, 39 | data: Vec, 40 | } 41 | 42 | impl TryFrom<&[u8]> for IcmpPacket { 43 | type Error = Error; 44 | 45 | fn try_from(value: &[u8]) -> Result { 46 | if value.len() < 8 { 47 | return Err(Error::Failed("Invalid data length")); 48 | } 49 | 50 | let ty = value[0].into(); 51 | let code = value[1]; 52 | let checksum = u16::from_be_bytes([value[2], value[3]]); 53 | let id = u16::from_be_bytes([value[4], value[5]]); 54 | let seq = u16::from_be_bytes([value[6], value[7]]); 55 | let data = value[8..].to_vec(); 56 | 57 | Ok(Self { 58 | ty, 59 | code, 60 | checksum, 61 | id, 62 | seq, 63 | data, 64 | }) 65 | } 66 | } 67 | 68 | impl IcmpPacket { 69 | pub fn calc_checksum(&mut self) { 70 | self.checksum = 0; 71 | let mut sum: u32 = 0; 72 | 73 | let header = [ 74 | self.ty.into(), 75 | self.code, 76 | 0, 77 | 0, // checksum 78 | (self.id >> 8) as u8, 79 | (self.id & 0xff) as u8, 80 | (self.seq >> 8) as u8, 81 | (self.seq & 0xff) as u8, 82 | ]; 83 | 84 | for chunk in header.chunks(2).chain(self.data.chunks(2)) { 85 | let word = match chunk { 86 | [h, l] => u16::from_be_bytes([*h, *l]), 87 | [h] => u16::from_be_bytes([*h, 0]), 88 | _ => 0, 89 | }; 90 | sum = sum.wrapping_add(word as u32); 91 | } 92 | 93 | while (sum >> 16) > 0 { 94 | sum = (sum & 0xffff) + (sum >> 16); 95 | } 96 | 97 | self.checksum = !(sum as u16); 98 | } 99 | 100 | pub fn to_vec(&self) -> Vec { 101 | let mut vec = Vec::new(); 102 | vec.push(self.ty.into()); 103 | vec.push(self.code); 104 | vec.extend_from_slice(&self.checksum.to_be_bytes()); 105 | vec.extend_from_slice(&self.id.to_be_bytes()); 106 | vec.extend_from_slice(&self.seq.to_be_bytes()); 107 | vec.extend_from_slice(&self.data); 108 | vec 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /kernel/src/sync/mutex.rs: -------------------------------------------------------------------------------- 1 | use crate::{arch::x86_64, error::Result}; 2 | use core::{ 3 | cell::SyncUnsafeCell, 4 | ops::{Deref, DerefMut}, 5 | sync::atomic::{AtomicBool, Ordering}, 6 | }; 7 | 8 | pub struct Mutex { 9 | value: SyncUnsafeCell, 10 | locked: AtomicBool, 11 | } 12 | 13 | impl Mutex { 14 | pub const fn new(value: T) -> Self { 15 | Self { 16 | value: SyncUnsafeCell::new(value), 17 | locked: AtomicBool::new(false), 18 | } 19 | } 20 | 21 | pub fn try_lock(&self) -> Result> { 22 | if self 23 | .locked 24 | .compare_exchange(false, true, Ordering::SeqCst, Ordering::Relaxed) 25 | .is_ok() 26 | { 27 | return Ok(unsafe { MutexGuard::new(self, &self.value) }); 28 | } 29 | 30 | Err("Mutex is already locked".into()) 31 | } 32 | 33 | pub unsafe fn get_force_mut(&mut self) -> &mut T { 34 | self.value.get_mut() 35 | } 36 | 37 | pub fn spin_lock(&self) -> MutexGuard { 38 | loop { 39 | if let Ok(guard) = self.try_lock() { 40 | return guard; 41 | } else { 42 | x86_64::stihlt(); 43 | } 44 | } 45 | } 46 | 47 | // pub fn lock(&self) -> MutexGuard { 48 | // self.try_lock().unwrap_or_else(|e| panic!("{:?}", e)) 49 | // } 50 | 51 | // pub fn is_locked(&self) -> bool { 52 | // self.locked.load(Ordering::SeqCst) 53 | // } 54 | } 55 | 56 | unsafe impl Sync for Mutex {} 57 | 58 | pub struct MutexGuard<'a, T> { 59 | mutex: &'a Mutex, 60 | value: &'a mut T, 61 | } 62 | 63 | impl<'a, T> MutexGuard<'a, T> { 64 | unsafe fn new(mutex: &'a Mutex, value: &SyncUnsafeCell) -> Self { 65 | Self { 66 | mutex, 67 | value: &mut *value.get(), 68 | } 69 | } 70 | } 71 | 72 | unsafe impl<'a, T> Sync for MutexGuard<'a, T> {} 73 | 74 | impl<'a, T> Deref for MutexGuard<'a, T> { 75 | type Target = T; 76 | 77 | fn deref(&self) -> &Self::Target { 78 | self.value 79 | } 80 | } 81 | 82 | impl<'a, T> DerefMut for MutexGuard<'a, T> { 83 | fn deref_mut(&mut self) -> &mut Self::Target { 84 | self.value 85 | } 86 | } 87 | 88 | impl<'a, T> Drop for MutexGuard<'a, T> { 89 | fn drop(&mut self) { 90 | self.mutex.locked.store(false, Ordering::Relaxed); 91 | } 92 | } 93 | 94 | #[test_case] 95 | fn test_lock_unlock() { 96 | let mutex = Mutex::new(0); 97 | 98 | { 99 | let mut guard = mutex.try_lock().unwrap(); 100 | *guard += 1; 101 | assert_eq!(*guard, 1); 102 | } 103 | 104 | { 105 | let guard = mutex.try_lock().unwrap(); 106 | assert_eq!(*guard, 1); 107 | } 108 | } 109 | 110 | #[test_case] 111 | fn test_unlock_force() { 112 | let mut mutex = Mutex::new(0); 113 | 114 | unsafe { 115 | let guard = mutex.get_force_mut(); 116 | *guard += 1; 117 | } 118 | 119 | let guard = mutex.try_lock().unwrap(); 120 | assert_eq!(*guard, 1); 121 | } 122 | -------------------------------------------------------------------------------- /kernel/src/device/urandom.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | device, 3 | device::{DeviceDriverFunction, DeviceDriverInfo}, 4 | error::Result, 5 | fs::vfs, 6 | kinfo, 7 | sync::mutex::Mutex, 8 | util, 9 | }; 10 | use alloc::vec::Vec; 11 | 12 | static mut URANDOM_DRIVER: Mutex = Mutex::new(UrandomDriver::new()); 13 | 14 | struct UrandomDriver { 15 | device_driver_info: DeviceDriverInfo, 16 | } 17 | 18 | impl UrandomDriver { 19 | const DEFAULT_SIZE: usize = 256; 20 | 21 | const fn new() -> Self { 22 | Self { 23 | device_driver_info: DeviceDriverInfo::new("urandom"), 24 | } 25 | } 26 | } 27 | 28 | impl DeviceDriverFunction for UrandomDriver { 29 | type AttachInput = (); 30 | type PollNormalOutput = (); 31 | type PollInterruptOutput = (); 32 | 33 | fn get_device_driver_info(&self) -> Result { 34 | Ok(self.device_driver_info.clone()) 35 | } 36 | 37 | fn probe(&mut self) -> Result<()> { 38 | Ok(()) 39 | } 40 | 41 | fn attach(&mut self, _arg: Self::AttachInput) -> Result<()> { 42 | let dev_desc = vfs::DeviceFileDescriptor { 43 | get_device_driver_info, 44 | open, 45 | close, 46 | read, 47 | write, 48 | }; 49 | vfs::add_dev_file(dev_desc, self.device_driver_info.name)?; 50 | self.device_driver_info.attached = true; 51 | Ok(()) 52 | } 53 | 54 | fn poll_normal(&mut self) -> Result { 55 | unimplemented!() 56 | } 57 | 58 | fn poll_int(&mut self) -> Result { 59 | unimplemented!() 60 | } 61 | 62 | fn open(&mut self) -> Result<()> { 63 | Ok(()) 64 | } 65 | 66 | fn close(&mut self) -> Result<()> { 67 | Ok(()) 68 | } 69 | 70 | fn read(&mut self) -> Result> { 71 | let uptime_durtion = device::local_apic_timer::global_uptime(); 72 | let seed = uptime_durtion.as_nanos() as u64; 73 | let buf = util::random::random_bytes_pcg32(Self::DEFAULT_SIZE, seed); 74 | Ok(buf) 75 | } 76 | 77 | fn write(&mut self, _data: &[u8]) -> Result<()> { 78 | Ok(()) 79 | } 80 | } 81 | 82 | pub fn get_device_driver_info() -> Result { 83 | let driver = unsafe { URANDOM_DRIVER.try_lock() }?; 84 | driver.get_device_driver_info() 85 | } 86 | 87 | pub fn probe_and_attach() -> Result<()> { 88 | let mut driver = unsafe { URANDOM_DRIVER.try_lock() }?; 89 | driver.probe()?; 90 | driver.attach(())?; 91 | kinfo!("{}: Attached!", driver.get_device_driver_info()?.name); 92 | 93 | Ok(()) 94 | } 95 | 96 | pub fn open() -> Result<()> { 97 | let mut driver = unsafe { URANDOM_DRIVER.try_lock() }?; 98 | driver.open() 99 | } 100 | 101 | pub fn close() -> Result<()> { 102 | let mut driver = unsafe { URANDOM_DRIVER.try_lock() }?; 103 | driver.close() 104 | } 105 | 106 | pub fn read() -> Result> { 107 | let mut driver = unsafe { URANDOM_DRIVER.try_lock() }?; 108 | driver.read() 109 | } 110 | 111 | pub fn write(data: &[u8]) -> Result<()> { 112 | let mut driver = unsafe { URANDOM_DRIVER.try_lock() }?; 113 | driver.write(data) 114 | } 115 | -------------------------------------------------------------------------------- /kernel/src/error.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | arch::x86_64::acpi::AcpiError, 3 | device::{tty::TtyError, usb::xhc::XhcDriverError}, 4 | fs::vfs::VirtualFileSystemError, 5 | graphics::{ 6 | draw::DrawError, multi_layer::LayerError, simple_window_manager::SimpleWindowManagerError, 7 | }, 8 | mem::{allocator::AllocationError, bitmap::BitmapMemoryManagerError, paging::PageManagerError}, 9 | util::{fifo::FifoError, lifo::LifoError}, 10 | }; 11 | use common::elf::Elf64Error; 12 | 13 | #[derive(Debug, Clone, PartialEq)] 14 | pub enum Error { 15 | NotInitialized, 16 | Failed(&'static str), 17 | LayerError(LayerError), 18 | BitmapMemoryManagerError(BitmapMemoryManagerError), 19 | PageManagerError(PageManagerError), 20 | FifoError(FifoError), 21 | LifoError(LifoError), 22 | IndexOutOfBoundsError(usize), 23 | VirtualFileSystemError(VirtualFileSystemError), 24 | Elf64Error(Elf64Error), 25 | SimpleWindowManagerError(SimpleWindowManagerError), 26 | AcpiError(AcpiError), 27 | AllocationError(AllocationError), 28 | DrawError(DrawError), 29 | TtyError(TtyError), 30 | XhcDriverError(XhcDriverError), 31 | } 32 | 33 | impl From<&'static str> for Error { 34 | fn from(s: &'static str) -> Self { 35 | Self::Failed(s) 36 | } 37 | } 38 | 39 | impl From for Error { 40 | fn from(err: LayerError) -> Self { 41 | Self::LayerError(err) 42 | } 43 | } 44 | 45 | impl From for Error { 46 | fn from(err: BitmapMemoryManagerError) -> Self { 47 | Self::BitmapMemoryManagerError(err) 48 | } 49 | } 50 | 51 | impl From for Error { 52 | fn from(err: PageManagerError) -> Self { 53 | Self::PageManagerError(err) 54 | } 55 | } 56 | 57 | impl From for Error { 58 | fn from(err: FifoError) -> Self { 59 | Self::FifoError(err) 60 | } 61 | } 62 | 63 | impl From for Error { 64 | fn from(err: LifoError) -> Self { 65 | Self::LifoError(err) 66 | } 67 | } 68 | 69 | impl From for Error { 70 | fn from(err: VirtualFileSystemError) -> Self { 71 | Self::VirtualFileSystemError(err) 72 | } 73 | } 74 | 75 | impl From for Error { 76 | fn from(err: Elf64Error) -> Self { 77 | Self::Elf64Error(err) 78 | } 79 | } 80 | 81 | impl From for Error { 82 | fn from(err: SimpleWindowManagerError) -> Self { 83 | Self::SimpleWindowManagerError(err) 84 | } 85 | } 86 | 87 | impl From for Error { 88 | fn from(err: AcpiError) -> Self { 89 | Self::AcpiError(err) 90 | } 91 | } 92 | 93 | impl From for Error { 94 | fn from(err: AllocationError) -> Self { 95 | Self::AllocationError(err) 96 | } 97 | } 98 | 99 | impl From for Error { 100 | fn from(err: DrawError) -> Self { 101 | Self::DrawError(err) 102 | } 103 | } 104 | 105 | impl From for Error { 106 | fn from(err: TtyError) -> Self { 107 | Self::TtyError(err) 108 | } 109 | } 110 | 111 | impl From for Error { 112 | fn from(err: XhcDriverError) -> Self { 113 | Self::XhcDriverError(err) 114 | } 115 | } 116 | 117 | pub type Result = core::result::Result; 118 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # myos-x86_64 2 | 3 | **myos-x86_64** is a hobby operating system written in Rust. 4 | 5 | This is a replacement project for the previous **[myos](https://github.com/Zakki0925224/myos)**. 6 | 7 | ## Images 8 | 9 | ![](https://github.com/user-attachments/assets/7cc7d545-b3ca-4042-b145-73a909834c13) 10 | ![](https://github.com/Zakki0925224/myos-x86_64/assets/49384910/b134ef0a-c94e-46f8-a578-a6e160747fae) 11 | ![](https://github.com/Zakki0925224/myos-x86_64/assets/49384910/fce1c2e4-f56b-46fa-8530-9eeec6069591) 12 | 13 | ## Features 14 | 15 | - [x] Written in Rust 16 | - [x] My own UEFI boot loader by using [uefi-rs](https://github.com/rust-osdev/uefi-rs) 17 | - [x] x86_64 kernel 18 | - [x] Paging 19 | - Bus support 20 | - [x] PCI 21 | - [x] USB 22 | - Device support 23 | - [x] PS/2 Keyboard and Mouse 24 | - [x] UART 16650A 25 | - [x] RTL8139 26 | - [x] xHCI 27 | - [x] HID Keyboard 28 | - [x] HID Tablet 29 | - [x] PC Speaker 30 | - Timer support 31 | - [x] Local APIC timer (main timer) 32 | - [x] ACPI PM timer 33 | - [x] TSC 34 | - [x] File system 35 | - [x] Own VFS (read/write, in-memory) 36 | - [x] FAT32 (read only) 37 | - [x] Device file (/dev) 38 | - [x] Networking 39 | - [x] ARP 40 | - [x] IPv4 41 | - [x] ICMP 42 | - [ ] TCP 43 | - [x] UDP 44 | - [x] Async runtime 45 | - [x] Simple priority-based executor 46 | - [x] Simple window manager 47 | - [x] [Userland applications](/apps/) (libc for myos available [here](/apps/libc/)) 48 | - [x] DOOM challenge! 49 | 50 | ## Third party 51 | 52 | - OVMF from [EDK II](https://github.com/tianocore/edk2.git) (included) 53 | - [Cozette](https://github.com/slavfox/Cozette.git) (download released binary when build) 54 | - [QEMU](https://gitlab.com/qemu-project/qemu.git) (for debugging) 55 | - [doom-for-myos](https://github.com/Zakki0925224/doom-for-myos) (forked from [ozkl/doomgeneric](https://github.com/ozkl/doomgeneric)) 56 | - [doom1.wad](https://distro.ibiblio.org/slitaz/sources/packages/d/doom1.wad) 57 | 58 | ## How to run 59 | 60 | ### Minimum packages required to build and run 61 | 62 | - For build kernel 63 | 64 | - rustup (and Rust toolchain) 65 | - python3 66 | - build-essential 67 | - lld 68 | - gcc-multilib 69 | - clang 70 | - qemu-system 71 | - dosfstools 72 | - wget 73 | 74 | - For build Cozette 75 | 76 | - python3-venv 77 | - bdf2psf (convert bdf file due to [bug in cozette.psf](https://github.com/slavfox/Cozette/issues/112)) 78 | 79 | - For build QEMU 80 | 81 | - ninja-build 82 | - meson 83 | - libglib2.0-dev 84 | - libsdl2-dev 85 | 86 | ```bash 87 | # install required packages 88 | $ sudo apt update && sudo apt install python3 build-essential lld gcc-multilib clang qemu-system dosfstools wget python3-venv bdf2psf ninja-build meson libglib2.0-dev libsdl2-dev 89 | 90 | $ git clone https://github.com/Zakki0925224/myos-x86_64.git 91 | $ cd myos-x86_64 92 | $ python3 ./task.py make_netdev 93 | $ python3 ./task.py run 94 | ``` 95 | 96 | ## How to run kernel test 97 | 98 | ```bash 99 | $ cd myos-x86_64/kernel 100 | $ cargo test 101 | ``` 102 | 103 | If you run `task.py` without an argument, you can see the list of commands. 104 | -------------------------------------------------------------------------------- /kernel/src/device/zakki.rs: -------------------------------------------------------------------------------- 1 | use super::{DeviceDriverFunction, DeviceDriverInfo}; 2 | use crate::{error::Result, fs::vfs, kinfo, sync::mutex::Mutex}; 3 | use alloc::vec::Vec; 4 | 5 | const MESSAGE: &str = "Hello! I'm Zakki, a low-level programmer!\nCheck out my links below:\n\tX: https://x.com/zakki0925224\n\tGitHub: https://github.com/Zakki0925224\n\tPortfolio: https://bento.me/zakki0925224\n"; 6 | 7 | static mut ZAKKI_DRIVER: Mutex = Mutex::new(ZakkiDriver::new()); 8 | 9 | // https://github.com/Zakki0925224/zakki_driver 10 | struct ZakkiDriver { 11 | device_driver_info: DeviceDriverInfo, 12 | } 13 | 14 | impl ZakkiDriver { 15 | const fn new() -> Self { 16 | Self { 17 | device_driver_info: DeviceDriverInfo::new("zakki"), 18 | } 19 | } 20 | } 21 | 22 | impl DeviceDriverFunction for ZakkiDriver { 23 | type AttachInput = (); 24 | type PollNormalOutput = (); 25 | type PollInterruptOutput = (); 26 | 27 | fn get_device_driver_info(&self) -> Result { 28 | Ok(self.device_driver_info.clone()) 29 | } 30 | 31 | fn probe(&mut self) -> Result<()> { 32 | Ok(()) 33 | } 34 | 35 | fn attach(&mut self, _arg: Self::AttachInput) -> Result<()> { 36 | let dev_desc = vfs::DeviceFileDescriptor { 37 | get_device_driver_info, 38 | open, 39 | close, 40 | read, 41 | write, 42 | }; 43 | vfs::add_dev_file(dev_desc, self.device_driver_info.name)?; 44 | self.device_driver_info.attached = true; 45 | Ok(()) 46 | } 47 | 48 | fn poll_normal(&mut self) -> Result { 49 | unimplemented!() 50 | } 51 | 52 | fn poll_int(&mut self) -> Result { 53 | unimplemented!() 54 | } 55 | 56 | fn open(&mut self) -> Result<()> { 57 | kinfo!("{}: Opened!", self.device_driver_info.name); 58 | Ok(()) 59 | } 60 | 61 | fn close(&mut self) -> Result<()> { 62 | kinfo!("{}: Closed!", self.device_driver_info.name); 63 | Ok(()) 64 | } 65 | 66 | fn read(&mut self) -> Result> { 67 | kinfo!("{}: Read!", self.device_driver_info.name); 68 | Ok(MESSAGE.as_bytes().to_vec()) 69 | } 70 | 71 | fn write(&mut self, _data: &[u8]) -> Result<()> { 72 | unimplemented!() 73 | } 74 | } 75 | 76 | pub fn get_device_driver_info() -> Result { 77 | let driver = unsafe { ZAKKI_DRIVER.try_lock() }?; 78 | driver.get_device_driver_info() 79 | } 80 | 81 | pub fn probe_and_attach() -> Result<()> { 82 | let mut driver = unsafe { ZAKKI_DRIVER.try_lock() }?; 83 | driver.probe()?; 84 | driver.attach(())?; 85 | kinfo!("{}: Attached!", driver.get_device_driver_info()?.name); 86 | Ok(()) 87 | } 88 | 89 | fn open() -> Result<()> { 90 | let mut driver = unsafe { ZAKKI_DRIVER.try_lock() }?; 91 | driver.open() 92 | } 93 | 94 | fn close() -> Result<()> { 95 | let mut driver = unsafe { ZAKKI_DRIVER.try_lock() }?; 96 | driver.close() 97 | } 98 | 99 | fn read() -> Result> { 100 | let mut driver = unsafe { ZAKKI_DRIVER.try_lock() }?; 101 | driver.read() 102 | } 103 | 104 | fn write(data: &[u8]) -> Result<()> { 105 | let mut driver = unsafe { ZAKKI_DRIVER.try_lock() }?; 106 | driver.write(data) 107 | } 108 | -------------------------------------------------------------------------------- /kernel/src/util/lifo.rs: -------------------------------------------------------------------------------- 1 | use crate::error::Result; 2 | use core::sync::atomic::{AtomicUsize, Ordering}; 3 | 4 | #[derive(Debug, Clone, Copy, PartialEq)] 5 | pub enum LifoError { 6 | BufferIsLocked, 7 | BufferIsFull, 8 | BufferIsEmpty, 9 | } 10 | 11 | #[derive(Debug)] 12 | pub struct Lifo { 13 | buf: [T; SIZE], 14 | top: AtomicUsize, 15 | } 16 | 17 | impl Lifo { 18 | pub const fn new(default: T) -> Self { 19 | Self { 20 | buf: [default; SIZE], 21 | top: AtomicUsize::new(0), 22 | } 23 | } 24 | 25 | pub fn len(&self) -> usize { 26 | self.top.load(Ordering::Relaxed) 27 | } 28 | 29 | pub fn is_full(&self) -> bool { 30 | self.len() == SIZE 31 | } 32 | 33 | pub fn is_empty(&self) -> bool { 34 | self.len() == 0 35 | } 36 | 37 | pub fn reset(&self) { 38 | self.top.store(0, Ordering::Relaxed); 39 | } 40 | 41 | pub fn push(&mut self, value: T) -> Result<()> { 42 | let current_top = self.top.load(Ordering::Relaxed); 43 | if current_top == SIZE { 44 | return Err(LifoError::BufferIsFull.into()); 45 | } 46 | 47 | if self 48 | .top 49 | .compare_exchange( 50 | current_top, 51 | current_top + 1, 52 | Ordering::SeqCst, 53 | Ordering::SeqCst, 54 | ) 55 | .is_err() 56 | { 57 | return Err(LifoError::BufferIsLocked.into()); 58 | } 59 | 60 | self.buf[current_top] = value; 61 | Ok(()) 62 | } 63 | 64 | pub fn pop(&mut self) -> Result { 65 | let current_top = self.top.load(Ordering::Relaxed); 66 | if current_top == 0 { 67 | return Err(LifoError::BufferIsEmpty.into()); 68 | } 69 | 70 | if self 71 | .top 72 | .compare_exchange( 73 | current_top, 74 | current_top - 1, 75 | Ordering::SeqCst, 76 | Ordering::SeqCst, 77 | ) 78 | .is_err() 79 | { 80 | return Err(LifoError::BufferIsLocked.into()); 81 | } 82 | 83 | Ok(self.buf[current_top - 1]) 84 | } 85 | 86 | pub fn get_buf_ref(&self) -> &[T; SIZE] { 87 | &self.buf 88 | } 89 | } 90 | 91 | #[test_case] 92 | fn test_new() { 93 | let lifo: Lifo = Lifo::new(0); 94 | assert_eq!(lifo.len(), 0); 95 | assert!(lifo.is_empty()); 96 | } 97 | 98 | #[test_case] 99 | fn test_push_pop() { 100 | let mut lifo: Lifo = Lifo::new(0); 101 | assert!(lifo.push(1).is_ok()); 102 | assert!(lifo.push(2).is_ok()); 103 | assert!(lifo.push(3).is_ok()); 104 | assert!(lifo.push(4).is_ok()); 105 | assert!(lifo.push(5).is_err()); 106 | 107 | assert_eq!(lifo.pop(), Ok(4)); 108 | assert_eq!(lifo.pop(), Ok(3)); 109 | assert_eq!(lifo.pop(), Ok(2)); 110 | assert_eq!(lifo.pop(), Ok(1)); 111 | assert!(lifo.pop().is_err()); 112 | } 113 | 114 | #[test_case] 115 | fn test_reset() { 116 | let mut lifo: Lifo = Lifo::new(0); 117 | lifo.push(1).unwrap(); 118 | lifo.push(2).unwrap(); 119 | lifo.push(3).unwrap(); 120 | lifo.reset(); 121 | 122 | assert_eq!(lifo.len(), 0); 123 | assert!(lifo.is_empty()); 124 | assert!(lifo.pop().is_err()); 125 | } 126 | -------------------------------------------------------------------------------- /kernel/src/net/udp.rs: -------------------------------------------------------------------------------- 1 | use crate::error::Error; 2 | use alloc::{ 3 | string::{String, ToString}, 4 | vec::Vec, 5 | }; 6 | use core::net::Ipv4Addr; 7 | 8 | #[derive(Debug)] 9 | pub struct UdpSocket { 10 | buf: Vec, 11 | } 12 | 13 | impl UdpSocket { 14 | pub fn new() -> Self { 15 | Self { buf: Vec::new() } 16 | } 17 | 18 | pub fn receive(&mut self, data: &[u8]) { 19 | self.buf.extend_from_slice(data); 20 | } 21 | 22 | pub fn buf_to_string_utf8_lossy(&self) -> String { 23 | String::from_utf8_lossy(&self.buf).to_string() 24 | } 25 | 26 | pub fn read_buf(&mut self, buf: &mut [u8]) -> usize { 27 | let read_len = buf.len().min(self.buf.len()); 28 | if read_len > 0 { 29 | buf[..read_len].copy_from_slice(&self.buf[..read_len]); 30 | self.buf.drain(..read_len); 31 | } 32 | read_len 33 | } 34 | } 35 | 36 | #[derive(Debug, Clone)] 37 | pub struct UdpPacket { 38 | src_port: u16, 39 | pub dst_port: u16, 40 | len: u16, 41 | checksum: u16, 42 | pub data: Vec, 43 | } 44 | 45 | impl TryFrom<&[u8]> for UdpPacket { 46 | type Error = Error; 47 | 48 | fn try_from(value: &[u8]) -> Result { 49 | if value.len() < 8 { 50 | return Err(Error::Failed("Invalid data length")); 51 | } 52 | 53 | let src_port = u16::from_be_bytes([value[0], value[1]]); 54 | let dst_port = u16::from_be_bytes([value[2], value[3]]); 55 | let len = u16::from_be_bytes([value[4], value[5]]); 56 | let checksum = u16::from_be_bytes([value[6], value[7]]); 57 | let data = value[8..(len as usize)].to_vec(); 58 | 59 | Ok(Self { 60 | src_port, 61 | dst_port, 62 | len, 63 | checksum, 64 | data, 65 | }) 66 | } 67 | } 68 | 69 | impl UdpPacket { 70 | pub fn new_with(src_port: u16, dst_port: u16, data: &[u8]) -> Self { 71 | let len = 8 + data.len() as u16; 72 | 73 | Self { 74 | src_port, 75 | dst_port, 76 | len, 77 | checksum: 0, 78 | data: data.to_vec(), 79 | } 80 | } 81 | 82 | pub fn calc_checksum_with_ipv4(&mut self, src_addr: Ipv4Addr, dst_addr: Ipv4Addr) { 83 | self.checksum = 0; 84 | let mut sum: u32 = 0; 85 | 86 | // pseudo header 87 | let src = src_addr.octets(); 88 | let dst = dst_addr.octets(); 89 | sum += ((src[0] as u32) << 8) | (src[1] as u32); 90 | sum += ((src[2] as u32) << 8) | (src[3] as u32); 91 | sum += ((dst[0] as u32) << 8) | (dst[1] as u32); 92 | sum += ((dst[2] as u32) << 8) | (dst[3] as u32); 93 | sum += 17; 94 | 95 | let udp_vec = self.to_vec(); 96 | let udp_len = udp_vec.len() as u32; 97 | sum += udp_len; 98 | 99 | for chunk in udp_vec.chunks(2) { 100 | let word = match chunk { 101 | [h, l] => u16::from_be_bytes([*h, *l]), 102 | [h] => u16::from_be_bytes([*h, 0]), 103 | _ => 0, 104 | }; 105 | sum = sum.wrapping_add(word as u32); 106 | } 107 | 108 | while (sum >> 16) > 0 { 109 | sum = (sum & 0xffff) + (sum >> 16); 110 | } 111 | 112 | self.checksum = !(sum as u16); 113 | } 114 | 115 | pub fn to_vec(&self) -> Vec { 116 | let mut vec = Vec::new(); 117 | vec.extend_from_slice(&self.src_port.to_be_bytes()); 118 | vec.extend_from_slice(&self.dst_port.to_be_bytes()); 119 | vec.extend_from_slice(&self.len.to_be_bytes()); 120 | vec.extend_from_slice(&self.checksum.to_be_bytes()); 121 | vec.extend_from_slice(&self.data); 122 | vec 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /apps/libc/syscalls.c: -------------------------------------------------------------------------------- 1 | #include "syscalls.h" 2 | 3 | #include "sys/socket.h" 4 | 5 | static uint64_t syscall(uint64_t syscall_number, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6) { 6 | uint64_t ret_val; 7 | __asm__ volatile( 8 | "movq %1, %%rax\n" 9 | "movq %2, %%rdi\n" 10 | "movq %3, %%rsi\n" 11 | "movq %4, %%rdx\n" 12 | "movq %5, %%r10\n" 13 | "movq %6, %%r8\n" 14 | "movq %7, %%r9\n" 15 | "syscall\n" 16 | "movq %%rax, %0\n" 17 | : "=r"(ret_val) 18 | : "r"(syscall_number), "r"(arg1), "r"(arg2), "r"(arg3), "r"(arg4), "r"(arg5), "r"(arg6) 19 | : "rax", "rdi", "rsi", "rdx", "r10", "r8", "r9", "memory"); 20 | return ret_val; 21 | } 22 | 23 | int sys_read(int fd, void* buf, size_t buf_len) { 24 | return (int)syscall(SN_READ, (uint64_t)fd, (uint64_t)buf, (uint64_t)buf_len, 0, 0, 0); 25 | } 26 | 27 | int sys_write(int fd, const void* buf, size_t buf_len) { 28 | return (int)syscall(SN_WRITE, (uint64_t)fd, (uint64_t)buf, (uint64_t)buf_len, 0, 0, 0); 29 | } 30 | 31 | int sys_open(const char* filepath, int flags) { 32 | return (int)syscall(SN_OPEN, (uint64_t)filepath, (uint64_t)flags, 0, 0, 0, 0); 33 | } 34 | 35 | int sys_close(int fd) { 36 | return (int)syscall(SN_CLOSE, (uint64_t)fd, 0, 0, 0, 0, 0); 37 | } 38 | 39 | void sys_exit(int status) { 40 | syscall(SN_EXIT, (uint64_t)status, 0, 0, 0, 0, 0); 41 | } 42 | 43 | void* sys_sbrk(size_t len) { 44 | uint64_t addr = syscall(SN_SBRK, (uint64_t)len, 0, 0, 0, 0, 0); 45 | return (void*)addr; 46 | } 47 | 48 | int sys_uname(utsname* buf) { 49 | return (int)syscall(SN_UNAME, (uint64_t)buf, 0, 0, 0, 0, 0); 50 | } 51 | 52 | void sys_break(void) { 53 | syscall(SN_BREAK, 0, 0, 0, 0, 0, 0); 54 | } 55 | 56 | int sys_stat(int fd, f_stat* buf) { 57 | return (int)syscall(SN_STAT, (uint64_t)fd, (uint64_t)buf, 0, 0, 0, 0); 58 | } 59 | 60 | uint64_t sys_uptime(void) { 61 | return syscall(SN_UPTIME, 0, 0, 0, 0, 0, 0); 62 | } 63 | 64 | int sys_exec(const char* args, int flags) { 65 | return (int)syscall(SN_EXEC, (uint64_t)args, (uint64_t)flags, 0, 0, 0, 0); 66 | } 67 | 68 | int sys_getcwd(char* buf, size_t buf_len) { 69 | return (int)syscall(SN_GETCWD, (uint64_t)buf, (uint64_t)buf_len, 0, 0, 0, 0); 70 | } 71 | 72 | int sys_chdir(const char* path) { 73 | return (int)syscall(SN_CHDIR, (uint64_t)path, 0, 0, 0, 0, 0); 74 | } 75 | 76 | size_t sys_sbrksz(const void* target) { 77 | return (size_t)syscall(SN_SBRKSZ, (uint64_t)target, 0, 0, 0, 0, 0); 78 | } 79 | 80 | int sys_getenames(const char* path, char* buf, size_t buf_len) { 81 | return (int)syscall(SN_GETENAMES, (uint64_t)path, (uint64_t)buf, (uint64_t)buf_len, 0, 0, 0); 82 | } 83 | 84 | int sys_iomsg(const void* msgbuf, void* replymsgbuf, size_t replymsgbuf_len) { 85 | return (int)syscall(SN_IOMSG, (uint64_t)msgbuf, (uint64_t)replymsgbuf, (uint64_t)replymsgbuf_len, 0, 0, 0); 86 | } 87 | 88 | int sys_socket(int domain, int type, int protocol) { 89 | return (int)syscall(SN_SOCKET, (uint64_t)domain, (uint64_t)type, (uint64_t)protocol, 0, 0, 0); 90 | } 91 | 92 | int sys_bind(int sockfd, const struct sockaddr* addr, size_t addrlen) { 93 | return (int)syscall(SN_BIND, (uint64_t)sockfd, (uint64_t)addr, (uint64_t)addrlen, 0, 0, 0); 94 | } 95 | 96 | int sys_sendto(int sockfd, const void* buf, size_t len, int flags, const struct sockaddr* dest_addr, size_t addrlen) { 97 | return (int)syscall(SN_SENDTO, (uint64_t)sockfd, (uint64_t)buf, (uint64_t)len, (uint64_t)flags, (uint64_t)dest_addr, (uint64_t)addrlen); 98 | } 99 | 100 | int sys_recvfrom(int sockfd, void* buf, size_t len, int flags, struct sockaddr* src_addr, size_t addrlen) { 101 | return (int)syscall(SN_RECVFROM, (uint64_t)sockfd, (uint64_t)buf, (uint64_t)len, (uint64_t)flags, (uint64_t)src_addr, (uint64_t)addrlen); 102 | } 103 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/registers/control.rs: -------------------------------------------------------------------------------- 1 | use super::Register; 2 | use core::arch::asm; 3 | 4 | // https://en.wikipedia.org/wiki/Control_register 5 | #[derive(Debug, Clone, Copy)] 6 | pub struct Cr0(u64); 7 | impl Register for Cr0 { 8 | fn read() -> Self { 9 | let cr0; 10 | 11 | unsafe { 12 | asm!("mov {}, cr0", out(reg) cr0, options(nomem, nostack)); 13 | } 14 | 15 | Self(cr0) 16 | } 17 | 18 | fn write(&self) { 19 | unsafe { 20 | asm!("mov cr0, {}", in(reg) self.0, options(nomem, nostack)); 21 | } 22 | } 23 | 24 | fn raw(&self) -> u64 { 25 | self.0 26 | } 27 | 28 | fn set_raw(&mut self, value: u64) { 29 | self.0 = value; 30 | } 31 | } 32 | 33 | impl Cr0 { 34 | pub fn set_paging(&mut self, value: bool) { 35 | self.0 = (self.0 & !0x8000_0000) | ((value as u64) << 31); 36 | } 37 | 38 | pub fn set_emulation(&mut self, value: bool) { 39 | self.0 = (self.0 & !0x04) | ((value as u64) << 2); 40 | } 41 | 42 | pub fn set_monitor_coprocessor(&mut self, value: bool) { 43 | self.0 = (self.0 & !0x02) | ((value as u64) << 1); 44 | } 45 | 46 | pub fn paging(&self) -> bool { 47 | (self.0 & 0x8000_0000) != 0 48 | } 49 | 50 | pub fn emulation(&self) -> bool { 51 | (self.0 & 0x04) != 0 52 | } 53 | 54 | pub fn monitor_coprocessor(&self) -> bool { 55 | (self.0 & 0x02) != 0 56 | } 57 | } 58 | 59 | pub struct Cr2(u64); 60 | 61 | impl Register for Cr2 { 62 | fn read() -> Self { 63 | let cr2; 64 | unsafe { 65 | asm!("mov {}, cr2", out(reg) cr2, options(nomem, nostack)); 66 | } 67 | 68 | Self(cr2) 69 | } 70 | 71 | fn write(&self) { 72 | unsafe { 73 | asm!("mov cr2, {}", in(reg) self.0, options(nomem, nostack)); 74 | } 75 | } 76 | 77 | fn raw(&self) -> u64 { 78 | self.0 79 | } 80 | 81 | fn set_raw(&mut self, value: u64) { 82 | self.0 = value; 83 | } 84 | } 85 | 86 | #[derive(Debug)] 87 | pub struct Cr3(u64); 88 | 89 | impl Register for Cr3 { 90 | fn read() -> Self { 91 | let cr3; 92 | unsafe { 93 | asm!("mov {}, cr3", out(reg) cr3, options(nomem, nostack)); 94 | } 95 | 96 | Self(cr3) 97 | } 98 | 99 | fn write(&self) { 100 | assert_eq!(self.raw() & 0xfff, 0, "CR3 must be 4KB aligned"); 101 | 102 | unsafe { 103 | asm!("mov cr3, {}", in(reg) self.0, options(nomem, nostack)); 104 | } 105 | } 106 | 107 | fn raw(&self) -> u64 { 108 | self.0 109 | } 110 | 111 | fn set_raw(&mut self, value: u64) { 112 | self.0 = value; 113 | } 114 | } 115 | 116 | #[derive(Debug)] 117 | pub struct Cr4(u64); 118 | 119 | impl Register for Cr4 { 120 | fn read() -> Self { 121 | let cr4; 122 | unsafe { 123 | asm!("mov {}, cr4", out(reg) cr4, options(nomem, nostack)); 124 | } 125 | 126 | Self(cr4) 127 | } 128 | 129 | fn write(&self) { 130 | unsafe { 131 | asm!("mov cr4, {}", in(reg) self.0, options(nomem, nostack)); 132 | } 133 | } 134 | 135 | fn raw(&self) -> u64 { 136 | self.0 137 | } 138 | 139 | fn set_raw(&mut self, value: u64) { 140 | self.0 = value; 141 | } 142 | } 143 | 144 | impl Cr4 { 145 | pub fn set_osfxsr(&mut self, value: bool) { 146 | self.0 = (self.0 & !0x200) | ((value as u64) << 9); 147 | } 148 | 149 | pub fn set_osxmmexcept(&mut self, value: bool) { 150 | self.0 = (self.0 & !0x400) | ((value as u64) << 10); 151 | } 152 | 153 | pub fn osfxsr(&self) -> bool { 154 | (self.0 & 0x200) != 0 155 | } 156 | 157 | pub fn osxmmexcept(&self) -> bool { 158 | (self.0 & 0x400) != 0 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /apps/sh/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define BUF_LEN 128 8 | 9 | static char buf[BUF_LEN] = {0}; 10 | static char* splitted_buf[BUF_LEN]; 11 | static char cwd_path[BUF_LEN] = {0}; 12 | static char envpath[BUF_LEN] = {0}; 13 | static char filepath_buf[BUF_LEN] = {0}; 14 | 15 | void exec_cmd(char* cmd) { 16 | int cmdargs_len = split(cmd, ' ', splitted_buf, BUF_LEN); 17 | 18 | if (cmdargs_len < 1) { 19 | return; 20 | } 21 | 22 | if (strlen(splitted_buf[0]) == 0) { 23 | return; 24 | } 25 | 26 | if (strcmp(splitted_buf[0], "help") == 0) { 27 | printf("sh: Built-in commands:\n"); 28 | printf(" help\n"); 29 | printf(" exit\n"); 30 | printf(" break\n"); 31 | printf(" exec\n"); 32 | printf(" window\n"); 33 | printf(" clear\n"); 34 | 35 | if (strlen(envpath) > 0) { 36 | printf("sh: envpath available\n"); 37 | printf(" is alias for \"exec %s/\"\n", envpath); 38 | } 39 | } else if (strcmp(splitted_buf[0], "exit") == 0) { 40 | exit(0); 41 | } else if (strcmp(splitted_buf[0], "break") == 0) { 42 | sys_break(); 43 | // __asm__ volatile("int3"); 44 | } else if (strcmp(splitted_buf[0], "exec") == 0) { 45 | if (cmdargs_len < 2) { 46 | printf("sh: exec: missing argument\n"); 47 | return; 48 | } 49 | 50 | char* args = splitted_buf[1]; 51 | if (cmdargs_len > 2) { 52 | args = concatenate((const char**)(splitted_buf + 1), cmdargs_len - 1, " "); 53 | 54 | if (args == NULL) { 55 | printf("sh: exec: failed to concatenate arguments\n"); 56 | return; 57 | } 58 | } 59 | 60 | if (sys_exec(args, EXEC_FLAG_DEBUG) == -1) { 61 | printf("sh: exec: failed to execute\n"); 62 | return; 63 | } 64 | } else if (strcmp(splitted_buf[0], "window") == 0) { 65 | component_descriptor* cdesc = create_component_window("test window", 200, 50, 300, 200); 66 | if (cdesc == NULL) { 67 | printf("sh: window: failed to create window\n"); 68 | return; 69 | } 70 | } else if (strcmp(splitted_buf[0], "clear") == 0) { 71 | printf("\e[2J"); 72 | printf("\e[1;1H"); 73 | } 74 | // execute command with envpath 75 | else if (strlen(envpath) > 0) { 76 | snprintf(filepath_buf, sizeof(filepath_buf), "%s/%s", envpath, splitted_buf[0]); 77 | splitted_buf[0] = filepath_buf; 78 | char* args = splitted_buf[0]; 79 | if (cmdargs_len > 1) { 80 | args = concatenate((const char**)splitted_buf, cmdargs_len, " "); 81 | 82 | if (args == NULL) { 83 | printf("sh: exec: failed to concatenate arguments\n"); 84 | return; 85 | } 86 | } 87 | 88 | if (sys_exec(args, EXEC_FLAG_NONE) == -1) { 89 | printf("sh: exec: failed to execute\n"); 90 | return; 91 | } 92 | } 93 | // unreachable 94 | else { 95 | printf("sh: %s: command not found\n", cmd); 96 | } 97 | } 98 | 99 | int main(int argc, char const* argv[]) { 100 | int getcwd_ret; 101 | 102 | if (argc > 1) { 103 | strncpy(envpath, argv[1], strlen(argv[1])); 104 | printf("sh: set envpath: %s\n", envpath); 105 | } 106 | 107 | while (1) { 108 | getcwd_ret = sys_getcwd(cwd_path, sizeof(cwd_path)); 109 | printf("\n\e[34m[%s]\e[m$ ", getcwd_ret == -1 ? "UNKNOWN" : cwd_path); 110 | 111 | if (sys_read(0, buf, BUF_LEN) == -1) { 112 | printf("Failed to read stdin\n"); 113 | return -1; 114 | } 115 | 116 | replace(buf, '\n', '\0'); 117 | exec_cmd(buf); 118 | } 119 | 120 | return 0; 121 | } 122 | -------------------------------------------------------------------------------- /kernel/src/arch/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::{error::Result, mem::paging}; 2 | 3 | pub mod x86_64; 4 | 5 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] 6 | #[repr(transparent)] 7 | pub struct PhysicalAddress(u64); 8 | 9 | impl PhysicalAddress { 10 | pub fn new(addr: u64) -> Self { 11 | Self(addr) 12 | } 13 | 14 | pub fn get(&self) -> u64 { 15 | self.0 16 | } 17 | 18 | pub fn set(&mut self, addr: u64) { 19 | self.0 = addr; 20 | } 21 | 22 | pub fn offset(&self, offset: usize) -> Self { 23 | Self::new(self.0 + offset as u64) 24 | } 25 | 26 | pub fn get_virt_addr(&self) -> Result { 27 | paging::calc_virt_addr(*self) 28 | } 29 | } 30 | 31 | impl From for PhysicalAddress { 32 | fn from(addr: u64) -> Self { 33 | Self::new(addr) 34 | } 35 | } 36 | 37 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] 38 | #[repr(transparent)] 39 | pub struct VirtualAddress(u64); 40 | 41 | impl VirtualAddress { 42 | pub fn new(addr: u64) -> Self { 43 | Self(addr) 44 | } 45 | 46 | pub fn get(&self) -> u64 { 47 | self.0 48 | } 49 | 50 | pub fn set(&mut self, addr: u64) { 51 | self.0 = addr; 52 | } 53 | 54 | pub fn offset(&self, offset: usize) -> Self { 55 | Self::new(self.0 + offset as u64) 56 | } 57 | 58 | pub fn get_phys_addr(&self) -> Result { 59 | paging::calc_phys_addr(*self) 60 | } 61 | 62 | pub fn get_pml4_entry_index(&self) -> usize { 63 | ((self.0 >> 39) & 0x1ff) as usize 64 | } 65 | 66 | pub fn get_pml3_entry_index(&self) -> usize { 67 | ((self.0 >> 30) & 0x1ff) as usize 68 | } 69 | 70 | pub fn get_pml2_entry_index(&self) -> usize { 71 | ((self.0 >> 21) & 0x1ff) as usize 72 | } 73 | 74 | pub fn get_pml1_entry_index(&self) -> usize { 75 | ((self.0 >> 12) & 0x1ff) as usize 76 | } 77 | 78 | pub fn get_page_offset(&self) -> usize { 79 | (self.0 & 0xfff) as usize 80 | } 81 | 82 | pub fn as_ptr(&self) -> *const T { 83 | self.get() as *const T 84 | } 85 | 86 | pub fn as_ptr_mut(&self) -> *mut T { 87 | self.get() as *mut T 88 | } 89 | 90 | pub fn copy_from_nonoverlapping(&self, src: *const T, count: usize) { 91 | unsafe { self.as_ptr_mut::().copy_from_nonoverlapping(src, count) } 92 | } 93 | } 94 | 95 | impl From for VirtualAddress { 96 | fn from(addr: u64) -> Self { 97 | Self::new(addr) 98 | } 99 | } 100 | 101 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] 102 | #[repr(transparent)] 103 | pub struct IoPortAddress(u32); 104 | 105 | impl IoPortAddress { 106 | pub const fn new(addr: u32) -> Self { 107 | Self(addr) 108 | } 109 | 110 | pub fn offset(&self, offset: usize) -> Self { 111 | Self::new(self.0 + offset as u32) 112 | } 113 | 114 | pub fn out8(&self, value: u8) { 115 | assert!(self.0 <= u16::MAX as u32); 116 | x86_64::out8(self.0 as u16, value); 117 | } 118 | 119 | pub fn in8(&self) -> u8 { 120 | assert!(self.0 <= u16::MAX as u32); 121 | x86_64::in8(self.0 as u16) 122 | } 123 | 124 | pub fn out16(&self, value: u16) { 125 | assert!(self.0 <= u16::MAX as u32); 126 | x86_64::out16(self.0 as u16, value); 127 | } 128 | 129 | pub fn in16(&self) -> u16 { 130 | assert!(self.0 <= u16::MAX as u32); 131 | x86_64::in16(self.0 as u16) 132 | } 133 | 134 | pub fn out32(&self, value: u32) { 135 | x86_64::out32(self.0, value); 136 | } 137 | 138 | pub fn in32(&self) -> u32 { 139 | x86_64::in32(self.0) 140 | } 141 | } 142 | 143 | impl From for IoPortAddress { 144 | fn from(addr: u16) -> Self { 145 | Self::new(addr as u32) 146 | } 147 | } 148 | 149 | impl From for IoPortAddress { 150 | fn from(addr: u32) -> Self { 151 | Self::new(addr) 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/mod.rs: -------------------------------------------------------------------------------- 1 | use core::arch::asm; 2 | 3 | pub mod acpi; 4 | pub mod apic; 5 | pub mod context; 6 | pub mod cpu; 7 | pub mod gdt; 8 | pub mod idt; 9 | pub mod registers; 10 | pub mod tsc; 11 | pub mod tss; 12 | 13 | #[repr(C, packed(2))] 14 | #[derive(Debug, Default)] 15 | pub struct DescriptorTableArgs { 16 | pub limit: u16, 17 | pub base: u64, 18 | } 19 | 20 | pub fn stihlt() { 21 | unsafe { asm!("sti", "hlt", options(nomem, nostack)) } 22 | } 23 | 24 | pub fn disabled_int R, R>(mut func: F) -> R { 25 | unsafe { asm!("cli", options(nomem, nostack)) }; 26 | let func_res = func(); 27 | unsafe { asm!("sti", options(nomem, nostack)) }; 28 | func_res 29 | } 30 | 31 | pub fn int3() { 32 | unsafe { asm!("int3", options(nomem, nostack)) } 33 | } 34 | 35 | pub fn out8(port: u16, data: u8) { 36 | unsafe { 37 | asm!( 38 | "out dx, al", 39 | in("dx") port, 40 | in("al") data, 41 | options(nomem, nostack) 42 | ); 43 | } 44 | } 45 | 46 | pub fn in8(port: u16) -> u8 { 47 | let data: u8; 48 | unsafe { 49 | asm!( 50 | "in al, dx", 51 | out("al") data, 52 | in("dx") port, 53 | options(nomem, nostack) 54 | ); 55 | } 56 | data 57 | } 58 | 59 | pub fn out16(port: u16, data: u16) { 60 | unsafe { 61 | asm!( 62 | "out dx, ax", 63 | in("dx") port, 64 | in("ax") data, 65 | options(nomem, nostack) 66 | ); 67 | } 68 | } 69 | 70 | pub fn in16(port: u16) -> u16 { 71 | let data: u16; 72 | unsafe { 73 | asm!( 74 | "in ax, dx", 75 | out("ax") data, 76 | in("dx") port, 77 | options(nomem, nostack) 78 | ); 79 | } 80 | data 81 | } 82 | 83 | pub fn out32(port: u32, data: u32) { 84 | unsafe { 85 | asm!( 86 | "out dx, eax", 87 | in("edx") port, 88 | in("eax") data, 89 | options(nomem, nostack) 90 | ); 91 | } 92 | } 93 | 94 | pub fn in32(port: u32) -> u32 { 95 | let data: u32; 96 | unsafe { 97 | asm!( 98 | "in eax, dx", 99 | out("eax") data, 100 | in("edx") port, 101 | options(nomem, nostack) 102 | ); 103 | } 104 | data 105 | } 106 | 107 | pub fn lidt(desc_table_args: &DescriptorTableArgs) { 108 | unsafe { 109 | asm!("lidt [{}]", in(reg) desc_table_args, options(nomem, nostack)); 110 | } 111 | } 112 | 113 | pub fn lgdt(desc_table_args: &DescriptorTableArgs) { 114 | unsafe { 115 | asm!("lgdt [{}]", in(reg) desc_table_args, options(nomem, nostack)); 116 | } 117 | } 118 | 119 | pub fn ltr(sel: u16) { 120 | unsafe { 121 | asm!("ltr cx", in("cx") sel, options(nomem, nostack)); 122 | } 123 | } 124 | 125 | pub fn read_msr(addr: u32) -> u64 { 126 | let low: u32; 127 | let high: u32; 128 | 129 | unsafe { 130 | asm!("rdmsr", in("ecx") addr, out("eax") low, out("edx") high, options(nomem, nostack)); 131 | } 132 | 133 | ((high as u64) << 32) | (low as u64) 134 | } 135 | 136 | pub fn write_msr(addr: u32, value: u64) { 137 | let low = value as u32; 138 | let high = (value >> 32) as u32; 139 | 140 | unsafe { 141 | asm!("wrmsr", in("ecx") addr, in("eax") low, in("edx") high, options(nomem, nostack)); 142 | } 143 | } 144 | 145 | pub fn read_xcr0() -> u64 { 146 | let value; 147 | unsafe { 148 | asm!("xgetbv", out("rax") value, options(nomem, nostack)); 149 | } 150 | value 151 | } 152 | 153 | pub fn write_xcr0(value: u64) { 154 | unsafe { 155 | asm!("xsetbv", in("rax") value, options(nomem, nostack)); 156 | } 157 | } 158 | 159 | pub fn rdtsc() -> u64 { 160 | let low: u32; 161 | let high: u32; 162 | 163 | unsafe { 164 | asm!("rdtsc", out("eax") low, out("edx") high, options(nomem, nostack)); 165 | } 166 | 167 | ((high as u64) << 32) | (low as u64) 168 | } 169 | -------------------------------------------------------------------------------- /kernel/src/debug/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | arch::x86_64::{self, idt::InterruptStackFrame}, 3 | debug::dwarf::Dwarf, 4 | device::tty, 5 | error::Result, 6 | print, println, 7 | }; 8 | use alloc::string::ToString; 9 | 10 | pub mod dwarf; 11 | pub mod logger; 12 | pub mod qemu; 13 | 14 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 15 | pub enum DebuggerResult { 16 | Continue, 17 | Step, 18 | Quit, 19 | } 20 | 21 | pub fn user_app_debugger( 22 | stack_frame: &InterruptStackFrame, 23 | dwarf: &Dwarf, 24 | ) -> Result { 25 | let ip = stack_frame.ins_ptr; 26 | 27 | if let Some(info) = dwarf.find_debug_info_by_ip(ip) { 28 | let mut function_name = None; 29 | let mut file_name = None; 30 | let mut dir_name = None; 31 | 32 | for (_, debug_abbrevs) in info { 33 | for debug_abbrev in debug_abbrevs { 34 | if !debug_abbrev.is_contains_by_ip(ip) { 35 | continue; 36 | } 37 | 38 | match debug_abbrev.tag { 39 | dwarf::AbbrevTag::CompileUnit => { 40 | for (attr, form) in &debug_abbrev.attributes { 41 | match (attr, form) { 42 | ( 43 | dwarf::AbbrevAttribute::Name, 44 | dwarf::AbbrevForm::LineStrp(name), 45 | ) => { 46 | file_name = Some(name.as_str()); 47 | } 48 | ( 49 | dwarf::AbbrevAttribute::CompDir, 50 | dwarf::AbbrevForm::LineStrp(name), 51 | ) => { 52 | dir_name = Some(name.as_str()); 53 | } 54 | _ => (), 55 | } 56 | } 57 | } 58 | dwarf::AbbrevTag::Subprogram => { 59 | for (attr, form) in &debug_abbrev.attributes { 60 | match (attr, form) { 61 | (dwarf::AbbrevAttribute::Name, dwarf::AbbrevForm::Strp(name)) => { 62 | function_name = Some(name.as_str()); 63 | } 64 | _ => (), 65 | } 66 | } 67 | } 68 | _ => (), 69 | } 70 | } 71 | } 72 | 73 | let file_path = file_name.and_then(|name| dir_name.map(|dir| format!("{}/{}", dir, name))); 74 | 75 | println!( 76 | "0x{:x} in {} at {}", 77 | ip, 78 | function_name.unwrap_or(""), 79 | file_path.unwrap_or("".to_string()) 80 | ); 81 | } else { 82 | println!("0x{:x} in at ", ip); 83 | } 84 | 85 | let result; 86 | 87 | loop { 88 | print!("(dbg) "); 89 | let mut input_s = None; 90 | while input_s.is_none() { 91 | if let Ok(s) = x86_64::disabled_int(|| tty::get_line()) { 92 | input_s = s; 93 | } else { 94 | x86_64::stihlt(); 95 | } 96 | } 97 | 98 | match input_s.unwrap().as_str().trim() { 99 | "q" => { 100 | result = DebuggerResult::Quit; 101 | break; 102 | } 103 | "c" => { 104 | result = DebuggerResult::Continue; 105 | break; 106 | } 107 | "s" => { 108 | result = DebuggerResult::Step; 109 | break; 110 | } 111 | s => { 112 | println!("Invalid command: {:?}", s); 113 | continue; 114 | } 115 | } 116 | } 117 | 118 | Ok(result) 119 | } 120 | -------------------------------------------------------------------------------- /kernel/src/net/arp.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | error::{Error, Result}, 3 | net::eth::*, 4 | }; 5 | use alloc::vec::Vec; 6 | use core::{fmt::Debug, net::Ipv4Addr}; 7 | 8 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 9 | pub enum ArpOperation { 10 | Request, 11 | Reply, 12 | } 13 | 14 | impl From for [u8; 2] { 15 | fn from(value: ArpOperation) -> [u8; 2] { 16 | match value { 17 | ArpOperation::Request => [0, 1], 18 | ArpOperation::Reply => [0, 2], 19 | } 20 | } 21 | } 22 | 23 | impl TryFrom<[u8; 2]> for ArpOperation { 24 | type Error = Error; 25 | 26 | fn try_from(value: [u8; 2]) -> Result { 27 | match value { 28 | [0, 1] => Ok(ArpOperation::Request), 29 | [0, 2] => Ok(ArpOperation::Reply), 30 | _ => Err(Error::Failed("Invalid ARP operation")), 31 | } 32 | } 33 | } 34 | 35 | #[derive(Debug, Clone, Copy)] 36 | pub struct ArpPacket { 37 | hardware_ty: [u8; 2], // must be [0, 1] 38 | protocol_ty: EthernetType, 39 | hardware_len: u8, // must be 6 40 | protocol_len: u8, // must be 4 41 | op: [u8; 2], 42 | pub sender_eth_addr: EthernetAddress, 43 | pub sender_ipv4_addr: Ipv4Addr, 44 | pub target_eth_addr: EthernetAddress, 45 | pub target_ipv4_addr: Ipv4Addr, 46 | } 47 | 48 | impl TryFrom<&[u8]> for ArpPacket { 49 | type Error = Error; 50 | 51 | fn try_from(data: &[u8]) -> Result { 52 | if data.len() < 28 { 53 | return Err(Error::Failed("Invalid data length")); 54 | } 55 | 56 | let hardware_ty = [data[0], data[1]]; 57 | let protocol_ty = EthernetType::from([data[2], data[3]]); 58 | let hardware_len = data[4]; 59 | let protocol_len = data[5]; 60 | let op = [data[6], data[7]]; 61 | let sender_eth_addr = 62 | EthernetAddress::from([data[8], data[9], data[10], data[11], data[12], data[13]]); 63 | let sender_ipv4_addr = Ipv4Addr::new(data[14], data[15], data[16], data[17]); 64 | let target_eth_addr = 65 | EthernetAddress::from([data[18], data[19], data[20], data[21], data[22], data[23]]); 66 | let target_ipv4_addr = Ipv4Addr::new(data[24], data[25], data[26], data[27]); 67 | 68 | Ok(Self { 69 | hardware_ty, 70 | protocol_ty, 71 | hardware_len, 72 | protocol_len, 73 | op, 74 | sender_eth_addr, 75 | sender_ipv4_addr, 76 | target_eth_addr, 77 | target_ipv4_addr, 78 | }) 79 | } 80 | } 81 | 82 | impl ArpPacket { 83 | pub fn new_with( 84 | op: ArpOperation, 85 | sender_eth_addr: EthernetAddress, 86 | sender_ipv4_addr: Ipv4Addr, 87 | target_eth_addr: EthernetAddress, 88 | target_ipv4_addr: Ipv4Addr, 89 | ) -> Self { 90 | Self { 91 | hardware_ty: [0, 1], 92 | protocol_ty: EthernetType::Ipv4, 93 | hardware_len: 6, 94 | protocol_len: 4, 95 | op: op.into(), 96 | sender_eth_addr, 97 | sender_ipv4_addr, 98 | target_eth_addr, 99 | target_ipv4_addr, 100 | } 101 | } 102 | 103 | pub fn op(&self) -> Result { 104 | ArpOperation::try_from(self.op) 105 | } 106 | 107 | pub fn to_vec(&self) -> Vec { 108 | let protocol_ty: [u8; 2] = self.protocol_ty.into(); 109 | let sender_eth_addr: [u8; 6] = self.sender_eth_addr.into(); 110 | let target_eth_addr: [u8; 6] = self.target_eth_addr.into(); 111 | 112 | let mut vec = Vec::new(); 113 | vec.extend_from_slice(&self.hardware_ty); 114 | vec.extend_from_slice(&protocol_ty); 115 | vec.push(self.hardware_len); 116 | vec.push(self.protocol_len); 117 | vec.extend_from_slice(&self.op); 118 | vec.extend_from_slice(&sender_eth_addr); 119 | vec.extend_from_slice(&self.sender_ipv4_addr.octets()); 120 | vec.extend_from_slice(&target_eth_addr); 121 | vec.extend_from_slice(&self.target_ipv4_addr.octets()); 122 | vec 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /kernel/src/device/speaker.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | arch::x86_64, 3 | device::{DeviceDriverFunction, DeviceDriverInfo}, 4 | error::Result, 5 | fs::vfs, 6 | kinfo, util, 7 | }; 8 | use alloc::vec::Vec; 9 | use core::time::Duration; 10 | 11 | static mut SPEAKER_DRIVER: SpeakerDriver = SpeakerDriver::new(); 12 | 13 | struct SpeakerDriver { 14 | device_driver_info: DeviceDriverInfo, 15 | } 16 | 17 | // https://wiki.osdev.org/PC_Speaker 18 | impl SpeakerDriver { 19 | const PIT_BASE_FREQ: u32 = 1193182; 20 | const PORT_PIT_CTRL: u16 = 0x43; 21 | const PORT_TIMER2_CTRL: u16 = 0x42; 22 | const TIMER2_SELECT: u8 = 0x80; 23 | const WRITE_WORD: u8 = 0x30; 24 | const MODE_SQUARE_WAVE: u8 = 0x06; 25 | 26 | const fn new() -> Self { 27 | Self { 28 | device_driver_info: DeviceDriverInfo::new("speaker"), 29 | } 30 | } 31 | 32 | fn play(&self, freq: u32) { 33 | let div = (Self::PIT_BASE_FREQ / freq) as u16; 34 | 35 | x86_64::out8( 36 | Self::PORT_PIT_CTRL, 37 | Self::TIMER2_SELECT | Self::WRITE_WORD | Self::MODE_SQUARE_WAVE, 38 | ); 39 | x86_64::out8(Self::PORT_TIMER2_CTRL, div as u8); 40 | 41 | x86_64::out8(Self::PORT_TIMER2_CTRL, (div >> 8) as u8); 42 | x86_64::out8(Self::PORT_TIMER2_CTRL, div as u8); 43 | 44 | x86_64::out8(0x61, x86_64::in8(0x61) | 3); 45 | } 46 | 47 | fn stop(&self) { 48 | x86_64::out8(0x61, x86_64::in8(0x61) & !3); 49 | } 50 | } 51 | 52 | impl DeviceDriverFunction for SpeakerDriver { 53 | type AttachInput = (); 54 | type PollNormalOutput = (); 55 | type PollInterruptOutput = (); 56 | 57 | fn get_device_driver_info(&self) -> Result { 58 | Ok(self.device_driver_info.clone()) 59 | } 60 | 61 | fn probe(&mut self) -> Result<()> { 62 | Ok(()) 63 | } 64 | 65 | fn attach(&mut self, _arg: Self::AttachInput) -> Result<()> { 66 | let dev_desc = vfs::DeviceFileDescriptor { 67 | get_device_driver_info, 68 | open, 69 | close, 70 | read, 71 | write, 72 | }; 73 | vfs::add_dev_file(dev_desc, self.device_driver_info.name)?; 74 | self.device_driver_info.attached = true; 75 | Ok(()) 76 | } 77 | 78 | fn poll_normal(&mut self) -> Result { 79 | unimplemented!() 80 | } 81 | 82 | fn poll_int(&mut self) -> Result { 83 | unimplemented!() 84 | } 85 | 86 | fn open(&mut self) -> Result<()> { 87 | unimplemented!() 88 | } 89 | 90 | fn close(&mut self) -> Result<()> { 91 | unimplemented!() 92 | } 93 | 94 | fn read(&mut self) -> Result> { 95 | unimplemented!() 96 | } 97 | 98 | fn write(&mut self, _data: &[u8]) -> Result<()> { 99 | unimplemented!() 100 | } 101 | } 102 | 103 | pub fn get_device_driver_info() -> Result { 104 | unsafe { SPEAKER_DRIVER.get_device_driver_info() } 105 | } 106 | 107 | pub fn probe_and_attach() -> Result<()> { 108 | unsafe { 109 | SPEAKER_DRIVER.probe()?; 110 | SPEAKER_DRIVER.attach(())?; 111 | kinfo!("{}: Attached!", get_device_driver_info()?.name); 112 | } 113 | 114 | Ok(()) 115 | } 116 | 117 | pub fn open() -> Result<()> { 118 | unsafe { SPEAKER_DRIVER.open() } 119 | } 120 | 121 | pub fn close() -> Result<()> { 122 | unsafe { SPEAKER_DRIVER.close() } 123 | } 124 | 125 | pub fn read() -> Result> { 126 | unsafe { SPEAKER_DRIVER.read() } 127 | } 128 | 129 | pub fn write(data: &[u8]) -> Result<()> { 130 | unsafe { SPEAKER_DRIVER.write(data) } 131 | } 132 | 133 | pub fn play(freq: u32, duration: Duration) { 134 | unsafe { 135 | SPEAKER_DRIVER.play(freq); 136 | util::time::sleep(duration); 137 | SPEAKER_DRIVER.stop(); 138 | } 139 | } 140 | 141 | pub async fn play_async(freq: u32, duration: Duration) { 142 | unsafe { 143 | SPEAKER_DRIVER.play(freq); 144 | util::time::sleep_async(duration).await; 145 | SPEAKER_DRIVER.stop(); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /apps/imgvw/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | #[macro_use] 5 | extern crate alloc; 6 | 7 | use alloc::vec::Vec; 8 | use core::{convert::Infallible, time::Duration}; 9 | use embedded_graphics::{pixelcolor::Rgb888, prelude::*, primitives::*}; 10 | use libc_rs::*; 11 | use tinygif::Gif; 12 | 13 | const WIDTH: usize = 450; 14 | const HEIGHT: usize = 400; 15 | 16 | struct Framebuffer { 17 | fb: *mut u8, 18 | width: usize, 19 | height: usize, 20 | } 21 | 22 | impl Dimensions for Framebuffer { 23 | fn bounding_box(&self) -> Rectangle { 24 | Rectangle::new( 25 | Point::zero(), 26 | Size::new(self.width as u32, self.height as u32), 27 | ) 28 | } 29 | } 30 | 31 | impl DrawTarget for Framebuffer { 32 | type Color = Rgb888; 33 | type Error = Infallible; 34 | 35 | fn draw_iter(&mut self, pixels: I) -> core::result::Result<(), Self::Error> 36 | where 37 | I: IntoIterator>, 38 | { 39 | for Pixel(coord, color) in pixels { 40 | let x = coord.x as usize; 41 | let y = coord.y as usize; 42 | if x < self.width && y < self.height { 43 | let offset = (y * self.width + x) * 4; 44 | unsafe { 45 | let pixel_ptr = self.fb.add(offset); 46 | *pixel_ptr = color.b(); 47 | *pixel_ptr.add(1) = color.g(); 48 | *pixel_ptr.add(2) = color.r(); 49 | *pixel_ptr.add(3) = 0xff; // Alpha channel 50 | } 51 | } 52 | } 53 | 54 | Ok(()) 55 | } 56 | } 57 | 58 | #[no_mangle] 59 | pub unsafe fn _start() { 60 | let args = parse_args!(); 61 | 62 | if args.len() < 2 { 63 | println!("Usage: imgvw "); 64 | exit(-1); 65 | } 66 | 67 | // open file 68 | let file = match File::open(args[1]) { 69 | Ok(f) => f, 70 | Err(err) => { 71 | println!("Failed to open the file: {:?}", err); 72 | exit(-1); 73 | } 74 | }; 75 | 76 | // read file 77 | let mut buf: Vec = vec![0; file.size()]; 78 | if let Err(err) = file.read(buf.as_mut_slice()) { 79 | println!("Failed to read the file: {:?}", err); 80 | exit(-1); 81 | } 82 | 83 | let gif = match Gif::::from_slice(buf.as_slice()) { 84 | Ok(gif) => gif, 85 | Err(err) => { 86 | println!("Failed to parse GIF(RGB888): {:?}", err); 87 | exit(-1); 88 | } 89 | }; 90 | 91 | // create window 92 | let title = format!("{} - imgvw\0", args[1]); 93 | let cdesc_window = create_component_window( 94 | title.as_ptr() as *const _, 95 | 100, 96 | 100, 97 | WIDTH + 10, 98 | HEIGHT + 50, 99 | ); 100 | if cdesc_window.is_null() { 101 | println!("Failed to create component window"); 102 | exit(-1); 103 | } 104 | 105 | // initialize framebuffer 106 | let fb = malloc((WIDTH * HEIGHT * 4) as u64); 107 | if fb.is_null() { 108 | println!("Failed to allocate framebuffer memory"); 109 | exit(-1); 110 | } 111 | 112 | // create image to window 113 | let cdesc_image = 114 | create_component_image(cdesc_window, WIDTH, HEIGHT, PIXEL_FORMAT_BGRA as u8, fb); 115 | if cdesc_image.is_null() { 116 | println!("Failed to create component image"); 117 | exit(-1); 118 | } 119 | 120 | let mut eg_fb = Framebuffer { 121 | fb: fb as *mut u8, 122 | width: WIDTH, 123 | height: HEIGHT, 124 | }; 125 | 126 | loop { 127 | for frame in gif.frames() { 128 | frame.draw(&mut eg_fb).unwrap(); 129 | 130 | let uptime = unsafe { sys_uptime() }; 131 | let start = Duration::from_millis(uptime); 132 | 133 | // delay 134 | loop { 135 | let uptime = unsafe { sys_uptime() }; 136 | let now = Duration::from_millis(uptime); 137 | 138 | if (now - start).as_millis() > 50 { 139 | break; 140 | } 141 | } 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/registers/model_specific.rs: -------------------------------------------------------------------------------- 1 | use super::Register; 2 | use crate::arch::x86_64; 3 | 4 | const IA32_EFER_MSR_ADDR: u32 = 0xc0000080; 5 | const IA32_STAR_MSR_ADDR: u32 = 0xc0000081; 6 | const IA32_LSTAR_MSR_ADDR: u32 = 0xc0000082; 7 | const IA32_FMASK_MSR_ADDR: u32 = 0xc0000084; 8 | 9 | #[derive(Debug, Clone, Copy)] 10 | pub struct ExtendedFeatureEnableRegister(u64); 11 | 12 | impl Register for ExtendedFeatureEnableRegister { 13 | fn read() -> Self { 14 | Self(x86_64::read_msr(IA32_EFER_MSR_ADDR)) 15 | } 16 | 17 | fn write(&self) { 18 | x86_64::write_msr(IA32_EFER_MSR_ADDR, self.0) 19 | } 20 | 21 | fn raw(&self) -> u64 { 22 | self.0 23 | } 24 | 25 | fn set_raw(&mut self, value: u64) { 26 | self.0 = value; 27 | } 28 | } 29 | 30 | impl ExtendedFeatureEnableRegister { 31 | pub fn set_syscall_enable(&mut self, value: bool) { 32 | self.set_raw((self.raw() & !0x1) | (value as u64)); 33 | } 34 | 35 | pub fn syscall_enable(&self) -> bool { 36 | (self.raw() & 0x1) != 0 37 | } 38 | } 39 | 40 | #[derive(Debug, Clone, Copy)] 41 | pub struct LongModeSystemCallTargetAddressRegister(u64); 42 | 43 | impl Register for LongModeSystemCallTargetAddressRegister { 44 | fn read() -> Self { 45 | Self(x86_64::read_msr(IA32_LSTAR_MSR_ADDR)) 46 | } 47 | 48 | fn write(&self) { 49 | x86_64::write_msr(IA32_LSTAR_MSR_ADDR, self.0) 50 | } 51 | 52 | fn raw(&self) -> u64 { 53 | self.0 54 | } 55 | 56 | fn set_raw(&mut self, value: u64) { 57 | self.0 = value; 58 | } 59 | } 60 | 61 | impl LongModeSystemCallTargetAddressRegister { 62 | pub fn set_target_addr(&mut self, target_addr: u64) { 63 | self.0 = target_addr; 64 | } 65 | 66 | pub fn target_addr(&self) -> u64 { 67 | self.0 68 | } 69 | } 70 | 71 | #[derive(Debug, Clone, Copy)] 72 | pub struct SystemCallTargetAddressRegister(u64); 73 | 74 | impl Register for SystemCallTargetAddressRegister { 75 | fn read() -> Self { 76 | Self(x86_64::read_msr(IA32_STAR_MSR_ADDR)) 77 | } 78 | 79 | fn write(&self) { 80 | x86_64::write_msr(IA32_STAR_MSR_ADDR, self.0) 81 | } 82 | 83 | fn raw(&self) -> u64 { 84 | self.0 85 | } 86 | 87 | fn set_raw(&mut self, value: u64) { 88 | self.0 = value; 89 | } 90 | } 91 | 92 | impl SystemCallTargetAddressRegister { 93 | pub fn set_target_addr(&mut self, target_addr: u64) { 94 | self.0 = target_addr; 95 | } 96 | 97 | pub fn target_addr(&self) -> u64 { 98 | self.0 99 | } 100 | } 101 | 102 | #[derive(Debug, Clone, Copy)] 103 | pub struct SystemCallFlagMaskRegister(u64); 104 | 105 | impl Register for SystemCallFlagMaskRegister { 106 | fn read() -> Self { 107 | Self(x86_64::read_msr(IA32_FMASK_MSR_ADDR)) 108 | } 109 | 110 | fn write(&self) { 111 | x86_64::write_msr(IA32_FMASK_MSR_ADDR, self.0) 112 | } 113 | 114 | fn raw(&self) -> u64 { 115 | self.0 116 | } 117 | 118 | fn set_raw(&mut self, value: u64) { 119 | self.0 = value; 120 | } 121 | } 122 | 123 | impl SystemCallFlagMaskRegister { 124 | pub fn set_value(&mut self, value: u64) { 125 | self.0 = value; 126 | } 127 | 128 | pub fn value(&self) -> u64 { 129 | self.0 130 | } 131 | } 132 | 133 | pub struct Xcr0(u64); 134 | 135 | impl Register for Xcr0 { 136 | fn read() -> Self { 137 | Self(x86_64::read_xcr0()) 138 | } 139 | 140 | fn write(&self) { 141 | x86_64::write_xcr0(self.0) 142 | } 143 | 144 | fn raw(&self) -> u64 { 145 | self.0 146 | } 147 | 148 | fn set_raw(&mut self, value: u64) { 149 | self.0 = value; 150 | } 151 | } 152 | 153 | impl Xcr0 { 154 | pub fn set_sse(&mut self, value: bool) { 155 | self.0 = (self.0 & !0x2) | ((value as u64) << 1); 156 | } 157 | 158 | pub fn set_avx(&mut self, value: bool) { 159 | self.0 = (self.0 & !0x4) | ((value as u64) << 2); 160 | } 161 | 162 | pub fn sse(&self) -> bool { 163 | (self.0 & 0x2) != 0 164 | } 165 | 166 | pub fn avx(&self) -> bool { 167 | (self.0 & 0x4) != 0 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /apps/bfi/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define MEM_LEN 30000 6 | #define STACK_LEN 32 7 | 8 | static uint8_t mem[MEM_LEN] = {0}; 9 | static int stack[STACK_LEN] = {0}; 10 | 11 | int exec_bf(const char* bf_code) { 12 | int code_len = strlen(bf_code); 13 | char str[2]; 14 | // instruction pointer 15 | int ip = 0; 16 | // memory pointer 17 | int mp = 0; 18 | // stack pointer 19 | int sp = 0; 20 | 21 | while (1) { 22 | if (code_len <= ip) { 23 | break; 24 | } 25 | 26 | switch (bf_code[ip]) { 27 | // increment pointed value 28 | case '+': 29 | if (mem[mp] == UINT8_MAX) { 30 | printf("[ERR]Memory overflow\n"); 31 | return -1; 32 | } 33 | mem[mp]++; 34 | break; 35 | 36 | // decrement pointed value 37 | case '-': 38 | if (mem[mp] == 0) { 39 | printf("[ERR]Memory underflow\n"); 40 | return -1; 41 | } 42 | mem[mp]--; 43 | break; 44 | 45 | // output pointed value to ascii 46 | case '.': 47 | str[0] = (char)mem[mp]; 48 | str[1] = '\0'; 49 | printf("%s", str); 50 | break; 51 | 52 | // increment pointer 53 | case '>': 54 | // printf(">"); 55 | if (mp == MEM_LEN - 1) { 56 | printf("[ERR]Memory pointer overflow\n"); 57 | return -1; 58 | } 59 | mp++; 60 | break; 61 | 62 | // decrement pointer 63 | case '<': 64 | if (mp == 0) { 65 | printf("[ERR]Memory pointer underflow\n"); 66 | return -1; 67 | } 68 | mp--; 69 | break; 70 | 71 | // start loop 72 | case '[': 73 | stack[sp++] = ip; 74 | if (sp >= STACK_LEN) { 75 | printf("[ERR]Stack overflow\n"); 76 | return -1; 77 | } 78 | 79 | if (mem[mp] == 0) { 80 | while (1) { 81 | ip++; 82 | if (ip >= code_len) { 83 | printf("[ERR]Unmatched '['\n"); 84 | return -1; 85 | } 86 | if (bf_code[ip] == ']') { 87 | sp--; 88 | break; 89 | } else if (bf_code[ip] == '[') { 90 | sp++; 91 | break; 92 | } 93 | } 94 | } 95 | break; 96 | 97 | // end loop 98 | case ']': 99 | if (sp == 0) { 100 | printf("[ERR]Unmatched ']'\n"); 101 | return -1; 102 | } 103 | 104 | if (mem[mp] != 0) { 105 | ip = stack[sp - 1]; 106 | } else { 107 | sp--; 108 | } 109 | break; 110 | 111 | // skip 112 | case ' ': 113 | break; 114 | 115 | case ',': 116 | printf("[ERR]Unimplemented instruction\n"); 117 | return -1; 118 | 119 | default: 120 | printf("[ERR]Invalid instruction\n"); 121 | return -1; 122 | } 123 | 124 | ip++; 125 | } 126 | 127 | printf("\n"); 128 | return 0; 129 | } 130 | 131 | int main(int argc, char const* argv[]) { 132 | const char* bf_code = "++ ++ ++ ++[ > ++ ++[ > ++ > ++ + > ++ + > + < < < < -] > + > + >->> +[ < ] < -] >>.> -- -.++ ++ ++ +..++ +.>>.<-.<.++ +.-- -- --.-- -- -- --.>> +.>++."; 133 | 134 | if (argc > 1) { 135 | bf_code = argv[1]; 136 | } 137 | 138 | printf("Welcome to Brainf**k interpreter!\n"); 139 | printf("code: \"%s\"\n", bf_code); 140 | if (exec_bf(bf_code) == -1) { 141 | return -1; 142 | } 143 | 144 | return 0; 145 | } 146 | -------------------------------------------------------------------------------- /kernel/src/util/fifo.rs: -------------------------------------------------------------------------------- 1 | use crate::error::Result; 2 | use core::sync::atomic::{AtomicUsize, Ordering}; 3 | 4 | #[derive(Debug, Clone, Copy, PartialEq)] 5 | pub enum FifoError { 6 | BufferIsLocked, 7 | BufferIsFull, 8 | BufferIsEmpty, 9 | } 10 | 11 | #[derive(Debug)] 12 | #[repr(C, align(4096))] 13 | struct FifoInner([T; SIZE]); 14 | 15 | #[derive(Debug)] 16 | pub struct Fifo { 17 | buf: FifoInner, 18 | size: usize, 19 | read_ptr: AtomicUsize, 20 | write_ptr: AtomicUsize, 21 | } 22 | 23 | impl Fifo { 24 | pub const fn new(default: T) -> Self { 25 | Self { 26 | buf: FifoInner([default; SIZE]), 27 | size: SIZE, 28 | read_ptr: AtomicUsize::new(0), 29 | write_ptr: AtomicUsize::new(0), 30 | } 31 | } 32 | 33 | pub fn len(&self) -> usize { 34 | self.write_ptr.load(Ordering::Relaxed) 35 | } 36 | 37 | pub fn is_full(&self) -> bool { 38 | let read_ptr = self.read_ptr.load(Ordering::Relaxed); 39 | let write_ptr = self.write_ptr.load(Ordering::Relaxed); 40 | (write_ptr + 1) % self.size == read_ptr 41 | } 42 | 43 | pub fn reset_ptr(&self) { 44 | self.read_ptr.store(0, Ordering::Relaxed); 45 | self.write_ptr.store(0, Ordering::Relaxed); 46 | } 47 | 48 | pub fn get_read_write_ptr(&self) -> (usize, usize) { 49 | ( 50 | self.read_ptr.load(Ordering::Relaxed), 51 | self.write_ptr.load(Ordering::Relaxed), 52 | ) 53 | } 54 | 55 | pub fn enqueue(&mut self, value: T) -> Result<()> { 56 | let read_ptr = self.read_ptr.load(Ordering::Relaxed); 57 | let write_ptr = self.write_ptr.load(Ordering::Relaxed); 58 | let next_write_ptr = (write_ptr + 1) % self.size; 59 | 60 | if next_write_ptr == read_ptr { 61 | return Err(FifoError::BufferIsFull.into()); 62 | } 63 | 64 | if self 65 | .write_ptr 66 | .compare_exchange( 67 | write_ptr, 68 | next_write_ptr, 69 | Ordering::SeqCst, 70 | Ordering::SeqCst, 71 | ) 72 | .is_err() 73 | { 74 | return Err(FifoError::BufferIsLocked.into()); 75 | } 76 | 77 | self.buf.0[write_ptr] = value; 78 | 79 | Ok(()) 80 | } 81 | 82 | pub fn dequeue(&mut self) -> Result { 83 | let read_ptr = self.read_ptr.load(Ordering::Relaxed); 84 | let write_ptr = self.write_ptr.load(Ordering::Relaxed); 85 | let next_read_ptr = (read_ptr + 1) % self.size; 86 | 87 | if read_ptr == write_ptr { 88 | return Err(FifoError::BufferIsEmpty.into()); 89 | } 90 | 91 | if self 92 | .read_ptr 93 | .compare_exchange( 94 | read_ptr, 95 | next_read_ptr, 96 | Ordering::Acquire, 97 | Ordering::Relaxed, 98 | ) 99 | .is_err() 100 | { 101 | return Err(FifoError::BufferIsLocked.into()); 102 | } 103 | 104 | Ok(self.buf.0[read_ptr]) 105 | } 106 | 107 | pub fn get_buf_ref(&self) -> &[T; SIZE] { 108 | &self.buf.0 109 | } 110 | } 111 | 112 | #[test_case] 113 | fn test_new() { 114 | let fifo: Fifo = Fifo::new(0); 115 | assert_eq!(fifo.len(), 0); 116 | assert_eq!(fifo.get_read_write_ptr(), (0, 0)); 117 | } 118 | 119 | #[test_case] 120 | fn test_enqueue_dequeue() { 121 | let mut fifo: Fifo = Fifo::new(0); 122 | assert!(fifo.enqueue(1).is_ok()); 123 | assert!(fifo.enqueue(2).is_ok()); 124 | assert!(fifo.enqueue(3).is_ok()); 125 | assert!(fifo.enqueue(4).is_err()); 126 | 127 | assert_eq!(fifo.dequeue(), Ok(1)); 128 | assert_eq!(fifo.dequeue(), Ok(2)); 129 | assert_eq!(fifo.dequeue(), Ok(3)); 130 | assert!(fifo.dequeue().is_err()); 131 | } 132 | 133 | #[test_case] 134 | fn test_reset() { 135 | let mut fifo: Fifo = Fifo::new(0); 136 | fifo.enqueue(1).unwrap(); 137 | fifo.enqueue(2).unwrap(); 138 | fifo.enqueue(3).unwrap(); 139 | fifo.reset_ptr(); 140 | 141 | assert_eq!(fifo.get_read_write_ptr(), (0, 0)); 142 | assert!(fifo.dequeue().is_err()); 143 | } 144 | -------------------------------------------------------------------------------- /kernel/src/debug/logger.rs: -------------------------------------------------------------------------------- 1 | use crate::{graphics::frame_buf_console, print, theme::GLOBAL_THEME, util}; 2 | 3 | static mut LOGGER: SimpleLogger = SimpleLogger::new(LogLevel::max()); 4 | 5 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] 6 | pub enum LogLevel { 7 | Error, 8 | Warn, 9 | Info, 10 | Debug, 11 | Trace, 12 | } 13 | 14 | impl LogLevel { 15 | const fn max() -> Self { 16 | LogLevel::Trace 17 | } 18 | 19 | fn to_str(self) -> &'static str { 20 | match self { 21 | LogLevel::Error => "ERROR", 22 | LogLevel::Warn => " WARN", 23 | LogLevel::Info => " INFO", 24 | LogLevel::Debug => "DEBUG", 25 | LogLevel::Trace => "TRACE", 26 | } 27 | } 28 | } 29 | 30 | struct SimpleLogger { 31 | max_level: LogLevel, 32 | } 33 | 34 | impl SimpleLogger { 35 | const fn new(max_level: LogLevel) -> Self { 36 | Self { max_level } 37 | } 38 | 39 | fn enabled(&self, level: LogLevel) -> bool { 40 | level <= self.max_level 41 | } 42 | 43 | fn log(&self, level: LogLevel, args: core::fmt::Arguments, file: &str, line: u32, col: u32) { 44 | if !self.enabled(level) { 45 | return; 46 | } 47 | 48 | let fore_color = match level { 49 | LogLevel::Error => GLOBAL_THEME.log_color_error, 50 | LogLevel::Warn => GLOBAL_THEME.log_color_warn, 51 | LogLevel::Info => GLOBAL_THEME.log_color_info, 52 | LogLevel::Debug => GLOBAL_THEME.log_color_debug, 53 | LogLevel::Trace => GLOBAL_THEME.log_color_trace, 54 | }; 55 | 56 | let _ = frame_buf_console::set_fore_color(fore_color); 57 | 58 | let uptime = util::time::global_uptime(); 59 | if uptime.is_zero() { 60 | print!("[??????.???]"); 61 | } else { 62 | let ms = uptime.as_millis() as usize; 63 | print!("[{:06}.{:03}]", ms / 1000, ms % 1000); 64 | } 65 | 66 | print!("[{}]: ", level.to_str()); 67 | 68 | if level == LogLevel::Error { 69 | print!("{}@{}:{}: ", file, line, col); 70 | } 71 | 72 | print!("{:?}\n", args); 73 | 74 | let _ = frame_buf_console::reset_fore_color(); 75 | } 76 | } 77 | 78 | pub unsafe fn log(level: LogLevel, args: core::fmt::Arguments, file: &str, line: u32, col: u32) { 79 | LOGGER.log(level, args, file, line, col); 80 | } 81 | 82 | #[macro_export] 83 | macro_rules! kinfo { 84 | ($($arg:tt)*) => { 85 | unsafe { 86 | $crate::debug::logger::log( 87 | $crate::debug::logger::LogLevel::Info, 88 | format_args!($($arg)*), 89 | file!(), 90 | line!(), 91 | column!() 92 | ); 93 | } 94 | }; 95 | } 96 | 97 | #[macro_export] 98 | macro_rules! kdebug { 99 | ($($arg:tt)*) => { 100 | unsafe { 101 | $crate::debug::logger::log( 102 | $crate::debug::logger::LogLevel::Debug, 103 | format_args!($($arg)*), 104 | file!(), 105 | line!(), 106 | column!() 107 | ); 108 | } 109 | }; 110 | } 111 | 112 | #[macro_export] 113 | macro_rules! kwarn { 114 | ($($arg:tt)*) => { 115 | unsafe { 116 | $crate::debug::logger::log( 117 | $crate::debug::logger::LogLevel::Warn, 118 | format_args!($($arg)*), 119 | file!(), 120 | line!(), 121 | column!() 122 | ); 123 | } 124 | }; 125 | } 126 | 127 | #[macro_export] 128 | macro_rules! kerror { 129 | ($($arg:tt)*) => { 130 | unsafe { 131 | $crate::debug::logger::log( 132 | $crate::debug::logger::LogLevel::Error, 133 | format_args!($($arg)*), 134 | file!(), 135 | line!(), 136 | column!() 137 | ); 138 | } 139 | }; 140 | } 141 | 142 | #[macro_export] 143 | macro_rules! ktrace { 144 | ($($arg:tt)*) => { 145 | unsafe { 146 | $crate::debug::logger::log( 147 | $crate::debug::logger::LogLevel::Trace, 148 | format_args!($($arg)*), 149 | file!(), 150 | line!(), 151 | column!() 152 | ); 153 | } 154 | }; 155 | } 156 | -------------------------------------------------------------------------------- /kernel/src/fs/fat/dir_entry.rs: -------------------------------------------------------------------------------- 1 | use alloc::{string::String, vec::Vec}; 2 | 3 | #[derive(Debug, Clone, PartialEq, Eq)] 4 | #[repr(u8)] 5 | pub enum Attribute { 6 | ReadOnly = 0x01, 7 | Hidden = 0x02, 8 | System = 0x04, 9 | VolumeLabel = 0x08, 10 | LongFileName = 0x0f, 11 | Directory = 0x10, 12 | Archive = 0x20, 13 | Device = 0x40, 14 | } 15 | 16 | #[derive(Debug, PartialEq, Eq)] 17 | pub enum EntryType { 18 | Null, 19 | Unused, 20 | LongFileName, 21 | Data, 22 | } 23 | 24 | pub trait ShortFileNameEntry { 25 | fn sf_name(&self) -> Option; 26 | } 27 | 28 | pub trait LongFileNameEntry { 29 | fn lfn_entry_index(&self) -> Option; 30 | fn lf_name(&self) -> Option; 31 | } 32 | 33 | #[derive(Debug, Clone, Copy)] 34 | #[repr(C)] 35 | pub struct DirectoryEntry([u8; 32]); 36 | 37 | impl DirectoryEntry { 38 | pub fn raw(&self) -> &[u8; 32] { 39 | &self.0 40 | } 41 | 42 | pub fn attr(&self) -> Option { 43 | match self.raw()[11] { 44 | 0x01 => Some(Attribute::ReadOnly), 45 | 0x02 => Some(Attribute::Hidden), 46 | 0x04 => Some(Attribute::System), 47 | 0x08 => Some(Attribute::VolumeLabel), 48 | 0x0f => Some(Attribute::LongFileName), 49 | 0x10 => Some(Attribute::Directory), 50 | 0x20 => Some(Attribute::Archive), 51 | 0x40 => Some(Attribute::Device), 52 | _ => None, 53 | } 54 | } 55 | 56 | pub fn entry_type(&self) -> EntryType { 57 | match self.raw()[0] { 58 | 0x00 => return EntryType::Null, 59 | 0xe5 => return EntryType::Unused, 60 | _ => (), 61 | } 62 | 63 | match self.raw()[10] { 64 | 0x0f => EntryType::LongFileName, 65 | _ => EntryType::Data, 66 | } 67 | } 68 | 69 | pub fn first_cluster_num(&self) -> usize { 70 | let raw = self.raw(); 71 | 72 | ((u16::from_le_bytes([raw[20], raw[21]]) as u32) << 16 73 | | u16::from_le_bytes([raw[26], raw[27]]) as u32) as usize 74 | } 75 | 76 | // bytes 77 | pub fn file_size(&self) -> usize { 78 | let raw = self.raw(); 79 | u32::from_le_bytes([raw[28], raw[29], raw[30], raw[31]]) as usize 80 | } 81 | 82 | fn is_lf_name_entry(&self) -> bool { 83 | match self.attr() { 84 | Some(attr) => match attr { 85 | Attribute::LongFileName => true, 86 | _ => false, 87 | }, 88 | None => false, 89 | } 90 | } 91 | } 92 | 93 | impl ShortFileNameEntry for DirectoryEntry { 94 | fn sf_name(&self) -> Option { 95 | match self.attr() { 96 | Some(attr) => match attr { 97 | Attribute::Directory | Attribute::Archive | Attribute::VolumeLabel => (), 98 | _ => return None, 99 | }, 100 | None => return None, 101 | } 102 | 103 | Some(String::from_utf8_lossy(&self.raw()[0..11]).into_owned()) 104 | } 105 | } 106 | 107 | impl LongFileNameEntry for DirectoryEntry { 108 | fn lfn_entry_index(&self) -> Option { 109 | if !self.is_lf_name_entry() { 110 | return None; 111 | } 112 | 113 | Some(self.raw()[0] as usize) 114 | } 115 | 116 | fn lf_name(&self) -> Option { 117 | if !self.is_lf_name_entry() { 118 | return None; 119 | } 120 | 121 | let mut utf16_buf = Vec::new(); 122 | let raw_s = self.raw(); 123 | 124 | for i in (1..11).step_by(2) { 125 | if utf16_buf.iter().find(|&&f| f == 0x0).is_some() { 126 | continue; 127 | } 128 | 129 | utf16_buf.push(raw_s[i] as u16 | raw_s[i + 1] as u16); 130 | } 131 | 132 | for i in (14..26).step_by(2) { 133 | if utf16_buf.iter().find(|&&f| f == 0x0).is_some() { 134 | continue; 135 | } 136 | 137 | utf16_buf.push(raw_s[i] as u16 | raw_s[i + 1] as u16); 138 | } 139 | 140 | for i in (28..32).step_by(2) { 141 | if utf16_buf.iter().find(|&&f| f == 0x0).is_some() { 142 | continue; 143 | } 144 | 145 | utf16_buf.push(raw_s[i] as u16 | raw_s[i + 1] as u16); 146 | } 147 | 148 | Some(String::from_utf16_lossy(&utf16_buf).replace("\0", "")) 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /kernel/src/graphics/font.rs: -------------------------------------------------------------------------------- 1 | use crate::error::Result; 2 | 3 | //PSF font v2 4 | const FONT_BIN: &[u8] = include_bytes!("../../../third-party/font.psf"); 5 | const FONT_MAGIC_NUM: u32 = 0x864ab572; 6 | const UNICODE_TABLE_SEPARATOR: u8 = 0xff; 7 | 8 | pub static FONT: PsfFont = PsfFont::new(); 9 | 10 | pub struct PsfFont { 11 | binary_len: usize, 12 | height: usize, 13 | width: usize, 14 | glyphs_len: usize, 15 | glyph_size: usize, 16 | has_unicode_table: bool, 17 | header_size: usize, 18 | unicode_table_offset: usize, 19 | } 20 | 21 | impl PsfFont { 22 | const fn new() -> Self { 23 | const fn get_magic_num() -> u32 { 24 | (FONT_BIN[3] as u32) << 24 25 | | (FONT_BIN[2] as u32) << 16 26 | | (FONT_BIN[1] as u32) << 8 27 | | FONT_BIN[0] as u32 28 | } 29 | 30 | const fn get_pixel_height() -> u32 { 31 | (FONT_BIN[27] as u32) << 24 32 | | (FONT_BIN[26] as u32) << 16 33 | | (FONT_BIN[25] as u32) << 8 34 | | FONT_BIN[24] as u32 35 | } 36 | 37 | const fn get_pixel_width() -> u32 { 38 | (FONT_BIN[31] as u32) << 24 39 | | (FONT_BIN[30] as u32) << 16 40 | | (FONT_BIN[29] as u32) << 8 41 | | FONT_BIN[28] as u32 42 | } 43 | 44 | const fn get_glyphs_len() -> u32 { 45 | (FONT_BIN[19] as u32) << 24 46 | | (FONT_BIN[18] as u32) << 16 47 | | (FONT_BIN[17] as u32) << 8 48 | | FONT_BIN[16] as u32 49 | } 50 | 51 | const fn get_glyph_size() -> u32 { 52 | (FONT_BIN[23] as u32) << 24 53 | | (FONT_BIN[22] as u32) << 16 54 | | (FONT_BIN[21] as u32) << 8 55 | | FONT_BIN[20] as u32 56 | } 57 | 58 | const fn has_unicode_table() -> bool { 59 | let flags = (FONT_BIN[15] as u32) << 24 60 | | (FONT_BIN[14] as u32) << 16 61 | | (FONT_BIN[13] as u32) << 8 62 | | FONT_BIN[12] as u32; 63 | 64 | flags == 1 65 | } 66 | 67 | const fn get_header_size() -> u32 { 68 | (FONT_BIN[11] as u32) << 24 69 | | (FONT_BIN[10] as u32) << 16 70 | | (FONT_BIN[9] as u32) << 8 71 | | FONT_BIN[8] as u32 72 | } 73 | 74 | if get_magic_num() != FONT_MAGIC_NUM { 75 | panic!("Invalid font binary"); 76 | } 77 | 78 | let binary_len = FONT_BIN.len(); 79 | let height = get_pixel_height() as usize; 80 | let width = get_pixel_width() as usize; 81 | let glyphs_len = get_glyphs_len() as usize; 82 | let glyph_size = get_glyph_size() as usize; 83 | let has_unicode_table = has_unicode_table(); 84 | let header_size = get_header_size() as usize; 85 | let unicode_table_offset = header_size + glyph_size * glyphs_len; 86 | 87 | if height > 16 || width > 8 { 88 | panic!("Unsupported font size"); 89 | } 90 | 91 | Self { 92 | binary_len, 93 | height, 94 | width, 95 | glyphs_len, 96 | glyph_size, 97 | has_unicode_table, 98 | header_size, 99 | unicode_table_offset, 100 | } 101 | } 102 | 103 | pub fn get_wh(&self) -> (usize, usize) { 104 | (self.width, self.height) 105 | } 106 | 107 | // ascii char only 108 | fn unicode_char_to_glyph_index(&self, c: char) -> usize { 109 | if !self.has_unicode_table { 110 | return c as usize; 111 | } 112 | 113 | let code_point = c as u8; 114 | let mut index = 0; 115 | 116 | for i in self.unicode_table_offset..self.binary_len { 117 | if code_point == FONT_BIN[i] { 118 | break; 119 | } 120 | 121 | if FONT_BIN[i] == UNICODE_TABLE_SEPARATOR { 122 | index += 1; 123 | } 124 | } 125 | 126 | index 127 | } 128 | 129 | pub fn get_glyph(&self, c: char) -> Result<&'static [u8]> { 130 | let index = self.unicode_char_to_glyph_index(c); 131 | 132 | if index > self.glyphs_len { 133 | return Err("Invalid glyph index".into()); 134 | } 135 | 136 | let offset = self.header_size + self.glyph_size * index; 137 | Ok(&FONT_BIN[offset..offset + self.glyph_size]) 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /kernel/src/arch/x86_64/registers/segment.rs: -------------------------------------------------------------------------------- 1 | use super::Register; 2 | use core::arch::asm; 3 | 4 | pub struct Cs(u16); 5 | 6 | impl Register for Cs { 7 | fn read() -> Self { 8 | let cs; 9 | 10 | unsafe { 11 | asm!("mov {:x}, cs", out(reg) cs, options(nomem, nostack)); 12 | } 13 | 14 | Self(cs) 15 | } 16 | 17 | fn write(&self) { 18 | unsafe { 19 | asm!( 20 | "lea rax, [rip + 55f]", 21 | "push cx", 22 | "push rax", 23 | "ljmp [rsp]", 24 | "55:", 25 | "add rsp, 8 + 2", 26 | in("cx") self.0, 27 | options(nomem, nostack) 28 | ); 29 | } 30 | } 31 | 32 | fn raw(&self) -> u16 { 33 | self.0 34 | } 35 | 36 | fn set_raw(&mut self, value: u16) { 37 | self.0 = value; 38 | } 39 | } 40 | 41 | pub struct Ss(u16); 42 | 43 | impl Register for Ss { 44 | fn read() -> Self { 45 | let ss; 46 | 47 | unsafe { 48 | asm!("mov {:x}, ss", out(reg) ss, options(nomem, nostack)); 49 | } 50 | 51 | Self(ss) 52 | } 53 | 54 | fn write(&self) { 55 | unsafe { 56 | asm!("mov ss, ax", in("ax") self.0, options(nomem, nostack)); 57 | } 58 | } 59 | 60 | fn raw(&self) -> u16 { 61 | self.0 62 | } 63 | 64 | fn set_raw(&mut self, value: u16) { 65 | self.0 = value; 66 | } 67 | } 68 | 69 | pub struct Ds(u16); 70 | 71 | impl Register for Ds { 72 | fn read() -> Self { 73 | let ds; 74 | 75 | unsafe { 76 | asm!("mov {:x}, ds", out(reg) ds, options(nomem, nostack)); 77 | } 78 | 79 | Self(ds) 80 | } 81 | 82 | fn write(&self) { 83 | unsafe { 84 | asm!("mov ds, ax", in("ax") self.0, options(nomem, nostack)); 85 | } 86 | } 87 | 88 | fn raw(&self) -> u16 { 89 | self.0 90 | } 91 | 92 | fn set_raw(&mut self, value: u16) { 93 | self.0 = value; 94 | } 95 | } 96 | 97 | pub struct Es(u16); 98 | 99 | impl Register for Es { 100 | fn read() -> Self { 101 | let es; 102 | 103 | unsafe { 104 | asm!("mov {:x}, es", out(reg) es, options(nomem, nostack)); 105 | } 106 | 107 | Self(es) 108 | } 109 | 110 | fn write(&self) { 111 | unsafe { 112 | asm!("mov es, ax", in("ax") self.0, options(nomem, nostack)); 113 | } 114 | } 115 | 116 | fn raw(&self) -> u16 { 117 | self.0 118 | } 119 | 120 | fn set_raw(&mut self, value: u16) { 121 | self.0 = value; 122 | } 123 | } 124 | 125 | pub struct Fs(u16); 126 | 127 | impl Register for Fs { 128 | fn read() -> Self { 129 | let fs; 130 | 131 | unsafe { 132 | asm!("mov {:x}, fs", out(reg) fs, options(nomem, nostack)); 133 | } 134 | 135 | Self(fs) 136 | } 137 | 138 | fn write(&self) { 139 | unsafe { 140 | asm!("mov fs, ax", in("ax") self.0, options(nomem, nostack)); 141 | } 142 | } 143 | 144 | fn raw(&self) -> u16 { 145 | self.0 146 | } 147 | 148 | fn set_raw(&mut self, value: u16) { 149 | self.0 = value; 150 | } 151 | } 152 | 153 | pub struct Gs(u16); 154 | 155 | impl Register for Gs { 156 | fn read() -> Self { 157 | let gs; 158 | 159 | unsafe { 160 | asm!("mov {:x}, gs", out(reg) gs, options(nomem, nostack)); 161 | } 162 | 163 | Self(gs) 164 | } 165 | 166 | fn write(&self) { 167 | unsafe { 168 | asm!("mov gs, ax", in("ax") self.0, options(nomem, nostack)); 169 | } 170 | } 171 | 172 | fn raw(&self) -> u16 { 173 | self.0 174 | } 175 | 176 | fn set_raw(&mut self, value: u16) { 177 | self.0 = value; 178 | } 179 | } 180 | 181 | pub fn set_ds_es_fs_gs(value: u16) { 182 | let mut ds = Ds::read(); 183 | ds.set_raw(value); 184 | ds.write(); 185 | 186 | let mut es = Es::read(); 187 | es.set_raw(value); 188 | es.write(); 189 | 190 | let mut fs = Fs::read(); 191 | fs.set_raw(value); 192 | fs.write(); 193 | 194 | let mut gs = Gs::read(); 195 | gs.set_raw(value); 196 | gs.write(); 197 | } 198 | 199 | pub fn set_ss_cs(ss_value: u16, cs_value: u16) { 200 | let mut ss = Ss::read(); 201 | ss.set_raw(ss_value); 202 | ss.write(); 203 | 204 | let mut cs = Cs::read(); 205 | cs.set_raw(cs_value); 206 | cs.write(); 207 | } 208 | -------------------------------------------------------------------------------- /apps/libc/window.c: -------------------------------------------------------------------------------- 1 | #include "window.h" 2 | 3 | #include "stdio.h" 4 | #include "stdlib.h" 5 | #include "string.h" 6 | #include "syscalls.h" 7 | 8 | int remove_component(component_descriptor* cdesc) { 9 | if (cdesc == NULL) { 10 | return -1; 11 | } 12 | 13 | void* msgbuf = malloc(sizeof(iomsg_remove_component)); 14 | if (msgbuf == NULL) { 15 | return -1; 16 | } 17 | 18 | iomsg_remove_component* msg = (iomsg_remove_component*)msgbuf; 19 | msg->header.cmd_id = IOMSG_CMD_REMOVE_COMPONENT; 20 | msg->header.payload_size = sizeof(int); 21 | msg->layer_id = cdesc->layer_id; 22 | 23 | void* replymsgbuf = malloc(sizeof(iomsg_reply_remove_component)); 24 | if (replymsgbuf == NULL) { 25 | free(msgbuf); 26 | return -1; 27 | } 28 | 29 | iomsg_reply_remove_component* replymsg = (iomsg_reply_remove_component*)replymsgbuf; 30 | if (sys_iomsg(msgbuf, replymsgbuf, sizeof(iomsg_reply_remove_component)) == -1) { 31 | free(msgbuf); 32 | free(replymsgbuf); 33 | return -1; 34 | } 35 | 36 | if (replymsg->header.cmd_id != IOMSG_CMD_REMOVE_COMPONENT) { 37 | free(msgbuf); 38 | free(replymsgbuf); 39 | return -1; 40 | } 41 | 42 | free(msgbuf); 43 | free(replymsgbuf); 44 | free(cdesc); 45 | return 0; 46 | } 47 | 48 | component_descriptor* create_component_window(const char* title, size_t x_pos, size_t y_pos, size_t width, size_t height) { 49 | size_t title_len = strlen(title) + 1; 50 | void* msgbuf = malloc(sizeof(iomsg_create_component_window) + title_len); 51 | if (msgbuf == NULL) { 52 | return NULL; 53 | } 54 | 55 | iomsg_create_component_window* msg = (iomsg_create_component_window*)msgbuf; 56 | msg->header.cmd_id = IOMSG_CMD_CREATE_COMPONENT_WINDOW; 57 | msg->header.payload_size = 8 * 4 + title_len; 58 | msg->x_pos = x_pos; 59 | msg->y_pos = y_pos; 60 | msg->width = width; 61 | msg->height = height; 62 | memcpy(msg->title, title, title_len); 63 | 64 | void* replymsgbuf = malloc(sizeof(iomsg_reply_create_component)); 65 | if (replymsgbuf == NULL) { 66 | free(msgbuf); 67 | return NULL; 68 | } 69 | 70 | iomsg_reply_create_component* replymsg = (iomsg_reply_create_component*)replymsgbuf; 71 | 72 | if (sys_iomsg(msgbuf, replymsgbuf, sizeof(iomsg_reply_create_component)) == -1) { 73 | free(msgbuf); 74 | free(replymsgbuf); 75 | return NULL; 76 | } 77 | 78 | if (replymsg->header.cmd_id != IOMSG_CMD_CREATE_COMPONENT_WINDOW) { 79 | free(msgbuf); 80 | free(replymsgbuf); 81 | return NULL; 82 | } 83 | 84 | component_descriptor* cdesc = (component_descriptor*)malloc(sizeof(component_descriptor)); 85 | if (cdesc == NULL) { 86 | free(msgbuf); 87 | free(replymsgbuf); 88 | return NULL; 89 | } 90 | 91 | cdesc->layer_id = replymsg->layer_id; 92 | 93 | free(msgbuf); 94 | free(replymsgbuf); 95 | return cdesc; 96 | } 97 | 98 | component_descriptor* create_component_image(component_descriptor* cdesc, size_t image_width, size_t image_height, uint8_t pixel_format, const void* framebuf) { 99 | if (cdesc == NULL || framebuf == NULL) { 100 | return NULL; 101 | } 102 | 103 | void* msgbuf = malloc(sizeof(iomsg_create_component_image)); 104 | if (msgbuf == NULL) { 105 | return NULL; 106 | } 107 | 108 | iomsg_create_component_image* msg = (iomsg_create_component_image*)msgbuf; 109 | msg->header.cmd_id = IOMSG_CMD_CREATE_COMPONENT_IMAGE; 110 | msg->header.payload_size = sizeof(iomsg_create_component_image) - sizeof(iomsg_header); 111 | msg->layer_id = cdesc->layer_id; 112 | msg->image_width = image_width; 113 | msg->image_height = image_height; 114 | msg->pixel_format = pixel_format; 115 | msg->framebuf = framebuf; 116 | 117 | void* replymsgbuf = malloc(sizeof(iomsg_reply_create_component)); 118 | if (replymsgbuf == NULL) { 119 | free(msgbuf); 120 | return NULL; 121 | } 122 | 123 | iomsg_reply_create_component* replymsg = (iomsg_reply_create_component*)replymsgbuf; 124 | 125 | if (sys_iomsg(msgbuf, replymsgbuf, sizeof(iomsg_reply_create_component)) == -1) { 126 | free(msgbuf); 127 | free(replymsgbuf); 128 | return NULL; 129 | } 130 | 131 | if (replymsg->header.cmd_id != IOMSG_CMD_CREATE_COMPONENT_IMAGE) { 132 | free(msgbuf); 133 | free(replymsgbuf); 134 | return NULL; 135 | } 136 | 137 | component_descriptor* new_cdesc = (component_descriptor*)malloc(sizeof(component_descriptor)); 138 | if (new_cdesc == NULL) { 139 | free(msgbuf); 140 | free(replymsgbuf); 141 | return NULL; 142 | } 143 | new_cdesc->layer_id = replymsg->layer_id; 144 | 145 | free(msgbuf); 146 | free(replymsgbuf); 147 | return new_cdesc; 148 | } 149 | -------------------------------------------------------------------------------- /kernel/src/fs/fat/boot_sector.rs: -------------------------------------------------------------------------------- 1 | use super::volume::FatType; 2 | use alloc::string::String; 3 | 4 | #[derive(Debug, Clone, Copy)] 5 | #[repr(C)] 6 | pub struct BootSectorFat32OtherField { 7 | fat_size32: [u8; 4], 8 | ext_flags: [u8; 2], 9 | fs_version: [u8; 2], 10 | root_cluster: [u8; 4], 11 | fs_info: [u8; 2], 12 | backup_boot_sector: [u8; 2], 13 | reserved0: [u8; 12], 14 | drive_num: u8, 15 | reserved1: u8, 16 | ext_boot_sign: u8, 17 | volume_id: [u8; 4], 18 | volume_label: [u8; 11], 19 | fs_type: [u8; 8], 20 | boot_code32: [u8; 420], 21 | boot_sign: [u8; 2], 22 | } 23 | 24 | impl BootSectorFat32OtherField { 25 | pub fn fs_info_sector_num(&self) -> usize { 26 | u16::from_le_bytes(self.fs_info) as usize 27 | } 28 | 29 | pub fn fat_size(&self) -> usize { 30 | u32::from_le_bytes(self.fat_size32) as usize 31 | } 32 | 33 | pub fn root_cluster_num(&self) -> usize { 34 | u32::from_le_bytes(self.root_cluster) as usize 35 | } 36 | } 37 | 38 | #[derive(Debug)] 39 | #[repr(C)] 40 | pub struct BootSector { 41 | jmp_boot: [u8; 3], 42 | oem_name: [u8; 8], 43 | bytes_per_sector: [u8; 2], 44 | sectors_per_cluster: u8, 45 | reserved_sector_count: [u8; 2], 46 | num_fats: u8, 47 | root_entry_count: [u8; 2], 48 | total_sector16: [u8; 2], 49 | media: u8, 50 | fat_size16: [u8; 2], 51 | sectors_per_track: [u8; 2], 52 | num_heads: [u8; 2], 53 | hidden_sectors: [u8; 4], 54 | total_sector32: [u8; 4], 55 | //pub other_field: BootSectorOtherField, 56 | other_field: [u8; 476], 57 | } 58 | 59 | impl BootSector { 60 | pub fn fat_type(&self) -> FatType { 61 | match self.data_clusters() { 62 | ..=4085 => FatType::Fat12, 63 | 4086..=65525 => FatType::Fat16, 64 | _ => FatType::Fat32, 65 | } 66 | } 67 | 68 | pub fn oem_name(&self) -> String { 69 | String::from_utf8_lossy(&self.oem_name).into_owned() 70 | } 71 | 72 | pub fn fat32_other_field(&self) -> Option { 73 | if self.fat_type() != FatType::Fat32 { 74 | return None; 75 | } 76 | 77 | Some(unsafe { core::mem::transmute(self.other_field) }) 78 | } 79 | 80 | pub fn data_clusters(&self) -> usize { 81 | self.data_sectors16() / self.sectors_per_cluster as usize 82 | } 83 | 84 | pub fn bytes_per_sector(&self) -> usize { 85 | u16::from_le_bytes(self.bytes_per_sector) as usize 86 | } 87 | 88 | pub fn sectors_per_cluster(&self) -> usize { 89 | self.sectors_per_cluster as usize 90 | } 91 | 92 | pub fn num_fats(&self) -> usize { 93 | self.num_fats as usize 94 | } 95 | 96 | pub fn fat_sectors16(&self) -> usize { 97 | self.fat_size16() * self.num_fats() 98 | } 99 | 100 | pub fn fat_sectors32(&self) -> Option { 101 | match self.fat32_other_field() { 102 | Some(other_field) => Some(other_field.fat_size() * self.num_fats()), 103 | None => None, 104 | } 105 | } 106 | 107 | pub fn total_sectors(&self) -> usize { 108 | let total_sector16 = u16::from_le_bytes(self.total_sector16); 109 | let total_sector32 = u32::from_le_bytes(self.total_sector32); 110 | 111 | match total_sector16 { 112 | 0 => total_sector32 as usize, 113 | _ => total_sector16 as usize, 114 | } 115 | } 116 | 117 | // fat start sector 118 | pub fn reserved_sectors(&self) -> usize { 119 | u16::from_le_bytes(self.reserved_sector_count) as usize 120 | } 121 | 122 | fn fat_size16(&self) -> usize { 123 | u16::from_le_bytes(self.fat_size16) as usize 124 | } 125 | 126 | fn root_entry_count(&self) -> usize { 127 | u16::from_le_bytes(self.root_entry_count) as usize 128 | } 129 | 130 | pub fn root_dir_start_sector16(&self) -> usize { 131 | self.reserved_sectors() + self.fat_sectors16() 132 | } 133 | 134 | pub fn root_dir_sectors16(&self) -> usize { 135 | (self.root_entry_count() * 32 + self.bytes_per_sector() - 1) / self.bytes_per_sector() 136 | } 137 | 138 | pub fn data_start_sector16(&self) -> usize { 139 | self.root_dir_start_sector16() + self.root_dir_sectors16() 140 | } 141 | 142 | pub fn data_sectors16(&self) -> usize { 143 | self.total_sectors() - self.data_start_sector16() 144 | } 145 | 146 | pub fn data_start_sector32(&self) -> Option { 147 | match self.fat_sectors32() { 148 | Some(fat_sectors) => Some(self.reserved_sectors() + fat_sectors), 149 | None => None, 150 | } 151 | } 152 | 153 | pub fn data_sectors32(&self) -> Option { 154 | match self.data_start_sector32() { 155 | Some(data_start_sector) => Some(self.total_sectors() - data_start_sector), 156 | None => None, 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /kernel/src/fs/fat/mod.rs: -------------------------------------------------------------------------------- 1 | use super::path::Path; 2 | use crate::error::{Error, Result}; 3 | use alloc::{collections::vec_deque::VecDeque, string::String, vec::Vec}; 4 | use dir_entry::*; 5 | use volume::FatVolume; 6 | 7 | pub mod boot_sector; 8 | pub mod dir_entry; 9 | pub mod file_allocation_table; 10 | pub mod fs_info_sector; 11 | pub mod volume; 12 | 13 | #[derive(Debug, Clone)] 14 | pub struct FileMetaData { 15 | pub name: String, 16 | pub attr: Attribute, 17 | pub size: usize, 18 | pub target_cluster_num: usize, 19 | } 20 | 21 | #[derive(Debug, PartialEq, Eq)] 22 | pub struct Fat { 23 | volume: FatVolume, 24 | root_cluster_num: usize, 25 | } 26 | 27 | impl Fat { 28 | pub fn new(volume: FatVolume) -> Self { 29 | let root_cluster_num = volume.root_cluster_num(); 30 | 31 | Self { 32 | volume, 33 | root_cluster_num, 34 | } 35 | } 36 | 37 | pub fn cluster_num( 38 | &self, 39 | dir_name: &str, 40 | current_dir_cluster_num: Option, 41 | ) -> Result { 42 | if current_dir_cluster_num.is_none() 43 | || current_dir_cluster_num == Some(self.root_cluster_num) 44 | { 45 | match dir_name { 46 | "." | ".." => return Ok(self.root_cluster_num), 47 | _ => (), 48 | } 49 | } 50 | 51 | let files = self.scan_dir(current_dir_cluster_num); 52 | let dir = files 53 | .iter() 54 | .find(|f| f.attr == Attribute::Directory && f.name.trim() == dir_name) 55 | .ok_or(Error::Failed("The directory does not exist"))?; 56 | 57 | Ok(dir.target_cluster_num) 58 | } 59 | 60 | pub fn get_file( 61 | &self, 62 | file_name: &str, 63 | current_dir_cluster_num: Option, 64 | ) -> Result<(FileMetaData, Vec)> { 65 | let files = self.scan_dir(current_dir_cluster_num); 66 | let file = files 67 | .iter() 68 | .find(|f| f.attr == Attribute::Archive && f.name.trim() == file_name) 69 | .ok_or(Error::Failed("The file does not exist"))?; 70 | 71 | let dir_entries = self 72 | .volume 73 | .read_chained_dir_entries(file.target_cluster_num); 74 | let mut bytes: Vec = dir_entries.iter().flat_map(|de| *de.raw()).collect(); 75 | bytes.resize(file.size, 0); 76 | 77 | Ok((file.clone(), bytes)) 78 | } 79 | 80 | pub fn get_file_by_abs_path(&self, path: &Path) -> Result<(FileMetaData, Vec)> { 81 | let mut current_dir_cluster_num = self.root_cluster_num; 82 | let path = path.normalize(); 83 | let parent_path = path.parent(); 84 | 85 | for dir_name in parent_path.names() { 86 | current_dir_cluster_num = self.cluster_num(dir_name, Some(current_dir_cluster_num))?; 87 | } 88 | 89 | let file = self.get_file(&path.name(), Some(current_dir_cluster_num))?; 90 | Ok(file) 91 | } 92 | 93 | pub fn scan_dir(&self, dir_cluster_num: Option) -> Vec { 94 | let dir_cluster_num = match dir_cluster_num { 95 | Some(cluster_num) => cluster_num, 96 | None => self.root_cluster_num, 97 | }; 98 | let mut files = Vec::new(); 99 | 100 | let mut lf_name_buf = VecDeque::new(); 101 | let dir_entries = self.volume.read_chained_dir_entries(dir_cluster_num); 102 | 103 | for i in 0..dir_entries.len() { 104 | let dir_entry = dir_entries[i]; 105 | let entry_type = dir_entry.entry_type(); 106 | let file_attr = dir_entry.attr(); 107 | 108 | // end of not null directories 109 | if entry_type == EntryType::Null && file_attr.is_none() { 110 | break; 111 | } 112 | 113 | // long file name entry 114 | if let (Some(lf_name), Some(lfn_entry_index)) = 115 | (dir_entry.lf_name(), dir_entry.lfn_entry_index()) 116 | { 117 | if lfn_entry_index >= 1 { 118 | lf_name_buf.push_front(lf_name); 119 | continue; 120 | } 121 | } 122 | 123 | match file_attr { 124 | Some(attr) => match attr { 125 | Attribute::Archive | Attribute::Directory => { 126 | let file_name = if lf_name_buf.len() > 0 { 127 | lf_name_buf.iter().fold(String::new(), |acc, s| acc + s) 128 | } else { 129 | dir_entry.sf_name().unwrap() 130 | }; 131 | 132 | let file = FileMetaData { 133 | name: file_name, 134 | attr, 135 | size: dir_entry.file_size(), 136 | target_cluster_num: dir_entry.first_cluster_num(), 137 | }; 138 | 139 | files.push(file); 140 | lf_name_buf.clear(); 141 | } 142 | _ => (), 143 | }, 144 | None => (), 145 | } 146 | } 147 | 148 | files 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /apps/libc-rs/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![allow(non_upper_case_globals)] 3 | #![allow(non_camel_case_types)] 4 | #![allow(non_snake_case)] 5 | 6 | #[cfg(not(feature = "kernel"))] 7 | #[macro_use] 8 | extern crate alloc; 9 | 10 | #[cfg(not(feature = "kernel"))] 11 | use alloc::{ffi::CString, vec::Vec}; 12 | #[cfg(not(feature = "kernel"))] 13 | use core::{ 14 | fmt::{self, Write}, 15 | panic::PanicInfo, 16 | str::FromStr, 17 | }; 18 | #[cfg(not(feature = "kernel"))] 19 | use linked_list_allocator::LockedHeap; 20 | 21 | include!(concat!(env!("OUT_DIR"), "/bindings.rs")); 22 | 23 | // result/error 24 | #[cfg(not(feature = "kernel"))] 25 | #[derive(Debug, Clone, PartialEq)] 26 | pub enum LibcError { 27 | FopenFailed, 28 | FreadFailed, 29 | } 30 | 31 | #[cfg(not(feature = "kernel"))] 32 | pub type Result = core::result::Result; 33 | 34 | // heap 35 | #[cfg(not(feature = "kernel"))] 36 | #[global_allocator] 37 | static ALLOCATOR: LockedHeap = LockedHeap::empty(); 38 | 39 | #[cfg(not(feature = "kernel"))] 40 | #[doc(hidden)] 41 | pub fn _init_heap() { 42 | let heap_size = 1024 * 1024; 43 | let heap = unsafe { malloc(heap_size as u64) as *mut u8 }; 44 | unsafe { 45 | ALLOCATOR.lock().init(heap, heap_size); 46 | } 47 | } 48 | 49 | // panic 50 | #[cfg(not(feature = "kernel"))] 51 | #[panic_handler] 52 | fn panic(info: &PanicInfo) -> ! { 53 | println!("{:?}", info.message()); 54 | println!("{:?}", info.location()); 55 | 56 | unsafe { 57 | exit(-1); 58 | } 59 | } 60 | 61 | // parse args macro 62 | #[cfg(not(feature = "kernel"))] 63 | #[doc(hidden)] 64 | pub unsafe fn _parse_args(argc: usize, argv: *const *const u8) -> Vec<&'static str> { 65 | let mut args = Vec::new(); 66 | for i in 0..argc { 67 | let ptr = *argv.add(i); 68 | let mut len = 0; 69 | while *ptr.add(len) != 0 { 70 | len += 1; 71 | } 72 | 73 | let slice = core::slice::from_raw_parts(ptr, len); 74 | let s = match str::from_utf8(slice) { 75 | Ok(s) => s, 76 | Err(_) => "", 77 | }; 78 | args.push(s); 79 | } 80 | 81 | args 82 | } 83 | 84 | #[cfg(not(feature = "kernel"))] 85 | #[macro_export] 86 | macro_rules! parse_args { 87 | () => {{ 88 | use core::arch::asm; 89 | 90 | let argc: usize; 91 | let argv: *const *const u8; 92 | unsafe { 93 | asm!("mov {}, rdi", out(reg) argc, options(nomem, nostack)); 94 | asm!("mov {}, rsi", out(reg) argv, options(nomem, nostack)); 95 | } 96 | 97 | $crate::_init_heap(); 98 | let args = unsafe { $crate::_parse_args(argc, argv) }; 99 | args 100 | }}; 101 | } 102 | 103 | // print macros 104 | #[cfg(not(feature = "kernel"))] 105 | struct Writer; 106 | 107 | #[cfg(not(feature = "kernel"))] 108 | impl fmt::Write for Writer { 109 | fn write_str(&mut self, s: &str) -> fmt::Result { 110 | unsafe { 111 | printf(format!("{}\0", s).as_ptr() as *const _); 112 | } 113 | 114 | Ok(()) 115 | } 116 | } 117 | 118 | #[cfg(not(feature = "kernel"))] 119 | #[doc(hidden)] 120 | pub fn _print(args: fmt::Arguments) { 121 | Writer.write_fmt(args).unwrap(); 122 | } 123 | 124 | #[cfg(not(feature = "kernel"))] 125 | #[macro_export] 126 | macro_rules! print { 127 | ($($arg:tt)*) => ($crate::_print(format_args!($($arg)*))); 128 | } 129 | 130 | #[cfg(not(feature = "kernel"))] 131 | #[macro_export] 132 | macro_rules! println { 133 | () => ($crate::print!("\n")); 134 | ($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*))); 135 | } 136 | 137 | // file 138 | #[cfg(not(feature = "kernel"))] 139 | #[repr(C)] 140 | pub struct File { 141 | ptr: *mut FILE, 142 | } 143 | 144 | #[cfg(not(feature = "kernel"))] 145 | impl Drop for File { 146 | fn drop(&mut self) { 147 | if !self.ptr.is_null() { 148 | unsafe { 149 | fclose(self.ptr); 150 | } 151 | } 152 | } 153 | } 154 | 155 | #[cfg(not(feature = "kernel"))] 156 | impl File { 157 | fn call_fopen(path: &str, mode: char) -> Result { 158 | let path_cstr = CString::from_str(path).unwrap(); 159 | let path = path_cstr.as_bytes_with_nul(); 160 | 161 | let mut buf = [0; 4]; 162 | let encoded = mode.encode_utf8(&mut buf); 163 | let mode_cstr = CString::new(encoded.as_bytes()).unwrap(); 164 | let mode = mode_cstr.as_bytes_with_nul(); 165 | 166 | let file_ptr = unsafe { fopen(path.as_ptr() as *const i8, mode.as_ptr() as *const i8) }; 167 | 168 | if file_ptr.is_null() { 169 | return Err(LibcError::FopenFailed); 170 | } 171 | 172 | Ok(Self { ptr: file_ptr }) 173 | } 174 | 175 | fn call_fread(&self, buf: &mut [u8]) -> Result<()> { 176 | match unsafe { fread(buf.as_mut_ptr() as *mut _, 1, buf.len() as u64, self.ptr) } { 177 | 0 => Err(LibcError::FreadFailed), 178 | _ => Ok(()), 179 | } 180 | } 181 | 182 | pub fn size(&self) -> usize { 183 | unsafe { (*(*self.ptr).stat).size } 184 | } 185 | 186 | pub fn open(path: &str) -> Result { 187 | Self::call_fopen(path, 'r') 188 | } 189 | 190 | pub fn create(path: &str) -> Result { 191 | Self::call_fopen(path, 'w') 192 | } 193 | 194 | pub fn read(&self, buf: &mut [u8]) -> Result<()> { 195 | self.call_fread(buf) 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /apps/libc/stdio.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | 3 | #include 4 | 5 | #include "stat.h" 6 | #include "stdlib.h" 7 | #include "string.h" 8 | #include "syscalls.h" 9 | 10 | void exit(int status) { 11 | sys_exit((uint64_t)status); 12 | } 13 | 14 | int fprintf(FILE *stream, const char *fmt, ...) { 15 | printf("[DEBUG]fprintf called\n"); 16 | return -1; 17 | } 18 | 19 | FILE *fopen(const char *filepath, const char *mode) { 20 | // printf("[DEBUG]fopen called\n"); 21 | uint32_t flags = OPEN_FLAG_NONE; 22 | 23 | if (strcmp(mode, "w") == 0) { 24 | flags |= OPEN_FLAG_CREATE; 25 | } 26 | 27 | int fd = sys_open(filepath, flags); 28 | if (fd == -1) 29 | return NULL; 30 | 31 | f_stat *stat = (f_stat *)malloc(sizeof(f_stat)); 32 | if (sys_stat(fd, stat) == -1) { 33 | free(stat); 34 | sys_close(fd); 35 | return NULL; 36 | } 37 | 38 | FILE *file = (FILE *)malloc(sizeof(FILE)); 39 | file->fd = fd; 40 | file->buf = NULL; 41 | file->stat = stat; 42 | file->pos = 0; 43 | return file; 44 | } 45 | 46 | int fclose(FILE *stream) { 47 | // printf("[DEBUG]fclose called\n"); 48 | if (stream == NULL) 49 | return -1; 50 | 51 | int64_t res = sys_close(stream->fd); 52 | if (res == -1) 53 | return -1; 54 | 55 | if (stream->buf != NULL) 56 | free(stream->buf); 57 | 58 | if (stream->stat != NULL) 59 | free(stream->stat); 60 | 61 | free(stream); 62 | return 0; 63 | } 64 | 65 | long int ftell(FILE *stream) { 66 | // printf("[DEBUG]ftell called\n"); 67 | if (stream == NULL) 68 | return -1; 69 | 70 | return stream->pos; 71 | } 72 | 73 | int fflush(FILE *stream) { 74 | if (stream == NULL) 75 | return -1; 76 | 77 | if (stream->buf == NULL || stream->pos == 0) 78 | return 0; 79 | 80 | int ret = sys_write(stream->fd, stream->buf, stream->pos); 81 | if (ret == -1) 82 | return -1; 83 | free(stream->buf); 84 | stream->buf = NULL; 85 | stream->pos = 0; 86 | return 0; 87 | } 88 | 89 | int puts(const char *c) { 90 | int ret = sys_write(FDN_STDOUT, c, strlen(c)); 91 | 92 | if (ret == -1) 93 | return -1; 94 | 95 | ret = sys_write(FDN_STDOUT, "\n", 1); 96 | if (ret == -1) 97 | return -1; 98 | 99 | return 0; 100 | } 101 | 102 | int putchar(int c) { 103 | return printf("%c", c); 104 | } 105 | 106 | char getchar(void) { 107 | char c; 108 | int ret = sys_read(FDN_STDIN, &c, 1); 109 | if (ret == -1) 110 | return EOF; 111 | return c; 112 | } 113 | 114 | int vfprintf(FILE *stream, const char *fmt, va_list ap) { 115 | printf("[DEBUG]vfprintf called\n"); 116 | return -1; 117 | } 118 | 119 | int sscanf(const char *buf, const char *fmt, ...) { 120 | printf("[DEBUG]sscanf called\n"); 121 | return -1; 122 | } 123 | 124 | size_t fread(void *buf, size_t size, size_t count, FILE *stream) { 125 | // printf("[DEBUG]fread called\n"); 126 | if (size == 0 || count == 0) 127 | return 0; 128 | 129 | if (stream == NULL) 130 | return 0; 131 | 132 | size_t f_size = stream->stat->size; 133 | 134 | if (stream->buf == NULL) { 135 | stream->buf = (char *)malloc(f_size); 136 | if (stream->buf == NULL) 137 | return 0; 138 | 139 | if (sys_read(stream->fd, stream->buf, f_size) == -1) { 140 | free(stream->buf); 141 | return 0; 142 | } 143 | } 144 | 145 | size_t remaining = f_size - stream->pos; 146 | size_t bytes_to_read = size * count > remaining ? remaining : size * count; 147 | 148 | memcpy(buf, stream->buf + stream->pos, bytes_to_read); 149 | stream->pos += bytes_to_read; 150 | 151 | return bytes_to_read / size; 152 | } 153 | 154 | int fseek(FILE *stream, long int offset, int whence) { 155 | // printf("[DEBUG]fseek called\n"); 156 | if (stream == NULL) 157 | return -1; 158 | 159 | size_t f_size = stream->stat->size; 160 | switch (whence) { 161 | case SEEK_SET: 162 | if (offset < 0 || offset > f_size) 163 | return -1; 164 | stream->pos = offset; 165 | break; 166 | case SEEK_CUR: 167 | if (stream->pos + offset < 0 || stream->pos + offset > f_size) 168 | return -1; 169 | stream->pos += offset; 170 | break; 171 | case SEEK_END: 172 | if (f_size + offset < 0) 173 | return -1; 174 | stream->pos = f_size + offset; 175 | break; 176 | default: 177 | return -1; 178 | } 179 | 180 | return 0; 181 | } 182 | 183 | size_t fwrite(const void *buf, size_t size, size_t count, FILE *stream) { 184 | // printf("[DEBUG]fwrite called\n"); 185 | if (size == 0 || count == 0) 186 | return 0; 187 | 188 | if (stream == NULL) 189 | return 0; 190 | 191 | size_t bytes_to_write = size * count; 192 | if (stream->buf == NULL) { 193 | stream->buf = (char *)malloc(bytes_to_write); 194 | if (stream->buf == NULL) 195 | return 0; 196 | } else { 197 | stream->buf = (char *)realloc(stream->buf, stream->pos + bytes_to_write); 198 | if (stream->buf == NULL) 199 | return 0; 200 | } 201 | 202 | memcpy(stream->buf + stream->pos, buf, bytes_to_write); 203 | stream->pos += bytes_to_write; 204 | 205 | return count; 206 | } 207 | -------------------------------------------------------------------------------- /kernel/src/task/async_task.rs: -------------------------------------------------------------------------------- 1 | use crate::{error::Result, kdebug, sync::mutex::Mutex, task::TaskId, util}; 2 | use alloc::{ 3 | boxed::Box, 4 | collections::{btree_map::BTreeMap, VecDeque}, 5 | }; 6 | use core::{ 7 | future::Future, 8 | pin::Pin, 9 | ptr::null, 10 | sync::atomic::{AtomicBool, Ordering}, 11 | task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, 12 | time::Duration, 13 | }; 14 | 15 | static mut ASYNC_TASK_EXECUTOR: Mutex = Mutex::new(Executor::new()); 16 | 17 | #[derive(Default)] 18 | struct Yield { 19 | polled: AtomicBool, 20 | } 21 | 22 | impl Future for Yield { 23 | type Output = (); 24 | 25 | fn poll(self: Pin<&mut Self>, _: &mut Context) -> Poll<()> { 26 | if self.polled.fetch_or(true, Ordering::SeqCst) { 27 | Poll::Ready(()) 28 | } else { 29 | Poll::Pending 30 | } 31 | } 32 | } 33 | 34 | pub struct TimeoutFuture { 35 | timeout: Duration, 36 | } 37 | 38 | impl TimeoutFuture { 39 | pub fn new(durtion: Duration) -> Self { 40 | let global_uptime = util::time::global_uptime(); 41 | Self { 42 | timeout: global_uptime + durtion, 43 | } 44 | } 45 | } 46 | 47 | impl Future for TimeoutFuture { 48 | type Output = (); 49 | 50 | fn poll(self: Pin<&mut Self>, _: &mut Context) -> Poll<()> { 51 | let global_uptime = util::time::global_uptime(); 52 | 53 | if self.timeout <= global_uptime { 54 | Poll::Ready(()) 55 | } else { 56 | Poll::Pending 57 | } 58 | } 59 | } 60 | 61 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] 62 | pub enum Priority { 63 | High, 64 | Normal, 65 | Low, 66 | } 67 | 68 | struct AsyncTask { 69 | id: TaskId, 70 | future: Pin>>, 71 | priority: Priority, 72 | } 73 | 74 | impl AsyncTask { 75 | fn new(future: impl Future + 'static, priority: Priority) -> Self { 76 | Self { 77 | id: TaskId::new(), 78 | future: Box::pin(future), 79 | priority, 80 | } 81 | } 82 | 83 | fn poll(&mut self, context: &mut Context) -> Poll<()> { 84 | self.future.as_mut().poll(context) 85 | } 86 | } 87 | 88 | struct Executor { 89 | task_queues: BTreeMap>, 90 | is_ready: bool, 91 | poll_count: usize, 92 | } 93 | 94 | impl Executor { 95 | const fn new() -> Self { 96 | Self { 97 | task_queues: BTreeMap::new(), 98 | is_ready: false, 99 | poll_count: 0, 100 | } 101 | } 102 | 103 | fn poll(&mut self) { 104 | if !self.is_ready { 105 | return; 106 | } 107 | 108 | self.poll_count = self.poll_count.wrapping_add(1); 109 | 110 | for &p in &[Priority::High, Priority::Normal, Priority::Low] { 111 | let do_skip = match p { 112 | Priority::High => false, 113 | Priority::Normal => self.poll_count % 2 != 0, 114 | Priority::Low => self.poll_count % 4 != 0, 115 | }; 116 | if do_skip { 117 | continue; 118 | } 119 | 120 | if let Some(queue) = self.task_queues.get_mut(&p) { 121 | if let Some(mut task) = queue.pop_front() { 122 | let waker = dummy_waker(); 123 | let mut context = Context::from_waker(&waker); 124 | match task.poll(&mut context) { 125 | Poll::Ready(()) => { 126 | kdebug!("task: Done (id: {})", task.id); 127 | } 128 | Poll::Pending => { 129 | queue.push_back(task); 130 | } 131 | } 132 | } 133 | } 134 | } 135 | } 136 | 137 | fn ready(&mut self) { 138 | self.is_ready = true; 139 | self.poll_count = 0; 140 | } 141 | 142 | fn spawn(&mut self, task: AsyncTask) { 143 | let priority = task.priority; 144 | self.task_queues 145 | .entry(priority) 146 | .or_insert_with(VecDeque::new) 147 | .push_back(task); 148 | } 149 | } 150 | 151 | fn dummy_raw_waker() -> RawWaker { 152 | fn no_op(_: *const ()) {} 153 | fn clone(_: *const ()) -> RawWaker { 154 | dummy_raw_waker() 155 | } 156 | let vtable = &RawWakerVTable::new(clone, no_op, no_op, no_op); 157 | RawWaker::new(null(), vtable) 158 | } 159 | 160 | fn dummy_waker() -> Waker { 161 | unsafe { Waker::from_raw(dummy_raw_waker()) } 162 | } 163 | 164 | pub async fn exec_yield() { 165 | Yield::default().await 166 | } 167 | 168 | pub fn poll() -> Result<()> { 169 | unsafe { ASYNC_TASK_EXECUTOR.try_lock() }?.poll(); 170 | Ok(()) 171 | } 172 | 173 | pub fn ready() -> Result<()> { 174 | unsafe { ASYNC_TASK_EXECUTOR.try_lock() }?.ready(); 175 | Ok(()) 176 | } 177 | 178 | pub fn spawn(future: impl Future + 'static) -> Result<()> { 179 | let task = AsyncTask::new(future, Priority::Normal); 180 | unsafe { ASYNC_TASK_EXECUTOR.try_lock() }?.spawn(task); 181 | Ok(()) 182 | } 183 | 184 | pub fn spawn_with_priority( 185 | future: impl Future + 'static, 186 | priority: Priority, 187 | ) -> Result<()> { 188 | let task = AsyncTask::new(future, priority); 189 | unsafe { ASYNC_TASK_EXECUTOR.try_lock() }?.spawn(task); 190 | Ok(()) 191 | } 192 | --------------------------------------------------------------------------------