diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..3d68dd1 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +root = true + +[*] +indent_style = tab +trim_trailing_whitespaces = true +insert_final_newline = false +charset = utf-8 + +[*.nix] +indent_size = 2 + +[*.{c,h,ld}] +indent_size = 4 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..f4dd614 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,54 @@ +name: Deploy website + +# Set permissions of the `GITHUB_TOKEN` to allow deployment to Github Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete +concurrency: + group: "pages" + cancel-in-progress: false + +# Workflow triggers +on: + # Whenever any changes are made to `web/` from either a push or merging a pull request + push: + paths: + - "web/**" + pull_request: + paths: + - "web/**" + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Workflow actions +jobs: + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + # Clone repository + - name: Checkout + uses: actions/checkout@v4 + + # Configure Github Pages + - name: Setup Pages + uses: actions/configure-pages@v5 + + # Upload build - In this case it's just static files e.g. HTML and CSS + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + # Upload specific directory + path: './web' + + # Deploy to Github Pages + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 08f6d07..570a96f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ build/ !build/src/kernel/console/functions/edit.c.o # Libraries/Dependencies -include/limine +include/limine/* #!include/limine/limine.h .DS_Store @@ -17,8 +17,9 @@ tools/png tools/bmp tools/lg.py -dsk/hdd0 -dsk/disk.img +.github/* + +logo.txt src/kernel/console/functions/edit.c diff --git a/.zed/settings.json b/.zed/settings.json new file mode 100644 index 0000000..1d0ac21 --- /dev/null +++ b/.zed/settings.json @@ -0,0 +1,3 @@ +{ + "project_name": "emexOS", +} diff --git a/Makefile b/Makefile index 388a8c9..ecaaf12 100644 --- a/Makefile +++ b/Makefile @@ -15,12 +15,13 @@ all: $(ISO) fetchDeps: @echo "[DEPS] Fetching dependencies/libraries" @mkdir -p $(INCLUDE_DIR) - #@mkdir -p $(BUILD_DIR)/src/kernel/console/functions + @echo "[DEPS] Fetching Limine" - @rm -rf $(INCLUDE_DIR)/limine - @git clone https://codeberg.org/Limine/Limine.git --branch=v10.3.0-binary --depth=1 $(INCLUDE_DIR)/limine - @echo "[DEPS] Building limine binary" - @$(MAKE) -C $(INCLUDE_DIR)/limine + @rm -rf $(LIMINE_DIR) + @git clone https://codeberg.org/Limine/Limine.git --branch=v10.x-binary --depth=1 $(LIMINE_DIR) + @rm -rf $(LIMINE_DIR)/.git + @echo "[DEPS] Fetching Limine protocol header file" + @wget https://codeberg.org/Limine/limine-protocol/raw/branch/trunk/include/limine.h -O $(LIMINE_DIR)/limine.h disk: @mkdir -p $(DISK_DIR) @@ -34,24 +35,16 @@ $(BUILD_DIR)/kernel.elf: src/kernel/linker.ld $(OBJS) userspace: @$(MAKE) -C src/userspace -# Ensure host limine tool exists (Linux/macOS binary). +# Compile Limine $(LIMINE_TOOL): @$(MAKE) -C $(LIMINE_DIR) # Create bootable ISO -$(ISO): limine.conf $(BUILD_DIR)/kernel.elf disk userspace $(LIMINE_TOOL) +$(ISO): limine.conf $(LIMINE_TOOL) $(BUILD_DIR)/kernel.elf disk userspace @echo "[ISO] Creating bootable image..." @rm -rf $(ISODIR) + @rm -f $(DISK_DIR)/initrd.cpio @mkdir -p $(ISODIR)/boot/limine $(ISODIR)/EFI/BOOT -#@cp $(BUILD_DIR)/kernel.elf $(ISODIR)/boot/ - @cp $(BUILD_DIR)/kernel.elf $(ISODIR)/boot/kernel_a.elf - @cp $(BUILD_DIR)/kernel.elf $(ISODIR)/boot/kernel_b.elf -#@cp activeslot.txt $(ISODIR)/boot/activeslot.cfg # slot system - - @cp $< $(ISODIR)/boot/limine/ - @cp $(addprefix $(INCLUDE_DIR)/limine/limine-, bios.sys bios-cd.bin uefi-cd.bin) $(ISODIR)/boot/limine/ - @cp $(addprefix $(INCLUDE_DIR)/limine/BOOT, IA32.EFI X64.EFI) $(ISODIR)/EFI/BOOT/ - @mkdir -p $(ISODIR)/boot @mkdir -p $(ISODIR)/boot/ui @mkdir -p $(ISODIR)/boot/ui/fonts @@ -60,26 +53,38 @@ $(ISO): limine.conf $(BUILD_DIR)/kernel.elf disk userspace $(LIMINE_TOOL) @mkdir -p $(ISODIR)/boot/keymaps @mkdir -p $(ISODIR)/boot/images @mkdir -p $(ISODIR)/boot/programs + @cp $(BUILD_DIR)/kernel.elf $(ISODIR)/boot/kernel_a.elf + @cp $(BUILD_DIR)/kernel.elf $(ISODIR)/boot/kernel_b.elf + @cp $< $(ISODIR)/boot/limine/ + @cp $(addprefix $(INCLUDE_DIR)/limine/limine-, bios.sys bios-cd.bin uefi-cd.bin) $(ISODIR)/boot/limine/ + @cp $(addprefix $(INCLUDE_DIR)/limine/BOOT, IA32.EFI X64.EFI) $(ISODIR)/EFI/BOOT/ - @echo "[MOD] creating executables..." - @cp src/userspace/hello.elf $(ISODIR)/boot/programs/hello.elf - -#@echo "[MOD] copying configs..." -#@cp shared/theme/bootconf.emcg $(ISODIR)/boot/bootconf.emcg -#@cp shared/theme/font8x15.bin $(ISODIR)/boot/liminefont.f15 - - @echo "[MOD] copying assets..." - @cp shared/ui/assets/bootlogo.bin $(ISODIR)/boot/ui/assets/ -#@cp shared/images/logo.bmp $(ISODIR)/boot/images/ -#@cp shared/images/background.bmp $(ISODIR)/boot/images/ - @cp shared/images/frog.bmp $(ISODIR)/boot/images/ - -#@cp shared/images/bg.jpg $(ISODIR)/boot/ - - @echo "[MOD] copying keymaps..." - @cp shared/keymaps/US.map $(ISODIR)/boot/keymaps/ - @cp shared/keymaps/DE.map $(ISODIR)/boot/keymaps/ -#@cp shared/keymaps/PL.map $(ISODIR)/boot/keymaps/ + @echo "[MK] copying executables..." + @mkdir -p $(DISK_DIR)/rd/user/apps + @mkdir -p $(DISK_DIR)/rd/user/bin + @mkdir -p $(DISK_DIR)/rd/bin + @mkdir -p $(DISK_DIR)/rd/emr/system + @cp -r src/userspace/apps/shell/shell.emx $(DISK_DIR)/rd/user/apps/ + @cp -r src/userspace/apps/system/system.emx $(DISK_DIR)/rd/emr/system/ + @cp -r src/userspace/apps/gui/gui.emx $(DISK_DIR)/rd/user/apps/ + + @echo "[MK] copying files..." +#@cp limine.conf $(DISK_DIR)/rd/boot/ + @cp src/userspace/apps/login/login.elf $(DISK_DIR)/rd/emr/system + @cp src/userspace/bin/echo/echo.elf $(DISK_DIR)/rd/bin/ + @cp src/userspace/bin/hello/hello.elf $(DISK_DIR)/rd/bin/ + @cp src/userspace/bin/ls/ls.elf $(DISK_DIR)/rd/bin/ + @cp src/userspace/bin/tree/tree.elf $(DISK_DIR)/rd/bin/ + @cp src/userspace/bin/cat/cat.elf $(DISK_DIR)/rd/bin/ + @cp src/userspace/bin/cd/cd.elf $(DISK_DIR)/rd/bin/ + @cp src/userspace/bin/lsblk/lsblk.elf $(DISK_DIR)/rd/bin/ + @cp src/userspace/bin/reboot/reboot.elf $(DISK_DIR)/rd/bin/ + + + @echo "[MK] creating initrd.cpio..." + @chmod +x tools/initrd.sh + ./tools/initrd.sh + @cp $(DISK_DIR)/initrd.cpio $(ISODIR)/boot/ @xorriso -as mkisofs -b boot/limine/limine-bios-cd.bin \ -no-emul-boot -boot-load-size 4 -boot-info-table \ @@ -123,4 +128,4 @@ $(BUILD_DIR)/%.asm.o: %.asm clean: @echo "[CLR] Cleaning..." @rm -rf $(BUILD_DIR) - @echo "[OK]" + @echo "[OK]" \ No newline at end of file diff --git a/README.md b/README.md index b73d268..70e9f2a 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,41 @@ -# emexOS - a simple 64 Bit OS written in C -
- - +

$${\Huge \color{white} \tilde{} emexOS \space \tilde{} \space \space \space }$$

+ + +$${\LARGE \color{red}a \space simple \space x86 \textunderscore 64 \space operating \space system \space in \space c}$$ + +![GitHub License](https://img.shields.io/github/license/emexos/emexOS1?style=for-the-badge&label=License&labelColor=black&color=white) +![GitHub repo size](https://img.shields.io/github/repo-size/emexos/emexOS1?style=for-the-badge&label=size&labelColor=black&color=white) +![GitHub Repo stars](https://img.shields.io/github/stars/emexos/emexos1?style=for-the-badge&labelColor=black&color=white) + + +![Discord Badge](https://img.shields.io/badge/Join%20the%20Discord-Black?style=for-the-badge&logo=discord&logoColor=white&color=black) +
-## Build Dependencies +## $${\large Build \space Dependencies}$$ For building and compiling emexOS, ensure you have the following installed, - x86_64 GCC cross-compiler - This is our preferred compiler for the source code. Currently, emexOS only supports 64-bit x86 machines, but we plan to support more architectures in the future. - [NASM](https://www.nasm.us/) - Assembler. - [QEMU](https://www.qemu.org/) - Our preferred emulator. - [Xorriso](https://www.gnu.org/software/xorriso/) - ISO creation. -- [Git](https://git-scm.com/) - To fetch dependencies. +- [Git](https://git-scm.com/) and [wget](https://www.gnu.org/software/wget/) - To fetch dependencies. -You can use Zig instead of x86_64-gcc if you prefer to, -- [Zig](https://ziglang.org/) - Zig lets you build the whole OS using just one command. +You can use [Zig](https://ziglang.org/) instead of GCC if you prefer to. -## For Nix Users -If you’re using [Nix](https://nixos.org/), you can run the provided flake that installs all the build dependencies. That way, you can set up a complete emexOS development environment with a single, simple command. +## $${\large For \space Nix \space Users}$$ +Ensure you have flakes enabled first and then run `nix develop` to enter the provided development shell which will have all build dependencies and such installed for you. I'd recommend updating the flake using `nix flake update` as it's sometimes not updated for long periods of time. -## Building and Compiling -Now that you have all the required build dependencies installed, you can finally build and run emexOS. +## $${\large Building \space and \space Compiling}$$ +With all build dependencies installed, you can finally build and run emexOS. +> [!CAUTION] +> emexOS currently only supports ATA disks, if such a disk is detected emexOS **WILL/CAN DELETE IT WITHOUT ASKING** (if you have OVERWRITEALL set to 1 in the configs which is by default 0.) **Using gnu-make** -- `make fetchDeps` - Fetches all libraries and such that emexOS depends on. Obviously `git` is used for this operation. -- `make` - Builds emexOS. -- `make run` - Emulates emexOS using QEMU. -- `make clean` - Cleans up all build outputs. +- `make fetchDeps` - Fetch all libraries and such that emexOS depends on e.g. Limine. `git` and `wget` are used for this. +- `make` - Build emexOS. +- `make run` - Emulate emexOS using QEMU. +- `make clean` - Clean up all build outputs. **Using Zig** - `zig build` - Fetch, build and run. @@ -34,44 +43,20 @@ Now that you have all the required build dependencies installed, you can finally - `zig build -Dclean` - Remove (cache, output), fetch, build and run. - `zig build -Dnofetch -Dclean` - Remove (cache, output), build and run. -## Running -to run emexOS on QEMU use `make run` -on real hardware make sure your device does not have any existing data on the disk, emexOS will delete it without asking! (soon there will be a menu which asks you) - -## Console -After the bootup emexOS will ask you about a password to login. the password is "emex", but you can change that in shared/config/user.h +## $${Console}$$ +After booting, you will be asked for a password which is "emex" by default, to log in. The password can be changed in `shared/config/user.h`. -## Commands +Currently, no SMP support is available just yet so emexOS runs using only a single core. -### Common - -| command | example | output | -|-----------------|-----------------|------------------------------| -| echo | echo text | text | -| clear | clear | [clears screen] | -| help | help echo | [help menu/specific command] | -| scale | scale 3 | [font size from 1 to 4] | -| date | date | [shows current date] | -| calendar | calendar | [shows current date & time] | -| time | time | [shows current time] | -| uptime | uptime | [shows current uptime] | - -### System - -| command | example | output | -|-----------------|-----------------|------------------------------| -| meminfo | meminfo | free memory: ... | -| dofetch | dofetch | [emexOS logo, user, ...] | -| date | date | [shows current date] | - ---- - -## License: -- GNU GPLv3 -- Attribution required (see ATTRIBUTION.md) +
+

$${Contributors}$$

+ + + +
+
-## Writer - - README.md by Voxi0 & emexSW & Bi Moz - - emexOS project started by emexSW -## +
+

$\color{gray}{readme\ by\ emexSW,\ Voxi0\ and\ Bi\ Moz}$

+
\ No newline at end of file diff --git a/common.mk b/common.mk index 0b41dc3..8fb6688 100644 --- a/common.mk +++ b/common.mk @@ -15,8 +15,8 @@ VLD = @echo "[LD] $@" && $(LD) # Compiler Flags COMMON_FLAGS += -I $(INCLUDE_DIR) -I $(SRC_DIR) -I shared/ -ffreestanding -fno-stack-protector -fno-lto \ -fno-PIE -fno-pic -m64 -march=x86-64 -mno-80387 -mno-mmx \ - -mno-sse -mno-sse2 -mno-red-zone -mcmodel=kernel -Wall -Wextra -CFLAGS ?= $(COMMON_FLAGS) -std=gnu11 + -mno-sse -mno-sse2 -mno-red-zone -mcmodel=kernel -Wall -Wextra -Wpedantic +CFLAGS ?= $(COMMON_FLAGS) -std=c23 CXXFLAGS ?= $(COMMON_FLAGS) -std=c++17 -fno-exceptions -fno-rtti LDFLAGS ?= -nostdlib -static -no-pie -z text -z max-page-size=0x1000 ASFLAGS ?= -f elf64 @@ -28,8 +28,8 @@ SRC_DIR := src USERSPACE_DIR = src/userspace USERSPACE_BUILD = build/userspace BUILD_DIR := build -DISK_DIR := $(BUILD_DIR)/dsk +DISK_DIR := dsk DISK_IMG := $(DISK_DIR)/disk.img INCLUDE_DIR := include ISODIR := $(BUILD_DIR)/isodir -ISO := $(BUILD_DIR)/$(OS_NAME).iso +ISO := $(BUILD_DIR)/$(OS_NAME).iso \ No newline at end of file diff --git a/docs/Building emexOS from source b/docs/Building emexOS from source deleted file mode 100644 index 8b13789..0000000 --- a/docs/Building emexOS from source +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/Emulating_emexOS_binary_using_QEMU.md b/docs/Emulating_emexOS_binary_using_QEMU.md index 1b51f17..d266bf7 100644 --- a/docs/Emulating_emexOS_binary_using_QEMU.md +++ b/docs/Emulating_emexOS_binary_using_QEMU.md @@ -11,4 +11,4 @@ The easiest way to run emexOS is to run it in QEMU. - Choose either to enable storage or not to. - Keep the default options and select "finish". -Learn how to install QEMU in [Arch](https://github.com/BloopBiMoz/emexOS1/blob/main/docs/QEMU_Arch.md) and [Debian](https://github.com/BloopBiMoz/emexOS1/blob/main/docs/QEMU_Debian.md) based distributions. +Learn how to install QEMU in [Arch](./QEMU_Arch.md) and [Debian](./QEMU_Debian.md) based distributions. \ No newline at end of file diff --git a/dsk/disk.img b/dsk/disk.img new file mode 100644 index 0000000..dbfe748 Binary files /dev/null and b/dsk/disk.img differ diff --git a/dsk/initrd.cpio b/dsk/initrd.cpio new file mode 100644 index 0000000..becb5e9 Binary files /dev/null and b/dsk/initrd.cpio differ diff --git a/dsk/rd/bin/cat.elf b/dsk/rd/bin/cat.elf new file mode 100755 index 0000000..4ff1ee4 Binary files /dev/null and b/dsk/rd/bin/cat.elf differ diff --git a/dsk/rd/bin/cd.elf b/dsk/rd/bin/cd.elf new file mode 100755 index 0000000..d88d1a9 Binary files /dev/null and b/dsk/rd/bin/cd.elf differ diff --git a/dsk/rd/bin/echo.elf b/dsk/rd/bin/echo.elf new file mode 100755 index 0000000..8bee398 Binary files /dev/null and b/dsk/rd/bin/echo.elf differ diff --git a/dsk/rd/bin/hello.elf b/dsk/rd/bin/hello.elf new file mode 100755 index 0000000..f292287 Binary files /dev/null and b/dsk/rd/bin/hello.elf differ diff --git a/dsk/rd/bin/ls.elf b/dsk/rd/bin/ls.elf new file mode 100755 index 0000000..18a517d Binary files /dev/null and b/dsk/rd/bin/ls.elf differ diff --git a/dsk/rd/bin/lsblk.elf b/dsk/rd/bin/lsblk.elf new file mode 100755 index 0000000..42f0314 Binary files /dev/null and b/dsk/rd/bin/lsblk.elf differ diff --git a/dsk/rd/bin/reboot.elf b/dsk/rd/bin/reboot.elf new file mode 100755 index 0000000..5374ad1 Binary files /dev/null and b/dsk/rd/bin/reboot.elf differ diff --git a/dsk/rd/bin/rm.elf b/dsk/rd/bin/rm.elf new file mode 100755 index 0000000..254cf23 Binary files /dev/null and b/dsk/rd/bin/rm.elf differ diff --git a/dsk/rd/bin/tree.elf b/dsk/rd/bin/tree.elf new file mode 100755 index 0000000..2a4a630 Binary files /dev/null and b/dsk/rd/bin/tree.elf differ diff --git a/dsk/rd/boot/activeslot.txt b/dsk/rd/boot/activeslot.txt new file mode 100644 index 0000000..f70f10e --- /dev/null +++ b/dsk/rd/boot/activeslot.txt @@ -0,0 +1 @@ +A diff --git a/dsk/rd/boot/limine.conf b/dsk/rd/boot/limine.conf new file mode 100644 index 0000000..c9e16a1 --- /dev/null +++ b/dsk/rd/boot/limine.conf @@ -0,0 +1,40 @@ +timeout: 1 # better for trying on real hardware + +kaslr: yes +verbose: yes + +#wallpaper: boot():/boot/bg.jpg +default_entry: 0 + +#term_font: boot():/boot/liminefont.f15 +#term_font_size: 8x15 +#term_font_spacing: 0 + +# ---- +# Dualslot kernel system +# ---- + +# default/ active +/emexOS A + protocol: limine + kernel_path: boot():/boot/kernel_a.elf + #module_path: boot():/boot/activeslot.txt # Slot A + + module_path: boot():/boot/initrd.cpio + +# slot 2 for update +/emexOS B + protocol: limine + kernel_path: boot():/boot/kernel_b.elf + #module_path: boot():/boot/activeslot.txt # slot B + + module_path: boot():/boot/initrd.cpio + + +# ---- +# resolutions +# ---- + +# resolution: 1920x1080x32 +# resolution: 2560x1440x32 +# resolution: 3840x2160x32 diff --git a/shared/ui/assets/bootlogo.bin b/dsk/rd/boot/ui/assets/bootlogo.bin similarity index 100% rename from shared/ui/assets/bootlogo.bin rename to dsk/rd/boot/ui/assets/bootlogo.bin diff --git a/shared/theme/font8x15.bin b/dsk/rd/boot/ui/fonts/font8x15.bin similarity index 100% rename from shared/theme/font8x15.bin rename to dsk/rd/boot/ui/fonts/font8x15.bin diff --git a/dsk/rd/boot/ui/fonts/unifont.sfn b/dsk/rd/boot/ui/fonts/unifont.sfn new file mode 100644 index 0000000..4a5addd Binary files /dev/null and b/dsk/rd/boot/ui/fonts/unifont.sfn differ diff --git a/dsk/rd/emr/.emxrc b/dsk/rd/emr/.emxrc new file mode 100644 index 0000000..9acf122 --- /dev/null +++ b/dsk/rd/emr/.emxrc @@ -0,0 +1,11 @@ +var login_path = ("/emr/system/login.elf") +var shell_path = (ep: "/user/apps/shell.emx") +var gui_path = (ep: "/user/apps/gui.emx") + +// ep == emex package + +//exec -f"ep" gui_path + +// last things which should happen +exec login_path +exec -f"ep" shell_path diff --git a/dsk/rd/emr/assets/copy_folders.bmp b/dsk/rd/emr/assets/copy_folders.bmp new file mode 100644 index 0000000..d360fe7 Binary files /dev/null and b/dsk/rd/emr/assets/copy_folders.bmp differ diff --git a/dsk/rd/emr/assets/file.bmp b/dsk/rd/emr/assets/file.bmp new file mode 100644 index 0000000..171ed6c Binary files /dev/null and b/dsk/rd/emr/assets/file.bmp differ diff --git a/dsk/rd/emr/assets/folder.bmp b/dsk/rd/emr/assets/folder.bmp new file mode 100644 index 0000000..b83966d Binary files /dev/null and b/dsk/rd/emr/assets/folder.bmp differ diff --git a/dsk/rd/emr/assets/locked_folder.bmp b/dsk/rd/emr/assets/locked_folder.bmp new file mode 100644 index 0000000..cf40e8b Binary files /dev/null and b/dsk/rd/emr/assets/locked_folder.bmp differ diff --git a/dsk/rd/emr/assets/system_file.bmp b/dsk/rd/emr/assets/system_file.bmp new file mode 100644 index 0000000..5553d3e Binary files /dev/null and b/dsk/rd/emr/assets/system_file.bmp differ diff --git a/dsk/rd/emr/assets/this_disk.bmp b/dsk/rd/emr/assets/this_disk.bmp new file mode 100644 index 0000000..8f6b976 Binary files /dev/null and b/dsk/rd/emr/assets/this_disk.bmp differ diff --git a/shared/keymaps/DE.map b/dsk/rd/emr/config/keymaps/DE.map similarity index 100% rename from shared/keymaps/DE.map rename to dsk/rd/emr/config/keymaps/DE.map diff --git a/shared/keymaps/PL.map b/dsk/rd/emr/config/keymaps/PL.map similarity index 100% rename from shared/keymaps/PL.map rename to dsk/rd/emr/config/keymaps/PL.map diff --git a/dsk/rd/emr/config/keymaps/RU.map b/dsk/rd/emr/config/keymaps/RU.map new file mode 100644 index 0000000..96e99c0 --- /dev/null +++ b/dsk/rd/emr/config/keymaps/RU.map @@ -0,0 +1,62 @@ +# Russian JCUKEN keyboard layout (CP1251 encoding) + +# row 1 - numbers +0x02 = '1' '!' +0x03 = '2' '@' +0x04 = '3' '#' +0x05 = '4' '$' +0x06 = '5' '%' +0x07 = '6' '^' +0x08 = '7' '&' +0x09 = '8' '*' +0x0A = '9' '(' +0x0B = '0' ')' +0x0C = '-' '_' +0x0D = '=' '+' + +# row 2 - JCUKEN +0x10 = '\xE9' '\xC9' +0x11 = '\xF6' '\xD6' +0x12 = '\xF3' '\xD3' +0x13 = '\xEA' '\xCA' +0x14 = '\xE5' '\xC5' +0x15 = '\xED' '\xCD' +0x16 = '\xE3' '\xC3' +0x17 = '\xF8' '\xD8' +0x18 = '\xF9' '\xD9' +0x19 = '\xE7' '\xC7' +0x1A = '\xF5' '\xD5' +0x1B = '\xFA' '\xDA' + +# row 3 +0x1E = '\xF4' '\xD4' +0x1F = '\xFB' '\xDB' +0x20 = '\xE2' '\xC2' +0x21 = '\xE0' '\xC0' +0x22 = '\xEF' '\xCF' +0x23 = '\xF0' '\xD0' +0x24 = '\xEE' '\xCE' +0x25 = '\xEB' '\xCB' +0x26 = '\xE4' '\xC4' +0x27 = '\xE6' '\xC6' +0x28 = '\xFD' '\xDD' + +# row 4 +0x2C = '\xFF' '\xDF' +0x2D = '\xF7' '\xD7' +0x2E = '\xF1' '\xD1' +0x2F = '\xEC' '\xCC' +0x30 = '\xE8' '\xC8' +0x31 = '\xF2' '\xD2' +0x32 = '\xFC' '\xDC' +0x33 = '\xE1' '\xC1' +0x34 = '\xFE' '\xDE' + +# backtick = ё/Ё +0x29 = '\xB8' '\xA8' + +# special keys +0x0E = '\b' '\b' +0x0F = '\t' '\t' +0x1C = '\n' '\n' +0x39 = ' ' ' ' diff --git a/shared/keymaps/US.map b/dsk/rd/emr/config/keymaps/US.map similarity index 100% rename from shared/keymaps/US.map rename to dsk/rd/emr/config/keymaps/US.map diff --git a/dsk/rd/emr/config/keymaps/keymap.cfg b/dsk/rd/emr/config/keymaps/keymap.cfg new file mode 100644 index 0000000..dc62f5d --- /dev/null +++ b/dsk/rd/emr/config/keymaps/keymap.cfg @@ -0,0 +1,6 @@ +KEYMAP: US + +#DE: path("/emr/config/keymaps/DE.map"); +#PL: path("/emr/config/keymaps/PL.map"); +#US: path("/emr/config/keymaps/US.map"); +#RU: path("/emr/config/keymaps/RU.map"); diff --git a/dsk/rd/emr/config/system.ecfg b/dsk/rd/emr/config/system.ecfg new file mode 100644 index 0000000..add10e2 --- /dev/null +++ b/dsk/rd/emr/config/system.ecfg @@ -0,0 +1,7 @@ +# +# System config +# system.emcg (emex config) +# + +OS_DEFNAME: "emexOS [x86_64] "; +OS_DEFRELEASE: "v0.5"; diff --git a/dsk/rd/emr/config/user.ecfg b/dsk/rd/emr/config/user.ecfg new file mode 100644 index 0000000..b3b9df5 --- /dev/null +++ b/dsk/rd/emr/config/user.ecfg @@ -0,0 +1,9 @@ +# +# User config +# user.emcg (emex config) +# + +PC_NAME: "pc" +USER_NAME: "emex" +PASSWORD: "emex" +DEFAULT_KM: US diff --git a/src/drivers/drivers.cfg b/dsk/rd/emr/drivers/drivers.cfg similarity index 100% rename from src/drivers/drivers.cfg rename to dsk/rd/emr/drivers/drivers.cfg diff --git a/dsk/rd/emr/system.ini b/dsk/rd/emr/system.ini new file mode 100644 index 0000000..232d78d --- /dev/null +++ b/dsk/rd/emr/system.ini @@ -0,0 +1,3 @@ +[GENERAL] +default_shell="/user/bin/shell.elf" +root_user=admin # from users.ini diff --git a/dsk/rd/emr/system/login.elf b/dsk/rd/emr/system/login.elf new file mode 100755 index 0000000..4162f16 Binary files /dev/null and b/dsk/rd/emr/system/login.elf differ diff --git a/dsk/rd/emr/system/srv.emx/app.elf b/dsk/rd/emr/system/srv.emx/app.elf new file mode 100755 index 0000000..e22e426 Binary files /dev/null and b/dsk/rd/emr/system/srv.emx/app.elf differ diff --git a/dsk/rd/emr/system/srv.emx/package.info b/dsk/rd/emr/system/srv.emx/package.info new file mode 100644 index 0000000..9350078 --- /dev/null +++ b/dsk/rd/emr/system/srv.emx/package.info @@ -0,0 +1,2 @@ +x1srv +emex \ No newline at end of file diff --git a/dsk/rd/emr/system/system.emx/app.elf b/dsk/rd/emr/system/system.emx/app.elf new file mode 100755 index 0000000..195d898 Binary files /dev/null and b/dsk/rd/emr/system/system.emx/app.elf differ diff --git a/dsk/rd/emr/system/system.emx/package.info b/dsk/rd/emr/system/system.emx/package.info new file mode 100644 index 0000000..e7767fe --- /dev/null +++ b/dsk/rd/emr/system/system.emx/package.info @@ -0,0 +1,10 @@ + + + emr_system + + + emex + [] + [] + + diff --git a/dsk/rd/emr/system/ter-powerline-v16n.psf b/dsk/rd/emr/system/ter-powerline-v16n.psf new file mode 100644 index 0000000..13a4489 Binary files /dev/null and b/dsk/rd/emr/system/ter-powerline-v16n.psf differ diff --git a/dsk/rd/emr/users.ini b/dsk/rd/emr/users.ini new file mode 100644 index 0000000..a78d33f --- /dev/null +++ b/dsk/rd/emr/users.ini @@ -0,0 +1,7 @@ +[USERS] +users=admin,user + +[admin] +permissions=administrator +[user] +permissions=user diff --git a/dsk/rd/user/apps/gui.emx/app.elf b/dsk/rd/user/apps/gui.emx/app.elf new file mode 100755 index 0000000..a751917 Binary files /dev/null and b/dsk/rd/user/apps/gui.emx/app.elf differ diff --git a/dsk/rd/user/apps/gui.emx/package.info b/dsk/rd/user/apps/gui.emx/package.info new file mode 100644 index 0000000..bb06ff6 --- /dev/null +++ b/dsk/rd/user/apps/gui.emx/package.info @@ -0,0 +1,4 @@ +gui +emexOS +0.1 +starts the mouse cursor daemon \ No newline at end of file diff --git a/src/userspace/hello.elf b/dsk/rd/user/apps/hello.elf similarity index 100% rename from src/userspace/hello.elf rename to dsk/rd/user/apps/hello.elf diff --git a/dsk/rd/user/apps/hello.emx/app.elf b/dsk/rd/user/apps/hello.emx/app.elf new file mode 100755 index 0000000..3e654b5 Binary files /dev/null and b/dsk/rd/user/apps/hello.emx/app.elf differ diff --git a/dsk/rd/user/apps/hello.emx/app_icon.bmp b/dsk/rd/user/apps/hello.emx/app_icon.bmp new file mode 100644 index 0000000..e69de29 diff --git a/dsk/rd/user/apps/hello.emx/package.info b/dsk/rd/user/apps/hello.emx/package.info new file mode 100644 index 0000000..eae9087 --- /dev/null +++ b/dsk/rd/user/apps/hello.emx/package.info @@ -0,0 +1,10 @@ + + + hello.elf + + + ein_franzose + 3001.0 + does cool stuff + + diff --git a/dsk/rd/user/apps/shell.emx/app.elf b/dsk/rd/user/apps/shell.emx/app.elf new file mode 100755 index 0000000..cba027a Binary files /dev/null and b/dsk/rd/user/apps/shell.emx/app.elf differ diff --git a/dsk/rd/user/apps/shell.emx/package.info b/dsk/rd/user/apps/shell.emx/package.info new file mode 100644 index 0000000..055ff67 --- /dev/null +++ b/dsk/rd/user/apps/shell.emx/package.info @@ -0,0 +1,10 @@ + + + shell + + + emex + v0.0.1a + emx userspace shell + + diff --git a/dsk/rd/user/apps/test.t b/dsk/rd/user/apps/test.t new file mode 100644 index 0000000..b14df64 --- /dev/null +++ b/dsk/rd/user/apps/test.t @@ -0,0 +1 @@ +Hi diff --git a/shared/images/frog.bmp b/dsk/rd/user/images/frog.bmp similarity index 100% rename from shared/images/frog.bmp rename to dsk/rd/user/images/frog.bmp diff --git a/flake.lock b/flake.lock index 171c4ba..ba65bc9 100644 --- a/flake.lock +++ b/flake.lock @@ -1,30 +1,12 @@ { "nodes": { - "flake-utils": { - "inputs": { - "systems": "systems" - }, - "locked": { - "lastModified": 1731533236, - "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, "nixpkgs": { "locked": { - "lastModified": 1762111121, - "narHash": "sha256-4vhDuZ7OZaZmKKrnDpxLZZpGIJvAeMtK6FKLJYUtAdw=", + "lastModified": 1772198003, + "narHash": "sha256-I45esRSssFtJ8p/gLHUZ1OUaaTaVLluNkABkk6arQwE=", "owner": "nixos", "repo": "nixpkgs", - "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev": "dd9b079222d43e1943b6ebd802f04fd959dc8e61", "type": "github" }, "original": { @@ -36,8 +18,8 @@ }, "root": { "inputs": { - "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs" + "nixpkgs": "nixpkgs", + "systems": "systems" } }, "systems": { diff --git a/flake.nix b/flake.nix index eb85cbf..3054dba 100644 --- a/flake.nix +++ b/flake.nix @@ -2,18 +2,39 @@ description = "emexos dev flake"; inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; - flake-utils.url = "github:numtide/flake-utils"; + systems.url = "github:nix-systems/default"; }; - outputs = inputs: inputs.flake-utils.lib.eachDefaultSystem(system: let - pkgs = import inputs.nixpkgs {inherit system;}; + outputs = inputs: let + forEachSystem = inputs.nixpkgs.lib.genAttrs (import inputs.systems); + pkgs = forEachSystem (system: import inputs.nixpkgs {inherit system;}); in { - devShells.default = pkgs.mkShellNoCC { - nativeBuildInputs = with pkgs; [ - pkgsCross.x86_64-embedded.stdenv.cc - nasm - libisoburn - git - ]; - }; - }); -} + formatter = forEachSystem (system: pkgs.${system}.alejandra); + devShells = forEachSystem (system: { + default = pkgs.${system}.mkShellNoCC { + nativeBuildInputs = with pkgs.${system}; [ + # Compiler and assembler + pkgsCross.x86_64-embedded.stdenv.cc + gcc # For building Limine + nasm + + # Provides a lot of handy tools for C/C++ dev e.g. formatter (clang-format) + clang-tools + + # For generating a `compile_commands.json` which can be used by clangd + # That file is used by the clangd lsp to figure out includes and all + compiledb + + # Provides `xorriso` for creating the emexOS ISO + libisoburn + + # Emulator + qemu + + # Git and wget are required to fetch some dependencies + git + wget + ]; + }; + }); + }; +} \ No newline at end of file diff --git a/limine b/limine deleted file mode 160000 index 0aa46ad..0000000 --- a/limine +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0aa46ad0a034a111df345dd80c3b950629041e2b diff --git a/limine.conf b/limine.conf index 3f967fa..c9e16a1 100644 --- a/limine.conf +++ b/limine.conf @@ -1,4 +1,4 @@ -timeout: 10 # better for trying on real hardware +timeout: 1 # better for trying on real hardware kaslr: yes verbose: yes @@ -20,15 +20,7 @@ default_entry: 0 kernel_path: boot():/boot/kernel_a.elf #module_path: boot():/boot/activeslot.txt # Slot A - module_path: boot():/boot/ui/assets/bootlogo.bin - module_path: boot():/boot/keymaps/US.map - module_path: boot():/boot/keymaps/DE.map - #module_path: boot():/boot/keymaps/PL.map - #module_path: boot():/boot/images/logo.bmp - #module_path: boot():/boot/images/background.bmp - module_path: boot():/boot/images/frog.bmp - module_path: boot():/boot/programs/hello.elf - + module_path: boot():/boot/initrd.cpio # slot 2 for update /emexOS B @@ -36,15 +28,7 @@ default_entry: 0 kernel_path: boot():/boot/kernel_b.elf #module_path: boot():/boot/activeslot.txt # slot B - module_path: boot():/boot/ui/assets/bootlogo.bin - module_path: boot():/boot/keymaps/US.map - module_path: boot():/boot/keymaps/DE.map - #module_path: boot():/boot/keymaps/PL.map - #module_path: boot():/boot/images/logo.bmp - #module_path: boot():/boot/images/background.bmp - module_path: boot():/boot/images/frog.bmp - module_path: boot():/boot/programs/hello.elf - + module_path: boot():/boot/initrd.cpio # ---- diff --git a/logo.txt b/logo.txt index 27f6699..301ff4c 100644 --- a/logo.txt +++ b/logo.txt @@ -1,10 +1,29 @@ - ###########;m; ###########;m; - # ####### #;m; # ###########;m; - ##########;m; #; ###; #####;m; ##########;m; ###;m; ###;m; # #;m; # #;m; # #;m; - # ######## #;m; ## ## #;# ## #;m; # ######## #;m; # #;m; # #;m; # #;m; # #;m; # #;m; -# #;m; # #;m; # #; # # #; # #;m; # #;m; # #;m; # #;m;# #;m; # #;m; # #;m; # #########;m; -# ######## #;m; # #; # #; # #;m; # ######## #;m; # ### #;m; # #;m; # #;m; ######### #;m; -# ##########;m; # #; # #; # #;m; # ##########;m; # ### #;m; # #;m; # #;m; # #;m; -# #;m; # #; # #; # #;m; # #;m; # #;m;# #;m; # #;m; # #;m; # #;m; - # ########## #;m; # #; # #; # #;m; # ########## #;m; # #;m; # #;m; # ####### #;m; ########### #;m; - ###########;m; # #; # #; # #;m; ###########;m; ###;m; ###;m; ###########;m; ##########;m; + ###########;m; ###########;m; + # ####### #;m; # ###########;m; + ##########;m; #; ###; #####;m; ##########;m; ###;m; ###;m; # #;m; # #;m; # #;m; + # ######## #;m; ## ## #;# ## #;m; # ######## #;m; # #;m; # #;m; # #;m; # #;m; # #;m; + # #;m; # #;m; # #; # # #; # #;m; # #;m; # #;m; # #;m;# #;m; # #;m; # #;m; # #########;m; + # ######## #;m; # #; # #; # #;m; # ######## #;m; # ### #;m; # #;m; # #;m; ######### #;m; + # ##########;m; # #; # #; # #;m; # ##########;m; # ### #;m; # #;m; # #;m; # #;m; + # #;m; # #; # #; # #;m; # #;m; # #;m;# #;m; # #;m; # #;m; # #;m; + # ########## #;m; # #; # #; # #;m; # ########## #;m; # #;m; # #;m; # ####### #;m; ########### #;m; + ###########;m; # #; # #; # #;m; ###########;m; ###;m; ###;m; ###########;m; ##########;m; + +┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬────────────┐ +│ esc │ f1 │ f2 │ f3 │ f4 │ f5 │ f6 │ f7 │ f8 │ f9 │ f10 │ f11 │ f12 │ power │ +├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼────────────┤ +│ ~ │ ! │ @ │ # │ $ │ % │ ^ │ & │ * │ ( │ ) │ _ │ + │ │ +│ ` │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ — │ = │ delete │ +├─────┴─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┬──────┤ +│ │ │ │ │ │ │ │ │ │ │ │ { │ } │ | │ +│ tab │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │ [ │ ] │ \ │ +├───────────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┴──────┤ +│ │ │ │ │ │ │ │ │ │ │ : │ “ │ │ +│ caps lock │ A │ S │ D │ F │ G │ H │ J │ K │ L │ ; │ ' │ enter │ +├───────────┴──┬──┴──┬──┴──┬──┴──┬──┴──┬──┴──┬──┴──┬──┴──┬──┴──┬──┴──┬──┴──┬──┴────────────┤ +│ │ │ │ │ │ │ │ │ < │ > │ ? │ │ +│ shift │ Z │ X │ C │ V │ B │ N │ M │ , │ . │ / │ shift │ +├─────┬──────┬─┴───┬─┴───┬─┴─────┴─────┴─────┴─────┴─────┼─────┼─────┼─────┴┬───────┬──────┤ +│ │ │ │ │ │ │ ├──────┤ ^ ├──────┤ +│ fn │ ctrl │ opt │ cmd │ s p a c e │ cmd │ opt │ < ├───────┤ > │ +└─────┴──────┴─────┴─────┴───────────────────────────────┴─────┴─────┴──────┴───────┴──────┘ diff --git a/shared/config/system.h b/shared/config/system.h index e861186..e84f8df 100644 --- a/shared/config/system.h +++ b/shared/config/system.h @@ -12,6 +12,8 @@ #define KERNELSPACE 0x40000000 #define KERNELPRIORITY 255 +#define JUMPTOUSER 1 + #define USE_HCF 1 #define BOOTUP_VISUALS 0 // verbose boot == 0, silent boot == 1 @@ -25,23 +27,33 @@ // on some hardware you can use "hardware compatibility off" and it will still run #define HARDWARE_SC 0 -// 1 == enable automatic formatting -// 0 == require manual formatting -// NOTE: this will ERASE *ALL DATA* on your disk if enabled! -#define OVERWRITEALL 0 - #if HARDWARE_SC == 1 - #define ENABLE_FAT32 0 - #define ENABLE_ATA 0 - #define ENABLE_ULIME 0 - #define ENABLE_GLIME 0 +# define ENABLE_FAT32 0 +# define ENABLE_ATA 0 +# define ENABLE_ULIME 0 +# define ENABLE_GLIME 0 #else - #define ENABLE_FAT32 1 - #define ENABLE_ATA 1 - #define ENABLE_ULIME 1 - #define ENABLE_GLIME 1 +# define ENABLE_FAT32 1 +# define ENABLE_ATA 1 +# define ENABLE_ULIME 1 +# define ENABLE_GLIME 1 #endif #define X64 1 #define RISCV 0 #define ARM64 0 + +#define EMEX "emex" +#define EMEX1 "EMEX" +#define EMEX2 "[emex]" +#define EMEX3 "[EMEX]" +#define EMEX4 "emx" +#define EMX EMEX4 + + +// 1 == enable automatic formatting +// 0 == require manual formatting +// NOTE: this will ERASE *ALL DATA* on your disk if enabled! +#define OVERWRITEALL 0 + +//#define NULL_ 1 \ No newline at end of file diff --git a/shared/config/tasks.h b/shared/config/tasks.h new file mode 100644 index 0000000..e83f4aa --- /dev/null +++ b/shared/config/tasks.h @@ -0,0 +1,6 @@ +#pragma once + +#define SOCKET1 0 +#define SOCKET2 0 +#define SOCKET3 1 +#define SOCKET4 0 diff --git a/shared/config/user_config.c b/shared/config/user_config.c index ee668bd..8e8bdf6 100644 --- a/shared/config/user_config.c +++ b/shared/config/user_config.c @@ -1,5 +1,6 @@ #include "user_config.h" #include +#include #include #include diff --git a/shared/keymaps/dirs.cfg b/shared/keymaps/dirs.cfg deleted file mode 100644 index 84046ff..0000000 --- a/shared/keymaps/dirs.cfg +++ /dev/null @@ -1,3 +0,0 @@ -DE: path("/emr/config/keymaps/DE.map"); -PL: path("/emr/config/keymaps/PL.map"); -US: path("/emr/config/keymaps/US.map"); diff --git a/shared/memory/mem.c b/shared/memory/mem.c index 3ab74c6..9e5256b 100644 --- a/shared/memory/mem.c +++ b/shared/memory/mem.c @@ -7,16 +7,38 @@ void memset(void *ptr, u8 val, size_t n) { u8 *p = (u8 *)ptr; - for (size_t i = 0; i < n; i++) - p[i] = val; + + while (n && ((size_t)p & 7)) { *p++ = val; n--; } + + // fill 8 bytes at a time + u64 fill = (u64)val * 0x0101010101010101ULL; + u64 *p64 = (u64 *)p; + size_t blocks = n / 8; + while (blocks--) *p64++ = fill; + + // remaining bytes + p = (u8 *)p64; + n &= 7; + while (n--) *p++ = val; } void memcpy(void *dst, const void *src, size_t n) { u8 *d = (u8 *)dst; + u64 *d64 = (u64 *)d; const u8 *s = (const u8 *)src; - for (size_t i = 0; i < n; i++) - d[i] = s[i]; + const u64 *s64 = (const u64 *)s; + + size_t blocks = n / 8; // 8 bytes + + while (n && ((size_t)d & 7)) { *d++ = *s++; n--; } + while (blocks--) *d64++ = *s64++; + + // remaining bytes + d = (u8 *)d64; + s = (const u8 *)s64; + n &= 7; + while (n--) *d++ = *s++; } void memmove(void *dst, const void *src, size_t n) @@ -24,12 +46,27 @@ void memmove(void *dst, const void *src, size_t n) u8 *d = (u8 *)dst; const u8 *s = (const u8 *)src; + if (d == s || n == 0) return; + if (d < s) { - for (size_t i = 0; i < n; i++) - d[i] = s[i]; + // forward copy: align then 8-byte chunks + while (n && ((size_t)d & 7)) { *d++ = *s++; n--; } + u64 *d64 = (u64 *)d; + const u64 *s64 = (const u64 *)s; + size_t blocks = n / 8; + while (blocks--) *d64++ = *s64++; + d = (u8 *)d64; s = (const u8 *)s64; n &= 7; + while (n--) *d++ = *s++; } else { - for (size_t i = n; i > 0; i--) - d[i - 1] = s[i - 1]; + // backward copy to handle overlap + d += n; s += n; + while (n && ((size_t)d & 7)) { *--d = *--s; n--; } + u64 *d64 = (u64 *)d; + const u64 *s64 = (const u64 *)s; + size_t blocks = n / 8; + while (blocks--) *--d64 = *--s64; + d = (u8 *)d64; s = (const u8 *)s64; n &= 7; + while (n--) *--d = *--s; } } diff --git a/shared/string/log.c b/shared/string/log.c deleted file mode 100644 index 316211e..0000000 --- a/shared/string/log.c +++ /dev/null @@ -1,144 +0,0 @@ -#include "log.h" -#include -#include -#include -#include -#include - -static u32 get_log_color(log_level_t level) { - switch (level) { - case LSUCCESS: - return LCOLOR_SCS; - case LWARNING: - return LCOLOR_WAR; - case LERROR: - return LCOLOR_ERR; - case LDEF: - default: - return LCOLOR_D; - } -} - - - -void log_message(const char *tag, const char *message, log_level_t level) { - if (!tag || !message) return; - - u32 msg_color = get_log_color(level); - - // gray - //print("[", LCOLOR_BRACKET); - print(tag, LCOLOR_TAG); - print(" ", LCOLOR_BRACKET); - - print(message, msg_color); - //printf("%s %s", tag, message); -} -void log_printf(log_level_t level, const char *tag, const char *format, ...) { - if (!tag || !format) return; - - u32 msg_color = get_log_color(level); - - // gray - //print("[", LCOLOR_BRACKET); - print(tag, LCOLOR_TAG); - print(" ", LCOLOR_BRACKET); - - - - va_list args; - va_start(args, format); - char buffer[512]; - int pos = 0; - - // formated string - for (const char *p = format; *p && pos < 511; p++) { - if (*p == '%' && *(p + 1)) { - p++; - switch (*p) { - case 's': { - const char *s = va_arg(args, const char*); - if (s) { - while (*s && pos < 511) { - buffer[pos++] = *s++; - } - } - break; - } - case 'd': - case 'i': { - int val = va_arg(args, int); - char num_buf[32]; - str_from_int(num_buf, val); - for (char *n = num_buf; *n && pos < 511; n++) { - buffer[pos++] = *n; - } - break; - } - case 'u': { - u32 val = va_arg(args, u32); - char num_buf[32]; - num_buf[0] = '\0'; - str_append_uint(num_buf, val); - for (char *n = num_buf; *n && pos < 511; n++) { - buffer[pos++] = *n; - } - break; - } - case 'x': - case 'X': { - u32 val = va_arg(args, u32); - char hex_buf[16]; - int hex_pos = 0; - if (val == 0) { - hex_buf[hex_pos++] = '0'; - } else { - u32 temp = val; - while (temp > 0 && hex_pos < 15) { - int digit = temp % 16; - hex_buf[hex_pos++] = (digit < 10) ? ('0' + digit) : ('a' + digit - 10); - temp /= 16; - } - } - hex_buf[hex_pos] = '\0'; - // reverse hex string - for (int i = hex_pos - 1; i >= 0 && pos < 511; i--) { - buffer[pos++] = hex_buf[i]; - } - break; - } - case 'c': { - char c = (char)va_arg(args, int); - if (pos < 511) { - buffer[pos++] = c; - } - break; - } - case '%': { - if (pos < 511) { - buffer[pos++] = '%'; - } - break; - } - default: - if (pos < 511) { - buffer[pos++] = '%'; - } - if (pos < 511) { - buffer[pos++] = *p; - } - break; - } - } else { - buffer[pos++] = *p; - } - } - - buffer[pos] = '\0'; - va_end(args); - - - - print(buffer, msg_color); - //printf("%s", buffer); -} diff --git a/shared/string/string.c b/shared/string/string.c index fdfe129..2163ae9 100644 --- a/shared/string/string.c +++ b/shared/string/string.c @@ -1,5 +1,5 @@ #include "string.h" -#include "print.h" +//#include "print.h" void str_copy(char *dest, const char *src) { diff --git a/shared/string/string.h b/shared/string/string.h index e495714..e143d12 100644 --- a/shared/string/string.h +++ b/shared/string/string.h @@ -2,11 +2,14 @@ #define STRING_H #include -#include "print.h" -#include "log.h" +//#include "print.h" +//#include "log.h" #include #include +#include +#include + void str_copy(char *dest, const char *src); void str_append(char *dest, const char *src); void str_append_uint(char *dest, u32 num); diff --git a/shared/syscalls/mmap.h b/shared/syscalls/mmap.h new file mode 100644 index 0000000..a24afe7 --- /dev/null +++ b/shared/syscalls/mmap.h @@ -0,0 +1,29 @@ +#ifndef MMAP_ARGS_H +#define MMAP_ARGS_H + +typedef struct { + unsigned long addr; + unsigned long length; + int prot; + int flags; + int fd; + long offset; +} mmap_args_t; + +// prot flags +#define PROT_NONE 0x00 +#define PROT_READ 0x01 +#define PROT_WRITE 0x02 +#define PROT_EXEC 0x04 + +// default flags +#define MAP_SHARED 0x01 +#define MAP_PRIVATE 0x02 +#define MAP_ANONYMOUS 0x20 +#define MAP_ANON MAP_ANONYMOUS +#define MAP_FAILED ((void *)-1) + +#define _SCAL_MMAP 9 +#define _SCAL_MUNMAP 11 + +#endif \ No newline at end of file diff --git a/shared/theme/bootconf.emcg b/shared/theme/bootconf.emcg deleted file mode 100644 index d24b17a..0000000 --- a/shared/theme/bootconf.emcg +++ /dev/null @@ -1,76 +0,0 @@ -include stdio; # printf, print, printInt -include stdclrs; - -# -# emexOS boot configuration -# bootconf.emcg (emex config) -# - -# bootup visuals -BOOTUP_VISUALS 0; # verbose boot == 0, silent boot == 1 -BOOTUP_COLOR_THEME STD -BOOTSCREEN_BG_COLOR GFX_ST_BLACK -BOOTSCREEN_COLOR GFX_ST_WHITE -LOGO_SCALE 1 - -# macros -if BOOTUP_VISUALS == 0: - BOOTUP_PRINTF(fmt, ...) == printf(fmt, ##__VA_ARGS__); - BOOTUP_PRINT(msg, col) == (__c__ #inline c - { - do { - print(msg, col); - if (boot_log_fd >= 0) fs_write(boot_log_fd, msg, str_len(msg)); - } while(0) - - }__c__); - - BOOTUP_PRINT_INT(num, col) == (__c__ - { - do { - printInt(num, col); - if (boot_log_fd >= 0) { - char buf[12]; - buf[0] = '\0'; - str_append_uint(buf, (u32)num); - fs_write(boot_log_fd, buf, str_len(buf)); - } - } while(0); - }__c__); - -else: - BOOTUP_PRINTF(fmt, ...) == ((void)0); - - BOOTUP_PRINT(msg, col) == (__c__ #inline c - { - do { - printf("%s", msg); - if (boot_log_fd >= 0) fs_write(boot_log_fd, msg, str_len(msg)); - } while(0) - - }__c__); - - BOOTUP_PRINT_INT(num, col) == (__c__ - { - do { - printInt(num, col); - if (boot_log_fd >= 0) { - char buf[12]; - buf[0] = '\0'; - str_append_uint(buf, (u32)num); - fs_write(boot_log_fd, buf, str_len(buf)); - } - } while(0); - }__c__); -end; - -# console -CONSOLESCREEN_BG_COLOR GFX_BG -CONSOLESCREEN_COLOR GFX_WHITE -CONSOLE_COLOR_THEME FLU - -# panic screen -PANICSCREEN_BG_COLOR GFX_ST_BLUE -PANICSCREEN_COLOR GFX_ST_WHITE -PANICSCREEN_COLOR_R GFX_ST_RED -PANIC_COLOR_THEME STD diff --git a/shared/theme/doccr.h b/shared/theme/doccr.h index 2396b08..09a79df 100644 --- a/shared/theme/doccr.h +++ b/shared/theme/doccr.h @@ -1,5 +1,7 @@ #pragma once #include "stdclrs.h" +#include "../ui/fonts.h" + #include // fs_write & fs_open #include #include @@ -33,8 +35,9 @@ extern int init_boot_log; #define CONSOLE_COLOR_THEME FLU //panic -#define PANIC_FONT FONT_8X8_DOS -#define PANICSCREEN_BG_COLOR GFX_ST_BLUE +#define PANIC_FONT FONT_8X8_BOLD +#define PANICSCREEN_BG_COLOR GFX_ST_RED +#define PANICSCREEN_FG_COLOR GFX_ST_RED + GFX_ST_WHITE #define PANICSCREEN_COLOR GFX_ST_WHITE #define PANICSCREEN_COLOR_R GFX_ST_RED #define PANIC_COLOR_THEME STD diff --git a/shared/types.h b/shared/types.h index fa6411b..44c85c4 100644 --- a/shared/types.h +++ b/shared/types.h @@ -1,6 +1,11 @@ #ifndef TYPES_H #define TYPES_H +/* + * THIS IS ONLY THE KLIBC TYPES.H NOT FOR USERSPACE + * +*/ + typedef unsigned char u8; typedef unsigned short u16, USHORT; typedef unsigned int u32; diff --git a/shared/ui/fonts.c b/shared/ui/fonts.c index 88f8d57..12eec72 100644 --- a/shared/ui/fonts.c +++ b/shared/ui/fonts.c @@ -10,7 +10,7 @@ // font registery const font_t font_registry[FONT_COUNT] = { - [FONT_8X12_BOLD] = { + /*[FONT_8X12_BOLD] = { .name = "8x12_BOLD", .data = &font_8x12_bold, .char_width = 8, @@ -29,7 +29,7 @@ const font_t font_registry[FONT_COUNT] = { .lsb_left = 1, .glyph_count = 2048, .unicode_direct = 1 - }, + },*/ [FONT_8X8_BOLD] = { .name = "8x8_BOLD", .data = &font_8x8_bold, @@ -40,7 +40,7 @@ const font_t font_registry[FONT_COUNT] = { .glyph_count = 256, .unicode_direct = 0 }, - [FONT_8X16] = { + /*[FONT_8X16] = { .name = "8x16", .data = &font_8x16, .char_width = 8, @@ -59,7 +59,7 @@ const font_t font_registry[FONT_COUNT] = { .lsb_left = 0, .glyph_count = 256, .unicode_direct = 0 - }, + },*/ [FONT_8X8] = { .name = "8x8", .data = &font_8x8, @@ -70,7 +70,7 @@ const font_t font_registry[FONT_COUNT] = { .glyph_count = 256, .unicode_direct = 0 }, - [FONT_16X32] = { + /*[FONT_16X32] = { .name = "16x32", .data = &font_16x32, .char_width = 16, @@ -79,7 +79,7 @@ const font_t font_registry[FONT_COUNT] = { .lsb_left = 0, .glyph_count = 256, .unicode_direct = 0 - }/*, + }*//*, [GOHUFONT] = { .name = "gohufont", .data = &gohufont_8x16, diff --git a/shared/ui/fonts.h b/shared/ui/fonts.h index 30bcdf4..0b5a8c8 100644 --- a/shared/ui/fonts.h +++ b/shared/ui/fonts.h @@ -3,15 +3,15 @@ #include typedef enum { - FONT_8X12_BOLD = 0, - FONT_8X12 = 1, - FONT_8X8_BOLD = 2, - FONT_8X8 = 3, - FONT_8X16 = 4, - FONT_8X16_BOLD = 5, - FONT_16X32 = 6, + //FONT_8X12_BOLD = 0, + //FONT_8X12 = 1, + FONT_8X8_BOLD = 0, + FONT_8X8 = 1, + //FONT_8X16 = 4, + //FONT_8X16_BOLD = 5, + //FONT_16X32 = 6, //GOHUFONT = 7, - FONT_COUNT = 7//8 + FONT_COUNT = 2//8 } font_type_t; typedef struct { const char *name; diff --git a/shared/ui/fonts/font_8x8.h b/shared/ui/fonts/font_8x8.h index 3b1dc58..4028fbc 100644 --- a/shared/ui/fonts/font_8x8.h +++ b/shared/ui/fonts/font_8x8.h @@ -4,17 +4,28 @@ //https://github.com/SloopyCode/BitFonts static const u8 font_8x8[256][8] = { // all unused characters can be used as a custom texture (0x00 to 0x1F) - [0x00] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // null - [0x01] = { 0x10, 0x18, 0x1C, 0x1E, 0x1C, 0x18, 0x10, 0x00}, // arrow - [0x02] = { 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00}, // long dash - [0x03] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // block filled - [0x04] = { 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF}, // hollow block - [0x05] = { 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E}, // rounded block filled - [0x06] = { 0x7E, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7E}, // rounded hollow block - [0x07] = { 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C}, // circle filled - [0x08] = { 0x18, 0x7E, 0x7E, 0xFF, 0xFF, 0x7E, 0x7E, 0x18}, // circle2 filled - [0x09] = { 0x3C, 0x42, 0x81, 0x81, 0x81, 0x81, 0x42, 0x3C}, // circle outline - [0x0A] = { 0x18, 0x66, 0x42, 0x81, 0x81, 0x42, 0x66, 0x18}, // circle2 outline + [0x00] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + [0x01] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + [0x02] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + [0x03] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + [0x04] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + [0x05] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + [0x06] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + [0x07] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + [0x08] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + [0x09] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + [0x0A] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + //[0x00] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // null + //[0x01] = { 0x10, 0x18, 0x1C, 0x1E, 0x1C, 0x18, 0x10, 0x00}, // arrow + //[0x02] = { 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00}, // long dash + //[0x03] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // block filled + //[0x04] = { 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF}, // hollow block + //[0x05] = { 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E}, // rounded block filled + //[0x06] = { 0x7E, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7E}, // rounded hollow block + //[0x07] = { 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C}, // circle filled + //[0x08] = { 0x18, 0x7E, 0x7E, 0xFF, 0xFF, 0x7E, 0x7E, 0x18}, // circle2 filled + //[0x09] = { 0x3C, 0x42, 0x81, 0x81, 0x81, 0x81, 0x42, 0x3C}, // circle outline + //[0x0A] = { 0x18, 0x66, 0x42, 0x81, 0x81, 0x42, 0x66, 0x18}, // circle2 outline // and iknow there are unicode expecialy for these special characters but this is simpler for now [0x0B] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // unused @@ -142,16 +153,16 @@ static const u8 font_8x8[256][8] = { // German (custom slots) - [0x80] = { 0x00,0x00,0x28,0x00,0x38,0x04,0x3C,0x44}, // ä - [0x81] = { 0x00,0x00,0x28,0x00,0x38,0x44,0x44,0x38}, // ö - [0x82] = { 0x00,0x00,0x28,0x00,0x44,0x44,0x44,0x3C}, // ü - [0x83] = { 0x00,0x00,0x38,0x44,0x40,0x38,0x40,0x7C}, // ß + [0x80] = { 0x28,0x00,0x38,0x04,0x3C,0x44,0x3C,0x00}, // ä + [0x81] = { 0x28,0x00,0x38,0x44,0x44,0x44,0x38,0x00}, // ö + [0x82] = { 0x28,0x00,0x44,0x44,0x44,0x44,0x3C,0x00}, // ü + [0x83] = { 0x00,0x38,0x44,0x40,0x38,0x40,0x7C,0x00}, // ß // Russian (CP1251 code points) [0xA8] = { 0x7c, 0x40, 0x40, 0x78, 0x40, 0x40, 0x7c, 0x10 }, // Ё [0xB8] = { 0x28, 0x00, 0x38, 0x44, 0x78, 0x40, 0x38, 0x00 }, // ё - + [0xC0] = { 0x10, 0x28, 0x44, 0x44, 0x7c, 0x44, 0x44, 0x00 }, // А [0xC1] = { 0x78, 0x40, 0x40, 0x78, 0x44, 0x44, 0x78, 0x00 }, // Б [0xC2] = { 0x78, 0x44, 0x44, 0x78, 0x44, 0x44, 0x78, 0x00 }, // В diff --git a/shared/ui/fonts/font_8x8_bold.h b/shared/ui/fonts/font_8x8_bold.h index 90c11bb..49c079d 100644 --- a/shared/ui/fonts/font_8x8_bold.h +++ b/shared/ui/fonts/font_8x8_bold.h @@ -3,18 +3,29 @@ #include //https://github.com/SloopyCode/BitFonts static const u8 font_8x8_bold[256][8] = { - // all unused characters can be used as a custom texture (0x00 to 0x1F) - [0x00] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // null - [0x01] = { 0x10, 0x18, 0x1C, 0x1E, 0x1C, 0x18, 0x10, 0x00}, // arrow - [0x02] = { 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00}, // long dash - [0x03] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // block filled - [0x04] = { 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF}, // hollow block - [0x05] = { 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E}, // rounded block filled - [0x06] = { 0x7E, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7E}, // rounded hollow block - [0x07] = { 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C}, // circle filled - [0x08] = { 0x18, 0x7E, 0x7E, 0xFF, 0xFF, 0x7E, 0x7E, 0x18}, // circle2 filled - [0x09] = { 0x3C, 0x42, 0x81, 0x81, 0x81, 0x81, 0x42, 0x3C}, // circle outline - [0x0A] = { 0x18, 0x66, 0x42, 0x81, 0x81, 0x42, 0x66, 0x18}, // circle2 outline + // all unused characters can be used as a custom texture (0x00 to 0x1F) + [0x00] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + [0x01] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + [0x02] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + [0x03] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + [0x04] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + [0x05] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + [0x06] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + [0x07] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + [0x08] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + [0x09] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + [0x0A] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + //[0x00] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // null + //[0x01] = { 0x10, 0x18, 0x1C, 0x1E, 0x1C, 0x18, 0x10, 0x00}, // arrow + //[0x02] = { 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00}, // long dash + //[0x03] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // block filled + //[0x04] = { 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF}, // hollow block + //[0x05] = { 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E}, // rounded block filled + //[0x06] = { 0x7E, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7E}, // rounded hollow block + //[0x07] = { 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C}, // circle filled + //[0x08] = { 0x18, 0x7E, 0x7E, 0xFF, 0xFF, 0x7E, 0x7E, 0x18}, // circle2 filled + //[0x09] = { 0x3C, 0x42, 0x81, 0x81, 0x81, 0x81, 0x42, 0x3C}, // circle outline + //[0x0A] = { 0x18, 0x66, 0x42, 0x81, 0x81, 0x42, 0x66, 0x18}, // circle2 outline // and iknow there are unicode expecialy for these special characters but this is simpler for now [0x0B] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // unused @@ -141,10 +152,10 @@ static const u8 font_8x8_bold[256][8] = { [0x007E] = {0x76,0xdc,0x00,0x00,0x00,0x00,0x00,0x00}, // ~ // German (custom slots) - [0x80] = { 0x00,0x00,0x28,0x00,0x38,0x04,0x3C,0x44}, // ä - [0x81] = { 0x00,0x00,0x28,0x00,0x38,0x44,0x44,0x38}, // ö - [0x82] = { 0x00,0x00,0x28,0x00,0x44,0x44,0x44,0x3C}, // ü - [0x83] = { 0x00,0x00,0x38,0x44,0x40,0x38,0x40,0x7C}, // ß + [0x80] = { 0x28,0x00,0x38,0x04,0x3C,0x44,0x3C,0x00}, // ä + [0x81] = { 0x28,0x00,0x38,0x44,0x44,0x44,0x38,0x00}, // ö + [0x82] = { 0x28,0x00,0x44,0x44,0x44,0x44,0x3C,0x00}, // ü + [0x83] = { 0x00,0x38,0x44,0x40,0x38,0x40,0x7C,0x00}, // ß // Russian (CP1251 code points) [0xA8] = { 0x7c, 0x40, 0x40, 0x78, 0x40, 0x40, 0x7c, 0x10 }, // Ё diff --git a/shared/ui/uno.c b/shared/ui/uno.c index 75cf1aa..f4e29c0 100644 --- a/shared/ui/uno.c +++ b/shared/ui/uno.c @@ -1,6 +1,5 @@ #include "uno.h" #include -#include static u32 calculate_text_width(const char *text, u16 font_size) { if (!text) return 0; diff --git a/src/TODO.md b/src/TODO.md index 91a6334..bb0fc07 100644 --- a/src/TODO.md +++ b/src/TODO.md @@ -1,19 +1,109 @@ -move reqs (inline assembly, limine reqs) to /kernel/include/ports(.h&.c) -with /kernel/include/reqs(.h&.c) +# Project TODO +> **Note:** This is a living document. Please update with new tasks, ideas, and details as development progresses. -remaking mem_manager with slab +--- -Make console to an app -make the top bar in console to an app -make every command to an app +## Bug Fixes +- [ ] **Log System** + - Refactor and stabilize the logging mechanism. + - Ensure thread safety and log rotation. + - Add log levels (debug, info, warn, error). -if we have a fs the kernel should no longer load per keyboard_pull and so on, -it should load the module system which searches for all modules which -are all saved in the fs and then they get loaded and everything should work +- [ ] **Bootscreen Performance** + - Investigate slow bootstrap or asset loading. + - Profile and optimize any bottlenecks. + - Reduce time-to-interaction at startup. +- [ ] **user_config File Overwrite Issue** + - Fix bug where `user_config` recreates/overwrites existing configs. + - Add checks for file existence before writing. + - Provide a safe way to update configs without data loss. + +- [ ] **FAT32 Not Registered** + - Debug FAT32 module (mounting/registration). + - Ensure correct integration with VFS and drivers. + +--- + +## Storage & Filesystems + +- [ ] **ATAPI Support** + - Implement ATAPI protocol for CD-ROM/DVD device access. + - Integrate with existing storage infrastructure. + +- [x] **BMP Image Format** + - Add loader and renderer for BMP images. + - Verify with test images of various bit depths. + +- [ ] **PNG Image Format** + - Implement PNG decoder. + - Support transparency and various color depths. + +- [ ] **MP4 Support** + - Implement basic MP4 parsing and playback. + - Leverage software decoding, investigate hardware acceleration. + +- [ ] **AHCI Driver** + - Develop driver for AHCI-compliant SATA controllers. + - Support for hotplug, NCQ, and advanced features. + +- [x] **libc Implementation** + - Integrate minimal standards-compliant libc. + - Document supported functions and limitations. + +- [ ] **emez: Kernel Stub System** + - Design & implement "emez" (Emex’s Zipped Kernel), inspired by vmlinux stubs. + - Enable booting/compression for faster load/testing. + - Provide generation tools/scripts. + +- [x] **procfs** + - Implement process filesystem for kernel/process info access. + - Ensure compatibility with debugging tools and utilities. + +- [ ] **ext2 Filesystem** + - Implement read/write support. + - Integrate with VFS layer. + +- [ ] **ext4 Filesystem** + - Implement read-only support first, later advance to write support. + - Handle journaling, extents, and 64-bit features. + +--- + +## Graphical Interface & User Experience + +- [ ] **Window System/Server** + - Core windowing server: composition, input routing, application management. + - IPC mechanism between apps and server. + - Hardware-accelerated drawing support. + +- [ ] **Desktop Environment** + - Build a standard environment (desktop, launcher, panels, wallpaper). + - Provide basic applets and settings support. + +- [ ] **Window Manager** + - Develop window tiling, decorations, focus, stacking. + - User-configurable settings (shortcuts, decorations, behavior). + +- [ ] **Theme Manager (Upgrade)** + - Expand theme definition (colors, icons, widgets, fonts). + - Implement theme package support and selector UI. + +- [ ] **Font Manager (Upgrade)** + - Add support for font discovery, preview, fallback, and internationalization. + - Cache rendering for performance. + +- [ ] **Bootscreen Manager (Upgrade)** + - Make bootscreen assets configurable. + - Add support for progress animation, logo customizations, tips/messages. + +--- + +## GENERAL NOTES + +- Add regression tests for each major subsystem/fix. +- Prioritize clear documentation for new features. +- For completed items: review and update this file regularly. -simple disk driver for fat32 (block reading) -(sector reader, 512 b) -bps parser , cluster size diff --git a/src/commands.TODO b/src/commands.TODO new file mode 100644 index 0000000..f01618f --- /dev/null +++ b/src/commands.TODO @@ -0,0 +1,54 @@ +[ ] dofetch +[ ] version +[x] cat +[x] ls +[x] echo +[x] cd +[x] tree +[ ] pwd +[ ] touch +[ ] mkdir +[ ] rmdir +[ ] rm +[ ] cp +[ ] ecc (emex c compiler) +[ ] mv +[ ] chmod +[ ] chown +[ ] find +[ ] grep +[ ] head +[ ] tail +[ ] less +[ ] more +[ ] wc +[ ] man +[ ] history +[ ] alias +[ ] uname +[ ] whoami +[ ] env +[ ] export +[ ] unset +[ ] source +[ ] df +[ ] du +[ ] dd +[ ] ping +[ ] top +[ ] htop +[ ] ps +[ ] kill +[ ] killall +[ ] jobs +[ ] bg +[ ] fg +[ ] sleep +[ ] date +[ ] cal +[ ] mount +[ ] umount +[ ] unalias +[ ] clear +[ ] reboot +[ ] shutdown diff --git a/src/drivers/drivers.h b/src/drivers/drivers.h index 027ffc6..a427b45 100644 --- a/src/drivers/drivers.h +++ b/src/drivers/drivers.h @@ -5,3 +5,13 @@ #include //#include //#include + +//#include +//#include + +//#include +//#include + +#include + +//ddir == dev dir \ No newline at end of file diff --git a/src/drivers/ps2/keyboard/keyboard.c b/src/drivers/ps2/keyboard/keyboard.c index dce2303..f69003d 100644 --- a/src/drivers/ps2/keyboard/keyboard.c +++ b/src/drivers/ps2/keyboard/keyboard.c @@ -4,6 +4,7 @@ #include #include #include +#include static key_buffer_t key_buffer = {0}; static int shift = 0; @@ -194,9 +195,9 @@ static void keyboard_module_fini(void) { } driver_module keyboard_module = (driver_module) { - .name = "ps2_keyboard", - .mount = "/emr/drv/keyboard", // because its not the driver not the device - .version = VERSION_NUM(0, 3, 1, 0), + .name = KBDNAME, + .mount = KBDPATH, // because its the driver not the device + .version = KBDUNIVERSAL, .init = keyboard_module_init, .fini = keyboard_module_fini, .open = NULL, diff --git a/src/drivers/ps2/keyboard/loader.c b/src/drivers/ps2/keyboard/loader.c index 365ac3d..417bc2a 100644 --- a/src/drivers/ps2/keyboard/loader.c +++ b/src/drivers/ps2/keyboard/loader.c @@ -1,6 +1,6 @@ // loader.c #include "loader.h" -#include +//#include #include #include #include @@ -8,6 +8,8 @@ #include // Parse .map (emex keymap) file format +#define KEYMAP_DIR "/emr/config/keymaps/" + static int parse_keymap_data(const char *data, size_t size, keymap_t *km) { if (!data || !km || size == 0) return -1; @@ -26,7 +28,7 @@ static int parse_keymap_data(const char *data, size_t size, keymap_t *km) { if (*line == '#' || *line == '\n') { // skip comments and empty lines while (line < end && *line != '\n') line++; - if (line < end && *line == '\n') line++; + if (line < end) line++; continue; } @@ -38,21 +40,17 @@ static int parse_keymap_data(const char *data, size_t size, keymap_t *km) { // (2 digits) for (int i = 0; i < 2 && line < end; i++) { scancode <<= 4; - if (*line >= '0' && *line <= '9') { - scancode |= (*line - '0'); - } else if (*line >= 'A' && *line <= 'F') { - scancode |= (*line - 'A' + 10); - } else if (*line >= 'a' && *line <= 'f') { - scancode |= (*line - 'a' + 10); - } + if (*line >= '0' && *line <= '9') scancode |= (*line - '0'); + else if (*line >= 'A' && *line <= 'F') scancode |= (*line - 'A' + 10); + else if (*line >= 'a' && *line <= 'f') scancode |= (*line - 'a' + 10); line++; } - while (line < end && *line != '=') line++; // = - if (line < end && *line == '=') line++; - while (line < end && (*line == ' ' || *line == '\t')) line++; // space + while (line < end && *line != '=') line++; + if (line < end) line++; // skip '=' + while (line < end && (*line == ' ' || *line == '\t')) line++; - // parse normal, between single quotes + // parse normal char if (line < end && *line == '\'') { line++; if (line < end) { @@ -70,13 +68,9 @@ static int parse_keymap_data(const char *data, size_t size, keymap_t *km) { u8 hex = 0; for (int i = 0; i < 2 && line < end; i++) { hex <<= 4; - if (*line >= '0' && *line <= '9') { - hex |= (*line - '0'); - } else if (*line >= 'A' && *line <= 'F') { - hex |= (*line - 'A' + 10); - } else if (*line >= 'a' && *line <= 'f') { - hex |= (*line - 'a' + 10); - } + if (*line >= '0' && *line <= '9') hex |= (*line - '0'); + else if (*line >= 'A' && *line <= 'F') hex |= (*line - 'A' + 10); + else if (*line >= 'a' && *line <= 'f') hex |= (*line - 'a' + 10); line++; } km->normal[scancode] = hex; @@ -115,13 +109,9 @@ static int parse_keymap_data(const char *data, size_t size, keymap_t *km) { u8 hex = 0; for (int i = 0; i < 2 && line < end; i++) { hex <<= 4; - if (*line >= '0' && *line <= '9') { - hex |= (*line - '0'); - } else if (*line >= 'A' && *line <= 'F') { - hex |= (*line - 'A' + 10); - } else if (*line >= 'a' && *line <= 'f') { - hex |= (*line - 'a' + 10); - } + if (*line >= '0' && *line <= '9') hex |= (*line - '0'); + else if (*line >= 'A' && *line <= 'F') hex |= (*line - 'A' + 10); + else if (*line >= 'a' && *line <= 'f') hex |= (*line - 'a' + 10); line++; } km->shift[scancode] = hex; @@ -142,7 +132,7 @@ static int parse_keymap_data(const char *data, size_t size, keymap_t *km) { // skip to nect line while (line < end && *line != '\n') line++; - if (line < end && *line == '\n') line++; + if (line < end) line++; } return 0; @@ -151,90 +141,32 @@ static int parse_keymap_data(const char *data, size_t size, keymap_t *km) { int keymap_load_from_module(const char *name, keymap_t *km) { if (!name || !km) return -1; - if (!module_request.response || module_request.response->module_count == 0) { - printf("[KEYMAP] No Limine modules available\n"); + // build path with us keymap + char path[64]; + str_copy(path, KEYMAP_DIR); + str_append(path, name); + str_append(path, KEYMAP_FORMAT); + + int fd = fs_open(path, O_RDONLY); + if (fd < 0) { + log("[KEYMAP]", "not found: ", d); + BOOTUP_PRINT(path, white()); + BOOTUP_PRINT("\n", white()); return -1; } - struct limine_module_response *response = - (struct limine_module_response *)module_request.response; - - // Builds the expected filename - char expected_name[64]; - str_copy(expected_name, name); - str_append(expected_name, KEYMAP_FORMAT); - - // search for keymap module - for (u64 i = 0; i < response->module_count; i++) { - struct limine_file *module = response->modules[i]; - - //Extract filename from path - const char *filename = module->path; - const char *last_slash = filename; - for (const char *p = filename; *p; p++) { - if (*p == '/') last_slash = p + 1; - } - filename = last_slash; + // read the whole file into a stack buffer + // .map files are small (< 4KB) + char buf[4096]; + ssize_t bytes = fs_read(fd, buf, sizeof(buf) - 1); + fs_close(fd); - // checks if this is our keymap - if (str_equals(filename, expected_name)) { - printf("[KEYMAP] Loading %s from module (%lu bytes)\n", - filename, module->size); + if (bytes <= 0) return -1; + buf[bytes] = '\0'; - return parse_keymap_data((const char*)module->address, - module->size, km); - } - } - - printf("[KEYMAP] Module %s not found\n", expected_name); - return -1; + return parse_keymap_data(buf, (size_t)bytes, km); } int keymap_modules_init(void) { - if (!module_request.response) { - printf("[KEYMAP] No module response available\n"); - return -1; - } - - struct limine_module_response *response = - (struct limine_module_response *)module_request.response; - - log("[KEYMAP]", "Found ", d); - char buf[32]; - str_from_int(buf, (int)response->module_count); - BOOTUP_PRINT(buf, white()); - BOOTUP_PRINT(" Limine modules\n", white()); - - - // lists all keymap modules - int keymap_count = 0; - for (u64 i = 0; i < response->module_count; i++) { - struct limine_file *module = response->modules[i]; - - const char *filename = module->path; - const char *last_slash = filename; - for (const char *p = filename; *p; p++) { - if (*p == '/') last_slash = p + 1; - } - filename = last_slash; - - // check if this is a keymap file - if (str_contains(filename, KEYMAP_FORMAT)) { - printf("[KEYMAP] Available: %s\n", filename); - keymap_count++; - } - } - - buf[0] = '\0'; - //char buf[64]; - char numbuf[32]; - - str_copy(buf, "Total keymaps found: "); - str_from_int(numbuf, keymap_count); - str_append(buf, numbuf); - str_append(buf, "\n"); - - log("[KEYMAP]", buf, d); - - return keymap_count; + return 0; } diff --git a/src/drivers/ps2/keyboard/maps.c b/src/drivers/ps2/keyboard/maps.c index e0b5d5b..1f961bf 100644 --- a/src/drivers/ps2/keyboard/maps.c +++ b/src/drivers/ps2/keyboard/maps.c @@ -33,6 +33,12 @@ int keymap_init(void) { return 0; } + if (keymap_load_from_module("RU", ¤t_keymap) == 0) { + str_copy(current_keymap_name, "RU"); + log("[KEYMAP]", "Loaded default: RU\n", d); + return 0; + } + log("[KEYMAP]", "ERROR: No keymap could be loaded!\n", warning); return -1; } diff --git a/src/drivers/ps2/mouse/mouse.c b/src/drivers/ps2/mouse/mouse.c new file mode 100644 index 0000000..220070e --- /dev/null +++ b/src/drivers/ps2/mouse/mouse.c @@ -0,0 +1,93 @@ +#include "mouse.h" +#include +#include +#include + +static mouse_event_t evbuf[MOUSE_BUF_SIZE]; +static volatile int ev_r = 0, ev_w = 0; +static void ev_push(mouse_event_t *e) { + int next = (ev_w + 1) % MOUSE_BUF_SIZE; + if (next != ev_r) { evbuf[ev_w] = *e; ev_w = next; } +} + +int mouse_has_event(void) { return ev_r != ev_w; } +int mouse_get_event(mouse_event_t *e) { + if (ev_r == ev_w) return 0; + *e = evbuf[ev_r]; ev_r = (ev_r + 1) % MOUSE_BUF_SIZE; + return 1; +} + +static int abs_x = 0, abs_y = 0; +static void ps2_wait_w(void) { + int t=100000; while(t-- && ( inb(PS2_CMD)&0x02)); +} +static void ps2_wait_r(void) { + int t=100000; while(t-- && (!inb(PS2_CMD)&0x01)); +} +static u8 ps2_rd(void){ + ps2_wait_r(); return inb(PS2_DATA); +} +static void ps2_cmd(u8 c){ + ps2_wait_w(); outb(PS2_CMD, c); +} +static void ps2_dat(u8 d){ + ps2_wait_w(); outb(PS2_DATA, d); +} + +static u8 pkt[3]; +static int pkt_i = 0; + +static void mouse_irq(cpu_state_t *s) { + (void)s; + u8 status = inb(PS2_CMD); + if (!(status & 0x01)) return; + + if (!(status & 0x20)) { inb(PS2_DATA); return; } + + u8 b = inb(PS2_DATA); + + if (pkt_i == 0 && !(b & 0x08)) return; // sync check + pkt[pkt_i++] = b; + if (pkt_i < 3) return; + pkt_i = 0; + + if (pkt[0] & 0xC0) return; // overflow and discard + + // 9-bit signed via sign bits in byte 0 + int dx = (int)pkt[1] - ((pkt[0] & 0x10) ? 256 : 0); + int dy = -((int)pkt[2] - ((pkt[0] & 0x20) ? 256 : 0)); + + u32 fw = get_fb_width(), fh = get_fb_height(); + if (!fw || !fh) return; + + abs_x += dx; abs_y += dy; + if (abs_x < 0) abs_x = 0; + if (abs_y < 0) abs_y = 0; + if (abs_x >= (int)fw) abs_x = (int)fw - 1; + if (abs_y >= (int)fh) abs_y = (int)fh - 1; + + mouse_event_t ev = { + .dx = dx, .dy = dy, + .abs_x = abs_x, .abs_y = abs_y, + .buttons = pkt[0] & 0x07 + }; + ev_push(&ev); +} + +void mouse_init(void) { + ps2_cmd(0xA8); + ps2_cmd(0x20); u8 cfg = ps2_rd(); cfg |= 0x02; cfg &= ~0x20; + ps2_cmd(0x60); ps2_dat(cfg); + ps2_cmd(0xD4); ps2_dat(0xF6); ps2_rd(); // defaults + ps2_cmd(0xD4); ps2_dat(0xE8); ps2_rd(); // set resolution + ps2_cmd(0xD4); ps2_dat(0x02); ps2_rd(); // 4 counts/mm + ps2_cmd(0xD4); ps2_dat(0xF3); ps2_rd(); // set sample rate + ps2_cmd(0xD4); ps2_dat(40); ps2_rd(); // 40 samples per sec + ps2_cmd(0xD4); ps2_dat(0xF4); ps2_rd(); // enable + + abs_x = (int)(get_fb_width() / 2); + abs_y = (int)(get_fb_height() / 2); + pkt_i = 0; + + irq_register_handler(12, mouse_irq); +} \ No newline at end of file diff --git a/src/drivers/ps2/mouse/mouse.h b/src/drivers/ps2/mouse/mouse.h new file mode 100644 index 0000000..6664a2b --- /dev/null +++ b/src/drivers/ps2/mouse/mouse.h @@ -0,0 +1,21 @@ +#pragma once +#include + +#define MOUSE_BUF_SIZE 64 + +#define PS2_DATA 0x60 +#define PS2_CMD 0x64 + +typedef struct { + int dx, dy; // relative movements + int abs_x, abs_y; + unsigned char buttons; +} mouse_event_t; + +#define MOUSE_BTN_LEFT (1<<0) +#define MOUSE_BTN_RIGHT (1<<1) +#define MOUSE_BTN_MIDDLE (1<<2) + +void mouse_init(void); +int mouse_has_event(void); +int mouse_get_event(mouse_event_t *ev); \ No newline at end of file diff --git a/src/drivers/ps2/ps2.h b/src/drivers/ps2/ps2.h index 9cb89be..c68a0fa 100644 --- a/src/drivers/ps2/ps2.h +++ b/src/drivers/ps2/ps2.h @@ -2,10 +2,9 @@ #define PS2_H #include "keyboard/keyboard.h" +#include "mouse/mouse.h" // keyboard driver void keyboard_poll(void); -// mouse driver - -#endif +#endif \ No newline at end of file diff --git a/src/drivers/storage/ata/disk.c b/src/drivers/storage/ata/disk.c index cde8d02..970a276 100644 --- a/src/drivers/storage/ata/disk.c +++ b/src/drivers/storage/ata/disk.c @@ -6,6 +6,7 @@ #include #include #include +//#include //note: // this is not a perfect ata driver and will not work on real hardware, but for fat32 i need a disk driver so i chose this one @@ -461,14 +462,14 @@ int ATAget_device_count(void) { return ATAdevice_count; } - +/* static int ATAmodule_init(void) { //ATAdetect_devices(); // already done log("[ATA]", "Load ATA module...\n", d); return 0; -} +}*/ // pub: void ata_init(void) { @@ -482,18 +483,19 @@ void ata_init(void) { //ATAmodule_init(); ATAdetect_devices(); } - +/* static void ATAmodule_fini(void) { // cleanup if needed } driver_module ata_module = { - .name = "ata-hdd0", - .mount = "/emr/drv/hdd0", - .version = VERSION_NUM(0, 1, 0, 0), + .name = ATANAME, + .mount = ATAPATH, + .version = ATAUNIVERSAL, .init = ATAmodule_init, .fini = ATAmodule_fini, .open = NULL, .read = NULL, .write = NULL, }; +*/ \ No newline at end of file diff --git a/src/kernel/arch/amd64/amd64.c b/src/kernel/arch/amd64/amd64.c index 96aa003..d42e1ac 100644 --- a/src/kernel/arch/amd64/amd64.c +++ b/src/kernel/arch/amd64/amd64.c @@ -10,12 +10,6 @@ static void cpuid(u32 leaf, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx) { : "a"(leaf), "c"(0)); } -static void cpuid_count(u32 leaf, u32 subleaf, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx) { - __asm__ volatile("cpuid" - : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) - : "a"(leaf), "c"(subleaf)); -} - void amd64_detect(amd64_info_t *info) { if (!info) return; @@ -209,4 +203,4 @@ void amd64_init_optimizations(void) { if (ecx & AMD_FEATURE_SVM) { printf("[AMD64] AMD-V virtualization available\n"); } -} +} \ No newline at end of file diff --git a/src/kernel/arch/x86_64/exceptions/irq.c b/src/kernel/arch/x86_64/exceptions/irq.c index ab72d7d..d0f2de8 100644 --- a/src/kernel/arch/x86_64/exceptions/irq.c +++ b/src/kernel/arch/x86_64/exceptions/irq.c @@ -84,7 +84,8 @@ void irq_register_handler(u8 irq, irq_handler_t handler) { if (irq < 16) { irq_handlers[irq] = handler; - irq_set_mask(irq, 0); // enable + irq_set_mask(irq, 0); + if (irq >= 8) irq_set_mask(2, 0); } } diff --git a/src/kernel/arch/x86_64/exceptions/isr.c b/src/kernel/arch/x86_64/exceptions/isr.c index 6d33c9a..16f7e60 100644 --- a/src/kernel/arch/x86_64/exceptions/isr.c +++ b/src/kernel/arch/x86_64/exceptions/isr.c @@ -12,16 +12,17 @@ void isr_install(void) } // set IDT Gates for ALL Exceptions - idt_set_gate(0, (u64)isr0, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT); - idt_set_gate(1, (u64)isr1, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT); - idt_set_gate(2, (u64)isr2, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT); - idt_set_gate(3, (u64)isr3, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT); - idt_set_gate(4, (u64)isr4, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT); - idt_set_gate(5, (u64)isr5, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT); - idt_set_gate(6, (u64)isr6, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT); - idt_set_gate(7, (u64)isr7, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT); - idt_set_gate(8, (u64)isr8, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT); - idt_set_gate(9, (u64)isr9, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT); + idt_set_gate(0, (u64)isr0, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT); + idt_set_gate(1, (u64)isr1, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT); + idt_set_gate(2, (u64)isr2, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT); + idt_set_gate(3, (u64)isr3, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT); + idt_set_gate(4, (u64)isr4, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT); + idt_set_gate(5, (u64)isr5, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT); + idt_set_gate(6, (u64)isr6, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT); + idt_set_gate(7, (u64)isr7, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT); + idt_set_gate_ist(8, (u64)isr8, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT, 1); + //idt_set_gate(8, (u64)isr8, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT); + idt_set_gate(9, (u64)isr9, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT); idt_set_gate(10, (u64)isr10, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT); idt_set_gate(11, (u64)isr11, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT); idt_set_gate(12, (u64)isr12, IDT_FLAG_PRESENT | IDT_FLAG_RING0 | IDT_FLAG_GATE_INT); diff --git a/src/kernel/arch/x86_64/exceptions/panic.c b/src/kernel/arch/x86_64/exceptions/panic.c index 172edb6..cea3854 100644 --- a/src/kernel/arch/x86_64/exceptions/panic.c +++ b/src/kernel/arch/x86_64/exceptions/panic.c @@ -1,50 +1,96 @@ #include "panic.h" + #include -#include #include #include +#include +#include +#include + +//#define BOOTUP_VISUALS 0 + +#define PANIC_BG PANICSCREEN_BG_COLOR +#define PANIC_FG PANICSCREEN_FG_COLOR + +// from the old console poweroff +static void panic_reboot(void) { + outb(0x64, 0xFE); + for (volatile int i = 0; i < 1000000; i++) __asm__ volatile("nop"); + + u8 tmp = inb(0xCF9); + outb(0xCF9, tmp | 0x02); + outb(0xCF9, tmp | 0x06); + for (volatile int i = 0; i < 1000000; i++) __asm__ volatile("nop"); + + // nothing worked, halt forever + log("\n::", "SHUTDOWN FAILED, HALTING FOREVER.", _d); + while (1) __asm__ volatile("cli; hlt"); +} __attribute__((noreturn)) void panic(const char *message) { + log("\n::", "PANIC WILL BE EXECUTED IN 100000000 TICKS\n\n", _d); + delay(10); + setcontext(THEME_PANIC); clear(PANICSCREEN_BG_COLOR); - // Disable interrupts + f_setcontext(PANIC_FONT); + // disable interrupts __asm__ volatile("cli"); - print("\n", white()); - print("!!! --- KERNEL PANIC --- !!!", red()); - print("\n", white()); + print("\n", PANIC_FG); + print("--- KERNEL PANIC --- ", PANIC_FG); + print("\n", PANIC_FG); + + f_setcontext(FONT_8X8); + + print("\nIt seems that emexOS has encountered an error.\n\n", PANIC_FG); if (message) { - print(message, red()); - print("\n", white()); + print(message, PANIC_FG); + print("\n", PANIC_FG); } - print("\nSystem halted.", white()); + print("System halted, \nYour computer will now restart...", PANIC_FG); + + delay(50); + panic_reboot(); // HALT - while(1) { - __asm__ volatile("cli; hlt"); - } + //while(1) { + // __asm__ volatile("cli; hlt"); + //} } __attribute__((noreturn)) void panic_exception(cpu_state_t *state, const char *message) { + u64 cr2, cr3; + __asm__ volatile("mov %%cr2, %0" : "=r"(cr2)); + __asm__ volatile("mov %%cr3, %0" : "=r"(cr3)); + + log("\n::", "PANIC WILL BE EXECUTED IN 100000000 TICKS\n\n", _d); + delay(10); + setcontext(THEME_PANIC); clear(PANICSCREEN_BG_COLOR); + f_setcontext(PANIC_FONT); // Disable interrupts __asm__ volatile("cli"); - print("\n", white()); - print("!!! PANIC !!!", red()); - print("\n", white()); + print("\n", PANIC_FG); + print("--- KERNEL PANIC --- ", PANIC_FG); + print("\n", PANIC_FG); + + f_setcontext(FONT_8X8); + + print("\nIt seems that emexOS has encountered an error.\n\n", PANIC_FG); if (message) { char buf[128]; str_copy(buf, "Exception: "); str_append(buf, message); - print(buf, red()); - print("\n", white()); + print(buf, PANIC_FG); + print("\n", PANIC_FG); } // Print exception details @@ -53,27 +99,70 @@ __attribute__((noreturn)) void panic_exception(cpu_state_t *state, const char *m str_append_uint(buf, (u32)state->int_no); str_append(buf, " ERR: "); str_append_uint(buf, (u32)state->err_code); - print(buf, white()); - print("\n", white()); + print(buf, PANIC_FG); + print("\n", PANIC_FG); // Print RIP + char hex[32]; str_copy(buf, "RIP: 0x"); - str_append_uint(buf, (u32)(state->rip >> 32)); - str_append_uint(buf, (u32)(state->rip & 0xFFFFFFFF)); - print(buf, white()); - print("\n", white()); + str_from_hex(hex, state->rip); + str_append(buf, hex); + print(buf, PANIC_FG); + print("\n", PANIC_FG); // Print RSP str_copy(buf, "RSP: 0x"); - str_append_uint(buf, (u32)(state->rsp >> 32)); - str_append_uint(buf, (u32)(state->rsp & 0xFFFFFFFF)); + str_from_hex(hex, state->rsp); + str_append(buf, hex); + print(buf, PANIC_FG); + print("\n\n", PANIC_FG); + + // Print RFLAGS + str_copy(buf, "RFLAGS: 0x"); + str_from_hex(hex, state->rflags); + str_append(buf, hex); + print(buf, white()); + print("\n", white()); + + if (state->int_no == 14) { + str_copy(buf, "CR2: 0x"); + str_from_hex(hex, cr2); + str_append(buf, hex); + str_append(buf, " (faulting address)"); + print(buf, PANIC_FG); + print("\n", white()); + + str_copy(buf, "Fault: "); + if (state->err_code & 1) + str_append(buf, "prot-violation "); + else str_append(buf, "not-present "); + if (state->err_code & 2) + str_append(buf, "write "); + else str_append(buf, "read "); + if (state->err_code & 4) + str_append(buf, "user-mode "); + else str_append(buf, "kernel-mode "); + if (state->err_code & 8) + str_append(buf, "reserved-bits "); + if (state->err_code & 16) + str_append(buf, "instruction-fetch "); + print(buf, PANIC_FG); + print("\n", white()); + } + + str_copy(buf, "CR3: 0x"); + str_from_hex(hex, cr3); + str_append(buf, hex); print(buf, white()); print("\n\n", white()); - print("System halted.", white()); + print("System halted, \nYour computer will now restart...", PANIC_FG); + + delay(50); + panic_reboot(); // HALT - while(1) { - __asm__ volatile("cli; hlt"); - } + //while(1) { + // __asm__ volatile("cli; hlt"); + //} } diff --git a/src/kernel/arch/x86_64/exceptions/panic.h b/src/kernel/arch/x86_64/exceptions/panic.h index 526d0b2..2d66a5e 100644 --- a/src/kernel/arch/x86_64/exceptions/panic.h +++ b/src/kernel/arch/x86_64/exceptions/panic.h @@ -4,6 +4,8 @@ #include #include +#define PANIC_SHOWSWITCH 1 + // Kernel panic __attribute__((noreturn)) void panic(const char *message); __attribute__((noreturn)) void panic_exception(cpu_state_t *state, const char *message); diff --git a/src/kernel/arch/x86_64/exceptions/timer.c b/src/kernel/arch/x86_64/exceptions/timer.c index d0a118e..1aa14c4 100644 --- a/src/kernel/arch/x86_64/exceptions/timer.c +++ b/src/kernel/arch/x86_64/exceptions/timer.c @@ -6,6 +6,7 @@ #include #include #include +//#include #include // using PIT (8254) @@ -17,12 +18,13 @@ static timer_callback_t timer_callbacks[MAX_TIMER_CALLBACKS]; static int callback_count = 0; #if ENABLE_ULIME -extern scheduler_t* scheduler; // Zugriff auf globale Variable +extern scheduler_t* scheduler; +extern mt_t* mt; #endif void timer_handler(cpu_state_t* state) { - (void)state; + //(void)state; if (!timer_initialized) { return; @@ -36,12 +38,10 @@ void timer_handler(cpu_state_t* state) } } - //banner_tick(); - // call schedule #if ENABLE_ULIME - if (scheduler) { - scheduler_tick(scheduler); + if (mt) { + mt_preempt(mt, state); // real preemptive switch } #endif } @@ -81,7 +81,7 @@ void timer_init(u32 frequency) timer_ticks = 0; timer_initialized = 1; - // Enable interrupts to start timer + // enable interrupts to start timer __asm__ volatile("sti"); //TODO: diff --git a/src/kernel/arch/x86_64/exceptions/timer.h b/src/kernel/arch/x86_64/exceptions/timer.h index 24cde7b..ab98be8 100644 --- a/src/kernel/arch/x86_64/exceptions/timer.h +++ b/src/kernel/arch/x86_64/exceptions/timer.h @@ -2,6 +2,7 @@ #define TIMER_H #include +#include #define TIMER_FREQUENCY 1000 // 1000 Hz = 1ms Ticks #define MAX_TIMER_CALLBACKS 8 diff --git a/src/kernel/arch/x86_64/gdt/gdt.c b/src/kernel/arch/x86_64/gdt/gdt.c index c79e83d..b3b21e6 100644 --- a/src/kernel/arch/x86_64/gdt/gdt.c +++ b/src/kernel/arch/x86_64/gdt/gdt.c @@ -8,10 +8,8 @@ static gdt_entry_t gdt[GDT_ENTRIES]; static tss_t tss; static gdt_ptr_t gdt_ptr; - -// Kernel stack for syscalls/interrupts (16KB, 16-byte aligned) -static u8 kernel_stack[16384] __attribute__((aligned(16))); - +static u8 kernel_stack[16384] __attribute__((aligned(16))); // 16KB +static u8 df_stack[8192] __attribute__((aligned(16))); // this time via ist1 // TODO: // move tss to kernel/arch/x64/tss/tss.c @@ -92,6 +90,7 @@ void tss_init(void) log("[TSS]", "init (Task State Segment)\n", d); memset(&tss, 0, sizeof(tss_t)); tss.rsp0 = (u64)kernel_stack + sizeof(kernel_stack); + tss.ist1 = (u64)df_stack + sizeof(df_stack); tss.iopb_offset = sizeof(tss_t); } diff --git a/src/kernel/arch/x86_64/idt/idt.c b/src/kernel/arch/x86_64/idt/idt.c index 77c6735..1c40a49 100644 --- a/src/kernel/arch/x86_64/idt/idt.c +++ b/src/kernel/arch/x86_64/idt/idt.c @@ -23,6 +23,12 @@ void idt_set_gate(u8 num, u64 handler, u8 flags) idt[num].reserved = 0; } +void idt_set_gate_ist(u8 num, u64 handler, u8 flags, u8 ist) +{ + idt_set_gate(num, handler, flags); + idt[num].ist = ist & 0x07; +} + void idt_load(void) { idt_ptr.limit = sizeof(idt) - 1; diff --git a/src/kernel/arch/x86_64/idt/idt.h b/src/kernel/arch/x86_64/idt/idt.h index 92f28a8..2aeb967 100644 --- a/src/kernel/arch/x86_64/idt/idt.h +++ b/src/kernel/arch/x86_64/idt/idt.h @@ -46,9 +46,10 @@ typedef struct { u64 rip, cs, rflags, rsp, ss; } __attribute__((packed)) cpu_state_t; -// Funktionen +// funktions void idt_init(void); void idt_set_gate(u8 num, u64 handler, u8 flags); +void idt_set_gate_ist(u8 num, u64 handler, u8 flags, u8 ist); void idt_load(void); #endif diff --git a/src/kernel/arch/x86_64/syscall_entry.asm b/src/kernel/arch/x86_64/syscall_entry.asm index 79b0c60..5a594ce 100644 --- a/src/kernel/arch/x86_64/syscall_entry.asm +++ b/src/kernel/arch/x86_64/syscall_entry.asm @@ -1,20 +1,40 @@ bits 64 global syscall_entry -extern syscall_handler - +global user_rsp +global user_rcx +global user_r11 +global user_cr3 +global user_rbx +global user_rbp +global user_r12 +global user_r13 +global user_r14 +global user_r15 +extern syscall_handler syscall_entry: - ; save user stack pointer mov [rel user_rsp], rsp + mov [rel user_rcx], rcx + mov [rel user_r11], r11 + + push rax + mov rax, cr3 + mov [rel user_cr3], rax + pop rax + + mov [rel user_rbx], rbx + mov [rel user_rbp], rbp + mov [rel user_r12], r12 + mov [rel user_r13], r13 + mov [rel user_r14], r14 + mov [rel user_r15], r15 - ; switch to kernel stack - mov rsp, [rel kernel_stack_top] + lea rsp, [rel kernel_stack_top] - ; save registers on kernel stack - push r11 ; rflags - push rcx ; user rip + push r11 + push rcx push rbx push rbp push r12 @@ -22,24 +42,15 @@ syscall_entry: push r14 push r15 + mov rcx, rdx ; arg3 + mov rdx, rsi ; arg2 + mov rsi, rdi ; arg1 + mov rdi, rax ; syscall_num - mov r10, rdi ; save arg1 - mov rdi, rax ; syscall number -> first param - mov rsi, r10 ; arg1 -> second param - ; rdx already has arg2 - mov rcx, rdx ; arg3 - ; r8 already correct - mov r10, r8 - mov r8, r10 ; arg4 - ; r9 already correct - - - - call syscall_handler ; from C + call syscall_handler ; result is in rax - ; restore registers pop r15 pop r14 pop r13 @@ -49,20 +60,24 @@ syscall_entry: pop rcx ; user rip pop r11 ; rflags - ; restore user stack mov rsp, [rel user_rsp] - - ; return to userspace with SYSRET - ; rcx = return address, r11 = rflags - o64 sysret + o64 sysret ; RIP = rcx, RFLAGS = r11, CPL → 3 section .data align 16 user_rsp: dq 0 - +user_rcx: dq 0 +user_r11: dq 0 +user_cr3: dq 0 +user_rbx: dq 0 +user_rbp: dq 0 +user_r12: dq 0 +user_r13: dq 0 +user_r14: dq 0 +user_r15: dq 0 section .bss align 16 kernel_stack_bottom: - resb 16384 ; 16KB kernel stack + resb 16384 kernel_stack_top: diff --git a/src/kernel/console/console.c b/src/kernel/console/console.c deleted file mode 100644 index 11e2479..0000000 --- a/src/kernel/console/console.c +++ /dev/null @@ -1,407 +0,0 @@ -#include "console.h" -#include "functions.h" - -static char input_buffer[MAX_INPUT_LEN]; -static int input_pos = 0; -char cwd[MAX_PATH_LEN] = "/"; -//int is_login_active = 0; - -//---------------------------------- -// ! IMPORTANT FOR NEW COMMANDS ! -int cmd_count = 30; - -console_cmd_t commands[MAX_CMDS] = { - CMDENTRY(cmd_echo, "echo", "prints text to console", "echo [text]"), - CMDENTRY(cmd_clear, "clear", "clears the screen", "clear [color]"), - CMDENTRY(cmd_help, "help", "displays all available commands", "help [command]"), - CMDENTRY(cmd_fsize, "scale", "change screen size", "scale [2-4]"), - CMDENTRY(cmd_modules, "lsmod", "list loaded modules", "lsmod"), - CMDENTRY(cmd_meminfo, "meminfo", "displays memory infos", "meminfo"), - //CMDENTRY(cmd_memtest, "memtest", "Memory test suite", "memtest"), - CMDENTRY(cmd_sysinfo, "dofetch", "system fetch", "dofetch"), - CMDENTRY(cmd_cal, "calendar", "displays current date & time", "calendar"), - CMDENTRY(cmd_date, "date", "displays current date", "date"), - CMDENTRY(cmd_uptime, "uptime", "System uptime", "uptime"), - CMDENTRY(cmd_time, "time", "displays current time", "time"), - CMDENTRY(cmd_reboot, "reboot", "Reboot the system", "reboot"), - CMDENTRY(cmd_shutdown, "shutdown", "Shutsdown the system", "shutdown"), - CMDENTRY(cmd_shutdown, "shut", "Shutsdown the system", "shut"), // alias - CMDENTRY(cmd_cat, "cat", "show file", "cat "), - CMDENTRY(cmd_ls, "ls", "list directory contents", "ls [path]"), - CMDENTRY(cmd_cd, "cd", "Change directory", "cd [path]"), - CMDENTRY(cmd_tree, "tree", "shows every folder, file * content", "tree"), - CMDENTRY(cmd_mkdir, "mkdir", "create directory", "mkdir "), - CMDENTRY(cmd_font, "font", "change console font", "font [0-1]"), - CMDENTRY(cmd_cyrillc_sumbol, "cyrillc-sumbol", "print cyrillic alphabet test", "cyrillc-sumbol"), - CMDENTRY(cmd_latin_sumbol, "latin-sumbol", "print latin alphabet test", "latin-sumbol"), - CMDENTRY(cmd_all_sumbol, "all-sumbol", "print latin and cyrillic alphabets", "all-sumbol"), - CMDENTRY(cmd_keymap, "loadkeys", "change keyboard layout", "loadkeys [keymap]"), - CMDENTRY(cmd_whoami, "whoami", "display current user", "whoami"), - CMDENTRY(cmd_source, "source", "reload configuration", "source console"), - CMDENTRY(cmd_touch, "touch", "create empty file", "touch "), - CMDENTRY(cmd_view, "view", "view BMP image", "view "), - CMDENTRY(cmd_ps, "ps", "displays processes", "ps"), - CMDENTRY(cmd_slot, "slot", "switch kernel slots", "slot "), -}; - -//---------------------------------- - -//module--------------------------- -static int console_module_init(void) { - // console already initialized in main - log("[CONSOLE]", "Load CONSOLE module...\n", d); - return 0; -} - -static void console_module_fini(void) { - // -} - -driver_module console_module = (driver_module) { - .name = "console", - .mount = "/dev/console", - .version = VERSION_NUM(0, 1, 2, 0), //should print like [v0.1.0.0] - .init = console_module_init, - .fini = console_module_fini, - .open = NULL, // later for fs - .read = NULL, // later for fs - .write = NULL, // later for fs -}; - -//--------------------------------- - - -//extern void prompt_config_init(); -void console_init(void) -{ - input_pos = 0; - input_buffer[0] = '\0'; - char buf[64]; - - log("[CONSOLE]","starting console...\n", d); - - //sconsole_theme(THEME_FLU); - f_setcontext(FONT_8X8); - clear(CONSOLESCREEN_BG_COLOR); - font_scale = 2; - - buf[0] = '\0'; //reset - //reset_cursor(); - /* - //module_register_driver(&console_module); - - if (cursor_x == 0 && cursor_y == 0) { - clear(CONSOLESCREEN_COLOR); - reset_cursor(); - } - */ - - cursor_x = 0; - cursor_y = 0; - - //is_login_active = 1; - //if (!login_authenticate()) { - // Login failed - should never reach here due to lock - //panic("Login authentication failed"); - //} - //is_login_active = 0; - - - //create config files for console: - /*fs_mkdir("/.config/ekmsh"); - fs_mkdir("/.config/ekmsh/promts"); - fs_open("/.config/ekmsh/promts/promt.conf", O_CREAT | O_WRONLY);*/ - - console_config_init(); - - clear(CONSOLESCREEN_BG_COLOR); - banner_init(); - - // Initialize console window - console_window_init(); - cursor_(); - - //string("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890+#,.-;:_'*`?=!\\\"$%&/()^°", GFX_WHITE); - // font testing - shell_print_prompt(); - - //console_execute("view /images/logo.bmp"); - cursor_draw(); - - console_run(); - -} - -void console_run(void) -{ - // main console loop will be called from keyboard handler - // this function exists for future expansion like syscalls maybe for a app like a code editor which needs a console - // actually idk why i created this xd - while (1) { - if (keyboard_has_key()) { - key_event_t event; - if (keyboard_get_event(&event)) { - if (event.pressed) { - console_handle_key_event(&event); - } - } - } - // Let CPU rest - __asm__ volatile("hlt"); - } -} - -static void console_redraw_input_line(void) { - u32 saved_y = cursor_y; - u32 char_width = fm_get_char_width() * font_scale; - u32 char_height = fm_get_char_height() * font_scale; - u32 start_x = cursor_x; - u32 clear_width = get_fb_width() - cursor_x; - - draw_rect(cursor_x, cursor_y, clear_width, char_height, CONSOLESCREEN_BG_COLOR); - - for (int i = input_pos; input_buffer[i] != '\0'; i++) { - putchar(input_buffer[i], GFX_WHITE); - } - - cursor_x = start_x; - cursor_y = saved_y; - cursor_draw(); -} - -void console_handle_key_event(key_event_t *event) { - cursor_c(); - - // Arrow keys - if (event->keycode == KEY_ARROW_LEFT) { - if (input_pos > 0) { - input_pos--; - u32 char_width = 8 * font_scale; - cursor_x -= char_width; - cursor_draw(); - } - return; - } - - if (event->keycode == KEY_ARROW_RIGHT) { - if (input_pos < str_len(input_buffer)) { - input_pos++; - u32 char_width = 8 * font_scale; - cursor_x += char_width; - cursor_draw(); - } - return; - } - - if (event->keycode == KEY_HOME) { - u32 char_width = 8 * font_scale; - cursor_x -= input_pos * char_width; - input_pos = 0; - cursor_draw(); - return; - } - - if (event->keycode == KEY_END) { - int len = str_len(input_buffer); - u32 char_width = 8 * font_scale; - cursor_x += (len - input_pos) * char_width; - input_pos = len; - cursor_draw(); - return; - } - - if (event->keycode == KEY_DELETE) { - int len = str_len(input_buffer); - if (input_pos < len) { - for (int i = input_pos; i < len; i++) { - input_buffer[i] = input_buffer[i + 1]; - } - console_redraw_input_line(); - } - return; - } - - if ((event->modifiers & KEY_CTRL_MASK) && (event->keycode == 's' || event->keycode == 'S')) { - // This will be handled by edit command - return; - } - - char c = (char)(event->keycode & 0xFF); - console_handle_key(c); - - cursor_reset_blink(); - cursor_draw(); -} - -void console_handle_key(char c) -{ - cursor_c(); - if (c == '\n') { - // execute command when enter - putchar('\n', GFX_WHITE); - - if (input_pos > 0 || str_len(input_buffer) > 0) { - input_buffer[str_len(input_buffer)] = '\0'; - - // check for && and use chained execution - int has_chain = 0; - int len = str_len(input_buffer); - for (int i = 0; i < len - 1; i++) { - if (input_buffer[i] == '&' && input_buffer[i+1] == '&') { - has_chain = 1; - break; - } - } - - // prints every command to the console - printf("%s\n", input_buffer); - - if (has_chain) { - parse_and_execute_chained(input_buffer); - } else { - console_execute(input_buffer); - } - - - input_pos = 0; - input_buffer[0] = '\0'; - } - - cursor_reset_blink(); - //cursor_draw(); - shell_print_prompt(); - return; - } - - if (c == '\r') { - putchar('\n', GFX_WHITE); - input_buffer[input_pos++] = '\n'; - cursor_draw(); - return; - } - - if (c == '\b') { - if (input_pos > 0) { - int len = str_len(input_buffer); - for (int i = input_pos - 1; i < len; i++) { - input_buffer[i] = input_buffer[i + 1]; - } - input_pos--; - //input_buffer[input_pos] = '\0'; - - // just move the cursor back then print space, draw rext, and move back again - u32 char_width = fm_get_char_width() * font_scale; - u32 char_height = fm_get_char_height() * font_scale; - /*if (cursor_x >= char_width) { - cursor_x -= char_width; - putchar(' ', GFX_WHITE); - cursor_x -= char_width; - - draw_rect(cursor_x, cursor_y, char_width, 8 * font_scale, CONSOLESCREEN_BG_COLOR); - }*/ - cursor_x -= char_width; - draw_rect(cursor_x, cursor_y, char_width, char_height, CONSOLESCREEN_BG_COLOR); - console_redraw_input_line(); - } - cursor_reset_blink(); - cursor_draw(); - return; - } - - console_window_check_scroll(); - - // add character to buffer - if (input_pos < MAX_INPUT_LEN - 1) { - int len = str_len(input_buffer); - - for (int i = len; i > input_pos; i--) { - input_buffer[i] = input_buffer[i - 1]; - } - - input_buffer[input_pos] = c; - input_buffer[len + 1] = '\0'; - - putchar(c, GFX_WHITE); - input_pos++; - - if (input_buffer[input_pos] != '\0') { - u32 old_x = cursor_x; - u32 old_y = cursor_y; - for (int i = input_pos; input_buffer[i] != '\0'; i++) { - putchar(input_buffer[i], GFX_WHITE); - } - cursor_x = old_x; - cursor_y = old_y; - } - } - cursor_reset_blink(); - cursor_draw(); -} - -void console_execute(const char *input) -{ - //TODO: - // OF UNKOWN BUGS THE SYSTEM CRASHES WHEN YOU ENTER A WRONG COMMAND - // not anymore :) - - // skip leading spaces - while (*input == ' ') input++; - - if (*input == '\0') return; - - // find command name end - const char *end = input; - while (*end && *end != ' ') end++; - - // extract it - char cmd_name[64]; - int len = end - input; - if (len >= 64) len = 63; - - for (int i = 0; i < len; i++) { - cmd_name[i] = input[i]; - } - cmd_name[len] = '\0'; - - // find arguments - const char *args = end; - while (*args == ' ') args++; - - console_cmd_t *cmd = console_find_cmd(cmd_name); - if (cmd) { - cmd->func(args); - - banner_force_update(); - - // for PC_NAME and USER_NAME - uci_reload(); - } else { - print(CONSOLE_NAME, WRONG_COMMAND_CL); - print(": command not found:", WRONG_COMMAND_CL); - print(cmd_name, WRONG_COMMAND_CL); - } -} - -console_cmd_t* console_find_cmd(const char *name) -{ - for (int i = 0; i < cmd_count; i++) { - // simple string comparison - const char *a = name; - const char *b = commands[i].name; - int match = 1; - - while (*a && *b) { - if (*a != *b) { - match = 0; - break; - } - a++; - b++; - } - - if (match && *a == '\0' && *b == '\0') { - return &commands[i]; - } - } - return NULL; -} diff --git a/src/kernel/console/console.h b/src/kernel/console/console.h deleted file mode 100644 index 26b253a..0000000 --- a/src/kernel/console/console.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef CONSOLE_H -#define CONSOLE_H - -#include -#include -#include -#include -#include -#include "graph/uno.h" -#include "graph/dos.h" -#include -#include -#include -#include -#include -//#include "login/login.h" -#include -#include -#include - -#include - -#include -extern driver_module console_module; - -#define MAX_INPUT_LEN 256 -#define MAX_PATH_LEN 256 -#define MAX_CMDS 32 -#define MAX_CHAINED_CMDS 8 - -#define CONSOLE_APP_NAME "console" -#define CONSOLE_NAME "ekmsh" // emex-kernelmode-shell -#define WRONG_COMMAND_CL GFX_RED - -// function header macro for command declarations it should be easier to port it to future syscalls -#define FHDR(name) void name(const char* s) - -typedef struct { - void (*func)(const char*); - const char *name; - const char *description; - const char *usage; -} console_cmd_t; - -// for the 'help ' -#define CMDENTRY(func, name, desc, usage) { func, name, desc, usage } - -extern char cwd[]; -//for help.c -extern console_cmd_t commands[]; -extern int cmd_count; - -void console_init(void); -void console_run(void); - -void console_handle_key(char c); -void console_handle_key_event(key_event_t *event); -void console_execute(const char *input); - -void shell_clear_screen(u32 color); -void shell_print_prompt(void); -void shell_redraw_input(void); - -void cursor_(void); -void cursor_draw(void); -void cursor_c(void); -void cursor_redraw(void); -void cursor_enable(void); -void cursor_disable(void); -void cursor_reset_blink(void); - - -void console_config_init(void); // config for promt in /.config/ekmsh/promts/promt.conf - - -console_cmd_t* console_find_cmd(const char *name); - -int parse_color(const char *color_str, u32 *out_color); -void parse_and_execute_chained(const char *input); - -#endif diff --git a/src/kernel/console/cursor.c b/src/kernel/console/cursor.c deleted file mode 100644 index bb98a21..0000000 --- a/src/kernel/console/cursor.c +++ /dev/null @@ -1,86 +0,0 @@ -#include "console.h" -#include -#include - -static int cursor_visible = 1; -static u32 cursor_blink_counter = 0; -static int cursor_enabled = 1; - -//todo: -// move to doccr.h with custom cursor bitmap/ character (e.g: A,B, _, █) -#define CURSOR_BLINK_RATE 300 // blinking -//------------------------ -// "_" -#define CURSOR_WIDTH_RATIO 6 -#define CURSOR_HEIGHT_RATIO 1 -//------------------------ -// "█" -//#define CURSOR_WIDTH_RATIO 5 -//#define CURSOR_HEIGHT_RATIO 8 -//------------------------ -// "|" -//#define CURSOR_WIDTH_RATIO 1 -///#define CURSOR_HEIGHT_RATIO 8 -//------------------------ -static void cursor_timer_callback() { - if (!cursor_enabled) return; - - cursor_blink_counter++; - if (cursor_blink_counter >= CURSOR_BLINK_RATE) { - cursor_blink_counter = 0; - cursor_visible = !cursor_visible; - cursor_redraw(); - } -} - -void cursor_(void) { - cursor_visible = 1; - cursor_blink_counter = 0; - cursor_enabled = 1; - timer_register_callback(cursor_timer_callback); -} - -void cursor_draw(void) { - if (!cursor_visible || !cursor_enabled) return; - - u32 char_width = fm_get_char_width() * font_scale; - u32 char_height = fm_get_char_height() * font_scale; - - u32 cursor_width = (char_width * CURSOR_WIDTH_RATIO) / 8; - u32 cursor_height = (char_height * CURSOR_HEIGHT_RATIO) / 8; - u32 cursor_y_pos = cursor_y + char_height - cursor_height; - - draw_rect(cursor_x, cursor_y_pos, cursor_width, cursor_height, CONSOLESCREEN_COLOR); -} - -void cursor_c(void) { - u32 char_width = fm_get_char_width() * font_scale; - u32 char_height = fm_get_char_height() * font_scale; - - u32 cursor_width = (char_width * CURSOR_WIDTH_RATIO) / 8; - u32 cursor_height = (char_height * CURSOR_HEIGHT_RATIO) / 8; - u32 cursor_y_pos = cursor_y + char_height - cursor_height; - - draw_rect(cursor_x, cursor_y_pos, cursor_width, cursor_height, CONSOLESCREEN_BG_COLOR); -} - -void cursor_redraw(void) { - cursor_c(); - cursor_draw(); -} - -void cursor_enable(void) { - cursor_enabled = 1; - cursor_visible = 1; - cursor_blink_counter = 0; -} - -void cursor_disable(void) { - cursor_c(); - cursor_enabled = 0; -} - -void cursor_reset_blink(void) { - cursor_blink_counter = 0; - cursor_visible = 1; -} diff --git a/src/kernel/console/functions.h b/src/kernel/console/functions.h deleted file mode 100644 index 1c2a980..0000000 --- a/src/kernel/console/functions.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#include "console.h" - -// text.c -FHDR(cmd_echo); -FHDR(cmd_clear); -FHDR(cmd_font); -FHDR(cmd_fsize); -FHDR(cmd_cyrillc_sumbol); -FHDR(cmd_latin_sumbol); -FHDR(cmd_all_sumbol); - -// help.c -FHDR(cmd_help); - -// system.c -FHDR(cmd_modules); -FHDR(cmd_meminfo); -FHDR(cmd_memtest); -FHDR(cmd_sysinfo); -//FHDR(cmd_usb); -//FHDR(cmd_usbinfo); - -//cmos.c -FHDR(cmd_cal); -FHDR(cmd_date); -FHDR(cmd_time); -FHDR(cmd_uptime); - -// File System -FHDR(cmd_tree); -FHDR(cmd_cat); -FHDR(cmd_ls); -FHDR(cmd_cd); -FHDR(cmd_mkdir); -FHDR(cmd_touch); - -// whoami.c -FHDR(cmd_whoami); - -// source.c -FHDR(cmd_source); - -// keymap.c -FHDR(cmd_keymap); - -// poweroff.c -//FHDR(cmd_poweroff); -FHDR(cmd_reboot); -FHDR(cmd_shutdown); - - -// view.c -FHDR(cmd_view); - -// proc -FHDR(cmd_ps); - -// slots.c -FHDR(cmd_slot); diff --git a/src/kernel/console/functions/cat.c b/src/kernel/console/functions/cat.c deleted file mode 100644 index 01d8676..0000000 --- a/src/kernel/console/functions/cat.c +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include - -extern char cwd[]; - -FHDR(cmd_cat) { - (void)s; - if (!s || *s == '\0') { - print("error: no file specified\n", GFX_RED); - return; - } - - char path[MAX_PATH_LEN]; - - if (s[0] == '/') { - str_copy(path, s); - } else { - str_copy(path, cwd); - - if (cwd[str_len(cwd) - 1] != '/') { - str_append(path, "/"); - } - - str_append(path, s); - } - - // opens in read only (RDONLY) - int fd = fs_open(path, O_RDONLY); - if (fd < 0) { - print("error: cannot open file\n", GFX_RED); - return; - } - - char buf[256]; - ssize_t bytes; - - while ((bytes = fs_read(fd, buf, sizeof(buf) - 1)) > 0) { - buf[bytes] = '\0'; - print(buf, GFX_WHITE); - } - - fs_close(fd); - - // buf[0] = '\0'; - print("\n", GFX_WHITE); -} diff --git a/src/kernel/console/functions/cd.c b/src/kernel/console/functions/cd.c deleted file mode 100644 index 678c620..0000000 --- a/src/kernel/console/functions/cd.c +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include - -extern char cwd[]; - -FHDR(cmd_cd) { - if (!s || *s == '\0') { - // cd with no arguments goes to root - str_copy(cwd, "/"); - return; - } - - char new_path[MAX_PATH_LEN]; - - if (s[0] == '/') { - str_copy(new_path, s); - } else { - str_copy(new_path, cwd); - - if (cwd[str_len(cwd) - 1] != '/') { - str_append(new_path, "/"); - } - - str_append(new_path, s); - } - - if (str_equals(s, "..")) { - int len = str_len(cwd); - if (len > 1 && cwd[len - 1] == '/') { - cwd[len - 1] = '\0'; - len--; - } - for (int i = len - 1; i >= 0; i--) { - if (cwd[i] == '/') { - if (i == 0) { - str_copy(cwd, "/"); - } else { - cwd[i] = '\0'; - } - return; - } - } - return; - } - - // if directory exists - fs_node *dir = fs_resolve(new_path); - if (!dir) { - print("error: directory not found\n", GFX_RED); - return; - } - - if (dir->type != FS_DIR) { - print("error: not a directory\n", GFX_RED); - return; - } - - // updates cwd - str_copy(cwd, new_path); - - // when cwd ends with / (except for the root) - int len = str_len(cwd); - if (len > 1 && cwd[len - 1] != '/') { - str_append(cwd, "/"); - } -} diff --git a/src/kernel/console/functions/cmos.c b/src/kernel/console/functions/cmos.c deleted file mode 100644 index fa7180e..0000000 --- a/src/kernel/console/functions/cmos.c +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include -#include - -FHDR(cmd_cal) { - (void)s; - - GetCMOSDate(); - print(" ", GFX_WHITE); - GetCMOSTime(); - -} - -FHDR(cmd_date) { - (void)s; - - GetCMOSDate(); -} - -FHDR(cmd_time) { - (void)s; - - GetCMOSTime(); -} - -FHDR(cmd_uptime) { - (void)s; - - print("Uptime: ", GFX_WHITE); - timer_print_uptime(); -} diff --git a/src/kernel/console/functions/help.c b/src/kernel/console/functions/help.c deleted file mode 100644 index 39c3ce7..0000000 --- a/src/kernel/console/functions/help.c +++ /dev/null @@ -1,56 +0,0 @@ -#include - -#define GEN "[GENERIC]" -#define FS "[FILESYSTEM]" -#define GUI "[GRAPHICS]" -#define PADDING 12 - -FHDR(cmd_help) -{ - extern console_cmd_t commands[]; - extern int cmd_count; - - if (*s == '\0') { - // these are COMMON commands, soon i will split all comands - print("[COMMON]\n", GFX_YELLOW); - - for (int i = 0; i < cmd_count; i++) { - char buf[128]; - str_copy(buf, " "); - str_append(buf, commands[i].name); - - int name_len = str_len(commands[i].name); - int padding = PADDING - name_len; - for (int p = 0; p < padding && p < 14; p++) { - str_append(buf, " "); - } - - str_append(buf, "- "); - str_append(buf, commands[i].description); - str_append(buf, "\n"); - print(buf, GFX_WHITE); - } - - print("Type 'help ' for details", GFX_GRAY_50); - } else { - // specific commands - const char *p = s; - while (*p == ' ') p++; - - console_cmd_t *cmd = console_find_cmd(p); - if (cmd) { - char buf[128]; - - str_copy(buf, "\n"); - str_append(buf, cmd->description); - print(buf, GFX_WHITE); - - str_copy(buf, "\nUsage: "); - str_append(buf, cmd->usage); - print(buf, GFX_YELLOW); - print("\n", GFX_WHITE); - } else { - print("\nCommand not found", GFX_RED); - } - } -} diff --git a/src/kernel/console/functions/keymap.c b/src/kernel/console/functions/keymap.c deleted file mode 100644 index a64d676..0000000 --- a/src/kernel/console/functions/keymap.c +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include - -FHDR(cmd_keymap) { - if (!s || *s == '\0') { - // Show current keymap - print("you use keymap: ", GFX_WHITE); - print(keymap_get_current_name(), GFX_WHITE); - print("\nuse: keymap \n", GFX_WHITE); - print("\nnote that only DE & US are correctly supported by now.\n", GFX_WHITE); - return; - } - - // parse keymap name - const char *p = s; - while (*p == ' ') p++; - - char keymap_name[16]; - int i = 0; - while (*p && *p != ' ' && *p != '\n' && i < 15) { - keymap_name[i++] = *p++; - } - keymap_name[i] = '\0'; - - // convert to uppercase - str_to_upper(keymap_name); - - // trys to set the keymap - if (keymap_set(keymap_name) != 0) { - print("error: keymap '", GFX_RED); - print(keymap_name, GFX_RED); - print("' not found\n", GFX_RED); - print("try: US, DE\n", GFX_RED); - return; - } - - print("keymap changed to: ", GFX_WHITE); - print(keymap_name, GFX_WHITE); - print("\n", GFX_WHITE); -} diff --git a/src/kernel/console/functions/ls.c b/src/kernel/console/functions/ls.c deleted file mode 100644 index 0442814..0000000 --- a/src/kernel/console/functions/ls.c +++ /dev/null @@ -1,74 +0,0 @@ -#include -#include - -extern char cwd[]; - -FHDR(cmd_ls) { - const char *path = s; - - // default to cwd if no path given - if (!s || *s == '\0') { - path = cwd; - } - - // resolve the directory - fs_node *dir = fs_resolve(path); - if (!dir) { - print("error: directory not found\n", GFX_RED); - print("use: \"ls /boot\" or \"ls /dev\" or any kind of dir.\n", GFX_RED); - return; - } - - if (dir->type != FS_DIR) { - print("error: not a directory\n", GFX_RED); - return; - } - - // list all children - fs_node *child = dir->children; - if (!child) { - print("this folder is empty \n", GFX_GRAY_50); - return; - } - - int count = 0; - while (child) { - // different colors for different types - u32 color = GFX_WHITE; - const char *type_str = ""; - - if (child->type == FS_DIR) { - color = GFX_BLUE; - type_str = "/"; - color = GFX_WHITE; - } else if (child->type == FS_DEV) { - color = GFX_WHITE; - type_str = "*"; - color = GFX_WHITE; - } - - print(child->name, color); - print(type_str, color); - - // show size for files - /*if (child->type == FS_FILE && child->size > 0) { - char buf[32]; - str_copy(buf, " | "); - str_append_uint(buf, (u32)child->size); - str_append(buf, " bytes"); - print(buf, GFX_GRAY_50); - }*/ - - print(" ", GFX_WHITE); - count++; - if (count % 6 == 0) { - print("\n", GFX_WHITE); - } - - child = child->next; - } - - if (count % 6 != 0) { - print("\n", GFX_WHITE); - } -} diff --git a/src/kernel/console/functions/mkdir.c b/src/kernel/console/functions/mkdir.c deleted file mode 100644 index bc5240f..0000000 --- a/src/kernel/console/functions/mkdir.c +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include - -extern char cwd[]; - -FHDR(cmd_mkdir) { - if (!s || *s == '\0') { - print("usage: mkdir \n", GFX_RED); - return; - } - - char full_path[MAX_PATH_LEN]; - - // Handle absolute vs relative paths - if (s[0] == '/') { - str_copy(full_path, s); - } else { - str_copy(full_path, cwd); - - if (cwd[str_len(cwd) - 1] != '/') { - str_append(full_path, "/"); - } - - str_append(full_path, s); - } - - // Create the directory - if (fs_mkdir(full_path) != 0) { - print("error: could not create directory\n", GFX_RED); - return; - } - - print("directory created: ", GFX_GREEN); - print(full_path, GFX_WHITE); - print("\n", GFX_WHITE); -} diff --git a/src/kernel/console/functions/poweroff.c b/src/kernel/console/functions/poweroff.c deleted file mode 100644 index ed3f12c..0000000 --- a/src/kernel/console/functions/poweroff.c +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include - -FHDR(cmd_reboot) -{ - (void)s; - - cursor_disable(); - print("Restarting system...\n", GFX_YELLOW); - - for (volatile int i = 0; i < 5000000; i++) - __asm__ volatile("nop"); - - cpu_poweroff(POWEROFF_REBOOT); -} - -FHDR(cmd_shutdown) -{ - (void)s; - - cursor_disable(); - print("Shutting down system...\n", GFX_YELLOW); - - for (volatile int i = 0; i < 5000000; i++) - __asm__ volatile("nop"); - - cpu_poweroff(POWEROFF_SHUTDOWN); -} diff --git a/src/kernel/console/functions/proc.c b/src/kernel/console/functions/proc.c deleted file mode 100644 index a33cf76..0000000 --- a/src/kernel/console/functions/proc.c +++ /dev/null @@ -1,14 +0,0 @@ -#include - -FHDR(cmd_ps) -{ -#if ENABLE_ULIME && RUNTESTS - if (!proc_mgr) - { - print("proc_mgr not initialized\n", white()); - return; - } - - proc_list_procs(proc_mgr); -#endif -} diff --git a/src/kernel/console/functions/slots.c b/src/kernel/console/functions/slots.c deleted file mode 100644 index bce3e76..0000000 --- a/src/kernel/console/functions/slots.c +++ /dev/null @@ -1,69 +0,0 @@ -#include -#include -//#include - -// ---- -// NOTE: -// Switching the active boot slot is a low-level operation, -// this directly modifies the boot configuration used by -// the system! -// ---- - -// --- -// this is a test function it will help us wenn updating the kernel -// --- - -FHDR(cmd_slot) -{ - if (!s || str_len(s) == 0) { - char current = readslot(); - - char msg[32] = "current active slot: "; - char slot_str[2]; - slot_str[0] = current; - slot_str[1] = 0; - - str_append(msg, slot_str); - str_append(msg, "\n"); - - print(msg, GFX_GREEN); - return; - } - - if (str_starts_with(s, "set ")) { - - char slot = s[4]; - - if (slot != 'A' && slot != 'B' && - slot != 'a' && slot != 'b') { - print("wrong slot num, use \"A\" or \"B\"\n", GFX_RED); - return; - } - - print("this does currently not switch the real kernel slot!\n", GFX_YELLOW); - - if (slot == 'a') slot = 'A'; - if (slot == 'b') slot = 'B'; - - char current = readslot(); - - if (current == slot) { - print("slot is already active\n", GFX_YELLOW); - return; - } - - if (writeslot(slot) == 0) { - print("switch slot and reboot...\n", GFX_YELLOW); - - for (volatile int i = 0; i < 5000000; i++) - __asm__ volatile("nop"); - - cpu_poweroff(POWEROFF_REBOOT); - } else { - print("failed to switch slot\n", GFX_RED); - } - - return; - } - return; -} diff --git a/src/kernel/console/functions/source.c b/src/kernel/console/functions/source.c deleted file mode 100644 index 389e8db..0000000 --- a/src/kernel/console/functions/source.c +++ /dev/null @@ -1,31 +0,0 @@ -// src/kernel/console/functions/source.c -#include - -FHDR(cmd_source) { - - // reloads the shell - - if (!s || *s == '\0') { - print("usage: source \n", GFX_RED); - return; - } - - if (str_equals(s, "console") || str_equals(s, "console/")) { - uci_reload(); - - reload_console_theme(); - - // Redraw banner - banner_force_update(); - - clear(CONSOLESCREEN_BG_COLOR); - banner_draw(); - console_window_init(); - - print("Console reloaded\n", GFX_GREEN); - //shell_print_prompt(); - return; - } - - print("source: only 'console' is supported\n", GFX_RED); -} diff --git a/src/kernel/console/functions/system.c b/src/kernel/console/functions/system.c deleted file mode 100644 index b955653..0000000 --- a/src/kernel/console/functions/system.c +++ /dev/null @@ -1,136 +0,0 @@ -#include -#include -#include -#include -#include -#include - -FHDR(cmd_modules) -{ - (void)s; // unused - print("Loaded Modules:\n", GFX_WHITE); - - int count = module_get_count(); - - if (count == 0) { - print("No modules loaded\n", GFX_WHITE); - return; - } - - char buf[128]; - for (int i = 0; i < count; i++) { - driver_module *mod = module_get_by_index(i); - if (mod) { - - //print("- ", GFX_WHITE); - //print(mod->name, GFX_GREEN); - - //print(" -> ", GFX_WHITE); - print(mod->mount, GFX_WHITE); - - //i simplified the module printing because its uneccesary - - u32 ver = mod->version; - u32 major = (ver >> 24) & 0xFF; - u32 minor = (ver >> 16) & 0xFF; - u32 patch = (ver >> 8) & 0xFF; - - //actually version is uneccesary too but i let it for now idk - str_copy(buf, " [v"); - str_append_uint(buf, major); - str_append(buf, "."); - str_append_uint(buf, minor); - str_append(buf, "."); - str_append_uint(buf, patch); - str_append(buf, "]"); - print(buf, GFX_GRAY_50); - - print("\n", GFX_WHITE); - } - } - - str_copy(buf, "\nTotal: "); - str_append_uint(buf, count); - str_append(buf, " module(s)"); - print(buf, GFX_WHITE); - //print("\nkeep in mind it will only show all modules if the os has a fs/vfs/memfs", GFX_GRAY_20); -} - -FHDR(cmd_meminfo) -{ - // (void)s; // unused parameter - - // char buf[128]; - - // u64 free = mem_get_free() / 1024; - // u64 used = mem_get_used() / 1024; - // u64 total = mem_get_total() / 1024; - - // str_copy(buf, "Free : "); - // str_append_uint(buf, (u32)(free >> 32)); - // str_append(buf, ":"); - // str_append_uint(buf, (u32)(free)); - // str_append(buf, " KB"); - // print(buf, GFX_GREEN); - - // str_copy(buf, "\nUsed : "); - // str_append_uint(buf, (u32)(used >> 32)); - // str_append(buf, ":"); - // str_append_uint(buf, (u32)(used)); - // str_append(buf, " KB"); - // print(buf, GFX_YELLOW); - - // str_copy(buf, "\nTotal: "); - // str_append_uint(buf, (u32)(total >> 32)); - // str_append(buf, ":"); - // str_append_uint(buf, (u32)(total)); - // str_append(buf, " KB"); - // print(buf, GFX_WHITE); - -} - -void print_res() { - char buf[128]; - str_copy(buf, ""); - str_append_uint(buf, get_fb_width()); - str_append(buf, "x"); - str_append_uint(buf, get_fb_height()); - str_append(buf, "\n"); - print(buf, GFX_WHITE); -} - -void ShowCPUName(){ - const char *cpu_name = cpu_get_brand(); - if (cpu_name[0]) { - print(cpu_name, GFX_WHITE); - } else { - print("Unknown CPU", GFX_WHITE); - } -} - -FHDR(cmd_sysinfo) -{ - (void)s; // unused parameter - - print(" \n", GFX_GREEN); - print(" ###########;m; ", GFX_GREEN); print(PC_NAME, GFX_GREEN); print("@", GFX_GREEN); print(USER_NAME, GFX_GREEN); print("\n", GFX_GREEN); - print(" # #########;m; ---------------\n", GFX_GREEN); //15 characters - print(" # #;m; Kernel: ", GFX_GREEN); print(KERNEL_BARENAME " " KERNEL_DEFRELEASE, GFX_WHITE); print("\n", GFX_WHITE); - print(" # #;m; Resolution: ", GFX_GREEN); print_res(); - print(" # ########;m; Bootloader: ", GFX_GREEN); print("Limine \n", GFX_WHITE); - print(" # ########;m; CPU: ", GFX_GREEN); ShowCPUName(); print("\n", GFX_WHITE); - print(" # #;m; Date: ", GFX_GREEN); GetCMOSDate(); print("\n", GFX_WHITE); - print(" # #;m; Uptime: ", GFX_GREEN); timer_print_uptime(); print("\n", GFX_WHITE); - print(" # #########;m; ---------------\n", GFX_GREEN); - print(" ###########;m; ", GFX_GREEN); - print("^ ", GFX_WHITE); //all colors: - print("^ ", GFX_RED); - print("^ ", GFX_GREEN); - print("^ ", GFX_YELLOW); - print("^ ", GFX_BLUE); - print("^ ", GFX_PURPLE); - print("^ ", GFX_CYAN); - print("^ \n", GFX_BG); //i think nobody will see this xd - print(" ", GFX_GREEN); // empty/new line - -} diff --git a/src/kernel/console/functions/text.c b/src/kernel/console/functions/text.c deleted file mode 100644 index 66f5dd9..0000000 --- a/src/kernel/console/functions/text.c +++ /dev/null @@ -1,167 +0,0 @@ -#include - -FHDR(cmd_echo) -{ - if (*s == '\0') { - print("\n", GFX_WHITE); - return; - } - - print(s, GFX_WHITE); -} - -FHDR(cmd_clear) -{ - u32 color = CONSOLESCREEN_BG_COLOR; - - /* - if (*s != '\0') { - if (!parse_color(s, &color)) { - print("wrong color\n", GFX_RED); - return; - } - } - */ - - if (*s != '\0') { - return; - } - - shell_clear_screen(color); - banner_force_update(); -} - -FHDR(cmd_fsize) -{ - if (*s == '\0') { - char buf[64]; - str_copy(buf, "Current font size: "); - str_append_uint(buf, font_scale); - print(buf, GFX_WHITE); - return; - } - - // skip spaces - while (*s == ' ') s++; - - // parse number - int size = 0; - while (*s >= '0' && *s <= '9') { - size = size * 10 + (*s - '0'); - s++; - } - - if (size < 1 || size > 4) { - print("Invalid size. Use 1-4\n", GFX_RED); - return; - } - - clear(CONSOLESCREEN_BG_COLOR); - set_font_scale(size); - /*char buf[64]; - str_copy(buf, " Font size set to "); - str_append_uint(buf, size); - print(buf, GFX_GREEN); - */ - clear(CONSOLESCREEN_BG_COLOR); - banner_force_update(); - console_window_update_layout(); - - cursor_x = CONSOLE_PADDING_X; - cursor_y = banner_get_height(); -} - -FHDR(cmd_font) { - if (*s == '\0') { - return; - } - - // Parse font number - const char *p = s; - while (*p == ' ') p++; - - int font_num = 0; - while (*p >= '0' && *p <= '9') { - font_num = font_num * 10 + (*p - '0'); - p++; - } - - if (f_setcontext((font_type_t)font_num) == 0) { - clear(CONSOLESCREEN_BG_COLOR); - banner_force_update(); - print("\n", GFX_GREEN); - } else { - print("use: font ", GFX_RED); - } -} - -FHDR(cmd_cyrillc_sumbol) -{ - (void)s; - print("АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ\n", GFX_WHITE); - print("абвгдеёжзийклмнопрстуфхцчшщъыьэюя\n", GFX_WHITE); -} - -FHDR(cmd_latin_sumbol) -{ - (void)s; - print("ABCDEFGHIJKLMNOPQRSTUVWXYZ\n", GFX_WHITE); - print("abcdefghijklmnopqrstuvwxyz\n", GFX_WHITE); -} - -FHDR(cmd_all_sumbol) -{ - (void)s; - print("ABCDEFGHIJKLMNOPQRSTUVWXYZ\n", GFX_WHITE); - print("abcdefghijklmnopqrstuvwxyz\n", GFX_WHITE); - print("AEOEUESS: ÄÖÜ äöü ß\n", GFX_WHITE); - print("АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ\n", GFX_WHITE); - print("абвгдеёжзийклмнопрстуфхцчшщъыьэюя\n", GFX_WHITE); - print("0123456789 !?.,:;+-*/=_()[]{}@#%&$\"'<>\\|`\n", GFX_WHITE); -} - -/*FHDR(cmd_help) -{ - if (*s == '\0') { - // show all commands - print("[COMMMON]\n", GFX_YELLOW); - print(" echo [text] - echo [text]\n", GFX_WHITE); - print(" clear [color] - clear screen\n", GFX_WHITE); - print(" help [command] - displays this list\n", GFX_WHITE); - print(" scale [1-4] - change screen size\n", GFX_WHITE); - print(" font [0-1] - switch fonts\n", GFX_WHITE); - print(" date - show current date\n", GFX_WHITE); - print(" time - show current time\n", GFX_WHITE); - print(" calendar - show date & time\n", GFX_WHITE); - print(" uptime - displays the uptime\n", GFX_WHITE); - print(" dofetch - emexOS system fetch\n", GFX_WHITE); - print(" cat - show file content\n", GFX_WHITE); - print(" ls - list directory contents\n", GFX_WHITE); - print(" shut - shuts down the system\n", GFX_WHITE); - //print("[SYSTEM]\n", GFX_YELLOW); - print(" meminfo - heap memory information\n", GFX_WHITE); - print(" modules - shows all modules in fs\n", GFX_WHITE); - print("Type 'help ' for details", GFX_GRAY_50); - } else { - // show specific command help - const char *p = s; - while (*p == ' ') p++; - - console_cmd_t *cmd = console_find_cmd(p); - if (cmd) { - char buf[128]; - - str_copy(buf, "\n"); - str_append(buf, cmd->description); - print(buf, GFX_WHITE); - - str_copy(buf, "\nUsage: "); - str_append(buf, cmd->usage); - print(buf, GFX_YELLOW); - print("\n", GFX_WHITE); - } else { - print("\nCommand not found", GFX_RED); - } - } -} -*/ diff --git a/src/kernel/console/functions/touch.c b/src/kernel/console/functions/touch.c deleted file mode 100644 index f549ce4..0000000 --- a/src/kernel/console/functions/touch.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include - -extern char cwd[]; - -FHDR(cmd_touch) -{ - if (!s || *s == '\0') { - print("usage: touch \n", GFX_RED); - return; - } - - char path[MAX_PATH_LEN]; - - if (s[0] == '/') { - str_copy(path, s); - } else { - str_copy(path, cwd); - if (cwd[str_len(cwd) - 1] != '/') str_append(path, "/"); - str_append(path, s); - } - - int fd = fs_open(path, O_CREAT | O_WRONLY); - if (fd < 0) { - print("error: cannot create file\n", GFX_RED); - return; - } - - fs_close(fd); -} diff --git a/src/kernel/console/functions/tree.c b/src/kernel/console/functions/tree.c deleted file mode 100644 index 4344aea..0000000 --- a/src/kernel/console/functions/tree.c +++ /dev/null @@ -1,76 +0,0 @@ -// src/kernel/console/functions/tree.c -#include -#include -extern char cwd[]; - -static void tree_print(fs_node *node, int depth, int is_last) -{ - while (node) - { - // indentation - for (int i = 0; i < depth; i++) { - print("| ", GFX_GRAY_50); - } - - // prefix - if (is_last && !node->next) { - print("`-- ", GFX_GRAY_50); - } else { - print("|-- ", GFX_GRAY_50); - } - - // name + color - u32 color = GFX_WHITE; - const char *suffix = ""; - - if (node->type == FS_DIR) { - color = GFX_BLUE; - suffix = "/"; - } else if (node->type == FS_DEV) { - color = GFX_WHITE; - suffix = "*"; - } - - print(node->name, color); - print(suffix, color); - print("\n", GFX_WHITE); - - // recurse into directories - if (node->type == FS_DIR && node->children) { - tree_print(node->children, depth + 1, !node->next); - } - - node = node->next; - } -} - -FHDR(cmd_tree) -{ - const char *path = s; - - if (!s || *s == '\0') { - path = cwd; - } - - fs_node *dir = fs_resolve(path); - if (!dir) { - print("error: directory not found\n", GFX_RED); - return; - } - - if (dir->type != FS_DIR) { - print("error: not a directory\n", GFX_RED); - return; - } - - // print root - print(dir->name, GFX_BLUE); - print("/\n", GFX_BLUE); - - if (!dir->children) { - print("(empty)\n", GFX_GRAY_50); - return; - } - - tree_print(dir->children, 0, 1); -} diff --git a/src/kernel/console/functions/view.c b/src/kernel/console/functions/view.c deleted file mode 100644 index 95347cd..0000000 --- a/src/kernel/console/functions/view.c +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include -#include - -FHDR(cmd_view) { - if (!s || *s == '\0') { - print("usage: view \n", GFX_RED); - return; - } - - bmp_image_t img; - if (bmp_load(s, &img) != 0) { - print("error: cannot load image\n", GFX_RED); - return; - } - - //clear(CONSOLESCREEN_BG_COLOR); - - // centers image - u32 x = (get_fb_width() - img.width) / 2; - u32 y = (get_fb_height() - img.height) / 2; - - bmp_draw(&img, x, y); - banner_draw(); - - //print("\nPress any key to continue...\n", GFX_GRAY_50); - - while (1) { - if (keyboard_has_key()) { - key_event_t event; - if (keyboard_get_event(&event) && event.pressed) { - break; - } - } - __asm__ volatile("hlt"); - } - - bmp_free(&img); - //clear(CONSOLESCREEN_BG_COLOR); - banner_draw(); -} diff --git a/src/kernel/console/functions/whoami.c b/src/kernel/console/functions/whoami.c deleted file mode 100644 index da4cb21..0000000 --- a/src/kernel/console/functions/whoami.c +++ /dev/null @@ -1,9 +0,0 @@ -// src/kernel/console/functions/whoami.c -#include - -FHDR(cmd_whoami) { - (void)s; - - print(uci_get_user_name(), GFX_WHITE); - print("\n", GFX_WHITE); -} diff --git a/src/kernel/console/graph/dos.c b/src/kernel/console/graph/dos.c deleted file mode 100644 index 0588fbb..0000000 --- a/src/kernel/console/graph/dos.c +++ /dev/null @@ -1,83 +0,0 @@ -#include "dos.h" -#include "uno.h" -#include -#include - -void console_window_init(void) { - cursor_x = CONSOLE_PADDING_X; - cursor_y = banner_get_height(); -} - -void console_window_clear(u32 color) -{ - u32 fb_w = get_fb_width(); - u32 fb_h = get_fb_height(); - u32 banner_h = banner_get_height(); - - // clear below banner - draw_rect(0, banner_h, fb_w, fb_h - banner_h, color); - //TODO: - // implement real dirty rectangles/ screen clear - - // redraw banner - banner_draw(); - - // reset cursor to console start - cursor_x = CONSOLE_PADDING_X; - cursor_y = banner_h; -} - -u32 console_window_get_start_y(void) { - return banner_get_height(); -} - -u32 console_window_get_max_y(void) { - return get_fb_height(); -} - -void console_window_check_scroll(void) -{ - u32 char_height = fm_get_char_height() * font_scale; - u32 line_height = char_height + 2 * font_scale; - u32 fb_h = get_fb_height(); - u32 banner_h = banner_get_height(); - - // check if cursor is out of screen - if (cursor_y + char_height > fb_h) { - u32 fb_w = get_fb_width(); - u32 pitch_dwords = get_fb_pitch() / 4; - u32 *fb = get_framebuffer(); - - // move content up by line_height - for (u32 y = banner_h + line_height; y < fb_h; y++) { - for (u32 x = 0; x < fb_w; x++) { - fb[(y - line_height) * pitch_dwords + x] = fb[y * pitch_dwords + x]; - } - } - - // cls bottom line - for (u32 y = fb_h - line_height; y < fb_h; y++) { - for (u32 x = 0; x < fb_w; x++) { - fb[y * pitch_dwords + x] = CONSOLESCREEN_BG_COLOR; - } - } - - // move cursor up - cursor_y -= line_height; - - if (cursor_y < banner_h) { - cursor_y = banner_h; - } - } -} - -void console_window_update_layout(void) -{ - //after fsize change - // adjust cursor - u32 banner_h = banner_get_height(); - - if (cursor_y < banner_h) { - cursor_y = banner_h; - } -} diff --git a/src/kernel/console/graph/dos.h b/src/kernel/console/graph/dos.h deleted file mode 100644 index d06bd98..0000000 --- a/src/kernel/console/graph/dos.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef CONSOLE_DOS_H -#define CONSOLE_DOS_H - -#include - -#define CONSOLE_PADDING_X 0 // 15(baner) + 8(font scale) 23 - -void console_window_init(void); -void console_window_clear(u32 color); -u32 console_window_get_start_y(void); -u32 console_window_get_max_y(void); -void console_window_check_scroll(void); -void console_window_update_layout(void); - -//TODO: -// this needs to be remade when we have a window system in usermode - -#endif diff --git a/src/kernel/console/graph/uno.c b/src/kernel/console/graph/uno.c deleted file mode 100644 index 692a649..0000000 --- a/src/kernel/console/graph/uno.c +++ /dev/null @@ -1,174 +0,0 @@ -#include "uno.h" -#include -#include -#include -#include -#include -#include - -#include - -static u32 banner_y = 0; -static u32 banner_y_s = BANNER_Y_SPACING; -static u8 last_second = 0; -static u8 needs_update = 1; -static u32 current_banner_height = 0;//BANNER_HEIGHT; - -// forward declaration -static void banner_timer_callback(void); - -void banner_init(void) -{ - banner_y = 0; - banner_y_s = BANNER_Y_SPACING; - last_second = 0; - needs_update = 1; - //current_banner_height = BANNER_HEIGHT; - - u32 char_height = fm_get_char_height() * font_scale; - current_banner_height = char_height + (banner_y_s * 2); - - timer_register_callback(banner_timer_callback); - banner_draw(); -} - -void banner_draw(void) -{ - u32 fb_w = get_fb_width(); - - // based on font scale - u32 char_height = fm_get_char_height() * font_scale; - u32 o_cursor_x = cursor_x; - u32 o_cursor_y = cursor_y; - u32 o_scale = font_scale; - current_banner_height = char_height + (banner_y_s * 2); - - // draw background (in future moved to the wm) - draw_rect(0, banner_y, fb_w, current_banner_height, BANNER_BG_COLOR); - draw_rect(0, banner_y + current_banner_height - font_scale, fb_w, font_scale, BANNER_BORDER_COLOR); - - // use current screen_scale for banner - - cursor_x = 4; - cursor_y = banner_y + banner_y_s; - - const char *os_name = KERNEL_VERSION; - for (int i = 0; os_name[i]; i++) { - putchar(os_name[i], BANNER_TEXT_COLOR); - } - - // centered = "console" - // TODO: - // should be called after the current app - const char *center_text = CONSOLE_APP_NAME; - int text_width = str_len(center_text) * (fm_get_char_width() * font_scale); - cursor_x = (fb_w - text_width) / 2; - cursor_y = banner_y + banner_y_s; - - for (int i = 0; center_text[i]; i++) { - putchar(center_text[i], BANNER_TEXT_COLOR); - } - - // right side = Date & Time - banner_update_time(); - - // restore cursor and scale from before - font_scale = o_scale; - cursor_x = o_cursor_x; - cursor_y = o_cursor_y; - - needs_update = 0; -} - -void banner_update_time(void) -{ - u32 fb_w = get_fb_width(); - u32 o_cursor_x = cursor_x; - u32 o_cursor_y = cursor_y; - u32 o_scale = font_scale; - - // based on screen scale - - cmos_time_t time; - cmos_read_time(&time); - - char time_buf[32]; - str_copy(time_buf, ""); - - // date as DD/MM/YY - if (time.month < 10) str_append(time_buf, "0"); - str_append_uint(time_buf, time.month); - str_append(time_buf, "/"); - if (time.day < 10) str_append(time_buf, "0"); - str_append_uint(time_buf, time.day); - str_append(time_buf, "/"); - if (time.year < 10) str_append(time_buf, "0"); - str_append_uint(time_buf, time.year); - //TODO: - // in future it will be a programm from functions/cmos.c - - str_append(time_buf, " "); - - // time in HH:MM:SS - if (time.hour < 10) str_append(time_buf, "0"); - str_append_uint(time_buf, time.hour); - str_append(time_buf, ":"); - if (time.minute < 10) str_append(time_buf, "0"); - str_append_uint(time_buf, time.minute); - str_append(time_buf, ":"); - if (time.second < 10) str_append(time_buf, "0"); - str_append_uint(time_buf, time.second); - //same for here its from cmos.c - - int text_len = str_len(time_buf); - int text_pixel_width = text_len * (fm_get_char_width() * font_scale); - - u32 char_height = fm_get_char_height() * font_scale; - draw_rect(fb_w - text_pixel_width - 8, banner_y, text_pixel_width + 8, current_banner_height, BANNER_BG_COLOR); - - cursor_x = fb_w - text_pixel_width - 4; - cursor_y = banner_y + banner_y_s; - - for (int i = 0; time_buf[i]; i++) { - putchar(time_buf[i], BANNER_TEXT_COLOR); - } - - //otherwise the time banner will overwrite the line - draw_rect(fb_w - text_pixel_width - 8, banner_y + current_banner_height - font_scale, - text_pixel_width + 8, font_scale, BANNER_BORDER_COLOR); - - font_scale = o_scale; - cursor_x = o_cursor_x; - cursor_y = o_cursor_y; -} - -// private timer callback (c static) -static void banner_timer_callback(void) -{ - cmos_time_t time; - cmos_read_time(&time); - - if (time.second != last_second) { - last_second = time.second; - needs_update = 1; - } - if (needs_update) { - banner_update_time(); - needs_update = 0; - } -} - -void banner_tick(void) { - // This function still exists due compatibility - // i don't want to rename it in other functions too - banner_timer_callback(); -} - -void banner_force_update(void) { - needs_update = 1; - banner_draw(); -} - -u32 banner_get_height(void) { - return current_banner_height; -} diff --git a/src/kernel/console/graph/uno.h b/src/kernel/console/graph/uno.h deleted file mode 100644 index ba2dff8..0000000 --- a/src/kernel/console/graph/uno.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef CONSOLE_UNO_H -#define CONSOLE_UNO_H - -#include -#include -#include - -//#define BANNER_HEIGHT 15 -#define BANNER_Y_SPACING 4 // vertical spacing -#define BANNER_BG_COLOR GFX_GRAY_20 // bar background -#define BANNER_BORDER_COLOR GFX_GRAY_40 // border bottom -#define BANNER_TEXT_COLOR CONSOLESCREEN_COLOR // White text -#define BANNER_UPDATE_INTERVAL 60 - -void banner_init(void); -void banner_draw(void); -void banner_update_time(void); -void banner_tick(void); // called from timer -void banner_force_update(void); // force update -u32 banner_get_height(void); - -#endif diff --git a/src/kernel/console/parser.c b/src/kernel/console/parser.c deleted file mode 100644 index 90e646f..0000000 --- a/src/kernel/console/parser.c +++ /dev/null @@ -1,93 +0,0 @@ -#include - -// parse color argument if provided -int parse_color(const char *color_str, u32 *out_color) { - if (!color_str || !out_color) return 0; - - const char *p = color_str; - while (*p == ' ') p++; - - // simple color name parsing - if (*p == 'b' && *(p+1) == 'l' && *(p+2) == 'a' && *(p+3) == 'c' && *(p+4) == 'k' && *(p+5) == '\0') { - *out_color = GFX_BLACK; - return 1; - } else if (*p == 'w' && *(p+1) == 'h' && *(p+2) == 'i' && *(p+3) == 't' && *(p+4) == 'e' && *(p+5) == '\0') { - *out_color = GFX_WHITE; - return 1; - } else if (*p == 'r' && *(p+1) == 'e' && *(p+2) == 'd' && *(p+3) == '\0') { - *out_color = GFX_RED; - return 1; - } else if (*p == 'g' && *(p+1) == 'r' && *(p+2) == 'e' && *(p+3) == 'e' && *(p+4) == 'n' && *(p+5) == '\0') { - *out_color = GFX_GREEN; - return 1; - } else if (*p == 'b' && *(p+1) == 'l' && *(p+2) == 'u' && *(p+3) == 'e' && *(p+4) == '\0') { - *out_color = GFX_BLUE; - return 1; - } else if (*p == 'c' && *(p+1) == 'y' && *(p+2) == 'a' && *(p+3) == 'n' && *(p+4) == '\0') { - *out_color = GFX_CYAN; - return 1; - } else if (*p == 'y' && *(p+1) == 'e' && *(p+2) == 'l' && *(p+3) == 'l' && *(p+4) == 'o' && *(p+5) == 'w' && *(p+6) == '\0') { - *out_color = GFX_YELLOW; - return 1; - } else if (*p == 'p' && *(p+1) == 'u' && *(p+2) == 'r' && *(p+3) == 'p' && *(p+4) == 'l' && *(p+5) == 'e' && *(p+6) == '\0') { - *out_color = GFX_PURPLE; - return 1; - } - - return 0; -} - -// split input in && then execute the commands -void parse_and_execute_chained(const char *input) { - if (!input || *input == '\0') return; - - char commands[MAX_CHAINED_CMDS][MAX_INPUT_LEN]; - int cmd_count = 0; - int cmd_pos = 0; - - const char *p = input; - - // split input in && - while (*p && cmd_count < MAX_CHAINED_CMDS) { - while (*p == ' ') p++; // space after/ before && - - // copy command until && or end - cmd_pos = 0; - while (*p && cmd_pos < MAX_INPUT_LEN - 1) { - if (*p == '&' && *(p+1) == '&') { // == && - commands[cmd_count][cmd_pos] = '\0'; - cmd_count++; - p += 2; - break; - } - commands[cmd_count][cmd_pos++] = *p++; - } - - // if last command is or buffer is full - if (*p == '\0' || cmd_pos >= MAX_INPUT_LEN - 1) { - commands[cmd_count][cmd_pos] = '\0'; - cmd_count++; - break; - } - } - - // execute all commands - for (int i = 0; i < cmd_count; i++) { - //trailing - int len = 0; - while (commands[i][len]) len++; - len--; - while (len >= 0 && commands[i][len] == ' ') { - commands[i][len] = '\0'; - len--; - } - - if (commands[i][0] != '\0') { - console_execute(commands[i]); - if (i < cmd_count - 1) { - print("\n", GFX_WHITE); - } - - } - } -} diff --git a/src/kernel/console/promtinit.c b/src/kernel/console/promtinit.c deleted file mode 100644 index 4ab3032..0000000 --- a/src/kernel/console/promtinit.c +++ /dev/null @@ -1,56 +0,0 @@ -#include "console.h" -#include - -void console_config_init(void) { - // Create directories - fs_mkdir("/.config/ekmsh"); - fs_mkdir("/.config/ekmsh/fonts"); - //fs_mkdir("/.config/ekmsh/prompts"); - - // Create default prompt.conf - int fd = fs_open("/.config/ekmsh/prompt.cfg", O_CREAT | O_WRONLY); - if (fd >= 0) { - const char *default_config = - "# currently there is no color support for the prompt, but soon!\n" - "# %u = username,\n# %h = hostname,\n# %w = curent directory\n" - "[%u@%h:%w]# \n" - ; - - fs_write(fd, default_config, str_len(default_config)); - fs_close(fd); - } - - // Create default theme.cfg - fd = fs_open("/.config/ekmsh/theme.cfg", O_CREAT | O_WRONLY); // get read by graph/theme - if (fd >= 0) { - const char *default_theme = - "# use: 0xAARRGGBB\n" - "\n" - "BLACK: 0xFF111111\n" - "BG: 0xFF1F1F1F\n" - "RED: 0xFF9E6E6E\n" - "GREEN: 0xFF7A8A7A\n" - "YELLOW: 0xFFB8A788\n" - "BLUE: 0xFF6E7F8E\n" - "PURPLE: 0xFF857A8E\n" - "CYAN: 0xFF7A8E8E\n" - "WHITE: 0xFFD8D8D8\n" - ; - - fs_write(fd, default_theme, str_len(default_theme)); - fs_close(fd); - } - fd = fs_open("/.config/ekmsh/con.cfg", O_CREAT | O_WRONLY); // get read by graph/theme - if (fd >= 0) { - const char *Cconfiguration = - "CONSOLE_PROG: \"ekmsh\"\n" - "CONSOLE_NAME: \"console\"\n" - "\n" - "CONSOLE_VERS: \"1.3\" # new with login\n" - ; - - fs_write(fd, Cconfiguration, str_len(Cconfiguration)); - fs_close(fd); - } - // copy bdf here... -} diff --git a/src/kernel/console/shell_screen.c b/src/kernel/console/shell_screen.c deleted file mode 100644 index 56b1d13..0000000 --- a/src/kernel/console/shell_screen.c +++ /dev/null @@ -1,108 +0,0 @@ -#include "console.h" -#include "graph/uno.h" -#include "graph/dos.h" -#include - -void shell_clear_screen(u32 color) -{ - - console_window_clear(color); -} - -static conf_entry_t prompt_conf[16]; -static int prompt_conf_count = 0; - -void shell_load_prompt_config(void) { - prompt_conf_count = conf_load("/.config/ekmsh/prompt.cfg", - prompt_conf, 16); -} - -extern char cwd[]; - -/*void shell_print_prompt(void) -{ - - string("\n", GFX_WHITE); - string(user_config_get_pc_name(), GFX_WHITE); - string("@", GFX_WHITE); - string(user_config_get_user_name(), GFX_WHITE); - //string("\x01 ", GFX_YELLOW); - string(":", GFX_WHITE); - if (str_len(cwd) > 1 && cwd[str_len(cwd) - 1] == '/') { - char prompt_cwd[MAX_PATH_LEN]; - str_copy(prompt_cwd, cwd); - prompt_cwd[str_len(cwd) - 1] = '\0'; - string(prompt_cwd, GFX_WHITE); - } - string("# ", GFX_BLUE); -}*/ - -void shell_print_prompt(void) -{ - // emexOS will be the directory if we have a file system - - // in future it should be like: - /* - * string("\n", GFX_WHITE); - * string(variable, GFX_PURPLE); // variable is the current dir - * string(" > ", GFX_WHITE); - */ - // - - if (prompt_conf_count <= 0) { - shell_load_prompt_config(); - } - - const char *format = conf_get(prompt_conf, prompt_conf_count, "format"); - - if (!format) { - printf("using standard"); - string("\n[", GFX_WHITE); - string(uci_get_pc_name(), GFX_WHITE); - string("@", GFX_WHITE); - string(uci_get_user_name(), GFX_WHITE); - string("]", GFX_WHITE); - - if (str_len(cwd) > 1 && cwd[str_len(cwd) - 1] == '/') { - char prompt_cwd[MAX_PATH_LEN]; - str_copy(prompt_cwd, cwd); - prompt_cwd[str_len(cwd) - 1] = '\0'; - string(prompt_cwd, GFX_WHITE); - } else { - string(cwd, GFX_WHITE); - } - - string("# ", GFX_BLUE); - return; - } - - string("\n", GFX_WHITE); - - for (const char *p = format; *p; p++) { - if (*p == '%') { - p++; - if (*p == 'u') string(uci_get_user_name(), GFX_WHITE); - else if (*p == 'h') string(uci_get_pc_name(), GFX_WHITE); - else if (*p == 'w') { - if (str_len(cwd) > 1 && cwd[str_len(cwd) - 1] == '/') { - char prompt_cwd[MAX_PATH_LEN]; - str_copy(prompt_cwd, cwd); - prompt_cwd[str_len(cwd) - 1] = '\0'; - string(prompt_cwd, GFX_WHITE); - } else { - string(cwd, GFX_WHITE); - } - } - else if (*p == '%') string("%", GFX_WHITE); - } else { - char c[2] = {*p, '\0'}; - string(c, GFX_WHITE); - } - } -} - -void shell_redraw_input(void) -{ - // for future use: redraw current input line - // useful when implementing line editing features (programms) -} diff --git a/src/kernel/cpu/cpu.h b/src/kernel/cpu/cpu.h index 273ff29..243e4aa 100644 --- a/src/kernel/cpu/cpu.h +++ b/src/kernel/cpu/cpu.h @@ -79,4 +79,11 @@ const char* cpu_get_brand(void); cpu_info_t* cpu_get_info(void); int cpu_has_feature(u32 feature); +void cli(void); +void sti(void); +__attribute__((noreturn)) void halt(void); +__attribute__((noreturn)) void idle(void); +void wfi(void); +void nop(void); + #endif diff --git a/src/kernel/cpu/halt.c b/src/kernel/cpu/halt.c new file mode 100644 index 0000000..ae18264 --- /dev/null +++ b/src/kernel/cpu/halt.c @@ -0,0 +1,39 @@ +#include "cpu.h" + +// +// MADE BY @msaid5860 +// + +// Disable interrupts +void cli(void) { + __asm__ volatile("cli"); +} + +// Enable interrupts +void sti(void) { + __asm__ volatile("sti"); +} + +// Full system halt +__attribute__((noreturn)) void chalt(void) { + __asm__ volatile("cli"); + for (;;) __asm__ volatile("hlt"); +} + +void halt(void) { + __asm__ volatile("hlt"); +} + +// Idle halt +__attribute__((noreturn)) void idle(void) { + for (;;) __asm__ volatile("hlt"); +} + +// Wait for interrupt +void wfi(void) { + __asm__ volatile("sti; pause; hlt"); +} + +void nop(void) { + __asm__ volatile("nop"); +} \ No newline at end of file diff --git a/src/kernel/cpu/poweroff.c b/src/kernel/cpu/poweroff.c index 421df4e..a255b92 100644 --- a/src/kernel/cpu/poweroff.c +++ b/src/kernel/cpu/poweroff.c @@ -18,12 +18,16 @@ static inline void x86_restart(void) __asm__ volatile("nop"); // PCI RCR - u8 temp = inb(0xCF9); - outb(0xCF9, temp | 0x02); - outb(0xCF9, temp | 0x06); + outb(0xCF9, 0x02); + for (volatile int i = 0; i < 100; i++) __asm__ volatile("nop"); + outb(0xCF9, 0x0E); + for (volatile int i = 0; i < 1000000; i++) __asm__ volatile("nop"); - for (volatile int i = 0; i < 1000000; i++) - __asm__ volatile("nop"); + __asm__ volatile( + "lidt %0\n" + "int $3\n" + :: "m"((u64[]){0, 0}) : "memory" + ); } static inline void x86_shutdown(void) diff --git a/src/kernel/devices/devices.h b/src/kernel/devices/devices.h new file mode 100644 index 0000000..bb8af65 --- /dev/null +++ b/src/kernel/devices/devices.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ATANAME "dev_atahdd0" +#define ATAPATH "/dev/hda" +#define ATAUNIVERSAL VERSION_NUM(0, 1, 2, 0) + +#define KBDNAME "dev_ps2_keyboard0" +#define KBDPATH "/dev/input/keyboard0" +#define KBDUNIVERSAL VERSION_NUM(0, 3, 1, 0) + +#define MS0NAME "dev_ps2_mouse0" +#define MS0PATH "/dev/input/mouse0" +#define MS0UNIVERSAL VERSION_NUM(0, 0, 0, 0) + +#define EFBNAME FBN +#define FB0NAME "dev_fb0" +#define FB0PATH "/dev/fb0" +#define FB0UNIVERSAL VERSION_NUM(0, 0, 0, 0) // always 0.0.0.0 + +#define ZERNAME "dev_zero" +#define ZERPATH "/dev/zero" +#define ZERUNIVERSAL VERSION_NUM(0, 0, 0, 0) // always 0.0.0.0 + +#define NULNAME "dev_null" +#define NULPATH "/dev/null" +#define NULUNIVERSAL VERSION_NUM(0, 0, 0, 0) // always 0.0.0.0 + +#define TTY0NAME "dev_tty0" +#define TTY0PATH "/dev/tty0" +#define TTY0UNIVERSAL VERSION_NUM(0, 0, 1, 2) + +#define URNDNAME "dev_urandom" +#define URNDPATH "/dev/urandom" +#define URNDUNIVERSAL VERSION_NUM(0, 0, 1, 0) + +#define RNDNAME "dev_random" +#define RNDPATH "/dev/random" +#define RNDUNIVERSAL VERSION_NUM(0, 0, 1, 0) \ No newline at end of file diff --git a/src/kernel/devices/disks/hdd0.c b/src/kernel/devices/disks/hdd0.c new file mode 100644 index 0000000..03c3dfe --- /dev/null +++ b/src/kernel/devices/disks/hdd0.c @@ -0,0 +1,97 @@ +#include "hdd0.h" +#include +#include +#include +#include +#include +#include +#include + +#define HDA_SECTOR_SIZE 512 + +static int ATAmodule_init(void) { + log("[HDA]", "init /dev/hda\n", d); + return 0; +} + +static void ATAmodule_fini(void) { + // cleanup if needed +} + +static void *hda_open(const char *path) { + (void)path; + return ATAget_device(0); +} + +static int hda_read(void *handle, void *buf, size_t count, u64 offset) +{ + ATAdevice_t *dev = (ATAdevice_t *)handle; + if (!dev || !buf || count == 0) return -1; + + u64 lba = offset / HDA_SECTOR_SIZE; + u32 lba_offset = offset % HDA_SECTOR_SIZE; + u32 sectors = (u32)((lba_offset + count + HDA_SECTOR_SIZE - 1) / HDA_SECTOR_SIZE); + + // temp buffer for unaligned reads + static u8 tmp[HDA_SECTOR_SIZE] __attribute__((aligned(16))); + size_t remaining = count; + u8 *dst = (u8 *)buf; + + for (u32 i = 0; i < sectors && remaining > 0; i++) + { + if (ATAread_sectors(dev, lba + i, 1, (u16 *)tmp) != 0) return -1; + + u32 src_off = (i == 0) ? lba_offset : 0; + u32 to_copy = HDA_SECTOR_SIZE - src_off; + if (to_copy > remaining) to_copy = (u32)remaining; + + memcpy(dst, tmp + src_off, to_copy); + + dst += to_copy; + remaining -= to_copy; + } + return (int)(count - remaining); +} + +static int hda_write(void *handle, const void *buf, size_t count, u64 offset) +{ + ATAdevice_t *dev = (ATAdevice_t *)handle; + if (!dev || !buf || count == 0) return -1; + + u64 lba = offset / HDA_SECTOR_SIZE; + u32 lba_offset = offset % HDA_SECTOR_SIZE; + u32 sectors = (u32)((lba_offset + count + HDA_SECTOR_SIZE - 1) / HDA_SECTOR_SIZE); + + static u8 tmp[HDA_SECTOR_SIZE] __attribute__((aligned(16))); + size_t remaining = count; + const u8 *src = (const u8 *)buf; + + for (u32 i = 0; i < sectors && remaining > 0; i++) + { + u32 dst_off = (i == 0) ? lba_offset : 0; + u32 to_copy = HDA_SECTOR_SIZE - dst_off; + if (to_copy > remaining) to_copy = (u32)remaining; + if (dst_off != 0 || to_copy != HDA_SECTOR_SIZE) { + if (ATAread_sectors(dev, lba + i, 1, (u16 *)tmp) != 0) return -1; + } + + memcpy(tmp + dst_off, src, to_copy); + + if (ATAwrite_sectors(dev, lba + i, 1, (u16 *)tmp) != 0) return -1; + + src += to_copy; + remaining -= to_copy; + } + return (int)(count - remaining); +} + +driver_module ata_module = { + .name = ATANAME, + .mount = ATAPATH, + .version = ATAUNIVERSAL, + .init = ATAmodule_init, + .fini = ATAmodule_fini, + .open = hda_open, + .read = hda_read, + .write = hda_write, +}; \ No newline at end of file diff --git a/src/kernel/devices/disks/hdd0.h b/src/kernel/devices/disks/hdd0.h new file mode 100644 index 0000000..153a8f3 --- /dev/null +++ b/src/kernel/devices/disks/hdd0.h @@ -0,0 +1,9 @@ +#ifndef DEVICE_HDD0_H +#define DEVICE_HDD0_H + +#include + +// /dev/hda +extern driver_module ata_module; + +#endif \ No newline at end of file diff --git a/src/kernel/devices/fb0/fb0.c b/src/kernel/devices/fb0/fb0.c new file mode 100644 index 0000000..9d865fc --- /dev/null +++ b/src/kernel/devices/fb0/fb0.c @@ -0,0 +1,156 @@ +#include "fb0.h" + +#include +#include +#include +#include +#include +#include + +#include + +static size_t fb_write_pos = 0; +static size_t fb_read_pos = 0; + +static int fb0_mod_init(void) { + log("[FB0]", "init /dev/fb0\n", d); + return 0; +} + +static void fb0_mod_fini(void) {} + +static void *fb0_open(const char *path) { + (void)path; + fb_write_pos = 0; + fb_read_pos = 0; + return (void *)1; +} + +static int fb0_read(void *handle, void *buf, size_t count, u64 offset) { + (void)handle; + (void)offset; + u32 *fb = get_framebuffer(); + u32 pitch = get_fb_pitch(); + u32 h = get_fb_height(); + + if (!fb) return -1; + + size_t fb_size = (size_t)pitch * h; + + // EOF + if (fb_read_pos >= fb_size) return 0; + + size_t remaining = fb_size - fb_read_pos; + if (count > remaining) count = remaining; + + memcpy(buf, (u8 *)fb + fb_read_pos, count); + fb_read_pos += count; + return (int)count; +} + +static int fb0_write(void *handle, const void *buf, size_t count, u64 offset) { + (void)handle; + (void)offset; + u32 *fb = get_framebuffer(); + u32 pitch = get_fb_pitch(); + u32 h = get_fb_height(); + + if (!fb) return -1; + + size_t fb_size = (size_t)pitch * h; + + // wrap around if we're on end + if (fb_write_pos >= fb_size) fb_write_pos = 0; + + size_t remaining = fb_size - fb_write_pos; + if (count > remaining) count = remaining; + + memcpy((u8 *)fb + fb_write_pos, buf, count); + fb_write_pos += count; + return (int)count; +} + +int fb0_ioctl(int request, void *arg) { + if (!arg) return -1; + + u32 w = get_fb_width(); + u32 h = get_fb_height(); + u32 pitch = get_fb_pitch(); + u32 *fb = get_framebuffer(); + + switch (request) { + case FBIOGET_VSCREENINFO: { + fb_var_screeninfo_t *info = (fb_var_screeninfo_t *)arg; + info->xres = w; + info->yres = h; + info->xres_virtual = w; + info->yres_virtual = h; + info->xoffset = 0; + info->yoffset = 0; + info->bits_per_pixel = 32; + info->grayscale = 0; + info->blue_offset = 0; info->blue_length = 8; + info->green_offset = 8; info->green_length = 8; + info->red_offset = 16; info->red_length = 8; + info->transp_offset = 24; info->transp_length = 8; + return 0; + } + case FBIOGET_FSCREENINFO: { + fb_fix_screeninfo_t *fix = (fb_fix_screeninfo_t *)arg; + str_copy(fix->id, FBN); + fix->smem_start = (u64)fb; + fix->smem_len = pitch * h; + fix->type = 0; // FB_TYPE_PACKED_PIXELS + fix->visual = 2; // FB_VISUAL_TRUECOLOR + fix->line_length = pitch; + return 0; + } + case FBIO_READ_RECT: { + fb_rect_t *r = (fb_rect_t *)arg; + if (!r || !r->pixels) return -1; + u32 pitch_dw = pitch / 4; + for (u32 row = 0; row < r->h; row++) { + u32 py = r->y + row; + if (py >= h) break; + for (u32 col = 0; col < r->w; col++) { + u32 px = r->x + col; + r->pixels[row * r->w + col] = (px < w) ? fb[py * pitch_dw + px] : 0; + } + } + return 0; + } + case FBIO_BLIT: { + fb_rect_t *r = (fb_rect_t *)arg; + if (!r || !r->pixels) return -1; + u32 pitch_dw = pitch / 4; + for (u32 row = 0; row < r->h; row++) { + u32 py = r->y + row; + if (py >= h) break; + for (u32 col = 0; col < r->w; col++) { + u32 px = r->x + col; + if (px >= w) break; + u32 c = r->pixels[row * r->w + col]; + if ((c >> 24) == 0) continue; // transparent + fb[py * pitch_dw + px] = c; + } + } + return 0; + } + case FBIO_RESET_POS: + fb_write_pos = 0; + return 0; + default: + return -1; + } +} + +driver_module fb0_module = { + .name = FB0NAME, + .mount = FB0PATH, + .version = FB0UNIVERSAL, + .init = fb0_mod_init, + .fini = fb0_mod_fini, + .open = fb0_open, + .read = fb0_read, + .write = fb0_write, +}; \ No newline at end of file diff --git a/src/kernel/devices/fb0/fb0.h b/src/kernel/devices/fb0/fb0.h new file mode 100644 index 0000000..186ae16 --- /dev/null +++ b/src/kernel/devices/fb0/fb0.h @@ -0,0 +1,58 @@ +#ifndef DEVICE_FB0_H +#define DEVICE_FB0_H + +#include +#include + +#include + +#define FBN EMEX "fb0" + +// fb_var_screeninfo +typedef struct { + u32 xres; + u32 yres; + u32 xres_virtual; + u32 yres_virtual; + u32 xoffset; + u32 yoffset; + u32 bits_per_pixel; + u32 grayscale; + u32 red_offset; + u32 red_length; + u32 green_offset; + u32 green_length; + u32 blue_offset; + u32 blue_length; + u32 transp_offset; + u32 transp_length; +} fb_var_screeninfo_t; +typedef struct { + char id[16]; + u64 smem_start; + u32 smem_len; + u32 type; + u32 visual; + u32 line_length; // pitch +} fb_fix_screeninfo_t; + +// /dev/fb0 request codes +#define FBIOGET_VSCREENINFO 0x4600 +#define FBIOPUT_VSCREENINFO 0x4601 +#define FBIOGET_FSCREENINFO 0x4602 +#define FBIO_RESET_POS 0x4603 +#define FBIO_READ_RECT 0x4610 +#define FBIO_BLIT 0x4611 + +typedef struct { + u32 x, y, w, h; + u32 *pixels; +} fb_rect_t; + +// /dev/fb0 module +extern driver_module fb0_module; + + +int fb0_ioctl(int request, void *arg); + +#endif \ No newline at end of file diff --git a/src/kernel/devices/input/kbd.c b/src/kernel/devices/input/kbd.c new file mode 100644 index 0000000..2f5037f --- /dev/null +++ b/src/kernel/devices/input/kbd.c @@ -0,0 +1,67 @@ +#include "kbd.h" + +#include +#include +#include +#include +#include + +#include + +static int kbd_dev_init(void) { + log("[KBD]", "init /dev/input/keyboard0\n", d); + // keyboard_module is gone... + keyboard_init(); + return 0; +} + +static void kbd_dev_fini(void) { + irq_unregister_handler(1); +} +static void *kbd_dev_open(const char *path) { + (void)path; + return (void *)1; // dummy handle +} + +static int kbd_dev_read(void *handle, void *buf, size_t count, u64 offset) { + (void)handle; + (void)offset; + + size_t ev_size = sizeof(key_event_t); + size_t written = 0; + u8 *out = (u8 *)buf; + + // drain as many events as fit in buf + while (written + ev_size <= count && keyboard_has_key()) { + key_event_t ev; + if (keyboard_get_event(&ev)) { + u8 *src = (u8 *)&ev; + for (size_t i = 0; i < ev_size; i++) { + out[written + i] = src[i]; + } + written += ev_size; + } + } + + return (int)written; +} + +// there is no write for input devices +static int kbd_dev_write(void *handle, const void *buf, size_t count, u64 offset) { + (void)handle; + (void)buf; + (void)count; + (void)offset; + return -1; +} + +driver_module kbd_dev_module = { + .name = KBDNAME, + .mount = KBDPATH, + .version = KBDUNIVERSAL, + .init = kbd_dev_init, + .fini = kbd_dev_fini, + .open = kbd_dev_open, + .read = kbd_dev_read, + .write = kbd_dev_write, +}; \ No newline at end of file diff --git a/src/kernel/devices/input/kbd.h b/src/kernel/devices/input/kbd.h new file mode 100644 index 0000000..76ee2d7 --- /dev/null +++ b/src/kernel/devices/input/kbd.h @@ -0,0 +1,8 @@ +#ifndef DEVICE_KBD_H +#define DEVICE_KBD_H + +#include + +extern driver_module kbd_dev_module; + +#endif \ No newline at end of file diff --git a/src/kernel/devices/input/mouse0.c b/src/kernel/devices/input/mouse0.c new file mode 100644 index 0000000..67366fd --- /dev/null +++ b/src/kernel/devices/input/mouse0.c @@ -0,0 +1,49 @@ +#include "mouse0.h" +#include +#include +#include +#include +#include +#include + +static int mouse0_init(void) { + log("[MOUSE]", "init /dev/input/mouse0\n", d); + mouse_init(); + return 0; +} +static void mouse0_fini(void){ + irq_unregister_handler(12); +} +static void *mouse0_open(const char *p){ + (void)p; return (void *)1; +} +static int mouse0_write(void *h, const void *b, size_t c, u64 o){ + (void)h;(void)b;(void)c;(void)o; return -1; +} + +static int mouse0_read(void *handle, void *buf, size_t count, u64 offset) { + (void)handle; (void)offset; + size_t esz = sizeof(mouse_event_t); + size_t written = 0; + u8 *out = (u8 *)buf; + while (written + esz <= count && mouse_has_event()) { + mouse_event_t ev; + if (mouse_get_event(&ev)) { + u8 *src = (u8 *)&ev; + for (size_t i = 0; i < esz; i++) out[written + i] = src[i]; + written += esz; + } + } + return (int)written; +} + +driver_module mouse0_module = { + .name = MS0NAME, + .mount = MS0PATH, + .version = MS0UNIVERSAL, + .init = mouse0_init, + .fini = mouse0_fini, + .open = mouse0_open, + .read = mouse0_read, + .write = mouse0_write, +}; \ No newline at end of file diff --git a/src/kernel/devices/input/mouse0.h b/src/kernel/devices/input/mouse0.h new file mode 100644 index 0000000..17356e4 --- /dev/null +++ b/src/kernel/devices/input/mouse0.h @@ -0,0 +1,9 @@ +#ifndef DEVICE_MOUSE0_H +#define DEVICE_MOUSE0_H + +#include + +// /dev/input/mouse0 +extern driver_module mouse0_module; + +#endif \ No newline at end of file diff --git a/src/kernel/devices/null/null.c b/src/kernel/devices/null/null.c new file mode 100644 index 0000000..91ff4a9 --- /dev/null +++ b/src/kernel/devices/null/null.c @@ -0,0 +1,38 @@ +#include "null.h" +#include +#include +#include +#include + +static int null_mod_init(void) { + log("[NULL]", "init /dev/null\n", d); + return 0; +} + +static void null_mod_fini(void) {} + +static void *null_open(const char *path) { + (void)path; + return (void *)1; +} + +static int null_read(void *handle, void *buf, size_t count, u64 offset) { + (void)handle; (void)buf; (void)count; (void)offset; + // eof + return 0; +} +static int null_write(void *handle, const void *buf, size_t count, u64 offset) { + (void)handle; (void)buf; (void)offset; + return (int)count; +} + +driver_module null_module = { + .name = NULNAME, + .mount = NULPATH, + .version = NULUNIVERSAL, + .init = null_mod_init, + .fini = null_mod_fini, + .open = null_open, + .read = null_read, + .write = null_write, +}; \ No newline at end of file diff --git a/src/kernel/devices/null/null.h b/src/kernel/devices/null/null.h new file mode 100644 index 0000000..fd9b270 --- /dev/null +++ b/src/kernel/devices/null/null.h @@ -0,0 +1,9 @@ +#ifndef DEVICE_NULL_H +#define DEVICE_NULL_H + +#include + +// /dev/null device module +extern driver_module null_module; + +#endif \ No newline at end of file diff --git a/src/kernel/devices/random/random.c b/src/kernel/devices/random/random.c new file mode 100644 index 0000000..60564b0 --- /dev/null +++ b/src/kernel/devices/random/random.c @@ -0,0 +1,29 @@ +#include "random.h" +#include "urandom.h" +#include +#include +#include +#include + +// +// for now random is just a alias from urandom +// cuz a real random would be way harder +// + +static int random_init(void) { + log("[RAND]", "init /dev/random (alias of urandom)\n", d); + return 0; +} + +static void random_fini(void) {} + +driver_module random_module = { + .name = RNDNAME, + .mount = RNDPATH, + .version = RNDUNIVERSAL, + .init = random_init, + .fini = random_fini, + .open = urandom_open_fn, + .read = urandom_read_fn, + .write = urandom_write_fn, +}; \ No newline at end of file diff --git a/src/kernel/devices/random/random.h b/src/kernel/devices/random/random.h new file mode 100644 index 0000000..467e8c7 --- /dev/null +++ b/src/kernel/devices/random/random.h @@ -0,0 +1,9 @@ +#ifndef DEVICE_RANDOM_H +#define DEVICE_RANDOM_H + +#include + +// /dev/random +extern driver_module random_module; + +#endif \ No newline at end of file diff --git a/src/kernel/devices/random/urandom.c b/src/kernel/devices/random/urandom.c new file mode 100644 index 0000000..89dc37c --- /dev/null +++ b/src/kernel/devices/random/urandom.c @@ -0,0 +1,98 @@ +#include "urandom.h" + +#include +#include +#include +#include +#include + +// +// Xorshift64 PRNG +// + +static u64 xr_state = 0; // 0 means "not seeded yet" + +static inline u64 rdtsc(void) { + u32 lo, hi; + __asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi)); + return ((u64)hi << 32) | lo; +} + +static u64 xorshift64(void) { + //https://en.wikipedia.org/wiki/Xorshift + // https://github.com/jj1bdx/xorshiftplus-c/blob/master/xorshift64star.c + if (xr_state == 0) { + xr_state = rdtsc(); + if (xr_state == 0) xr_state = 0xDEADBEEFCAFEBABEULL; // fallback + } + u64 x = xr_state; + x ^= x << 13; + x ^= x >> 7; + x ^= x << 17; + xr_state = x; + return x; +} + +static int urandom_init(void) { + log("[URND]", "init /dev/urandom\n", d); + // pre-seed from RDTSC so state is ready + xr_state = rdtsc(); + if (xr_state == 0) xr_state = 0xDEADBEEFCAFEBABEULL; + return 0; +} + +static void urandom_fini(void) {} + +// /dev/random will just alias those next 3 +void *urandom_open_fn(const char *path) { + (void)path; + return (void *)1; +} + +int urandom_read_fn(void *handle, void *buf, size_t count, u64 offset) { + (void)handle; + (void)offset; + u8 *out = (u8 *)buf; + size_t i = 0; + + // fill 8 bytes at a time then handle tail + while (i + 8 <= count) { + u64 r = xorshift64(); + out[i+0] = (u8)(r); + out[i+1] = (u8)(r >> 8); + out[i+2] = (u8)(r >> 16); + out[i+3] = (u8)(r >> 24); + out[i+4] = (u8)(r >> 32); + out[i+5] = (u8)(r >> 40); + out[i+6] = (u8)(r >> 48); + out[i+7] = (u8)(r >> 56); + i += 8; + } + if (i < count) { + u64 r = xorshift64(); + while (i < count) { + out[i++] = (u8)(r & 0xFF); + r >>= 8; + } + } + return (int)count; +} + +int urandom_write_fn(void *handle, const void *buf, size_t count, u64 offset) { + // accept writes mb for future + (void)handle; + (void)buf; + (void)offset; + return (int)count; +} + +driver_module urandom_module = { + .name = URNDNAME, + .mount = URNDPATH, + .version = URNDUNIVERSAL, + .init = urandom_init, + .fini = urandom_fini, + .open = urandom_open_fn, + .read = urandom_read_fn, + .write = urandom_write_fn, +}; \ No newline at end of file diff --git a/src/kernel/devices/random/urandom.h b/src/kernel/devices/random/urandom.h new file mode 100644 index 0000000..e4d06e8 --- /dev/null +++ b/src/kernel/devices/random/urandom.h @@ -0,0 +1,14 @@ +#ifndef DEVICE_URANDOM_H +#define DEVICE_URANDOM_H + +#include + +// /dev/urandom +extern driver_module urandom_module; + +// shared with /dev/random alias +void *urandom_open_fn(const char *path); +int urandom_read_fn(void *handle, void *buf, size_t count, u64 offset); +int urandom_write_fn(void *handle, const void *buf, size_t count, u64 offset); + +#endif \ No newline at end of file diff --git a/src/kernel/devices/tty/tty0.c b/src/kernel/devices/tty/tty0.c new file mode 100644 index 0000000..8e8448e --- /dev/null +++ b/src/kernel/devices/tty/tty0.c @@ -0,0 +1,222 @@ +#include "tty0.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef enum { + ANSI_NORMAL = 0, + ANSI_ESC, // got \033 + ANSI_CSI, // got \033[ +} tty0_ansi_state_t; + +static tty0_ansi_state_t ansi_state = ANSI_NORMAL; +static int ansi_param = 0; +static u32 ansi_fg = 0xFFFFFFFF; // default white +static u32 ansi_bg = 0xFF000000; + +static u32 tty0_ansi_color(int code) { + switch (code) { + case 0: return 0xFFFFFFFF; // reset + case 30: return 0xFF111111; // black + case 31: return 0xFFFF5555; // red + case 32: return 0xFF55FF55; // green + case 33: return 0xFFFFFF55; // yellow + case 34: return 0xFF5555FF; // blue + case 35: return 0xFFFF55FF; // magenta + case 36: return 0xFF55FFFF; // cyan + case 37: return 0xFFFFFFFF; // white + case 90: return 0xFF888888; // bright black/gray + case 91: return 0xFFFF8888; // bright red + case 92: return 0xFF88FF88; // bright green + case 93: return 0xFFFFFF88; // bright yellow + case 94: return 0xFF8888FF; // bright blue + case 95: return 0xFFFF88FF; // bright magenta + case 96: return 0xFF88FFFF; // bright cyan + case 97: return 0xFFFFFFFF; // bright white + default: return 0xFFFFFFFF; + } +} + +void tty0_write_char(char c) { + char tmp[2] = { c, '\0' }; + switch (ansi_state) { + case ANSI_NORMAL: + if (c == '\033') { + ansi_state = ANSI_ESC; + } else if (c == '\b') { + u32 char_width = fm_get_char_width() * font_scale; + u32 char_height = fm_get_char_height() * font_scale; + if (cursor_x >= char_width) { + cursor_x -= char_width; + draw_rect(cursor_x, cursor_y, char_width, char_height, ansi_bg); + // later the window-system/desktop-environment should handle that + } + } else { + cprintf(tmp, ansi_fg); + } + break; + + case ANSI_ESC: + if (c == '[') { + ansi_state = ANSI_CSI; + ansi_param = 0; + } else { + cprintf("\033", ansi_fg); + cprintf(tmp, ansi_fg); + ansi_state = ANSI_NORMAL; + } + break; + + case ANSI_CSI: + if (c >= '0' && c <= '9') { + ansi_param = ansi_param * 10 + (c - '0'); + } else if (c == 'm') { + ansi_fg = tty0_ansi_color(ansi_param); + ansi_param = 0; + ansi_state = ANSI_NORMAL; + } else if (c == ';') { + ansi_fg = tty0_ansi_color(ansi_param); + ansi_param = 0; + // stay in CSI + } else { + ansi_param = 0; + ansi_state = ANSI_NORMAL; + } + break; + } +} + + +static int tty0_echo_mode = TTY_ECHO; // default == 0 + +void tty0_set_echo_mode(int mode) { tty0_echo_mode = mode; } +int tty0_get_echo_mode(void) { return tty0_echo_mode; } + +static int tty0_init(void) { + log("[TTY0]", "init /dev/tty0\n", d); + return 0; +} + +static void tty0_fini(void) {} + +static void *tty0_open(const char *path) { + (void)path; + return (void *)1; // dummy handle +} + +static int tty0_dev_write(void *handle, const void *buf, size_t count, u64 offset) { + (void)handle; + (void)offset; + const char *p = (const char *)buf; + for (size_t i = 0; i < count; i++) { + tty0_write_char(p[i]); + } + return (int)count; +} +static int tty0_dev_read(void *handle, void *buf, size_t count, u64 offset) { + (void)handle; + (void)offset; + if (!buf || count == 0) return 0; + + char *out = (char *)buf; + size_t i = 0; + + // lazyopen keyboard device fd once + static int kbd_fd = -1; + if (kbd_fd < 0) { + kbd_fd = fs_open(KEYBOARD0, O_RDONLY); + if (kbd_fd < 0) { + printf("[TTY0] read: cannot open " KEYBOARD0 "\n"); + return -1; + } + } + + __asm__ volatile("sti"); + + if (tty0_echo_mode == TTY_RAW) { + while (1) { + key_event_t event; + char c = (char)(event.keycode & 0xFF); + int n = fs_read(kbd_fd, &event, sizeof(key_event_t)); + + __asm__ volatile("hlt"); + if (n != (int)sizeof(key_event_t)) continue; + if (!event.pressed) continue; + if (event.keycode == 0x09) c = '\t'; + if (c == '\n' || c == '\r' || c == '\b' || c == '\t' || + (c >= 0x20 && c <= 0x7E)) { + out[0] = (c == '\r') ? '\n' : c; + + __asm__ volatile("cli"); + return 1; + } + } + } + + while (i < count - 1) { + key_event_t event; + int got = 0; + + while (!got) { + __asm__ volatile("hlt"); + int n = fs_read(kbd_fd, &event, sizeof(key_event_t)); + if (n == (int)sizeof(key_event_t)) got = 1; + } + + if (!event.pressed) continue; + + char c = (char)(event.keycode & 0xFF); + + if (c == '\n' || c == '\r') { + // always echo the newline so cursor moves to next line + tty0_write_char('\n'); + out[i++] = '\n'; + break; + } + + if (c == '\b') { + if (i > 0) { + i--; + if (tty0_echo_mode != TTY_NOECHO) + tty0_write_char('\b'); + } + continue; + } + + if (c < 0x20 || c > 0x7E) continue; + + // echo based on current mode + if (tty0_echo_mode == TTY_ECHO) + tty0_write_char(c); + else if (tty0_echo_mode == TTY_MASKECHO) + tty0_write_char('*'); + // TTY_NOECHO == no output at all + + out[i++] = c; + } + + __asm__ volatile("cli"); + + out[i] = '\0'; + return (int)i; +} + +driver_module tty0_module = { + .name = TTY0NAME, + .mount = TTY0PATH, + .version = TTY0UNIVERSAL, + .init = tty0_init, + .fini = tty0_fini, + .open = tty0_open, + .read = tty0_dev_read, + .write = tty0_dev_write, +}; \ No newline at end of file diff --git a/src/kernel/devices/tty/tty0.h b/src/kernel/devices/tty/tty0.h new file mode 100644 index 0000000..19a0378 --- /dev/null +++ b/src/kernel/devices/tty/tty0.h @@ -0,0 +1,23 @@ +#ifndef DEVICE_TTY0_H +#define DEVICE_TTY0_H + +#include + +#define KEYBOARD0 KBDPATH +//#define MOUSE0 MS0PATH + + +extern driver_module tty0_module; + +// ioctl request codes for tty +#define TTY_ECHO 0 // normal echo +#define TTY_NOECHO 1 // no echo at all +#define TTY_MASKECHO 2 +#define TTY_RAW 3 + + +void tty0_write_char(char c); +void tty0_set_echo_mode(int mode); +int tty0_get_echo_mode(void); + +#endif \ No newline at end of file diff --git a/src/kernel/devices/zero/zero.c b/src/kernel/devices/zero/zero.c new file mode 100644 index 0000000..c3d5b45 --- /dev/null +++ b/src/kernel/devices/zero/zero.c @@ -0,0 +1,48 @@ +#include "zero.h" +#include +#include +#include +#include +#include + +#include + +static int zero_mod_init(void) { + log("[ZERO]", "init /dev/zero\n", d); + return 0; +} + +static void zero_mod_fini(void) {} + +static void *zero_open(const char *path) { + (void)path; + return (void *)1; +} + +// write buffer full with 0s +static int zero_read(void *handle, void *buf, size_t count, u64 offset) { + (void)handle; + (void)offset; + if (buf && count > 0) { + memset(buf, 0, count); + } + return (int)count; +} + +static int zero_write(void *handle, const void *buf, size_t count, u64 offset) { + (void)handle; + (void)buf; + (void)offset; + return (int)count; +} + +driver_module zero_module = { + .name = ZERNAME, + .mount = ZERPATH, + .version = ZERUNIVERSAL, + .init = zero_mod_init, + .fini = zero_mod_fini, + .open = zero_open, + .read = zero_read, + .write = zero_write, +}; \ No newline at end of file diff --git a/src/kernel/devices/zero/zero.h b/src/kernel/devices/zero/zero.h new file mode 100644 index 0000000..7177c4e --- /dev/null +++ b/src/kernel/devices/zero/zero.h @@ -0,0 +1,9 @@ +#ifndef DEVICE_ZERO_H +#define DEVICE_ZERO_H + +#include + +// /dev/zero device module +extern driver_module zero_module; + +#endif \ No newline at end of file diff --git a/src/kernel/file_systems/fat32/fat32.c b/src/kernel/file_systems/fat32/fat32.c index 8fd347d..e2c1ec5 100644 --- a/src/kernel/file_systems/fat32/fat32.c +++ b/src/kernel/file_systems/fat32/fat32.c @@ -461,7 +461,7 @@ int fat32_read(file_t* this_file, void* buffer, size_t size) uint32_t skipped_clusters = (uint32_t)(this_file->readPos / (bootSector.sectors_per_cluster * bootSector.bytes_per_sector)); - for(int i = 0; i < skipped_clusters; i++) + for(uint32_t i = 0; i < skipped_clusters; i++) current_cluster = get_next_cluster(current_cluster); uint32_t offset = this_file->readPos - @@ -512,4 +512,4 @@ int fat32_test_write(void) { log("[FAT32]", "finish\n", success); return 0; -} +} \ No newline at end of file diff --git a/src/kernel/file_systems/vfs/devfs/devfs.c b/src/kernel/file_systems/vfs/devfs/devfs.c index f84ea3d..6c185a1 100644 --- a/src/kernel/file_systems/vfs/devfs/devfs.c +++ b/src/kernel/file_systems/vfs/devfs/devfs.c @@ -32,14 +32,18 @@ static ssize_t devfs_read(fs_file *file, void *buf, size_t cnt) { devfs_data *dev = (devfs_data*)file->node->priv; if (!dev || !dev->mod || !dev->mod->read) return -1; - return dev->mod->read(dev->handle, buf, cnt); + ssize_t n = dev->mod->read(dev->handle, buf, cnt, file->pos); + if (n > 0) file->pos += (u64)n; + return n; } static ssize_t devfs_write(fs_file *file, const void *buf, size_t cnt) { devfs_data *dev = (devfs_data*)file->node->priv; if (!dev || !dev->mod || !dev->mod->write) return -1; - return dev->mod->write(dev->handle, buf, cnt); + ssize_t n = dev->mod->write(dev->handle, buf, cnt, file->pos); + if (n > 0) file->pos += (u64)n; + return n; } static fs_node* devfs_lookup(fs_node *dir, const char *name) { @@ -56,14 +60,27 @@ static fs_node* devfs_lookup(fs_node *dir, const char *name) { return NULL; } +// create a subdir inside a devfs dir (like /dev/input and so on) +static int devfs_mkdir_node(fs_node *dir, const char *name) { + fs_node *sub = fs_mknode(name, FS_DIR); + if (!dir || !name) return -1; + if (devfs_lookup(dir, name)) return 0; + if (!sub) return -1; + + sub->ops = dir->ops; // inherit devfs ops + fs_addchild(dir, sub); + + return 0; +} + static fs_ops devfs_ops = { - .open = devfs_open, - .close = devfs_close, - .read = devfs_read, - .write = devfs_write, + .open = devfs_open, + .close = devfs_close, + .read = devfs_read, + .write = devfs_write, .lookup = devfs_lookup, .create = NULL, - .mkdir = NULL, + .mkdir = devfs_mkdir_node, }; static int devfs_mount(const char *src, const char *tgt, fs_mnt *mnt) { @@ -95,12 +112,14 @@ void devfs_register(void) { //cannot be alone standing // register a device driver module to devfs +// "/dev/input/keyboard0" creates input/ subdir automatically int devfs_register_device(driver_module *mod) { if (!mod || !devfs_root) return -1; // extract device name from mount path // "/dev/console" -> "console" + // "/dev/input/keyboard0" -> "input/keyboard0" const char *path = mod->mount; const char *name = path; @@ -108,8 +127,38 @@ int devfs_register_device(driver_module *mod) name = path + 5; // skip "/dev/" } - // check if already exists - if (devfs_lookup(devfs_root, name)) { + // check if there is a subdir + const char *slash = NULL; + for (const char *p = name; *p; p++) { + if (*p == '/') { slash = p; break; } + } + + fs_node *parent = devfs_root; + + if (slash) { + // extract subdir name ("input") + char subdir[64]; + int slen = slash - name; + if (slen <= 0 || slen >= 64) return -1; + + for (int i = 0; i < slen; i++) subdir[i] = name[i]; + subdir[slen] = '\0'; + + // find or create the subdir inside devfs root + fs_node *sub = devfs_lookup(devfs_root, subdir); + if (!sub) { + sub = fs_mknode(subdir, FS_DIR); + if (!sub) return -1; + sub->ops = &devfs_ops; + fs_addchild(devfs_root, sub); + } + + parent = sub; + name = slash + 1; // device name after the slash + } + + // check if already exists in target parent + if (devfs_lookup(parent, name)) { return -1; } @@ -128,13 +177,13 @@ int devfs_register_device(driver_module *mod) data->handle = NULL; node->priv = data; - node->ops = &devfs_ops; + node->ops = &devfs_ops; - fs_addchild(devfs_root, node); + fs_addchild(parent, node); log("[DEVFS]", "registered ", d); - BOOTUP_PRINT(name,white()); - BOOTUP_PRINT("\n",white()); + BOOTUP_PRINT(mod->mount, white()); + BOOTUP_PRINT("\n", white()); return 0; -} +} \ No newline at end of file diff --git a/src/kernel/file_systems/vfs/procfs/procfs.c b/src/kernel/file_systems/vfs/procfs/procfs.c new file mode 100644 index 0000000..a703251 --- /dev/null +++ b/src/kernel/file_systems/vfs/procfs/procfs.c @@ -0,0 +1,344 @@ +#include "../vfs.h" +#include "procfs.h" +#include +#include +#include +#include +#include +#include +#include + +// +// procfs: +// layout: +// /proc//status +// /proc//maps +// + +#if ENABLE_ULIME +extern ulime_t *ulime; +#endif + +#define STATUS_MSG "status" +#define MAPS_MSG "maps" + +static fs_node *procfs_root = NULL; // nothings mounted on start + +// +// helpers +// + +// convert a decimal string to u64 +static u64 procfs_atopid(const char *s) { + if (!s || *s == '\0') return 0; + u64 n = 0; + const char *p = s; + while (*p >= '0' && *p <= '9') { + n = n * 10 + (u64)(*p - '0'); + p++; + } + // must consume the whole string + if (*p != '\0') return 0; + if (p == s) return 0; + + return n; +} +static ulime_proc_t *procfs_find_pid(u64 pid) { + #if ENABLE_ULIME + if (!ulime) return NULL; + ulime_proc_t *proc = ulime->ptr_proc_list; + while (proc) { + if (proc->pid == pid) return proc; + proc = proc->next; + } + #else + (void)pid; + #endif + return NULL; +} +static const char *procfs_state_str(u64 state) { + // same as ulime procs + switch (state) { + case PROC_CREATED: return "CREATED"; + case PROC_READY: return "READY"; + case PROC_RUNNING: return "RUNNING"; + case PROC_BLOCKED: return "BLOCKED"; + case PROC_ZOMBIE: return "ZOMBIE"; + default: return "UNKNOWN"; + } +} +static char *procfs_gen_status(ulime_proc_t *proc, u64 *out_len) +{ + char *buf = (char *)klime_create((klime_t *)fs_klime, 256); + char tmp[32]; + if (!buf) return NULL; + + str_copy(buf, "name: "); + str_append(buf,(char *)proc->name); + str_append(buf,"\n"); + str_append(buf,"pid: "); + tmp[0] = '\0'; + str_append_uint(tmp, (u32)proc->pid); + str_append(buf, tmp); + str_append(buf, "\n"); + str_append(buf,"state: "); + str_append(buf,procfs_state_str(proc->state)); + str_append(buf,"\n"); + str_append(buf,"priority: "); + tmp[0] = '\0'; + str_append_uint(tmp, (u32)proc->priority); + str_append(buf,tmp); + str_append(buf,"\n"); + + *out_len = (u64)str_len(buf); + return buf; +} +static char *procfs_gen_maps(ulime_proc_t *proc, u64 *out_len) +{ + char *buf = (char *)klime_create((klime_t *)fs_klime, 256); + char tmp[32]; + if (!buf) return NULL; + + str_copy(buf, "heap: 0x"); + str_from_hex(tmp, proc->heap_base); + str_append(buf,tmp); + str_append(buf," size: "); + tmp[0] = '\0'; + str_append_uint(tmp, (u32)proc->heap_size); + str_append(buf,tmp); + str_append(buf,"\n"); + str_append(buf,"stack: 0x"); + str_from_hex(tmp, proc->stack_base); + str_append(buf, tmp); + str_append(buf," size: "); + tmp[0] = '\0'; + str_append_uint(tmp, (u32)proc->stack_size); + str_append(buf,tmp); + str_append(buf,"\n"); + + *out_len = (u64)str_len(buf); + return buf; +} +static fs_node *procfs_mknode(const char *name, u8 type, u64 pid, u8 kind) +{ + fs_node *node = fs_mknode(name, type); + if (!node) return NULL; + + procfs_data *data = (procfs_data *)klime_create((klime_t *)fs_klime, sizeof(procfs_data)); + if (!data) return NULL; + + data->pid = pid; + data->kind = kind; + data->buf = NULL; + data->len = 0; + + node->priv = data; + return node; +} + +// ops + + +static int procfs_open(fs_node *node, fs_file *file) +{ + procfs_data *data = (procfs_data *)node->priv; + if (!data) return -1; + + (void)file; + + // generate content for file nodes on open + if (data->kind == PROCFS_KIND_STATUS || data->kind == PROCFS_KIND_MAPS) { + #if ENABLE_ULIME // why did i just make this enable_ulime... + // the problem it would take days to remove it its toooo deep in the system... + ulime_proc_t *proc = procfs_find_pid(data->pid); + if (!proc) return -1; + + if (data->kind == PROCFS_KIND_STATUS) { + data->buf = procfs_gen_status(proc, &data->len); + } else { + data->buf = procfs_gen_maps(proc, &data->len); + } + + if (!data->buf) return -1; + #else + data->buf = (char *)klime_create((klime_t *)fs_klime, 32); + if (!data->buf) return -1; + str_copy(data->buf, "ulime disabled\n"); + data->len = (u64)str_len(data->buf); + #endif + } + + return 0; +} + +static int procfs_close(fs_file *file) {(void)file; return 0;} + +static ssize_t procfs_read(fs_file *file, void *buf, size_t cnt) +{ + fs_node *node = file->node; + procfs_data *data = (procfs_data *)node->priv; + + // if dirs are not readable + if (!data || data->kind == PROCFS_KIND_ROOT || data->kind == PROCFS_KIND_DIR) return -1; + if (!data->buf) return 0; + + // eof + if (file->pos >= data->len) return 0; + + size_t to_read = cnt; + if (file->pos + to_read > data->len) { + to_read = data->len - file->pos; + } + + memcpy(buf, data->buf + file->pos, to_read); + file->pos += to_read; + + return (ssize_t)to_read; +} +static ssize_t procfs_write(fs_file *file, const void *buf, size_t cnt) { + { + (void)file;(void)buf;(void)cnt; + } + return -1; +} +static fs_node *procfs_lookup(fs_node *dir, const char *name) +{ + if (dir->type != FS_DIR) return NULL; + + procfs_data *data = (procfs_data *)dir->priv; + if (!data) return NULL; + + if (data->kind == PROCFS_KIND_ROOT) { + // /proc/ lookup - name must be a decimal pid + u64 pid = procfs_atopid(name); + if (pid == 0) return NULL; + + // check the process actually exists + if (!procfs_find_pid(pid)) return NULL; + + // build pid dir node + fs_node *piddir = procfs_mknode(name, FS_DIR, pid, PROCFS_KIND_DIR); + if (!piddir) return NULL; + + piddir->ops = dir->ops; + return piddir; + } + + if (data->kind == PROCFS_KIND_DIR) + { + // /proc//status or /proc//maps + u8 kind = 0; + if (str_equals(name, STATUS_MSG)) { + kind = PROCFS_KIND_STATUS; + } else if (str_equals(name, MAPS_MSG)) { + kind = PROCFS_KIND_MAPS; + } else { + return NULL; + } + + fs_node *fnode = procfs_mknode(name, FS_FILE, data->pid, kind); + if (!fnode) return NULL; + + fnode->ops = dir->ops; + return fnode; + } + + return NULL; +} +static fs_ops procfs_ops; +static fs_node* procfs_readdir(fs_node *dir) { + //(void)dir; + + if (!dir || !dir->priv) return NULL; + procfs_data *data = (procfs_data *)dir->priv; + + #if ENABLE_ULIME + if (data->kind == PROCFS_KIND_ROOT) + { + if (!ulime) return NULL; + + fs_node *head = NULL; + fs_node *tail = NULL; + ulime_proc_t *proc = ulime->ptr_proc_list; + + while (proc) + { + char pidstr[24]; + u64 pid = proc->pid; + int ti = 0; + char tmp[24]; + + if (pid == 0) { pidstr[0] = '0'; pidstr[1] = '\0'; } + else { + while (pid > 0) { tmp[ti++] = '0' + (int)(pid % 10); pid /= 10; } + for (int i = 0; i < ti; i++) pidstr[i] = tmp[ti - 1 - i]; + pidstr[ti] = '\0'; + } + + fs_node *n = procfs_mknode(pidstr, FS_DIR, proc->pid, PROCFS_KIND_DIR); + + if (n) { + n->ops = &procfs_ops; + if (!head) head = n; + else tail->next = n; + tail = n; + } + proc = proc->next; + } + return head; + } + if (data->kind == PROCFS_KIND_DIR) { + fs_node *status = procfs_mknode(STATUS_MSG, FS_FILE, data->pid, PROCFS_KIND_STATUS); + fs_node *maps = procfs_mknode(MAPS_MSG, FS_FILE, data->pid, PROCFS_KIND_MAPS); + + if (status) status->ops = &procfs_ops; + if (maps) maps->ops = &procfs_ops; + if (status && maps) status->next = maps; + + return status ? status : maps; + } + #endif + + return NULL; +} + +static fs_ops procfs_ops = { + .open = procfs_open, + .close = procfs_close, + .read = procfs_read, + .write = procfs_write, + .lookup = procfs_lookup, + .create = NULL, + .mkdir = NULL, + .readdir = procfs_readdir, +}; + +// +// mount +// + +static int procfs_mount(const char *src, const char *tgt, fs_mnt *mnt) { + { + (void)src;(void)tgt; + } + + fs_node *root = procfs_mknode("proc", FS_DIR, 0, PROCFS_KIND_ROOT); + if (!root) return -1; + + root->ops = &procfs_ops; + mnt->root = root; + procfs_root = root; + + return 0; +} + +static fs_type procfs = { + .name = "procfs", + .mount = procfs_mount, + .ops = &procfs_ops, +}; + +// register procfs type +void procfs_register(void) { + fs_register(&procfs); +} \ No newline at end of file diff --git a/src/kernel/file_systems/vfs/procfs/procfs.h b/src/kernel/file_systems/vfs/procfs/procfs.h new file mode 100644 index 0000000..ae061be --- /dev/null +++ b/src/kernel/file_systems/vfs/procfs/procfs.h @@ -0,0 +1,22 @@ +#ifndef PROCFS_H +#define PROCFS_H + +#include + +// node kinds stored in procfs_data.kind +#define PROCFS_KIND_ROOT 0 // /proc itself +#define PROCFS_KIND_DIR 1 // /proc/ +#define PROCFS_KIND_STATUS 2 // /proc//status +#define PROCFS_KIND_MAPS 3 // /proc//maps + +// stored in node->priv for every procfs node +typedef struct { + u64 pid; + u8 kind; + char *buf; + u64 len; +} procfs_data; + +//void procfs_register(void); + +#endif \ No newline at end of file diff --git a/src/kernel/file_systems/vfs/sysfs/sysfs.c b/src/kernel/file_systems/vfs/sysfs/sysfs.c new file mode 100644 index 0000000..439895b --- /dev/null +++ b/src/kernel/file_systems/vfs/sysfs/sysfs.c @@ -0,0 +1,108 @@ +#include "../vfs.h" +#include "sysfs.h" +#include +#include +#include +#include +#include + + +static fs_node* sysfs_lookup(fs_node *dir, const char *name); + +static fs_ops sysfs_ops = { + .open = NULL, + .close = NULL, + .read = NULL, + .write = NULL, + .lookup = sysfs_lookup, + .create = NULL, + .mkdir = NULL, +}; + +static fs_node* sysfs_make_block(void) +{ + fs_node *block = fs_mknode("block", FS_DIR); + if (!block) return NULL; + block->ops = &sysfs_ops; + + int count = ATAget_device_count(); + fs_node *tail = NULL; + for (int i = 0; i < count; i++) + { + char devname[4]; + devname[0] = 'h'; + devname[1] = 'd'; + devname[2] = (char)('a' + i); + devname[3] = '\0'; + + fs_node *n = fs_mknode(devname, FS_DIR); + if (!n) continue; + n->ops = &sysfs_ops; + + if (!block->children) block->children = n; + else tail->next = n; + tail = n; + } + return block; +} + +static fs_node* sysfs_lookup(fs_node *dir, const char *name) +{ + if (!dir || !name) return NULL; + + // /sys > "block" + if (str_equals(dir->name, "sys")) { + if (str_equals(name, "block")) + return sysfs_make_block(); + return NULL; + } + + // /sys/block + if (str_equals(dir->name, "block")) + { + int count = ATAget_device_count(); + for (int i = 0; i < count; i++) { + char devname[4]; + devname[0] = 'h'; + devname[1] = 'd'; + devname[2] = (char)('a' + i); + devname[3] = '\0'; + if (str_equals(name, devname)) { + fs_node *n = fs_mknode(devname, FS_DIR); + if (!n) return NULL; + n->ops = &sysfs_ops; + return n; + } + } + return NULL; + } + return NULL; +} + +static int sysfs_mount(const char *src, const char *tgt, fs_mnt *mnt) +{ + (void)src; + (void)tgt; + + fs_node *root = fs_mknode("sys", FS_DIR); + if (!root) return -1; + root->ops = &sysfs_ops; + root->children = sysfs_make_block(); + mnt->root = root; + + return 0; +} + +static fs_type sysfs_type = { + .name = "sysfs", + .mount = sysfs_mount, + .ops = &sysfs_ops, +}; + +void sysfs_register(void) { + fs_register(&sysfs_type); +} + +void sysfs_refresh(void) { + extern fs_mnt *fs_get_mount(const char *path); +} \ No newline at end of file diff --git a/src/kernel/file_systems/vfs/sysfs/sysfs.h b/src/kernel/file_systems/vfs/sysfs/sysfs.h new file mode 100644 index 0000000..a3085f1 --- /dev/null +++ b/src/kernel/file_systems/vfs/sysfs/sysfs.h @@ -0,0 +1,4 @@ +#pragma once + +void sysfs_register(void); +void sysfs_refresh(void); \ No newline at end of file diff --git a/src/kernel/file_systems/vfs/vfs.c b/src/kernel/file_systems/vfs/vfs.c index 248f359..66c7cb2 100644 --- a/src/kernel/file_systems/vfs/vfs.c +++ b/src/kernel/file_systems/vfs/vfs.c @@ -196,6 +196,39 @@ int fs_addchild(fs_node *parent, fs_node *child) { return 0; } +int fs_listdir(const char *path, _emx_kdirent_t *buf, int max_entries) { + fs_node *node = fs_resolve(path); + if (!node || node->type != FS_DIR) return -1; + + fs_node *children = NULL; + if (node->ops && node->ops->readdir) + children = node->ops->readdir(node); + else + children = node->children; + + int count = 0; + fs_node *child = children; + + while (child && count < max_entries) { + buf[count].type = child->type; + // FS_FILE=0x01 + // FS_DIR=0x02 + // FS_DEV=0x04 + + // copy name safely + int i = 0; + while (i < 63 && child->name[i]) { + buf[count].name[i] = child->name[i]; + i++; + } + buf[count].name[i] = '\0'; + + count++; + child = child->next; + } + + return count; +} // // main init diff --git a/src/kernel/file_systems/vfs/vfs.h b/src/kernel/file_systems/vfs/vfs.h index 55718ac..d8a8b8f 100644 --- a/src/kernel/file_systems/vfs/vfs.h +++ b/src/kernel/file_systems/vfs/vfs.h @@ -58,14 +58,17 @@ struct fs_file { u64 pos; u32 flags; }; +typedef struct { + u8 type; + char name[64]; +} _emx_kdirent_t; // operations struct fs_ops { int (*open)(fs_node *node, fs_file *file); int (*close)(fs_file *file); - ssize_t (*read)(fs_file *file, void *buf, size_t cnt); // read - ssize_t (*write)(fs_file *file, const void *buf, size_t cnt); // write - // could be used for syscalls + ssize_t (*read)(fs_file *file, void *buf, size_t cnt); + ssize_t (*write)(fs_file *file, const void *buf, size_t cnt); fs_node* (*lookup)(fs_node *dir, const char *name); int (*create)(fs_node *dir, const char *name); @@ -74,6 +77,9 @@ struct fs_ops { //tmpfs using ram // devfs using modules/modules... // ... maybe writing on disk + + + fs_node* (*readdir)(fs_node *dir); }; // filesystem type @@ -116,6 +122,7 @@ int fs_close(int fd); ssize_t fs_read(int fd, void *buf, size_t cnt); ssize_t fs_write(int fd, const void *buf, size_t cnt); int fs_mkdir(const char *path); +int fs_listdir(const char *path, _emx_kdirent_t *buf, int max_entries); // global klime pointer (shared by all fs types) extern void *fs_klime; @@ -142,4 +149,6 @@ typedef struct { void devfs_register(void); int devfs_register_device(driver_module *mod); +void procfs_register(void); + #endif diff --git a/src/kernel/file_systems/vfs/vfs_init.c b/src/kernel/file_systems/vfs/vfs_init.c index 9465c4e..576fe33 100644 --- a/src/kernel/file_systems/vfs/vfs_init.c +++ b/src/kernel/file_systems/vfs/vfs_init.c @@ -1,6 +1,8 @@ -#include "init.h" +//#include "init.h" +#include +#include int init_boot_log = -1; -char *logpath = "/emr/logs/log1.txt"; +char *logpath = "/emr/system/logs/log1.txt"; #include "vfs.h" #include #include @@ -129,26 +131,18 @@ void fs_system_init(void *klime) // register fs types tmpfs_register(); devfs_register(); + procfs_register(); + sysfs_register(); log("[FS]", "mounting roots: \n", white()); - // mount root as tmpfs - fs_mount(NULL, ROOT_MOUNT_DEFAULT, ROOTFS); // in future its just root so for (fat32,ext2,...) - //fs_mount(NULL, "/", "/"); // or root + // mount file systems + fs_mount(NULL, ROOT_MOUNT_DEFAULT, ROOTFS); + fs_mount(NULL, DEV_MOUNT_DEFAULT, DEVFS); + fs_mount(NULL, PROC_MOUNT_DEFAULT, PROCFS); + //fs_mount(NULL, SYS_MOUNT_DEFAULT, SYSFS); - // create standard dirs - fs_mkdir(DEV_DIRECTORY); - fs_mkdir(TMP_DIRECTORY); - fs_mkdir(BOOT_DIRECTORY); - //emx system requirement paths - fs_mkdir(EMX_DIRECTORY); // /emr - fs_mkdir(EMLOG_DIRECTORY); - fs_mkdir(EMAST_DIRECTORY); - fs_mkdir(EMCFG_DIRECTORY); - fs_mkdir(KEYMP_DIRECTORY); - fs_mkdir(EMDRV_DIRECTORY); - - fs_mkdir(CONF_DIRECTORY); + initvfs(); init_boot_log = fs_open(logpath, O_CREAT | O_WRONLY); log("[FS]", "[FS] wrote", d); @@ -157,18 +151,9 @@ void fs_system_init(void *klime) panic("Cannot open [logs]"); } BOOTUP_PRINT("\n", white()); - //TODO: bootconf loading from /boot/bootconf - // in shared/theme/bootconf file - - //fs_check_bootconf(); - //fs_load_bootconf(); - - // mount devfs at /dev - fs_mount(NULL, DEV_MOUNT_DEFAULT, DEVFS); //last thing for init is loading all limine modules load_limine_module(); // logo - } void fs_register_mods() diff --git a/src/kernel/graph/draw.c b/src/kernel/graph/draw.c index ac954ab..a41d23e 100644 --- a/src/kernel/graph/draw.c +++ b/src/kernel/graph/draw.c @@ -3,11 +3,11 @@ void draw_rect(u32 x, u32 y, u32 width, u32 height, u32 color) { - for (u32 dy = 0; dy < height; dy++) - { - for (u32 dx = 0; dx < width; dx++) - { - putpixel(x + dx, y + dy, color); + u32 pitch_dwords = fb_pitch / 4; + for (u32 dy = 0; dy < height; dy++) { + u32 *row = framebuffer + (y + dy) * pitch_dwords + x; + for (u32 dx = 0; dx < width; dx++) { + row[dx] = color; } } } diff --git a/src/kernel/graph/graphics.c b/src/kernel/graph/graphics.c index 1d239f5..68ba1d9 100644 --- a/src/kernel/graph/graphics.c +++ b/src/kernel/graph/graphics.c @@ -49,29 +49,37 @@ void clear(u32 color) u32 w = get_fb_width(); u32 h = get_fb_height(); draw_rect(0, 0, w, h, color); - reset_cursor(); - print(" ", GFX_BG); + //reset_cursor(); + cursor_y = 0; + cursor_x = 0; + //print(" ", GFX_BG); + // OH WHY DID I PUT THIS HERE MONTHS AGO I WONDERED WHERE THE RANDOM SPACE CAME FROM............. :( } void scroll_up(u32 lines) { u32 pixels_to_scroll = lines; u32 pitch_dwords = fb_pitch / 4; - - // Move framebuffer content up - for (u32 y = pixels_to_scroll; y < fb_height; y++) { - for (u32 x = 0; x < fb_width; x++) { - framebuffer[(y - pixels_to_scroll) * pitch_dwords + x] = - framebuffer[y * pitch_dwords + x]; - } - } - - // Clear bottom lines - for (u32 y = fb_height - pixels_to_scroll; y < fb_height; y++) { - for (u32 x = 0; x < fb_width; x++) { - framebuffer[y * pitch_dwords + x] = bg(); - } - } + //u32 bytes_per_row = fb_width * sizeof(u32); + //u32 bg_color = black(); + + // move framebuffer content up + //for (u32 y = pixels_to_scroll; y < fb_height; y++) { + // memcpy(framebuffer + (y - pixels_to_scroll) * pitch_dwords, + // framebuffer + y * pitch_dwords, + // bytes_per_row); + //} + + u32 *src = framebuffer + pixels_to_scroll * pitch_dwords; + u32 *dst = framebuffer; + size_t rows = fb_height - pixels_to_scroll; + memmove(dst, src, rows * pitch_dwords * sizeof(u32)); + + // clear bottom lines (bg is black = 0) + memset( + framebuffer + (fb_height - pixels_to_scroll) * pitch_dwords, 0, + pixels_to_scroll * pitch_dwords * sizeof(u32) + ); } void putpixel(u32 x, u32 y, u32 color) diff --git a/src/kernel/graph/graphics.h b/src/kernel/graph/graphics.h index a6b5ce8..dbc3345 100644 --- a/src/kernel/graph/graphics.h +++ b/src/kernel/graph/graphics.h @@ -7,6 +7,7 @@ #include #include #include +#include extern u32 *framebuffer; extern u32 fb_width; diff --git a/src/kernel/graph/theme.h b/src/kernel/graph/theme.h index 5270c6c..be85a99 100644 --- a/src/kernel/graph/theme.h +++ b/src/kernel/graph/theme.h @@ -1,74 +1,4 @@ -#ifndef THEME_H -#define THEME_H +#pragma once #include - -#ifdef __cplusplus -extern "C" { -#endif - -// theme types -typedef enum { - THEME_STD = 0, - THEME_FLU = 1 -} ThemeType; -//context types -typedef enum { - THEME_BOOTUP = 0, - THEME_CONSOLE = 1, - THEME_PANIC = 2 -} ThemeContext; - -// unified naming -typedef enum { - COLOR_BLACK = 0, - COLOR_BG, - COLOR_RED, - COLOR_GREEN, - COLOR_YELLOW, - COLOR_BLUE, - COLOR_PURPLE, - COLOR_CYAN, - COLOR_WHITE -} ThemeColor; -typedef struct { - u32 BLACK; - u32 BG; - u32 RED; - u32 GREEN; - u32 YELLOW; - u32 BLUE; - u32 PURPLE; - u32 CYAN; - u32 WHITE; -} ThemeColors; - - -void theme_init(); -void setcontext(ThemeContext context); -ThemeContext getcontext(); - -void sbootup_theme(ThemeType type); -//void sconsole_theme(ThemeType type); -void spanic_theme(ThemeType type); -void reload_console_theme(void); - -u32 get_color(ThemeColor color); - - -// current colors from theme -u32 black(); -u32 bg(); -u32 red(); -u32 green(); -u32 yellow(); -u32 blue(); -u32 purple(); -u32 cyan(); -u32 white(); - -#ifdef __cplusplus -} -#endif - -#endif +#include diff --git a/src/kernel/inits/console/config.c b/src/kernel/inits/console/config.c new file mode 100644 index 0000000..301cecd --- /dev/null +++ b/src/kernel/inits/console/config.c @@ -0,0 +1,18 @@ +#include "gen.h" + +//#include + +void running_console_config_init(void) { + int fd = fs_open(CONSOLECONFIG "/con.cfg", O_CREAT | O_WRONLY); // get read by graph/theme + if (fd >= 0) { + const char *Cconfiguration = + "CONSOLE_PROG: \"ekmsh\"\n" + "CONSOLE_NAME: \"console\"\n" + "\n" + "CONSOLE_VERS: \"1.3\" # new with login\n" + ; + + fs_write(fd, Cconfiguration, str_len(Cconfiguration)); + fs_close(fd); + } +} diff --git a/src/kernel/inits/console/gen.c b/src/kernel/inits/console/gen.c new file mode 100644 index 0000000..2c20586 --- /dev/null +++ b/src/kernel/inits/console/gen.c @@ -0,0 +1,12 @@ +#include "gen.h" + +//#include + +char cwd[MAX_PATH_LEN] = "/"; + +void console_init_gen(void) { + promptdirs(); + promptcont(); + init_consoletheme(); + running_console_config_init(); +} diff --git a/src/kernel/inits/console/gen.h b/src/kernel/inits/console/gen.h new file mode 100644 index 0000000..1026d06 --- /dev/null +++ b/src/kernel/inits/console/gen.h @@ -0,0 +1,28 @@ +#ifndef GEN_H +#define GEN_H + +#include +#include_next + +#define CONSOLECONFIG "/.config/ekmsh" +#define PROMPT_PATH "/.config/ekmsh/prompt.cfg" + +#define MAX_INPUT_LEN 256 +#define MAX_PATH_LEN 256 +#define MAX_CMDS 32 +#define MAX_CHAINED_CMDS 8 + +#define CONSOLE_APP_NAME "console" +#define CONSOLE_WINDOW "w1" +#define CONSOLE_NAME "ekmsh" // emex-kernelmode-shell +#define WRONG_COMMAND_CL GFX_RED + +extern char cwd[MAX_PATH_LEN]; + +void promptdirs(void); +void promptcont(void); +void console_init_gen(void); +void init_consoletheme(void); +void running_console_config_init(void); + +#endif diff --git a/src/kernel/inits/console/prompt.c b/src/kernel/inits/console/prompt.c new file mode 100644 index 0000000..c98d766 --- /dev/null +++ b/src/kernel/inits/console/prompt.c @@ -0,0 +1,24 @@ +#include "gen.h" + +//#include + + +void promptdirs(void) { + fs_mkdir(CONSOLECONFIG); + fs_mkdir(CONSOLECONFIG "/fonts"); + + //return; +} + +void promptcont(void) { + int fd = fs_open(PROMPT_PATH, O_CREAT | O_WRONLY); + if (fd >= 0) { + const char *default_config = + "# currently there is no color support for the prompt, but soon!\n" + "# %u = username,\n# %h = hostname,\n# %w = curent directory\n" + "[%u@%h:%w]# \n" + ; + fs_write(fd, default_config, str_len(default_config)); + fs_close(fd); + } +} diff --git a/src/kernel/inits/console/theme.c b/src/kernel/inits/console/theme.c new file mode 100644 index 0000000..10c15d8 --- /dev/null +++ b/src/kernel/inits/console/theme.c @@ -0,0 +1,26 @@ +#include "gen.h" + +//#include + + +void init_consoletheme(void) { + int fd = fs_open(CONSOLECONFIG "/theme.cfg", O_CREAT | O_WRONLY); // get read by graph/theme + if (fd >= 0) { + const char *default_theme = + "# use: 0xAARRGGBB\n" + "\n" + "BLACK: 0xFF111111\n" + "BG: 0xFF1F1F1F\n" + "RED: 0xFF9E6E6E\n" + "GREEN: 0xFF7A8A7A\n" + "YELLOW: 0xFFB8A788\n" + "BLUE: 0xFF6E7F8E\n" + "PURPLE: 0xFF857A8E\n" + "CYAN: 0xFF7A8E8E\n" + "WHITE: 0xFFD8D8D8\n" + ; + + fs_write(fd, default_theme, str_len(default_theme)); + fs_close(fd); + } +} diff --git a/src/kernel/inits/fs/init.c b/src/kernel/inits/fs/init.c new file mode 100644 index 0000000..bccf04e --- /dev/null +++ b/src/kernel/inits/fs/init.c @@ -0,0 +1,26 @@ +#include "init.h" + +#include + +void initvfs(void){ + // only necessary dirs the rest comes from initrd.cpio + // create standard dirs + fs_mkdir(DEV_DIRECTORY); + fs_mkdir(TMP_DIRECTORY); + + fs_mkdir(BOOT_DIRECTORY); + //emx system requirement paths + fs_mkdir(EMX_DIRECTORY); // /emr + fs_mkdir(EMSYS_DIRECTORY); + fs_mkdir(EMLOG_DIRECTORY); + //fs_mkdir(EMAST_DIRECTORY); + //fs_mkdir(EMCFG_DIRECTORY); + //fs_mkdir(KEYMP_DIRECTORY); + //fs_mkdir(EMDRV_DIRECTORY); + + //fs_mkdir(CONF_DIRECTORY); + fs_mkdir(PROC_DIRECTORY); + fs_mkdir(SYS_DIRECTORY); + + //initrd.cpio does the rest :) +} diff --git a/src/kernel/file_systems/vfs/init.h b/src/kernel/inits/fs/init.h similarity index 70% rename from src/kernel/file_systems/vfs/init.h rename to src/kernel/inits/fs/init.h index a8a55fb..709f8b2 100644 --- a/src/kernel/file_systems/vfs/init.h +++ b/src/kernel/inits/fs/init.h @@ -2,24 +2,29 @@ extern char *logpath; extern int init_boot_log; +void initvfs(void); + #define DISK_NAME "hdd0" #define ROOTFS TMPFS // for now, soon its fat32/ext2 #define ROOT_MOUNT_DEFAULT "/" #define FAT32 "fat32" -#define FAT32_DIRECTORY "/" +#define FAT32_DIRECTORY "/" #define EXT2 "ext2" -#define EXT2_DIRECTORY "/" +#define EXT2_DIRECTORY "/" #define TMPFS "tmpfs" -#define TMP_DIRECTORY "/tmp" +#define TMP_DIRECTORY "/tmp" +#define SYSFS "sysfs" +#define SYS_MOUNT_DEFAULT "/sys" +#define SYS_DIRECTORY "/sys" #define DEVFS "devfs" #define DEV_MOUNT_DEFAULT "/dev" -#define DEV_DIRECTORY "/dev" +#define DEV_DIRECTORY "/dev" #define _DEV "/dev/" #define MOUNT_DEV "/dev/hda" @@ -27,7 +32,8 @@ extern int init_boot_log; #define _EMX "/emr/" // mount point (/disk) #define EMCFG_DIRECTORY /*" /emr "*/EMX_DIRECTORY "/config" // == system configs #define EMAST_DIRECTORY /*" /emr "*/EMX_DIRECTORY "/assets" -#define EMLOG_DIRECTORY /*" /emr "*/EMX_DIRECTORY "/logs" +#define EMSYS_DIRECTORY /*" /emr "*/EMX_DIRECTORY "/system" +#define EMLOG_DIRECTORY /*" /emr "*/EMSYS_DIRECTORY "/logs" #define KEYMP_DIRECTORY /*" /emr "*/EMCFG_DIRECTORY "/keymaps" #define EMDRV_DIRECTORY /*" /emr "*/EMX_DIRECTORY "/drvs" @@ -42,8 +48,12 @@ extern int init_boot_log; #define LOGO_DIRECTORY BOOT_DIRECTORY UI_DIRECTORY AST_DIRECTORY #define LOGO_NAME LOGO_DIRECTORY "/bootlogo.bin" +#define PROCFS "procfs" +#define PROC_MOUNT_DEFAULT "/proc" +#define PROC_DIRECTORY "/proc" + static inline void init_early_boot_log(void) { extern int init_boot_log; - init_boot_log = -1; // Noch nicht bereit + init_boot_log = -1; } diff --git a/src/kernel/inits/init.c b/src/kernel/inits/init.c index 798dd20..9870921 100644 --- a/src/kernel/inits/init.c +++ b/src/kernel/inits/init.c @@ -4,34 +4,35 @@ void keymaps_load(void) { // create keymap settings - int fd_keymap_cfg = fs_open("/emr/config/keymaps/keymap.cfg", O_CREAT | O_WRONLY); + /*int fd_keymap_cfg = fs_open("/emr/config/keymaps/keymap.cfg", O_CREAT | O_WRONLY); if (fd_keymap_cfg >= 0) { const char *default_config = "# US, PL, DE \nKEYMAP: US\n"; fs_write(fd_keymap_cfg, default_config, str_len(default_config)); fs_close(fd_keymap_cfg); } - log("[FS]","created keymap.cfg\n", d); + log("[FS]","created keymap.cfg\n", d);*/ // load all keymaps - limine_module_load("US.map", "/emr/config/keymaps/US.map"); - limine_module_load("DE.map", "/emr/config/keymaps/DE.map"); + //limine_module_load("US.map", "/emr/config/keymaps/US.map"); + //limine_module_load("DE.map", "/emr/config/keymaps/DE.map"); //limine_module_load("PL.map", "/emr/config/keymaps/PL.map"); + //limine_module_load("RU.map", "/emr/config/keymaps/RU.map"); } void logos_load(void) { - limine_module_load("bootlogo.bin", "/boot/ui/assets/bootlogo.bin"); + //limine_module_load("bootlogo.bin", "/boot/ui/assets/bootlogo.bin"); //limine_module_load("logo.bmp", "/emr/assets/logo.bmp"); //limine_module_load("console_icon.bmp", "/images/iconsole.bmp"); //limine_module_load("desktop_icon.bmp", "/images/idesktop.bmp"); //fs_mkdir("/emr/images/"); //limine_module_load("background.bmp", "/emr/assets/bg.bmp"); - limine_module_load("frog.bmp", "/emr/assets/frog.bmp"); + //limine_module_load("frog.bmp", "/emr/assets/frog.bmp"); } void users_load(void) { - int fd_users = fs_open(USERINI_PATH "", O_CREAT | O_WRONLY); // how can this be possible..... + /*int fd_users = fs_open(USERINI_PATH "", O_CREAT | O_WRONLY); // how can this be possible..... int fd_system = fs_open(SYSTEMINI_PATH "", O_CREAT | O_WRONLY); // if it works don't touch it! if (fd_users >= 0) { @@ -52,7 +53,7 @@ void users_load(void) { "root_user=admin # from users.ini\n"; fs_write(fd_system, system_config, str_len(system_config)); fs_close(fd_system); - } + }*/ //fs_mkdir("/user"); //fs_mkdir("/user/bin"); //fs_mkdir("/user/apps"); diff --git a/src/kernel/inits/init.h b/src/kernel/inits/init.h index a89c0c1..b18e9c4 100644 --- a/src/kernel/inits/init.h +++ b/src/kernel/inits/init.h @@ -12,8 +12,8 @@ #include #include -// Load all Limine modules to VFS -void dualslotvalidating(void); +// load all Limine modules to VFS +//void dualslotvalidating(void); void keymaps_load(void); void logos_load(void); void users_load(void); diff --git a/src/kernel/inits/initrd/initrd.c b/src/kernel/inits/initrd/initrd.c new file mode 100644 index 0000000..760dca5 --- /dev/null +++ b/src/kernel/inits/initrd/initrd.c @@ -0,0 +1,83 @@ +#include "initrd.h" +#include +#include +#include // module_request +#include +#include +#include +#include + +int initrd_load(void) +{ + log("[INITRD]", "looking for " INITRD_MODULE_NAME "...\n", d); + + if (!module_request.response || + module_request.response->module_count == 0) + { + log("[INITRD]", "no Limine modules available\n", warning); + return -1; + } + + struct limine_module_response *resp = module_request.response; + struct limine_file *initrd_file = NULL; + + for (u64 i = 0; i < resp->module_count; i++) { + const char *path = resp->modules[i]->path; + + // extract just the filename from the Limine path + const char *fname = path; + for (const char *p = path; *p; p++) { + if (*p == '/') fname = p + 1; + } + + if (str_equals(fname, INITRD_MODULE_NAME)) { + initrd_file = resp->modules[i]; + break; + } + } + + if (!initrd_file) { + log("[INITRD]", INITRD_MODULE_NAME " not found in Limine modules\n", warning); + //hcf(); + return -1; + } + + + + search_initrd: { + char buf[48]; + str_copy(buf, "found at 0x"); + str_from_hex(buf + str_len(buf), (u64)initrd_file->address); + str_append(buf, " ("); + str_append_uint(buf, (u32)initrd_file->size); + str_append(buf, " bytes)\n"); + log("[INITRD]", buf, d); + }; + + + // CPIO newc magic + const u8 *raw = (const u8 *)initrd_file->address; + if (initrd_file->size < 6 || + raw[0]!='0' || raw[1]!='7' || raw[2]!='0' || + raw[3]!='7' || raw[4]!='0' || (raw[5]!='1' && raw[5]!='2')) + { + log("[INITRD]", "the initrd file uses the wrong format, need to be newc\n", error); + return -1; + } + + + int extracted = cpio_extract_to_vfs( + raw, + (u64)initrd_file->size, + "/" + ); + + if (extracted < 0) { + log("[INITRD]", "extraction failed\n", error); + //hcf(); + return -1; + } + + //log("[INITRD]", "mounted at the root\n", success); + return extracted; +} diff --git a/src/kernel/inits/initrd/initrd.h b/src/kernel/inits/initrd/initrd.h new file mode 100644 index 0000000..27882d2 --- /dev/null +++ b/src/kernel/inits/initrd/initrd.h @@ -0,0 +1,9 @@ +#ifndef INITRD_H +#define INITRD_H + +#define INITRD_MOUNT_POINT "/" +#define INITRD_MODULE_NAME "initrd.cpio" + +int initrd_load(void); + +#endif diff --git a/src/kernel/interface/partition.c b/src/kernel/interface/partition.c index 9ef18d1..68dfb7b 100644 --- a/src/kernel/interface/partition.c +++ b/src/kernel/interface/partition.c @@ -55,7 +55,7 @@ int partition_init(void) { BOOTUP_PRINT(" Partition ", white()); BOOTUP_PRINT_INT(partition_count, white()); BOOTUP_PRINT(": ", white()); - BOOTUP_PRINT(part->type_name, cyan()); + BOOTUP_PRINT(part->type_name, white()); BOOTUP_PRINT(" LBA: ", white()); BOOTUP_PRINT_INT(part->start_lba, white()); BOOTUP_PRINT(", sectors: ", white()); @@ -101,16 +101,16 @@ int partition_needs_format(void) { //not a real format rn but it works... so i don't touch it int partition_format_disk_fat32(void) { - BOOTUP_PRINT("[PARTITION] ", GFX_GRAY_70); - BOOTUP_PRINT("formatting disk with FAT32...\n", yellow()); + //BOOTUP_PRINT("[PARTITION] ", GFX_GRAY_70); + log("[PARTITION]","formatting disk with FAT32...\n", d); // NOTE: // this will overwrite everything withouth backups or other ATAdevice_t *device = ATAget_device(0); if (!device) { - BOOTUP_PRINT("[PARTITION] ", GFX_GRAY_70); - BOOTUP_PRINT("nothing foun\n", red()); + //BOOTUP_PRINT("[PARTITION] ", GFX_GRAY_70); + log("[PARTITION]","nothing foun\n", error); return -1; } @@ -126,8 +126,7 @@ int partition_format_disk_fat32(void) { u32 partition_sectors ; //= total_sectors - start_lba - 2048; if (total_sectors_64 < (start_lba + 2048)) { - BOOTUP_PRINT("[PARTITION] ", GFX_GRAY_70); - BOOTUP_PRINT("disk is too small\n", red()); + log("[PARTITION]","disk is too small\n", error); return -1; } if (total_sectors_64 > 0xFFFFFFFF) { @@ -139,8 +138,7 @@ int partition_format_disk_fat32(void) { partition_sectors = total_sectors - start_lba - 2048; if (partition_sectors < PARTSECSIZE) { - BOOTUP_PRINT("[PARTITION] ", GFX_GRAY_70); - BOOTUP_PRINT("partition too small\n", red()); + log("[PARTITION]","partition too small\n", error); return -1; } @@ -155,18 +153,17 @@ int partition_format_disk_fat32(void) { if (mbr_create_partition(&mbr, 0, MBR_PARTITION_FAT32_LBA, start_lba, partition_sectors) != 0) { - BOOTUP_PRINT("[PARTITION] ", GFX_GRAY_70); - BOOTUP_PRINT("failed to create partition entry\n", red()); + log("[PARTITION]","failed to create partition entry\n", error); return -1; } if (mbr_write(&mbr) != 0) { - BOOTUP_PRINT("[PARTITION] ", GFX_GRAY_70); - BOOTUP_PRINT("failed to write MBR\n", red()); + //BOOTUP_PRINT("[PARTITION] ", GFX_GRAY_70); + log("[PARTITION]","failed to write MBR\n", error); return -1; } - BOOTUP_PRINT("[PARTITION] ", GFX_GRAY_70); - BOOTUP_PRINT("MBR created .\n", green()); + //BOOTUP_PRINT("[PARTITION] ", GFX_GRAY_70); + log("[PARTITION]","MBR created \n", d); return 0; } diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 1ecb381..441d9f4 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -1,18 +1,15 @@ #include #include -#include #include #include +#include #include #include #include //int init_boot_log = -1; // boot logs - -// Drivers #include - // Dual Slot Kernel System #include @@ -33,16 +30,26 @@ #include #endif +//Devices +#include +#include +#include +#include +#include +#include +#include +#include +#include // usermode stuff #include //Desktop Enviroment #include - - // executables -#include +#include +#include +#include // Memory @@ -55,19 +62,24 @@ klime_t *klime = NULL; #if ENABLE_ULIME #include #include + #include + #include + #include + #include + #include + #include scheduler_t *scheduler = NULL; #define SCHEDQUANT 20 proc_manager_t *proc_mgr = NULL; ulime_t *ulime = NULL; + mt_t *mt = NULL; #endif - -//debug -#include - -//vFS & fs +//vFS & fs & disk #include -#include +#include +#include +#include #if ENABLE_FAT32 #include // finally fat32! // interface @@ -75,9 +87,6 @@ klime_t *klime = NULL; #include #include #endif - -// disk drivers -#include #if ENABLE_ATA #include #endif @@ -90,16 +99,7 @@ klime_t *klime = NULL; void _start(void) { - if (framebuffer_request.response != NULL && - framebuffer_request.response->framebuffer_count > 0) { - struct limine_framebuffer *fb = framebuffer_request.response->framebuffers[0]; - u32 *pixels = (u32 *)fb->address; - u64 total = fb->width * fb->height; - for (u64 i = 0; i < total; i++) { - pixels[i] = 0x00FF0000; // red = kernel alive - } - } - { // Initializing Boot screen + d_boot_screen: { // Initializing Boot screen theme_init(); setcontext(THEME_BOOTUP); // gets loaded over sbootup_theme until, sbootup == FLU sbootup_theme(THEME_STD); @@ -109,39 +109,36 @@ void _start(void) // Temporaly before switchin to glime_t // emexOS start // Ensure that Limine base revision is supported and that we have a framebuffer - /*if (framebuffer_request.response == NULL || - framebuffer_request.response->framebuffer_count < 1) { - printf("no response"); + if (framebuffer_request.response == NULL || + framebuffer_request.response->framebuffer_count < 1) + { + printf("no response"); hcf(); // enable text mode - }*/ + } // Initialize framebuffer graphics struct limine_framebuffer *fb = framebuffer_request.response->framebuffers[0]; graphics_init(fb); - printf("\ninit graphics, draw logo\n"); - //draw_logo(); - + kproc_loader_init(); + init_bootscreen(); fm_init(); - clear(bg()); + log("::", "finished loading esr\n", _d); cursor_x = 0; cursor_y = 0; font_scale = 1; - - f_setcontext(FONT_8X8); + clear(bg()); BOOTUP_PRINT("\n\n ======================\n", white()); BOOTUP_PRINT(" | Welcome to ", white()); BOOTUP_PRINT("emexOS", cyan()); BOOTUP_PRINT("! |\n", white()); BOOTUP_PRINT(" ======================\n\n", white()); - delay(2); #if BOOTUP_VISUALS == 1 log("[BOOT]", "BOOTUP_VISUALS == 1\n", warning); #else log("[BOOT]", "BOOTUP_VISUALS == 0\n", warning); #endif - delay(3); //actually not needed but maybe later (e.g. for testing themes) //draw_rect(10, 10, fb_width - 20, fb_height - 20, blue()); @@ -158,7 +155,7 @@ void _start(void) proc_mgr = proc_mng_init(ulime); #endif - { // MADE BY @TSARAKI (github) + memory_ss: { // MADE BY @TSARAKI (github) cpu_detect(); #if X64 == 1 @@ -171,8 +168,9 @@ void _start(void) physmem_init(memmap_request.response, hhdm_request.response); paging_init(hhdm_request.response); + map_region_alloc(hhdm_request.response, HEAP_START, HEAP_SIZE); + // kernel lifetime - u64 phys_klime = map_region_alloc(hhdm_request.response, HEAP_START, HEAP_SIZE); klime_t *klime = klime_init((u64 *)HEAP_START, HEAP_SIZE); if (!framebuffer_request.response) { @@ -184,8 +182,6 @@ void _start(void) } #if ENABLE_GLIME - u64 phys_glime = map_region_alloc(hhdm_request.response, GRAPHICS_START, GRAPHICS_SIZE); - limine_framebuffer_t *fb = framebuffer_request.response->framebuffers[0]; glime_response_t glres; @@ -194,6 +190,7 @@ void _start(void) glres.height = (u64)fb->height; glres.pitch = (u64)fb->pitch; + map_region_alloc(hhdm_request.response, GRAPHICS_START, GRAPHICS_SIZE); glime_t *glime = glime_init(&glres, (u64 *)GRAPHICS_START, GRAPHICS_SIZE); #else log("[GLIME]", "skipped (hardware compatibility)\n", warning); @@ -218,6 +215,14 @@ void _start(void) scheduler = scheduler_init(ulime, SCHEDQUANT); proc_mgr = proc_mng_init(ulime); + mt = (mt_t*)klime_create(ulime->klime, sizeof(mt_t)); + if (mt) { + mt_init(mt, scheduler, ulime); + //log("[MT]", "multitasking initialized\n", d); + //ipc_init(); + //ipc_test(); + } + if (scheduler) { char buf[32]; str_append_uint(buf, SCHEDQUANT); @@ -229,6 +234,13 @@ void _start(void) log("[PROCMGR]", "initialized\n", d); } + init_ipc: + { + ipc_messages_init(); + ipc_shm_init(); + //ipc_test(); + }; + syscall_arch_init(); // SYSCALL/SYSRET _init_syscalls_table(ulime); } @@ -249,78 +261,69 @@ void _start(void) //BOOTUP_PRINT("\n", GFX_WHITE); } - // KERNEL SLOT subsystem - { + kernel_slot_ss: { dualslotvalidating(); } + // initialize Limine modules + limine_module_ss: limine_modules_init(); { + initrd_load(); + dualslotvalidating(); + keymaps_load(); + logos_load(); + users_load(); + } #if ENABLE_ATA == 1 - ata_init();{ - // Initialize partition system - int part_result = partition_init(); - - if (part_result != 0 || partition_needs_format()) { - //BOOTUP_PRINT("[DISK] ", GFX_GRAY_70); - - #if OVERWRITEALL == 1 - log("[DISK]", "(OVERWRITEALL=1)...\n", d); - if - (partition_format_disk_fat32() == 0) - { - log("[DISK]", "Creating FAT32 filesystem...\n", d); - if - (fat32_format_partition(2048, ATAget_device(0)->sectors - 4096) == 0) - { - log("[DISK]", "Disk formated successfully\n", success); - partition_init(); - } else - { - log("[DISK]", "FAT32 Format failed\n", error); - } - } else - { - log("[DISK]", "MBR creation failed\n", error); - } - #else - log("[DISK]", "Disk needs formatting\n", warning); - log("[DISK]", "set \"OVERWRITEALL=0\" to \"1\" in shared/config/disk.h\n", warning); + ata_init();{ + // initialize partition system + int part_result = partition_init(); + + if (part_result != 0 || partition_needs_format()) { + log("[DISK]", "no valid partition found\n", warning); + log("[DISK]", "run 'install' to set up the disk\n", warning); + } + + #if ENABLE_FAT32 == 1 + log("[FAT32]", "mounting FAT32 file system\n", d); + fat32_init(); #endif } - #if ENABLE_FAT32 == 1 - log("[FAT32]", "mounting FAT32 file system\n", d); - fat32_init(); + #if ENABLE_FAT32 + //fat32_mount("/dev/hda1", "/boot", "fat32"); + //log("[BOOT]", "Boot partition mounted at /boot\n", d); #endif - } #else - log("[ATA]", "skipped (hardware compatibility)\n", warning); + log("[ATA]", "skipped (hardware compatibility)\n", warning); #endif - // Initialize Limine modules - limine_modules_init(); { - dualslotvalidating(); - keymaps_load(); - logos_load(); - users_load(); - } + fs_mount(NULL, SYS_MOUNT_DEFAULT, SYSFS); + //logo_init(); //draw_logo(); #if HARDWARE_SC == 1 // let the cpu rest a small time for (volatile int i = 0; i < 1000000; i++) { - __asm__ volatile("nop"); + nop(); } #endif - module_init(); { + module_ss: module_init(); { // Register driver modules log("[MOD]", "Init regs:\n", d); - module_register(&console_module); - module_register(&keyboard_module); - #if ENABLE_ATA + + //module_register(&console_module); module_register(&ata_module); - #endif + module_register(&null_module); + module_register(&zero_module); + module_register(&fb0_module); + module_register(&kbd_dev_module); + module_register(&mouse0_module); + module_register(&tty0_module); + module_register(&urandom_module); + module_register(&random_module); + log("[MOD]", "found ", d); int count = module_get_count(); str_append_uint(buf, count); @@ -347,14 +350,21 @@ void _start(void) #if HARDWARE_SC == 1 // let the cpu rest a small time for (volatile int i = 0; i < 1000000; i++) { - __asm__ volatile("nop"); + __asm__ volatile("nop"); } #endif } //hcf(); - extern void kproc(void); - kproc(); + for (volatile int i = 0; i < 100000; i++) { + __asm__ volatile("nop"); + } + + //extern void kproc(void); + genprocs(); + proc_list_procs(proc_mgr); + dump_kprocesses(); + //hcf(); DEinit(); //should not reach here @@ -365,4 +375,4 @@ void _start(void) panic("USE_HCF; FAILED --> USING PANIC"); #endif -}; +} \ No newline at end of file diff --git a/src/kernel/kernel_processes/bootscreen/boot.c b/src/kernel/kernel_processes/bootscreen/boot.c new file mode 100644 index 0000000..4b9936f --- /dev/null +++ b/src/kernel/kernel_processes/bootscreen/boot.c @@ -0,0 +1,36 @@ +#include "boot.h" +#include + +// all the print function will be migrated to this file +// because currently the console is a part of the screen (like console_scrollup) +// and this is bad thats why i create kernel processes and the bootscreen process +// which will handle all bootup messages and also the scroll up (and mb login) + +static int bs_init(kproc_t *self) { + (void)self; + printf("[BOOTSCREEN] init\n"); + return KPROC_EFINE; +} + +static int bs_tick(kproc_t *self) { + (void)self; + return KPROC_EFINE; +} + +static void bs_fini(kproc_t *self) { + (void)self; +} + +kproc_t bootscreen_proc = { + .name = "bootscreen", + .state = KPROC_STATE_READY, + .flags = KPROC_FLAG_EARLY | KPROC_FLAG_CRITICAL | KPROC_FLAG_PERMANENT, + .priority = 128, + .init = bs_init, + .tick = bs_tick, + .fini = bs_fini, +}; + +void init_bootscreen(void) { + kproc_register_and_start(&bootscreen_proc); +} diff --git a/src/kernel/kernel_processes/bootscreen/boot.h b/src/kernel/kernel_processes/bootscreen/boot.h new file mode 100644 index 0000000..9f37305 --- /dev/null +++ b/src/kernel/kernel_processes/bootscreen/boot.h @@ -0,0 +1,10 @@ +#ifndef BOOT_H +#define BOOT_H + +#include + +extern kproc_t bootscreen_proc; + +void init_bootscreen(void); + +#endif diff --git a/src/kernel/kernel_processes/bootscreen/console/console.c b/src/kernel/kernel_processes/bootscreen/console/console.c new file mode 100644 index 0000000..0c36ec9 --- /dev/null +++ b/src/kernel/kernel_processes/bootscreen/console/console.c @@ -0,0 +1,6 @@ +#include "console.h" + +void cprintf(const char *str, u32 color) +{ + string(str, color); +} \ No newline at end of file diff --git a/src/kernel/kernel_processes/bootscreen/console/console.h b/src/kernel/kernel_processes/bootscreen/console/console.h new file mode 100644 index 0000000..b593e2e --- /dev/null +++ b/src/kernel/kernel_processes/bootscreen/console/console.h @@ -0,0 +1,6 @@ +#pragma once + +#include +//#include "../print.h" + +void cprintf(const char *str, u32 color); \ No newline at end of file diff --git a/src/kernel/kernel_processes/bootscreen/log.c b/src/kernel/kernel_processes/bootscreen/log.c new file mode 100644 index 0000000..f541263 --- /dev/null +++ b/src/kernel/kernel_processes/bootscreen/log.c @@ -0,0 +1,158 @@ +#include "log.h" +#include +#include +#include +#include +#include + +static u32 get_log_color(log_level_t level) { + switch (level) { + case LSUCCESS: + return LCOLOR_SCS; + case LWARNING: + return LCOLOR_WAR; + case LERROR: + return LCOLOR_ERR; + case LDEF: + default: + return LCOLOR_D; + } +} +static u32 get_tag_color(log_level_t level) { + switch (level) { + case LDEBUG_TAG: + return GFX_GRAY_70; + default: + return LCOLOR_TAG; + } +} + + +void log_message(const char *tag, const char *message, log_level_t level) { + if (!tag || !message) return; + + #if BOOTUP_VISUALS == 0 + + u32 msg_color = get_log_color(level); + u32 tag_color = get_tag_color(level); + + // gray + //print("[", LCOLOR_BRACKET); + + print(tag, tag_color); + print(" ", LCOLOR_BRACKET); + print(message, msg_color); + //printf("%s %s", tag, message); + #endif + //printf("%s", str); +} +void log_printf(log_level_t level, const char *tag, const char *format, ...) { + if (!tag || !format) return; + + #if BOOTUP_VISUALS == 0 + + u32 msg_color = get_log_color(level); + u32 tag_color = get_tag_color(level); + + // gray + //print("[", LCOLOR_BRACKET); + print(tag, tag_color); + print(" ", LCOLOR_BRACKET); + + va_list args; + va_start(args, format); + char buffer[512]; + int pos = 0; + + // formated string + for (const char *p = format; *p && pos < 511; p++) { + if (*p == '%' && *(p + 1)) { + p++; + switch (*p) { + case 's': { + const char *s = va_arg(args, const char*); + if (s) { + while (*s && pos < 511) { + buffer[pos++] = *s++; + } + } + break; + } + case 'd': + case 'i': { + int val = va_arg(args, int); + char num_buf[32]; + str_from_int(num_buf, val); + for (char *n = num_buf; *n && pos < 511; n++) { + buffer[pos++] = *n; + } + break; + } + case 'u': { + u32 val = va_arg(args, u32); + char num_buf[32]; + num_buf[0] = '\0'; + str_append_uint(num_buf, val); + for (char *n = num_buf; *n && pos < 511; n++) { + buffer[pos++] = *n; + } + break; + } + case 'x': + case 'X': { + u32 val = va_arg(args, u32); + char hex_buf[16]; + int hex_pos = 0; + if (val == 0) { + hex_buf[hex_pos++] = '0'; + } else { + u32 temp = val; + while (temp > 0 && hex_pos < 15) { + int digit = temp % 16; + hex_buf[hex_pos++] = (digit < 10) ? ('0' + digit) : ('a' + digit - 10); + temp /= 16; + } + } + hex_buf[hex_pos] = '\0'; + // reverse hex string + for (int i = hex_pos - 1; i >= 0 && pos < 511; i--) { + buffer[pos++] = hex_buf[i]; + } + break; + } + case 'c': { + char c = (char)va_arg(args, int); + if (pos < 511) { + buffer[pos++] = c; + } + break; + } + case '%': { + if (pos < 511) { + buffer[pos++] = '%'; + } + break; + } + default: + if (pos < 511) { + buffer[pos++] = '%'; + } + if (pos < 511) { + buffer[pos++] = *p; + } + break; + } + } else { + buffer[pos++] = *p; + } + } + + buffer[pos] = '\0'; + va_end(args); + + + + print(buffer, msg_color); + //printf("%s", buffer); + #endif +} diff --git a/shared/string/log.h b/src/kernel/kernel_processes/bootscreen/log.h similarity index 94% rename from shared/string/log.h rename to src/kernel/kernel_processes/bootscreen/log.h index 0920ceb..1b02155 100644 --- a/shared/string/log.h +++ b/src/kernel/kernel_processes/bootscreen/log.h @@ -9,11 +9,13 @@ typedef enum { LDEF = 0, LSUCCESS, LWARNING, - LERROR + LERROR, + LDEBUG_TAG } log_level_t; // Keywords for log levels #define d LDEF +#define _d LDEBUG_TAG #define success LSUCCESS #define warning LWARNING #define error LERROR diff --git a/shared/string/print.c b/src/kernel/kernel_processes/bootscreen/print.c similarity index 68% rename from shared/string/print.c rename to src/kernel/kernel_processes/bootscreen/print.c index dce8ecb..d120295 100644 --- a/shared/string/print.c +++ b/src/kernel/kernel_processes/bootscreen/print.c @@ -1,11 +1,12 @@ #include "print.h" #include -#include +#include #include //#include -#include +//#include +// made by Dexoron Feb. 18, 2026 // Decode one UTF-8 sequence and return pointer to next byte. // On invalid data, returns '?' and advances by one byte. static const char *utf8_next_codepoint(const char *p, u32 *codepoint) @@ -101,48 +102,62 @@ static const char *utf8_next_codepoint(const char *p, u32 *codepoint) static void putchar_at(u32 codepoint, u32 x, u32 y, u32 color) { - u32 char_width = fm_get_char_width(); + u32 char_width = fm_get_char_width(); u32 char_height = fm_get_char_height(); - u32 row_bytes = fm_get_glyph_row_bytes(); - u32 lsb_left = fm_get_glyph_lsb_left(); + u32 row_bytes = fm_get_glyph_row_bytes(); + u32 lsb_left = fm_get_glyph_lsb_left(); + u32 pitch_dwords = fb_pitch / 4; + u32 bg_color = bg(); const u8 *glyph = fm_get_glyph_cp(codepoint); if (!glyph) return; + for (u32 dy = 0; dy < char_height; dy++) { - u32 row = 0; + u32 row_bits = 0; const u8 *row_ptr = glyph + (dy * row_bytes); if (row_bytes == 1) { - row = row_ptr[0]; + row_bits = row_ptr[0]; } else if (row_bytes == 2) { - row = (u32)((u16)row_ptr[0] | ((u16)row_ptr[1] << 8)); + row_bits = (u32)row_ptr[0] | ((u32)row_ptr[1] << 8); } else if (row_bytes == 4) { - row = (u32)row_ptr[0] | - ((u32)row_ptr[1] << 8) | - ((u32)row_ptr[2] << 16) | - ((u32)row_ptr[3] << 24); + row_bits = (u32)row_ptr[0] | ((u32)row_ptr[1] << 8) | + ((u32)row_ptr[2] << 16) | ((u32)row_ptr[3] << 24); } else { return; } - for (u32 dx = 0; dx < char_width; dx++) - { - u32 bit_index = lsb_left ? dx : ((char_width - 1u) - dx); - if (row & (1u << bit_index)) - { - for (u32 sy = 0; sy < font_scale; sy++) { - for (u32 sx = 0; sx < font_scale; sx++) { - putpixel(x + dx * font_scale + sx, y + dy * font_scale + sy, color); - } + for (u32 sy = 0; sy < font_scale; sy++) { + u32 *fb_row = framebuffer + (y + dy * font_scale + sy) * pitch_dwords + x; + for (u32 dx = 0; dx < char_width; dx++) { + u32 bit_index = lsb_left ? dx : ((char_width - 1u) - dx); + u32 pixel_color = (row_bits & (1u << bit_index)) ? color : bg_color; + for (u32 sx = 0; sx < font_scale; sx++) { + fb_row[dx * font_scale + sx] = pixel_color; } } } } } +static void bs_scroll(u32 line_height) { + u32 fb_h = get_fb_height(); + u32 pitch_dwords = get_fb_pitch() / 4; + u32 *fb = get_framebuffer(); + + // single memmove shifts the entire framebuffer at once (much faster than row-by-row on real hardware) + memmove(fb, + fb + line_height * pitch_dwords, + (fb_h - line_height) * pitch_dwords * sizeof(u32)); + + // clear bottom lines with memset (bg is black = 0) + memset(fb + (fb_h - line_height) * pitch_dwords, 0, + line_height * pitch_dwords * sizeof(u32)); +} + static void putcodepoint(u32 codepoint, u32 color) { - u32 char_width = fm_get_char_width() * font_scale; + u32 char_width = fm_get_char_width() * font_scale; u32 char_height = fm_get_char_height() * font_scale; u32 char_spacing = char_width; u32 line_height = char_height + 2 * font_scale; @@ -151,7 +166,11 @@ static void putcodepoint(u32 codepoint, u32 color) { cursor_x = 0; cursor_y += line_height; - console_window_check_scroll(); + // scroll only once, right here + if (cursor_y + char_height > fb_height) { + bs_scroll(line_height); + cursor_y -= line_height; + } return; } @@ -159,11 +178,14 @@ static void putcodepoint(u32 codepoint, u32 color) { cursor_x = 0; cursor_y += line_height; - console_window_check_scroll(); + // scroll only once, right here + if (cursor_y + char_height > fb_height) { + bs_scroll(line_height); + cursor_y -= line_height; + } } - console_window_check_scroll(); - + // removed the third redundant scroll check that was here before drawing putchar_at(codepoint, cursor_x, cursor_y, color); cursor_x += char_spacing; } @@ -240,15 +262,21 @@ void IntToString(int value, char *buffer) void printInt(int value, u32 color) { - char buffer[12]; - IntToString(value, buffer); - string(buffer, color); + #if BOOTUP_VISUALS == 0 + char buffer[12]; + IntToString(value, buffer); + string(buffer, color); + #endif + //printf("%s", value); } void print(const char *str, u32 color) { - string(str, color); - //putchar('\n', color); + #if BOOTUP_VISUALS == 0 + string(str, color); + //putchar('\n', color); + #endif + //printf("%s", str); } void reset_cursor(void) diff --git a/shared/string/print.h b/src/kernel/kernel_processes/bootscreen/print.h similarity index 82% rename from shared/string/print.h rename to src/kernel/kernel_processes/bootscreen/print.h index a1a9829..5f29982 100644 --- a/shared/string/print.h +++ b/src/kernel/kernel_processes/bootscreen/print.h @@ -3,6 +3,8 @@ #include +#include "console/console.h" + void putchar_bootstrap(char c, u32 color); void printbs(const char *str, u32 color); @@ -11,6 +13,7 @@ void putchar(char c, u32 color); void string(const char *str, u32 color); void print(const char *str, u32 color); void printInt(int value, u32 color); +//void cprintf(const char *str, u32 color); void reset_cursor(void); diff --git a/shared/string/print_b.c b/src/kernel/kernel_processes/bootscreen/print_b.c similarity index 63% rename from shared/string/print_b.c rename to src/kernel/kernel_processes/bootscreen/print_b.c index a60baa6..5f5c9ed 100644 --- a/shared/string/print_b.c +++ b/src/kernel/kernel_processes/bootscreen/print_b.c @@ -2,24 +2,25 @@ #include #include #include -#include static void putchar_bootstrap_at(char c, u32 x, u32 y, u32 color) { const u8 *glyph = font_8x8_bold[(u8)c]; + u32 pitch_dwords = fb_pitch / 4; + // bootstrap phase uses black background + u32 bg_color = 0x00000000; for (int dy = 0; dy < 8; dy++) { u8 row = glyph[dy]; - for (int dx = 0; dx < 8; dx++) - { - if (row & (1 << (7 - dx))) - { - // Draw scaled pixel - for (u32 sy = 0; sy < font_scale; sy++) { - for (u32 sx = 0; sx < font_scale; sx++) { - putpixel(x + dx * font_scale + sx, y + dy * font_scale + sy, color); - } + // draw font_scale scanlines per glyph row + for (u32 sy = 0; sy < font_scale; sy++) { + u32 *fb_row = framebuffer + (y + dy * font_scale + sy) * pitch_dwords + x; + for (int dx = 0; dx < 8; dx++) { + // draw both fg and bg in single pass + u32 pixel_color = (row & (1 << (7 - dx))) ? color : bg_color; + for (u32 sx = 0; sx < font_scale; sx++) { + fb_row[dx * font_scale + sx] = pixel_color; } } } @@ -40,7 +41,7 @@ void putchar_bootstrap(char c, u32 color) return; } - // Check if we need to wrap to next line + // check if we need to wrap to next line if (cursor_x + char_width >= fb_width) { cursor_x = 0; // past was 20 diff --git a/src/kernel/kernel_processes/dump.c b/src/kernel/kernel_processes/dump.c new file mode 100644 index 0000000..4b61492 --- /dev/null +++ b/src/kernel/kernel_processes/dump.c @@ -0,0 +1,16 @@ +#include "loader.h" + +#include +#include + +// only reason that this is in a extra file is cuz i want to make it more advanced... but not yet... + +void dump_kprocesses(void) { + printf("[KPROC] table (%d/%d)\n", kproc_cnt, KPROC_MAX); + for (int i = 0; i < kproc_cnt; i++) { + kproc_t *p = kproc_table[i]; + if (!p) continue; + printf(" [%d] %-20s (%-8s) (%d) flags=0x%02X\n", + i, p->name, state_str(p->state), p->priority, p->flags); + } +} diff --git a/src/kernel/graph/fm.c b/src/kernel/kernel_processes/fm/fm.c similarity index 87% rename from src/kernel/graph/fm.c rename to src/kernel/kernel_processes/fm/fm.c index 85e7654..50eeabb 100644 --- a/src/kernel/graph/fm.c +++ b/src/kernel/kernel_processes/fm/fm.c @@ -4,9 +4,19 @@ #include #include #include +#include + static font_type_t current_font_type = FONT_8X8_BOLD; // default font static const font_t *current_font = NULL; +/* + * the font manager doesnt use the kernel process manager + * but its still a 'process' in kinda way... like its used for graphics + */ + + /* + * unicode_to_glyph_index made by dexoron 18.2.2026 + */ static u32 unicode_to_glyph_index(u32 cp) { if (cp == 0x00A0) return (u32)' '; // NBSP @@ -34,9 +44,9 @@ void fm_init(void) { BOOTUP_PRINTBS("[FM] ", GFX_GRAY_70); BOOTUP_PRINTBS("start font manager\n", white()); - // default font is DOS font - current_font_type = FONT_8X8_BOLD; - current_font = &font_registry[FONT_8X8_BOLD]; + // default font + current_font_type = CURRENT_FONT; + current_font = &font_registry[CURRENT_FONT]; BOOTUP_PRINTBS("[FM] ", GFX_GRAY_70); BOOTUP_PRINTBS("default: ", white()); @@ -55,6 +65,9 @@ int f_setcontext(font_type_t font_type) current_font_type = font_type; current_font = &font_registry[font_type]; + // do not print font switch messages during panic + if (getcontext() == THEME_PANIC) return 0; + BOOTUP_PRINT("[FM] ", GFX_GRAY_70); BOOTUP_PRINT("switched to: ", white()); BOOTUP_PRINT(current_font->name, GFX_ST_CYAN); diff --git a/src/kernel/graph/fm.h b/src/kernel/kernel_processes/fm/fm.h similarity index 92% rename from src/kernel/graph/fm.h rename to src/kernel/kernel_processes/fm/fm.h index 072608f..c3a8872 100644 --- a/src/kernel/graph/fm.h +++ b/src/kernel/kernel_processes/fm/fm.h @@ -4,6 +4,8 @@ #include #include +#define CURRENT_FONT FONT_8X8 + void fm_init(void); int f_setcontext(font_type_t font_type); font_type_t fm_get_current_font(void); diff --git a/src/kernel/kernel_processes/graphics/.gitkeep b/src/kernel/kernel_processes/graphics/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/kernel/kernel_processes/kernel/gen.h b/src/kernel/kernel_processes/kernel/gen.h new file mode 100644 index 0000000..1a8dd56 --- /dev/null +++ b/src/kernel/kernel_processes/kernel/gen.h @@ -0,0 +1,35 @@ +#ifndef GEN_HEADER +#define GEN_HEADER + + +#include "../loader.h" + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#if ENABLE_ULIME +extern proc_manager_t *proc_mgr; +extern ulime_t *ulime; +#endif + +void kproc(void); +void init_kernelprocesses2(void); +void uproc(void); +void genprocs(void); + +#endif diff --git a/src/kernel/kernel_processes/kernel/kproc.c b/src/kernel/kernel_processes/kernel/kproc.c new file mode 100644 index 0000000..6ed3ff4 --- /dev/null +++ b/src/kernel/kernel_processes/kernel/kproc.c @@ -0,0 +1,86 @@ +#include "gen.h" + +/*#if ENABLE_ULIME +extern proc_manager_t *proc_mgr; +extern ulime_t *ulime; +#endif +*/ + +static int kernelprocesses2_init(kproc_t *self) { + (void)self; + printf("[KERNELPROCESSES2] initialising...\n"); + kproc(); + return KPROC_EFINE; +} + +static int kernelprocesses2_tick(kproc_t *self) { + (void)self; + return KPROC_EFINE; +} + +static void kernelprocesses2_fini(kproc_t *self) { + (void)self; +} + + +/* +// create a process for the kernel +// if proc: kernel == quit the system stops/halt/crashes idk +void create_kernel_process(ulime_t *ulime, proc_manager_t *proc_mgr) +{ + ulime_proc_t *kernel_proc = ulime_proc_create( + ulime, + (u8*)"kernel", + (u64)kmain + ); + + kernel_proc->priority = 255; + kernel_proc->state = PROC_READY; + kernel_proc->is_critical = 1; + + // register process manager + proc_add(proc_mgr, kernel_proc); + + log("[KPROC]", "Kernel process created\n", 0); +} +*/ + +void kproc(void ) { + + #if ENABLE_ULIME && RUNTESTS // set to 1 to enable test + //BOOTUP_PRINT("test RUNTESTS block\n", white()); + if (proc_mgr){ + ulime_proc_t *p1 = proc_create_proc(proc_mgr, (u8*)KERNELPROC, KERNELSPACE, KERNELPRIORITY); + ulime_proc_t *p2 = proc_create_proc(proc_mgr, (u8*)"__rt", 0x40001000, 2); // run tests + + log("[KPROC]", "creating test processes\n", d); + if (p1) log("[KPROC]", "created kernel\n", d); + if (p2) log("[KPROC]", "created __rt\n", d); + + //proc_list_procs(proc_mgr); + + //log("[TEST_CODE]", "loading test code:\n", d); + //ulime_load_program(p4, test_code, sizeof(test_code)); + //log("[TEST_CODE]", "test code loaded successfully\n", d); + //JumpToUserspace(p4); + log("[KPROC]", "Kernel processes created\n", d); + } + //proc_list_procs(proc_mgr); + #endif + +}; +//void kproc(void); +// +kproc_t kernelprocesses2_proc = { + .name = "kproc_kernel", + .state = KPROC_STATE_READY, + .flags = KPROC_FLAG_EARLY | KPROC_FLAG_CRITICAL | KPROC_FLAG_PERMANENT, + .priority = 255, + .init = kernelprocesses2_init, + .tick = kernelprocesses2_tick, + .fini = kernelprocesses2_fini, +}; + +void init_kernelprocesses2(void) { + kproc_register_and_start(&kernelprocesses2_proc); +} diff --git a/src/kernel/kernel_processes/kernel/procs.c b/src/kernel/kernel_processes/kernel/procs.c new file mode 100644 index 0000000..e25d54b --- /dev/null +++ b/src/kernel/kernel_processes/kernel/procs.c @@ -0,0 +1,7 @@ +#include "gen.h" + +void genprocs(void) { + //kproc(); + init_kernelprocesses2(); + uproc(); +} diff --git a/src/kernel/kernel_processes/kernel/user.c b/src/kernel/kernel_processes/kernel/user.c new file mode 100644 index 0000000..3cecb41 --- /dev/null +++ b/src/kernel/kernel_processes/kernel/user.c @@ -0,0 +1,45 @@ +#include "gen.h" +#include + +// path to the init app in the VFS (loaded from initrd.cpio) +#define SYSTEMLOCATE "/emr/system/system.emx" +//mod +//#define LOGINLOCATE "/emr/bin/login.elf" + +void uproc(void) { + #if ENABLE_ULIME + if (!proc_mgr || !ulime) { + log("[INIT]", "proc_mgr or ulime not ready\n", error); + return; + } + + log("[INIT]", "loading " SYSTEMLOCATE "...\n", d); + + ulime_proc_t *init_proc = NULL; + int result = emex_launch_app(SYSTEMLOCATE, &init_proc); + + if (result != EMEX_OK || !init_proc) { + log("[INIT]", "failed to load " SYSTEMLOCATE "\n", error); + log("[INIT]", "system cannot continue without init\n", error); + //while (1) __asm__ volatile("cli; hlt"); + // hcf(); + } + + log("[INIT]", "jumping to userspace\n", success); + + //first clear screen + clear(0xff000000); + + dump_kprocesses(); + proc_list_procs(proc_mgr); + ulime->ptr_proc_curr = init_proc; + #if JUMPTOUSER == 1 + JumpToUserspace(init_proc); + #endif + + + __builtin_unreachable(); + + //proc_list_procs(proc_mgr); + #endif +} diff --git a/src/kernel/kernel_processes/loader.c b/src/kernel/kernel_processes/loader.c new file mode 100644 index 0000000..fd57bf0 --- /dev/null +++ b/src/kernel/kernel_processes/loader.c @@ -0,0 +1,110 @@ +#include "loader.h" + +#include +#include + +kproc_t *kproc_table[KPROC_MAX]; +int kproc_cnt = 0; +int kproc_init_done = 0; + +const char *state_str(u8 s) { + switch (s) { + case KPROC_STATE_EMPTY: return "EMPTY"; + case KPROC_STATE_READY: return "READY"; + case KPROC_STATE_RUNNING: return "RUNNING"; + case KPROC_STATE_BLOCKED: return "BLOCKED"; + case KPROC_STATE_DONE: return "DONE"; + case KPROC_STATE_FAILED: return "FAILED"; + default: return "?"; + } +} + + +void kproc_loader_init(void) { + for (int i = 0; i < KPROC_MAX; i++) + kproc_table[i] = NULL; + kproc_cnt = 0; + kproc_init_done = 1; +} +int kproc_register(kproc_t *proc) { + if (!proc) return -1; + if (!kproc_init_done) kproc_loader_init(); + if (kproc_cnt >= KPROC_MAX) return -1; + + int id = kproc_cnt; + proc->id = (u32)id; + proc->state = KPROC_STATE_READY; + + kproc_table[id] = proc; + kproc_cnt++; + return id; +} +int kproc_start(u32 id) { + if (id >= (u32)kproc_cnt) return KPROC_ERROR; + kproc_t *p = kproc_table[id]; + if (!p) return KPROC_ERROR; + if (p->state != KPROC_STATE_READY) return KPROC_ERROR; + + p->state = KPROC_STATE_RUNNING; + + if (p->init) { + int r = p->init(p); + if (r == KPROC_ERROR) { + p->state = KPROC_STATE_FAILED; + if (p->fini) p->fini(p); + return KPROC_ERROR; + } + } + return KPROC_EFINE; +} +int kproc_register_and_start(kproc_t *proc) { + int id = kproc_register(proc); + if (id < 0) return -1; + if (kproc_start((u32)id) != KPROC_EFINE) return -1; + return id; +} +int kproc_tick(u32 id) { + if (id >= (u32)kproc_cnt) return KPROC_ERROR; + kproc_t *p = kproc_table[id]; + if (!p || p->state != KPROC_STATE_RUNNING) return KPROC_ERROR; + if (!p->tick) return KPROC_EFINE; + + int r = p->tick(p); + + if (r == KPROC_ERROR) { + p->state = KPROC_STATE_FAILED; + if (p->fini) p->fini(p); + } else if (r != KPROC_EFINE && r != KPROC_YIELD) { + if (!(p->flags & KPROC_FLAG_PERMANENT)) { + p->state = KPROC_STATE_DONE; + if (p->fini) p->fini(p); + } + } + return r; +} +void kproc_stop(u32 id) { + if (id >= (u32)kproc_cnt) return; + kproc_t *p = kproc_table[id]; + if (!p || p->state == KPROC_STATE_DONE) return; + if (p->fini) p->fini(p); + p->state = KPROC_STATE_DONE; +} + + +kproc_t *kproc_get(u32 id) { + if (id >= (u32)kproc_cnt) return NULL; + return kproc_table[id]; +} +kproc_t *kproc_find_by_name(const char *name) { + if (!name) return NULL; + for (int i = 0; i < kproc_cnt; i++) { + if (kproc_table[i] && str_equals(kproc_table[i]->name, name)) + return kproc_table[i]; + } + return NULL; +} + + +int count_kernelprocesses(void) { + return kproc_cnt; +} diff --git a/src/kernel/kernel_processes/loader.h b/src/kernel/kernel_processes/loader.h new file mode 100644 index 0000000..88aac94 --- /dev/null +++ b/src/kernel/kernel_processes/loader.h @@ -0,0 +1,65 @@ +#ifndef KPROC_LOADER_H +#define KPROC_LOADER_H + +#include + +#define KPROC_MAX 255 +#define KPROC_NAME_LEN 15 + +// states +#define KPROC_STATE_EMPTY 0 +#define KPROC_STATE_READY 1 +#define KPROC_STATE_RUNNING 2 +#define KPROC_STATE_BLOCKED 3 +#define KPROC_STATE_DONE 4 +#define KPROC_STATE_FAILED 5 + +// flags +#define KPROC_FLAG_NONE 0x00 +#define KPROC_FLAG_EARLY 0x01 +#define KPROC_FLAG_CRITICAL 0x02 +#define KPROC_FLAG_PERMANENT 0x04 + +// return codes +#define KPROC_EFINE 0 +#define KPROC_ERROR -1 +#define KPROC_YIELD 1 + +typedef struct kproc kproc_t; + +typedef int (*kproc_init_fn)(kproc_t *self); +typedef int (*kproc_tick_fn)(kproc_t *self); +typedef void (*kproc_fini_fn)(kproc_t *self); + +struct kproc { + char name[KPROC_NAME_LEN]; + u8 state; + u8 flags; + u8 priority; + u8 _pad; + kproc_init_fn init; + kproc_tick_fn tick; + kproc_fini_fn fini; + void *priv; + u32 id; +}; + +extern kproc_t *kproc_table[KPROC_MAX]; +extern int kproc_cnt; +extern int kproc_init_done; + +const char *state_str(u8 s); + +void kproc_loader_init(void); +int kproc_register(kproc_t *proc); +int kproc_start(u32 id); +int kproc_register_and_start(kproc_t *proc); +int kproc_tick(u32 id); +void kproc_stop(u32 id); +kproc_t *kproc_get(u32 id); +kproc_t *kproc_find_by_name(const char *name); + +int count_kprocesses(void); +void dump_kprocesses(void); + +#endif diff --git a/src/kernel/graph/theme.c b/src/kernel/kernel_processes/tm/theme.c similarity index 100% rename from src/kernel/graph/theme.c rename to src/kernel/kernel_processes/tm/theme.c diff --git a/src/kernel/kernel_processes/tm/theme.h b/src/kernel/kernel_processes/tm/theme.h new file mode 100644 index 0000000..5270c6c --- /dev/null +++ b/src/kernel/kernel_processes/tm/theme.h @@ -0,0 +1,74 @@ +#ifndef THEME_H +#define THEME_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// theme types +typedef enum { + THEME_STD = 0, + THEME_FLU = 1 +} ThemeType; +//context types +typedef enum { + THEME_BOOTUP = 0, + THEME_CONSOLE = 1, + THEME_PANIC = 2 +} ThemeContext; + +// unified naming +typedef enum { + COLOR_BLACK = 0, + COLOR_BG, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW, + COLOR_BLUE, + COLOR_PURPLE, + COLOR_CYAN, + COLOR_WHITE +} ThemeColor; +typedef struct { + u32 BLACK; + u32 BG; + u32 RED; + u32 GREEN; + u32 YELLOW; + u32 BLUE; + u32 PURPLE; + u32 CYAN; + u32 WHITE; +} ThemeColors; + + +void theme_init(); +void setcontext(ThemeContext context); +ThemeContext getcontext(); + +void sbootup_theme(ThemeType type); +//void sconsole_theme(ThemeType type); +void spanic_theme(ThemeType type); +void reload_console_theme(void); + +u32 get_color(ThemeColor color); + + +// current colors from theme +u32 black(); +u32 bg(); +u32 red(); +u32 green(); +u32 yellow(); +u32 blue(); +u32 purple(); +u32 cyan(); +u32 white(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/kernel/kernelslot/slot.c b/src/kernel/kernelslot/slot.c index 0fe293e..8081680 100644 --- a/src/kernel/kernelslot/slot.c +++ b/src/kernel/kernelslot/slot.c @@ -1,6 +1,5 @@ #include #include -#include #include char readslot(void) diff --git a/src/kernel/kernelslot/slot_write.c b/src/kernel/kernelslot/slot_write.c new file mode 100644 index 0000000..014fe97 --- /dev/null +++ b/src/kernel/kernelslot/slot_write.c @@ -0,0 +1,18 @@ +#include "slot.h" +#include +#include +#include +#include + +#define LIMINE_CONF_PATH "/boot/limine/limine.conf" +#define LIMINE_CONF_BUFSIZE 4096 + +int slot_write_limine_conf(char slot) +{ + if (slot != 'A' && slot != 'B') return -1; + + int target_entry = (slot == 'A') ? 0 : 1; + (void)target_entry; + + return 0; +} \ No newline at end of file diff --git a/src/kernel/kproc.c b/src/kernel/kproc.c deleted file mode 100644 index 40426f4..0000000 --- a/src/kernel/kproc.c +++ /dev/null @@ -1,118 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#if ENABLE_ULIME -extern proc_manager_t *proc_mgr; -extern ulime_t *ulime; -#endif - - -/* -// create a process for the kernel -// if proc: kernel == quit the system stops/halt/crashes idk -void create_kernel_process(ulime_t *ulime, proc_manager_t *proc_mgr) -{ - ulime_proc_t *kernel_proc = ulime_proc_create( - ulime, - (u8*)"kernel", - (u64)kmain - ); - - kernel_proc->priority = 255; - kernel_proc->state = PROC_READY; - kernel_proc->is_critical = 1; - - // register process manager - proc_add(proc_mgr, kernel_proc); - - log("[KPROC]", "Kernel process created\n", 0); -} -*/ - -void kproc(void ) { - - #if ENABLE_ULIME && RUNTESTS // set to 1 to enable test - //BOOTUP_PRINT("test RUNTESTS block\n", white()); - if (proc_mgr){ - ulime_proc_t *p1 = proc_create_proc(proc_mgr, (u8*)KERNELPROC, KERNELSPACE, KERNELPRIORITY); - ulime_proc_t *p2 = proc_create_proc(proc_mgr, (u8*)"__rt", 0x40001000, 2); // run tests - - log("[KPROC]", "creating test processes\n", d); - if (p1) log("[KPROC]", "created kernel\n", d); - if (p2) log("[KPROC]", "created __rt\n", d); - - //proc_list_procs(proc_mgr); - - //log("[TEST_CODE]", "loading test code:\n", d); - //ulime_load_program(p4, test_code, sizeof(test_code)); - //log("[TEST_CODE]", "test code loaded successfully\n", d); - //JumpToUserspace(p4); - log("[KPROC]", "Kernel processes created\n", d); - } - if ( - proc_mgr && - ulime && - module_request.response && - module_request.response->module_count - > 0){ - - ulime_proc_t *p4 = proc_create_proc(proc_mgr, (u8*)USERPROC, USERSPACE, USERPRIORITY); - if (p4) log("[KPROC]", "created user process\n", d); - #define USERPROGRAMMSPACE 0x40004200 - #define USERPROGRAMMPRIORITY 1 - - struct limine_module_response *mod_resp = module_request.response; - struct limine_file *hello_mod = NULL; - - for (u64 i = 0; i < mod_resp->module_count; i++) { - const char *path = mod_resp->modules[i]->path; - if (str_contains((char*)path, "hello.elf")) { - hello_mod = mod_resp->modules[i]; - break; - } - } - - if (hello_mod) - { - log("[ELF]", "found hello.elf module\n", d); - - ulime_proc_t *proc = proc_create_proc(proc_mgr, (u8*)"hello", USERPROGRAMMSPACE, USERPROGRAMMPRIORITY); - if (proc) - { - u8 *elf_data = (u8*)hello_mod->address; - u64 elf_size = hello_mod->size; - - if (elf_load(proc, elf_data, elf_size) == 0) { - ulime->ptr_proc_curr = proc; - log("[ELF]", "jumping to userspace\n", d); - u64 user_rsp = (proc->stack_base + proc->stack_size - 16) & ~0xFULL; - - verify_page_permissions(proc->ulime->hpr, proc->entry_point, "Code page"); - verify_page_permissions(proc->ulime->hpr, user_rsp, "Stack page"); - verify_gdt_setup(); - //JumpToUserspace(proc); - } - } - } else { - log("[ELF]", "hello.elf not found in ramfs\n", error); - } - } - proc_list_procs(proc_mgr); - #endif - -}; -//void kproc(void); diff --git a/src/kernel/mem/glime/glime.c b/src/kernel/mem/glime/glime.c index be56230..1cc5244 100644 --- a/src/kernel/mem/glime/glime.c +++ b/src/kernel/mem/glime/glime.c @@ -117,9 +117,9 @@ void glime_commit(glime_t *glime) { //clear all - for (int i = 0; i < glime->dirty_boxes_len; i++) { + for (u64 i = 0; i < glime->dirty_boxes_len; i++) { gbox_t db = glime->dirty_boxes[i]; - for (int y = 0; y < db.height; y++) { + for (u64 y = 0; y < db.height; y++) { u32 src_offset = (db.y + y) * glime->glres.width + db.x; u32 dst_offset = (db.y + y) * pitch_pixels + db.x; memset(&fb[dst_offset], 0, db.width * sizeof(u32)); @@ -203,4 +203,4 @@ void glime_keyboard_handler(glime_t *glime) { glime_commit(glime); } -} +} \ No newline at end of file diff --git a/src/kernel/mem/glime/kb.c b/src/kernel/mem/glime/kb.c index c9dc78e..b1e9bba 100644 --- a/src/kernel/mem/glime/kb.c +++ b/src/kernel/mem/glime/kb.c @@ -16,22 +16,6 @@ static const unsigned char scancode_to_ascii[128] = { [0x37]='*',[0x38]=0,[0x39]=' ',[0x3A]=0 }; -static const unsigned char scancode_to_ascii_shift[128] = { - [0x00]=0,[0x01]=0, - [0x02]='!',[0x03]='"',[0x04]='#',[0x05]='$',[0x06]='%', - [0x07]='&',[0x08]='/',[0x09]='(',[0x0A]=')',[0x0B]='=', - [0x0C]='?',[0x0D]='`',[0x0E]=0,[0x0F]=0, - [0x10]='Q',[0x11]='W',[0x12]='E',[0x13]='R',[0x14]='T', - [0x15]='Y',[0x16]='U',[0x17]='I',[0x18]='O',[0x19]='P', - [0x1A]=0x82,[0x1B]='*',[0x1C]='\n',[0x1D]=0, - [0x1E]='A',[0x1F]='S',[0x20]='D',[0x21]='F',[0x22]='G', - [0x23]='H',[0x24]='J',[0x25]='K',[0x26]='L',[0x27]=0x81, - [0x28]=0x80,[0x29]='>',[0x2A]=0,[0x2B]='\'',[0x2C]='Z', - [0x2D]='X',[0x2E]='C',[0x2F]='V',[0x30]='B',[0x31]='N', - [0x32]='M',[0x33]=';',[0x34]=':',[0x35]='_',[0x36]=0, - [0x37]='*',[0x38]=0,[0x39]=' ',[0x3A]=0 -}; - glime_keyboardrb_t *glime_keyboard_init(glime_t *glime, u64 count) { if (!glime || count == 0) return NULL; @@ -80,4 +64,4 @@ int keyboard_next(glime_keyboardrb_t *kbrb, glime_key_event_t *out) { u8 keyboard_event_to_char(glime_key_event_t event) { if (event.scancode >= 128) return 0; return scancode_to_ascii[event.scancode]; -} +} \ No newline at end of file diff --git a/src/kernel/mem/glime/session.c b/src/kernel/mem/glime/session.c index 6431d76..cc9321c 100644 --- a/src/kernel/mem/glime/session.c +++ b/src/kernel/mem/glime/session.c @@ -31,7 +31,7 @@ gsession_t *gsession_init(glime_t *glime, u8 *name, u64 width) { int gsession_attach(glime_t *glime, gsession_t *gsession, u8 *workspace_name) { if (!glime || !gsession || !workspace_name) return 1; - for (int i = 0; i < glime->workspaces_total; i++) { + for (u64 i = 0; i < glime->workspaces_total; i++) { gworkspace_t *ws = glime->workspaces[i]; u8 *wsname = ws->name; int seek = 0; @@ -64,7 +64,7 @@ int gsession_attach(glime_t *glime, gsession_t *gsession, u8 *workspace_name) { int gsession_detach(gworkspace_t *gworkspace, gsession_t *gsession) { if (!gworkspace || !gsession) return 1; u8 *ssname = gsession->name; - for (int i = 0; i < gworkspace->sessions_total; i++) { + for (u64 i = 0; i < gworkspace->sessions_total; i++) { gsession_t *session = gworkspace->sessions[i]; u8 *ssname_loop = session->name; int seek = 0; @@ -218,4 +218,4 @@ void gsession_put_at_char_dummy(gsession_t *gsession, u8 c, u32 x, u32 y, u32 co } } -} +} \ No newline at end of file diff --git a/src/kernel/mem/glime/workspace.c b/src/kernel/mem/glime/workspace.c index d0b0f3c..6f92d10 100644 --- a/src/kernel/mem/glime/workspace.c +++ b/src/kernel/mem/glime/workspace.c @@ -38,7 +38,7 @@ int gworkspace_init(glime_t *glime, u8 *name, u64 pos) { gworkspace_t *gworkspace_get_name(glime_t *glime, u8 *workspace_name) { if (!glime) return NULL; - for (int i = 0; i < glime->workspaces_total; i++) { + for (u64 i = 0; i < glime->workspaces_total; i++) { gworkspace_t *ws = glime->workspaces[i]; u8 *wsname = ws->name; int seek = 0; @@ -64,7 +64,7 @@ gworkspace_t *gworkspace_get_name(glime_t *glime, u8 *workspace_name) { gworkspace_t *gworkspace_get_pos(glime_t *glime, u64 pos) { if (!glime) return NULL; - for (int i = 0; i < glime->workspaces_total; i++) { + for (u64 i = 0; i < glime->workspaces_total; i++) { gworkspace_t *ws = glime->workspaces[i]; if (ws->pos_y == pos) return ws; } @@ -83,11 +83,10 @@ int gworkspace_posx_get(gworkspace_t *gworkspace, u64 *out) { u64 list_len = gworkspace->sessions_len; u64 ret = 0; - for (int i = 0; i < list_len; i++) { + for (u64 i = 0; i < list_len; i++) { ret += gworkspace->sessions[i]->box.width + gworkspace->gap_x; } *out = ret; return 0; } - diff --git a/src/kernel/mem/klime/klime.c b/src/kernel/mem/klime/klime.c index ec94b17..913fee2 100644 --- a/src/kernel/mem/klime/klime.c +++ b/src/kernel/mem/klime/klime.c @@ -34,6 +34,7 @@ klime_t *klime_init(u64 *ptr, u64 size) { } void klime_setup_slab(klime_t *klime) { + (void)klime; } u64 *klime_create(klime_t *klime, u64 size) { @@ -79,4 +80,4 @@ u64 klime_get_used_size(klime_t *klime) { u64 klime_get_free_size(klime_t *klime) { return klime->total_heap - klime->used_heap; -} +} \ No newline at end of file diff --git a/src/kernel/mem/mem.h b/src/kernel/mem/mem.h index c8eafc9..6b9aaad 100644 --- a/src/kernel/mem/mem.h +++ b/src/kernel/mem/mem.h @@ -10,7 +10,8 @@ typedef struct limine_hhdm_response limine_hhdm_response_t; typedef struct limine_framebuffer_response limine_framebuffer_response_t; typedef struct limine_framebuffer limine_framebuffer_t; -#define HEAP_START 0xFFFF800000000000 // Start of kernel heap +// moved above the HHDM range +#define HEAP_START 0xFFFFA00000000000ULL // Start of kernel heap #define HEAP_SIZE 1024 * 1024 * 32 #define GRAPHICS_START (HEAP_START + HEAP_SIZE) // Start of graphics memory @@ -32,7 +33,7 @@ typedef struct limine_framebuffer limine_framebuffer_t; #define KLIME_OFFSET_HEAP KLIME_OFFSET_DMA + KLIME_SIZE_DMA #define GLIME_SIZE_META (PAGE_SIZE * 256) //2mb -#define GLIME_HEAP_SIZE (GRAPHICS_SIZE - GLIME_SIZE_META) +#define GLIME_HEAP_SIZE (GRAPHICS_SIZE - GLIME_SIZE_META) #define PAGE_SIZE 4096 #define FRAME_FREE 0x00 // Frame is available diff --git a/src/kernel/mem/meminclude.h b/src/kernel/mem/meminclude.h index 0036b7a..ce660ae 100644 --- a/src/kernel/mem/meminclude.h +++ b/src/kernel/mem/meminclude.h @@ -7,5 +7,6 @@ #include #include #include +#include "sfence.h" #endif diff --git a/src/kernel/mem/paging/paging.c b/src/kernel/mem/paging/paging.c index a5b124e..8636671 100644 --- a/src/kernel/mem/paging/paging.c +++ b/src/kernel/mem/paging/paging.c @@ -12,6 +12,8 @@ extern u8 _kernel_start[]; extern u8 _kernel_end[]; +u64 g_hhdm_offset = 0; + page_table_t *kernel_pml4 = NULL; @@ -99,15 +101,45 @@ void paging_map_page( ((physical_addr & 0x000FFFFFFFFFF000) | flags) & ~PTE_NX; // Invalidate TLB entry - asm volatile("invlpg (%0)" : : "r" (virtual_addr) : "memory"); + __asm__ volatile("invlpg (%0)" : : "r" (virtual_addr) : "memory"); } +void paging_unmap_page(u64 virtual_addr) { + u64 pml4_index = (virtual_addr >> 39) & 0x1FF; + u64 pdp_index = (virtual_addr >> 30) & 0x1FF; + u64 pd_index = (virtual_addr >> 21) & 0x1FF; + u64 pt_index = (virtual_addr >> 12) & 0x1FF; + + if (!(kernel_pml4->entries[pml4_index] & PTE_PRESENT)) return; + + u64 pdpt_phys = kernel_pml4->entries[pml4_index] & 0x000FFFFFFFFFF000; + page_table_t *pdpt = (page_table_t *)(pdpt_phys + kernel_pml4->entries[pml4_index]); + + (void)pdpt_phys; (void)pdp_index; (void)pd_index; (void)pt_index; + (void)pdpt; + + extern u64 g_hhdm_offset; + + page_table_t *pdpt2 = (page_table_t *)(pdpt_phys + g_hhdm_offset); + if (!(pdpt2->entries[pdp_index] & PTE_PRESENT)) return; + + u64 pd_phys = pdpt2->entries[pdp_index] & 0x000FFFFFFFFFF000; + page_table_t *pd = (page_table_t *)(pd_phys + g_hhdm_offset); + if (!(pd->entries[pd_index] & PTE_PRESENT)) return; + + u64 pt_phys = pd->entries[pd_index] & 0x000FFFFFFFFFF000; + page_table_t *pt = (page_table_t *)(pt_phys + g_hhdm_offset); + + pt->entries[pt_index] = 0; + __asm__ volatile("invlpg (%0)" : : "r"(virtual_addr) : "memory"); +} void paging_init(limine_hhdm_response_t *hpr) { u64 current_cr3; - asm volatile("mov %%cr3, %0" : "=r" (current_cr3)); + __asm__ volatile("mov %%cr3, %0" : "=r" (current_cr3)); kernel_pml4 = (page_table_t*)((current_cr3 & 0x000FFFFFFFFFF000) + hpr->offset); + g_hhdm_offset = hpr->offset; // save for paging_unmap_page } u64 map_region_alloc(limine_hhdm_response_t *hpr, u64 virt, u64 size) { @@ -177,4 +209,4 @@ void map_ulime_region(limine_hhdm_response_t *hpr, u64 phys_start, u64 size) { paging_map_page(hpr, virt_addr, phys_addr, PTE_PRESENT | PTE_WRITABLE); } } -} +} \ No newline at end of file diff --git a/src/kernel/mem/paging/paging.h b/src/kernel/mem/paging/paging.h index deb9928..4cc41ea 100644 --- a/src/kernel/mem/paging/paging.h +++ b/src/kernel/mem/paging/paging.h @@ -27,6 +27,7 @@ typedef struct { } page_table_t; extern page_table_t *kernel_pml4; +extern u64 g_hhdm_offset; void paging_map_page(limine_hhdm_response_t *hpr, u64 virtual_addr, u64 physical_addr, u64 flags); void paging_unmap_page(u64 virtual_addr); @@ -39,4 +40,8 @@ int verify_page_permissions(limine_hhdm_response_t *hpr, u64 virtual_addr, const void* phys_to_virt(limine_hhdm_response_t *hpr, u64 phys_addr); u64 virt_to_phys(limine_hhdm_response_t *hpr, void* virt_addr); +// perprocess page table support +u64 paging_create_proc_pml4 (limine_hhdm_response_t *hpr); +void paging_map_page_proc (limine_hhdm_response_t *hpr, u64 pml4_phys, u64 virtual_addr, u64 physical_addr, u64 flags); + #endif diff --git a/src/kernel/mem/paging/paging_proc.c b/src/kernel/mem/paging/paging_proc.c new file mode 100644 index 0000000..3df20be --- /dev/null +++ b/src/kernel/mem/paging/paging_proc.c @@ -0,0 +1,84 @@ +#include "paging.h" +#include +#include +#include +#include +#include +#include + +u64 paging_create_proc_pml4(limine_hhdm_response_t *hpr) +{ + u64 pml4_phys = physmem_alloc_to(1); + if (!pml4_phys) panic("[PAGING] failed to allocate proc PML4"); + + page_table_t *pml4 = (page_table_t *)(pml4_phys + hpr->offset); + memset(pml4, 0, PAGE_SIZE); + + // share kernel upper half so syscalls/kernel code work in every process + for (int i = 256; i < 512; i++) { + pml4->entries[i] = kernel_pml4->entries[i]; + } + + return pml4_phys; +} + +void paging_map_page_proc( + limine_hhdm_response_t *hpr, + u64 pml4_phys, + u64 virtual_addr, + u64 physical_addr, + u64 flags) +{ + page_table_t *pml4 = (page_table_t *)(pml4_phys + hpr->offset); + + u64 pml4_index = (virtual_addr >> 39) & 0x1FF; + u64 pdp_index = (virtual_addr >> 30) & 0x1FF; + u64 pd_index = (virtual_addr >> 21) & 0x1FF; + u64 pt_index = (virtual_addr >> 12) & 0x1FF; + + u64 upper_flags = PTE_PRESENT | PTE_WRITABLE; + if (flags & PTE_USER) upper_flags |= PTE_USER; + + page_table_t *pdpt = NULL; + if (!(pml4->entries[pml4_index] & PTE_PRESENT)) { + u64 pdpt_phys = physmem_alloc_to(1); + if (!pdpt_phys) panic("[PAGING] failed to allocate PDPT for proc"); + pml4->entries[pml4_index] = (pdpt_phys & 0x000FFFFFFFFFF000) | upper_flags; + pdpt = (page_table_t *)(pdpt_phys + hpr->offset); + memset(pdpt, 0, PAGE_SIZE); + } else { + u64 pdpt_phys = pml4->entries[pml4_index] & 0x000FFFFFFFFFF000; + pdpt = (page_table_t *)(pdpt_phys + hpr->offset); + pml4->entries[pml4_index] |= upper_flags; + } + + page_table_t *pd = NULL; + if (!(pdpt->entries[pdp_index] & PTE_PRESENT)) { + u64 pd_phys = physmem_alloc_to(1); + if (!pd_phys) panic("[PAGING] failed to allocate PD for proc"); + pdpt->entries[pdp_index] = (pd_phys & 0x000FFFFFFFFFF000) | upper_flags; + pd = (page_table_t *)(pd_phys + hpr->offset); + memset(pd, 0, PAGE_SIZE); + } else { + u64 pd_phys = pdpt->entries[pdp_index] & 0x000FFFFFFFFFF000; + pd = (page_table_t *)(pd_phys + hpr->offset); + pdpt->entries[pdp_index] |= upper_flags; + } + + page_table_t *pt = NULL; + if (!(pd->entries[pd_index] & PTE_PRESENT)) { + u64 pt_phys = physmem_alloc_to(1); + if (!pt_phys) panic("[PAGING] failed to allocate PT for proc"); + pd->entries[pd_index] = (pt_phys & 0x000FFFFFFFFFF000) | upper_flags; + pt = (page_table_t *)(pt_phys + hpr->offset); + memset(pt, 0, PAGE_SIZE); + } else { + u64 pt_phys = pd->entries[pd_index] & 0x000FFFFFFFFFF000; + pt = (page_table_t *)(pt_phys + hpr->offset); + pd->entries[pd_index] |= upper_flags; + } + + pt->entries[pt_index] = (physical_addr & 0x000FFFFFFFFFF000) | flags; + + __asm__ volatile("invlpg (%0)" : : "r"(virtual_addr) : "memory"); +} \ No newline at end of file diff --git a/src/kernel/mem/sfence.h b/src/kernel/mem/sfence.h new file mode 100644 index 0000000..2208c5d --- /dev/null +++ b/src/kernel/mem/sfence.h @@ -0,0 +1,6 @@ +#pragma once + +static inline void store_fence() +{ + __asm__ volatile("sfence" ::: "memory"); +} \ No newline at end of file diff --git a/src/kernel/module/module.h b/src/kernel/module/module.h index 4a8ca19..6a1ce3f 100644 --- a/src/kernel/module/module.h +++ b/src/kernel/module/module.h @@ -19,8 +19,8 @@ typedef struct driver_module { // not used just for the file system in future // void *(*open)(const char *path); - int (*read)(void *handle, void *buf, size_t count); - int (*write)(void *handle, const void *buf, size_t count); + int (*read)(void *handle, void *buf, size_t count, u64 offset); + int (*write)(void *handle, const void *buf, size_t count, u64 offset); } driver_module; diff --git a/src/kernel/modules/limine.c b/src/kernel/modules/limine.c index cc37376..e960b76 100644 --- a/src/kernel/modules/limine.c +++ b/src/kernel/modules/limine.c @@ -113,3 +113,28 @@ int limine_module_load(const char *module_name, const char *vfs_path) { return 0; } + +/* +int limine_module_find_raw(const char *module_name, void **out_addr, u64 *out_size) { + if (!module_request.response || module_request.response->module_count == 0) return -1; + if (!module_name || !out_addr || !out_size) return -1; + + struct limine_module_response *response = + (struct limine_module_response *)module_request.response; + + for (u64 i = 0; i < response->module_count; i++) { + const char *path = response->modules[i]->path; + + const char *filename = path; + for (const char *p = path; *p; p++) { + if (*p == '/') filename = p + 1; + } + + if (str_equals(filename, module_name)) { + *out_addr = (void *)response->modules[i]->address; + *out_size = response->modules[i]->size; + return 0; + } + } + return -1; +}*/ \ No newline at end of file diff --git a/src/kernel/modules/limine.h b/src/kernel/modules/limine.h index 703eecf..3dc771a 100644 --- a/src/kernel/modules/limine.h +++ b/src/kernel/modules/limine.h @@ -10,4 +10,6 @@ int limine_modules_count(void); // module-info by index struct limine_file* limine_module_get(int index); -#endif +//int limine_module_find_raw(const char *module_name, void **out_addr, u64 *out_size); + +#endif \ No newline at end of file diff --git a/src/kernel/multitasking/ipc/ipc.h b/src/kernel/multitasking/ipc/ipc.h new file mode 100644 index 0000000..a472b66 --- /dev/null +++ b/src/kernel/multitasking/ipc/ipc.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include +#include +#include + +// +// https://github.com/Novice06/Novix/tree/main/src/kernel/multitasking/ipc +// + +#define IPC_MAX_MESSAGES 256 +#define IPC_MAX_MSG_SIZE 512 +#define IPC_MAX_PROCS 32 +#define IPC_MAX_WAITERS 16 +#define IPC_MAX_SHM 64 +#define IPC_MAX_SHM_PAGES 64 // 256KB per region max +#define IPC_SHM_INVALID 0 + +typedef struct { + u64 sender_id; + u64 receiver_id; + u32 size; + u8 data[IPC_MAX_MSG_SIZE]; + int used; +} ipc_msg_t; +typedef struct { + int is_open; + int count; + ipc_msg_t *messages[IPC_MAX_MESSAGES]; + ulime_proc_t *waiters[IPC_MAX_WAITERS]; + int waiter_count; +} ipc_endpoint_t; +typedef struct { + u64 id; + u64 phys_pages[IPC_MAX_SHM_PAGES]; + u32 page_count; + int ref_count; + int used; + u64 virt_per_proc[IPC_MAX_PROCS]; +} ipc_shm_t; + +void ipc_messages_init(void); +void ipc_shm_init(void); + +void open_inbox(ulime_t *ulime, ulime_proc_t *proc); +void close_inbox(ulime_proc_t *proc); +void destroy_endpoint(ulime_t *ulime, ulime_proc_t *proc); +int send_msg(ulime_t *ulime,ulime_proc_t *sender,u64 receiver_id,const void *data,u32 size); +int receive_async_msg(ulime_t *ulime,ulime_proc_t *proc,void *buf,u32 buf_size,u64 *out_sender); +void receive_msg(ulime_t *ulime,ulime_proc_t *proc,void *buf,u32 buf_size,u64 *out_sender); + +u64 shm_create(ulime_t *ulime, u32 pages); +void *shm_attach(ulime_t *ulime, ulime_proc_t *proc, u64 id); +void shm_detach(ulime_t *ulime, ulime_proc_t *proc, u64 id); +void shm_detach_all(ulime_t *ulime, ulime_proc_t *proc); \ No newline at end of file diff --git a/src/kernel/multitasking/ipc/messages.c b/src/kernel/multitasking/ipc/messages.c new file mode 100644 index 0000000..101047f --- /dev/null +++ b/src/kernel/multitasking/ipc/messages.c @@ -0,0 +1,152 @@ +#include "ipc.h" +#include +#include + +extern klime_t *klime; + +#define MAX_MESSAGES 256 + +static ipc_endpoint_t *endpoints[IPC_MAX_PROCS]; + +void ipc_messages_init(void) { + for (int i = 0; i < IPC_MAX_PROCS; i++) endpoints[i] = NULL; +} + +static ipc_endpoint_t *get_ep(u64 pid) { + if (pid >= IPC_MAX_PROCS) return NULL; + return endpoints[pid]; +} + +static ulime_proc_t *find_proc(ulime_t *ulime, u64 pid) { + ulime_proc_t *p = ulime->ptr_proc_list; + while (p) { + if (p->pid == pid) return p; + p = p->next; + } + return NULL; +} + +static void wake_waiters(ipc_endpoint_t *ep) { + for (int i = 0; i < ep->waiter_count; i++) { + if (ep->waiters[i] && ep->waiters[i]->state == PROC_BLOCKED) + ep->waiters[i]->state = PROC_READY; + } + ep->waiter_count = 0; +} + +void open_inbox(ulime_t *ulime, ulime_proc_t *proc) +{ + u64 pid = proc->pid; + if (pid >= IPC_MAX_PROCS) return; + + if (endpoints[pid]) { + endpoints[pid]->is_open = 1; + return; + } + + ipc_endpoint_t *ep = (ipc_endpoint_t *)klime_create(ulime->klime, sizeof(ipc_endpoint_t)); + if (!ep) return; + + ep->is_open = 1; + ep->count = 0; + ep->waiter_count = 0; + for (int i = 0; i < IPC_MAX_MESSAGES; i++) ep->messages[i] = NULL; + for (int i = 0; i < IPC_MAX_WAITERS; i++) ep->waiters[i] = NULL; + + endpoints[pid] = ep; +} + +void close_inbox(ulime_proc_t *proc) { + ipc_endpoint_t *ep = get_ep(proc->pid); + if (ep) ep->is_open = 0; +} + +void destroy_endpoint(ulime_t *ulime, ulime_proc_t *proc) +{ + u64 pid = proc->pid; + ipc_endpoint_t *ep = get_ep(pid); + if (!ep) return; + + close_inbox(proc); + + for (int i = 0; i < ep->count; i++) { + if (ep->messages[i]) { + klime_free(ulime->klime, (u64 *)ep->messages[i]); + ep->messages[i] = NULL; + } + } + ep->count = 0; + + wake_waiters(ep); + + klime_free(ulime->klime, (u64 *)ep); + endpoints[pid] = NULL; +} + +int send_msg( + ulime_t *ulime, ulime_proc_t *sender, u64 receiver_id, + const void *data, u32 size +) { + if (!data || size == 0 || size > IPC_MAX_MSG_SIZE) return -1; + + ipc_endpoint_t *ep = get_ep(receiver_id); + if (!ep || !ep->is_open) return -1; + + while (ep->count >= IPC_MAX_MESSAGES) { + if (ep->waiter_count < IPC_MAX_WAITERS) + ep->waiters[ep->waiter_count++] = sender; + sender->state = PROC_BLOCKED; + + while (sender->state == PROC_BLOCKED) + __asm__ volatile("pause"); + } + + ipc_msg_t *msg = (ipc_msg_t *)klime_create(ulime->klime, sizeof(ipc_msg_t)); + if (!msg) return -1; + + msg->sender_id = sender->pid; + msg->receiver_id = receiver_id; + msg->size = size; + msg->used = 1; + memcpy(msg->data, data, size); + + ep->messages[ep->count++] = msg; + + ulime_proc_t *recv_proc = find_proc(ulime, receiver_id); + if (recv_proc && recv_proc->state == PROC_BLOCKED) + recv_proc->state = PROC_READY; + + return 0; +} + +int receive_async_msg(ulime_t *ulime, ulime_proc_t *proc, void *buf, u32 buf_size, u64 *out_sender) +{ + ipc_endpoint_t *ep = get_ep(proc->pid); + if (!ep || ep->count <= 0) return -1; + + ipc_msg_t *msg = ep->messages[0]; + u32 copy_size = msg->size < buf_size ? msg->size : buf_size; + + memcpy(buf, msg->data, copy_size); + if (out_sender) *out_sender = msg->sender_id; + + ep->count--; + for (int i = 0; i < ep->count; i++) + ep->messages[i] = ep->messages[i + 1]; + ep->messages[ep->count] = NULL; + + klime_free(ulime->klime, (u64 *)msg); + + if (ep->waiter_count > 0) + wake_waiters(ep); + + return (int)copy_size; +} + +void receive_msg(ulime_t *ulime, ulime_proc_t *proc, void *buf, u32 buf_size, u64 *out_sender) { + while (receive_async_msg(ulime, proc, buf, buf_size, out_sender) < 0) { + proc->state = PROC_BLOCKED; + while (proc->state == PROC_BLOCKED) + __asm__ volatile("pause"); + } +} \ No newline at end of file diff --git a/src/kernel/multitasking/ipc/shared_memory.c b/src/kernel/multitasking/ipc/shared_memory.c new file mode 100644 index 0000000..7c8f82b --- /dev/null +++ b/src/kernel/multitasking/ipc/shared_memory.c @@ -0,0 +1,139 @@ +#include "ipc.h" +#include +#include +#include + +static ipc_shm_t shm_table[IPC_MAX_SHM]; +static u64 shm_counter = 1; + +void ipc_shm_init(void) { + for (int i = 0; i < IPC_MAX_SHM; i++) { + shm_table[i].used = 0; + shm_table[i].id = 0; + shm_table[i].ref_count = 0; + } +} + +static ipc_shm_t *shm_find(u64 id) { + for (int i = 0; i < IPC_MAX_SHM; i++) { + if (shm_table[i].used && shm_table[i].id == id) + return &shm_table[i]; + } + return NULL; +} + +static ipc_shm_t *shm_alloc_slot(void) { + for (int i = 0; i < IPC_MAX_SHM; i++) { + if (!shm_table[i].used) + return &shm_table[i]; + } + return NULL; +} + +static void shm_free_phys(ipc_shm_t *shm) +{ + for (u32 i = 0; i < shm->page_count; i++) { + if (shm->phys_pages[i]) { + physmem_free_to(shm->phys_pages[i], 1); + shm->phys_pages[i] = 0; + } + } + shm->used = 0; + shm->ref_count = 0; +} + +u64 shm_create(ulime_t *ulime, u32 pages) +{ + (void)ulime; + if (pages == 0 || pages > IPC_MAX_SHM_PAGES) return IPC_SHM_INVALID; + + ipc_shm_t *shm = shm_alloc_slot(); + if (!shm) return IPC_SHM_INVALID; + + for (u32 i = 0; i < pages; i++) { + u64 phys = physmem_alloc_to(1); + if (!phys) { + for (u32 j = 0; j < i; j++) + physmem_free_to(shm->phys_pages[j], 1); + return IPC_SHM_INVALID; + } + shm->phys_pages[i] = phys; + } + + shm->id = shm_counter++; + shm->page_count = pages; + shm->ref_count = 0; + shm->used = 1; + + for (int i = 0; i < IPC_MAX_PROCS; i++) + shm->virt_per_proc[i] = 0; + + printf("[SHM] created id=%llu pages=%u\n", (unsigned long long)shm->id, pages); + return shm->id; +} + +void *shm_attach(ulime_t *ulime, ulime_proc_t *proc, u64 id) +{ + ipc_shm_t *shm = shm_find(id); + if (!shm) return NULL; + + u64 pid = proc->pid; + if (pid >= IPC_MAX_PROCS) return NULL; + + if (shm->virt_per_proc[pid] != 0) + return (void *)shm->virt_per_proc[pid]; + + u64 virt = (ulime->user_space_used + 0xFFF) & ~0xFFFULL; + ulime->user_space_used = virt + (u64)shm->page_count * PAGE_SIZE; + + u64 flags = PTE_PRESENT | PTE_WRITABLE | PTE_USER; + for (u32 i = 0; i < shm->page_count; i++) { + paging_map_page_proc( + ulime->hpr, + proc->pml4_phys, + virt + (u64)i * PAGE_SIZE, + shm->phys_pages[i], + flags + ); + } + + shm->virt_per_proc[pid] = virt; + shm->ref_count++; + + printf("[SHM] attached id=%llu to pid=%llu virt=0x%llx\n", (unsigned long long)id, (unsigned long long)pid, (unsigned long long)virt); + return (void *)virt; +} + +void shm_detach(ulime_t *ulime, ulime_proc_t *proc, u64 id) { + ipc_shm_t *shm = shm_find(id); + if (!shm) return; + + u64 pid = proc->pid; + if (pid >= IPC_MAX_PROCS) return; + if (shm->virt_per_proc[pid] == 0) return; + + u64 virt = shm->virt_per_proc[pid]; + for (u32 i = 0; i < shm->page_count; i++) { + u64 va = virt + (u64)i * PAGE_SIZE; + paging_map_page_proc(ulime->hpr, proc->pml4_phys, va, 0, 0); + __asm__ volatile("invlpg (%0)" :: "r"(va) : "memory"); + } + + shm->virt_per_proc[pid] = 0; + shm->ref_count--; + + printf("[SHM] detached id=%llu from pid=%llu\n",(unsigned long long)id, (unsigned long long)pid); + + if (shm->ref_count <= 0) + shm_free_phys(shm); +} + +void shm_detach_all(ulime_t *ulime, ulime_proc_t *proc) { + u64 pid = proc->pid; + if (pid >= IPC_MAX_PROCS) return; + + for (int i = 0; i < IPC_MAX_SHM; i++) { + if (shm_table[i].used && shm_table[i].virt_per_proc[pid] != 0) + shm_detach(ulime, proc, shm_table[i].id); + } +} \ No newline at end of file diff --git a/src/kernel/multitasking/multitasking.c b/src/kernel/multitasking/multitasking.c new file mode 100644 index 0000000..8973143 --- /dev/null +++ b/src/kernel/multitasking/multitasking.c @@ -0,0 +1,182 @@ +#include "multitasking.h" +#include +#include + +static int mt_find_next(mt_t *mt, int from_idx) +{ + if (mt->task_count == 0) return -1; + + int start = (from_idx + 1) % mt->task_count; + int i = start; + + do { + mt_task_t *t = &mt->tasks[i]; + if (t->valid && t->proc && + (t->proc->state == PROC_READY || t->proc->state == PROC_CREATED)) { + return i; + } + i = (i + 1) % mt->task_count; + } while (i != start); + + mt_task_t *t = &mt->tasks[start]; + if (t->valid && t->proc && + (t->proc->state == PROC_READY || t->proc->state == PROC_CREATED)) { + return start; + } + + return -1; +} + +void mt_init(mt_t *mt, scheduler_t *sched, ulime_t *ulime) +{ + if (!mt) return; + + for (int i = 0; i < MT_MAX_TASKS; i++) { + mt->tasks[i].proc = NULL; + mt->tasks[i].valid = 0; + mt->tasks[i].user_ctx.saved = 0; + } + + mt->task_count = 0; + mt->current_idx = -1; + mt->initialized = 1; + mt->sched = sched; + mt->ulime = ulime; + + printf("[MT] multitasking initialized (max=%d quantum=%llu)\n", + MT_MAX_TASKS, + sched ? (unsigned long long)sched->quantum : 0ULL + ); +} + +int mt_add_task(mt_t *mt, ulime_proc_t *proc) +{ + if (!mt || !proc) return -1; + if (!mt->initialized) return -1; + if (mt->task_count >= MT_MAX_TASKS) return -1; + + int idx = mt->task_count; + mt_task_t *t = &mt->tasks[idx]; + + t->proc = proc; + t->valid = 1; + t->user_ctx.saved = 0; + t->user_ctx.cr3 = proc->pml4_phys; + + mt->task_count++; + + printf("[MT] task added: idx=%d pid=%llu entry=0x%llx\n", + idx, + (unsigned long long)proc->pid, + (unsigned long long)proc->entry_point + ); + + return idx; +} + +void mt_preempt(mt_t *mt, cpu_state_t *state) +{ + if (!mt || !mt->initialized || !state) return; + if (mt->task_count < 2) return; + + // only switch if we interrupted user code + if ((state->cs & 3) != 3) return; + + if (mt->sched) { + mt->sched->ticks++; + if (mt->sched->ticks < mt->sched->quantum) return; + mt->sched->ticks = 0; + } + + int old_idx = mt->current_idx; + int new_idx = mt_find_next(mt, old_idx); + + if (new_idx < 0 || new_idx == old_idx) return; + + // save old process + if (old_idx >= 0 && mt->tasks[old_idx].valid) { + mt_task_t *old = &mt->tasks[old_idx]; + mt_user_ctx_t *uc = &old->user_ctx; + + uc->r15 = state->r15; uc->r14 = state->r14; + uc->r13 = state->r13; uc->r12 = state->r12; + uc->r11 = state->r11; uc->r10 = state->r10; + uc->r9 = state->r9; uc->r8 = state->r8; + uc->rbp = state->rbp; uc->rdi = state->rdi; + uc->rsi = state->rsi; uc->rdx = state->rdx; + uc->rcx = state->rcx; uc->rbx = state->rbx; + uc->rax = state->rax; + + uc->rip = state->rip; + uc->cs = state->cs; + uc->rflags = state->rflags; + uc->rsp = state->rsp; + uc->ss = state->ss; + uc->cr3 = old->proc->pml4_phys; + uc->saved = 1; + + if (old->proc->state == PROC_RUNNING) + old->proc->state = PROC_READY + ; + } + + // load next process + mt_task_t *next = &mt->tasks[new_idx]; + mt_user_ctx_t *nc = &next->user_ctx; + + if (nc->saved) { + state->r15 = nc->r15; state->r14 = nc->r14; + state->r13 = nc->r13; state->r12 = nc->r12; + state->r11 = nc->r11; state->r10 = nc->r10; + state->r9 = nc->r9; state->r8 = nc->r8; + state->rbp = nc->rbp; state->rdi = nc->rdi; + state->rsi = nc->rsi; state->rdx = nc->rdx; + state->rcx = nc->rcx; state->rbx = nc->rbx; + state->rax = nc->rax; + state->rip = nc->rip; + state->cs = nc->cs; + state->rflags = nc->rflags; + state->rsp = nc->rsp; + state->ss = nc->ss; + } else { + // first run + state->r15 = state->r14 = state->r13 = state->r12 = 0; + state->r11 = state->r10 = state->r9 = state->r8 = 0; + state->rbp = state->rdi = state->rsi = state->rdx = 0; + state->rcx = state->rbx = state->rax = 0; + + state->rip = next->proc->entry_point; + state->cs = (u64)(USER_CODE_SELECTOR | 3); + state->rflags = 0x202; // IF=1 + state->rsp = (next->proc->stack_base + next->proc->stack_size - 16)& ~0xFULL; + state->ss = (u64)(USER_DATA_SELECTOR | 3); + } + + next->proc->state = PROC_RUNNING; + mt->current_idx = new_idx; + + if (mt->ulime) mt->ulime->ptr_proc_curr = next->proc; + + __asm__ volatile( + "mov %0, %%cr3" + :: + "r"(next->proc->pml4_phys) + : + "memory" + ); +} + +void mt_yield(mt_t *mt) { + if (!mt || !mt->initialized) return; + if (mt->sched) mt->sched->ticks = 0; +} + +int mt_task_count(mt_t *mt) { + if (!mt) return 0; + return mt->task_count; +} + +mt_task_t *mt_current_task(mt_t *mt) { + if (!mt || mt->current_idx < 0) return NULL; + return &mt->tasks[mt->current_idx]; +} \ No newline at end of file diff --git a/src/kernel/multitasking/multitasking.h b/src/kernel/multitasking/multitasking.h new file mode 100644 index 0000000..abd3c19 --- /dev/null +++ b/src/kernel/multitasking/multitasking.h @@ -0,0 +1,71 @@ +#pragma once + +#include +#include +#include +#include + +// offsets MUST match scheduler.asm exactly +typedef struct { + u64 r15; // 0 + u64 r14; // 8 + u64 r13; // 16 + u64 r12; // 24 + u64 r11; // 32 + u64 r10; // 40 + u64 r9; // 48 + u64 r8; // 56 + u64 rbp; // 64 + u64 rdi; // 72 + u64 rsi; // 80 + u64 rdx; // 88 + u64 rcx; // 96 + u64 rbx; // 104 + u64 rax; // 112 + u64 _pad0; // 120 + u64 _pad1; // 128 + u64 rip; // 136 + u64 _pad2; // 144 + u64 rflags; // 152 + u64 rsp; // 160 +} mt_context_t; + +// saved user-mode cpu state +typedef struct { + u64 r15, r14, r13, r12, r11, r10, r9, r8; + u64 rbp, rdi, rsi, rdx, rcx, rbx, rax; + u64 rip; + u64 cs; + u64 rflags; + u64 rsp; + u64 ss; + u64 cr3; + int saved; // 0 == first run; use entry_point +} mt_user_ctx_t; + +#define MT_MAX_TASKS 32 + +typedef struct { + ulime_proc_t *proc; + mt_context_t ctx; + mt_user_ctx_t user_ctx; + int valid; +} mt_task_t; + +typedef struct { + mt_task_t tasks[MT_MAX_TASKS]; + int task_count; + int current_idx; + int initialized; + scheduler_t *sched; + ulime_t *ulime; +} mt_t; + +extern void scheduler_context_switch(mt_context_t *old_ctx, mt_context_t *new_ctx); + +void mt_init(mt_t *mt, scheduler_t *sched, ulime_t *ulime); +int mt_add_task(mt_t *mt, ulime_proc_t *proc); +void mt_preempt(mt_t *mt, cpu_state_t *state); +void mt_yield(mt_t *mt); +int mt_task_count(mt_t *mt); +mt_task_t *mt_current_task(mt_t *mt); diff --git a/src/kernel/net/head.h b/src/kernel/net/head.h new file mode 100644 index 0000000..5545d85 --- /dev/null +++ b/src/kernel/net/head.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +// commit: deleted unix_sockets \ No newline at end of file diff --git a/src/kernel/net/net.h b/src/kernel/net/net.h new file mode 100644 index 0000000..9301158 --- /dev/null +++ b/src/kernel/net/net.h @@ -0,0 +1,25 @@ +#pragma once + +// commit: deleted unix_sockets + +//! ( +//! this file is half empty now :( +//! ) + + +// gen net + +#define _EAF_UNIX 1 +#include +#include +// initial tasks +#ifndef SOCKET1 +# include +# define EITASK "1" +#elif SOCKET2 +# define EITASK "2" +#elif SOCKET3 +# define EITASK "3" +#elif SOCKET4 +# define EITASK "4" +#endif \ No newline at end of file diff --git a/src/kernel/net/unix/unix_sock.c b/src/kernel/net/unix/unix_sock.c new file mode 100644 index 0000000..221f299 --- /dev/null +++ b/src/kernel/net/unix/unix_sock.c @@ -0,0 +1 @@ +// commit: deleted unix_sockets \ No newline at end of file diff --git a/src/kernel/net/unix/unix_sock.h b/src/kernel/net/unix/unix_sock.h new file mode 100644 index 0000000..307e38c --- /dev/null +++ b/src/kernel/net/unix/unix_sock.h @@ -0,0 +1,3 @@ +#pragma once + +// commit: deleted unix_sockets \ No newline at end of file diff --git a/src/kernel/packages/cpio/cpio.c b/src/kernel/packages/cpio/cpio.c new file mode 100644 index 0000000..1b4be5c --- /dev/null +++ b/src/kernel/packages/cpio/cpio.c @@ -0,0 +1,212 @@ +#include "cpio.h" + +#include +#include +#include +#include +#include +#include + +static u32 parse_hex8(const char **p) +{ + u32 val = 0; + for (int i = 0; i < 8; i++) { + char c = (*p)[i]; + u32 n; + if (c >= '0' && c <= '9') n = (u32)(c - '0'); + else if (c >= 'a' && c <= 'f') n = (u32)(c - 'a' + 10); + else if (c >= 'A' && c <= 'F') n = (u32)(c - 'A' + 10); + else n = 0; + val = (val << 4) | n; + } + *p += 8; + return val; +} + +static inline u64 align4(u64 n){ return (n + 3) & ~(u64)3; } + +// pub iterators +// +void cpio_iter_init(cpio_iter_t *iter, const u8 *data, u64 size) +{ + if (!iter) return; + iter->base = data; + iter->size = size; + iter->offset = 0; +} + +int cpio_iter_next(cpio_iter_t *iter, cpio_entry_t *entry) +{ + if (!iter || !entry) return CPIO_ERR_TRUNC; + + u64 off = iter->offset; + + if (off+CPIO_HEADER_SIZE > iter->size) return CPIO_ERR_TRUNC; + + const char *hdr = (const char *)(iter->base + off); + + if (!(hdr[0]=='0' && hdr[1]=='7' && hdr[2]=='0' && + hdr[3]=='7' && hdr[4]=='0' && (hdr[5]=='1' || hdr[5]=='2'))) + return CPIO_ERR_MAGIC; + + const char *p = hdr + 6; + entry->ino = parse_hex8(&p); + entry->mode = parse_hex8(&p); + entry->uid = parse_hex8(&p); + entry->gid = parse_hex8(&p); + entry->nlink = parse_hex8(&p); + entry->mtime = parse_hex8(&p); + entry->filesize = parse_hex8(&p); + entry->devmajor = parse_hex8(&p); + entry->devminor = parse_hex8(&p); + entry->rdevmajor = parse_hex8(&p); + entry->rdevminor = parse_hex8(&p); + entry->namesize = parse_hex8(&p); + parse_hex8(&p); // crc field / ignored + + off += CPIO_HEADER_SIZE; + + if (off+ entry->namesize > iter->size) return CPIO_ERR_TRUNC; + entry->name = (const char *)(iter->base + off); + + off = iter->offset + align4(CPIO_HEADER_SIZE + entry->namesize); + + if (str_equals(entry->name, CPIO_TRAILER)){ + iter->offset = off; + + return CPIO_ERR_EOF; + } + + if (off + entry->filesize > iter->size) return CPIO_ERR_TRUNC; + entry->data = iter->base + off; + iter->offset = off + align4(entry->filesize); + + return CPIO_OK; +} + +#define CPIO_MAX_ENTRIES 512 + +typedef struct { + cpio_entry_t e; + char path[256]; +} cpio_staged_t; + +static cpio_staged_t _staged[CPIO_MAX_ENTRIES]; + +static void make_path(char *out, const char *base, const char *name) +{ + // strip leading "./" or lone "." + if (name[0] == '.' && name[1] == '/') name += 2; + if (name[0] == '.' && name[1] == '\0') { str_copy(out, base); return; } + + if (str_equals(base, "/")) { + out[0] = '/'; + str_copy(out + 1, name); + } else { + str_copy(out, base); + int bl = str_len(out); + if (bl > 0 && out[bl-1] != '/') str_append(out, "/"); + str_append(out, name); + } + // remove trailing slash unless root + int l = str_len(out); + if (l >1 && out[l-1] == '/') out[l-1] = '\0'; +} + +int cpio_extract_to_vfs(const u8 *data, u64 size, const char *base_path) +{ + if (!data || size == 0 || !base_path) return CPIO_ERR_TRUNC; + + cpio_iter_t iter; + cpio_entry_t entry; + cpio_iter_init(&iter, data, size); + + int total = 0; + int staged = 0; + + // self explaining i think... reading archive.... + print("\n", white()); + log("[CPIO]", "reading archive...\n", d); + + while (staged < CPIO_MAX_ENTRIES) { + int rc = cpio_iter_next(&iter, &entry); + if (rc == CPIO_ERR_EOF) break; + if (rc != CPIO_OK) { log("[CPIO]", "parse error\n", error); return rc; } + + const char *n = entry.name; + //strips "./" or "." + if (n[0]=='.' && n[1]=='\0') continue; + if (n[0]=='.' && n[1]=='/' && n[2]=='\0') continue; + if (!cpio_is_file(&entry) && !cpio_is_dir(&entry) && !cpio_is_symlink(&entry)) continue; + + cpio_staged_t *s = &_staged[staged]; + s->e = entry; + make_path(s->path, base_path, entry.name); + + if (cpio_is_dir(&entry)) { + log("[CPIO]",DIR_PREFIX, d);} + else { + log("[CPIO]",FILE_PREFIX, d);} + print(s->path, white()); + if (cpio_is_file(&entry) && entry.filesize > 0) { + char buf[20]; + str_copy(buf, " ("); + str_append_uint(buf, entry.filesize); // shows how many bytes a file has + str_append(buf, "B)"); + print(buf, white()); + } + print("\n", white()); + staged++; + } + print("\n", white()); + + // only now create all directorys + // (just made it so it looks better...) + for (int i = 0; i < staged; i++) { + if (cpio_is_dir(&_staged[i].e)) { + fs_mkdir(_staged[i].path); + total++; + } + } + + // this writes the files but it can also overwrite files + for (int i = 0; i < staged; i++) + { + cpio_staged_t *s = &_staged[i]; + if (!cpio_is_file(&s->e) && !cpio_is_symlink(&s->e)) continue; + + int fd = fs_open(s->path, O_CREAT | O_WRONLY); + if (fd < 0) continue; + if (s->e.filesize > 0) + fs_write(fd, (void *)s->e.data, s->e.filesize); + fs_close(fd); + total++; + } + + char buf[32]; + str_copy(buf, ""); + str_append_uint(buf, (u32)total); + log("[CPIO]", "extracted ", d); + print(buf, white()); + print(" entries\n", white()); + + return total; +} + +int cpio_find(const u8 *data, u64 size, const char *name, cpio_entry_t *entry) +{ + if (!data || !name || !entry) return CPIO_ERR_TRUNC; + + cpio_iter_t iter; + cpio_iter_init(&iter, data, size); + + while (1) { + int rc = cpio_iter_next(&iter, entry); + if (rc == CPIO_ERR_EOF) return CPIO_ERR_EOF; + if (rc != CPIO_OK) return rc; + + const char *n = entry->name; + if (n[0]=='.' && n[1]=='/') n += 2; + if (str_equals(n, name)) return CPIO_OK; + } +} diff --git a/src/kernel/packages/cpio/cpio.h b/src/kernel/packages/cpio/cpio.h new file mode 100644 index 0000000..df4dd8e --- /dev/null +++ b/src/kernel/packages/cpio/cpio.h @@ -0,0 +1,76 @@ +#ifndef CPIO_H +#define CPIO_H + +#include + +// what the heck is newc format bro..... :( +#define CPIO_MAGIC_NEWC "070701" +#define CPIO_MAGIC_NEWC_CRC "070702" +#define CPIO_MAGIC_LEN 6 + +#define DIR_PREFIX "dir: " +#define FILE_PREFIX "file: " + +// signals end of the archive +#define CPIO_TRAILER "TRAILER!!!" + +// newc header is always 110 bytes before the filename +#define CPIO_HEADER_SIZE 110 + +#define CPIO_MODE_IFMT 0170000 // mask to get file type bits +#define CPIO_MODE_IFSOCK 0140000 +#define CPIO_MODE_IFLNK 0120000 // link +#define CPIO_MODE_IFREG 0100000 // regular file +#define CPIO_MODE_IFBLK 0060000 // block device (linux-> lsblk) +#define CPIO_MODE_IFDIR 0040000 +#define CPIO_MODE_IFCHR 0020000 // character device +#define CPIO_MODE_IFIFO 0010000 // FIFO == named pipe + + +typedef struct { + u32 ino; + u32 mode; + u32 uid; + u32 gid; + u32 nlink; + u32 mtime; + u32 filesize; + u32 devmajor; + u32 devminor; + u32 rdevmajor; + u32 rdevminor; + u32 namesize;// includes null terminator + + const char *name; // pointer into archive data, NOT a copy + const u8 *data; // pointer to file data inside archive, NOT a copy +} cpio_entry_t; +typedef struct { + const u8 *base; // start of CPIO archive in memory + u64 size; // total archive size in bytes + u64 offset; // current parse position +} cpio_iter_t; + +// retc +#define CPIO_OK 0 +#define CPIO_ERR_MAGIC (-1) // wrong magic +#define CPIO_ERR_TRUNC (-2) // archive trunctaded +#define CPIO_ERR_EOF (-3) // TRAILER!!! end + + +void cpio_iter_init(cpio_iter_t *iter, const u8 *data, u64 size); +int cpio_iter_next(cpio_iter_t *iter, cpio_entry_t *entry); +int cpio_extract_to_vfs(const u8 *data, u64 size, const char *base_path); +int cpio_find(const u8 *data, u64 size, const char *name, cpio_entry_t *entry); + + +static inline int cpio_is_file(const cpio_entry_t *e) { + return (e->mode & CPIO_MODE_IFMT) == CPIO_MODE_IFREG; +} +static inline int cpio_is_dir(const cpio_entry_t *e) { + return (e->mode & CPIO_MODE_IFMT) == CPIO_MODE_IFDIR; +} +static inline int cpio_is_symlink(const cpio_entry_t *e) { + return (e->mode & CPIO_MODE_IFMT) == CPIO_MODE_IFLNK; +} + +#endif diff --git a/src/kernel/exec/elf/loader.c b/src/kernel/packages/elf/loader.c similarity index 61% rename from src/kernel/exec/elf/loader.c rename to src/kernel/packages/elf/loader.c index b02763e..7537f05 100644 --- a/src/kernel/exec/elf/loader.c +++ b/src/kernel/packages/elf/loader.c @@ -5,6 +5,7 @@ #include #include #include +#include int elf_load(ulime_proc_t *proc, u8 *elf_data, u64 size) { if (!proc || !elf_data || size < sizeof(elf_header_t)) { @@ -30,7 +31,7 @@ int elf_load(ulime_proc_t *proc, u8 *elf_data, u64 size) { return -1; } - if (ehdr->ident.endian != 1) { // 1 = little-endian + if (ehdr->ident.endian != 1) { // 1 == little-endian printf("[ELF] unsupported endianness\n"); return -1; } @@ -48,9 +49,12 @@ int elf_load(ulime_proc_t *proc, u8 *elf_data, u64 size) { elf_program_header_t *phdr = (elf_program_header_t*)(elf_data + ehdr->phoff); u64 min_vaddr = (u64)-1; + u64 max_vaddr = 0; for (u16 i = 0; i < ehdr->phnum; i++) { - if (phdr[i].type == PT_LOAD && phdr[i].vaddr < min_vaddr) { - min_vaddr = phdr[i].vaddr; + if (phdr[i].type == PT_LOAD) { + if (phdr[i].vaddr < min_vaddr) min_vaddr = phdr[i].vaddr; + u64 end = phdr[i].vaddr + phdr[i].memsz; + if (end > max_vaddr) max_vaddr = end; } } if (min_vaddr == (u64)-1) { @@ -59,6 +63,7 @@ int elf_load(ulime_proc_t *proc, u8 *elf_data, u64 size) { } u64 load_offset = proc->heap_base - min_vaddr; + u64 hhdm_offset = proc->ulime->hpr->offset; printf("[ELF] Loading '%s'\n", proc->name); printf(" ELF base addr: 0x%lX\n", min_vaddr); @@ -66,14 +71,15 @@ int elf_load(ulime_proc_t *proc, u8 *elf_data, u64 size) { printf(" Load offset: 0x%lX\n", load_offset); printf(" Original entry: 0x%lX\n", ehdr->entry); - // load PT_LOAD segments with relocation + // load PT_LOAD segments + // writes via HHDM so kernel CR3 doesnt matter for (u16 i = 0; i < ehdr->phnum; i++) { if (phdr[i].type != PT_LOAD) continue; - u64 vaddr = phdr[i].vaddr + load_offset; // apply relocation + u64 vaddr = phdr[i].vaddr + load_offset; // relocated virtual address u64 offset = phdr[i].offset; u64 filesz = phdr[i].filesz; - u64 memsz = phdr[i].memsz; + u64 memsz = phdr[i].memsz; printf(" Segment %d:\n", i); printf(" Original vaddr: 0x%lX\n", phdr[i].vaddr); @@ -81,7 +87,7 @@ int elf_load(ulime_proc_t *proc, u8 *elf_data, u64 size) { printf(" File size: %lu bytes\n", filesz); printf(" Mem size: %lu bytes\n", memsz); - // check bounds + // bounds check against heap if (vaddr < proc->heap_base || vaddr + memsz > proc->heap_base + proc->heap_size) { printf("[ELF] ERROR: Segment outside heap bounds\n"); printf(" Segment range: 0x%lX - 0x%lX\n", vaddr, vaddr + memsz); @@ -93,17 +99,22 @@ int elf_load(ulime_proc_t *proc, u8 *elf_data, u64 size) { printf("[ELF] Segment exceeds ELF size\n"); return -1; } + + // convert virtual address to kernel-accessible HHDM address + u64 phys_dest = proc->phys_heap + (vaddr - proc->heap_base); + void *hhdm_dest = (void *)(phys_dest + hhdm_offset); + if (filesz > 0) { - memcpy((void*)vaddr, elf_data + offset, filesz); + memcpy(hhdm_dest, elf_data + offset, filesz); printf(" Copied %lu bytes\n", filesz); } if (memsz > filesz) { - memset((void*)(vaddr + filesz), 0, memsz - filesz); + memset((u8 *)hhdm_dest + filesz, 0, memsz - filesz); printf(" Zeroed %lu bytes\n", memsz - filesz); } - // last verification - u8 *code = (u8*)vaddr; + // print first bytes for debug (read via HHDM too) + u8 *code = (u8 *)hhdm_dest; printf(" First bytes: "); for (int j = 0; j < 16 && j < (int)filesz; j++) { printf("%02X ", code[j]); @@ -115,6 +126,32 @@ int elf_load(ulime_proc_t *proc, u8 *elf_data, u64 size) { proc->entry_point = ehdr->entry + load_offset; proc->state = PROC_READY; + u64 code_end = proc->heap_base + (max_vaddr - min_vaddr); + proc->brk = (code_end + 0xFFFULL) & ~0xFFFULL; // round up to next page + printf("[ELF] Program break set to 0x%lX (code ends at 0x%lX)\n", + proc->brk, code_end); + + // if the ELF was relocated it also maps the original VMA into the process PML4 + // so that absolute addresses baked into the binary still work at runtime + if (load_offset != 0) { + u64 total_size = (max_vaddr - min_vaddr + 0xFFF) & ~0xFFFULL; + u64 pages = total_size / 0x1000; + u64 heap_flags = PTE_PRESENT | PTE_WRITABLE | PTE_USER; + + printf("[ELF] remapping original VMA 0x%lX (%lu pages) to same phys\n", + min_vaddr, pages); + + for (u64 p = 0; p < pages; p++) { + u64 phys = proc->phys_heap + (p * 0x1000); + u64 orig_virt = min_vaddr + (p * 0x1000); + // maps into the processes own PML4 NOT the global kernel one + paging_map_page_proc(proc->ulime->hpr, proc->pml4_phys, + orig_virt, phys, heap_flags); + } + + printf("[ELF] original VMA alias mapped\n"); + } + printf("[ELF] Relocated entry point: 0x%lX\n", proc->entry_point); printf("[ELF] Load successful\n"); return 0; diff --git a/src/kernel/exec/elf/loader.h b/src/kernel/packages/elf/loader.h similarity index 100% rename from src/kernel/exec/elf/loader.h rename to src/kernel/packages/elf/loader.h diff --git a/src/kernel/packages/emex/emex.c b/src/kernel/packages/emex/emex.c new file mode 100644 index 0000000..dddb43b --- /dev/null +++ b/src/kernel/packages/emex/emex.c @@ -0,0 +1,117 @@ +#include "emex.h" + +#include +#include +#include +#include +#include +#include +#include + +#if ENABLE_ULIME +extern proc_manager_t *proc_mgr; +extern ulime_t *ulime; +#endif + +// prints everything about a package to serial +void emex_print_info(emex_package_t *pkg) +{ + if (!pkg) return; + printf("[EMX] path: %s\n", pkg->path); + printf("[EMX] title: %s\n", pkg->info.title); + printf("[EMX] author: %s\n", pkg->info.author); + printf("[EMX] version: %s\n", pkg->info.version); + printf("[EMX] description: %s\n", pkg->info.description); + printf("[EMX] has icon: %s\n", pkg->has_icon ? "yes" : "no"); + printf("[EMX] resources: %s\n", pkg->has_resources ? "yes" : "no"); +} + +// opens the package, reads the elf, launches with process +int emex_launch_app(const char *path, ulime_proc_t **out_proc) +{ + if (!path) return EMEX_ERR_NOT_FOUND; + + if (out_proc) *out_proc = NULL; + + printf("[EMX] launching: %s\n", path); + + emex_package_t pkg; + int open_result = emex_open_app(path, &pkg); + if (open_result != EMEX_OK) { + printf("[EMX] failed to open package (code %d)\n", open_result); + return open_result; + } + + emex_print_info(&pkg); + + char elf_path[256]; + str_copy(elf_path, path); + int plen = str_len(elf_path); + if (plen > 0 && elf_path[plen - 1] != '/') str_append(elf_path, "/"); + str_append(elf_path, EMEX_ELF_NAME); + + int fd = fs_open(elf_path, O_RDONLY); + if (fd < 0) { + printf("[EMX] can't open %s\n", elf_path); + emex_close_app(&pkg); + return EMEX_ERR_NO_ELF; + } + + // 512kb max elf size, static to avoid depending on klime here + #define EMX_ELF_MAX_SIZE (512 * 1024) + static u8 elf_buf[EMX_ELF_MAX_SIZE]; + ssize_t elf_size = fs_read(fd, elf_buf, EMX_ELF_MAX_SIZE); + fs_close(fd); + + if (elf_size <= 0) { + printf("[EMX] elf file is empty or unreadable\n"); + emex_close_app(&pkg); + return EMEX_ERR_BAD_ELF; + } + + printf("[EMX] read %d bytes of elf\n", (int)elf_size); + +#if ENABLE_ULIME + if (!ulime || !proc_mgr) { + printf("[EMX] ulime/proc_mgr not ready\n"); + emex_close_app(&pkg); + return EMEX_ERR_NO_PROC; + } + + u8 proc_name[32]; + int name_len = str_len(pkg.info.title); + if (name_len > 31) name_len = 31; + int i; + for (i = 0; i < name_len; i++) { + proc_name[i] = (u8)pkg.info.title[i]; + } + proc_name[i] = '\0'; + + ulime_proc_t *proc = proc_create_proc(proc_mgr, proc_name, 0, USERPRIORITY); + if (!proc) { + printf("[EMX] failed to create process for '%s'\n", pkg.info.title); + emex_close_app(&pkg); + return EMEX_ERR_NO_PROC; + } + + printf("[EMX] created process pid=%llu for '%s'\n", proc->pid, pkg.info.title); + + int elf_result = elf_load(proc, elf_buf, (u64)elf_size); + if (elf_result != 0) { + printf("[EMX] elf_load failed for '%s'\n", pkg.info.title); + emex_close_app(&pkg); + return EMEX_ERR_BAD_ELF; + } + + printf("[EMX] '%s' ready at entry=0x%llX (state=PROC_READY)\n", + pkg.info.title, proc->entry_point); + + if (out_proc) *out_proc = proc; + +#else + printf("[EMX] ENABLE_ULIME is off, can't run the app\n"); +#endif + + emex_close_app(&pkg); + return EMEX_OK; +} diff --git a/src/kernel/packages/emex/emex.h b/src/kernel/packages/emex/emex.h new file mode 100644 index 0000000..06e2c64 --- /dev/null +++ b/src/kernel/packages/emex/emex.h @@ -0,0 +1,67 @@ +#ifndef EMEX_H +#define EMEX_H + +#include +#include +#include +#include + +// +// EMX it's the emexOS app package format +// used for compatibility with [REDACTED]OS (raspberry pi OS) +// https://github.com/differrari/RedactedOS/blob/main/kernel/process/loading/elf_file.c +// +// current different things: +// package.info uses html +// app.elf is a fixed name +// + +// those cant be changed otherwise compatibility will brake +#define EMEX_GEN_NAME "app" +#define EMEX_ELF_NAME EMEX_GEN_NAME "" ".elf" +#define EMEX_INFO_NAME "package.info" +#define EMEX_ICON_NAME "app_icon.bmp" +#define EMEX_RES_DIR "resources" +#define EMEX_NEWEXT ".emx" +#define EMEX_OK 0 +#define EMEX_ERR_NOT_FOUND -1// directory doesn't exist +#define EMEX_ERR_NOT_EMX -2 // wrong extention +#define EMEX_ERR_NO_ELF -3 // app.elf is missing without it the .emx is useles.... +#define EMEX_ERR_NO_INFO -4 // missing package.info +#define EMEX_ERR_BAD_INFO -5 // wrong package.info (can happen when redacted OS apps are transfered) +#define EMEX_ERR_BAD_ELF -6 // failed to load elf +#define EMEX_ERR_NO_PROC -7 // failed to create process + +// info parsed from package.info (html) +typedef struct { + char title[64];// fixed length + char author[64]; // fixed length + char version[16]; // fixed length + char description[256]; // fixed length +} emex_info_t; + +// the full package struct that gets filled by emex_open() +typedef struct { + char path[256]; // path to .emx + emex_info_t info; + bmp_image_t icon;// app icons are just bmp images + int has_icon; // 1 if success + int has_resources; +} emex_package_t; + +// packreader +int emex_open_app(const char *path, emex_package_t *pkg); +void emex_close_app(emex_package_t *pkg); + +// info parser +int emex_parse_info(const char *info_path, emex_info_t *info); + +// image/icon parser +int emex_load_icon(const char *icon_path, bmp_image_t *icon); +void emex_draw_icon(bmp_image_t *icon, u32 x, u32 y); + +// main file +int emex_launch_app(const char *path, ulime_proc_t **out_proc); +void emex_print_info(emex_package_t *pkg); + +#endif diff --git a/src/kernel/packages/emex/icnparse.c b/src/kernel/packages/emex/icnparse.c new file mode 100644 index 0000000..318b8b3 --- /dev/null +++ b/src/kernel/packages/emex/icnparse.c @@ -0,0 +1,31 @@ +#include "emex.h" + +#include +#include + +// +// icon loader +// + +int emex_load_icon(const char *icon_path, bmp_image_t *icon) +{ + if (!icon_path || !icon) return EMEX_ERR_NOT_FOUND; + + int result = bmp_load(icon_path, icon); + if (result != 0) { + printf("[EMX-ICON] failed to load icon from %s\n", icon_path); + return EMEX_ERR_NOT_FOUND; + } + + printf("[EMX-ICON] loaded icon (%dx%d)\n", icon->width, icon->height); + return EMEX_OK; +} + +void emex_draw_icon(bmp_image_t *icon, u32 x, u32 y) { + if (!icon || !icon->data) { + printf("[EMX-ICON] tried to draw a null icon, skipping\n"); + return; + } + + bmp_draw(icon, x, y); +} diff --git a/src/kernel/packages/emex/iparser.c b/src/kernel/packages/emex/iparser.c new file mode 100644 index 0000000..28d5a40 --- /dev/null +++ b/src/kernel/packages/emex/iparser.c @@ -0,0 +1,100 @@ +#include "emex.h" + +#include +#include +#include +#include + +// +// info parser/reader +// +// +// Cool App +// +// ein_franzose +// 3001.0 +// does cool stuff +// +// +// +// all fields except title are technically optional... +// but yeah better to have all those +// + +// copies src into dst, but caps it at max_len-1 so we don't overflow +// nothing fancy, just safe copying +static void safe_copy(char *dst, const char *src, int max_len) { + if (!dst || !src) return; + int i = 0; + while (src[i] != '\0' && i < max_len - 1) { + dst[i] = src[i]; + i++; + } + dst[i] = '\0'; +} + +int emex_parse_info(const char *info_path, emex_info_t *info) +{ + if (!info_path || !info) return EMEX_ERR_BAD_INFO; + + // zero out the info struct first so we always have clean defaults + str_copy(info->title,EMEX_ELF_NAME); + str_copy(info->author,EMEX_GEN_NAME "" EMEX_NEWEXT); + str_copy(info->version,"0"); + str_copy(info->description,"[empty]"); + + int fd = fs_open(info_path, O_RDONLY); + if (fd < 0) { + printf("[EMX-INFO] can't open %s\n", info_path); + return EMEX_ERR_NO_INFO; + } + + // read it into a buffer + char buf[2048]; // 2KB if we put all max lengths together it cant be more than this + + ssize_t bytes = fs_read(fd, buf, sizeof(buf) - 1); + fs_close(fd); + + if (bytes <= 0) { + printf("[EMX-INFO] %s is empty or unreadable\n", info_path); + return EMEX_ERR_BAD_INFO; + } + buf[bytes] = '\0'; + + // let the html parser do its thing + // NOTE: htmlparse() modifies the buffer in place (replaces some chars with \0), + // so we can't use "buf" for anything else after this call + htmlparse(buf); + // we need to create a new buffer now + + // grab whatever fields we can find and copy them into info + // if a field is missing we just keep the default from above + + const char *title = htmlget("title"); + const char *author = htmlget("author"); + const char *version = htmlget("version"); + const char *desc = htmlget("description"); + if (title && *title) { + safe_copy(info->title, title, sizeof(info->title)); + } else { + printf("[EMX-INFO] warning: no found in package.info\n"); + } + if (author && *author) { + safe_copy(info->author, author, sizeof(info->author)); + } else { + printf("[EMX-INFO] warning: no <author> tag in package.info\n"); + } + if (version && *version) { + safe_copy(info->version, version, sizeof(info->version)); + } else { + printf("[EMX-INFO] warning: no <version> tag in package.info\n"); + } + if (desc && *desc) { + safe_copy(info->description, desc, sizeof(info->description)); + } else { + printf("[EMX-INFO] warning: no <description> tag in package.info\n"); + } + + + return EMEX_OK; +} diff --git a/src/kernel/packages/emex/packreader.c b/src/kernel/packages/emex/packreader.c new file mode 100644 index 0000000..59dbe79 --- /dev/null +++ b/src/kernel/packages/emex/packreader.c @@ -0,0 +1,125 @@ +#include "emex.h" + +#include <kernel/file_systems/vfs/vfs.h> +#include <string/string.h> +#include <kernel/communication/serial.h> + + +// checks if a given path ends with .emx +static int path_has_emx_ext(const char *path) +{ + if (!path) return 0; + + int len = str_len(path); + // .emx + 1 + if (len < 5) return 0; + + // check the last 4 characters + const char *tail = path + len - 4; + return (tail[0] == '.' && + tail[1] == 'e' && + tail[2] == 'm' && + tail[3] == 'x'); + // guess what... its .emx ... mind blowing ik +} +// builds a full child path by joining base_path + / + child_name +// (/apps/myapp.emx + / + app.elf == /apps/myapp.emx/app.elf) +static void build_child_path(char *out, const char *base, const char *child) { + str_copy(out, base); + + int blen = str_len(out); + if (blen > 0 && out[blen - 1] != '/') { + str_append(out, "/"); + } + + str_append(out, child); +} +static int file_exists(const char *path) { + fs_node *node = fs_resolve(path); + if (!node) return 0; + return (node->type == FS_FILE); +} +static int dir_exists(const char *path) { + fs_node *node = fs_resolve(path); + if (!node) return 0; + return (node->type == FS_DIR); +} + +int emex_open_app(const char *path, emex_package_t *pkg) { + if (!path || !pkg) return EMEX_ERR_NOT_FOUND; + + // copy path to kernel buffer first, NEVER use the raw pointer again after this + str_copy(pkg->path, path); + pkg->has_icon = 0; + pkg->has_resources = 0; + + // only if the path ends with .emx + if (!path_has_emx_ext(pkg->path)) { + printf("[EMX] '%s' doesn't end with .emx, not a valid emx package\n", pkg->path); + return EMEX_ERR_NOT_EMX; + } + if (!dir_exists(pkg->path)) { + printf("[EMX] '%s' not found or isn't a directory\n", pkg->path); + return EMEX_ERR_NOT_FOUND; + } + + printf("[EMX] opening package: %s\n", pkg->path); + + char child_path[256]; + + // app.elf is required otherwise + build_child_path(child_path, pkg->path, EMEX_ELF_NAME); + if (!file_exists(child_path)) { + printf("[EMX] %s is missing! can't launch without it\n", EMEX_ELF_NAME); + return EMEX_ERR_NO_ELF; + } + printf("[EMX] found %s\n", EMEX_ELF_NAME); + + // package.info is also required with title the other things not really but well + build_child_path(child_path, pkg->path, EMEX_INFO_NAME); + if (!file_exists(child_path)) { + printf("[EMX] %s is missing! package needs metadata\n", EMEX_INFO_NAME); + return EMEX_ERR_NO_INFO; + } + printf("[EMX] found %s\n", EMEX_INFO_NAME); + int info_result = emex_parse_info(child_path, &pkg->info); + if (info_result != EMEX_OK) { + printf("[EMX] failed to parse %s (code %d)\n", EMEX_INFO_NAME, info_result); + return EMEX_ERR_BAD_INFO; + } + + // optional icon + // icon is later good for a taskbar or smth else but + // then i probably delete it from the kernel and move the icon parser to the wm or smth + build_child_path(child_path, pkg->path, EMEX_ICON_NAME); + if (file_exists(child_path)) { + printf("[EMX] found %s, loading...\n", EMEX_ICON_NAME); + if (emex_load_icon(child_path, &pkg->icon) == EMEX_OK) { + pkg->has_icon = 1; + } else { + pkg->has_icon = 0; + } + } else { + printf("[EMX] no %s found\n", EMEX_ICON_NAME); + } + + build_child_path(child_path, pkg->path, EMEX_RES_DIR); + if (dir_exists(child_path)) { + pkg->has_resources = 1; // optional to have + } + + printf("[EMX] package '%s' by %s v%s opened successfully\n", + pkg->info.title, pkg->info.author, pkg->info.version); + + return EMEX_OK; +} + +void emex_close_app(emex_package_t *pkg) { + if (!pkg) return; + if (pkg->has_icon) { + bmp_free(&pkg->icon); + pkg->has_icon = 0; + } + + printf("[EMX] package closed\n"); +} diff --git a/src/kernel/packages/gz/gzip.c.t b/src/kernel/packages/gz/gzip.c.t new file mode 100644 index 0000000..43dc54b --- /dev/null +++ b/src/kernel/packages/gz/gzip.c.t @@ -0,0 +1,197 @@ +#include <freestanding/stdint.h> +#include <freestanding/stddef.h> +#include <main/string.h> +#include <main/gzip.h> + +// +// MADE BY @msaid5860 +// gzip parser +// (currently not used) +// + +static uint32_t tgz_get_bits(tgz_stream *s, int bits) { + while (s->bit_cnt < bits) { + s->bit_buf |= ((uint32_t)(*s->in++)) << s->bit_cnt; + s->bit_cnt += 8; + } + uint32_t val = s->bit_buf & ((1 << bits) - 1); + s->bit_buf >>= bits; + s->bit_cnt -= bits; + return val; +} + +// --- Huffman Logic --- +typedef struct { + uint16_t counts[TGZ_MAX_BITS + 1]; + uint16_t symbols[TGZ_MAX_BITS + 1][288]; +} tgz_huffman; + +static void tgz_build_tree(tgz_huffman *tree, const uint8_t *lens, int n) { + int i, codes[TGZ_MAX_BITS + 1]; + memset(tree->counts, 0, sizeof(tree->counts)); + for (i = 0; i < n; i++) tree->counts[lens[i]]++; + tree->counts[0] = 0; + + int code = 0; + for (i = 1; i <= TGZ_MAX_BITS; i++) { + code = (code + tree->counts[i-1]) << 1; + codes[i] = code; + } + + int offsets_map[TGZ_MAX_BITS + 1]; + for(i=0; i<=TGZ_MAX_BITS; i++) offsets_map[i] = 0; + + for (i = 0; i < n; i++) { + if (lens[i] != 0) tree->symbols[lens[i]][offsets_map[lens[i]]++] = (uint16_t)i; + } +} + +static int tgz_decode_symbol(tgz_stream *s, tgz_huffman *tree) { + int len, code = 0, first = 0, count; + for (len = 1; len <= TGZ_MAX_BITS; len++) { + code |= tgz_get_bits(s, 1); + count = tree->counts[len]; + if (code - count < first) return tree->symbols[len][code - first]; + first += count; + first <<= 1; + code <<= 1; + } + return -1; +} + +static const uint8_t CLCL_ORDER[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + +// --- Inflate --- +static int tgz_inflate(tgz_stream *s) { + int final = 0; + while (!final) { + final = tgz_get_bits(s, 1); + int type = tgz_get_bits(s, 2); + + if (type == 0) { // Uncompressed + s->bit_buf >>= (s->bit_cnt & 7); + s->bit_cnt &= ~7; + uint16_t len = (uint16_t)tgz_get_bits(s, 16); + uint16_t nlen = (uint16_t)tgz_get_bits(s, 16); + if (len != (uint16_t)~nlen) return TGZ_ERR_FORMAT; + + // Note: No output bounds check here! + memcpy(s->out, s->in, len); + s->in += len; + s->out += len; + + } else if (type == 1 || type == 2) { + tgz_huffman lit_tree, dist_tree; + if (type == 1) { // Fixed + uint8_t lens[288], dist_lens[32]; + int i; + for (i=0; i<144; i++) lens[i] = 8; + for (; i<256; i++) lens[i] = 9; + for (; i<280; i++) lens[i] = 7; + for (; i<288; i++) lens[i] = 8; + tgz_build_tree(&lit_tree, lens, 288); + for (i=0; i<32; i++) dist_lens[i] = 5; + tgz_build_tree(&dist_tree, dist_lens, 32); + } else { // Dynamic + int hlit = tgz_get_bits(s, 5) + 257; + int hdist = tgz_get_bits(s, 5) + 1; + int hclen = tgz_get_bits(s, 4) + 4; + uint8_t code_lens[19]; + memset(code_lens, 0, 19); + for (int i = 0; i < hclen; i++) code_lens[CLCL_ORDER[i]] = (uint8_t)tgz_get_bits(s, 3); + + tgz_huffman code_tree; + tgz_build_tree(&code_tree, code_lens, 19); + uint8_t lens[288 + 32]; + int n = 0; + while (n < hlit + hdist) { + int sym = tgz_decode_symbol(s, &code_tree); + if (sym < 16) lens[n++] = (uint8_t)sym; + else if (sym == 16) { + int copy_len = tgz_get_bits(s, 2) + 3; + uint8_t prev = lens[n-1]; + while (copy_len--) lens[n++] = prev; + } else if (sym == 17) { + int copy_len = tgz_get_bits(s, 3) + 3; + while (copy_len--) lens[n++] = 0; + } else if (sym == 18) { + int copy_len = tgz_get_bits(s, 7) + 11; + while (copy_len--) lens[n++] = 0; + } + } + tgz_build_tree(&lit_tree, lens, hlit); + tgz_build_tree(&dist_tree, lens + hlit, hdist); + } + + while (1) { + int sym = tgz_decode_symbol(s, &lit_tree); + if (sym < 256) { + *s->out++ = (uint8_t)sym; + } else if (sym == 256) { + break; + } else { + sym -= 257; + static const int lbase[] = {3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258}; + static const int lext[] = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + int len = lbase[sym] + tgz_get_bits(s, lext[sym]); + + int dist_sym = tgz_decode_symbol(s, &dist_tree); + static const int dbase[] = {1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577}; + static const int dext[] = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + int dist = dbase[dist_sym] + tgz_get_bits(s, dext[dist_sym]); + + // LZ77 Byte Copy + uint8_t *src_copy = s->out - dist; + for (int i = 0; i < len; i++) *s->out++ = *src_copy++; + } + } + } else return TGZ_ERR_FORMAT; + } + return TGZ_OK; +} + +// --- Public Wrapper --- + +/* + * ungzip + * * src: pointer to GZIP data + * * dst: pointer to destination buffer (MUST BE LARGE ENOUGH) + * * Returns: Number of bytes written to dst + */ +int ungzip(const void *src, void *dst) { + const uint8_t *in = (const uint8_t *)src; + + // Check Header (0x1F, 0x8B, 0x08) + if (in[0] != 0x1F || in[1] != 0x8B || in[2] != 8) return TGZ_ERR_FORMAT; + + uint8_t flags = in[3]; + const uint8_t *data_start = in + 10; + + // Skip Header Fields + if (flags & 0x04) { // FEXTRA + uint16_t extra_len = data_start[0] | (data_start[1] << 8); + data_start += 2 + extra_len; + } + if (flags & 0x08) { // FNAME + while (*data_start) data_start++; + data_start++; + } + if (flags & 0x10) { // FCOMMENT + while (*data_start) data_start++; + data_start++; + } + if (flags & 0x02) data_start += 2; // FHCRC + + // Initialize Stream + tgz_stream stream; + stream.in = data_start; + stream.out = (uint8_t *)dst; + stream.out_start = (uint8_t *)dst; + stream.bit_buf = 0; + stream.bit_cnt = 0; + + // Decompress until End-of-Block symbol found + if (tgz_inflate(&stream) != TGZ_OK) return TGZ_ERR_FORMAT; + + return (int)(stream.out - stream.out_start); +} diff --git a/src/kernel/user/_start.c b/src/kernel/user/_start.c index 33796f6..22b790f 100644 --- a/src/kernel/user/_start.c +++ b/src/kernel/user/_start.c @@ -1,10 +1,11 @@ #include "gen.h" //mod -#define USERLOCATE "/user/bin/login.elf" +//#define USERLOCATE "/user/bin/login.elf" void DEinit(void) { + //dump_kprocesses(); log("[DE]", "init Desktop Enviroment...\n", d); /* input_pos = 0; @@ -17,15 +18,16 @@ void DEinit(void) print("\n", white()); - if (!login_authenticate()) { - hcf(); - } + */ + //if (!login_authenticate()) { + // hcf(); + //} + -*/ // smth like desktop enviroment and userswitch are here - console_init(); - keyboard_poll(); + //console_init(); + //keyboard_poll(); } diff --git a/src/kernel/user/calls.h b/src/kernel/user/calls.h index 6a9162c..c5da4d2 100644 --- a/src/kernel/user/calls.h +++ b/src/kernel/user/calls.h @@ -36,10 +36,28 @@ #define VFORK 58 #define EXECVE 59 + #define GETDENTS 78 // list directory entries (path, buf, max) #define CHDIR 80 #define MKDIR 83 #define FCHDIR 133 + #define UNLINK 87 + #define IOCTL 16 + #define MMAP 9 + #define MUNMAP 11 + #define FTRUNCATE 77 + + #define MQ_OPEN 240 + #define MQ_UNLINK 241 + #define MQ_SEND 242 + #define MQ_RECV 243 + + + #define SHM_DESTROY 245 + + // emex specific + #define EMXREBOOT 169 + #elif ARM64 == 1 #define EXIT 93 @@ -60,17 +78,30 @@ #define CLOSE 57 #define STAT 80 - //#define FSTAT 79 - //#define LSTAT 79 + + #define MMAP 222 + #define MUNMAP 215 + #define FTRUNCATE 46 #define FORK 220 #define VFORK 221 #define EXECVE 221 + #define GETDENTS 78 #define CHDIR 49 #define MKDIR 80 #define FCHDIR 50 + #define UNLINK 87 + #define IOCTL 16 + + #define MQ_OPEN 277 + #define MQ_UNLINK 278 + #define MQ_SEND 281 + #define MQ_RECV 282 + + #define SHM_DESTROY 283 + #endif diff --git a/src/kernel/user/gen.h b/src/kernel/user/gen.h index 49e537b..4f7376e 100644 --- a/src/kernel/user/gen.h +++ b/src/kernel/user/gen.h @@ -3,14 +3,14 @@ //source: src/kernel/console/console.h #include <kernel/graph/graphics.h> -#include <kernel/graph/fm.h> +#include <kernel/kernel_processes/fm/fm.h> +#include <kernel/kernel_processes/loader.h> #include <kernel/include/ports.h> #include <kernel/communication/serial.h> #include <drivers/ps2/keyboard/keyboard.h> //#include "graph/uno.h" //#include "graph/dos.h" #include <kernel/graph/theme.h> -#include <kernel/graph/fm.h> #include <theme/doccr.h> #include <config/user.h> #include <config/system.h> @@ -19,7 +19,7 @@ #include <kernel/proc/scheduler.h> #include <kernel/proc/proc_manager.h> #include <kernel/include/assembly.h> -#include <kernel/console/console.h> +//#include <kernel/console/console.h> #include <string/string.h> diff --git a/src/kernel/user/jump.c b/src/kernel/user/jump.c index 94845ea..c0ccad4 100644 --- a/src/kernel/user/jump.c +++ b/src/kernel/user/jump.c @@ -11,11 +11,19 @@ void JumpToUserspace(ulime_proc_t *proc) { return; } - u64 kernel_stack = proc->stack_base + 0x1000; - gdt_set_kernel_stack(kernel_stack); + //u64 kernel_stack = proc->stack_base + 0x1000; + //gdt_set_kernel_stack(kernel_stack); u64 user_rip = proc->entry_point; - u64 user_rsp = (proc->stack_base + proc->stack_size - 16) & ~0xFULL; // 16-byte aligned + + // use entry_rsp if it was set by execve argv + u64 user_rsp; + if (proc->entry_rsp != 0) { + user_rsp = proc->entry_rsp; + } else { + user_rsp = (proc->stack_base + proc->stack_size - 16) & ~0xFULL; // 16-byte aligned + } + u64 user_rflags = 0x202; // IF=1 , reserved bit 1 set u16 user_cs = USER_CODE_SELECTOR | 3; // RPL=3 @@ -26,56 +34,12 @@ void JumpToUserspace(ulime_proc_t *proc) { printf("[ULIME] Jumping to %s at RIP=0x%lX RSP=0x%lX\n", proc->name, user_rip, user_rsp); - if (user_rip < proc->heap_base || user_rip >= proc->heap_base + proc->heap_size) { - printf("[ULIME] ERROR: RIP 0x%lX outside process heap!\n", user_rip); - return; - } - if (user_rsp < proc->stack_base || user_rsp >= proc->stack_base + proc->stack_size) { - printf("[ULIME] ERROR: RSP 0x%lX outside process stack!\n", user_rsp); - return; - } - - printf("[ULIME] Values: SS=0x%X CS=0x%X RFLAGS=0x%lX\n", - user_ss, user_cs, user_rflags); - - printf("[ULIME] iretq frame will be:\n"); - printf(" [RIP] = 0x%016lX\n", user_rip); - printf(" [CS] = 0x%016lX\n", (u64)user_cs); - printf(" [RFLAGS] = 0x%016lX\n", user_rflags); - printf(" [RSP] = 0x%016lX\n", user_rsp); - printf(" [SS] = 0x%016lX\n", (u64)user_ss); - - u64 *test_rip = (u64*)user_rip; - u64 *test_rsp = (u64*)user_rsp; - - printf("[ULIME] Testing memory access:\n"); - printf(" Code at RIP: 0x%016lX\n", *test_rip); - - // try writing to stack - *test_rsp = 0xDEADBEEF; - if (*test_rsp != 0xDEADBEEF) { - printf("[ULIME] ERROR: Stack not writable!\n"); - return; - } - printf(" Stack test: PASS\n"); - - // page table permissions - printf("\n"); - if (!verify_page_permissions(proc->ulime->hpr, user_rip, "Code page")) { - printf("[ULIME] ERROR: code page not properly mapped!\n"); - return; - } - printf("\n"); - if (!verify_page_permissions(proc->ulime->hpr, user_rsp, "Stack page")) { - printf("[ULIME] ERROR: stack page not properly mapped!\n"); - return; - } - printf("\n"); - + // switch to the processes own PML4 BEFORE touching any userspace addresses + __asm__ volatile( "mov %0, %%cr3" : : "r"(proc->pml4_phys) : "memory"); __asm__ volatile( "cli\n" - "subq $40, %%rsp\n"//$40 == (allocate) 40 bytes + "subq $40, %%rsp\n"//allocate 40 bytes "movq %0, 32(%%rsp)\n" // SS "movq %1, 24(%%rsp)\n" // user RSP @@ -84,9 +48,9 @@ void JumpToUserspace(ulime_proc_t *proc) { "movq %4, 0(%%rsp)\n" // RIP // verifys what debug wrote (halt if after jump back doesnt got verified) - "movq 0(%%rsp), %%rax\n" - "cmp %4, %%rax\n" - "jne 1f\n" + //"movq 0(%%rsp), %%rax\n" + //"cmp %4, %%rax\n" + //"jne 1f\n" //"cli\n" // clears General Purpose Registers @@ -109,8 +73,8 @@ void JumpToUserspace(ulime_proc_t *proc) { // even sysretq doesnt work "iretq\n" - "1:\n" // corruption - "hlt\n" + //"1:\n" // corruption + //"hlt\n" : : "r"((u64)user_ss), "r"(user_rsp), diff --git a/src/kernel/user/resume_parent_sysret.asm b/src/kernel/user/resume_parent_sysret.asm new file mode 100644 index 0000000..9c16495 --- /dev/null +++ b/src/kernel/user/resume_parent_sysret.asm @@ -0,0 +1,55 @@ +bits 64 + +global resume_parent_sysret +resume_parent_sysret: + cli + + ;read stack args before we lose rsp + mov rax, [rsp + 8] ;r12 + mov [rel .r12], rax + mov rax, [rsp + 16] ;r13 + mov [rel .r13], rax + mov rax, [rsp + 24] ;r14 + mov [rel .r14], rax + mov rax, [rsp + 32] ;r15 + mov [rel .r15], rax + + ;switch to parents page table + ;kernel upperhalf stays valid after this switch + mov cr3, rcx + + ;set up sysret registers: + ; rcx = return RIP (was in rdi) + ; r11 = RFLAGS (was in rdx) + ; rsp = user stack (was in rsi) + mov rcx, rdi ; RIP >> rcx (sysret reads RIP from here) + mov r11, rdx ; RFLAGS >> r11 (sysret reads RFLAGS from here) + mov rsp, rsi ; restore user stack + + + ;restore callee-saved registers + mov rbx, r8 + mov rbp, r9 + mov r12, [rel .r12] + mov r13, [rel .r13] + mov r14, [rel .r14] + mov r15, [rel .r15] + + ;rax = 0 >> execve() return value the parent sees (success) + xor rax, rax + xor rdi, rdi + xor rsi, rsi + xor rdx, rdx + ; rcx/r11/rsp already set above, don't zero them + xor r8, r8 + xor r9, r9 + xor r10, r10 + + o64 sysret ; RIP = rcx, RFLAGS = r11, CPL >> 3 + +section .data +align 8 +.r12: dq 0 +.r13: dq 0 +.r14: dq 0 +.r15: dq 0 diff --git a/src/kernel/user/scalls/mq.c b/src/kernel/user/scalls/mq.c new file mode 100644 index 0000000..8320b8e --- /dev/null +++ b/src/kernel/user/scalls/mq.c @@ -0,0 +1,49 @@ +#include "scalls.h" +#include <kernel/multitasking/ipc/ipc.h> + +u64 scall_mq_open(ulime_proc_t *proc, u64 name_ptr, u64 oflag, u64 mode) +{ + (void)oflag; + (void)mode; + + if (!name_ptr || name_ptr > 0x0000800000000000ULL) return (u64)-1; + + open_inbox(proc->ulime, proc); + return (u64)proc->pid; +} + +u64 scall_mq_unlink(ulime_proc_t *proc, u64 name_ptr, u64 arg2, u64 arg3) +{ + (void)name_ptr; + (void)arg2; + (void)arg3; + + destroy_endpoint(proc->ulime, proc); + return 0; +} + +u64 scall_mq_send(ulime_proc_t *proc, u64 mqid, u64 buf, u64 size) { + int r = send_msg(proc->ulime, proc, mqid, (const void *)buf, (u32)size); + + if (!buf || buf > 0x0000800000000000ULL) return (u64)-1; + if (size == 0 || size > IPC_MAX_MSG_SIZE) return (u64)-1; + + return r == 0 ? 0 : (u64)-1; +} + +u64 scall_mq_recv(ulime_proc_t *proc, u64 mqid, u64 buf, u64 size) +{ + (void)mqid; + + u64 sender = 0; + int got = receive_async_msg(proc->ulime, proc, (void *)buf, (u32)size, &sender); + + if (!buf || buf > 0x0000800000000000ULL) return (u64)-1; + if (size == 0) return (u64)-1; + if (got < 0) { + receive_msg(proc->ulime, proc, (void *)buf, (u32)size, &sender); + got = (int)size; + } + + return (u64)got; +} \ No newline at end of file diff --git a/src/kernel/user/scalls/scalls.h b/src/kernel/user/scalls/scalls.h new file mode 100644 index 0000000..ca5c1dc --- /dev/null +++ b/src/kernel/user/scalls/scalls.h @@ -0,0 +1,17 @@ +#pragma once + +#include <types.h> +#include <kernel/user/ulime.h> + +u64 scall_mq_open(ulime_proc_t *proc, u64 name_ptr, u64 oflag, u64 mode); +u64 scall_mq_unlink(ulime_proc_t *proc, u64 name_ptr, u64 arg2, u64 arg3); +u64 scall_mq_send(ulime_proc_t *proc, u64 mqid, u64 buf, u64 size); +u64 scall_mq_recv(ulime_proc_t *proc, u64 mqid, u64 buf, u64 size); + +u64 scall_mmap(ulime_proc_t *proc, u64 addr, u64 length, u64 shm_id); +u64 scall_munmap(ulime_proc_t *proc, u64 addr, u64 length, u64 arg3); + +//u64 scall_fork(ulime_proc_t *proc, u64 a1, u64 a2, u64 a3); + +// emex specific +u64 scall_reboot(ulime_proc_t *proc, u64 magic1, u64 magic2, u64 cmd); \ No newline at end of file diff --git a/src/kernel/user/scalls/shm.c b/src/kernel/user/scalls/shm.c new file mode 100644 index 0000000..4a6e9ce --- /dev/null +++ b/src/kernel/user/scalls/shm.c @@ -0,0 +1,35 @@ +#include "scalls.h" +#include <kernel/multitasking/ipc/ipc.h> + +u64 scall_mmap(ulime_proc_t *proc, u64 addr, u64 length, u64 shm_id) { + (void)addr; + + u32 pages = (u32)((length + 0xFFF) / 0x1000); + if (pages == 0) pages = 1; + + if (shm_id == 0) { + u64 id = shm_create(proc->ulime, pages); + if (id == IPC_SHM_INVALID) return (u64)-1; + void *virt = shm_attach(proc->ulime, proc, id); + return virt == NULL ? (u64)-1 : (u64)virt; + } + + void *virt = shm_attach(proc->ulime, proc, shm_id); + return virt == NULL ? (u64)-1 : (u64)virt; +} + +u64 scall_munmap(ulime_proc_t *proc, u64 addr, u64 length, u64 arg3) { + (void)length; (void)arg3; + if (addr == 0) return (u64)-1; + + for (int i = 0; i < IPC_MAX_SHM; i++) { + //shm_detach handles "not found" gracefully + // + // TODO: + // reverse lookup by virt addr + (void)proc; + break; + } + + return 0; +} \ No newline at end of file diff --git a/src/kernel/user/scalls/system.c b/src/kernel/user/scalls/system.c new file mode 100644 index 0000000..8eeb2d2 --- /dev/null +++ b/src/kernel/user/scalls/system.c @@ -0,0 +1,25 @@ +#include "scalls.h" +#include <kernel/cpu/poweroff.h> +#include <kernel/user/ulime.h> +#include <drivers/ps2/mouse/mouse.h> + +// unix/linux -like +#define RSYSTEM_MAGIC1 0xfee1dead +#define RSYSTEM_MAGIC2 0x28121969 +#define RSYSTEM_CMD_RESTART 0x01234567 +#define RSYSTEM_CMD_HALT 0xcdef0123 +#define RSYSTEM_CMD_POWEROFF 0x4321fedc + +u64 scall_reboot(ulime_proc_t *proc, u64 magic1, u64 magic2, u64 cmd) { + (void)proc; + + if (magic1 != RSYSTEM_MAGIC1 || magic2 != RSYSTEM_MAGIC2) return (u64)-1; + + if (cmd == RSYSTEM_CMD_RESTART) { + cpu_poweroff(POWEROFF_REBOOT); + } else if (cmd == RSYSTEM_CMD_POWEROFF || cmd == RSYSTEM_CMD_HALT) { + cpu_poweroff(POWEROFF_SHUTDOWN); + } + + return (u64)-1; +} \ No newline at end of file diff --git a/src/kernel/user/syscalls.c b/src/kernel/user/syscalls.c index 2bdbad7..27d8a7d 100644 --- a/src/kernel/user/syscalls.c +++ b/src/kernel/user/syscalls.c @@ -7,99 +7,658 @@ #include <string/string.h> //#include <kernel/mem/paging/paging.h> #include <kernel/graph/theme.h> +#include <kernel/packages/emex/emex.h> +#include <kernel/packages/elf/loader.h> +#include <kernel/file_systems/vfs/vfs.h> +#include <kernel/proc/proc_manager.h> #include <theme/doccr.h> +#include <kernel/arch/x86_64/gdt/gdt.h> +#include <kernel/cpu/cpu.h> -static ulime_t *g_ulime = NULL; +// read syscall +#include <drivers/drivers.h> + +#include <kernel/devices/devices.h> + +#include <config/user.h> + +// memory +#include <syscalls/mmap.h> +#include <kernel/mem/paging/paging.h> +#include <kernel/mem/phys/physmem.h> + +//multitasking +#include <kernel/multitasking/ipc/ipc.h> +#include <kernel/multitasking/multitasking.h> + +#include "scalls/scalls.h" + +//#include <kernel/devices/fb0/fb0.h> +//#include <kernel/devices/tty/tty0.h> + + +ulime_t *g_ulime = NULL; + +#if ENABLE_ULIME +extern ulime_t *ulime; +#endif + +#define SCWRITE 0xFFFFFFFF +//#define KEYBOARD0 KBDPATH +#define MOUSE0 MS0PATH + +extern char cwd[]; +extern mt_t *mt; + +// fromsyscall_entry.asm +extern u64 user_rsp; +extern u64 user_rcx; +extern u64 user_r11; +extern u64 user_cr3; +extern u64 user_rbx; +extern u64 user_rbp; +extern u64 user_r12; +extern u64 user_r13; +extern u64 user_r14; +extern u64 user_r15; +extern void resume_parent_sysret(u64 rip,u64 rsp,u64 r11,u64 cr3,u64 rbx,u64 rbp,u64 r12,u64 r13,u64 r14,u64 r15); + +// full saved context of the blocked parent +static ulime_proc_t *blocked_parent = NULL; +static u64 blocked_parent_rip = 0; +static u64 blocked_parent_rsp = 0; +static u64 blocked_parent_cr3 = 0; +static u64 blocked_parent_rbx = 0; +static u64 blocked_parent_r11 = 0; +static u64 blocked_parent_rbp = 0; +static u64 blocked_parent_r12 = 0; +static u64 blocked_parent_r13 = 0; +static u64 blocked_parent_r14 = 0; +static u64 blocked_parent_r15 = 0; +static ulime_proc_t *find_proc_by_cr3(ulime_t *u, u64 cr3) { + ulime_proc_t *p = u->ptr_proc_list; + while (p) { + if (p->pml4_phys == cr3) return p; + p = p->next; + } + return NULL; +} + +static u32 ansi_fg_color = SCWRITE; +static u32 ansi_code_to_color(int code) { + switch (code) { + case 0: return 0xFFFFFFFF; // reset (white) + case 30: return 0xFF111111; // black + case 31: return 0xFFFF5555; // red + case 32: return 0xFF55FF55; // green + case 33: return 0xFFFFFF55; // yellow + case 34: return 0xFF5555FF; // blue + case 35: return 0xFFFF55FF; // magenta + case 36: return 0xFF55FFFF; // cyan + case 37: return 0xFFFFFFFF; // white + case 90: return 0xFF888888; // gray + case 91: return 0xFFFF8888; // bright red + case 92: return 0xFF88FF88; // bright green + case 93: return 0xFFFFFF88; // bright yellow + case 94: return 0xFF8888FF; // bright blue + case 95: return 0xFFFF88FF; // bright magenta + case 96: return 0xFF88FFFF; // bright cyan + case 97: return 0xFFFFFFFF; // bright white + default: return 0xFFFFFFFF; + } +} + +typedef enum { + ANSI_STATE_NORMAL = 0, + ANSI_STATE_ESC,// saw \033 + ANSI_STATE_CSI,// saw \033[ +} ansi_state_t; + +static ansi_state_t ansi_state = ANSI_STATE_NORMAL; +static int ansi_param = 0; + +static void ansi_write_char(char c) { + char tmp[2] = {c, '\0'}; + switch (ansi_state) { + case ANSI_STATE_NORMAL: + if (c == '\033') { ansi_state = ANSI_STATE_ESC; } + else { cprintf(tmp, ansi_fg_color); } + break; + case ANSI_STATE_ESC: + if (c == '[') { ansi_state = ANSI_STATE_CSI; ansi_param = 0; } + else {cprintf("\033", ansi_fg_color); cprintf(tmp, ansi_fg_color); ansi_state = ANSI_STATE_NORMAL;} + break; + case ANSI_STATE_CSI: + if (c >= '0' && c <= '9') { + ansi_param = ansi_param * 10 + (c - '0'); + } else if (c == 'm') { + ansi_fg_color = ansi_code_to_color(ansi_param); + ansi_param = 0; + ansi_state = ANSI_STATE_NORMAL; + } else if (c == ';') { + ansi_fg_color = ansi_code_to_color(ansi_param); + ansi_param = 0; + } else { + ansi_param = 0; + ansi_state = ANSI_STATE_NORMAL; + } + break; + } +} // syscall handlers u64 scall_write(ulime_proc_t *proc, u64 fd, u64 buf, u64 count) { (void)proc; + if (buf == 0 || buf > 0x0000800000000000ULL) return (u64)-1; + + if (fd >= 3) + return (u64)fs_write((int)fd, (const void *)buf, (size_t)count); + if (fd != 1 && fd != 2) return (u64)-1; - const char *str = (const char *)buf; - for (u64 i = 0; i < count; i++) { - //count ++; - printf("%c", str[i]); + // lazy-open /dev/tty0 + static int tty_fd = -1; + if (tty_fd < 0) { + tty_fd = fs_open(TTY0PATH, O_WRONLY); + if (tty_fd < 0) { + const char *s = (const char *)buf; + for (u64 i = 0; i < count; i++) tty0_write_char(s[i]); + return count; + } } - - return count; + return (u64)fs_write(tty_fd, (const void *)buf, (size_t)count); } -u64 scall_exit(ulime_proc_t *proc, u64 exit_code, u64 arg2, u64 arg3) { +u64 scall_exit(ulime_proc_t *proc, u64 exit_code, u64 arg2, u64 arg3) +{ (void)arg2; (void)arg3; printf("\n[SYSCALL] process '%s' exited with code %lu\n", proc->name, exit_code); proc->state = PROC_ZOMBIE; - //BOOTUP_PRINTF("[USERMODE] !!! RETURN !!!\n"); + if (blocked_parent) { + ulime_proc_t *parent = blocked_parent; + u64 rip = blocked_parent_rip; + u64 rsp = blocked_parent_rsp; + u64 r11 = blocked_parent_r11; + u64 cr3 = blocked_parent_cr3; + u64 rbx = blocked_parent_rbx; + u64 rbp = blocked_parent_rbp; + u64 r12 = blocked_parent_r12; + u64 r13 = blocked_parent_r13; + u64 r14 = blocked_parent_r14; + u64 r15 = blocked_parent_r15; + + blocked_parent = NULL; + blocked_parent_rip = 0; + blocked_parent_rsp = 0; + blocked_parent_r11 = 0; + blocked_parent_cr3 = 0; + blocked_parent_rbx = 0; + blocked_parent_rbp = 0; + blocked_parent_r12 = 0; + blocked_parent_r13 = 0; + blocked_parent_r14 = 0; + blocked_parent_r15 = 0; + parent->state = PROC_RUNNING; + g_ulime->ptr_proc_curr = parent; + + printf("[SYSCALL] resuming '%s' via sysret: RIP=0x%lX\n", parent->name, rip); + + // restore full parent state + resume_parent_sysret(rip, rsp, r11, cr3, rbx, rbp, r12, r13, r14, r15); + __builtin_unreachable(); + } + + g_ulime->ptr_proc_curr = NULL; while(1) { __asm__ volatile("cli; hlt"); } - return 0; } -u64 scall_read(ulime_proc_t *proc, u64 fd, u64 buf, u64 count) { - (void)proc; - (void)fd; - (void)buf; - (void)count; +static void setup_argv_on_stack(ulime_proc_t *new_proc, char **user_argv, int argc) +{ + if (argc <= 0 || !user_argv) return; - return 0; + u64 hhdm = g_ulime->hpr->offset; + u64 pstack = new_proc->phys_stack; + u64 ssize = new_proc->stack_size; + u64 sbase = new_proc->stack_base; + + u64 str_p_phys = pstack + ssize; + u64 str_p_virt = sbase + ssize; + + u64 str_vaddrs[32]; + + for (int i = argc - 1; i >= 0; i--) { + const char *s = user_argv[i]; + u64 len = 0; + while (s[len]) len++; + len++; + + str_p_phys -= len; + str_p_virt -= len; + + char *dst = (char *)(hhdm + str_p_phys); + for (u64 j = 0; j < len; j++) dst[j] = s[j]; + str_vaddrs[i] = str_p_virt; + } + + str_p_virt = str_p_virt & ~7ULL; + str_p_phys = pstack + (str_p_virt - sbase); + + u64 ptrsec = (u64)(1 + argc + 1) * 8; + u64 rsp_phys = (str_p_phys - ptrsec) & ~0xFULL; + u64 rsp_virt = sbase + (rsp_phys - pstack); + + u64 *p = (u64 *)(hhdm + rsp_phys); + *p++ = (u64)argc; + for (int i = 0; i < argc; i++) *p++ = str_vaddrs[i]; + *p = 0; + + new_proc->entry_rsp = rsp_virt; } -u64 scall_getpid(ulime_proc_t *proc, u64 arg1, u64 arg2, u64 arg3) { - (void)arg1; - (void)arg2; +u64 scall_execve(ulime_proc_t *proc, u64 path_ptr, u64 argv_ptr, u64 arg3) +{ (void)arg3; + if (path_ptr == 0 || path_ptr > 0x0000800000000000ULL) return (u64)-1; + + const char *path = (const char *)path_ptr; + + printf("[SYSCALL] execve: '%s'\n", path); + + ulime_proc_t *caller = find_proc_by_cr3(g_ulime, user_cr3); + if (!caller) {caller = proc;} + + int path_len = str_len(path); + int is_elf = (path_len > 4 && + path[path_len - 4] == '.' && + path[path_len - 3] == 'e' && + path[path_len - 2] == 'l' && + path[path_len - 1] == 'f'); + + ulime_proc_t *new_proc = NULL; + + if (is_elf) { + if (!ulime || !proc_mgr) { + printf("[SYSCALL] execve: ulime not ready\n"); + return (u64)-1; + } + + int fd = fs_open(path, O_RDONLY); + if (fd < 0) { + printf("[SYSCALL] execve: cannot open '%s'\n", path); + return (u64)-1; + } + + #define EXECVE_ELF_MAX (512 * 1024) + static u8 execve_elf_buf[EXECVE_ELF_MAX]; + + ssize_t elf_size = fs_read(fd, execve_elf_buf, EXECVE_ELF_MAX); + fs_close(fd); + + if (elf_size <= 0) { + printf("[SYSCALL] execve: elf empty or unreadable\n"); + return (u64)-1; + } + + const char *name = path; + for (int i = 0; i < path_len; i++) { + if (path[i] == '/') name = path + i + 1; + } + + new_proc = proc_create_proc(proc_mgr, (u8*)name, 0, USERPRIORITY); + if (!new_proc) { + printf("[SYSCALL] execve: failed to create process\n"); + return (u64)-1; + } + + if (elf_load(new_proc, execve_elf_buf, (u64)elf_size) != 0) { + printf("[SYSCALL] execve: elf_load failed\n"); + return (u64)-1; + } + } else { + + int result = emex_launch_app(path, &new_proc); + if (result != 0 || !new_proc) { + printf("[SYSCALL] execve failed with code %d\n", result); + return (u64)-1; + } + } + + if (argv_ptr && argv_ptr < 0x0000800000000000ULL) { + char **user_argv = (char **)argv_ptr; + int argc = 0; + while (argc < 31 && user_argv[argc]) argc++; + setup_argv_on_stack(new_proc, user_argv, argc); + } + + blocked_parent = caller; + blocked_parent_rip = user_rcx; + blocked_parent_rsp = user_rsp; + blocked_parent_r11 = user_r11; + blocked_parent_cr3 = user_cr3; + blocked_parent_rbx = user_rbx; + blocked_parent_rbp = user_rbp; + blocked_parent_r12 = user_r12; + blocked_parent_r13 = user_r13; + blocked_parent_r14 = user_r14; + blocked_parent_r15 = user_r15; + + caller->state = PROC_BLOCKED; + g_ulime->ptr_proc_curr = new_proc; + + printf("[SYSCALL] process '%s' blocked, waiting for '%s'\n", + caller->name, new_proc->name); + + JumpToUserspace(new_proc); + + __builtin_unreachable(); +} + +u64 scall_read(ulime_proc_t *proc, u64 fd, u64 buf, u64 count) +{ + (void)proc; + if (buf == 0 || count == 0) return 0; + + // (urandom, zero, files, ...) + if (fd >= 3) + return (u64)fs_read((int)fd, (void *)buf, (size_t)count); + + // fd 0 stdin to tty0 + if (fd != 0) return (u64)-1; + + static int tty_fd = -1; + if (tty_fd < 0) { + tty_fd = fs_open(TTY0PATH, O_RDONLY); + if (tty_fd < 0) { + printf("[SYSCALL] read: cannot open " TTY0PATH "\n"); + return (u64)-1; + } + } + return (u64)fs_read(tty_fd, (void *)buf, (size_t)count); +} + +u64 scall_getpid(ulime_proc_t *proc, u64 arg1, u64 arg2, u64 arg3) { + (void)arg1; (void)arg2; (void)arg3; return proc->pid; } -u64 scall_brk(ulime_proc_t *proc, u64 addr, u64 arg2, u64 arg3) { - (void)arg2; - (void)arg3; +u64 scall_brk(ulime_proc_t *proc, u64 addr, u64 arg2, u64 arg3) +{ + (void)arg2; (void)arg3; + + if (addr == 0) return proc->brk; + + + u64 heap_end = proc->heap_base + proc->heap_size; + if (addr > heap_end) { + printf("[SYSCALL] brk: OOM — 0x%lX > heap end 0x%lX\n", addr, heap_end); + return proc->brk; + } + + if (addr < proc->heap_base) return proc->brk; + + proc->brk = addr; + return proc->brk; +} + +u64 scall_open(ulime_proc_t *proc, u64 path_ptr, u64 flags, u64 arg3) { + (void)proc; (void)arg3; + if (!path_ptr || path_ptr > 0x0000800000000000ULL) return (u64)-1; + int fd = fs_open((const char *)path_ptr, (int)flags); + return (fd < 0) ? (u64)-1 : (u64)fd; +} + +u64 scall_close(ulime_proc_t *proc, u64 fd, u64 arg2, u64 arg3) { + (void)proc; (void)arg2; (void)arg3; + return (u64)fs_close((int)fd); +} + +u64 scall_getdents(ulime_proc_t *proc, u64 path_ptr, u64 buf_ptr, u64 max_entries) { + (void)proc; + if (!path_ptr || !buf_ptr || path_ptr > 0x0000800000000000ULL) return (u64)-1; + int n = fs_listdir((const char *)path_ptr, (_emx_kdirent_t *)buf_ptr, (int)max_entries); + return (n < 0) ? (u64)-1 : (u64)n; +} + +u64 scall_chdir(ulime_proc_t *proc, u64 path_ptr, u64 arg2, u64 arg3) +{ + (void)proc; (void)arg2; (void)arg3; + + if (!path_ptr || path_ptr > 0x0000800000000000ULL) return (u64)-1; + + const char *s = (const char *)path_ptr; + + // no argument then go to root + if (!s || *s == '\0') { + str_copy(cwd, "/"); + return 0; + } + + char new_path[FS_MAX_PATH]; + + // handle ".." (go back) before resolution + if (str_equals(s, "..")) { + int len = str_len(cwd); + if (len > 1 && cwd[len - 1] == '/') { + cwd[len - 1] = '\0'; + len--; + } + for (int i = len - 1; i >= 0; i--) { + if (cwd[i] == '/') { + if (i == 0) str_copy(cwd, "/"); + else cwd[i] = '\0'; + return 0; + } + } + return 0; + } + + // absolute vs relative path + if (s[0] == '/') { + str_copy(new_path, s); + } else { + str_copy(new_path, cwd); + if (cwd[str_len(cwd) - 1] != '/') str_append(new_path, "/"); + str_append(new_path, s); + } + + // verifyy the path exists and is a directory + fs_node *dir = fs_resolve(new_path); + if (!dir) return (u64)-1; + if (dir->type != FS_DIR) return (u64)-1; + + + // new cwd + str_copy(cwd, new_path); + + // ensurey trailing slash (except for root) + int len = str_len(cwd); + if (len > 1 && cwd[len - 1] != '/') str_append(cwd, "/"); - if (addr == 0) { - return proc->heap_base + proc->heap_size; + return 0; +} + +u64 scall_ioctl(ulime_proc_t *proc, u64 fd, u64 request, u64 arg_ptr) +{ + (void)proc; + if (arg_ptr > 0x0000800000000000ULL) return (u64)-1; + + void *arg = (void *)arg_ptr; + + // fb0:fb0_ioctl + if (fd >= 3) { + fs_file *f = fs_get_file((int)fd); + if (f && f->node) { + // fb0 ioctl + if (str_equals(f->node->name, "fb0")) { + return (u64)fb0_ioctl((int)request, arg); + } + } + } + + // tty ioctl (fd 0, 1, 2) + if (fd <= 2) { + switch ((int)request) { + case 0: tty0_set_echo_mode(0); return 0; // TTY_ECHO + case 1: tty0_set_echo_mode(1); return 0; // TTY_NOECHO + case 2: tty0_set_echo_mode(2); return 0; // TTY_MASKECHO + case 3: tty0_set_echo_mode(3); return 0; // TTY_RAW + default: return (u64)-1; + } } - u64 new_size = addr - proc->heap_base; - if (new_size > proc->heap_size) { - proc->heap_size = new_size; + return (u64)-1; +} + +u64 scall_getcwd(ulime_proc_t *proc, u64 buf_ptr, u64 size, u64 arg3) { + (void)proc; + (void)arg3; + + if (!buf_ptr || size == 0 || buf_ptr > 0x0000800000000000ULL) return 0; + + char *buf = (char *)buf_ptr; + int cwlen = str_len(cwd); + + if ((u64)(cwlen + 1) > size) return 0; // buffer too small + + str_copy(buf, cwd); + return (u64)(cwlen + 1); // return written byte count (> 0 = success) +} + +/*u64 scall_mmap(ulime_proc_t *proc, u64 args_ptr, u64 arg2, u64 arg3) { + (void)arg2; (void)arg3; + + if (!args_ptr || args_ptr > 0x0000800000000000ULL) return (u64)MAP_FAILED; + + mmap_args_t *a = (mmap_args_t *)args_ptr; + + if (a->length == 0) return (u64)MAP_FAILED; + + u64 len = (a->length + 0xFFF) & ~0xFFFULL; + u64 pages = len / 4096; + + if (a->flags & MAP_ANONYMOUS) { + u64 phys = physmem_alloc_to(pages); + if (!phys) return (u64)MAP_FAILED; + + u64 virt = a->addr; + if (!virt || virt < 0x400000) { + virt = proc->mmap_base; + if (!virt) virt = proc->heap_base + proc->heap_size + 0x100000; + } + virt = (virt + 0xFFF) & ~0xFFFULL; + + for (u64 i = 0; i < pages; i++) { + paging_map_page_proc( + g_ulime->hpr, + proc->pml4_phys, + virt + i * 4096, + phys + i * 4096, + USER_FLAGS + ); + } + + // zero via HHDM + u8 *p = (u8 *)(phys + g_ulime->hpr->offset); + for (u64 i = 0; i < len; i++) p[i] = 0; + + proc->mmap_base = virt + len; + return virt; } - return proc->heap_base + proc->heap_size; + // fb0 file mapping + if (a->fd >= 3) { + fs_file *f = fs_get_file(a->fd); + if (f && f->node && str_equals(f->node->name, "fb0")) { + u32 *fb = get_framebuffer(); + u64 fbphys = virt_to_phys(g_ulime->hpr, (void *)fb); + u64 fbsize = (u64)get_fb_pitch() * get_fb_height(); + + u64 fbpages = (fbsize + 0xFFF) / 4096; + u64 virt = a->addr; + if (!virt) virt = proc->mmap_base; + if (!virt) virt = 0x3000000; + virt = (virt + 0xFFF) & ~0xFFFULL; + + for (u64 i = 0; i < fbpages; i++) { + paging_map_page_proc( + g_ulime->hpr, + proc->pml4_phys, + virt + i * 4096, + fbphys + i * 4096, + USER_FLAGS | PTE_PCD + ); + } + proc->mmap_base = virt + fbpages * 4096; + return virt; + } + } + return (u64)MAP_FAILED; } +u64 scall_munmap(ulime_proc_t *proc, u64 addr, u64 length, u64 arg3) { + (void)proc; (void)arg3; + if (!addr) return (u64)-1; -void _init_syscalls_table(ulime_t *ulime) { - if (!ulime) return; + u64 len = (length + 0xFFF) & ~0xFFFULL; + u64 pages = len / 4096; - g_ulime = ulime; - memset(ulime->syscalls, 0, sizeof(ulime->syscalls)); + for (u64 i = 0; i < pages; i++) { + paging_unmap_page(addr + i * 4096); + } + return 0; +}*/ - ulime->syscalls[READ] = scall_read; - ulime->syscalls[WRITE] = scall_write; +void _init_syscalls_table(ulime_t *ulime_ptr) { + if (!ulime_ptr) return; + + g_ulime = ulime_ptr; + memset(ulime_ptr->syscalls, 0, sizeof(ulime_ptr->syscalls)); + + ulime_ptr->syscalls[READ] = scall_read; + ulime_ptr->syscalls[WRITE] = scall_write; //ulime->syscalls[READ] = scall_read; - ulime->syscalls[GETPID] = scall_getpid; - ulime->syscalls[BRK] = scall_brk; - ulime->syscalls[EXIT] = scall_exit; + ulime_ptr->syscalls[OPEN] = scall_open; + ulime_ptr->syscalls[CLOSE] = scall_close; + ulime_ptr->syscalls[GETPID] = scall_getpid; + ulime_ptr->syscalls[BRK] = scall_brk; + ulime_ptr->syscalls[EXIT] = scall_exit; + ulime_ptr->syscalls[EXECVE] = scall_execve; + ulime_ptr->syscalls[GETDENTS] = scall_getdents; + ulime_ptr->syscalls[CHDIR] = scall_chdir; + ulime_ptr->syscalls[GETCWD] = scall_getcwd; + ulime_ptr->syscalls[IOCTL] = scall_ioctl; + ulime_ptr->syscalls[MQ_OPEN] = scall_mq_open; + ulime_ptr->syscalls[MQ_UNLINK] = scall_mq_unlink; + ulime_ptr->syscalls[MQ_SEND] = scall_mq_send; + ulime_ptr->syscalls[MQ_RECV] = scall_mq_recv; + //ulime_ptr->syscalls[SHM_DESTROY] = scall_shm_destroy; + ulime_ptr->syscalls[MMAP] = scall_mmap; + ulime_ptr->syscalls[MUNMAP] = scall_munmap; + + // emex specific + ulime_ptr->syscalls[EMXREBOOT] = scall_reboot; log("[SYSCALL]", "syscall table initialized\n", d); } -// syscall handler (called from assembly) + +// syscall handler (called from assembly) uses find_proc_by_cr3 u64 syscall_handler(u64 syscall_num, u64 arg1, u64 arg2, u64 arg3) { if (!g_ulime) { printf("[SYSCALL] error: ulime not initialized\n"); return (u64)-1; } - ulime_proc_t *current = g_ulime->ptr_proc_curr; + ulime_proc_t *current = find_proc_by_cr3(g_ulime, user_cr3); if (!current) { - printf("[SYSCALL] error: no current process\n"); + printf("[SYSCALL] error: no process for CR3 0x%lX\n", user_cr3); return (u64)-1; } diff --git a/src/kernel/user/ulime.c b/src/kernel/user/ulime.c index ffe6212..5cbee05 100644 --- a/src/kernel/user/ulime.c +++ b/src/kernel/user/ulime.c @@ -80,14 +80,13 @@ ulime_proc_t *ulime_proc_create(ulime_t *ulime, u8 *name, u64 entry_point) { proc->state = PROC_CREATED; proc->entry_point = entry_point; - // align alocations - proc->heap_size = 64 * 1024; // 64KB : CODE/DATA - proc->heap_base = (ulime->user_space_used + 0xFFF) & ~0xFFF; // align to 4KB + proc->heap_size = 256 * 1024; + //proc->heap_size = 8 * 1024 * 1024; + proc->heap_base = (ulime->user_space_used + 0xFFF) & ~0xFFF; ulime->user_space_used = proc->heap_base + proc->heap_size; - - // stack separate from code / heap - proc->stack_size = 16 * 1024; // 16KB - proc->stack_base = (ulime->user_space_used + 0xFFF) & ~0xFFF; // align to 4KB + proc->stack_size = 64 * 1024; + //proc->stack_size = 256 * 1024; + proc->stack_base = (ulime->user_space_used + 0xFFF) & ~0xFFF; ulime->user_space_used = proc->stack_base + proc->stack_size; printf("[ULIME] Process '%s' created:\n", proc->name); @@ -131,34 +130,35 @@ int ulime_proc_mmap(ulime_t *ulime, ulime_proc_t *proc) { printf(" Heap phys: 0x%llx (%llu pages)\n", (unsigned long long)phys_heap, (unsigned long long)heap_pages); - // stack pages: Non-Execute enabled (security) - u64 stack_flags = PTE_PRESENT | PTE_WRITABLE | PTE_USER | PTE_NO_EXEC; + u64 pml4_phys = paging_create_proc_pml4(ulime->hpr); + proc->pml4_phys = pml4_phys; + printf(" PML4 phys: 0x%llx\n", (unsigned long long)pml4_phys); - // heap/code pages: Executable (no NX bit) - u64 heap_flags = PTE_PRESENT | PTE_WRITABLE | PTE_USER; + u64 stack_flags = PTE_PRESENT | PTE_WRITABLE | PTE_USER | PTE_NO_EXEC; + u64 heap_flags = PTE_PRESENT | PTE_WRITABLE | PTE_USER; - // map heap (executable for code) + // map heap/code into the process's own PML4 for (u64 i = 0; i < heap_pages; i++) { u64 virt = proc->heap_base + (i * PAGE_SIZE); u64 phys = phys_heap + (i * PAGE_SIZE); - paging_map_page(ulime->hpr, virt, phys, heap_flags); + paging_map_page_proc(ulime->hpr, pml4_phys, virt, phys, heap_flags); } - // map stack (with NX) + // map stack into the processes own PML4 for (u64 i = 0; i < stack_pages; i++) { u64 virt = proc->stack_base + (i * PAGE_SIZE); u64 phys = phys_stack + (i * PAGE_SIZE); - paging_map_page(ulime->hpr, virt, phys, stack_flags); + paging_map_page_proc(ulime->hpr, pml4_phys, virt, phys, stack_flags); } - // clear memory via HHDM (physical + offset) - void *heap_clear = (void*)(phys_heap + ulime->hpr->offset); - void *stack_clear = (void*)(phys_stack + ulime->hpr->offset); - memset(heap_clear, 0, proc->heap_size); + // clear memory via HHDM + void *heap_clear = (void *)(phys_heap + ulime->hpr->offset); + void *stack_clear = (void *)(phys_stack + ulime->hpr->offset); + memset(heap_clear, 0, proc->heap_size); memset(stack_clear, 0, proc->stack_size); proc->phys_stack = phys_stack; - proc->phys_heap = phys_heap; + proc->phys_heap = phys_heap; proc->state = PROC_READY; printf("[ULIME] memory mapped successfully\n"); diff --git a/src/kernel/user/ulime.h b/src/kernel/user/ulime.h index 65eeb64..1c0bb10 100644 --- a/src/kernel/user/ulime.h +++ b/src/kernel/user/ulime.h @@ -19,6 +19,7 @@ typedef struct ulime_proc { u64 priority; u64 state; u64 *ptr_pagetable; + u64 pml4_phys; // physical address of this process's PML4 (loaded into CR3) u64 entry_point; u64 heap_base; u64 heap_size; @@ -28,6 +29,10 @@ typedef struct ulime_proc { u64 phys_heap; u64 phys_stack; + u64 brk; + u64 entry_rsp; + u64 mmap_base; // next virtual address for mmap allocations + struct ulime *ulime; struct ulime_proc *next; struct ulime_proc *prev; diff --git a/src/userspace/Makefile b/src/userspace/Makefile index 8602f64..30477cd 100644 --- a/src/userspace/Makefile +++ b/src/userspace/Makefile @@ -1,17 +1,37 @@ -AS := x86_64-elf-as -LD := x86_64-elf-ld -LDFLAGS := -nostdlib -static -no-pie -T user.ld +all: + @$(MAKE) -C libc -all: hello.elf + #@$(MAKE) -C apps/hello + @$(MAKE) -C apps/system + @$(MAKE) -C apps/shell + @$(MAKE) -C apps/login + @$(MAKE) -C apps/gui -hello.elf: hello.o user.ld - $(LD) $(LDFLAGS) hello.o -o hello.elf - @echo "Built hello.elf" - -hello.o: hello.S - $(AS) hello.S -o hello.o + @$(MAKE) -C bin/echo + @$(MAKE) -C bin/hello + @$(MAKE) -C bin/ls + @$(MAKE) -C bin/tree + @$(MAKE) -C bin/cd + @$(MAKE) -C bin/cat + @$(MAKE) -C bin/lsblk + @$(MAKE) -C bin/reboot clean: - rm -f *.o hello.elf + @$(MAKE) -C libc clean + + #@$(MAKE) -C apps/hello clean + @$(MAKE) -C apps/system clean + @$(MAKE) -C apps/shell clean + @$(MAKE) -C apps/login clean + @$(MAKE) -C apps/gui clean + + @$(MAKE) -C bin/echo clean + @$(MAKE) -C bin/hello clean + @$(MAKE) -C bin/ls clean + @$(MAKE) -C bin/tree clean + @$(MAKE) -C bin/cd clean + @$(MAKE) -C bin/cat clean + @$(MAKE) -C bin/lsblk clean + @$(MAKE) -C bin/reboot clean .PHONY: all clean diff --git a/src/userspace/apps/gui/Makefile b/src/userspace/apps/gui/Makefile new file mode 100644 index 0000000..e46a1e2 --- /dev/null +++ b/src/userspace/apps/gui/Makefile @@ -0,0 +1,27 @@ +CC := x86_64-elf-gcc +LD := x86_64-elf-ld +LIBC := ../../libc + +CFLAGS := -ffreestanding -nostdlib -fno-builtin -fno-stack-protector \ + -fno-PIE -fno-pic -m64 -march=x86-64 -mno-sse -mno-sse2 \ + -mno-mmx -mno-red-zone -Wall -Wextra -std=gnu11 \ + -I$(LIBC)/include + +LDFLAGS := -nostdlib -static -no-pie -T ../../user.ld + +all: clean gui.emx/app.elf + +gui.emx/app.elf: gui.o $(LIBC)/build/crt0.o $(LIBC)/build/libc.a + mkdir -p gui.emx + $(LD) $(LDFLAGS) $(LIBC)/build/crt0.o gui.o $(LIBC)/build/libc.a -o $@ + +gui.o: gui.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(LIBC)/build/crt0.o $(LIBC)/build/libc.a: + $(MAKE) -C $(LIBC) + +clean: + rm -f *.o gui.emx/app.elf gui.emx/package.info + +.PHONY: all clean \ No newline at end of file diff --git a/src/userspace/apps/gui/gui.c b/src/userspace/apps/gui/gui.c new file mode 100644 index 0000000..32f6d67 --- /dev/null +++ b/src/userspace/apps/gui/gui.c @@ -0,0 +1,83 @@ +#include <emx/fb.h> +#include <emx/mouse.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <unistd.h> + +#define T 0x00000000u +#define B 0xFF101010u // a bit lighter than black, but its lit unoticable +#define W 0xFFFFFFFFu + +#define CW 9 +#define CH 12 + +static const unsigned int cursor_px[CW * CH] = { + B,T,T,T,T,T,T,T,T, + B,B,T,T,T,T,T,T,T, + B,W,B,T,T,T,T,T,T, + B,W,W,B,T,T,T,T,T, + B,W,W,W,B,T,T,T,T, + B,W,W,W,W,B,T,T,T, + B,W,W,W,W,W,B,T,T, + B,W,W,W,W,W,W,B,T, + B,W,W,B,B,B,B,B,T, + B,W,B,T,T,T,T,T,T, + B,B,T,T,T,T,T,T,T, + T,T,T,T,T,T,T,T,T, +}; + +// saved background pixels so we can restore before each move +static unsigned int bg_save[CW * CH]; +static int bg_valid = 0; +static int old_x = 0, old_y = 0; + +int main(void) { + int fb = open( "/dev/fb0", 0); + int mfd = open("/dev/input/mouse0", 0); + if (fb < 0 || mfd < 0) _exit(1); + + for (;;) { + // wait for next mouse event from kernel ring buffer + mouse_event_t ev; + if ((int)read(mfd, &ev, sizeof(ev)) < (int)sizeof(ev)) continue; + + int nx = ev.abs_x; + int ny = ev.abs_y; + + // restores the previous background before moving cursor + if (bg_valid) { + fb_rect_t rst = { + .x = (unsigned int)old_x, + .y = (unsigned int)old_y, + .w = CW, + .h = CH, + .pixels = bg_save + }; + ioctl(fb, FBIO_BLIT, &rst); + } + + // save the new background at new position + fb_rect_t save = { + .x = (unsigned int)nx, + .y = (unsigned int)ny, + .w = CW, + .h = CH, + .pixels = bg_save + }; + ioctl(fb, FBIO_READ_RECT, &save); + bg_valid = 1; + old_x = nx; + old_y = ny; + + // draw the cursor at new position + fb_rect_t drw = { + .x = (unsigned int)nx, + .y = (unsigned int)ny, + .w = CW, + .h = CH, + .pixels = (unsigned int *)cursor_px + }; + + ioctl(fb, FBIO_BLIT, &drw); + } +} \ No newline at end of file diff --git a/src/userspace/apps/gui/gui.emx/app.elf b/src/userspace/apps/gui/gui.emx/app.elf new file mode 100755 index 0000000..a751917 Binary files /dev/null and b/src/userspace/apps/gui/gui.emx/app.elf differ diff --git a/src/userspace/apps/gui/gui.o b/src/userspace/apps/gui/gui.o new file mode 100644 index 0000000..69f64a8 Binary files /dev/null and b/src/userspace/apps/gui/gui.o differ diff --git a/src/userspace/apps/libc.h b/src/userspace/apps/libc.h index 5366491..fd45a31 100644 --- a/src/userspace/apps/libc.h +++ b/src/userspace/apps/libc.h @@ -1,35 +1,5 @@ #pragma once - +/* typedef unsigned long size_t; typedef long ssize_t; - -static inline size_t syscall3(size_t n, size_t a1, size_t a2, size_t a3) { - size_t ret; - __asm__ volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), "d"(a3) : "rcx", "r11", "memory"); - return ret; -} - -static inline size_t syscall1(size_t n, size_t a1) { - size_t ret; - __asm__ volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1) : "rcx", "r11", "memory"); - return ret; -} - -static inline ssize_t write(int fd, const void *buf, size_t count) { - return (ssize_t)syscall3(1, (size_t)fd, (size_t)buf, (size_t)count); -} - -static inline void exit(int status) { - syscall1(60, (size_t)status); - __builtin_unreachable(); -} - -static inline size_t strlen(const char *s) { - size_t len = 0; - while (s[len]) len++; - return len; -} - -static inline void print(const char *s) { - write(1, s, strlen(s)); -} +*/ diff --git a/src/userspace/apps/login/Makefile b/src/userspace/apps/login/Makefile new file mode 100644 index 0000000..3522831 --- /dev/null +++ b/src/userspace/apps/login/Makefile @@ -0,0 +1,28 @@ +CC := x86_64-elf-gcc +LD := x86_64-elf-ld +LIBC := ../../libc + +CFLAGS := -ffreestanding -nostdlib -fno-builtin -fno-stack-protector \ + -fno-PIE -fno-pic -m64 -march=x86-64 -mno-sse -mno-sse2 \ + -mno-mmx -mno-red-zone -Wall -Wextra -std=gnu11 \ + -I$(LIBC)/include + +LDFLAGS := -nostdlib -static -no-pie -T ../../user.ld + +OUT := login.elf + +all: clean $(OUT) + +$(OUT): login.o $(LIBC)/build/crt0.o $(LIBC)/build/libc.a + $(LD) $(LDFLAGS) $(LIBC)/build/crt0.o login.o $(LIBC)/build/libc.a -o $@ + +login.o: login.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(LIBC)/build/crt0.o $(LIBC)/build/libc.a: + $(MAKE) -C $(LIBC) + +clean: + rm -f *.o $(OUT) + +.PHONY: all clean diff --git a/src/userspace/apps/login/login.c b/src/userspace/apps/login/login.c new file mode 100644 index 0000000..5b0d838 --- /dev/null +++ b/src/userspace/apps/login/login.c @@ -0,0 +1,108 @@ +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <stdio.h> + +#include "login.h" + +#include <emx/ansi.h> + +//TODO: +// implement password hashing + +/* +static void print_str(const char *s) { + write(STDOUT_FILENO, s, strlen(s)); +}*/ + +static int str_eq(const char *a, const char *b) { + while (*a && *b) { + if (*a != *b) return 0; + a++; b++; + } + return (*a == '\0' && *b == '\0'); +} + +static void strip_nl(char *buf, int len) { + for (int i = 0; i < len; i++) { + if (buf[i] == '\n' || buf[i] == '\r') { + buf[i] = '\0'; + return; + } + } +} + +int main(void) +{ + char user_buf[BUF_SIZE]; + char pass_buf[BUF_SIZE]; + + printf("\n"); + + print_logo: { + #define LOGO_PATH "/emr/assets/logo.txt" + #define LOGO_BUF 2048 + + int fd = open(LOGO_PATH, O_RDONLY); + if (fd < 0) { + goto login; + } else { + char buf[LOGO_BUF]; + ssize_t n = read(fd, buf, LOGO_BUF - 1); + close(fd); + if (n > 0) { + buf[n] = '\0'; + printf("\033[96m"); + write(STDOUT_FILENO, buf, (size_t)n); + printf("\033[0m\n"); + } + goto login; + } + } + + printf("if this is reached this is bad :("); + +login: + printf("\n\n"); + //printf("----------------------\n"); + printf(" [emexOS login]\n"); + + for (int attempt = 0; attempt < MAX_TRIES; attempt++) + { + printf(A_GFX_YELLOW " login:\033[0m "); + ssize_t n = read(STDIN_FILENO, user_buf, BUF_SIZE - 1); + if (n <= 0) continue; + user_buf[n] = '\0'; + strip_nl(user_buf, (int)n); + + printf(A_GFX_YELLOW " password:\033[0m "); + ssize_t m = read(STDIN_FILENO, pass_buf, BUF_SIZE - 1); + if (m <= 0) continue; + pass_buf[m] = '\0'; + strip_nl(pass_buf, (int)m); + + if (str_eq(user_buf, LOGIN_USER) && str_eq(pass_buf, LOGIN_PASS)) + { + //printf("\033[0m----------------------\n"); + //printf("\n"); + printf("\n \033[31m>\033[32m>\033[35m>\033[36m welcome, "); + printf(user_buf); + printf("!\n\n\033[0m"); + + // launch the shell + //char *const argv[] = { (char *)SHELL_PATH, (char *)0 }; + //char *const envp[] = { (char *)0 }; + //execve(SHELL_PATH, argv, envp); + + //should not return + //print_str("error: failed to launch shell\n"); + return 0; + } + + printf("\033[31m [login incorrect]\033[0m\n"); + } + //printf("\033[0m----------------------\n"); + printf("\033[0m\n too many failed attempts\n"); + + return 2; +} diff --git a/src/userspace/apps/login/login.elf b/src/userspace/apps/login/login.elf new file mode 100755 index 0000000..4162f16 Binary files /dev/null and b/src/userspace/apps/login/login.elf differ diff --git a/src/userspace/apps/login/login.h b/src/userspace/apps/login/login.h new file mode 100644 index 0000000..fe0f37e --- /dev/null +++ b/src/userspace/apps/login/login.h @@ -0,0 +1,8 @@ +#pragma once + +#define LOGIN_USER "emex" +#define LOGIN_PASS "emex" +#define SHELL_PATH "/user/apps/shell.emx" +#define MAX_TRIES 3 +#define BUF_SIZE 64 +#define LHASH zumotokaari diff --git a/src/userspace/apps/login/login.o b/src/userspace/apps/login/login.o new file mode 100644 index 0000000..f24ff3a Binary files /dev/null and b/src/userspace/apps/login/login.o differ diff --git a/src/userspace/apps/shell/Makefile b/src/userspace/apps/shell/Makefile new file mode 100644 index 0000000..d641c31 --- /dev/null +++ b/src/userspace/apps/shell/Makefile @@ -0,0 +1,27 @@ +CC := x86_64-elf-gcc +LD := x86_64-elf-ld +LIBC := ../../libc + +CFLAGS := -ffreestanding -nostdlib -fno-builtin -fno-stack-protector \ + -fno-PIE -fno-pic -m64 -march=x86-64 -mno-sse -mno-sse2 \ + -mno-mmx -mno-red-zone -Wall -Wextra -std=gnu11 \ + -I$(LIBC)/include + +LDFLAGS := -nostdlib -static -no-pie -T ../../user.ld + +all: clean shell.emx/app.elf + +shell.emx/app.elf: shell.o $(LIBC)/build/crt0.o $(LIBC)/build/libc.a + mkdir -p shell.emx + $(LD) $(LDFLAGS) $(LIBC)/build/crt0.o shell.o $(LIBC)/build/libc.a -o $@ + +shell.o: shell.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(LIBC)/build/crt0.o $(LIBC)/build/libc.a: + $(MAKE) -C $(LIBC) + +clean: + rm -f *.o shell.emx/app.elf + +.PHONY: all clean diff --git a/src/userspace/apps/shell/shell.c b/src/userspace/apps/shell/shell.c new file mode 100644 index 0000000..5a226bb --- /dev/null +++ b/src/userspace/apps/shell/shell.c @@ -0,0 +1,91 @@ +#include <stdio.h> +#include <unistd.h> +#include <string.h> + + +//-////////////////////////////////////////-// +//-// //-// +//-// SHELLY :) //-// +//-// emex user-space shell //-// +//-// //-// +//-////////////////////////////////////////-// + +#define BUFFER 256 +#define SHELL_PROMPT "\033[0m[pc@emexos]$ " +#define SHELL_CONFIG "/.config/shelly/" +#define BIN_PATH "/bin/" + +#define WELCOME_MESSAGE "\n\033[0m Welcome to shelly, emexOS's default shell.\n Type \"ls /bin\" for a list of commands.\n\n" + + +static int parse_args(char *buf, char **argv, int max_args) +{ + int argc = 0; + char *p = buf; + + while (*p && argc < max_args - 1) { + // skip spaces + while (*p == ' ') p++; + if (*p == '\0') break; + + argv[argc++] = p; + + // find end of token + while (*p && *p != ' ') p++; + if (*p == ' ') *p++ = '\0'; + } + + argv[argc] = NULL; + return argc; +} +static int exec_from_bin(const char *cmd, char **argv) +{ + // /bin/ + cmd + .elf + char path[BUFFER]; + char *const envp[] = { (char *)0 }; + size_t bin_len = sizeof(BIN_PATH) - 1; // length of "/bin/" + size_t cmd_len = strlen(cmd); + size_t elf_len = 4; // ".elf" + + if (bin_len + cmd_len + elf_len + 1 > BUFFER) return -1; + + memcpy(path, BIN_PATH, bin_len); + memcpy(path + bin_len, cmd, cmd_len); + memcpy(path + bin_len + cmd_len, ".elf", elf_len + 1); // +1 for \0 + + return execve(path, argv, envp); +} + +int main(void) +{ + printf(WELCOME_MESSAGE); + + char buf[BUFFER]; + char *argv[32]; + + for (;;) + { + printf(SHELL_PROMPT); + + // block until newline (\n) + ssize_t n = read(STDIN_FILENO, buf, sizeof(buf) - 1); + + if (n <= 0) continue; + + buf[n] = '\0'; + + if (n > 0 && buf[n - 1] == '\n') buf[--n] = '\0'; + if (n == 0) continue; + + int argc = parse_args(buf, argv, 32); + if (argc == 0) continue; + + int ret = exec_from_bin(argv[0], argv); + if (ret < 0) { + printf(argv[0]); + printf(": command not found\n"); + } + } + + return 0; +} diff --git a/src/userspace/apps/shell/shell.emx/app.elf b/src/userspace/apps/shell/shell.emx/app.elf new file mode 100755 index 0000000..cba027a Binary files /dev/null and b/src/userspace/apps/shell/shell.emx/app.elf differ diff --git a/src/userspace/apps/shell/shell.emx/package.info b/src/userspace/apps/shell/shell.emx/package.info new file mode 100644 index 0000000..055ff67 --- /dev/null +++ b/src/userspace/apps/shell/shell.emx/package.info @@ -0,0 +1,10 @@ +<html> + <head> + <title>shell + + + emex + v0.0.1a + emx userspace shell + + diff --git a/src/userspace/apps/shell/shell.o b/src/userspace/apps/shell/shell.o new file mode 100644 index 0000000..ad3c8ed Binary files /dev/null and b/src/userspace/apps/shell/shell.o differ diff --git a/src/userspace/apps/system/Makefile b/src/userspace/apps/system/Makefile new file mode 100644 index 0000000..a44b9d3 --- /dev/null +++ b/src/userspace/apps/system/Makefile @@ -0,0 +1,26 @@ +CC := x86_64-elf-gcc +LD := x86_64-elf-ld +LIBC := ../../libc + +CFLAGS := -ffreestanding -nostdlib -fno-builtin -fno-stack-protector \ + -fno-PIE -fno-pic -m64 -march=x86-64 -mno-sse -mno-sse2 \ + -mno-mmx -mno-red-zone -Wall -Wextra -std=gnu11 \ + -I$(LIBC)/include + +LDFLAGS := -nostdlib -static -no-pie -T ../../user.ld + +all: clean system.emx/app.elf + +system.emx/app.elf: init.o emxrc.o $(LIBC)/build/crt0.o $(LIBC)/build/libc.a + $(LD) $(LDFLAGS) $(LIBC)/build/crt0.o init.o emxrc.o $(LIBC)/build/libc.a -o $@ + +emxrc.o: emxrc.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(LIBC)/build/crt0.o $(LIBC)/build/libc.a: + $(MAKE) -C $(LIBC) + +clean: + rm -f *.o system.emx/app.elf + +.PHONY: all clean diff --git a/src/userspace/apps/system/emxrc.c b/src/userspace/apps/system/emxrc.c new file mode 100644 index 0000000..5ce9fbe --- /dev/null +++ b/src/userspace/apps/system/emxrc.c @@ -0,0 +1,141 @@ +#include "emxrc.h" +#include +#include +#include +#include +#include + +static char buf[2048]; +static char *tp; +static char tb[256]; // token result buffer + +#define PREFIX ":: emxrc: " +#define CMD_PREFIX "-" + +#define VAR_NAME "var" +#define EMX_NAME "ep" +#define ELF_NAME "elf" +#define EXE_NAME "exec" +#define FMT_NAME "f" + +static char *tok(void) { + int i = 0; + + while (*tp == ' ' || *tp == '\t') tp++; + + if (!*tp || *tp == '\n') return NULL; + if (*tp == '"') { + for (tp++; *tp && *tp != '"' && *tp != '\n';) tb[i++] = *tp++; + if (*tp == '"') tp++; + tb[i] = '\0'; + return tb; + } + if (*tp == '=' || *tp == '(' || *tp == ')' || *tp == ':') { + tb[0] = *tp++; tb[1] = '\0'; + return tb; + } + + while (*tp + && *tp != ' ' && *tp != '\t' && *tp != '\n' + && *tp != '=' && *tp != '(' && *tp != ')' + && *tp != ':' && *tp != '"' && i < 255 + ) tb[i++] = *tp++; + + tb[i] = '\0'; + return i ? tb : NULL; +} + +static void skipline(void) { + while (*tp && *tp != '\n') tp++; + if (*tp) tp++; +} + +int emxrc_parse(const char *path, emxrc_t *out) { + if (!out) return -1; + out->var_count = out->exec_count = 0; + + int fd = open(path, O_RDONLY); + int n = (int)read(fd, buf, sizeof(buf) - 1); + + if (fd < 0) return -1; + close(fd); + if (n <= 0) return -1; + buf[n] = '\0'; + tp = buf; + + while (*tp) { + while (*tp == ' ' || *tp == '\t') tp++; // space or tab + if (*tp == '\n') { tp++; continue; } // new line + if (tp[0]=='/' && tp[1]=='/') { skipline(); continue; } // comments + + char *kw = tok(); + if (!kw) { skipline(); continue; } + + // var name=("path") or var name=(ep: "path") + if (strcmp(kw, VAR_NAME) == 0 && out->var_count < EMXRC_MAX_VARS) { + emxrc_var_t *v = &out->vars[out->var_count]; + v->fmt = EMXRC_FMT_ELF; + + char *name = tok(); if (!name) { skipline(); continue; } + strncpy(v->name, name, sizeof(v->name) - 1); + + tok(); + tok(); // skip '=' '(' + + char *next = tok(); + if (next && strcmp(next, EMX_NAME) == 0) { + v->fmt = EMXRC_FMT_EP; + tok(); // skip ':' + next = tok(); + } + if (next) strncpy(v->path, next, sizeof(v->path) - 1); + out->var_count++; + } + + // exec -f"format" var_name + else if (strcmp(kw, EXE_NAME) == 0 && out->exec_count < EMXRC_MAX_EXECS) { + emxrc_exec_t *e = &out->execs[out->exec_count]; + e->fmt = EMXRC_FMT_INHERIT; // fmt == format btw + + char *next = tok(); + if (!next) { skipline(); continue; } + if (next[0] == CMD_PREFIX && next[1] == FMT_NAME) { + char *fs = tok(); // "ep" or "elf" or whatever + e->fmt = (fs && strcmp(fs, EMX_NAME) == 0) ? EMXRC_FMT_EP : EMXRC_FMT_ELF; + next = tok(); + } + if (next) strncpy(e->var_name, next, sizeof(e->var_name) - 1); + + out->exec_count++; + } + skipline(); + } + return 0; +} + +void emxrc_run(emxrc_t *rc) { + for (int i = 0; i < rc->exec_count; i++) { + emxrc_exec_t *e = &rc->execs[i]; + + const char *path = NULL; + emxrc_fmt_t fmt = e->fmt; + + for (int j = 0; j < rc->var_count; j++) { + if (strcmp(rc->vars[j].name, e->var_name) == 0) { + path = rc->vars[j].path; + if (fmt == EMXRC_FMT_INHERIT) fmt = rc->vars[j].fmt; + break; + } + } + + if (!path) { fprintf(stderr, PREFIX "unknown var '%s'\n", e->var_name); continue; } + + printf(PREFIX "" EXE_NAME" %s (%s)\n", path, fmt == EMXRC_FMT_EP ? EMX_NAME : ELF_NAME); + + char *const argv[] = {(char *)path, (char*) 0}; + char *const envp[] = {(char *) 0 }; + int r = execve(path, argv, envp); + + if (r < 0) fprintf(stderr, PREFIX "" EXE_NAME " failed: '%s'\n", path); + } +} \ No newline at end of file diff --git a/src/userspace/apps/system/emxrc.h b/src/userspace/apps/system/emxrc.h new file mode 100644 index 0000000..d87435f --- /dev/null +++ b/src/userspace/apps/system/emxrc.h @@ -0,0 +1,33 @@ +#pragma once + +#define EMXRC_MAX_VARS 255 +#define EMXRC_MAX_EXECS 255 + +#define EMXRC_PATH "/emr/.emxrc" + +typedef enum { + EMXRC_FMT_ELF = 0, // plain elf + EMXRC_FMT_EP = 1, // emex package + EMXRC_FMT_INHERIT = 2,// if no -f just use the var's format (ep:, elf:) +} emxrc_fmt_t; + +typedef struct { + char name[64]; + char path[256]; + emxrc_fmt_t fmt; +} emxrc_var_t; + +typedef struct { + char var_name[64]; + emxrc_fmt_t fmt; +} emxrc_exec_t; + +typedef struct { + emxrc_var_t vars[EMXRC_MAX_VARS]; + int var_count; + emxrc_exec_t execs[EMXRC_MAX_EXECS]; + int exec_count; +} emxrc_t; + +int emxrc_parse(const char *path, emxrc_t *out); +void emxrc_run(emxrc_t *rc); \ No newline at end of file diff --git a/src/userspace/apps/system/emxrc.o b/src/userspace/apps/system/emxrc.o new file mode 100644 index 0000000..f1a9aed Binary files /dev/null and b/src/userspace/apps/system/emxrc.o differ diff --git a/src/userspace/apps/system/init.S b/src/userspace/apps/system/init.S new file mode 100644 index 0000000..7f255ad --- /dev/null +++ b/src/userspace/apps/system/init.S @@ -0,0 +1,20 @@ +.section .rodata +msg: + .ascii "[emr_system] starting... main usersystem\n" +msg_len = . - msg + +.section .text +.global _start + +_start: + # write(1, msg, msg_len) + mov $1, %rax + mov $1, %rdi + lea msg(%rip), %rsi + mov $msg_len, %rdx + syscall + + # execve("/login.emx") or whatever +.loop: + pause + jmp .loop diff --git a/src/userspace/apps/system/init.c b/src/userspace/apps/system/init.c new file mode 100644 index 0000000..8f6b777 --- /dev/null +++ b/src/userspace/apps/system/init.c @@ -0,0 +1,25 @@ +#include "init.h" +#include "emxrc.h" + +#include +#include +#include + +int main(void) { + static emxrc_t rc; + + if (emxrc_parse(EMXRC_PATH, &rc) != 0) { + fprintf(stderr, "[init] .emxrc not found, using defaults!\n"); + char *const argv[] = { (char *)LOGINLOCATE, (char *)0 }; + char *const envp[] = { (char *)0 }; + execve(LOGINLOCATE, argv, envp); + goto error; + } + + emxrc_run(&rc); + +error: + fprintf(stderr, "[init] all execs failed, halting\n"); + for (;;) __asm__ volatile("pause"); + return 0; +} \ No newline at end of file diff --git a/src/userspace/apps/system/init.h b/src/userspace/apps/system/init.h new file mode 100644 index 0000000..b5d35fc --- /dev/null +++ b/src/userspace/apps/system/init.h @@ -0,0 +1,17 @@ +#pragma once + +// esh will automatically load the shell after everything is finished +#define EMX_SHELL "/user/apps/shell.emx" +#define LOGINLOCATE "/emr/system/login.elf"//user/apps/login.emx" + + +#define SEPERATOR "$SEPERATOR$" + +#define EMRHANDLERS { \ + "bootloader",/*kernel process*/ \ + "kernel" /*kernel process*/ \ + ,SEPERATOR, \ + "kernel", /*ulime/real process*/ \ + "user", /*ulime/real process*/ \ + "__rt" /*ulime/real process*/ \ +}; diff --git a/src/userspace/apps/system/init.o b/src/userspace/apps/system/init.o new file mode 100644 index 0000000..8679896 Binary files /dev/null and b/src/userspace/apps/system/init.o differ diff --git a/src/userspace/apps/system/system.emx/app.elf b/src/userspace/apps/system/system.emx/app.elf new file mode 100755 index 0000000..195d898 Binary files /dev/null and b/src/userspace/apps/system/system.emx/app.elf differ diff --git a/src/userspace/apps/system/system.emx/package.info b/src/userspace/apps/system/system.emx/package.info new file mode 100644 index 0000000..e7767fe --- /dev/null +++ b/src/userspace/apps/system/system.emx/package.info @@ -0,0 +1,10 @@ + + + emr_system + + + emex + [] + [] + + diff --git a/src/userspace/apps/system/todo.md b/src/userspace/apps/system/todo.md new file mode 100644 index 0000000..4588795 --- /dev/null +++ b/src/userspace/apps/system/todo.md @@ -0,0 +1,7 @@ +[x] jump to userspace +[ ] create a login +[ ] create a desktop enviroment +[ ] create a window system +[ ] create a shell (emesh) +[ ] port doom +[ ] be happy :) diff --git a/src/userspace/bin/cat/Makefile b/src/userspace/bin/cat/Makefile new file mode 100644 index 0000000..f1314f6 --- /dev/null +++ b/src/userspace/bin/cat/Makefile @@ -0,0 +1,28 @@ +CC := x86_64-elf-gcc +LD := x86_64-elf-ld +LIBC := ../../libc + +CFLAGS := -ffreestanding -nostdlib -fno-builtin -fno-stack-protector \ + -fno-PIE -fno-pic -m64 -march=x86-64 -mno-sse -mno-sse2 \ + -mno-mmx -mno-red-zone -Wall -Wextra -std=gnu11 \ + -I$(LIBC)/include + +LDFLAGS := -nostdlib -static -no-pie -T ../../user.ld + +OUT := cat.elf + +all: clean $(OUT) + +$(OUT): cat.o $(LIBC)/build/crt0.o $(LIBC)/build/libc.a + $(LD) $(LDFLAGS) $(LIBC)/build/crt0.o cat.o $(LIBC)/build/libc.a -o $@ + +cat.o: cat.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(LIBC)/build/crt0.o $(LIBC)/build/libc.a: + $(MAKE) -C $(LIBC) + +clean: + rm -f *.o $(OUT) + +.PHONY: all clean \ No newline at end of file diff --git a/src/userspace/bin/cat/cat.c b/src/userspace/bin/cat/cat.c new file mode 100644 index 0000000..f79d401 --- /dev/null +++ b/src/userspace/bin/cat/cat.c @@ -0,0 +1,127 @@ +#include +#include +#include +#include + +#define CAT_BUFSZ 4096 + +static void resolve_path(const char *arg, char *out_buf, int bufsz) +{ + char cwd[256]; + int ci = 0; + int ai = 0; + + if (!arg || arg[0] == '/') { + int i = 0; + if (arg) while (i < bufsz - 1 && arg[i]) { out_buf[i] = arg[i]; i++; } + out_buf[i] = '\0'; + return; + } + if (!getcwd(cwd, sizeof(cwd))) { + cwd[0] = '/'; cwd[1] = '\0'; + } + + + while (ci < bufsz - 1 && cwd[ci]) { out_buf[ci] = cwd[ci]; ci++; } + + if (ci > 0 && out_buf[ci - 1] != '/') { + if (ci < bufsz - 1) out_buf[ci++] = '/'; + } + while (ci < bufsz - 1 && arg[ai]) { out_buf[ci++] = arg[ai++]; } + out_buf[ci] = '\0'; +} + +static int cat_fd(int src_fd, int dst_fd) { + char buf[CAT_BUFSZ]; + ssize_t n; + while ((n = read(src_fd, buf, sizeof(buf))) > 0) { + ssize_t written = 0; + while (written < n) { + ssize_t w = write(dst_fd, buf + written, (size_t)(n - written)); + if (w <= 0) return -1; + written += w; + } + } + return 0; +} + +int main(int argc, char *argv[]) +{ + const char *src_files[32]; + int src_count = 0; + const char *dst_path = NULL; // NULL == stdout + int expect_dst = 0; + + for (int i = 1; i < argc; i++) { + if (expect_dst) { + dst_path = argv[i]; + expect_dst = 0; + continue; + } + + if (argv[i][0] == '>' && argv[i][1] == '\0') { + // standalone '>' + expect_dst = 1; + continue; + } + + if (argv[i][0] == '>') { + // '>foo' destination + dst_path = argv[i] + 1; + continue; + } + + if (src_count < 32) + src_files[src_count++] = argv[i]; + } + + int dst_fd = STDOUT_FILENO; + int dst_opened = 0; + + if (dst_path) { + char dst_resolved[256]; + resolve_path(dst_path, dst_resolved, sizeof(dst_resolved)); + + dst_fd = open(dst_resolved, O_WRONLY | O_CREAT); + if (dst_fd < 0) { + write(STDERR_FILENO, "cat: cannot open output: ", 25); + write(STDERR_FILENO, dst_resolved, strlen(dst_resolved)); + write(STDERR_FILENO, "\n", 1); + return 1; + } + dst_opened = 1; + } + if (src_count == 0) { + cat_fd(STDIN_FILENO, dst_fd); + if (dst_opened) close(dst_fd); + return 0; + } + + int ret = 0; + + for (int i = 0; i < src_count; i++) { + char path[256]; + resolve_path(src_files[i], path, sizeof(path)); + + int src_fd = open(path, O_RDONLY); + if (src_fd < 0) { + write(STDERR_FILENO, "cat: ", 5); + write(STDERR_FILENO, path, strlen(path)); + write(STDERR_FILENO, ": cannot open\n", 14); + ret = 1; + continue; + } + + if (cat_fd(src_fd, dst_fd) < 0) { + write(STDERR_FILENO, "cat: ", 5); + write(STDERR_FILENO, path, strlen(path)); + write(STDERR_FILENO, ": read/write error\n", 19); + ret = 1; + } + + close(src_fd); + } + + if (dst_opened) close(dst_fd); + return ret; +} \ No newline at end of file diff --git a/src/userspace/bin/cat/cat.elf b/src/userspace/bin/cat/cat.elf new file mode 100755 index 0000000..4ff1ee4 Binary files /dev/null and b/src/userspace/bin/cat/cat.elf differ diff --git a/src/userspace/bin/cat/cat.o b/src/userspace/bin/cat/cat.o new file mode 100644 index 0000000..5759e4f Binary files /dev/null and b/src/userspace/bin/cat/cat.o differ diff --git a/src/userspace/bin/cd/Makefile b/src/userspace/bin/cd/Makefile new file mode 100644 index 0000000..ab416ea --- /dev/null +++ b/src/userspace/bin/cd/Makefile @@ -0,0 +1,28 @@ +CC := x86_64-elf-gcc +LD := x86_64-elf-ld +LIBC := ../../libc + +CFLAGS := -ffreestanding -nostdlib -fno-builtin -fno-stack-protector \ + -fno-PIE -fno-pic -m64 -march=x86-64 -mno-sse -mno-sse2 \ + -mno-mmx -mno-red-zone -Wall -Wextra -std=gnu11 \ + -I$(LIBC)/include + +LDFLAGS := -nostdlib -static -no-pie -T ../../user.ld + +OUT := cd.elf + +all: clean $(OUT) + +$(OUT): cd.o $(LIBC)/build/crt0.o $(LIBC)/build/libc.a + $(LD) $(LDFLAGS) $(LIBC)/build/crt0.o cd.o $(LIBC)/build/libc.a -o $@ + +cd.o: cd.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(LIBC)/build/crt0.o $(LIBC)/build/libc.a: + $(MAKE) -C $(LIBC) + +clean: + rm -f *.o $(OUT) + +.PHONY: all clean \ No newline at end of file diff --git a/src/userspace/bin/cd/cd.c b/src/userspace/bin/cd/cd.c new file mode 100644 index 0000000..19b072d --- /dev/null +++ b/src/userspace/bin/cd/cd.c @@ -0,0 +1,35 @@ +#include +#include + +// +// NOTE: +// as a standalone binary "cd" only changes the directory of "this" process +// for it to work in a shell it must exec it as a builtin or use the +// result path +// most shells handle cd internally +// + +int main(int argc, char *argv[]) +{ + if (argc < 2) { + // no argument: change to root + if (chdir("/") != 0) { + puts("cd: failed to change to /"); + return 1; + } + return 0; + } + + if (chdir(argv[1]) != 0) { + fprintf(stderr, "cd: %s: no such directory\n", argv[1]); + return 1; + } + + // print the new cwd so the parent shell can pick it up if needed + char buf[256]; + if (getcwd(buf, sizeof(buf))) { + puts(buf); + } + + return 0; +} \ No newline at end of file diff --git a/src/userspace/bin/cd/cd.elf b/src/userspace/bin/cd/cd.elf new file mode 100755 index 0000000..d88d1a9 Binary files /dev/null and b/src/userspace/bin/cd/cd.elf differ diff --git a/src/userspace/bin/cd/cd.o b/src/userspace/bin/cd/cd.o new file mode 100644 index 0000000..4ad484c Binary files /dev/null and b/src/userspace/bin/cd/cd.o differ diff --git a/src/userspace/bin/echo/Makefile b/src/userspace/bin/echo/Makefile new file mode 100644 index 0000000..9a41368 --- /dev/null +++ b/src/userspace/bin/echo/Makefile @@ -0,0 +1,28 @@ +CC := x86_64-elf-gcc +LD := x86_64-elf-ld +LIBC := ../../libc + +CFLAGS := -ffreestanding -nostdlib -fno-builtin -fno-stack-protector \ + -fno-PIE -fno-pic -m64 -march=x86-64 -mno-sse -mno-sse2 \ + -mno-mmx -mno-red-zone -Wall -Wextra -std=gnu11 \ + -I$(LIBC)/include + +LDFLAGS := -nostdlib -static -no-pie -T ../../user.ld + +OUT := echo.elf + +all: clean $(OUT) + +$(OUT): echo.o $(LIBC)/build/crt0.o $(LIBC)/build/libc.a + $(LD) $(LDFLAGS) $(LIBC)/build/crt0.o echo.o $(LIBC)/build/libc.a -o $@ + +echo.o: echo.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(LIBC)/build/crt0.o $(LIBC)/build/libc.a: + $(MAKE) -C $(LIBC) + +clean: + rm -f *.o $(OUT) + +.PHONY: all clean diff --git a/src/userspace/bin/echo/echo.c b/src/userspace/bin/echo/echo.c new file mode 100644 index 0000000..faade73 --- /dev/null +++ b/src/userspace/bin/echo/echo.c @@ -0,0 +1,23 @@ +#include +#include + +int main(int argc, char **argv) +{ + // no args, just print newline + if (argc < 2) { + write(STDOUT_FILENO, "\n", 1); + return 0; + } + + // print each arg separated by space + for (int i = 1; i < argc; i++) { + size_t len = strlen(argv[i]); + write(STDOUT_FILENO, argv[i], len); + + if (i < argc - 1) + write(STDOUT_FILENO, " ", 1); + } + + write(STDOUT_FILENO, "\n", 1); + return 0; +} diff --git a/src/userspace/bin/echo/echo.elf b/src/userspace/bin/echo/echo.elf new file mode 100755 index 0000000..8bee398 Binary files /dev/null and b/src/userspace/bin/echo/echo.elf differ diff --git a/src/userspace/bin/echo/echo.o b/src/userspace/bin/echo/echo.o new file mode 100644 index 0000000..5af7e36 Binary files /dev/null and b/src/userspace/bin/echo/echo.o differ diff --git a/src/userspace/bin/hello/Makefile b/src/userspace/bin/hello/Makefile new file mode 100644 index 0000000..3638d8d --- /dev/null +++ b/src/userspace/bin/hello/Makefile @@ -0,0 +1,28 @@ +CC := x86_64-elf-gcc +LD := x86_64-elf-ld +LIBC := ../../libc + +CFLAGS := -ffreestanding -nostdlib -fno-builtin -fno-stack-protector \ + -fno-PIE -fno-pic -m64 -march=x86-64 -mno-sse -mno-sse2 \ + -mno-mmx -mno-red-zone -Wall -Wextra -std=gnu11 \ + -I$(LIBC)/include + +LDFLAGS := -nostdlib -static -no-pie -T ../../user.ld + +OUT := hello.elf + +all: clean $(OUT) + +$(OUT): hello.o $(LIBC)/build/crt0.o $(LIBC)/build/libc.a + $(LD) $(LDFLAGS) $(LIBC)/build/crt0.o hello.o $(LIBC)/build/libc.a -o $@ + +hello.o: hello.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(LIBC)/build/crt0.o $(LIBC)/build/libc.a: + $(MAKE) -C $(LIBC) + +clean: + rm -f *.o $(OUT) + +.PHONY: all clean diff --git a/src/userspace/bin/hello/hello.c b/src/userspace/bin/hello/hello.c new file mode 100644 index 0000000..bfc12d4 --- /dev/null +++ b/src/userspace/bin/hello/hello.c @@ -0,0 +1,10 @@ +#include +#include + +#include + +int main(void) +{ + printf(A_GFX_GREEN "\nhello, world!\n\n"); + return 0; +} diff --git a/src/userspace/bin/hello/hello.elf b/src/userspace/bin/hello/hello.elf new file mode 100755 index 0000000..f292287 Binary files /dev/null and b/src/userspace/bin/hello/hello.elf differ diff --git a/src/userspace/bin/hello/hello.o b/src/userspace/bin/hello/hello.o new file mode 100644 index 0000000..9f5de8e Binary files /dev/null and b/src/userspace/bin/hello/hello.o differ diff --git a/src/userspace/bin/ls/Makefile b/src/userspace/bin/ls/Makefile new file mode 100644 index 0000000..d8ba6ff --- /dev/null +++ b/src/userspace/bin/ls/Makefile @@ -0,0 +1,28 @@ +CC := x86_64-elf-gcc +LD := x86_64-elf-ld +LIBC := ../../libc + +CFLAGS := -ffreestanding -nostdlib -fno-builtin -fno-stack-protector \ + -fno-PIE -fno-pic -m64 -march=x86-64 -mno-sse -mno-sse2 \ + -mno-mmx -mno-red-zone -Wall -Wextra -std=gnu11 \ + -I$(LIBC)/include + +LDFLAGS := -nostdlib -static -no-pie -T ../../user.ld + +OUT := ls.elf + +all: clean $(OUT) + +$(OUT): ls.o $(LIBC)/build/crt0.o $(LIBC)/build/libc.a + $(LD) $(LDFLAGS) $(LIBC)/build/crt0.o ls.o $(LIBC)/build/libc.a -o $@ + +ls.o: ls.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(LIBC)/build/crt0.o $(LIBC)/build/libc.a: + $(MAKE) -C $(LIBC) + +clean: + rm -f *.o $(OUT) + +.PHONY: all clean diff --git a/src/userspace/bin/ls/ls.c b/src/userspace/bin/ls/ls.c new file mode 100644 index 0000000..2221989 --- /dev/null +++ b/src/userspace/bin/ls/ls.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include + +#define COLS 6 // items per row + +static void resolve_path(const char *arg, char *out_buf, int bufsz) +{ + if (arg && arg[0] == '/') { + int i = 0; + while (i < bufsz - 1 && arg[i]) { out_buf[i] = arg[i]; i++; } + out_buf[i] = '\0'; + return; + } + + char cwd[256]; + if (!getcwd(cwd, sizeof(cwd))) { + cwd[0] = '/'; cwd[1] = '\0'; + } + + if (!arg || arg[0] == '\0') { + int i = 0; + while (i < bufsz - 1 && cwd[i]) { out_buf[i] = cwd[i]; i++; } + out_buf[i] = '\0'; + return; + } + int ci = 0; + while (ci < bufsz - 1 && cwd[ci]) { out_buf[ci] = cwd[ci]; ci++; } + if (ci > 0 && out_buf[ci - 1] != '/') { + if (ci < bufsz - 1) out_buf[ci++] = '/'; + } + int ai = 0; + while (ci < bufsz - 1 && arg[ai]) { out_buf[ci++] = arg[ai++]; } + out_buf[ci] = '\0'; +} + +int main(int argc, char **argv) +{ + char path[256]; + resolve_path((argc > 1) ? argv[1] : NULL, path, sizeof(path)); + + DIR *dir = opendir(path); + if (!dir) { + write(STDOUT_FILENO, "ls: cannot open '", 17); + write(STDOUT_FILENO, path, strlen(path)); + write(STDOUT_FILENO, "'\n", 2); + return 1; + } + + #define MAX_ENTRIES 256 + #define NAME_MAX_LEN 64 + + static char names[MAX_ENTRIES][NAME_MAX_LEN + 1]; + static char is_dir[MAX_ENTRIES]; + int count = 0; + + struct dirent *ent; + while (count < MAX_ENTRIES && (ent = readdir(dir)) != NULL) { + int ni = 0; + const char *src = ent->d_name; + while (ni < NAME_MAX_LEN && src[ni]) { + names[count][ni] = src[ni]; + ni++; + } + names[count][ni] = '\0'; + is_dir[count] = (ent->d_type == DT_DIR) ? 1 : 0; + count++; + } + + closedir(dir); + + // print COLS items per row + for (int i = 0; i < count; i++) { + if (is_dir[i]) { + write(STDOUT_FILENO, "\033[34m", 5); // blue for dirs + write(STDOUT_FILENO, names[i], strlen(names[i])); + write(STDOUT_FILENO, "/", 1); + write(STDOUT_FILENO, "\033[0m", 4); + } else { + write(STDOUT_FILENO, names[i], strlen(names[i])); + } + if ((i + 1) % COLS == 0 || i == count - 1) { + write(STDOUT_FILENO, "\n", 1); + } else { + write(STDOUT_FILENO, "\t", 1); + } + } + + return 0; +} \ No newline at end of file diff --git a/src/userspace/bin/ls/ls.elf b/src/userspace/bin/ls/ls.elf new file mode 100755 index 0000000..18a517d Binary files /dev/null and b/src/userspace/bin/ls/ls.elf differ diff --git a/src/userspace/bin/ls/ls.o b/src/userspace/bin/ls/ls.o new file mode 100644 index 0000000..84f6622 Binary files /dev/null and b/src/userspace/bin/ls/ls.o differ diff --git a/src/userspace/bin/lsblk/Makefile b/src/userspace/bin/lsblk/Makefile new file mode 100644 index 0000000..ee3d4fd --- /dev/null +++ b/src/userspace/bin/lsblk/Makefile @@ -0,0 +1,28 @@ +CC := x86_64-elf-gcc +LD := x86_64-elf-ld +LIBC := ../../libc + +CFLAGS := -ffreestanding -nostdlib -fno-builtin -fno-stack-protector \ + -fno-PIE -fno-pic -m64 -march=x86-64 -mno-sse -mno-sse2 \ + -mno-mmx -mno-red-zone -Wall -Wextra -std=gnu11 \ + -I$(LIBC)/include + +LDFLAGS := -nostdlib -static -no-pie -T ../../user.ld + +OUT := lsblk.elf + +all: clean $(OUT) + +$(OUT): lsblk.o $(LIBC)/build/crt0.o $(LIBC)/build/libc.a + $(LD) $(LDFLAGS) $(LIBC)/build/crt0.o lsblk.o $(LIBC)/build/libc.a -o $@ + +lsblk.o: lsblk.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(LIBC)/build/crt0.o $(LIBC)/build/libc.a: + $(MAKE) -C $(LIBC) + +clean: + rm -f *.o $(OUT) + +.PHONY: all clean \ No newline at end of file diff --git a/src/userspace/bin/lsblk/lsblk.c b/src/userspace/bin/lsblk/lsblk.c new file mode 100644 index 0000000..e0c822d --- /dev/null +++ b/src/userspace/bin/lsblk/lsblk.c @@ -0,0 +1,20 @@ +#include +#include + +int main(void) { + struct dirent *entry; + DIR *dp = opendir("/sys/block"); + if (dp == NULL) { + perror("lsblk"); + return 1; + } + + printf("NAME\n"); + while ((entry = readdir(dp))) { + if (entry->d_name[0] == '.') continue; + printf("%s\n", entry->d_name); + } + + closedir(dp); + return 0; +} \ No newline at end of file diff --git a/src/userspace/bin/lsblk/lsblk.elf b/src/userspace/bin/lsblk/lsblk.elf new file mode 100755 index 0000000..42f0314 Binary files /dev/null and b/src/userspace/bin/lsblk/lsblk.elf differ diff --git a/src/userspace/bin/lsblk/lsblk.h b/src/userspace/bin/lsblk/lsblk.h new file mode 100644 index 0000000..e116800 --- /dev/null +++ b/src/userspace/bin/lsblk/lsblk.h @@ -0,0 +1,3 @@ +#pragma once + +// \ No newline at end of file diff --git a/src/userspace/bin/lsblk/lsblk.o b/src/userspace/bin/lsblk/lsblk.o new file mode 100644 index 0000000..8f139c1 Binary files /dev/null and b/src/userspace/bin/lsblk/lsblk.o differ diff --git a/src/userspace/bin/reboot/Makefile b/src/userspace/bin/reboot/Makefile new file mode 100644 index 0000000..a0ea266 --- /dev/null +++ b/src/userspace/bin/reboot/Makefile @@ -0,0 +1,28 @@ +CC := x86_64-elf-gcc +LD := x86_64-elf-ld +LIBC := ../../libc + +CFLAGS := -ffreestanding -nostdlib -fno-builtin -fno-stack-protector \ + -fno-PIE -fno-pic -m64 -march=x86-64 -mno-sse -mno-sse2 \ + -mno-mmx -mno-red-zone -Wall -Wextra -std=gnu11 \ + -I$(LIBC)/include + +LDFLAGS := -nostdlib -static -no-pie -T ../../user.ld + +OUT := reboot.elf + +all: clean $(OUT) + +$(OUT): reboot.o $(LIBC)/build/crt0.o $(LIBC)/build/libc.a + $(LD) $(LDFLAGS) $(LIBC)/build/crt0.o reboot.o $(LIBC)/build/libc.a -o $@ + +reboot.o: reboot.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(LIBC)/build/crt0.o $(LIBC)/build/libc.a: + $(MAKE) -C $(LIBC) + +clean: + rm -f *.o $(OUT) + +.PHONY: all clean \ No newline at end of file diff --git a/src/userspace/bin/reboot/reboot.c b/src/userspace/bin/reboot/reboot.c new file mode 100644 index 0000000..4f9b1ea --- /dev/null +++ b/src/userspace/bin/reboot/reboot.c @@ -0,0 +1,7 @@ +#include +#include + +int main(void) { + reboot(RSYSTEM_CMD_RESTART); + _exit(1); +} \ No newline at end of file diff --git a/src/userspace/bin/reboot/reboot.elf b/src/userspace/bin/reboot/reboot.elf new file mode 100755 index 0000000..5374ad1 Binary files /dev/null and b/src/userspace/bin/reboot/reboot.elf differ diff --git a/src/userspace/bin/reboot/reboot.o b/src/userspace/bin/reboot/reboot.o new file mode 100644 index 0000000..d6eef49 Binary files /dev/null and b/src/userspace/bin/reboot/reboot.o differ diff --git a/src/userspace/bin/tree/Makefile b/src/userspace/bin/tree/Makefile new file mode 100644 index 0000000..c6d1565 --- /dev/null +++ b/src/userspace/bin/tree/Makefile @@ -0,0 +1,28 @@ +CC := x86_64-elf-gcc +LD := x86_64-elf-ld +LIBC := ../../libc + +CFLAGS := -ffreestanding -nostdlib -fno-builtin -fno-stack-protector \ + -fno-PIE -fno-pic -m64 -march=x86-64 -mno-sse -mno-sse2 \ + -mno-mmx -mno-red-zone -Wall -Wextra -std=gnu11 \ + -I$(LIBC)/include + +LDFLAGS := -nostdlib -static -no-pie -T ../../user.ld + +OUT := tree.elf + +all: clean $(OUT) + +$(OUT): tree.o $(LIBC)/build/crt0.o $(LIBC)/build/libc.a + $(LD) $(LDFLAGS) $(LIBC)/build/crt0.o tree.o $(LIBC)/build/libc.a -o $@ + +tree.o: tree.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(LIBC)/build/crt0.o $(LIBC)/build/libc.a: + $(MAKE) -C $(LIBC) + +clean: + rm -f *.o $(OUT) + +.PHONY: all clean diff --git a/src/userspace/bin/tree/tree.c b/src/userspace/bin/tree/tree.c new file mode 100644 index 0000000..383ef3f --- /dev/null +++ b/src/userspace/bin/tree/tree.c @@ -0,0 +1,89 @@ +#include +#include +#include + +#define MAX_DEPTH 8 +#define MAX_ENTRIES 64 +#define MAX_PATH 256 + +#define SYM_VERT "| " +#define SYM_TEE "+-- " +#define SYM_LAST "`-- " +#define SYM_EMPTY " " + +static void print_str(const char *s) { + write(STDOUT_FILENO, s, strlen(s)); +} + +static int has_more[MAX_DEPTH + 1]; + +static void print_prefix(int depth, int is_last) { + for (int i = 0; i < depth; i++) + print_str(has_more[i] ? SYM_VERT : SYM_EMPTY); + print_str(is_last ? SYM_LAST : SYM_TEE); +} +typedef struct { + unsigned char type; + char name[64]; +} _snap_t; + +static void tree_recurse(const char *path, int depth) { + if (depth > MAX_DEPTH) return; + + DIR *dir = opendir(path); + if (!dir) return; + + _snap_t snap[MAX_ENTRIES]; + int total = 0; + + struct dirent *ent; + while (total < MAX_ENTRIES && (ent = readdir(dir)) != NULL) { + snap[total].type = ent->d_type; + // copy only first 63 chars of name (safe for 8.3 + ext paths) + strncpy(snap[total].name, ent->d_name, 63); + snap[total].name[63] = '\0'; + total++; + } + + closedir(dir); + + for (int i = 0; i < total; i++) { + int is_last = (i == total - 1); + has_more[depth] = !is_last; + print_prefix(depth, is_last); + + if (snap[i].type == DT_DIR) { + write(STDOUT_FILENO, "\033[36m", 5); // cyan + print_str(snap[i].name); + print_str("/"); + write(STDOUT_FILENO, "\033[0m", 4); + print_str("\n"); + + char child[MAX_PATH]; + size_t plen = strlen(path); + size_t nlen = strlen(snap[i].name); + if (plen + nlen + 2 <= MAX_PATH) { + memcpy(child, path, plen); + if (plen > 0 && child[plen - 1] != '/') child[plen++] = '/'; + memcpy(child + plen, snap[i].name, nlen + 1); + tree_recurse(child, depth + 1); + } + } else { + print_str(snap[i].name); + print_str("\n"); + } + } +} + +int main(int argc, char **argv) +{ + const char *path = (argc > 1) ? argv[1] : "/"; + + write(STDOUT_FILENO, "\033[36m", 5); + print_str(path); + write(STDOUT_FILENO, "\033[0m", 4); + print_str("\n"); + + tree_recurse(path, 0); + return 0; +} diff --git a/src/userspace/bin/tree/tree.elf b/src/userspace/bin/tree/tree.elf new file mode 100755 index 0000000..2a4a630 Binary files /dev/null and b/src/userspace/bin/tree/tree.elf differ diff --git a/src/userspace/bin/tree/tree.o b/src/userspace/bin/tree/tree.o new file mode 100644 index 0000000..fcc8ed1 Binary files /dev/null and b/src/userspace/bin/tree/tree.o differ diff --git a/src/userspace/hello.S b/src/userspace/hello.S deleted file mode 100644 index 2e772ec..0000000 --- a/src/userspace/hello.S +++ /dev/null @@ -1,11 +0,0 @@ -.section .text -.global _start - -_start: - # Just exit immediately with code 42 to test if user mode works - mov $60, %rax # SYS_EXIT - mov $42, %rdi # status = 42 - syscall - - # Should never reach here - hlt diff --git a/src/userspace/hello.o b/src/userspace/hello.o deleted file mode 100644 index 2628cba..0000000 Binary files a/src/userspace/hello.o and /dev/null differ diff --git a/src/userspace/libc/Makefile b/src/userspace/libc/Makefile new file mode 100644 index 0000000..f12c03b --- /dev/null +++ b/src/userspace/libc/Makefile @@ -0,0 +1,31 @@ +CC := x86_64-elf-gcc +AR := x86_64-elf-ar +INC := $(CURDIR)/include +BLD := $(CURDIR)/build + +CFLAGS := -ffreestanding -nostdlib -fno-builtin -fno-stack-protector \ + -fno-PIE -fno-pic -m64 -march=x86-64 -mno-sse -mno-sse2 \ + -mno-mmx -mno-red-zone -Wall -Wextra -std=gnu11 \ + -I$(INC) -Isrc + +SRCS := src/errno.c src/string.c src/stdlib.c src/unistd.c src/fcntl.c src/stdio.c src/dirent.c src/ioctl.c src/system.c +OBJS := $(patsubst src/%.c, $(BLD)/%.o, $(SRCS)) + +all: $(BLD)/libc.a $(BLD)/crt0.o + +$(BLD)/libc.a: $(OBJS) + $(AR) rcs $@ $^ + +$(BLD)/%.o: src/%.c | $(BLD) + $(CC) $(CFLAGS) -c $< -o $@ + +$(BLD)/crt0.o: src/crt0.S | $(BLD) + $(CC) $(CFLAGS) -c $< -o $@ + +$(BLD): + mkdir -p $@ + +clean: + rm -rf $(BLD) + +.PHONY: all clean diff --git a/src/userspace/libc/include/ctype.h b/src/userspace/libc/include/ctype.h new file mode 100644 index 0000000..6f70f09 --- /dev/null +++ b/src/userspace/libc/include/ctype.h @@ -0,0 +1 @@ +#pragma once diff --git a/src/userspace/libc/include/dirent.h b/src/userspace/libc/include/dirent.h new file mode 100644 index 0000000..89337de --- /dev/null +++ b/src/userspace/libc/include/dirent.h @@ -0,0 +1,29 @@ +#pragma once +#include + +// d_type values (POSIX / same as Linux) +#define DT_UNKNOWN 0 +#define DT_FIFO 1 +#define DT_CHR 2 // character device +#define DT_DIR 4 // directory +#define DT_BLK 6 // block device +#define DT_REG 8 // regular file +#define DT_LNK 10 // symbolic link +#define DT_SOCK 12 // socket +#define DT_WHT 14 // whiteout + +struct dirent { + ino_t d_ino; + off_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[256];// null-terminated filename +}; +typedef struct __dir DIR; + +DIR *opendir (const char *path); +struct dirent *readdir (DIR *dirp); +int closedir(DIR *dirp); + +// rewind to beginning +void rewinddir(DIR *dirp); diff --git a/src/userspace/libc/include/emx/ansi.h b/src/userspace/libc/include/emx/ansi.h new file mode 100644 index 0000000..8d7b3c3 --- /dev/null +++ b/src/userspace/libc/include/emx/ansi.h @@ -0,0 +1,16 @@ +#pragma once + +// +// ansi lib +// + +// console colors +//ansi: \esc[color +#define A_GFX_RED "\033[31m" +#define A_GFX_GREEN "\033[32m" +#define A_GFX_YELLOW "\033[33m" +#define A_GFX_BLUE "\033[34m" +#define A_GFX_MAGENTA "\033[35m" +#define A_GFX_CYAN "\033[36m" +#define A_GFX_WHITE "\033[37m" +#define A_GFX_RESET "\033[0m" diff --git a/src/userspace/libc/include/emx/fb.h b/src/userspace/libc/include/emx/fb.h new file mode 100644 index 0000000..d87c631 --- /dev/null +++ b/src/userspace/libc/include/emx/fb.h @@ -0,0 +1,42 @@ +#pragma once + +// ioctl request codes for /dev/fb0 +#define FBIOGET_VSCREENINFO 0x4600 +#define FBIOPUT_VSCREENINFO 0x4601 +#define FBIOGET_FSCREENINFO 0x4602 +#define FBIO_READ_RECT 0x4610 +#define FBIO_BLIT 0x4611 + +typedef struct { + unsigned int xres; + unsigned int yres; + unsigned int xres_virtual; + unsigned int yres_virtual; + unsigned int xoffset; + unsigned int yoffset; + unsigned int bits_per_pixel; + unsigned int grayscale; + unsigned int red_offset; + unsigned int red_length; + unsigned int green_offset; + unsigned int green_length; + unsigned int blue_offset; + unsigned int blue_length; + unsigned int transp_offset; + unsigned int transp_length; +} fb_var_screeninfo; + +typedef struct { + char id[16]; + unsigned long smem_start; // physical address of framebuffer + unsigned int smem_len; // size in bytes + unsigned int type; + unsigned int visual; + unsigned int line_length; // pitch in bytes +} fb_fix_screeninfo; + +// used for both FBIO_READ_RECT and FBIO_BLIT +typedef struct { + unsigned int x, y, w, h; + unsigned int *pixels; +} fb_rect_t; \ No newline at end of file diff --git a/src/userspace/libc/include/emx/mouse.h b/src/userspace/libc/include/emx/mouse.h new file mode 100644 index 0000000..5b0d010 --- /dev/null +++ b/src/userspace/libc/include/emx/mouse.h @@ -0,0 +1,13 @@ +#pragma once + +//int mouse_init(void); + +/* + +typedef struct { + int dx, dy; + int abs_x, abs_y; + unsigned char buttons; +} mouse_event_t; + +*/ \ No newline at end of file diff --git a/src/userspace/libc/include/emx/sinfo.h b/src/userspace/libc/include/emx/sinfo.h new file mode 100644 index 0000000..79d7146 --- /dev/null +++ b/src/userspace/libc/include/emx/sinfo.h @@ -0,0 +1,27 @@ +#pragma once + +#define __EMEX__ "emex" +#define __EMEXF_C__ "EMEX" +#define __EMEXF_B1__ "[emex]" +#define __EMEXF_B1C__ "[EMEX]" +#define __EMEXF_S__ "emx" +#define __EMXSOPN__ EMEX4 +#define __EMXSOPN_B1__ "[" EMEX4 "]" + +/* + * F_C == fromat caps + * F_B1 == fromat brackets type 1 + * F_B2 == fromat brackets type 2 + * F_S == format short + * + * SOP == system or program + * + * N == name + */ + +/* + * b1 == [] + * b2 == () + * b3 == {} + * b4 == <> + */ \ No newline at end of file diff --git a/src/userspace/libc/include/emx/system.h b/src/userspace/libc/include/emx/system.h new file mode 100644 index 0000000..c8eb2c7 --- /dev/null +++ b/src/userspace/libc/include/emx/system.h @@ -0,0 +1,10 @@ +#pragma once + +// from linux +#define RSYSTEM_MAGIC1 0xfee1deadUL +#define RSYSTEM_MAGIC2 0x28121969UL +#define RSYSTEM_CMD_RESTART 0x01234567UL +#define RSYSTEM_CMD_HALT 0xcdef0123UL +#define RSYSTEM_CMD_POWEROFF 0x4321fedcUL + +int reboot(unsigned long cmd); \ No newline at end of file diff --git a/src/userspace/libc/include/emx/tty.h b/src/userspace/libc/include/emx/tty.h new file mode 100644 index 0000000..38de6d9 --- /dev/null +++ b/src/userspace/libc/include/emx/tty.h @@ -0,0 +1,8 @@ +#pragma once + +//request codes for /dev/tty0 + +#define TTY_ECHO 0 //default +#define TTY_NOECHO 1 +#define TTY_MASKECHO 2 +#define TTY_RAW 3 \ No newline at end of file diff --git a/src/userspace/libc/include/errno.h b/src/userspace/libc/include/errno.h new file mode 100644 index 0000000..7656a92 --- /dev/null +++ b/src/userspace/libc/include/errno.h @@ -0,0 +1,21 @@ +#pragma once +extern int errno; +#define EPERM 1 +#define ENOENT 2 +#define ESRCH 3 +#define EINTR 4 +#define EIO 5 +#define EBADF 9 +#define ENOMEM 12 +#define EACCES 13 +#define EFAULT 14 +#define EEXIST 17 +#define ENODEV 19 +#define ENOTDIR 20 +#define EISDIR 21 +#define EINVAL 22 +#define EMFILE 24 +#define ENOSPC 28 +#define EPIPE 32 +#define ERANGE 34 +#define ENOSYS 38 diff --git a/src/userspace/libc/include/fcntl.h b/src/userspace/libc/include/fcntl.h new file mode 100644 index 0000000..65858dd --- /dev/null +++ b/src/userspace/libc/include/fcntl.h @@ -0,0 +1,11 @@ +#pragma once +#include + +// open flags (needs to vfs.h) +#define O_RDONLY 0x01 +#define O_WRONLY 0x02 +#define O_RDWR 0x03 +#define O_CREAT 0x04 + +int open(const char *path, int flags, ...); +int close(int fd); diff --git a/src/userspace/libc/include/math.h b/src/userspace/libc/include/math.h new file mode 100644 index 0000000..32f73a8 --- /dev/null +++ b/src/userspace/libc/include/math.h @@ -0,0 +1,5 @@ +#pragma once + +#define M_PI 3.14159265358979323846 +#define M_PI_2 1.57079632679489661923 +#define M_SQRT2 1.41421356237309504880 diff --git a/src/userspace/libc/include/stdarg.h b/src/userspace/libc/include/stdarg.h new file mode 100644 index 0000000..65a9992 --- /dev/null +++ b/src/userspace/libc/include/stdarg.h @@ -0,0 +1,6 @@ +#pragma once +typedef __builtin_va_list va_list; +#define va_start(v,l) __builtin_va_start(v,l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v,T) __builtin_va_arg(v,T) +#define va_copy(d,s) __builtin_va_copy(d,s) diff --git a/src/userspace/libc/include/stdbool.h b/src/userspace/libc/include/stdbool.h new file mode 100644 index 0000000..abc7c42 --- /dev/null +++ b/src/userspace/libc/include/stdbool.h @@ -0,0 +1,4 @@ +#pragma once +#define bool _Bool +#define true 1 +#define false 0 diff --git a/src/userspace/libc/include/stddef.h b/src/userspace/libc/include/stddef.h new file mode 100644 index 0000000..f87760b --- /dev/null +++ b/src/userspace/libc/include/stddef.h @@ -0,0 +1,5 @@ +#pragma once +typedef unsigned long size_t; +typedef long ptrdiff_t; +#define NULL ((void *)0) +#define offsetof(t, m) __builtin_offsetof(t, m) diff --git a/src/userspace/libc/include/stdint.h b/src/userspace/libc/include/stdint.h new file mode 100644 index 0000000..768a883 --- /dev/null +++ b/src/userspace/libc/include/stdint.h @@ -0,0 +1,19 @@ +#pragma once +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef signed long long int64_t; +typedef unsigned long uintptr_t; +typedef long intptr_t; +#define UINT8_MAX 255U +#define UINT16_MAX 65535U +#define UINT32_MAX 4294967295U +#define UINT64_MAX 18446744073709551615ULL +#define INT32_MIN (-2147483648) +#define INT32_MAX 2147483647 +#define INT64_MIN (-9223372036854775807LL - 1) +#define INT64_MAX 9223372036854775807LL diff --git a/src/userspace/libc/include/stdio.h b/src/userspace/libc/include/stdio.h new file mode 100644 index 0000000..5516723 --- /dev/null +++ b/src/userspace/libc/include/stdio.h @@ -0,0 +1,43 @@ +#pragma once +#include +#include + +#define EOF (-1) + +typedef struct { + int _fd; + int _flags; + int _eof; + int _err; +} FILE; + + +#define _FILE_READ 0x01 +#define _FILE_WRITE 0x02 + +extern FILE *stdin; +extern FILE *stdout; +extern FILE *stderr; + +void perror(const char *s); + +FILE *fopen(const char *path, const char *mode); + +int fclose(FILE *f); +size_t fread(void *buf, size_t sz, size_t n, FILE *f); +size_t fwrite(const void *buf, size_t sz, size_t n, FILE *f); +char *fgets(char *buf, int n, FILE *f); +int fputc(int c, FILE *f); +int fputs(const char *s, FILE *f); +int feof(FILE *f); +int ferror(FILE *f); +int fprintf(FILE *f, const char *fmt, ...); +int vfprintf(FILE *f, const char *fmt, va_list ap); + +int puts(const char *s); +int putchar(int c); + +int printf(const char *fmt, ...); +int vprintf(const char *fmt, va_list ap); +int snprintf(char *buf, size_t size, const char *fmt, ...); +int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap); diff --git a/src/userspace/libc/include/stdlib.h b/src/userspace/libc/include/stdlib.h new file mode 100644 index 0000000..8709ea8 --- /dev/null +++ b/src/userspace/libc/include/stdlib.h @@ -0,0 +1,23 @@ +#pragma once +#include + +void *malloc(size_t n); +void *calloc(size_t nmemb, size_t size); +void *realloc(void *ptr, size_t n); +void free (void *ptr); + +void exit(int status) __attribute__((noreturn)); +void abort(void) __attribute__((noreturn)); + +int atoi(const char *s); +long atol(const char *s); +long strtol(const char *s, char **end, int base); + +int abs(int x); +long labs(long x); + +// for screen clear command +//int system(const char *cmd); + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 diff --git a/src/userspace/libc/include/string.h b/src/userspace/libc/include/string.h new file mode 100644 index 0000000..4d19e87 --- /dev/null +++ b/src/userspace/libc/include/string.h @@ -0,0 +1,22 @@ +#pragma once +#include + +char *strerror(int errnum); + +void *memcpy (void *dst, const void *src, size_t n); +void *memmove(void *dst, const void *src, size_t n); +void *memset (void *s, int c, size_t n); +int memcmp (const void *a, const void *b, size_t n); + +size_t strlen (const char *s); +char *strcpy (char *dst, const char *src); +char *strncpy(char *dst, const char *src, size_t n); +char *strcat (char *dst, const char *src); +char *strncat(char *dst, const char *src, size_t n); +int strcmp (const char *a, const char *b); +int strncmp(const char *a, const char *b, size_t n); +char *strchr (const char *s, int c); +char *strrchr(const char *s, int c); +char *strstr (const char *hay, const char *needle); +char *strtok (char *s, const char *delim); +char *strdup (const char *s); diff --git a/src/userspace/libc/include/sys/ioctl.h b/src/userspace/libc/include/sys/ioctl.h new file mode 100644 index 0000000..98f3156 --- /dev/null +++ b/src/userspace/libc/include/sys/ioctl.h @@ -0,0 +1,9 @@ +#pragma once +#include +#include +#include + +// return: +// 0 == success +// -1 == error +int ioctl(int fd, int request, void *arg); \ No newline at end of file diff --git a/src/userspace/libc/include/sys/types.h b/src/userspace/libc/include/sys/types.h new file mode 100644 index 0000000..34a484d --- /dev/null +++ b/src/userspace/libc/include/sys/types.h @@ -0,0 +1,9 @@ +#pragma once +#include +typedef long ssize_t; +typedef int pid_t; +typedef long off_t; +typedef unsigned long ino_t; // inode num +typedef unsigned int mode_t; +typedef unsigned int uid_t; +typedef unsigned int gid_t; diff --git a/src/userspace/libc/include/unistd.h b/src/userspace/libc/include/unistd.h new file mode 100644 index 0000000..51d099b --- /dev/null +++ b/src/userspace/libc/include/unistd.h @@ -0,0 +1,35 @@ +#pragma once +#include +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + + +// i/o +ssize_t read(int fd, void *buf, size_t n); +ssize_t write(int fd, const void *buf, size_t n); + +// filesystem +int chdir (const char *path); +int mkdir (const char *path); +char *getcwd (char *buf, size_t size); +int unlink(const char *path); + +// process +pid_t getpid (void); +pid_t fork (void); +void _exit (int status) __attribute__((noreturn)); +int execve (const char *path, char *const argv[], char *const envp[]); + +static inline pid_t spawn(const char *path) { + pid_t pid = fork(); + if (pid == 0) { + // spawn child + char *const argv[] = { (char *)path, (char *)0 }; + char *const envp[] = { (char *)0 }; + execve(path, argv, envp); + _exit(1); // execve failed + } + return pid; // parent gets pid immediately + // no wait +} \ No newline at end of file diff --git a/src/userspace/libc/src/_syscall.h b/src/userspace/libc/src/_syscall.h new file mode 100644 index 0000000..90ce201 --- /dev/null +++ b/src/userspace/libc/src/_syscall.h @@ -0,0 +1,43 @@ +#pragma once + +#define _SCAL_READ 0 +#define _SCAL_WRITE 1 +#define _SCAL_OPEN 2 +#define _SCAL_CLOSE 3 +#define _SCAL_BRK 12 +#define _SCAL_GETPID 39 +#define _SCAL_FORK 57 +#define _SCAL_EXECVE 59 +#define _SCAL_EXIT 60 +#define _SCAL_GETDENTS 78 // list directory entries (path, buf, max) +#define _SCAL_GETCWD 79 +#define _SCAL_CHDIR 80 +#define _SCAL_MKDIR 83 +#define _SCAL_UNLINK 87 // (delete file) +#define _SCAL_IOCTL 16 +#define _SCAL_IPC_SEND 200 +#define _SCAL_IPC_RECV 201 +#define _SCAL_REBOOT 169 +#define _SCAL_MOUSE_INIT 250 + +static inline long _sc0(long n) { + long r; + __asm__ volatile("syscall":"=a"(r):"a"(n):"rcx","r11","memory"); + return r; +} + +static inline long _sc1(long n, long a1) { + long r; + __asm__ volatile("syscall":"=a"(r):"a"(n),"D"(a1):"rcx","r11","memory"); + return r; +} +static inline long _sc2(long n, long a1, long a2) { + long r; + __asm__ volatile("syscall":"=a"(r):"a"(n),"D"(a1),"S"(a2):"rcx","r11","memory"); + return r; +} +static inline long _sc3(long n, long a1, long a2, long a3) { + long r; + __asm__ volatile("syscall":"=a"(r):"a"(n),"D"(a1),"S"(a2),"d"(a3):"rcx","r11","memory"); + return r; +} diff --git a/src/userspace/libc/src/crt0.S b/src/userspace/libc/src/crt0.S new file mode 100644 index 0000000..52cb5bd --- /dev/null +++ b/src/userspace/libc/src/crt0.S @@ -0,0 +1,12 @@ +.section .text +.global _start + + +_start: + xor %rbp, %rbp // clear frame pointer (ABI requirement) + mov (%rsp), %rdi // argc == *rsp + lea 8(%rsp), %rsi // argv == rsp+8 + call main + mov %rax, %rdi + call exit + hlt diff --git a/src/userspace/libc/src/dirent.c b/src/userspace/libc/src/dirent.c new file mode 100644 index 0000000..2c847fe --- /dev/null +++ b/src/userspace/libc/src/dirent.c @@ -0,0 +1,86 @@ +#include +#include +#include +#include +#include "_syscall.h" + +// entry written by scall_getdents (matches _emx_kdirent_t) +typedef struct { + unsigned char _type; + char _name[64]; +} _kdirent_t; + +// max entries per directory read +// kept small so the stack buffer stays 4KB +#define _KDIRENT_MAX 64 + +static unsigned char _ktype_to_dt(unsigned char ktype) { + switch (ktype) { + case 0x01: return DT_REG; + case 0x02: return DT_DIR; + case 0x04: return DT_CHR; + default: return DT_UNKNOWN; + } +} + +struct __dir { + struct dirent *_entries; + int _count; + int _pos; +}; + +DIR *opendir(const char *path) +{ + if (!path) { errno = EINVAL; return NULL; } + + // use a STACK buffer for the raw kernel data + // free automatically when opendir returns + _kdirent_t raw[_KDIRENT_MAX]; + + long n = _sc3(_SCAL_GETDENTS, (long)path, (long)raw, (long)_KDIRENT_MAX); + if (n < 0) { errno = ENOENT; return NULL; } + + // only allocate heap for the actual entries we got back + struct dirent *entries = NULL; + if (n > 0) { + entries = (struct dirent *)malloc(sizeof(struct dirent) * (int)n); + if (!entries) { errno = ENOMEM; return NULL; } + + for (int i = 0; i < (int)n; i++) { + entries[i].d_ino = 0; + entries[i].d_off = 0; + entries[i].d_reclen = (unsigned short)sizeof(struct dirent); + entries[i].d_type = _ktype_to_dt(raw[i]._type); + strncpy(entries[i].d_name, raw[i]._name, 255); + entries[i].d_name[255] = '\0'; + } + } + + DIR *dir = (DIR *)malloc(sizeof(DIR)); + if (!dir) { + free(entries); + errno = ENOMEM; + return NULL; + } + + dir->_entries = entries; + dir->_count = (int)n; + dir->_pos = 0; + + return dir; +} + +struct dirent *readdir(DIR *dirp){ + if (!dirp) { errno = EBADF; return NULL; } + if (dirp->_pos >= dirp->_count) return NULL; + return &dirp->_entries[dirp->_pos++]; +} + +int closedir(DIR *dirp) { + if (!dirp) { errno = EBADF; return -1; } + free(dirp->_entries); + free(dirp); + return 0; +} + +void rewinddir(DIR *dirp){ if (dirp) dirp->_pos = 0;} diff --git a/src/userspace/libc/src/errno.c b/src/userspace/libc/src/errno.c new file mode 100644 index 0000000..c898fab --- /dev/null +++ b/src/userspace/libc/src/errno.c @@ -0,0 +1,2 @@ +#include +int errno = 0; diff --git a/src/userspace/libc/src/fcntl.c b/src/userspace/libc/src/fcntl.c new file mode 100644 index 0000000..963e82a --- /dev/null +++ b/src/userspace/libc/src/fcntl.c @@ -0,0 +1,17 @@ +#include +#include +#include "_syscall.h" + +int open(const char *path, int flags, ...) +{ + long r = _sc2(_SCAL_OPEN, (long)path, (long)flags); + if (r < 0) { errno = (int)-r; return -1; } + return (int)r; +} + +int close(int fd) +{ + long r = _sc1(_SCAL_CLOSE, fd); + if (r < 0) { errno = (int)-r; return -1; } + return 0; +} diff --git a/src/userspace/libc/src/ioctl.c b/src/userspace/libc/src/ioctl.c new file mode 100644 index 0000000..583d5f4 --- /dev/null +++ b/src/userspace/libc/src/ioctl.c @@ -0,0 +1,16 @@ +#include +#include "_syscall.h" + +// +//#define SYS_IOCTL 16 + +int ioctl(int fd, int request, void *arg) { + long ret; + __asm__ volatile ( + "syscall" + : "=a"(ret) + : "0"(_SCAL_IOCTL), "D"((long)fd), "S"((long)request), "d"((long)arg) + : "rcx", "r11", "memory" + ); + return (int)ret; +} \ No newline at end of file diff --git a/src/userspace/libc/src/stdio.c b/src/userspace/libc/src/stdio.c new file mode 100644 index 0000000..d3d69e9 --- /dev/null +++ b/src/userspace/libc/src/stdio.c @@ -0,0 +1,304 @@ +#include +#include +#include +#include +#include +#include +//#include + +static FILE _stdin = { ._fd = STDIN_FILENO, ._flags = _FILE_READ, ._eof = 0, ._err = 0 }; +static FILE _stdout = { ._fd = STDOUT_FILENO, ._flags = _FILE_WRITE, ._eof = 0, ._err = 0 }; +static FILE _stderr = { ._fd = STDERR_FILENO, ._flags = _FILE_WRITE, ._eof = 0, ._err = 0 }; + +FILE *stdin = &_stdin; +FILE *stdout = &_stdout; +FILE *stderr = &_stderr; + +FILE *fopen(const char *path, const char *mode) +{ + if (!path || !mode) { errno = EINVAL; return NULL; } + + int flags = 0; + int fflags = 0; + + // parse mode string + char m = mode[0]; + int plus = (mode[1] == '+') || (mode[2] == '+'); + + if (m == 'r') { + flags = plus ? O_RDWR : O_RDONLY; + fflags = plus ? (_FILE_READ | _FILE_WRITE) : _FILE_READ; + } else if (m == 'w') { + flags = plus ? (O_RDWR | O_CREAT) : (O_WRONLY | O_CREAT); + fflags = plus ? (_FILE_READ | _FILE_WRITE) : _FILE_WRITE; + } else if (m == 'a') { + flags = O_WRONLY | O_CREAT; + fflags = _FILE_WRITE; + } else { + errno = EINVAL; + return NULL; + } + + int fd = open(path, flags); + if (fd < 0) return NULL; // errno already set by open() + + FILE *f = (FILE *)malloc(sizeof(FILE)); + if (!f) { close(fd); errno = ENOMEM; return NULL; } + + f->_fd = fd; + f->_flags = fflags; + f->_eof = 0; + f->_err = 0; + + return f; +} + +int fclose(FILE *f) +{ + if (!f) { errno = EINVAL; return EOF; } + + // do not close the static standard streams + int is_std = (f == stdin || f == stdout || f == stderr); + + int r = 0; + if (!is_std) { + r = close(f->_fd); + free(f); + } + return r; +} + +size_t fread(void *buf, size_t sz, size_t n, FILE *f) +{ + if (!f || !buf || !sz || !n) return 0; + if (f->_eof || f->_err) return 0; + if (!(f->_flags & _FILE_READ)) { f->_err = 1; return 0; } + + size_t total = sz * n; + ssize_t got = read(f->_fd, buf, total); + + if (got < 0) { f->_err = 1; return 0; } + if (got == 0 || (size_t)got < total) f->_eof = 1; + + return (size_t)got / sz; // full elements read +} + +size_t fwrite(const void *buf, size_t sz, size_t n, FILE *f) +{ + if (!f || !buf || !sz || !n) return 0; + if (!(f->_flags & _FILE_WRITE)) { f->_err = 1; return 0; } + + size_t total = sz * n; + ssize_t written = write(f->_fd, buf, total); + + if (written < 0) { f->_err = 1; return 0; } + return (size_t)written / sz; +} + +char *fgets(char *buf, int n, FILE *f) +{ + if (!f || !buf || n <= 0) return NULL; + if (f->_eof || f->_err) return NULL; + if (!(f->_flags & _FILE_READ)) { f->_err = 1; return NULL; } + + int i = 0; + while (i < n - 1) { + char c; + ssize_t r = read(f->_fd, &c, 1); + if (r < 0) { f->_err = 1; break; } + if (r == 0) { f->_eof = 1; break; } + buf[i++] = c; + if (c == '\n') break; + } + + if (i == 0) return NULL; + buf[i] = '\0'; + return buf; +} + + +int fputc(int c, FILE *f) +{ + if (!f || !(f->_flags & _FILE_WRITE)) return EOF; + unsigned char ch = (unsigned char)c; + ssize_t r = write(f->_fd, &ch, 1); + if (r != 1) { f->_err = 1; return EOF; } + return (unsigned char)c; +} +int fputs(const char *s, FILE *f) +{ + if (!f || !s || !(f->_flags & _FILE_WRITE)) return EOF; + size_t len = strlen(s); + ssize_t r = write(f->_fd, s, len); + if (r < 0) { f->_err = 1; return EOF; } + return 0; +} +int feof(FILE *f) { return f ? f->_eof : 1; } +int ferror(FILE *f) { return f ? f->_err : 1; } + + +int vfprintf(FILE *f, const char *fmt, va_list ap) +{ + char buf[512]; + int len = vsnprintf(buf, sizeof(buf), fmt, ap); + if (len >= (int)sizeof(buf)) len = (int)sizeof(buf) - 1; + ssize_t r = write(f->_fd, buf, (size_t)len); + if (r < 0) { f->_err = 1; return -1; } + return len; +} + +int fprintf(FILE *f, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int r = vfprintf(f, fmt, ap); + va_end(ap); + return r; +} + +static int _uitoa(unsigned long v, int base, char *out) +{ + static const char _hex[] = "0123456789abcdef"; + char tmp[32]; + int len = 0; + if (v == 0) { out[0] = '0'; return 1; } + while (v) { tmp[len++] = _hex[v % (unsigned)base]; v /= (unsigned)base; } + for (int i = 0; i < len; i++) out[i] = tmp[len - 1 - i]; + return len; +} + +int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) +{ + size_t pos = 0; + char tmp[32]; + int tlen; + +#define _EMIT(c) do { if (buf && pos + 1 < size) buf[pos] = (c); pos++; } while (0) + + for (const char *p = fmt; *p; p++) { + if (*p != '%') { _EMIT(*p); continue; } + p++; + if (!*p) break; + + // width and zero-pad + char pad = ' '; + int width = 0; + int is_long = 0; + + if (*p == '0') { pad = '0'; p++; } + while (*p >= '1' && *p <= '9') { width = width * 10 + (*p - '0'); p++; } + if (*p == 'l') { is_long = 1; p++; } + + switch (*p) { + case 's': { + const char *s = va_arg(ap, const char *); + if (!s) s = "(null)"; + while (*s) _EMIT(*s++); + break; + } + case 'd': { + long val = is_long ? va_arg(ap, long) : (long)va_arg(ap, int); + if (val < 0) { _EMIT('-'); val = -val; } + tlen = _uitoa((unsigned long)val, 10, tmp); + for (int i = tlen; i < width; i++) _EMIT(pad); + for (int i = 0; i < tlen; i++) _EMIT(tmp[i]); + tlen = 0; + break; + } + case 'u': { + unsigned long val = is_long ? va_arg(ap, unsigned long) + : (unsigned long)va_arg(ap, unsigned int); + tlen = _uitoa(val, 10, tmp); + for (int i = tlen; i < width; i++) _EMIT(pad); + for (int i = 0; i < tlen; i++) _EMIT(tmp[i]); + tlen = 0; + break; + } + case 'x': { + unsigned long val = is_long ? va_arg(ap, unsigned long) + : (unsigned long)va_arg(ap, unsigned int); + tlen = _uitoa(val, 16, tmp); + for (int i = tlen; i < width; i++) _EMIT(pad); + for (int i = 0; i < tlen; i++) _EMIT(tmp[i]); + tlen = 0; + break; + } + case 'p': { + unsigned long val = (unsigned long)va_arg(ap, void *); + _EMIT('0'); _EMIT('x'); + tlen = _uitoa(val, 16, tmp); + for (int i = 0; i < tlen; i++) _EMIT(tmp[i]); + tlen = 0; + break; + } + case 'c': { + _EMIT((char)va_arg(ap, int)); + break; + } + case '%': { + _EMIT('%'); + break; + } + default: { + _EMIT('%'); + if (is_long) _EMIT('l'); + _EMIT(*p); + break; + } + } + } + + if (buf && size > 0) buf[pos < size ? pos : size - 1] = '\0'; + return (int)pos; + +#undef _EMIT +} + + +int snprintf(char *buf, size_t size, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + int r = vsnprintf(buf, size, fmt, ap); + va_end(ap); + return r; +} + +int vprintf(const char *fmt, va_list ap) { + char buf[512]; + int len = vsnprintf(buf, sizeof(buf), fmt, ap); + // clamp to actual buffer size to avoid overrun + if (len >= (int)sizeof(buf)) len = (int)sizeof(buf) - 1; + write(STDOUT_FILENO, buf, (size_t)len); + return len; +} + +int printf(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + int r = vprintf(fmt, ap); + va_end(ap); + return r; +} + +int putchar(int c) { + char ch = (char)c; + write(STDOUT_FILENO, &ch, 1); + return (unsigned char)ch; +} + +int puts(const char *s) { + write(STDOUT_FILENO, s, strlen(s)); + write(STDOUT_FILENO, "\n", 1); + return 0; +} + +void perror(const char *s) { + // "prefix: error message\n" + if (s && s[0] != '\0') { + write(STDERR_FILENO, s, strlen(s)); + write(STDERR_FILENO, ": ", 2); + } + const char *msg = strerror(errno); + write(STDERR_FILENO, msg, strlen(msg)); + write(STDERR_FILENO, "\n", 1); +} \ No newline at end of file diff --git a/src/userspace/libc/src/stdlib.c b/src/userspace/libc/src/stdlib.c new file mode 100644 index 0000000..3afff67 --- /dev/null +++ b/src/userspace/libc/src/stdlib.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include "_syscall.h" + +// bump allocator via brk +static char *_heap = NULL; + + +void *malloc(size_t n) { + if (!n) return NULL; + if (!_heap) _heap = (char *)_sc1(_SCAL_BRK, 0); + n = (n + 15) & ~(size_t)15; // align 16 + char *p = _heap, *end = _heap + n; + if ((char *)_sc1(_SCAL_BRK, (long)end) < end) { errno = ENOMEM; return NULL; } + _heap = end; + return p; +} + +void *calloc(size_t nmemb, size_t size) { + size_t total = nmemb * size; + void *p = malloc(total); + if (p) memset(p, 0, total); + return p; +} + +void *realloc(void *ptr, size_t n) { + if (!ptr) return malloc(n); + void *p = malloc(n); + if (p) memcpy(p, ptr, n); // may copy garbage if n > old size, acceptable + return p; +} + +void free(void *ptr) { (void)ptr; } // no-op with bump allocator + + +// _exit in unistd.c +extern void _exit(int status) __attribute__((noreturn)); + +void exit(int status) { _exit(status); __builtin_unreachable(); } + +void abort(void) { _exit(1); } + +long strtol(const char *s, char **end, int base) { + while (*s == ' ') s++; + int neg = (*s == '-'); if (neg || *s == '+') s++; + if (base == 0) { + if (*s == '0' && (s[1]=='x'||s[1]=='X')) { base=16; s+=2; } + else if (*s == '0') { base=8; } + else base=10; + } else if (base==16 && *s=='0' && (s[1]=='x'||s[1]=='X')) s+=2; + long v = 0; + while (*s) { + int d; + if (*s>='0'&&*s<='9') d=*s-'0'; + else if (*s>='a'&&*s<='z') d=*s-'a'+10; + else if (*s>='A'&&*s<='Z') d=*s-'A'+10; + else break; + if (d >= base) break; + v = v*base + d; s++; + } + if (end) *end = (char *)s; + return neg ? -v : v; +} + + +int atoi(const char *s) { return (int)strtol(s, NULL, 10); } +long atol(const char *s) { return strtol(s, NULL, 10); } +int abs (int x) { return x < 0 ? -x : x; } +long labs(long x) { return x < 0 ? -x : x; } diff --git a/src/userspace/libc/src/string.c b/src/userspace/libc/src/string.c new file mode 100644 index 0000000..4e2f60c --- /dev/null +++ b/src/userspace/libc/src/string.c @@ -0,0 +1,121 @@ +#include +#include +#include + +void *memcpy(void *dst, const void *src, size_t n) { + unsigned char *d = dst; const unsigned char *s = src; + for (size_t i = 0; i < n; i++) d[i] = s[i]; + return dst; +} +void *memmove(void *dst, const void *src, size_t n) { + unsigned char *d = dst; const unsigned char *s = src; + if (d < s) for (size_t i = 0; i < n; i++) d[i] = s[i]; + else for (size_t i = n; i > 0; i--) d[i-1] = s[i-1]; + return dst; +} +void *memset(void *s, int c, size_t n) { + unsigned char *p = s; + for (size_t i = 0; i < n; i++) p[i] = (unsigned char)c; + return s; +} +int memcmp(const void *a, const void *b, size_t n) { + const unsigned char *x = a, *y = b; + for (size_t i = 0; i < n; i++) + if (x[i] != y[i]) return (int)x[i] - (int)y[i]; + return 0; +} +// who designed this, shouldnt this be in stdlib.c...... + +char *strerror(int errnum) { + switch (errnum) { + case 0: return "success"; + case EPERM: return "operation not permitted"; + case ENOENT: return "no such file or directory"; + case ESRCH: return "no such process"; + case EINTR: return "interrupted system call"; + case EIO: return "i/o error"; + case EBADF: return "bad file descriptor"; + case ENOMEM: return "out of memory"; + case EACCES: return "permission denied"; + case EFAULT: return "bad address"; + case EEXIST: return "file exists"; + case ENODEV: return "no such device"; + case ENOTDIR:return "not a directory"; + case EISDIR: return "is a directory"; + case EINVAL: return "invalid argument"; + case EMFILE: return "too many open files"; + case ENOSPC: return "no space left on device"; + case EPIPE: return "broken pipe"; + case ERANGE: return "result too large"; + case ENOSYS: return "function not implemented"; + default: return "unknown error"; + } +} + +size_t strlen(const char *s) { + size_t n = 0; while (s[n]) n++; return n; +} +char *strcpy(char *dst, const char *src) { + char *r = dst; while ((*dst++ = *src++)); return r; +} +char *strncpy(char *dst, const char *src, size_t n) { + size_t i = 0; + for (; i < n && src[i]; i++) dst[i] = src[i]; + for (; i < n; i++) dst[i] = '\0'; + return dst; +} +char *strcat(char *dst, const char *src) { + char *r = dst; while (*dst) dst++; while ((*dst++ = *src++)); return r; +} +char *strncat(char *dst, const char *src, size_t n) { + char *r = dst; while (*dst) dst++; + for (size_t i = 0; i < n && src[i]; i++) *dst++ = src[i]; + *dst = '\0'; return r; +} +int strcmp(const char *a, const char *b) { + while (*a && *a == *b) { a++; b++; } + return (unsigned char)*a - (unsigned char)*b; +} +int strncmp(const char *a, const char *b, size_t n) { + for (size_t i = 0; i < n; i++) { + if (a[i] != b[i]) return (unsigned char)a[i] - (unsigned char)b[i]; + if (!a[i]) return 0; + } + return 0; +} +char *strchr(const char *s, int c) { + for (; *s; s++) if (*s == (char)c) return (char *)s; + return NULL; +} +char *strrchr(const char *s, int c) { + char *r = NULL; + for (; *s; s++) if (*s == (char)c) r = (char *)s; + return r; +} +char *strstr(const char *hay, const char *needle) { + if (!*needle) return (char *)hay; + size_t nl = strlen(needle); + for (; *hay; hay++) + if (*hay == *needle && strncmp(hay, needle, nl) == 0) + return (char *)hay; + return NULL; +} + +static char *_tok; +char *strtok(char *s, const char *delim) { + if (s) _tok = s; + if (!_tok) return NULL; + while (*_tok && strchr(delim, *_tok)) _tok++; + if (!*_tok) { _tok = NULL; return NULL; } + char *tok = _tok; + while (*_tok && !strchr(delim, *_tok)) _tok++; + if (*_tok) *_tok++ = '\0'; else _tok = NULL; + return tok; +} + +char *strdup(const char *s) { + size_t n = strlen(s) + 1; + char *p = malloc(n); + if (p) memcpy(p, s, n); + return p; +} diff --git a/src/userspace/libc/src/system.c b/src/userspace/libc/src/system.c new file mode 100644 index 0000000..8d59f93 --- /dev/null +++ b/src/userspace/libc/src/system.c @@ -0,0 +1,16 @@ +#include +#include "_syscall.h" + +int reboot(unsigned long cmd) { + long r; + __asm__ volatile( + "syscall" + : "=a"(r) + : "a"((long)_SCAL_REBOOT), + "D"((long)RSYSTEM_MAGIC1), + "S"((long)RSYSTEM_MAGIC2), + "d"((long)cmd) + : "rcx", "r11", "memory" + ); + return (int)r; +} diff --git a/src/userspace/libc/src/unistd.c b/src/userspace/libc/src/unistd.c new file mode 100644 index 0000000..2dd0791 --- /dev/null +++ b/src/userspace/libc/src/unistd.c @@ -0,0 +1,47 @@ +#include +#include "_syscall.h" + +// no errno access + +ssize_t read(int fd, void *buf, size_t n) { + return (ssize_t)_sc3(_SCAL_READ, fd, (long)buf, (long)n); +} + +ssize_t write(int fd, const void *buf, size_t n) { + return (ssize_t)_sc3(_SCAL_WRITE, fd, (long)buf, (long)n); +} + +pid_t getpid(void) { + return (pid_t)_sc1(_SCAL_GETPID, 0); +} + +pid_t fork(void) { + return (pid_t)_sc0(_SCAL_FORK); +} + +void _exit(int status) { + _sc1(_SCAL_EXIT, status); + __builtin_unreachable(); +} + +int execve(const char *path, char *const argv[], char *const envp[]) { + (void)envp; + return (int)_sc2(_SCAL_EXECVE, (long)path, (long)argv); +} + +int chdir(const char *path) { + return (int)_sc1(_SCAL_CHDIR, (long)path); +} + +int mkdir(const char *path) { + return (int)_sc1(_SCAL_MKDIR, (long)path); +} + +int unlink(const char *path) { + return (int)_sc1(_SCAL_UNLINK, (long)path); +} + +char *getcwd(char *buf, size_t size) { + long r = _sc2(_SCAL_GETCWD, (long)buf, (long)size); + return (r > 0) ? buf : NULL; +} diff --git a/src/userspace/user.ld b/src/userspace/user.ld index daea53d..21726ea 100644 --- a/src/userspace/user.ld +++ b/src/userspace/user.ld @@ -2,15 +2,17 @@ OUTPUT_FORMAT(elf64-x86-64) OUTPUT_ARCH(i386:x86-64) ENTRY(_start) +/* force one single PT_LOAD segment (RWX) so the emex loader doesnt miss .rodata/.data which would otherwise end up +* in separate segments the loader never processes +*/ +PHDRS { load PT_LOAD FLAGS(7); } + SECTIONS { . = 0x40000000; - .text : { - *(.text._start) - *(.text*) - } - .rodata : { *(.rodata*) } - .data : { *(.data*) } - .bss : { *(.bss*) *(COMMON) } + .text : { *(.text._start) *(.text*) } :load + .rodata : { *(.rodata*) } :load + .data : { *(.data*) } :load + .bss : { *(.bss*) *(COMMON) } :load /DISCARD/ : { *(.eh_frame) *(.note*) *(.comment) } } diff --git a/tools/initrd.sh b/tools/initrd.sh new file mode 100755 index 0000000..e23adcf --- /dev/null +++ b/tools/initrd.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -euo pipefail + + +SRC="./dsk/rd" +OUT="./dsk/initrd.cpio" + + +if [ ! -d "$SRC" ]; then + echo "error: $SRC not found" + exit 1 +fi + + +# pick cpio binaryv +CPIO="cpio" +if [ "$(uname -s)" = "Darwin" ] && command -v gcpio &>/dev/null; then + CPIO="gcpio" # on macos just install it with brew install cpio +fi + +( + cd "$SRC" + # -H newc = header is newc (the kernel only supports newc now) + # -R 0:0 = force uid/gid 0 + find . \ + \( -name ".DS_Store" \ + -o -name "._*" \ + -o -name ".Spotlight-V100" \ + -o -name ".Trashes" \ + -o -name ".fseventsd" \ + -o -name ".TemporaryItems" \ + -o -name ".VolumeIcon.icns" \ + -o -name ".AppleDouble" \) -prune -o -print \ + | sort | "$CPIO" -o -H newc -R 0:0 +) > "$OUT" + +echo "done: $OUT ($(wc -c < "$OUT" | tr -d ' ') bytes)"