Compare commits
136 Commits
26.4-stabl
...
26.5.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b04bde3d9e | ||
|
|
d854d0e50f | ||
|
|
5b7940dd04 | ||
|
|
b486bb2ca5 | ||
|
|
7ae1d40e41 | ||
|
|
9ec4695df1 | ||
|
|
a43465e3d3 | ||
|
|
39088c7e8e | ||
|
|
5ff52b430d | ||
|
|
8d0e744991 | ||
|
|
7a480b44b9 | ||
|
|
836c20de8a | ||
|
|
d1a6eb8985 | ||
|
|
c11d4a8a00 | ||
|
|
81ea21e746 | ||
|
|
8006a83449 | ||
|
|
915e33434e | ||
|
|
228b5753d9 | ||
|
|
eb19e37d91 | ||
|
|
35ee3fec21 | ||
|
|
85d1dc0991 | ||
|
|
4d1e619d7a | ||
|
|
5f1a564d29 | ||
|
|
5af02da5a1 | ||
|
|
bbc5a44982 | ||
|
|
206cca7e28 | ||
|
|
034aab48d3 | ||
|
|
987a96e2e8 | ||
|
|
3893276974 | ||
|
|
67f27a908f | ||
|
|
9988a6e420 | ||
|
|
c1411e378a | ||
|
|
db4862c2d0 | ||
|
|
c3d1f44dfd | ||
|
|
9c600caf45 | ||
|
|
2498045362 | ||
|
|
8d51238a3d | ||
|
|
d14000b7eb | ||
|
|
054c802ad0 | ||
|
|
1634b621cf | ||
|
|
a1c06fdd08 | ||
|
|
ee4ce4039c | ||
|
|
0a7d1f1ee7 | ||
|
|
5ee006f736 | ||
|
|
840c0a0be4 | ||
|
|
b865023dc2 | ||
|
|
ef32527733 | ||
|
|
f2753c0d57 | ||
|
|
51e26758ee | ||
|
|
75b262c767 | ||
|
|
016f6dad15 | ||
|
|
65d5fc974f | ||
|
|
750880dcb5 | ||
|
|
0e32f35d91 | ||
|
|
f8ca9d9d91 | ||
|
|
af5eda1647 | ||
|
|
ae8c7e21ac | ||
|
|
7d66d9b439 | ||
|
|
b1f45b90cd | ||
|
|
4280c3a802 | ||
|
|
78ae0f154d | ||
|
|
f788ba416d | ||
|
|
8ab28661a1 | ||
|
|
6e85adb000 | ||
|
|
5be803e4d4 | ||
|
|
992aad52e5 | ||
|
|
75c3e4c27a | ||
|
|
4fc48eab73 | ||
|
|
ecaa5f60f7 | ||
|
|
75278b9a27 | ||
|
|
baa52da4c0 | ||
|
|
f6b6fd97ce | ||
|
|
b419de43f0 | ||
|
|
6d999fdaa3 | ||
|
|
01aa75a4f1 | ||
|
|
e1864b2a66 | ||
|
|
d4b066c29f | ||
|
|
3eafa5b360 | ||
|
|
8ea457694d | ||
|
|
fb00bbac2b | ||
|
|
89140d7546 | ||
|
|
9357f82d17 | ||
|
|
d00eed4e13 | ||
|
|
0a8f913045 | ||
|
|
15a7465019 | ||
|
|
c4562e8778 | ||
|
|
e738041020 | ||
|
|
9830b6ad96 | ||
|
|
a09103e40d | ||
|
|
aff3e99ab2 | ||
|
|
93bf2e1734 | ||
|
|
eaa02c9a5d | ||
|
|
0ad151d7fc | ||
|
|
b54e371f3f | ||
|
|
79eeaa73d9 | ||
|
|
481eb42268 | ||
|
|
feb0d6ffbf | ||
|
|
67ebcb98d1 | ||
|
|
957c74365c | ||
|
|
31b6f48a2c | ||
|
|
67b7bb1a97 | ||
|
|
e05ff65f92 | ||
|
|
40f63097e1 | ||
|
|
d677d37b1c | ||
|
|
9b6297c917 | ||
|
|
dd6cbf1fe0 | ||
|
|
7e123b6429 | ||
|
|
4177484366 | ||
|
|
8dc5ee5867 | ||
|
|
884c2f8980 | ||
|
|
36d61e3b7b | ||
|
|
013f0b513f | ||
|
|
28108adde3 | ||
|
|
62ac2ab849 | ||
|
|
7f510c6aa5 | ||
|
|
7116de4152 | ||
|
|
049d67e821 | ||
|
|
0f3971bb1c | ||
|
|
66f55242a7 | ||
|
|
8a8fb7de27 | ||
|
|
914c60e1f1 | ||
|
|
5141eaea60 | ||
|
|
6e90c3e197 | ||
|
|
bdd43f43cd | ||
|
|
a8866da3cb | ||
|
|
14decdd705 | ||
|
|
ed73b88ec1 | ||
|
|
f9bc6c7c38 | ||
|
|
bb187faf79 | ||
|
|
fd7fa4f16e | ||
|
|
5bd9e537c5 | ||
|
|
e4603792b6 | ||
|
|
a27b2c6423 | ||
|
|
bb176f2193 | ||
|
|
8dd756f25b | ||
|
|
d13fca2d4a |
62
.github/workflows/nightly.yml
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
name: Nightly Build
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
build-and-release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
make \
|
||||
gcc-x86-64-linux-gnu \
|
||||
binutils-x86-64-linux-gnu \
|
||||
nasm \
|
||||
xorriso
|
||||
sudo ln -sf /usr/bin/x86_64-linux-gnu-gcc /usr/local/bin/x86_64-elf-gcc
|
||||
sudo ln -sf /usr/bin/x86_64-linux-gnu-ld /usr/local/bin/x86_64-elf-ld
|
||||
|
||||
- name: Build ISO
|
||||
run: make -j4
|
||||
|
||||
- name: Update nightly tag
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git tag -fa nightly -m "Nightly build ${GITHUB_SHA}" "${GITHUB_SHA}"
|
||||
git push origin refs/tags/nightly --force
|
||||
|
||||
- name: Prepare release metadata
|
||||
id: metadata
|
||||
run: |
|
||||
echo "short_sha=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Publish nightly release asset
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: nightly
|
||||
name: Nightly Build (${{ steps.metadata.outputs.short_sha }})
|
||||
body: |
|
||||
This is an automated nightly build of BoredOS, this is not a final release and may be unstable.
|
||||
|
||||
Built from commit:
|
||||
- Full hash: `${{ github.sha }}`
|
||||
- Short hash: `${{ steps.metadata.outputs.short_sha }}`
|
||||
prerelease: true
|
||||
make_latest: false
|
||||
files: |
|
||||
boredos.iso
|
||||
overwrite_files: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
196
Makefile
@@ -17,35 +17,59 @@ ISO_DIR = iso_root
|
||||
KERNEL_ELF = $(BUILD_DIR)/boredos.elf
|
||||
ISO_IMAGE = boredos.iso
|
||||
|
||||
BLUE = \033[1;34m
|
||||
GREEN = \033[1;32m
|
||||
YELLOW= \033[1;33m
|
||||
RESET = \033[0m
|
||||
|
||||
define PRINT_STEP
|
||||
@printf ""
|
||||
@printf "\n$(BLUE)============================================================$(RESET)\n"
|
||||
@printf "$(BLUE)== %s$(RESET)\n" "$(1)"
|
||||
@printf "$(BLUE)============================================================$(RESET)\n"
|
||||
endef
|
||||
|
||||
DOCK_COLLOID_ICONS = $(shell sed -n 's/^[[:space:]]*{"\([^"]*\.png\)",[[:space:]]*DOCK_ICON_UNTRIED.*/\1/p' $(SRC_DIR)/wm/wm.c)
|
||||
USERLAND_COLLOID_ICONS = $(shell { \
|
||||
find $(SRC_DIR)/userland -type f -name '*.c' ! -path '*/third_party/*' -exec grep -hoE '"[^"]+\.png"' {} + 2>/dev/null; \
|
||||
find $(SRC_DIR)/userland -type f -name '*.h' ! -path '*/third_party/*' ! -name 'stb_image.h' -exec grep -hoE '"[^"]+\.png"' {} + 2>/dev/null; \
|
||||
} | sed 's/"//g' | sed 's@.*/@@' | sort -u)
|
||||
USERLAND_METADATA_ICONS = $(shell { \
|
||||
find $(SRC_DIR)/userland -type f -name '*.c' -exec sed -n 's@^[[:space:]]*//[[:space:]]*BOREDOS_APP_ICONS:[[:space:]]*@@p' {} + 2>/dev/null; \
|
||||
} | tr ';' '\n' | sed 's@.*/@@' | sed '/^[[:space:]]*$$/d' | sort -u)
|
||||
COLLOID_ICONS = $(sort $(DOCK_COLLOID_ICONS) $(USERLAND_COLLOID_ICONS) $(USERLAND_METADATA_ICONS) xterm.png)
|
||||
|
||||
C_SOURCES = $(wildcard $(SRC_DIR)/core/*.c) \
|
||||
$(wildcard $(SRC_DIR)/sys/*.c) \
|
||||
$(wildcard $(SRC_DIR)/mem/*.c) \
|
||||
$(wildcard $(SRC_DIR)/dev/*.c) \
|
||||
$(wildcard $(SRC_DIR)/input/*.c) \
|
||||
$(wildcard $(SRC_DIR)/net/*.c) \
|
||||
$(wildcard $(SRC_DIR)/net/nic/*.c) \
|
||||
$(wildcard $(SRC_DIR)/fs/*.c) \
|
||||
$(wildcard $(SRC_DIR)/wm/*.c) \
|
||||
$(wildcard $(SRC_DIR)/net/lwip/core/*.c) \
|
||||
$(wildcard $(SRC_DIR)/net/lwip/core/ipv4/*.c) \
|
||||
$(SRC_DIR)/net/lwip/netif/ethernet.c \
|
||||
$(SRC_DIR)/net/lwip/netif/bridgeif.c
|
||||
$(wildcard $(SRC_DIR)/net/third_party/lwip/core/*.c) \
|
||||
$(wildcard $(SRC_DIR)/net/third_party/lwip/core/ipv4/*.c) \
|
||||
$(SRC_DIR)/net/third_party/lwip/netif/ethernet.c \
|
||||
$(SRC_DIR)/net/third_party/lwip/netif/bridgeif.c
|
||||
|
||||
ASM_SOURCES = $(wildcard $(SRC_DIR)/arch/*.asm)
|
||||
OBJ_FILES = $(patsubst $(SRC_DIR)/core/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/core/*.c)) \
|
||||
$(patsubst $(SRC_DIR)/sys/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/sys/*.c)) \
|
||||
$(patsubst $(SRC_DIR)/mem/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/mem/*.c)) \
|
||||
$(patsubst $(SRC_DIR)/dev/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/dev/*.c)) \
|
||||
$(patsubst $(SRC_DIR)/input/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/input/*.c)) \
|
||||
$(patsubst $(SRC_DIR)/net/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/net/*.c)) \
|
||||
$(patsubst $(SRC_DIR)/net/nic/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/net/nic/*.c)) \
|
||||
$(patsubst $(SRC_DIR)/fs/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/fs/*.c)) \
|
||||
$(patsubst $(SRC_DIR)/wm/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/wm/*.c)) \
|
||||
$(patsubst $(SRC_DIR)/net/lwip/%.c, $(BUILD_DIR)/lwip/%.o, $(filter $(SRC_DIR)/net/lwip/%.c, $(C_SOURCES))) \
|
||||
$(patsubst $(SRC_DIR)/net/third_party/lwip/%.c, $(BUILD_DIR)/lwip/%.o, $(filter $(SRC_DIR)/net/third_party/lwip/%.c, $(C_SOURCES))) \
|
||||
$(patsubst $(SRC_DIR)/arch/%.asm, $(BUILD_DIR)/%.o, $(ASM_SOURCES))
|
||||
|
||||
CFLAGS = -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding \
|
||||
-fno-stack-protector -fno-stack-check -fno-lto -fPIE \
|
||||
-m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone \
|
||||
-I$(SRC_DIR) -I$(SRC_DIR)/net/lwip -I$(SRC_DIR)/core -I$(SRC_DIR)/sys -I$(SRC_DIR)/mem -I$(SRC_DIR)/dev -I$(SRC_DIR)/net -I$(SRC_DIR)/net/nic -I$(SRC_DIR)/fs -I$(SRC_DIR)/wm
|
||||
-I$(SRC_DIR) -I$(SRC_DIR)/net/third_party/lwip -I$(SRC_DIR)/core -I$(SRC_DIR)/sys -I$(SRC_DIR)/mem -I$(SRC_DIR)/dev -I$(SRC_DIR)/net -I$(SRC_DIR)/net/nic -I$(SRC_DIR)/fs -I$(SRC_DIR)/wm -I$(SRC_DIR)/input
|
||||
|
||||
LDFLAGS = -m elf_x86_64 -nostdlib -static -pie --no-dynamic-linker \
|
||||
-z text -z max-page-size=0x1000 -T linker.ld
|
||||
@@ -55,158 +79,282 @@ NASMFLAGS = -f elf64
|
||||
LIMINE_VERSION = 10.8.2
|
||||
LIMINE_URL_BASE = https://github.com/limine-bootloader/limine/raw/v$(LIMINE_VERSION)
|
||||
|
||||
.PHONY: all clean run limine-setup
|
||||
.PHONY: all clean run limine-setup run-windows run-mac run-linux
|
||||
|
||||
all: $(ISO_IMAGE)
|
||||
all:
|
||||
$(call PRINT_STEP,STARTING BOREDOS BUILD)
|
||||
$(MAKE) $(ISO_IMAGE)
|
||||
$(call PRINT_STEP,BUILD COMPLETE)
|
||||
|
||||
$(BUILD_DIR):
|
||||
$(call PRINT_STEP,CREATING BUILD DIRECTORY)
|
||||
mkdir -p $(BUILD_DIR)
|
||||
mkdir -p $(BUILD_DIR)
|
||||
|
||||
limine-setup:
|
||||
$(call PRINT_STEP,SETTING UP LIMINE)
|
||||
@if [ ! -f limine/limine-bios.sys ]; then \
|
||||
echo "Limine binaries missing or invalid. Cloning v$(LIMINE_VERSION)-binary..."; \
|
||||
printf "$(YELLOW)[LIMINE] Limine binaries missing or invalid. Cloning v$(LIMINE_VERSION)-binary...$(RESET)"; \
|
||||
rm -rf limine; \
|
||||
git clone https://github.com/limine-bootloader/limine.git --branch=v$(LIMINE_VERSION)-binary --depth=1 limine; \
|
||||
else \
|
||||
printf "$(YELLOW)[LIMINE] Existing Limine binaries found.$(RESET)"; \
|
||||
fi
|
||||
@if [ ! -f $(SRC_DIR)/core/limine.h ]; then \
|
||||
echo "Copying limine.h..."; \
|
||||
printf "$(YELLOW)[LIMINE] Copying limine.h...$(RESET)"; \
|
||||
cp limine/limine.h $(SRC_DIR)/core/limine.h; \
|
||||
else \
|
||||
printf "$(YELLOW)[LIMINE] limine.h already present.$(RESET)"; \
|
||||
fi
|
||||
@echo "Building Limine host utility..."; \
|
||||
@printf "$(YELLOW)[LIMINE] Building Limine host utility...$(RESET)"
|
||||
$(MAKE) -C limine
|
||||
@printf "$(GREEN)[OK] Limine setup complete.$(RESET)"
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c | $(BUILD_DIR) limine-setup
|
||||
@printf "$(YELLOW)[CC]$(RESET) $< -> $@"
|
||||
mkdir -p $(dir $@)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/core/%.c | $(BUILD_DIR) limine-setup
|
||||
@printf "$(YELLOW)[CC]$(RESET)[core] $< -> $@"
|
||||
mkdir -p $(dir $@)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/sys/%.c | $(BUILD_DIR) limine-setup
|
||||
@printf "$(YELLOW)[CC]$(RESET)[sys] $< -> $@"
|
||||
mkdir -p $(dir $@)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/mem/%.c | $(BUILD_DIR) limine-setup
|
||||
@printf "$(YELLOW)[CC]$(RESET)[mem] $< -> $@"
|
||||
mkdir -p $(dir $@)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/dev/%.c | $(BUILD_DIR) limine-setup
|
||||
@printf "$(YELLOW)[CC]$(RESET)[dev] $< -> $@"
|
||||
mkdir -p $(dir $@)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/input/%.c | $(BUILD_DIR) limine-setup
|
||||
@printf "$(YELLOW)[CC]$(RESET)[input] $< -> $@"
|
||||
mkdir -p $(dir $@)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/net/%.c | $(BUILD_DIR) limine-setup
|
||||
@printf "$(YELLOW)[CC]$(RESET)[net] $< -> $@"
|
||||
mkdir -p $(dir $@)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/net/nic/%.c | $(BUILD_DIR) limine-setup
|
||||
@printf "$(YELLOW)[CC]$(RESET)[net/nic] $< -> $@"
|
||||
mkdir -p $(dir $@)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/fs/%.c | $(BUILD_DIR) limine-setup
|
||||
@printf "$(YELLOW)[CC]$(RESET)[fs] $< -> $@"
|
||||
mkdir -p $(dir $@)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/wm/%.c | $(BUILD_DIR) limine-setup
|
||||
@printf "$(YELLOW)[CC]$(RESET)[wm] $< -> $@"
|
||||
mkdir -p $(dir $@)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BUILD_DIR)/lwip/%.o: $(SRC_DIR)/net/lwip/%.c | $(BUILD_DIR) limine-setup
|
||||
$(BUILD_DIR)/lwip/%.o: $(SRC_DIR)/net/third_party/lwip/%.c | $(BUILD_DIR) limine-setup
|
||||
@printf "$(YELLOW)[CC]$(RESET)[lwIP] $< -> $@"
|
||||
mkdir -p $(dir $@)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/arch/%.asm | $(BUILD_DIR)
|
||||
@printf "$(YELLOW)[ASM]$(RESET) $< -> $@"
|
||||
$(NASM) $(NASMFLAGS) $< -o $@
|
||||
|
||||
$(BUILD_DIR)/test_syscall.o: $(SRC_DIR)/arch/test_syscall.asm | $(BUILD_DIR)
|
||||
@printf "$(YELLOW)[ASM][test_syscall]$(RESET) $< -> $@"
|
||||
$(NASM) $(NASMFLAGS) $< -o $@
|
||||
|
||||
$(BUILD_DIR)/user_test.o: $(SRC_DIR)/arch/user_test.asm | $(BUILD_DIR)
|
||||
@printf "$(YELLOW)[ASM][user_test]$(RESET) $< -> $@"
|
||||
$(NASM) $(NASMFLAGS) $< -o $@
|
||||
|
||||
$(BUILD_DIR)/process_asm.o: $(SRC_DIR)/arch/process_asm.asm | $(BUILD_DIR)
|
||||
@printf "$(YELLOW)[ASM][process]$(RESET) $< -> $@"
|
||||
$(NASM) $(NASMFLAGS) $< -o $@
|
||||
|
||||
$(KERNEL_ELF): $(OBJ_FILES)
|
||||
$(call PRINT_STEP,LINKING KERNEL)
|
||||
@printf "$(YELLOW)[LD]$(RESET) Linking kernel ELF: $@"
|
||||
$(LD) $(LDFLAGS) -o $@ $(OBJ_FILES)
|
||||
@printf "$(GREEN)[OK]$(RESET) Kernel ELF built: $@"
|
||||
$(call PRINT_STEP,BUILDING USERLAND)
|
||||
$(MAKE) -C $(SRC_DIR)/userland
|
||||
@printf "$(GREEN)[OK]$(RESET) Userland build complete."
|
||||
|
||||
$(BUILD_DIR)/initrd.tar: $(KERNEL_ELF)
|
||||
$(call PRINT_STEP,BUILDING INITRD)
|
||||
@printf "$(YELLOW)[INITRD]$(RESET) Cleaning previous initrd directory..."
|
||||
rm -rf $(BUILD_DIR)/initrd
|
||||
|
||||
@printf "$(YELLOW)[INITRD]$(RESET) Creating directory structure..."
|
||||
mkdir -p $(BUILD_DIR)/initrd/bin
|
||||
mkdir -p $(BUILD_DIR)/initrd/Library/images/Wallpapers
|
||||
mkdir -p $(BUILD_DIR)/initrd/Library/images/gif
|
||||
mkdir -p $(BUILD_DIR)/initrd/Library/images/icons/colloid
|
||||
mkdir -p $(BUILD_DIR)/initrd/Library/Fonts/Emoji
|
||||
mkdir -p $(BUILD_DIR)/initrd/Library/DOOM
|
||||
mkdir -p $(BUILD_DIR)/initrd/Library/bsh
|
||||
mkdir -p $(BUILD_DIR)/initrd/docs
|
||||
|
||||
@printf "$(YELLOW)[COPY]$(RESET) Userland binaries..."
|
||||
@for f in $(SRC_DIR)/userland/bin/*.elf; do \
|
||||
if [ -f "$$f" ]; then cp "$$f" $(BUILD_DIR)/initrd/bin/; fi \
|
||||
if [ -f "$$f" ]; then \
|
||||
printf " -> $$f"; \
|
||||
cp "$$f" $(BUILD_DIR)/initrd/bin/; \
|
||||
fi \
|
||||
done
|
||||
|
||||
@printf "$(YELLOW)[COPY]$(RESET) Wallpapers..."
|
||||
@for f in $(SRC_DIR)/images/wallpapers/*; do \
|
||||
if [ -f "$$f" ]; then cp "$$f" $(BUILD_DIR)/initrd/Library/images/Wallpapers/; fi \
|
||||
if [ -f "$$f" ]; then \
|
||||
printf " -> $$f"; \
|
||||
cp "$$f" $(BUILD_DIR)/initrd/Library/images/Wallpapers/; \
|
||||
fi \
|
||||
done
|
||||
|
||||
@printf "$(YELLOW)[COPY]$(RESET) GIF assets..."
|
||||
@for f in $(SRC_DIR)/images/gif/*.gif; do \
|
||||
if [ -f "$$f" ]; then cp "$$f" $(BUILD_DIR)/initrd/Library/images/gif/; fi \
|
||||
if [ -f "$$f" ]; then \
|
||||
printf " -> $$f"; \
|
||||
cp "$$f" $(BUILD_DIR)/initrd/Library/images/gif/; \
|
||||
fi \
|
||||
done
|
||||
|
||||
@printf "$(YELLOW)[COPY]$(RESET) Colloid icons..."
|
||||
@for f in $(COLLOID_ICONS); do \
|
||||
src="$(SRC_DIR)/images/icons/colloid/$$f"; \
|
||||
if [ -f "$$src" ]; then \
|
||||
printf " -> $$src"; \
|
||||
cp "$$src" $(BUILD_DIR)/initrd/Library/images/icons/colloid/; \
|
||||
fi \
|
||||
done
|
||||
|
||||
@printf "$(YELLOW)[COPY]$(RESET) Fonts..."
|
||||
@for f in $(SRC_DIR)/fonts/*.ttf; do \
|
||||
if [ -f "$$f" ]; then cp "$$f" $(BUILD_DIR)/initrd/Library/Fonts/; fi \
|
||||
if [ -f "$$f" ]; then \
|
||||
printf " -> $$f"; \
|
||||
cp "$$f" $(BUILD_DIR)/initrd/Library/Fonts/; \
|
||||
fi \
|
||||
done
|
||||
|
||||
@printf "$(YELLOW)[COPY]$(RESET) Emoji fonts..."
|
||||
@for f in $(SRC_DIR)/fonts/Emoji/*.ttf; do \
|
||||
if [ -f "$$f" ]; then cp "$$f" $(BUILD_DIR)/initrd/Library/Fonts/Emoji/; fi \
|
||||
if [ -f "$$f" ]; then \
|
||||
printf " -> $$f"; \
|
||||
cp "$$f" $(BUILD_DIR)/initrd/Library/Fonts/Emoji/; \
|
||||
fi \
|
||||
done
|
||||
@if [ -f $(SRC_DIR)/userland/games/doom/doom1.wad ]; then cp $(SRC_DIR)/userland/games/doom/doom1.wad $(BUILD_DIR)/initrd/Library/DOOM/; fi
|
||||
|
||||
@printf "$(YELLOW)[COPY]$(RESET) bsh configuration..."
|
||||
@if [ -f $(SRC_DIR)/library/bsh/bshrc ]; then printf " -> bshrc"; cp $(SRC_DIR)/library/bsh/bshrc $(BUILD_DIR)/initrd/Library/bsh/; fi
|
||||
@if [ -f $(SRC_DIR)/library/bsh/startup.bsh ]; then printf " -> startup.bsh"; cp $(SRC_DIR)/library/bsh/startup.bsh $(BUILD_DIR)/initrd/Library/bsh/; fi
|
||||
@if [ -f $(SRC_DIR)/library/bsh/boot.bsh ]; then printf " -> boot.bsh"; cp $(SRC_DIR)/library/bsh/boot.bsh $(BUILD_DIR)/initrd/Library/bsh/; fi
|
||||
|
||||
@printf "$(YELLOW)[COPY]$(RESET) DOOM assets..."
|
||||
@if [ -f $(SRC_DIR)/userland/games/doom/doom1.wad ]; then printf " -> doom1.wad"; cp $(SRC_DIR)/userland/games/doom/doom1.wad $(BUILD_DIR)/initrd/Library/DOOM/; fi
|
||||
|
||||
@printf "$(YELLOW)[COPY]$(RESET) Documentation..."
|
||||
@for f in $$(find docs -name '*.md' 2>/dev/null); do \
|
||||
if [ -f "$$f" ]; then \
|
||||
printf " -> $$f"; \
|
||||
dir=$$(dirname "$$f"); \
|
||||
mkdir -p $(BUILD_DIR)/initrd/"$$dir"; \
|
||||
cp "$$f" $(BUILD_DIR)/initrd/"$$dir"/; \
|
||||
fi \
|
||||
done
|
||||
@if [ -f README.md ]; then cp README.md $(BUILD_DIR)/initrd/; fi
|
||||
@if [ -f LICENSE ]; then cp LICENSE $(BUILD_DIR)/initrd/; fi
|
||||
|
||||
@printf "$(YELLOW)[COPY]$(RESET) Root files..."
|
||||
@if [ -f README.md ]; then printf " -> README.md"; cp README.md $(BUILD_DIR)/initrd/; fi
|
||||
@if [ -f LICENSE ]; then printf " -> LICENSE"; cp LICENSE $(BUILD_DIR)/initrd/; fi
|
||||
@if [ -f limine.conf ]; then printf " -> limine.conf"; cp limine.conf $(BUILD_DIR)/initrd/; fi
|
||||
|
||||
@printf "$(YELLOW)[TAR]$(RESET) Creating initrd.tar..."
|
||||
cd $(BUILD_DIR)/initrd && COPYFILE_DISABLE=1 tar --exclude="._*" -cf ../initrd.tar *
|
||||
@printf "$(GREEN)[OK]$(RESET) Initrd created: $(BUILD_DIR)/initrd.tar"
|
||||
|
||||
$(ISO_IMAGE): $(KERNEL_ELF) $(BUILD_DIR)/initrd.tar limine.conf limine-setup
|
||||
$(call PRINT_STEP,CREATING ISO IMAGE)
|
||||
@printf "$(YELLOW)[ISO]$(RESET) Cleaning previous ISO root..."
|
||||
rm -rf $(ISO_DIR)
|
||||
|
||||
@printf "$(YELLOW)[ISO]$(RESET) Creating ISO directory structure..."
|
||||
mkdir -p $(ISO_DIR)
|
||||
mkdir -p $(ISO_DIR)/EFI/BOOT
|
||||
|
||||
@printf "$(YELLOW)[COPY]$(RESET) Kernel ELF..."
|
||||
cp $(KERNEL_ELF) $(ISO_DIR)/
|
||||
|
||||
@printf "$(YELLOW)[COPY]$(RESET) Limine config..."
|
||||
cp limine.conf $(ISO_DIR)/
|
||||
|
||||
@printf "$(YELLOW)[COPY]$(RESET) Initrd..."
|
||||
cp $(BUILD_DIR)/initrd.tar $(ISO_DIR)/
|
||||
echo " module_path: boot():/initrd.tar" >> $(ISO_DIR)/limine.conf
|
||||
|
||||
@if [ -f splash.jpg ]; then cp splash.jpg $(ISO_DIR)/; fi
|
||||
@printf "$(YELLOW)[CONFIG]$(RESET) Adding initrd module path..."
|
||||
printf " module_path: boot():/initrd.tar" >> $(ISO_DIR)/limine.conf
|
||||
|
||||
@printf "$(YELLOW)[COPY]$(RESET) Optional splash image..."
|
||||
@if [ -f splash.jpg ]; then printf " -> splash.jpg"; cp splash.jpg $(ISO_DIR)/; else printf " -> no splash.jpg found"; fi
|
||||
|
||||
@printf "$(YELLOW)[COPY]$(RESET) Limine boot files..."
|
||||
cp limine/limine-bios.sys $(ISO_DIR)/
|
||||
cp limine/limine-bios-cd.bin $(ISO_DIR)/
|
||||
cp limine/limine-uefi-cd.bin $(ISO_DIR)/
|
||||
|
||||
@printf "$(YELLOW)[COPY]$(RESET) EFI bootloaders..."
|
||||
cp limine/BOOTX64.EFI $(ISO_DIR)/EFI/BOOT/
|
||||
cp limine/BOOTIA32.EFI $(ISO_DIR)/EFI/BOOT/
|
||||
|
||||
$(call PRINT_STEP,GENERATING BOOTABLE ISO)
|
||||
$(XORRISO) -as mkisofs -R -J -b limine-bios-cd.bin \
|
||||
-no-emul-boot -boot-load-size 4 -boot-info-table \
|
||||
--efi-boot limine-uefi-cd.bin \
|
||||
-efi-boot-part --efi-boot-image --protective-msdos-label \
|
||||
$(ISO_DIR) -o $(ISO_IMAGE)
|
||||
|
||||
@printf "$(YELLOW)[LIMINE]$(RESET) Installing BIOS bootloader..."
|
||||
./limine/limine bios-install $(ISO_IMAGE)
|
||||
@printf "$(GREEN)[OK]$(RESET) ISO image ready: $(ISO_IMAGE)"
|
||||
|
||||
clean:
|
||||
$(call PRINT_STEP,CLEANING BUILD OUTPUT)
|
||||
rm -rf $(BUILD_DIR) $(ISO_DIR) $(ISO_IMAGE)
|
||||
$(MAKE) -C $(SRC_DIR)/userland clean
|
||||
@printf "$(GREEN)[OK]$(RESET) Clean complete."
|
||||
|
||||
run: $(ISO_IMAGE)
|
||||
run-windows: $(ISO_IMAGE)
|
||||
$(call PRINT_STEP,RUNNING BOREDOS IN QEMU ON WINDOWS)
|
||||
qemu-system-x86_64 -m 4G -serial stdio -cdrom $< -boot d \
|
||||
-smp 4 \
|
||||
-audiodev dsound,id=audio0 -machine pcspk-audiodev=audio0 \
|
||||
-vga std -global VGA.xres=1920 -global VGA.yres=1080 \
|
||||
-drive file=disk.img,format=raw,file.locking=off
|
||||
|
||||
run-mac: $(ISO_IMAGE)
|
||||
$(call PRINT_STEP,RUNNING BOREDOS IN QEMU ON MACOS)
|
||||
qemu-system-x86_64 -m 4G -serial stdio -cdrom $< -boot d \
|
||||
-smp 4 \
|
||||
-audiodev coreaudio,id=audio0 -machine pcspk-audiodev=audio0 \
|
||||
-netdev user,id=net0,hostfwd=udp::12346-:12345 -device virtio-net-pci,netdev=net0 \
|
||||
-vga std -global VGA.xres=1920 -global VGA.yres=1080 \
|
||||
-display cocoa,show-cursor=off \
|
||||
-drive file=disk.img,format=raw,file.locking=off \
|
||||
-cpu max
|
||||
|
||||
run-linux: $(ISO_IMAGE)
|
||||
$(call PRINT_STEP,RUNNING BOREDOS IN QEMU ON LINUX)
|
||||
qemu-system-x86_64 -m 4G -serial stdio -cdrom $< -boot d \
|
||||
-smp 4 \
|
||||
-audiodev pa,id=audio0 -machine pcspk-audiodev=audio0 \
|
||||
-vga std -global VGA.xres=1920 -global VGA.yres=1080 \
|
||||
-display gtk,show-cursor=off \
|
||||
-drive file=disk.img,format=raw,file.locking=off \
|
||||
-cpu max
|
||||
|
||||
154
POLICY.md
Normal file
@@ -0,0 +1,154 @@
|
||||
# BoredOS — Usage Policy & Legal Notice
|
||||
|
||||
Version 2.0 | Last updated: May 2026
|
||||
|
||||
---
|
||||
|
||||
## 1. Purpose of This Document
|
||||
|
||||
This document provides additional context about the intended use of BoredOS and outlines important legal and practical considerations.
|
||||
|
||||
**It is not a software license.**
|
||||
BoredOS is licensed exclusively under the GNU General Public License v3.0 (GPLv3), which governs your rights to use, modify, and distribute the software.
|
||||
|
||||
In the event of any conflict, the GPLv3 takes full precedence.
|
||||
|
||||
---
|
||||
|
||||
## 2. License
|
||||
|
||||
BoredOS is free software released under the **GNU General Public License v3.0 (GPLv3)**.
|
||||
|
||||
You are free to:
|
||||
- Use the software for any purpose
|
||||
- Study and modify the source code
|
||||
- Redistribute original or modified versions
|
||||
|
||||
A copy of the GPLv3 is provided in the [`LICENSE`](./LICENSE) file.
|
||||
|
||||
---
|
||||
|
||||
## 3. No Age Verification or Regulatory Features
|
||||
|
||||
BoredOS is designed as a **local operating system** and:
|
||||
|
||||
- Does not implement **age verification**
|
||||
- Does not implement **age-gating**
|
||||
- Does not perform **identity checks**
|
||||
- Does not collect or process **personal data**
|
||||
|
||||
There are currently no plans to introduce such features.
|
||||
|
||||
---
|
||||
|
||||
## 4. Responsibility for Legal Compliance
|
||||
|
||||
Laws and regulations vary between jurisdictions and may apply differently depending on how software is used or distributed.
|
||||
|
||||
**You are solely responsible for ensuring that your use, distribution, or deployment of BoredOS complies with applicable laws and regulations in your jurisdiction.**
|
||||
|
||||
This includes, but is not limited to, laws relating to:
|
||||
|
||||
- Child safety and age-appropriate design
|
||||
- Data protection and privacy
|
||||
- Software distribution and platform obligations
|
||||
|
||||
If your use case requires features that BoredOS does not provide (such as age verification), you are responsible for implementing those features yourself or choosing alternative software.
|
||||
|
||||
---
|
||||
|
||||
## 5. No Representation of Legal Compliance
|
||||
|
||||
The author makes **no representation or warranty** that BoredOS complies with any specific legal or regulatory framework, including but not limited to:
|
||||
|
||||
- The California Age-Appropriate Design Code Act (AB 2273)
|
||||
- The Children’s Online Privacy Protection Act (COPPA)
|
||||
- The UK Age Appropriate Design Code (Children’s Code)
|
||||
- Any similar laws in other jurisdictions
|
||||
|
||||
BoredOS is general-purpose software and is not designed or certified for compliance with regulatory regimes.
|
||||
|
||||
---
|
||||
|
||||
## 6. No Monitoring or Enforcement
|
||||
|
||||
BoredOS:
|
||||
|
||||
- Does not track users
|
||||
- Does not verify location or identity
|
||||
- Does not enforce jurisdiction-specific restrictions
|
||||
|
||||
The author has no technical ability to monitor or control how the software is used.
|
||||
|
||||
---
|
||||
|
||||
## 7. Privacy
|
||||
|
||||
**BoredOS collects no data.**
|
||||
|
||||
- No telemetry
|
||||
- No analytics
|
||||
- No crash reporting
|
||||
- No accounts
|
||||
- No background network communication
|
||||
|
||||
All operation is local to the user’s device.
|
||||
|
||||
The source code is hosted on GitHub, which is operated by GitHub, Inc. Their data practices are governed by their own privacy policy.
|
||||
|
||||
---
|
||||
|
||||
## 8. Disclaimer of Warranty
|
||||
|
||||
BoredOS is provided **"as is"**, without warranty of any kind, express or implied, including:
|
||||
|
||||
- Merchantability
|
||||
- Fitness for a particular purpose
|
||||
- Non-infringement
|
||||
|
||||
The author does not guarantee that:
|
||||
|
||||
- The software is free of bugs or vulnerabilities
|
||||
- The software will work on any specific hardware
|
||||
- The software is suitable for any particular use case
|
||||
|
||||
---
|
||||
|
||||
## 9. Limitation of Liability
|
||||
|
||||
To the maximum extent permitted by applicable law, the author shall not be liable for:
|
||||
|
||||
- Data loss
|
||||
- Hardware damage
|
||||
- Loss of profits
|
||||
- Business interruption
|
||||
- Any indirect or consequential damages
|
||||
|
||||
Nothing in this section excludes liability where such exclusion is not permitted by law.
|
||||
|
||||
---
|
||||
|
||||
## 10. Trademarks and Attribution
|
||||
|
||||
"BoredOS" and associated branding may not be used to endorse or promote derived products without prior permission.
|
||||
|
||||
This does not limit your rights under the GPLv3, but applies to branding and representation.
|
||||
|
||||
---
|
||||
|
||||
## 11. Changes to This Document
|
||||
|
||||
This document may be updated to reflect changes in legal context or project direction.
|
||||
|
||||
The latest version will always be available in the repository.
|
||||
Previous versions will remain accessible via version history.
|
||||
|
||||
---
|
||||
|
||||
## 12. Contact
|
||||
|
||||
For questions or concerns, open an issue on the GitHub repository or contact the author via email at chris@boreddev.nl.
|
||||
|
||||
---
|
||||
|
||||
*BoredOS Usage Policy v2.0 — May 2026*
|
||||
16
README.md
@@ -7,6 +7,7 @@
|
||||
[](https://www.gnu.org/licenses/gpl-3.0)
|
||||

|
||||

|
||||

|
||||
</div>
|
||||
|
||||
---
|
||||
@@ -29,12 +30,12 @@ BoredOS is a x86_64 operating system featuring a custom Desktop Environment (DE)
|
||||
* **Multiboot2 Compliant:** Bootable on real hardware and modern emulators.
|
||||
* **Kernel Core:** Interrupt Descriptor Table (IDT) management and a robust syscall interface.
|
||||
* **Filesystem:** Full **FAT32** support for persistent and in-memory storage.
|
||||
* **Networking:** Includes the lwIP networking stack.
|
||||
* **Networking:** Includes the lwIP networking stack and a basic web browser.
|
||||
|
||||
### Graphical User Interface
|
||||
* **BoredWM:** A custom Window Manager with drag-and-drop, mouse-centered interaction.
|
||||
* **Customization:** Adjustable UI to suit your aesthetic.
|
||||
* **Media Support:** Built-in image decoding.
|
||||
* **Media Support:** Built-in image decoding. (PNG, GIF, JPEG, TGA, BMP)
|
||||
|
||||
### Included Applications
|
||||
* **Productivity:** GUI Text Editor calculator, Markdown Viewer, a simple browser and BoredWord.
|
||||
@@ -66,9 +67,9 @@ If you find this project interesting or helpful, consider fueling the developmen
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Project Disclaimer & Heritage
|
||||
## Project Disclaimer & Heritage
|
||||
|
||||
**BoredOS** is the successor to **BrewKernel**, a project initiated in 2023.
|
||||
**BoredOS** is the successor to **[BrewKernel](https://github.com/boreddevnl/brewkernel)**, a project initiated in 2023.
|
||||
|
||||
While BrewKernel served as the foundational learning ground for this OS, it has been officially **deprecated and archived**. It no longer receives updates, bug fixes, or pull request reviews. BoredOS represents a complete architectural reboot, applying years of lessons learned to create a cleaner, more modular, and more capable system.
|
||||
|
||||
@@ -77,9 +78,14 @@ While BrewKernel served as the foundational learning ground for this OS, it has
|
||||
|
||||
---
|
||||
|
||||
## Contributors
|
||||
|
||||
- **BoredDevNL** — Project creator and lead maintainer.
|
||||
- **Lluciocc** — Contributor.
|
||||
|
||||
## License
|
||||
|
||||
**Copyright (C) 2024-2026 boreddevnl**
|
||||
**Copyright (C) 2023-2026 boreddevnl**
|
||||
|
||||
Distributed under the **GNU General Public License v3**. See the `LICENSE` file for details.
|
||||
|
||||
|
||||
286
build.log
@@ -1,286 +0,0 @@
|
||||
mkdir -p build
|
||||
mkdir -p build
|
||||
nasm -f elf64 src/arch/boot.asm -o build/boot.o
|
||||
nasm -f elf64 src/arch/gdt_asm.asm -o build/gdt_asm.o
|
||||
nasm -f elf64 src/arch/interrupts.asm -o build/interrupts.o
|
||||
nasm -f elf64 src/arch/process_asm.asm -o build/process_asm.o
|
||||
nasm -f elf64 src/arch/syscalls.asm -o build/syscalls.o
|
||||
nasm -f elf64 src/arch/test_syscall.asm -o build/test_syscall.o
|
||||
nasm -f elf64 src/arch/user_test.asm -o build/user_test.o
|
||||
Building Limine host utility...
|
||||
make[1]: Nothing to be done for `all'.
|
||||
mkdir -p build/
|
||||
mkdir -p build/
|
||||
mkdir -p build/
|
||||
mkdir -p build/
|
||||
mkdir -p build/
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/core/kutils.c -o build/kutils.o
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/core/main.c -o build/main.o
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/core/version.c -o build/version.o
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/sys/elf.c -o build/elf.o
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/core/platform.c -o build/platform.o
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/core/panic.c -o build/panic.o
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/sys/idt.c -o build/idt.o
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/sys/gdt.c -o build/gdt.o
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/sys/kernel_subsystem.c -o build/kernel_subsystem.o
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/sys/lapic.c -o build/lapic.o
|
||||
src/sys/idt.c: In function 'pic_remap':
|
||||
src/sys/idt.c:120:17: warning: variable 'a2' set but not used [-Wunused-but-set-variable]
|
||||
120 | uint8_t a1, a2;
|
||||
| ^~
|
||||
src/sys/idt.c:120:13: warning: variable 'a1' set but not used [-Wunused-but-set-variable]
|
||||
120 | uint8_t a1, a2;
|
||||
| ^~
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/sys/module_manager.c -o build/module_manager.o
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/sys/process.c -o build/process.o
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/sys/smp.c -o build/smp.o
|
||||
mkdir -p build/
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/sys/syscall.c -o build/syscall.o
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/sys/sysfs_init.c -o build/sysfs_init.o
|
||||
src/sys/smp.c: In function 'smp_init':
|
||||
src/sys/smp.c:171:14: warning: variable 'bsp_index' set but not used [-Wunused-but-set-variable]
|
||||
171 | uint32_t bsp_index = 0;
|
||||
| ^~~~~~~~~
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/sys/work_queue.c -o build/work_queue.o
|
||||
mkdir -p build/
|
||||
src/sys/sysfs_init.c:11:13: warning: 'sys_itoa' defined but not used [-Wunused-function]
|
||||
11 | static void sys_itoa(int n, char *s) {
|
||||
| ^~~~~~~~
|
||||
mkdir -p build/
|
||||
src/sys/syscall.c: In function 'syscall_handler_inner':
|
||||
src/sys/syscall.c:493:28: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
|
||||
493 | float scale = *(float*)&scale_bits;
|
||||
| ^~~~~~~~~~~~~~~~~~~
|
||||
src/sys/syscall.c:561:28: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
|
||||
561 | float scale = *(float*)&scale_bits;
|
||||
| ^~~~~~~~~~~~~~~~~~~
|
||||
src/sys/syscall.c:569:28: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
|
||||
569 | float slope = *(float*)&slope_bits;
|
||||
| ^~~~~~~~~~~~~~~~~~~
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/mem/memory_manager.c -o build/memory_manager.o
|
||||
src/sys/syscall.c:695:21: warning: unused variable 'win' [-Wunused-variable]
|
||||
695 | Window *win = (Window *)arg2;
|
||||
| ^~~
|
||||
src/sys/syscall.c:725:28: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
|
||||
725 | float scale = *(float*)&scale_bits;
|
||||
| ^~~~~~~~~~~~~~~~~~~
|
||||
src/sys/syscall.c:762:28: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
|
||||
762 | float scale = *(float*)&scale_bits;
|
||||
| ^~~~~~~~~~~~~~~~~~~
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/mem/paging.c -o build/paging.o
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/mem/vm.c -o build/vm.o
|
||||
mkdir -p build/
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/dev/disk_manager.c -o build/disk_manager.o
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/dev/ahci.c -o build/ahci.o
|
||||
mkdir -p build/
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/dev/pci.c -o build/pci.o
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/dev/ps2.c -o build/ps2.o
|
||||
src/dev/pci.c: In function 'pci_enumerate_devices':
|
||||
src/dev/pci.c:52:31: warning: comparison is always true due to limited range of data type [-Wtype-limits]
|
||||
52 | for (uint8_t bus = 0; bus < 256 && count < max_devices; bus++) {
|
||||
| ^
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/dev/rtc.c -o build/rtc.o
|
||||
src/dev/rtc.c: In function 'rtc_get_datetime':
|
||||
src/dev/rtc.c:28:13: warning: unused variable 'last_century' [-Wunused-variable]
|
||||
28 | uint8_t last_century;
|
||||
| ^~~~~~~~~~~~
|
||||
src/dev/rtc.c:21:13: warning: unused variable 'century' [-Wunused-variable]
|
||||
21 | uint8_t century;
|
||||
| ^~~~~~~
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/net/lwip_port.c -o build/lwip_port.o
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/net/network.c -o build/network.o
|
||||
mkdir -p build/
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/net/nic/e1000.c -o build/e1000.o
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/net/nic/nic.c -o build/nic.o
|
||||
src/net/network.c: In function 'network_dhcp_acquire':
|
||||
src/net/network.c:186:9: warning: unused variable 'loops' [-Wunused-variable]
|
||||
186 | int loops = 0;
|
||||
| ^~~~~
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/net/nic/nic_netif.c -o build/nic_netif.o
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/net/nic/rtl8111.c -o build/rtl8111.o
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/net/nic/rtl8139.c -o build/rtl8139.o
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/net/nic/virtio_net.c -o build/virtio_net.o
|
||||
mkdir -p build/
|
||||
src/net/network.c: In function 'network_init':
|
||||
src/net/network.c:93:9: warning: 'ip.bytes[0]' may be used uninitialized [-Wmaybe-uninitialized]
|
||||
93 | k_itoa(ip.bytes[0], buf); serial_write(buf); serial_write(".");
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~
|
||||
src/net/network.c:88:24: note: 'ip.bytes[0]' was declared here
|
||||
88 | ipv4_address_t ip;
|
||||
| ^~
|
||||
src/net/network.c:94:9: warning: 'ip.bytes[1]' may be used uninitialized [-Wmaybe-uninitialized]
|
||||
94 | k_itoa(ip.bytes[1], buf); serial_write(buf); serial_write(".");
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~
|
||||
src/net/network.c:88:24: note: 'ip.bytes[1]' was declared here
|
||||
88 | ipv4_address_t ip;
|
||||
| ^~
|
||||
src/net/network.c:95:9: warning: 'ip.bytes[2]' may be used uninitialized [-Wmaybe-uninitialized]
|
||||
95 | k_itoa(ip.bytes[2], buf); serial_write(buf); serial_write(".");
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~
|
||||
src/net/network.c:88:24: note: 'ip.bytes[2]' was declared here
|
||||
88 | ipv4_address_t ip;
|
||||
| ^~
|
||||
src/net/network.c:96:9: warning: 'ip.bytes[3]' may be used uninitialized [-Wmaybe-uninitialized]
|
||||
96 | k_itoa(ip.bytes[3], buf); serial_write(buf); serial_write("\n");
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~
|
||||
src/net/network.c:88:24: note: 'ip.bytes[3]' was declared here
|
||||
88 | ipv4_address_t ip;
|
||||
| ^~
|
||||
src/net/nic/rtl8111.c: In function 'rtl8111_init':
|
||||
src/net/nic/rtl8111.c:67:14: warning: unused variable 'bar2' [-Wunused-variable]
|
||||
67 | uint32_t bar2 = pci_read_config(pci_dev->bus, pci_dev->device, pci_dev->function, 0x18);
|
||||
| ^~~~
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/fs/fat32.c -o build/fat32.o
|
||||
mkdir -p build/
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/fs/procfs.c -o build/procfs.o
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/fs/sysfs.c -o build/sysfs.o
|
||||
src/fs/fat32.c: In function 'realfs_delete_from_vol':
|
||||
src/fs/fat32.c:1110:14: warning: variable 'entry_offset' set but not used [-Wunused-but-set-variable]
|
||||
1110 | uint32_t entry_offset = 0;
|
||||
| ^~~~~~~~~~~~
|
||||
src/fs/fat32.c:1109:14: warning: variable 'entry_sector' set but not used [-Wunused-but-set-variable]
|
||||
1109 | uint32_t entry_sector = 0;
|
||||
| ^~~~~~~~~~~~
|
||||
src/fs/sysfs.c: In function 'sysfs_open':
|
||||
src/fs/sysfs.c:12:31: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||
12 | static void* sysfs_open(void *fs_private, const char *path, const char *mode) {
|
||||
| ~~~~~~^~~~~~~~~~
|
||||
src/fs/sysfs.c:12:73: warning: unused parameter 'mode' [-Wunused-parameter]
|
||||
12 | static void* sysfs_open(void *fs_private, const char *path, const char *mode) {
|
||||
| ~~~~~~~~~~~~^~~~
|
||||
src/fs/sysfs.c: In function 'sysfs_close':
|
||||
src/fs/sysfs.c:43:31: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||
43 | static void sysfs_close(void *fs_private, void *handle) {
|
||||
| ~~~~~~^~~~~~~~~~
|
||||
src/fs/sysfs.c: In function 'sysfs_read':
|
||||
src/fs/sysfs.c:47:29: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||
47 | static int sysfs_read(void *fs_private, void *handle, void *buf, int size) {
|
||||
| ~~~~~~^~~~~~~~~~
|
||||
src/fs/sysfs.c: In function 'sysfs_write':
|
||||
src/fs/sysfs.c:56:30: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||
56 | static int sysfs_write(void *fs_private, void *handle, const void *buf, int size) {
|
||||
| ~~~~~~^~~~~~~~~~
|
||||
src/fs/sysfs.c: In function 'sysfs_readdir':
|
||||
src/fs/sysfs.c:86:49: warning: comparison of integer expressions of different signedness: 'size_t' {aka 'long unsigned int'} and 'int' [-Wsign-compare]
|
||||
86 | if (path_len == 0 || (k_strlen(s->name) > path_len && k_strncmp(s->name, path, path_len) == 0 && s->name[path_len] == '/')) {
|
||||
| ^
|
||||
src/fs/sysfs.c:65:32: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||
65 | static int sysfs_readdir(void *fs_private, const char *path, vfs_dirent_t *entries, int max) {
|
||||
| ~~~~~~^~~~~~~~~~
|
||||
src/fs/sysfs.c: In function 'sysfs_exists':
|
||||
src/fs/sysfs.c:142:31: warning: comparison of integer expressions of different signedness: 'size_t' {aka 'long unsigned int'} and 'int' [-Wsign-compare]
|
||||
142 | if (k_strlen(s->name) > path_len && k_strncmp(s->name, path, path_len) == 0 && s->name[path_len] == '/') return true;
|
||||
| ^
|
||||
src/fs/sysfs.c:116:32: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||
116 | static bool sysfs_exists(void *fs_private, const char *path) {
|
||||
| ~~~~~~^~~~~~~~~~
|
||||
src/fs/procfs.c: In function 'procfs_open':
|
||||
src/fs/procfs.c:15:25: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||
15 | void* procfs_open(void *fs_private, const char *path, const char *mode) {
|
||||
| ~~~~~~^~~~~~~~~~
|
||||
src/fs/procfs.c:15:67: warning: unused parameter 'mode' [-Wunused-parameter]
|
||||
15 | void* procfs_open(void *fs_private, const char *path, const char *mode) {
|
||||
| ~~~~~~~~~~~~^~~~
|
||||
src/fs/procfs.c: In function 'procfs_close':
|
||||
src/fs/procfs.c:50:25: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||
50 | void procfs_close(void *fs_private, void *handle) {
|
||||
| ~~~~~~^~~~~~~~~~
|
||||
src/fs/procfs.c: In function 'procfs_read':
|
||||
src/fs/procfs.c:54:23: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||
54 | int procfs_read(void *fs_private, void *handle, void *buf, int size) {
|
||||
| ~~~~~~^~~~~~~~~~
|
||||
src/fs/procfs.c: In function 'procfs_write':
|
||||
src/fs/procfs.c:178:24: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||
178 | int procfs_write(void *fs_private, void *handle, const void *buf, int size) {
|
||||
| ~~~~~~^~~~~~~~~~
|
||||
src/fs/procfs.c: In function 'procfs_readdir':
|
||||
src/fs/procfs.c:200:26: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||
200 | int procfs_readdir(void *fs_private, const char *path, vfs_dirent_t *entries, int max) {
|
||||
| ~~~~~~^~~~~~~~~~
|
||||
src/fs/procfs.c: In function 'procfs_exists':
|
||||
src/fs/procfs.c:241:26: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||
241 | bool procfs_exists(void *fs_private, const char *path) {
|
||||
| ~~~~~~^~~~~~~~~~
|
||||
src/fs/procfs.c: In function 'procfs_is_dir':
|
||||
src/fs/procfs.c:264:26: warning: unused parameter 'fs_private' [-Wunused-parameter]
|
||||
264 | bool procfs_is_dir(void *fs_private, const char *path) {
|
||||
| ~~~~~~^~~~~~~~~~
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/fs/tar.c -o build/tar.o
|
||||
mkdir -p build/
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/fs/vfs.c -o build/vfs.o
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/wm/cmd.c -o build/cmd.o
|
||||
mkdir -p build/
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/wm/explorer.c -o build/explorer.o
|
||||
src/wm/cmd.c: In function 'internal_cmd_cd':
|
||||
src/wm/cmd.c:1014:13: error: too few arguments to function 'vfs_normalize_path'; expected 3, have 2
|
||||
1014 | vfs_normalize_path(full_path, normalized_path);
|
||||
| ^~~~~~~~~~~~~~~~~~
|
||||
In file included from src/wm/cmd.c:11:
|
||||
src/fs/vfs.h:111:6: note: declared here
|
||||
111 | void vfs_normalize_path(const char *cwd, const char *path, char *normalized);
|
||||
| ^~~~~~~~~~~~~~~~~~
|
||||
mkdir -p build/
|
||||
make: *** [build/cmd.o] Error 1
|
||||
make: *** Waiting for unfinished jobs....
|
||||
x86_64-elf-gcc -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fPIE -m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone -Isrc -Isrc/net/lwip -Isrc/core -Isrc/sys -Isrc/mem -Isrc/dev -Isrc/net -Isrc/net/nic -Isrc/fs -Isrc/wm -c src/wm/font_manager.c -o build/font_manager.o
|
||||
src/wm/explorer.c: In function 'explorer_draw_file_icon':
|
||||
src/wm/explorer.c:885:73: warning: unused parameter 'color' [-Wunused-parameter]
|
||||
885 | static void explorer_draw_file_icon(int x, int y, bool is_dir, uint32_t color, const char *filename, const char *current_path) {
|
||||
| ~~~~~~~~~^~~~~
|
||||
src/wm/explorer.c: In function 'explorer_paint':
|
||||
src/wm/explorer.c:922:15: warning: unused variable 'dirty' [-Wunused-variable]
|
||||
922 | DirtyRect dirty = graphics_get_dirty_rect();
|
||||
| ^~~~~
|
||||
In file included from src/wm/font_manager.c:4:
|
||||
src/wm/stb_truetype.h: In function 'stbtt_FreeShape':
|
||||
src/wm/stb_truetype.h:2672:54: warning: unused parameter 'info' [-Wunused-parameter]
|
||||
2672 | STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~^~~~
|
||||
src/wm/stb_truetype.h: In function 'stbtt__hheap_alloc':
|
||||
src/wm/stb_truetype.h:2770:70: warning: unused parameter 'userdata' [-Wunused-parameter]
|
||||
2770 | static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata)
|
||||
| ~~~~~~^~~~~~~~
|
||||
src/wm/stb_truetype.h: In function 'stbtt__hheap_cleanup':
|
||||
src/wm/stb_truetype.h:2797:58: warning: unused parameter 'userdata' [-Wunused-parameter]
|
||||
2797 | static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata)
|
||||
| ~~~~~~^~~~~~~~
|
||||
src/wm/stb_truetype.h: In function 'stbtt_FlattenCurves':
|
||||
src/wm/stb_truetype.h:3618:154: warning: unused parameter 'userdata' [-Wunused-parameter]
|
||||
3618 | static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata)
|
||||
| ~~~~~~^~~~~~~~
|
||||
src/wm/stb_truetype.h: In function 'stbtt_FreeBitmap':
|
||||
src/wm/stb_truetype.h:3708:62: warning: unused parameter 'userdata' [-Wunused-parameter]
|
||||
3708 | STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata)
|
||||
| ~~~~~~^~~~~~~~
|
||||
src/wm/stb_truetype.h: In function 'stbtt_FreeSDF':
|
||||
src/wm/stb_truetype.h:4767:59: warning: unused parameter 'userdata' [-Wunused-parameter]
|
||||
4767 | STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata)
|
||||
| ~~~~~~^~~~~~~~
|
||||
src/wm/font_manager.c: In function 'font_manager_load':
|
||||
src/wm/font_manager.c:112:9: warning: unused variable 'read' [-Wunused-variable]
|
||||
112 | int read = fat32_read(fh, buffer, fsize);
|
||||
| ^~~~
|
||||
@@ -5,31 +5,66 @@
|
||||
|
||||
---
|
||||
|
||||
Welcome to the internal documentation for BoredOS! This directory contains detailed guides on how the OS functions, how to build it, and how to develop applications for it.
|
||||
Welcome to the documentation for BoredOS! This directory contains detailed guides on how the OS functions, how to build it, and how to develop applications for it.
|
||||
|
||||
## 📚 Table of Contents
|
||||
## Table of Contents
|
||||
|
||||
The documentation is organized into three main categories:
|
||||
|
||||
### 1. 🏗️ [Architecture](architecture/)
|
||||
### 1. [Architecture](architecture/)
|
||||
Explains the logical layout of the kernel and internal components.
|
||||
- [`Core`](architecture/core.md): Kernel source layout and the boot process (Limine, Multiboot2).
|
||||
- [`Memory`](architecture/memory.md): Physical Memory Management (PMM) and Virtual Memory Management (VMM).
|
||||
- [`Filesystem`](architecture/filesystem.md): Virtual File System (VFS) and the RAM-based FAT32 simulation.
|
||||
- [`Window Manager`](architecture/window_manager.md): How the built-in Window Manager natively handles graphics, events, and compositing.
|
||||
|
||||
### 2. 🔨 [Building and Deployment](build/)
|
||||
#### System
|
||||
- [`Core`](architecture/system/core.md): Kernel source layout and the boot process (Limine, Multiboot2).
|
||||
- [`Processes & Scheduling`](architecture/system/processes.md): Multitasking, context switching, and ELF loading.
|
||||
- [`Interrupts & Exceptions`](architecture/system/interrupts.md): IDT, GDT, and exception handling.
|
||||
|
||||
#### Memory
|
||||
- [`Memory (PMM/VMM)`](architecture/memory/memory.md): Physical Memory Management and Virtual Memory Management.
|
||||
- [`Memory Manager`](architecture/memory/memory_manager.md): Slab allocator and block allocator for kernel heap.
|
||||
|
||||
#### Storage & Filesystems
|
||||
- [`Filesystem`](architecture/storage/filesystem.md): Virtual File System (VFS) and the RAM-based FAT32 simulation.
|
||||
- [`AHCI Drivers`](architecture/storage/ahci_drivers.md): Hardware communication for block storage devices.
|
||||
|
||||
#### Network
|
||||
- [`Network Stack`](architecture/network/network_stack.md): TCP/IP implementation and socket APIs.
|
||||
- [`Network Drivers`](architecture/network/network_drivers.md): Hardware interaction for network cards (e.g. e1000).
|
||||
|
||||
#### Graphics
|
||||
- [`Window Manager`](architecture/graphics/window_manager.md): Compositor, events, and overlapping windows.
|
||||
- [`Rendering`](architecture/graphics/rendering.md): Framebuffer, font rendering, and image loading.
|
||||
|
||||
#### Hardware
|
||||
- [`PCI`](architecture/hardware/pci.md): PCI bus enumeration and device binding.
|
||||
- [`Input`](architecture/hardware/input.md): PS/2 Keyboard and Mouse input handling.
|
||||
|
||||
#### Misc
|
||||
- [`Versioning`](architecture/versioning.md): The OS date-based version scheme (`YY.M[.x]`) and kernel semantic versioning (`MAJOR.MINOR.PATCH`).
|
||||
|
||||
### 2. [Building and Deployment](build/)
|
||||
Instructions for compiling the OS from source.
|
||||
- [`Toolchain`](build/toolchain.md): Prerequisites and cross-compiler setup (`x86_64-elf-gcc`, `nasm`, `xorriso`).
|
||||
- [`Usage`](build/usage.md): Understanding the Makefile targets, QEMU emulation, and flashing to bare metal hardware.
|
||||
|
||||
### 3. 🚀 [Application Development](appdev/)
|
||||
### 3. [Application Development](appdev/)
|
||||
The SDK and toolchain guides for creating your own `.elf` userland binaries.
|
||||
- [`SDK Reference`](appdev/sdk_reference.md): Explanation of the custom `libc` wrappers (`stdlib.h`, `string.h`) and system calls.
|
||||
- [`SDK Reference`](appdev/sdk_reference.md): Overview hub for SDK layout, includes, and links to detailed libc/syscall docs.
|
||||
- [`Syscalls`](appdev/syscalls.md): Current syscall numbers, FS/SYSTEM command IDs, and wrapper guidance.
|
||||
- [`libc Reference`](appdev/libc_reference.md): Current libc headers, implemented APIs, and behavior notes.
|
||||
- [`UI API`](appdev/ui_api.md): Drawing on the screen, creating windows, and polling the event loop using `libui.h`.
|
||||
- [`Widget API`](appdev/widget_api.md): High-level UI components like buttons, textboxes, and scrollbars using `libwidget.h`.
|
||||
- [`Custom Apps`](appdev/custom_apps.md): A step-by-step tutorial on writing a new graphical C application, editing the Makefile, and bundling it into the ISO.
|
||||
- [`ELF App Metadata`](appdev/elf_metadata.md): How to declare app icons and descriptions using source annotations, how the build system embeds them into `.note.boredos.app` ELF sections, and how the kernel reads them at runtime.
|
||||
- [`Example Apps`](appdev/examples/README.md): A collection of sample C applications ranging from basic terminal output to advanced TCP networking.
|
||||
- [`Grapher`](appdev/grapher.md): Full reference for the built-in mathematical graphing application — equation syntax, keyboard controls, architecture, and configuration.
|
||||
|
||||
### 4. [Usage](usage/)
|
||||
General guides on how to interact with the OS.
|
||||
- [`Booting`](usage/booting.md): How to use the Limine bootloader and toggle kernel boot flags like `-v`.
|
||||
- [`Desktop`](usage/desktop.md): Window management, shortcuts, and desktop interaction.
|
||||
- [`Lumos`](usage/lumos.md): Using the system-wide search (`Shift + Ctrl + Space`).
|
||||
- [`Terminal`](usage/terminal.md): Command line interface, redirection, and common commands.
|
||||
- [`Launching Apps`](usage/launching_apps.md): Ways to launch files and applications, plus a software overview.
|
||||
|
||||
---
|
||||
|
||||
307
docs/appdev/elf_metadata.md
Normal file
@@ -0,0 +1,307 @@
|
||||
<div align="center">
|
||||
<h1>ELF App Metadata</h1>
|
||||
<p><em>How BoredOS embeds and reads application identity and icon data from <code>.elf</code> binaries.</em></p>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
BoredOS supports embedding **application metadata** including a display name, short description, and icon paths directly inside `.elf` executables using a standard ELF NOTE section. The kernel reads this metadata at runtime to display correct icons in the file explorer and on the desktop, without requiring any external sidecar files.
|
||||
|
||||
## Overview
|
||||
|
||||
When an ELF binary is compiled for BoredOS, the build system automatically injects a special ELF NOTE entry into a dedicated section called `.note.boredos.app`. This note holds a packed C struct (`boredos_app_metadata_t`) containing the app's metadata.
|
||||
|
||||
At runtime, the Window Manager (`wm.c`) and File Explorer (`explorer.c`) call `app_metadata_get_primary_image()` to extract the primary icon path from any `.elf` file before rendering its icon. This allows each app to display its own distinct icon instead of the generic binary icon.
|
||||
|
||||
---
|
||||
|
||||
## The `boredos_app_metadata_t` Structure
|
||||
|
||||
Defined in [`src/sys/elf.h`](../../src/sys/elf.h):
|
||||
|
||||
```c
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint32_t magic; // Must be BOREDOS_APP_METADATA_MAGIC (0x414d4431)
|
||||
uint16_t version; // Must be BOREDOS_APP_METADATA_VERSION (1)
|
||||
uint16_t image_count; // Number of valid icon paths (0–4)
|
||||
uint16_t reserved; // Padding, set to 0
|
||||
char app_name[BOREDOS_APP_METADATA_MAX_APP_NAME]; // Up to 63 chars + NUL
|
||||
char description[BOREDOS_APP_METADATA_MAX_DESCRIPTION]; // Up to 191 chars + NUL
|
||||
char images[BOREDOS_APP_METADATA_MAX_IMAGES][BOREDOS_APP_METADATA_MAX_IMAGE_PATH]; // Up to 4 icon paths
|
||||
} boredos_app_metadata_t;
|
||||
```
|
||||
|
||||
### Field Reference
|
||||
|
||||
| Field | Size | Description |
|
||||
|---|---|---|
|
||||
| `magic` | 4 bytes | Magic number `0x414D4431` — validates the struct is a real metadata blob. |
|
||||
| `version` | 2 bytes | Schema version. Currently always `1`. |
|
||||
| `image_count` | 2 bytes | How many entries in `images[]` are valid (0–4). |
|
||||
| `reserved` | 2 bytes | Must be 0. Reserved for future use. |
|
||||
| `app_name` | 64 bytes | Null-terminated display name of the app (e.g., `"Terminal"`). |
|
||||
| `description` | 192 bytes | Null-terminated short description (e.g., `"Terminal shell and command runner."`). |
|
||||
| `images[4][160]` | 640 bytes | Up to 4 absolute VFS paths to PNG icons. First entry is the primary icon. |
|
||||
|
||||
### Limits
|
||||
|
||||
| Constant | Value | Meaning |
|
||||
|---|---|---|
|
||||
| `BOREDOS_APP_METADATA_MAX_APP_NAME` | 64 | Max bytes for `app_name` including NUL |
|
||||
| `BOREDOS_APP_METADATA_MAX_DESCRIPTION` | 192 | Max bytes for `description` including NUL |
|
||||
| `BOREDOS_APP_METADATA_MAX_IMAGES` | 4 | Max number of icon paths |
|
||||
| `BOREDOS_APP_METADATA_MAX_IMAGE_PATH` | 160 | Max bytes per icon path including NUL |
|
||||
|
||||
---
|
||||
|
||||
## The ELF NOTE Format
|
||||
|
||||
The metadata is stored inside a standard ELF NOTE entry (defined by `Elf64_Nhdr` in `elf.h`) within the `.note.boredos.app` section.
|
||||
|
||||
```
|
||||
+------------------+
|
||||
| Elf64_Nhdr | namesz, descsz, type
|
||||
+------------------+
|
||||
| name: "BOREDOS\0"| 8 bytes (sizeof BOREDOS_APP_NOTE_NAME)
|
||||
+------------------+
|
||||
| boredos_app_ | sizeof(boredos_app_metadata_t)
|
||||
| metadata_t |
|
||||
+------------------+
|
||||
```
|
||||
|
||||
### Note Constants
|
||||
|
||||
| Constant | Value | Description |
|
||||
|---|---|---|
|
||||
| `BOREDOS_APP_NOTE_OWNER` | `"BOREDOS"` | The note owner/name string |
|
||||
| `BOREDOS_APP_NOTE_SECTION` | `".note.boredos.app"` | ELF section name |
|
||||
| `BOREDOS_APP_NOTE_TYPE` | `0x41505031` | Note type identifier (`"APP1"` in ASCII) |
|
||||
| `BOREDOS_APP_METADATA_MAGIC` | `0x414D4431` | Metadata struct magic (`"AMD1"`) |
|
||||
| `BOREDOS_APP_METADATA_VERSION` | `1` | Current schema version |
|
||||
|
||||
---
|
||||
|
||||
## Embedding Metadata into your applications
|
||||
|
||||
Developers declare metadata using **special comment annotations** at the top of their C source file. The build system reads these automatically during compilation.
|
||||
|
||||
```c
|
||||
// BOREDOS_APP_DESC: My application's short description.
|
||||
// BOREDOS_APP_ICONS: /Library/images/icons/colloid/my-icon.png
|
||||
```
|
||||
|
||||
### `BOREDOS_APP_DESC`
|
||||
|
||||
A single-line description of the application. Truncated to 191 characters.
|
||||
|
||||
### `BOREDOS_APP_ICONS`
|
||||
|
||||
A semicolon-separated list of absolute VFS paths to PNG icons. Up to 4 icons are supported. The **first** entry is used as the primary icon displayed in the File Explorer and on the Desktop.
|
||||
|
||||
```c
|
||||
// BOREDOS_APP_ICONS: /Library/images/icons/colloid/primary.png;/Library/images/icons/colloid/alternate.png
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> If no `BOREDOS_APP_ICONS` annotation is provided, the build tool falls back to `/Library/images/icons/colloid/xterm.png`.
|
||||
> If no `BOREDOS_APP_DESC` annotation is provided, the build tool uses `"BoredOS userspace application."`.
|
||||
|
||||
---
|
||||
|
||||
## Build System Integration
|
||||
|
||||
### The `gen_userland_note.sh` Tool
|
||||
|
||||
Located at [`tools/gen_userland_note.sh`](../../tools/gen_userland_note.sh), this script is invoked automatically by the `src/userland/Makefile` for every compiled application.
|
||||
|
||||
**Usage:**
|
||||
```sh
|
||||
gen_userland_note.sh <app-name> <source-file> <icon-source-dir> <output.note.c>
|
||||
```
|
||||
|
||||
| Argument | Description |
|
||||
|---|---|
|
||||
| `<app-name>` | The base name of the application (e.g., `terminal`) |
|
||||
| `<source-file>` | Path to the main `.c` source to extract annotations from |
|
||||
| `<icon-source-dir>` | Directory where icon files are expected to exist on the *host* (build-time validation) |
|
||||
| `<output.note.c>` | Path for the generated C source file |
|
||||
|
||||
The script:
|
||||
1. Reads `BOREDOS_APP_DESC` and `BOREDOS_APP_ICONS` from the source file.
|
||||
2. Validates that each declared icon file exists in `<icon-source-dir>` at build time.
|
||||
3. Generates a C file (e.g., `bin/terminal.note.c`) that defines a `__attribute__((section(".note.boredos.app")))` constant struct containing all metadata.
|
||||
|
||||
### Makefile Rules
|
||||
|
||||
In `src/userland/Makefile`, the following rules handle metadata generation and linking:
|
||||
|
||||
```make
|
||||
# Generate the .note.c for each app from its source annotations
|
||||
$(BIN_DIR)/%.note.c: $(APP_METADATA_TOOL) | $(BIN_DIR)
|
||||
src="$(call app_source_for,$*)"; \
|
||||
sh $(APP_METADATA_TOOL) "$*" "$$src" "$(APP_ICON_SOURCE_DIR)" "$@"
|
||||
|
||||
# Compile the generated note C file
|
||||
$(BIN_DIR)/%.note.o: $(BIN_DIR)/%.note.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
# Link note object into each ELF (generic rule)
|
||||
$(BIN_DIR)/%.elf: $(LIBC_OBJS) $(BIN_DIR)/%.o $(BIN_DIR)/%.note.o
|
||||
$(LD) $(LDFLAGS) $^ -o $@
|
||||
```
|
||||
|
||||
Special-cased apps (`doom`, `lua`, `viewer`, `settings`, `browser`, `screenshot`) also link in their own `.note.o` explicitly.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> The `-I../sys` flag is added to `CFLAGS` so that generated `.note.c` files can `#include "elf.h"` when referencing the metadata constants.
|
||||
|
||||
---
|
||||
|
||||
## Runtime Parsing: `app_metadata.c`
|
||||
|
||||
At runtime, `src/sys/app_metadata.c` provides two public functions:
|
||||
|
||||
```c
|
||||
bool app_metadata_read(const char *path, boredos_app_metadata_t *out_metadata);
|
||||
bool app_metadata_get_primary_image(const char *path, char *out_path, size_t out_path_size);
|
||||
```
|
||||
|
||||
### `app_metadata_read`
|
||||
|
||||
Opens the ELF at `path` via VFS and searches for the `.note.boredos.app` section. It uses a **two-pass strategy**:
|
||||
|
||||
1. **Raw scan** (`am_scan_raw_notes`): For files up to 16 MiB, loads the entire binary into memory and byte-scans for a NOTE header matching the `BOREDOS` owner and `BOREDOS_APP_NOTE_TYPE`. This handles cases where the section header table is missing or unreadable.
|
||||
2. **Section-based scan** (`am_parse_note_section`): Reads the ELF section header table, locates the `.note.boredos.app` section by name, then parses NOTE entries within it.
|
||||
|
||||
After a successful parse, the struct is validated via `am_validate_metadata` (checks magic and version fields) and sanitized via `am_sanitize_metadata` (null-terminates all strings).
|
||||
|
||||
### `app_metadata_get_primary_image`
|
||||
|
||||
A convenience wrapper around `app_metadata_read` that returns just the first icon path:
|
||||
|
||||
```c
|
||||
bool app_metadata_get_primary_image(const char *path, char *out_path, size_t out_path_size);
|
||||
```
|
||||
|
||||
Returns `true` and populates `out_path` if the binary has at least one valid icon declared.
|
||||
|
||||
### Metadata Cache
|
||||
|
||||
To avoid re-reading ELF files on every frame redraw, results are stored in a **simple FIFO cache** of up to 64 entries:
|
||||
|
||||
```c
|
||||
#define APP_METADATA_CACHE_SIZE 64
|
||||
```
|
||||
|
||||
Both positive (metadata found) and negative (no metadata) results are cached. The cache uses a round-robin eviction strategy — no LRU, no invalidation. This is intentional for a kernel context where metadata does not change while the OS is running.
|
||||
|
||||
---
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Userspace API
|
||||
|
||||
Userspace applications can query the ELF metadata of any `.elf` binary on the VFS through two wrapper functions declared in [`src/userland/libc/syscall.h`](../../src/userland/libc/syscall.h).
|
||||
|
||||
### The `boredos_app_metadata_t` struct (userland)
|
||||
|
||||
The struct is redefined verbatim in the userland header so that apps do **not** need to include any kernel header:
|
||||
|
||||
```c
|
||||
#define BOREDOS_APP_METADATA_MAX_APP_NAME 64
|
||||
#define BOREDOS_APP_METADATA_MAX_DESCRIPTION 192
|
||||
#define BOREDOS_APP_METADATA_MAX_IMAGES 4
|
||||
#define BOREDOS_APP_METADATA_MAX_IMAGE_PATH 160
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint32_t magic;
|
||||
uint16_t version;
|
||||
uint16_t image_count;
|
||||
uint16_t reserved;
|
||||
char app_name[BOREDOS_APP_METADATA_MAX_APP_NAME];
|
||||
char description[BOREDOS_APP_METADATA_MAX_DESCRIPTION];
|
||||
char images[BOREDOS_APP_METADATA_MAX_IMAGES][BOREDOS_APP_METADATA_MAX_IMAGE_PATH];
|
||||
} boredos_app_metadata_t;
|
||||
```
|
||||
|
||||
### Functions
|
||||
|
||||
#### `sys_get_elf_metadata`
|
||||
|
||||
```c
|
||||
int sys_get_elf_metadata(const char *path, boredos_app_metadata_t *out_metadata);
|
||||
```
|
||||
|
||||
Reads the full metadata blob from the `.note.boredos.app` section of the ELF at `path` and writes it into `*out_metadata`.
|
||||
|
||||
Returns `1` on success, `0` on failure (file not found, no metadata note, or validation failure).
|
||||
|
||||
#### `sys_get_elf_primary_image`
|
||||
|
||||
```c
|
||||
int sys_get_elf_primary_image(const char *path, char *out_path, size_t out_path_size);
|
||||
```
|
||||
|
||||
Convenience wrapper that returns only the first icon path from the metadata. Useful when you just need to display an application icon without allocating a full `boredos_app_metadata_t`.
|
||||
|
||||
Returns `1` and writes a null-terminated VFS path into `out_path` if at least one icon was declared. Returns `0` otherwise.
|
||||
|
||||
### Syscall IDs
|
||||
|
||||
Both functions route through `SYS_SYSTEM` using dedicated command IDs:
|
||||
|
||||
| ID | Macro | Function |
|
||||
|---|---|---|
|
||||
| 76 | `SYSTEM_CMD_GET_ELF_METADATA` | `sys_get_elf_metadata` |
|
||||
| 77 | `SYSTEM_CMD_GET_ELF_PRIMARY_IMAGE` | `sys_get_elf_primary_image` |
|
||||
|
||||
### Caching
|
||||
|
||||
Both calls share the same kernel-side **64-entry FIFO metadata cache** used by the Window Manager and File Explorer. If the metadata for a path has already been read, the result is returned from cache without re-reading the file. Negative results (no metadata) are also cached.
|
||||
|
||||
### Example: reading full metadata
|
||||
|
||||
```c
|
||||
#include "syscall.h"
|
||||
#include "stdio.h"
|
||||
|
||||
void print_app_info(const char *elf_path) {
|
||||
boredos_app_metadata_t meta;
|
||||
if (!sys_get_elf_metadata(elf_path, &meta)) {
|
||||
printf("%s: no metadata\n", elf_path);
|
||||
return;
|
||||
}
|
||||
printf("Name: %s\n", meta.app_name);
|
||||
printf("Description: %s\n", meta.description);
|
||||
printf("Icons (%u):\n", meta.image_count);
|
||||
for (int i = 0; i < (int)meta.image_count; i++) {
|
||||
printf(" [%d] %s\n", i, meta.images[i]);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Example: fetching just the icon path
|
||||
|
||||
```c
|
||||
#include "syscall.h"
|
||||
|
||||
void load_icon_for(const char *elf_path, Image *out_icon) {
|
||||
char icon_path[BOREDOS_APP_METADATA_MAX_IMAGE_PATH];
|
||||
if (sys_get_elf_primary_image(elf_path, icon_path, sizeof(icon_path))) {
|
||||
*out_icon = image_load(icon_path);
|
||||
} else {
|
||||
*out_icon = image_load("/Library/images/icons/colloid/xterm.png"); // fallback
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> The metadata is read **from the VFS**, so the ELF must already be present as a file. The kernel does **not** read metadata from an already-running process image in memory — it re-opens the file via the filesystem.
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
*See also: [`custom_apps.md`](custom_apps.md) for a full tutorial on building and bundling a new application, [`sdk_reference.md`](sdk_reference.md) for an overview of the SDK, and [`syscalls.md`](syscalls.md) for the complete SYSTEM command ID table.*
|
||||
@@ -7,16 +7,18 @@
|
||||
|
||||
This example demonstrates the bare minimum structure of a BoredOS application that outputs text to the standard output (usually the Terminal executing the binary).
|
||||
|
||||
## 📝 Concepts Introduced
|
||||
## Concepts Introduced
|
||||
* Including `stdlib.h` for basic IO.
|
||||
* The `main()` entry point.
|
||||
* Using `printf()` for formatted output.
|
||||
* Declaring app metadata via source annotations.
|
||||
|
||||
---
|
||||
|
||||
## 💻 The Code (`src/userland/cli/hello_world.c`)
|
||||
## The Code (`src/userland/cli/hello_world.c`)
|
||||
|
||||
```c
|
||||
// BOREDOS_APP_DESC: Hello World — a minimal CLI demo.
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
@@ -34,14 +36,15 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
```
|
||||
|
||||
## 🛠️ How it Works
|
||||
## How it Works
|
||||
|
||||
1. **`#include <stdlib.h>`**: We include the SDK's standard library header which gives us access to `printf`.
|
||||
2. **`int main(...)`**: Every process begins execution here (managed transparently by `crt0.asm`).
|
||||
3. **`printf(...)`**: The SDK routes this call internally directly to the `SYS_WRITE` system call, making it available on the terminal.
|
||||
4. **`return 0`**: A successful exit code.
|
||||
5. **`BOREDOS_APP_DESC` / `BOREDOS_APP_ICONS`**: These comment annotations are read by the build system (`gen_userland_note.sh`) and embedded as a `boredos_app_metadata_t` NOTE entry inside the compiled `.elf`. The File Explorer and Desktop use this to display the correct icon. See [`elf_metadata.md`](../elf_metadata.md) for full details.
|
||||
|
||||
## 🚀 Running It
|
||||
## Running It
|
||||
|
||||
If you build the project, you can open the Terminal and type:
|
||||
```sh
|
||||
|
||||
@@ -7,17 +7,19 @@
|
||||
|
||||
This example demonstrates how to create an empty window that stays active on the screen until the user explicitly closes it by clicking the 'X' button.
|
||||
|
||||
## 📝 Concepts Introduced
|
||||
## Concepts Introduced
|
||||
* Including `libui.h` and the event structure.
|
||||
* Creating a `ui_window_t` handle.
|
||||
* Creating an infinite event loop using `ui_get_event()`.
|
||||
* Yielding CPU time to the kernel via `sys_yield()`.
|
||||
* Declaring app metadata via source annotations.
|
||||
|
||||
---
|
||||
|
||||
## 💻 The Code (`src/userland/gui/basic_window.c`)
|
||||
## The Code (`src/userland/gui/basic_window.c`)
|
||||
|
||||
```c
|
||||
// BOREDOS_APP_DESC: Basic Window — a minimal graphical window demo.
|
||||
#include <stdlib.h>
|
||||
#include <libui.h>
|
||||
#include <syscall.h>
|
||||
@@ -65,7 +67,8 @@ int main(void) {
|
||||
2. **The Event Loop**: Graphical programs run forever until closed. The `while (1)` loop serves this purpose.
|
||||
3. **Polling**: `ui_get_event` asks the kernel, "Hey, did the user click my window or press a key since the last time I asked?". It is non-blocking, so it immediately returns `false` if nothing happened.
|
||||
4. **CPU Yielding**: Since we are constantly polling in a tight loop, we call `sys_yield()` at the end of the loop frame. This politely tells the OS scheduler, "I'm done checking for events, go ahead and let another program run for a bit."
|
||||
5. **`BOREDOS_APP_DESC` / `BOREDOS_APP_ICONS`**: Embedded into the `.elf` by the build system as a BoredOS NOTE section. The Window Manager reads this at runtime to render the app's icon on the Desktop and in the File Explorer. See [`elf_metadata.md`](../elf_metadata.md) for full details.
|
||||
|
||||
## 🚀 Running It
|
||||
## Running It
|
||||
|
||||
Launch the Terminal and type `basic_window`. You'll see an empty window appear that you can move around the screen!
|
||||
|
||||
@@ -7,17 +7,20 @@
|
||||
|
||||
This example builds upon the `02_basic_window` guide. It demonstrates how to constantly update the screen to simulate a bouncing square moving freely inside the window bounds.
|
||||
|
||||
## 📝 Concepts Introduced
|
||||
## Concepts Introduced
|
||||
* Maintaining application state across frames (Velocity/Position).
|
||||
* Drawing primitives (`ui_fill_rect`, `ui_draw_string`).
|
||||
* The importance of clearing the screen on a new frame.
|
||||
* Explicitly forcing standard visual updates via `ui_mark_dirty()`.
|
||||
* Declaring app metadata via source annotations.
|
||||
|
||||
---
|
||||
|
||||
## 💻 The Code (`src/userland/gui/bounce.c`)
|
||||
## The Code (`src/userland/gui/bounce.c`)
|
||||
|
||||
```c
|
||||
// BOREDOS_APP_DESC: Bouncing ball animation demo.
|
||||
// BOREDOS_APP_ICONS: /Library/images/icons/colloid/applications-games.png
|
||||
#include <stdlib.h>
|
||||
#include <libui.h>
|
||||
#include <syscall.h>
|
||||
@@ -81,12 +84,13 @@ int main(void) {
|
||||
}
|
||||
```
|
||||
|
||||
## 🛠️ How it Works
|
||||
## How it Works
|
||||
|
||||
1. **State Management**: We store `pos_x`, `pos_y`, `vel_x`, and `vel_y`. These variables represent the "physics" of our system. Notice that they update *outside* the event-checking logic so that the animation runs even if the user isn't clicking the mouse.
|
||||
2. **Screen Clearing**: We *must* fill the screen with black (`ui_draw_rect(wid, 0, 0, W_WIDTH, W_HEIGHT, ...)`). If we don't clear the screen, the red square will leave a permanent trailing smear everywhere it goes!
|
||||
3. **The Double Buffer**: `ui_draw_rect` and `ui_draw_string` do not immediately appear on your monitor. They just color a hidden buffer within the kernel.
|
||||
4. **`ui_mark_dirty`**: This is the crucial command that tells the kernel Window Manager, "I'm done drawing my frame. Can you quickly copy my hidden buffer over to the real screen now?"
|
||||
5. **`BOREDOS_APP_DESC` / `BOREDOS_APP_ICONS`**: Embedded into the compiled `.elf` as a BoredOS NOTE section. The Desktop and File Explorer read this to show the game's icon instead of the generic binary icon. See [`elf_metadata.md`](../elf_metadata.md) for full details.
|
||||
|
||||
> [!WARNING]
|
||||
> Because `sys_yield()`'s pause duration depends heavily on CPU load and how many other processes are running (or QEMU emulation speed), tying physics/movement strictly to loops can make the game run faster on faster computers. Advanced developers will want to calculate delta time (time elapsed since the last frame) for smooth motion.
|
||||
|
||||
@@ -12,12 +12,15 @@ This advanced example demonstrates the steps required to use the raw network sys
|
||||
* Performing DNS lookups manually via `sys_dns_lookup`.
|
||||
* Managing strict TCP flow logic (`sys_tcp_connect`, send, block for receive).
|
||||
* Using the terminal `SYS_WRITE` output for debugging.
|
||||
* Declaring app metadata via source annotations.
|
||||
|
||||
---
|
||||
|
||||
## 💻 The Code (`src/userland/cli/http_get.c`)
|
||||
## The Code (`src/userland/cli/http_get.c`)
|
||||
|
||||
```c
|
||||
// BOREDOS_APP_DESC: HTTP GET client — fetches a webpage over TCP.
|
||||
// BOREDOS_APP_ICONS: /Library/images/icons/colloid/network-wired.png
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syscall.h>
|
||||
@@ -79,14 +82,15 @@ int main(void) {
|
||||
}
|
||||
```
|
||||
|
||||
## 🛠️ How it Works
|
||||
## How it Works
|
||||
|
||||
1. **Network Setup**: First, we must ensure the host machine or QEMU environment gave BoredOS a valid IP address via DHCP. The `sys_network_has_ip()` check prevents our app from hanging trying to route data to nowhere.
|
||||
2. **DNS (`sys_dns_lookup`)**: Since we want to connect to a domain name, not a raw IP, we query the DNS server configured by the OS (which it received via DHCP).
|
||||
3. **Connection (`sys_tcp_connect`)**: We block the application thread while the OS performs the 3-way TCP handshake over port 80.
|
||||
4. **Payload (`sys_tcp_send`)**: We format a compliant HTTP/1.1 payload representing a simple GET request for the root directory `/`.
|
||||
5. **Chunked Receiving (`sys_tcp_recv`)**: The server's response might be larger than our `recv_buf` (512 bytes). Therefore, we loop. `sys_tcp_recv` blocks execution until data arrives. If it returns `0`, the remote server cleanly closed the connection (which happens automatically because we specified `Connection: close` in our request payload!).
|
||||
6. **`BOREDOS_APP_DESC` / `BOREDOS_APP_ICONS`**: Embedded into the compiled `.elf` as a BoredOS NOTE section. The Desktop and File Explorer read this to display the app's icon. See [`elf_metadata.md`](../elf_metadata.md) for full details.
|
||||
|
||||
## 🚀 Running It
|
||||
## Running It
|
||||
|
||||
Make sure QEMU is running with networking enabled. Launch the terminal and type `http_get`. You will see the raw headers and HTML source of the target webpage scroll down the CLI interface!
|
||||
|
||||
251
docs/appdev/inputs_api_(utf8).md
Normal file
@@ -0,0 +1,251 @@
|
||||
# UTF-8 Library — Application Development Guide
|
||||
|
||||
## Overview
|
||||
|
||||
The userland libc provides a lightweight UTF-8 utility module located in:
|
||||
|
||||
- src/userland/libc/utf-8.c
|
||||
- src/userland/libc/utf-8.h
|
||||
|
||||
This module is designed for **direct use in applications** requiring UTF-8 handling. It provides basic primitives for decoding, encoding, and traversing UTF-8 strings safely.
|
||||
|
||||
It is intended for:
|
||||
|
||||
- text rendering
|
||||
- terminal input/output
|
||||
- cursor movement
|
||||
- string processing at the character level
|
||||
|
||||
---
|
||||
|
||||
## Synopsis
|
||||
|
||||
```c
|
||||
#include "utf-8.h"
|
||||
|
||||
uint32_t text_decode_utf8(const char *s, int *advance);
|
||||
int text_encode_utf8(uint32_t cp, char *out);
|
||||
|
||||
const char* text_next_utf8(const char *s);
|
||||
const char* text_prev_utf8(const char *start, const char *s);
|
||||
|
||||
int text_strlen_utf8(const char *s);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Reference
|
||||
|
||||
### text_decode_utf8
|
||||
|
||||
```c
|
||||
uint32_t text_decode_utf8(const char *s, int *advance);
|
||||
```
|
||||
|
||||
Decodes a UTF-8 sequence into a Unicode code point.
|
||||
|
||||
- `s`: pointer to current position in a UTF-8 string
|
||||
- `advance`: receives number of bytes consumed
|
||||
|
||||
Returns:
|
||||
|
||||
- decoded Unicode code point (`uint32_t`)
|
||||
- `0` if input is null or empty
|
||||
- `0xFFFD` for invalid sequences
|
||||
|
||||
---
|
||||
|
||||
### text_encode_utf8
|
||||
|
||||
```c
|
||||
int text_encode_utf8(uint32_t cp, char *out);
|
||||
```
|
||||
|
||||
Encodes a Unicode code point into UTF-8.
|
||||
|
||||
- `cp`: Unicode code point
|
||||
- `out`: buffer receiving encoded bytes
|
||||
|
||||
Returns:
|
||||
|
||||
- number of bytes written (1–4)
|
||||
- writes replacement character if `cp` is invalid
|
||||
|
||||
---
|
||||
|
||||
### text_next_utf8
|
||||
|
||||
```c
|
||||
const char* text_next_utf8(const char *s);
|
||||
```
|
||||
|
||||
Advances to the next UTF-8 character.
|
||||
|
||||
Returns a pointer to the next character boundary.
|
||||
|
||||
---
|
||||
|
||||
### text_prev_utf8
|
||||
|
||||
```c
|
||||
const char* text_prev_utf8(const char *start, const char *s);
|
||||
```
|
||||
|
||||
Moves backward to the previous UTF-8 character.
|
||||
|
||||
- `start`: beginning of the buffer
|
||||
- `s`: current position
|
||||
|
||||
Used for reverse traversal and cursor movement.
|
||||
|
||||
---
|
||||
|
||||
### text_strlen_utf8
|
||||
|
||||
```c
|
||||
int text_strlen_utf8(const char *s);
|
||||
```
|
||||
|
||||
Counts UTF-8 characters (code points), not bytes.
|
||||
|
||||
---
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Iterating over UTF-8 characters
|
||||
|
||||
```c
|
||||
const char *p = text;
|
||||
|
||||
while (*p) {
|
||||
int adv;
|
||||
uint32_t cp = text_decode_utf8(p, &adv);
|
||||
|
||||
/* process cp */
|
||||
|
||||
p += adv;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Cursor movement
|
||||
|
||||
```c
|
||||
cursor = text_next_utf8(cursor);
|
||||
cursor = text_prev_utf8(buffer_start, cursor);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Encoding a character
|
||||
|
||||
```c
|
||||
char out[4];
|
||||
int len = text_encode_utf8(0x20AC, out);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Backspace handling
|
||||
|
||||
```c
|
||||
char *prev = (char*)text_prev_utf8(buffer, cursor);
|
||||
cursor = prev;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
### UTF-8 Encoding
|
||||
|
||||
The implementation supports:
|
||||
|
||||
- 1 byte: `0x00 – 0x7F`
|
||||
- 2 bytes: `0x80 – 0x7FF`
|
||||
- 3 bytes: `0x800 – 0xFFFF`
|
||||
- 4 bytes: `0x10000 – 0x10FFFF`
|
||||
|
||||
---
|
||||
|
||||
### Replacement Character
|
||||
|
||||
Invalid sequences are replaced with:
|
||||
|
||||
- code point: `0xFFFD`
|
||||
- UTF-8 encoding: `0xEF 0xBF 0xBD`
|
||||
|
||||
---
|
||||
### UTF-8 Byte Structure
|
||||
|
||||
The following diagram illustrates how UTF-8 bytes are structured, including
|
||||
ASCII, continuation bytes, and multi-byte sequence headers:
|
||||
|
||||
<img width="815" height="1003" alt="image" src="https://github.com/user-attachments/assets/0d289a94-6037-4039-87a3-125c0c0e83d0" />
|
||||
<sub>Source: <a href="https://www.youtube.com/watch?v=vpSkBV5vydg">Nic Barker — "UTF-8, Explained Simply"</a> (YouTube)</sub>
|
||||
|
||||
---
|
||||
|
||||
### Control Signals
|
||||
|
||||
Some decoded code points correspond to control signals instead of printable characters.
|
||||
|
||||
ASCII control range:
|
||||
|
||||
- `0x00 – 0x1F`
|
||||
|
||||
Examples:
|
||||
|
||||
- `0x08` → Backspace
|
||||
- `0x09` → Tab
|
||||
- `0x0A` → Line Feed
|
||||
- `0x0D` → Carriage Return
|
||||
- `0x1B` → Escape
|
||||
|
||||
These are typically interpreted by:
|
||||
|
||||
- terminal logic
|
||||
- shell input handling
|
||||
- system interfaces
|
||||
|
||||
---
|
||||
|
||||
### Non-ASCII Characters
|
||||
|
||||
Characters outside the ASCII range (`0x00 – 0x7F`) are encoded using multi-byte UTF-8 sequences.
|
||||
|
||||
Examples:
|
||||
|
||||
- 'é' → `0xC3 0xA9`
|
||||
- '€' → `0xE2 0x82 0xAC`
|
||||
|
||||
Decoded values:
|
||||
|
||||
- 'é' → `U+00E9`
|
||||
- '€' → `U+20AC`
|
||||
|
||||
---
|
||||
|
||||
### Modifiers and Layout
|
||||
|
||||
Character output depends on:
|
||||
|
||||
- keyboard layout
|
||||
- modifier keys (Shift, Ctrl, AltGr)
|
||||
|
||||
Example:
|
||||
|
||||
- `KEY_E` → 'e'
|
||||
- `KEY_E + SHIFT` → 'E'
|
||||
- `KEY_E + AltGr` → '€'
|
||||
|
||||
---
|
||||
|
||||
## Also worth watching
|
||||
|
||||
If you want to dive deeper or simply get a better intuitive understanding of UTF-8, the video below is highly recommended:
|
||||
|
||||
[Nic Barker — "UTF-8, Explained Simply"](https://www.youtube.com/watch?v=vpSkBV5vydg)
|
||||
|
||||
|
||||
184
docs/appdev/libc_reference.md
Normal file
@@ -0,0 +1,184 @@
|
||||
# libc Reference
|
||||
|
||||
This page documents the current BoredOS userland libc surface from `src/userland/libc/`.
|
||||
|
||||
BoredOS libc is a compact implementation focused on the APIs used by in-tree apps. It is not a full glibc replacement.
|
||||
|
||||
## Header Overview
|
||||
|
||||
| Header | Focus |
|
||||
|---|---|
|
||||
| `stdlib.h` | allocation, conversion, process helpers |
|
||||
| `string.h` | memory/string primitives |
|
||||
| `stdio.h` | `FILE*` and formatted I/O |
|
||||
| `unistd.h` | POSIX-like fd/process calls |
|
||||
| `fcntl.h` | open/fcntl flags, `dup`, `pipe` |
|
||||
| `input.h` | keyboard keycode constants |
|
||||
| `signal.h` | signal handlers and masks |
|
||||
| `sys/stat.h` | `stat`/`fstat` and file mode bits |
|
||||
| `sys/types.h` | core typedefs (`pid_t`, `ssize_t`, ...) |
|
||||
| `sys/wait.h` | `waitpid` and wait macros |
|
||||
| `errno.h` | errno values |
|
||||
| `time.h` | time/date utilities |
|
||||
| `math.h` | floating-point math helpers |
|
||||
| `libui.h` | GUI/window drawing API |
|
||||
|
||||
## stdlib.h
|
||||
|
||||
Implemented core functions:
|
||||
- Memory: `malloc`, `free`, `calloc`, `realloc`
|
||||
- Memory aliases: `memset`, `memcpy`
|
||||
- Conversions: `atoi`, `itoa`, `strtod`, `abs`
|
||||
- Output: `puts`, `printf`
|
||||
- Process/environment: `exit`, `_exit`, `sleep`, `chdir`, `getcwd`, `access`, `system`, `getenv`, `abort`
|
||||
|
||||
Notes:
|
||||
- `sleep` is millisecond-based and maps to kernel sleep command.
|
||||
- `system` is a stub-style helper in this libc, not a full shell launcher equivalent.
|
||||
|
||||
## string.h
|
||||
|
||||
Implemented C string/memory set includes:
|
||||
- Memory: `memmove`, `memcmp`, `memcpy`, `memset`, `memchr`
|
||||
- Search: `strchr`, `strrchr`, `strpbrk`, `strstr`
|
||||
- Span: `strspn`, `strcspn`
|
||||
- Compare: `strcmp`, `strncmp`, `strcasecmp`, `strncasecmp`, `strcoll`
|
||||
- Build/copy: `strlen`, `strcpy`, `strcat`, `strdup`
|
||||
- Errors: `strerror`
|
||||
|
||||
## stdio.h
|
||||
|
||||
Provided API includes:
|
||||
- Stream open/close: `fopen`, `freopen`, `fclose`
|
||||
- Read/write: `fread`, `fwrite`, `fgets`, `fputs`, `getc`, `fputc`, `putchar`
|
||||
- Positioning: `fseek`, `ftell`, `filelength`
|
||||
- Formatting: `fprintf`, `vfprintf`, `snprintf`, `vsnprintf`, `sprintf`, `sscanf`
|
||||
- Stream state: `feof`, `ferror`, `clearerr`, `fflush`, `ungetc`
|
||||
- Temp/filesystem helpers: `remove`, `rename`, `tmpfile`, `tmpnam`
|
||||
|
||||
## unistd.h
|
||||
|
||||
Provided POSIX-like interfaces:
|
||||
- FD I/O: `read`, `write`, `close`, `lseek`, `isatty`
|
||||
- Filesystem: `unlink`
|
||||
- Exec family: `execv`, `execve`, `execvp`, `execl`, `execlp`, `execle`
|
||||
- Process wait: `waitpid`
|
||||
|
||||
Also defines:
|
||||
- `SEEK_SET`, `SEEK_CUR`, `SEEK_END`
|
||||
- `F_OK`, `X_OK`, `W_OK`, `R_OK`
|
||||
|
||||
## fcntl.h
|
||||
|
||||
Flags and fd control:
|
||||
- Open flags: `O_RDONLY`, `O_WRONLY`, `O_RDWR`, `O_CREAT`, `O_EXCL`, `O_TRUNC`, `O_APPEND`, `O_NONBLOCK`, `O_ACCMODE`
|
||||
- fcntl ops: `F_GETFL`, `F_SETFL`
|
||||
- FD flag: `FD_CLOEXEC` (declared)
|
||||
|
||||
Functions:
|
||||
- `open`
|
||||
- `fcntl`
|
||||
- `dup`
|
||||
- `dup2`
|
||||
- `pipe`
|
||||
|
||||
## input.h
|
||||
|
||||
Defines keyboard/control keycode constants used by apps that process
|
||||
|
||||
Current constants include:
|
||||
- Arrow keys: `KEY_UP`, `KEY_DOWN`, `KEY_LEFT`, `KEY_RIGHT`
|
||||
- Controls: `KEY_ENTER`, `KEY_BACKSPACE`, `KEY_ESCAPE`, `KEY_SPACE`, `KEY_ALT`, `KEY_CTRL_L`, `KEY_TAB`
|
||||
|
||||
## signal.h
|
||||
|
||||
Current signal surface:
|
||||
- Basic handler API: `signal`, `raise`, `kill`
|
||||
- POSIX-style API: `sigaction`, `sigprocmask`, `sigpending`
|
||||
- Types: `sighandler_t`, `sigset_t`, `struct sigaction`
|
||||
- Constants: `SIGINT`, `SIGTERM`, `SIGKILL`, `SIG_DFL`, `SIG_IGN`, `SIG_ERR`
|
||||
- Mask ops: `SIG_BLOCK`, `SIG_UNBLOCK`, `SIG_SETMASK`
|
||||
- Action flags: `SA_RESTART`, `SA_NODEFER`, `SA_RESETHAND`
|
||||
|
||||
## ctype.h
|
||||
|
||||
Character classification and case conversion:
|
||||
- `isdigit`, `isalpha`, `isalnum`, `isspace`
|
||||
- `isupper`, `islower`, `isxdigit`
|
||||
- `iscntrl`, `ispunct`, `isprint`, `isgraph`
|
||||
- `tolower`, `toupper`
|
||||
|
||||
## locale.h
|
||||
|
||||
Locale stubs and conventions:
|
||||
- `struct lconv`
|
||||
- `setlocale`
|
||||
- `localeconv`
|
||||
- `LC_ALL`
|
||||
|
||||
## limits.h
|
||||
|
||||
Integer and floating-point limit macros:
|
||||
- `CHAR_BIT`, `INT_MIN`, `INT_MAX`, `UINT_MAX`
|
||||
- `LONG_MIN`, `LONG_MAX`, `ULONG_MAX`
|
||||
- `LLONG_MIN`, `LLONG_MAX`, `ULLONG_MAX`
|
||||
- `DBL_MAX`
|
||||
|
||||
## setjmp.h
|
||||
|
||||
Non-local jump support:
|
||||
- `jmp_buf`
|
||||
- `setjmp`
|
||||
- `longjmp`
|
||||
|
||||
## time.h
|
||||
|
||||
Time/date APIs and types:
|
||||
- Types: `time_t`, `clock_t`, `struct tm`
|
||||
- Constants: `CLOCKS_PER_SEC`
|
||||
- Functions: `time`, `clock`, `localtime`, `gmtime`, `strftime`, `mktime`
|
||||
|
||||
## libui.h
|
||||
|
||||
Windowing and drawing API used by GUI apps:
|
||||
- Window/event: `ui_window_create`, `ui_get_event`, `ui_mark_dirty`, `ui_window_set_title`, `ui_window_set_resizable`
|
||||
- Drawing: `ui_draw_rect`, `ui_draw_rounded_rect_filled`, `ui_draw_string`, `ui_draw_string_bitmap`, `ui_draw_image`
|
||||
- Text metrics/scaled text: `ui_get_string_width`, `ui_get_font_height`, `ui_draw_string_scaled`, `ui_draw_string_scaled_sloped`, `ui_get_string_width_scaled`, `ui_get_font_height_scaled`
|
||||
- System UI helpers: `ui_get_screen_size`, `ui_set_font`
|
||||
|
||||
## sys/stat.h and sys/types.h
|
||||
|
||||
`sys/stat.h` provides:
|
||||
- `struct stat`
|
||||
- `stat`, `fstat`, `mkdir`
|
||||
- mode/type macros (`S_IFREG`, `S_IFDIR`, `S_ISREG`, `S_ISDIR`, permission bits)
|
||||
|
||||
Note:
|
||||
- `access` is declared in `stdlib.h` in this libc.
|
||||
|
||||
`sys/types.h` provides:
|
||||
- `ssize_t`, `off_t`, `mode_t`, `pid_t`, `uid_t`, `gid_t`
|
||||
|
||||
## sys/wait.h
|
||||
|
||||
- `waitpid`
|
||||
- `WNOHANG`
|
||||
- status macros: `WEXITSTATUS`, `WIFEXITED`, `WTERMSIG`, `WIFSIGNALED`
|
||||
|
||||
## errno.h
|
||||
|
||||
Defined errno values include:
|
||||
- Generic/input: `EINVAL`, `EDOM`, `ERANGE`, `E2BIG`
|
||||
- File/path: `ENOENT`, `EEXIST`, `EISDIR`, `ENOTDIR`, `EBADF`
|
||||
- Runtime/state: `ENOMEM`, `EACCES`, `EIO`, `EAGAIN`, `EINTR`, `ECHILD`, `EBUSY`, `EPIPE`, `ESPIPE`, `ENOSYS`, `ENOTSUP`
|
||||
|
||||
## Relationship to raw syscalls
|
||||
|
||||
- libc high-level I/O and process APIs are backed by wrappers in `src/userland/libc/syscall.c`.
|
||||
- Full syscall command IDs and multiplexer details are documented in `docs/appdev/syscalls.md`.
|
||||
|
||||
## Practical Guidance
|
||||
|
||||
- Prefer libc APIs (`open`, `read`, `write`, `waitpid`, `sigaction`) for portability inside BoredOS userland.
|
||||
- Use raw wrapper calls from `syscall.h` only for capabilities that do not yet have higher-level libc wrappers.
|
||||
- Avoid numeric `sys_system(...)` command literals in app code; use `SYSTEM_CMD_*` macros.
|
||||
@@ -1,214 +1,52 @@
|
||||
<div align="center">
|
||||
<h1>Userland SDK Reference</h1>
|
||||
<p><em>Comprehensive manual for custom libc and system calls in BoredOS.</em></p>
|
||||
<p><em>Overview and entry point for BoredOS userland development.</em></p>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
BoredOS provides a custom `libc` implementation necessary for writing userland applications (`.elf` binaries). By avoiding a full-blown standard library like `glibc`, the OS ensures a minimal executable footprint tailored strictly to the existing kernel features.
|
||||
BoredOS provides a compact userland SDK for building `.elf` applications.
|
||||
This page is the high-level map; detailed API references now live in dedicated pages.
|
||||
|
||||
All headers are located in `src/userland/libc/` (standard functions) and `src/wm/` (UI and widgets).
|
||||
- `stdlib.h`: Memory, strings, and basic I/O.
|
||||
- `math.h`: Freestanding floating-point math library.
|
||||
- `libui.h`: Core window and drawing API.
|
||||
- `libwidget.h`: High-level UI components.
|
||||
## SDK Structure
|
||||
|
||||
## Standard Library (`stdlib.h` & `string.h`)
|
||||
Primary headers are in `src/userland/libc/` and UI helpers are in `src/wm/`.
|
||||
|
||||
The standard library wrappers provide memory management, string manipulation, and basic IO formatting without needing direct syscalls.
|
||||
- `stdlib.h`, `string.h`, `stdio.h`, `unistd.h`: core libc surface
|
||||
- `syscall.h`: raw syscall wrappers and command constants
|
||||
- `libui.h`: window creation, drawing, and event polling
|
||||
- `libwidget.h`: higher-level reusable widgets
|
||||
- `math.h`: freestanding math helpers
|
||||
|
||||
### Memory Allocation
|
||||
* `void* malloc(size_t size);` - Allocate a block of memory on the heap.
|
||||
* `void free(void* ptr);` - Free a previously allocated memory block.
|
||||
* `void* calloc(size_t nmemb, size_t size);` - Allocate and zero-out a block of memory for an array.
|
||||
* `void* realloc(void* ptr, size_t size);` - Resize an existing memory block.
|
||||
## Detailed References
|
||||
|
||||
### Memory Manipulation (`string.h`)
|
||||
* `void* memset(void *s, int c, size_t n);` - Fill a block of memory with a specific byte.
|
||||
* `void* memcpy(void *dest, const void *src, size_t n);` - Copy memory from source to destination.
|
||||
* `void* memmove(void *dest, const void *src, size_t n);` - Safely copy overlapping memory blocks.
|
||||
* `int memcmp(const void *s1, const void *s2, size_t n);` - Compare two memory blocks.
|
||||
- [`libc Reference`](libc_reference.md): current libc headers and implemented APIs
|
||||
- [`Syscalls`](syscalls.md): syscall numbers, FS/SYSTEM command IDs, and wrappers
|
||||
- [`UI API`](ui_api.md): drawing and event APIs
|
||||
- [`Widget API`](widget_api.md): common widgets and interaction helpers
|
||||
|
||||
### String Utilities
|
||||
* `size_t strlen(const char *s);` - Get the length of a string.
|
||||
* `int strcmp(const char *s1, const char *s2);` - Compare two strings lexicographically.
|
||||
* `char* strcpy(char *dest, const char *src);` - Copy a string to a destination buffer.
|
||||
* `char* strcat(char *dest, const char *src);` - Concatenate two strings.
|
||||
|
||||
### Conversion and Formatting
|
||||
* `int atoi(const char *nptr);` - String to integer conversion.
|
||||
* `void itoa(int n, char *buf);` - Integer to string conversion.
|
||||
|
||||
### Input / Output
|
||||
* `void puts(const char *s);` - Print a string followed by a newline to the standard output.
|
||||
* `void printf(const char *fmt, ...);` - Formatted print to standard output (supports `%d`, `%s`, `%x`, etc.).
|
||||
|
||||
### Process Control
|
||||
* `void exit(int status);` - Terminate the current process.
|
||||
* `void sleep(int ms);` - Pause execution for a specified number of milliseconds.
|
||||
|
||||
---
|
||||
|
||||
## Math Library (`math.h`)
|
||||
|
||||
BoredOS ships a freestanding floating-point math library in `libc/math.h`. It uses pure arithmetic — Taylor series, Newton-Raphson, and range-reduction — with no dependency on a host `libm` or hardware math intrinsics. It is automatically linked into every userland ELF.
|
||||
## Typical Include Set
|
||||
|
||||
```c
|
||||
#include "math.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <syscall.h>
|
||||
```
|
||||
|
||||
### Constants
|
||||
For GUI apps:
|
||||
|
||||
| Constant | Value | Description |
|
||||
|---|---|---|
|
||||
| `M_PI` | 3.14159… | π |
|
||||
| `M_E` | 2.71828… | Euler's number |
|
||||
| `M_LN2` | 0.69315… | Natural log of 2 |
|
||||
| `M_SQRT2` | 1.41421… | √2 |
|
||||
| `HUGE_VAL` | ~+∞ | Overflow sentinel |
|
||||
|
||||
### Functions
|
||||
|
||||
#### Absolute value & remainder
|
||||
* `double fabs(double x);` — Absolute value.
|
||||
* `double fmod(double x, double y);` — Floating-point remainder. Returns `0` when `y == 0`.
|
||||
|
||||
#### Rounding
|
||||
* `double floor(double x);` — Largest integer ≤ x.
|
||||
* `double ceil(double x);` — Smallest integer ≥ x.
|
||||
|
||||
#### Trigonometry *(arguments in radians)*
|
||||
* `double sin(double x);` — Sine. Range-reduced to `[-π, π]` then computed via 8-term Taylor series.
|
||||
* `double cos(double x);` — Cosine. Computed via `sin(x + π/2)`.
|
||||
* `double tan(double x);` — Tangent. Returns sentinel `1e15` near poles.
|
||||
|
||||
#### Exponential & logarithm
|
||||
* `double sqrt(double x);` — Square root via Newton-Raphson (25 iterations). Returns `0` for `x ≤ 0`.
|
||||
* `double log(double x);` — Natural logarithm (ln). Returns `-1e30` for `x ≤ 0`.
|
||||
* `double log2(double x);` — Base-2 logarithm.
|
||||
* `double log10(double x);` — Base-10 logarithm.
|
||||
* `double exp(double x);` — e^x. Saturates to `1e300` for `x > 700`, `0` for `x < -700`.
|
||||
* `double pow(double base, double exponent);` — General power. Integer exponents use fast binary exponentiation; fractional exponents use `exp(e * log(b))`.
|
||||
|
||||
#### Hyperbolic
|
||||
* `double sinh(double x);` — Hyperbolic sine.
|
||||
* `double cosh(double x);` — Hyperbolic cosine.
|
||||
* `double tanh(double x);` — Hyperbolic tangent.
|
||||
|
||||
#### Utility
|
||||
* `double hypot(double x, double y);` — `sqrt(x² + y²)` without intermediate overflow.
|
||||
* `double fmin(double a, double b);` — Minimum of two values.
|
||||
* `double fmax(double a, double b);` — Maximum of two values.
|
||||
* `double fclamp(double x, double lo, double hi);` — Clamps `x` into `[lo, hi]`.
|
||||
|
||||
> [!NOTE]
|
||||
> The implementation file is named `libc/libmath.c` (not `libc/math.c`) to avoid a name collision with the `math` CLI calculator app in userland. The public header is still included as `#include "math.h"`.
|
||||
|
||||
For advanced operations, `syscall.h` provides direct wrappers into the kernel.
|
||||
|
||||
### Process & System Info
|
||||
* `void sys_exit(int status);` - Raw exit syscall.
|
||||
* `int sys_write(int fd, const char *buf, int len);` - Write to a file descriptor (usually fd 1 for stdout).
|
||||
* `void* sys_sbrk(int incr);` - Expand or shrink the process data segment (used internally by `malloc`).
|
||||
* `void sys_kill(int pid);` - Send a kill signal to a process.
|
||||
* `void sys_yield(void);` - Yield the remainder of the process's timeslice to the scheduler.
|
||||
* `int sys_system(int cmd, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4);` - Execute a privileged system command (e.g., reboot, shutdown, beep).
|
||||
* `int sys_get_os_info(os_info_t *info);` - Populate an `os_info_t` struct with version and environment details.
|
||||
* `uint64_t sys_get_shell_config(const char *key);` - Retrieve internal shell configuration values.
|
||||
* `void sys_set_text_color(uint32_t color);` - Set the raw CLI text output color.
|
||||
|
||||
### File System API (VFS)
|
||||
Interacting with files and directories using the Virtual File System.
|
||||
* `int sys_open(const char *path, const char *mode);` - Open a file, returning a file descriptor.
|
||||
* `int sys_read(int fd, void *buf, uint32_t len);` - Read from an open file.
|
||||
* `int sys_write_fs(int fd, const void *buf, uint32_t len);` - Write to an open file.
|
||||
* `void sys_close(int fd);` - Close an open file descriptor.
|
||||
* `int sys_seek(int fd, int offset, int whence);` - Reposition the file offset.
|
||||
* `uint32_t sys_tell(int fd);` - Get the current file offset.
|
||||
* `uint32_t sys_size(int fd);` - Get the total file size.
|
||||
* `int sys_delete(const char *path);` - Delete a file.
|
||||
* `int sys_mkdir(const char *path);` - Create a new directory.
|
||||
* `int sys_exists(const char *path);` - Check if a path exists on the filesystem.
|
||||
* `int sys_getcwd(char *buf, int size);` - Get the current working directory string.
|
||||
* `int sys_chdir(const char *path);` - Change the current working directory.
|
||||
* `int sys_list(const char *path, FAT32_FileInfo *entries, int max_entries);` - List directory contents into an array of `FAT32_FileInfo` structs.
|
||||
* `int sys_get_file_info(const char *path, FAT32_FileInfo *info);` - Retrieve metadata for a specific file.
|
||||
|
||||
### Networking Stack API
|
||||
BoredOS includes lwIP for hardware TCP/UDP networking.
|
||||
|
||||
#### Configuration and Status
|
||||
* `int sys_network_init(void);` - Initialize the network stack.
|
||||
* `int sys_network_is_initialized(void);` - Check stack status.
|
||||
* `int sys_network_dhcp_acquire(void);` - Request an IP configuration from a DHCP server.
|
||||
* `int sys_network_has_ip(void);` - Check if the system has a valid IP address.
|
||||
* `int sys_network_get_mac(net_mac_address_t *mac);` - Get the physical MAC address of the NIC.
|
||||
* `int sys_network_get_nic_name(char *name_out);` - Get the name of the active network interface card.
|
||||
* `int sys_network_get_ip(net_ipv4_address_t *ip);` - Get current local IPv4 address.
|
||||
* `int sys_network_set_ip(const net_ipv4_address_t *ip);` - Manually assign a static IP.
|
||||
* `int sys_network_get_gateway(net_ipv4_address_t *ip);` - Get the default gateway IP.
|
||||
* `int sys_network_get_dns(net_ipv4_address_t *ip);` - Get the primary DNS server IP.
|
||||
* `int sys_set_dns_server(const net_ipv4_address_t *ip);` - Set the primary DNS server.
|
||||
* `int sys_get_dns_server(net_ipv4_address_t *ip);` - Retrieve configured DNS server.
|
||||
* `int sys_network_get_stat(int stat_type);` - Get network statistics (packets in/out, drops, etc.).
|
||||
* `void sys_network_force_unlock(void);` - Force release of network stack locks (use with caution).
|
||||
|
||||
#### Communication
|
||||
* `int sys_icmp_ping(const net_ipv4_address_t *dest_ip);` - Send an ICMP echo request.
|
||||
* `int sys_udp_send(const net_ipv4_address_t *dest_ip, uint16_t dest_port, uint16_t src_port, const void *data, size_t data_len);` - Send a raw UDP datagram.
|
||||
* `int sys_dns_lookup(const char *name, net_ipv4_address_t *out_ip);` - Resolve a hostname to an IPv4 address.
|
||||
* `int sys_tcp_connect(const net_ipv4_address_t *ip, uint16_t port);` - Establish a TCP connection to a remote host.
|
||||
* `int sys_tcp_send(const void *data, size_t len);` - Send data over an active TCP socket.
|
||||
* `int sys_tcp_recv(void *buf, size_t max_len);` - Receive data from a TCP socket (blocking).
|
||||
* `int sys_tcp_recv_nb(void *buf, size_t max_len);` - Receive data from a TCP socket (non-blocking).
|
||||
* `int sys_tcp_close(void);` - Close the active TCP socket.
|
||||
|
||||
---
|
||||
|
||||
## Core Data Structures
|
||||
|
||||
### `os_info_t`
|
||||
Contains detailed build and version information about the OS.
|
||||
```c
|
||||
typedef struct {
|
||||
char os_name[64];
|
||||
char os_version[64];
|
||||
char os_codename[64];
|
||||
char kernel_name[64];
|
||||
char kernel_version[64];
|
||||
char build_date[64];
|
||||
char build_time[64];
|
||||
char build_arch[64];
|
||||
} os_info_t;
|
||||
#include <libui.h>
|
||||
#include <libwidget.h>
|
||||
```
|
||||
|
||||
### `FAT32_FileInfo`
|
||||
Represents a filesystem entry.
|
||||
```c
|
||||
typedef struct {
|
||||
char name[256];
|
||||
uint32_t size;
|
||||
uint8_t is_directory;
|
||||
uint32_t start_cluster;
|
||||
uint16_t write_date;
|
||||
uint16_t write_time;
|
||||
} FAT32_FileInfo;
|
||||
```
|
||||
## Build and Packaging
|
||||
|
||||
- Add app source under `src/userland/` (CLI, GUI, or games subfolder).
|
||||
- Ensure it is included in the userland build rules/targets.
|
||||
- Build from repo root with `make`.
|
||||
- Built binaries are copied into initrd under `/bin` by the top-level `Makefile`.
|
||||
|
||||
### `ProcessInfo`
|
||||
Provides status information for an active process.
|
||||
```c
|
||||
typedef struct {
|
||||
uint32_t pid;
|
||||
char name[64];
|
||||
uint64_t ticks;
|
||||
size_t used_memory;
|
||||
} ProcessInfo;
|
||||
```
|
||||
|
||||
### IP / MAC Addresses
|
||||
Wrappers for raw byte arrays.
|
||||
```c
|
||||
typedef struct { uint8_t bytes[6]; } net_mac_address_t;
|
||||
typedef struct { uint8_t bytes[4]; } net_ipv4_address_t;
|
||||
```
|
||||
|
||||
154
docs/appdev/syscalls.md
Normal file
@@ -0,0 +1,154 @@
|
||||
# Syscall Reference
|
||||
|
||||
This page documents the current syscall surface in BoredOS as implemented in:
|
||||
- `src/sys/syscall.h` (kernel command IDs)
|
||||
- `src/userland/libc/syscall.h` (userland wrappers)
|
||||
|
||||
Use libc wrappers when possible instead of calling raw syscall numbers directly.
|
||||
|
||||
## Top-Level Syscall Numbers
|
||||
|
||||
| Number | Name | Purpose |
|
||||
|---|---|---|
|
||||
| 0 | `SYS_EXIT` (userland header) | Terminate current process |
|
||||
| 1 | `SYS_WRITE` | Write to stdout/tty path |
|
||||
| 3 | `SYS_GUI` | Window manager and drawing commands |
|
||||
| 4 | `SYS_FS` | Filesystem and fd commands |
|
||||
| 5 | `SYS_SYSTEM` | System-wide command multiplexer |
|
||||
| 9 | `SYS_SBRK` (userland header) | Heap break management |
|
||||
| 10 | `SYS_KILL` (userland header) | Kill process by PID |
|
||||
| 60 | `SYS_EXIT` (kernel header) | Internal kernel syscall number map |
|
||||
|
||||
Notes:
|
||||
- Some numbers differ between kernel and userland headers for historical reasons. For app code, rely on wrapper functions in `src/userland/libc/syscall.c`.
|
||||
- `SYS_GUI`, `SYS_FS`, and `SYS_SYSTEM` are command multiplexers.
|
||||
|
||||
## FS Command IDs (`SYS_FS`)
|
||||
|
||||
| ID | Macro | Meaning |
|
||||
|---|---|---|
|
||||
| 1 | `FS_CMD_OPEN` | Open file |
|
||||
| 2 | `FS_CMD_READ` | Read from fd |
|
||||
| 3 | `FS_CMD_WRITE` | Write to fd |
|
||||
| 4 | `FS_CMD_CLOSE` | Close fd |
|
||||
| 5 | `FS_CMD_SEEK` | Seek in file |
|
||||
| 6 | `FS_CMD_TELL` | Current offset |
|
||||
| 7 | `FS_CMD_LIST` | Directory listing |
|
||||
| 8 | `FS_CMD_DELETE` | Delete file |
|
||||
| 9 | `FS_CMD_SIZE` | File size |
|
||||
| 10 | `FS_CMD_MKDIR` | Create directory |
|
||||
| 11 | `FS_CMD_EXISTS` | Path exists check |
|
||||
| 12 | `FS_CMD_GETCWD` | Get cwd |
|
||||
| 13 | `FS_CMD_CHDIR` | Change cwd |
|
||||
| 14 | `FS_CMD_GET_INFO` | File metadata |
|
||||
| 15 | `FS_CMD_DUP` | `dup` fd |
|
||||
| 16 | `FS_CMD_DUP2` | `dup2` fd |
|
||||
| 17 | `FS_CMD_PIPE` | Create pipe |
|
||||
| 18 | `FS_CMD_FCNTL` | `fcntl` flags ops |
|
||||
|
||||
## SYSTEM Command IDs (`SYS_SYSTEM`)
|
||||
|
||||
### Desktop and display
|
||||
|
||||
| ID | Macro | Meaning |
|
||||
|---|---|---|
|
||||
| 1 | `SYSTEM_CMD_SET_BG_COLOR` | Set desktop background color |
|
||||
| 2 | `SYSTEM_CMD_SET_BG_PATTERN` | Set desktop background pattern |
|
||||
| 3 | `SYSTEM_CMD_SET_WALLPAPER` | Legacy wallpaper command slot |
|
||||
| 4 | `SYSTEM_CMD_SET_DESKTOP_PROP` | Set desktop behavior property |
|
||||
| 5 | `SYSTEM_CMD_SET_MOUSE_SPEED` | Set mouse speed |
|
||||
| 7 | `SYSTEM_CMD_GET_DESKTOP_PROP` | Get desktop property |
|
||||
| 8 | `SYSTEM_CMD_GET_MOUSE_SPEED` | Get mouse speed |
|
||||
| 9 | `SYSTEM_CMD_GET_WALLPAPER_THUMB` | Legacy wallpaper thumb slot |
|
||||
| 10 | `SYSTEM_CMD_CLEAR_SCREEN` | Clear text console |
|
||||
| 29 | `SYSTEM_CMD_SET_TEXT_COLOR` | Set console text color |
|
||||
| 31 | `SYSTEM_CMD_SET_WALLPAPER_PATH` | Set wallpaper from path |
|
||||
| 40 | `SYSTEM_CMD_SET_FONT` | Set active font |
|
||||
| 47 | `SYSTEM_CMD_SET_RESOLUTION` | Set display mode |
|
||||
|
||||
### Time, power, and system state
|
||||
|
||||
| ID | Macro | Meaning |
|
||||
|---|---|---|
|
||||
| 11 | `SYSTEM_CMD_RTC_GET` | Read RTC datetime |
|
||||
| 12 | `SYSTEM_CMD_REBOOT` | Reboot machine |
|
||||
| 13 | `SYSTEM_CMD_SHUTDOWN` | Power off machine |
|
||||
| 14 | `SYSTEM_CMD_BEEP` | PC speaker beep |
|
||||
| 15 | `SYSTEM_CMD_GET_MEM_INFO` | Return total/used memory |
|
||||
| 16 | `SYSTEM_CMD_GET_TICKS` | Return scheduler/WM tick count |
|
||||
| 28 | `SYSTEM_CMD_GET_SHELL_CONFIG` | Read shell config value |
|
||||
| 32 | `SYSTEM_CMD_RTC_SET` | Set RTC datetime |
|
||||
| 41 | `SYSTEM_CMD_SET_RAW_MODE` | Terminal raw-mode control |
|
||||
| 43 | `SYSTEM_CMD_YIELD` | Yield scheduler timeslice |
|
||||
| 46 | `SYSTEM_CMD_SLEEP` | Sleep current process |
|
||||
|
||||
### Network
|
||||
|
||||
| ID | Macro | Meaning |
|
||||
|---|---|---|
|
||||
| 6 | `SYSTEM_CMD_NETWORK_INIT` | Init networking |
|
||||
| 17 | `SYSTEM_CMD_PCI_LIST` | PCI device list access |
|
||||
| 18 | `SYSTEM_CMD_NETWORK_DHCP` | DHCP acquire |
|
||||
| 19 | `SYSTEM_CMD_NETWORK_GET_MAC` | Read NIC MAC |
|
||||
| 20 | `SYSTEM_CMD_NETWORK_GET_IP` | Read IPv4 |
|
||||
| 21 | `SYSTEM_CMD_NETWORK_SET_IP` | Set static IPv4 |
|
||||
| 22 | `SYSTEM_CMD_UDP_SEND` | Send UDP packet |
|
||||
| 23 | `SYSTEM_CMD_NETWORK_GET_STATS` | Network stats |
|
||||
| 24 | `SYSTEM_CMD_NETWORK_GET_GATEWAY` | Read gateway |
|
||||
| 25 | `SYSTEM_CMD_NETWORK_GET_DNS` | Read DNS server |
|
||||
| 26 | `SYSTEM_CMD_ICMP_PING` | ICMP ping |
|
||||
| 27 | `SYSTEM_CMD_NETWORK_IS_INIT` | Network initialized flag |
|
||||
| 30 | `SYSTEM_CMD_NETWORK_HAS_IP` | Has IPv4 address flag |
|
||||
| 33 | `SYSTEM_CMD_TCP_CONNECT` | TCP connect |
|
||||
| 34 | `SYSTEM_CMD_TCP_SEND` | TCP send |
|
||||
| 35 | `SYSTEM_CMD_TCP_RECV` | TCP recv (blocking) |
|
||||
| 36 | `SYSTEM_CMD_TCP_CLOSE` | TCP close |
|
||||
| 37 | `SYSTEM_CMD_DNS_LOOKUP` | DNS lookup |
|
||||
| 38 | `SYSTEM_CMD_SET_DNS` | Set DNS server |
|
||||
| 39 | `SYSTEM_CMD_NET_UNLOCK` | Force net lock release |
|
||||
| 42 | `SYSTEM_CMD_TCP_RECV_NB` | TCP recv (non-blocking) |
|
||||
| 48 | `SYSTEM_CMD_NETWORK_GET_NIC_NAME` | NIC name |
|
||||
|
||||
### Process, tty, signals
|
||||
|
||||
| ID | Macro | Meaning |
|
||||
|---|---|---|
|
||||
| 50 | `SYSTEM_CMD_PARALLEL_RUN` | Dispatch parallel job |
|
||||
| 60 | `SYSTEM_CMD_TTY_CREATE` | Create tty |
|
||||
| 61 | `SYSTEM_CMD_TTY_READ_OUT` | Read tty output buffer |
|
||||
| 62 | `SYSTEM_CMD_TTY_WRITE_IN` | Write tty input buffer |
|
||||
| 63 | `SYSTEM_CMD_TTY_READ_IN` | Read input for current tty |
|
||||
| 64 | `SYSTEM_CMD_SPAWN` | Spawn process |
|
||||
| 65 | `SYSTEM_CMD_TTY_SET_FG` | Set tty foreground PID |
|
||||
| 66 | `SYSTEM_CMD_TTY_GET_FG` | Get tty foreground PID |
|
||||
| 67 | `SYSTEM_CMD_TTY_KILL_FG` | Kill tty foreground PID |
|
||||
| 68 | `SYSTEM_CMD_TTY_KILL_ALL` | Kill tty process group |
|
||||
| 69 | `SYSTEM_CMD_TTY_DESTROY` | Destroy tty |
|
||||
| 70 | `SYSTEM_CMD_EXEC` | Exec replace current process |
|
||||
| 71 | `SYSTEM_CMD_WAITPID` | Wait/reap child |
|
||||
| 72 | `SYSTEM_CMD_KILL_SIGNAL` | Send signal |
|
||||
| 73 | `SYSTEM_CMD_SIGACTION` | Set/get handler |
|
||||
| 74 | `SYSTEM_CMD_SIGPROCMASK` | Signal mask ops |
|
||||
| 75 | `SYSTEM_CMD_SIGPENDING` | Get pending signals |
|
||||
|
||||
### ELF app metadata
|
||||
|
||||
| ID | Macro | Meaning |
|
||||
|---|---|---|
|
||||
| 76 | `SYSTEM_CMD_GET_ELF_METADATA` | Read full app metadata from an ELF |
|
||||
| 77 | `SYSTEM_CMD_GET_ELF_PRIMARY_IMAGE` | Read primary icon path from an ELF |
|
||||
|
||||
## Common Wrapper API (`src/userland/libc/syscall.h`)
|
||||
|
||||
Typical wrappers used by apps:
|
||||
- Process/system: `sys_exit`, `sys_yield`, `sys_spawn`, `sys_exec`, `sys_waitpid`, `sys_kill_signal`
|
||||
- Filesystem: `sys_open`, `sys_read`, `sys_write_fs`, `sys_close`, `sys_seek`, `sys_tell`, `sys_size`, `sys_list`
|
||||
- Network: `sys_network_init`, `sys_network_dhcp_acquire`, `sys_udp_send`, `sys_tcp_connect`, `sys_tcp_recv_nb`, `sys_dns_lookup`
|
||||
- TTY: `sys_tty_create`, `sys_tty_read_out`, `sys_tty_write_in`, `sys_tty_set_fg`
|
||||
- ELF metadata: `sys_get_elf_metadata`, `sys_get_elf_primary_image` — see [`elf_metadata.md`](elf_metadata.md) for full usage
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Do not hardcode numeric command IDs in app code.
|
||||
- Prefer high-level libc calls (`open`, `read`, `waitpid`, `sigaction`) where available.
|
||||
- Use `syscall.h` macros when a raw `sys_system` call is still needed.
|
||||
@@ -16,7 +16,7 @@ BoredOS features a fully custom, graphical Window Manager built directly into th
|
||||
> [!TIP]
|
||||
> The performance of the window manager heavily depends on minimizing the "dirty regions" drawn in the compositing loop rather than sweeping the whole screen.
|
||||
|
||||
## 🪟 Window System (`wm.c`)
|
||||
## Window System (`wm.c`)
|
||||
|
||||
The windowing system is built around a linked list of `Window` structures.
|
||||
|
||||
@@ -34,7 +34,7 @@ The WM acts as the central hub for input routing.
|
||||
|
||||
- **Event Polling**: The UI loop inside an app continuously calls `ui_poll_event()` to respond to mouse clicks and window movement dispatched by the kernel WM.
|
||||
|
||||
## 🧵 Multi-Core Safety & Performance
|
||||
## Multi-Core Safety & Performance
|
||||
|
||||
With the introduction of Symmetric Multi-Processing (SMP), the Window Manager (WM) was redesigned to ensure stability and high performance across multiple cores.
|
||||
|
||||
41
docs/architecture/hardware/pci.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# PCI Bus Subsystem
|
||||
|
||||
The Peripheral Component Interconnect (PCI) subsystem in BoredOS is responsible for discovering, enumerating, and configuring hardware devices connected to the motherboard. It provides the foundation for the OS to load specific device drivers (like Network Interface Cards or AHCI controllers).
|
||||
|
||||
## 1. Configuration Space Access
|
||||
|
||||
BoredOS interacts with the PCI bus via the legacy x86 I/O ports:
|
||||
- **`0xCF8`**: Address Port (used to select a specific bus, device, function, and register offset).
|
||||
- **`0xCFC`**: Data Port (used to read or write the 32-bit value at the selected address).
|
||||
|
||||
These are abstracted in `src/dev/pci.c` by the `pci_read_config()` and `pci_write_config()` functions. By writing a formatted 32-bit address to `0xCF8`, the CPU signals the PCI bridge to route the subsequent data read/write on `0xCFC` to the correct hardware device.
|
||||
|
||||
## 2. Device Enumeration
|
||||
|
||||
During boot, BoredOS recursively scans the PCI buses. The PCI bus topology is hierarchical:
|
||||
- Up to **256 buses**.
|
||||
- Each bus has up to **32 devices**.
|
||||
- Each device has up to **8 functions** (for multi-function devices).
|
||||
|
||||
The enumeration process (`pci_enumerate_devices`):
|
||||
1. Iterates through Bus 0 to 255.
|
||||
2. For each bus, iterates through Devices 0 to 31.
|
||||
3. For each device, it reads the `Vendor ID` at offset 0. If the value is `0xFFFF`, no device is present at that slot.
|
||||
4. If a valid Vendor ID is found, it populates a `pci_device_t` structure containing the:
|
||||
- `Vendor ID` and `Device ID` (used to uniquely identify the hardware model).
|
||||
- `Class Code`, `Subclass`, and `Prog IF` (used to identify the generic type of the device, e.g., Network Controller, Mass Storage Controller).
|
||||
|
||||
## 3. Base Address Registers (BARs)
|
||||
|
||||
PCI devices expose memory-mapped I/O (MMIO) regions or I/O port ranges via Base Address Registers (BARs).
|
||||
BoredOS provides the `pci_get_bar(dev, bar_num)` function to extract these base addresses.
|
||||
|
||||
Drivers use BARs to talk directly to the hardware. For example:
|
||||
- The AHCI driver reads BAR5 to find the base address of the AHCI memory registers (ABAR).
|
||||
- The E1000 driver uses a BAR to map the NIC's control registers into the kernel's virtual memory space.
|
||||
|
||||
## 4. Hardware Configuration
|
||||
|
||||
Once a device is found, drivers can call helper functions to enable specific PCI features:
|
||||
- **`pci_enable_bus_mastering(dev)`**: Sets the Bus Master bit in the PCI Command Register. This is critical for drivers that use DMA (Direct Memory Access), allowing the hardware to read/write system RAM independently of the CPU (used heavily by AHCI and Network drivers).
|
||||
- **`pci_enable_mmio(dev)`**: Sets the Memory Space Enable bit, allowing the CPU to access the device's MMIO regions.
|
||||
273
docs/architecture/input/keyboard.md
Normal file
@@ -0,0 +1,273 @@
|
||||
# Input Subsystem
|
||||
|
||||
## Overview
|
||||
The input subsystem is responsible for handling user input, primarily from the keyboard.
|
||||
|
||||
It provides a structured pipeline that transforms low-level hardware signals into usable data for the kernel and higher-level components. This subsystem abstracts hardware-specific behavior and exposes a consistent interface to the rest of the operating system.
|
||||
|
||||
---
|
||||
|
||||
## Scope
|
||||
The `/input` directory focuses on keyboard input. It includes:
|
||||
|
||||
- A keyboard driver responsible for handling hardware events
|
||||
- A keycode layer used as an intermediate representation
|
||||
- A keymap system that translates keycodes into characters
|
||||
|
||||
---
|
||||
|
||||
## Design Principles
|
||||
|
||||
- **Hardware abstraction**
|
||||
Hardware-specific logic is isolated from higher-level components.
|
||||
|
||||
- **Simplicity**
|
||||
The input path is kept minimal and efficient, especially in interrupt context.
|
||||
|
||||
- **Modularity**
|
||||
Each stage of input processing is handled by a dedicated component.
|
||||
|
||||
- **Extensibility**
|
||||
The system is designed to support additional input devices and layouts in the future.
|
||||
|
||||
---
|
||||
|
||||
## Directory Structure
|
||||
```
|
||||
input/
|
||||
├── keyboard.c
|
||||
├── keyboard.h
|
||||
├── keycodes.h
|
||||
├── keymap.c
|
||||
├── keymap.h
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Input Processing Model
|
||||
|
||||
Keyboard input is processed in three distinct stages:
|
||||
|
||||
1. Raw scancodes are received from the hardware
|
||||
2. Scancodes are converted into keycodes
|
||||
3. Keycodes are translated into characters or control signals
|
||||
|
||||
Each stage is handled independently to ensure clarity and maintainability.
|
||||
|
||||
---
|
||||
|
||||
## Components
|
||||
|
||||
### Keyboard Driver
|
||||
|
||||
#### Overview
|
||||
The keyboard driver interfaces directly with the keyboard hardware. It handles interrupts and processes raw input data from the controller.
|
||||
|
||||
#### Responsibilities
|
||||
|
||||
- Handle keyboard interrupts
|
||||
- Read scancodes from the PS/2 controller
|
||||
- Convert scancodes into keycodes
|
||||
- Forward processed data to higher layers
|
||||
|
||||
#### Behavior
|
||||
|
||||
The driver operates in an interrupt-driven context. When a key event occurs, the hardware triggers an interrupt. The driver reads the corresponding scancode and processes it immediately.
|
||||
|
||||
Because this code runs at a low level, it must be fast, predictable, and minimal.
|
||||
|
||||
#### Integration
|
||||
|
||||
The keyboard driver depends on:
|
||||
|
||||
- The PS/2 controller driver for hardware communication
|
||||
- The interrupt subsystem for event handling
|
||||
|
||||
It provides output to:
|
||||
|
||||
- The keycode system
|
||||
- The keymap system
|
||||
|
||||
#### Constraints
|
||||
|
||||
- Must not block execution
|
||||
- Must minimize processing time per interrupt
|
||||
- Must correctly handle key press and key release events
|
||||
|
||||
---
|
||||
|
||||
### Keycodes
|
||||
|
||||
#### Overview
|
||||
Keycodes define a hardware-independent representation of keyboard keys.
|
||||
|
||||
They serve as an abstraction layer between raw scancodes and higher-level logic.
|
||||
|
||||
#### Purpose
|
||||
|
||||
The keycode system standardizes keyboard input by mapping all physical key events to a consistent set of identifiers.
|
||||
|
||||
This allows the system to:
|
||||
|
||||
- Remain independent from specific hardware implementations
|
||||
- Simplify input handling logic
|
||||
- Support multiple layouts and configurations
|
||||
|
||||
#### Design
|
||||
|
||||
Each key is represented by a unique constant, such as:
|
||||
|
||||
- KEY_A
|
||||
- KEY_ENTER
|
||||
- KEY_SHIFT
|
||||
|
||||
#### Role in the System
|
||||
|
||||
Keycodes act as the intermediate layer between:
|
||||
|
||||
- Hardware-level scancodes
|
||||
- Character-level or command-level input
|
||||
|
||||
#### Usage
|
||||
|
||||
- Generated by the keyboard driver
|
||||
- Consumed by the keymap system
|
||||
|
||||
#### Extensibility
|
||||
|
||||
The keycode system can be extended to support:
|
||||
|
||||
- Additional keys (function keys, multimedia keys)
|
||||
- Non-standard input devices
|
||||
- Custom mappings
|
||||
|
||||
---
|
||||
|
||||
### Keymap
|
||||
|
||||
#### Overview
|
||||
The keymap system translates keycodes into characters or control signals.
|
||||
|
||||
It defines how physical key presses are interpreted based on layout and modifier state.
|
||||
|
||||
#### Responsibilities
|
||||
|
||||
- Convert keycodes into ASCII or equivalent representations
|
||||
- Apply modifier logic such as Shift and Control
|
||||
- Provide consistent character output
|
||||
|
||||
#### Behavior
|
||||
|
||||
The keymap takes a keycode as input and produces an output depending on:
|
||||
|
||||
- The current keyboard layout
|
||||
- Active modifier keys
|
||||
|
||||
The same keycode may produce different results depending on modifier state.
|
||||
|
||||
|
||||
#### Integration
|
||||
|
||||
- Receives keycodes from the keyboard driver
|
||||
- Outputs characters to the kernel or userland
|
||||
|
||||
---
|
||||
|
||||
## Control Signals
|
||||
|
||||
In addition to character generation, the input subsystem produces **control signals** representing non-printable keys and command-oriented input.
|
||||
|
||||
These signals are derived from keycodes that do not map directly to ASCII characters.
|
||||
|
||||
---
|
||||
|
||||
### Definition
|
||||
|
||||
A control signal is an abstract representation of a key event used to trigger system-level behavior rather than text output.
|
||||
|
||||
Typical control signals include:
|
||||
|
||||
- Enter
|
||||
- Backspace
|
||||
- Escape
|
||||
- Tab
|
||||
- Arrow keys
|
||||
- Function keys
|
||||
|
||||
---
|
||||
|
||||
### Encoding
|
||||
|
||||
Control signals may be represented in different ways depending on the layer:
|
||||
|
||||
#### ASCII Control Characters (when applicable)
|
||||
|
||||
Some keys map to standard ASCII control codes:
|
||||
|
||||
- `ENTER` → `0x0A` (Line Feed) or `0x0D` (Carriage Return)
|
||||
- `BACKSPACE` → `0x08`
|
||||
- `TAB` → `0x09`
|
||||
- `ESC` → `0x1B`
|
||||
|
||||
These values are part of the ASCII control range (`0x00`–`0x1F`).
|
||||
|
||||
---
|
||||
|
||||
#### Non-ASCII Keys
|
||||
|
||||
Keys that do not belong to the ASCII set are typically handled as **extended keycodes** or **internal constants**:
|
||||
|
||||
Examples:
|
||||
|
||||
- Arrow keys
|
||||
- Insert / Delete
|
||||
- Home / End
|
||||
- Function keys (F1–F12)
|
||||
|
||||
------
|
||||
## Non-ASCII Characters
|
||||
|
||||
Non-ASCII characters include any character outside the standard 7-bit ASCII range (`0x00`–`0x7F`).
|
||||
|
||||
Examples:
|
||||
|
||||
- Accented characters: `é`, `à`, `ç`
|
||||
- Symbols: `€`, `£`
|
||||
- Unicode characters from non-Latin scripts
|
||||
|
||||
---
|
||||
|
||||
### Encoding Considerations
|
||||
|
||||
The current system typically assumes ASCII output. However, supporting non-ASCII characters requires:
|
||||
|
||||
- A wider character encoding (e.g. UTF-8)
|
||||
- Extended keymaps capable of mapping key combinations to multi-byte sequences
|
||||
|
||||
Example:
|
||||
|
||||
- `'é'` in UTF-8 → `0xC3 0xA9`
|
||||
|
||||
---
|
||||
|
||||
### Modifier and Layout Impact
|
||||
|
||||
Non-ASCII characters are often produced through:
|
||||
|
||||
- Keyboard layout differences (AZERTY vs QWERTY)
|
||||
- Modifier combinations (Shift, AltGr)
|
||||
|
||||
Example:
|
||||
|
||||
- `AltGr + E` → `'€'` (depending on layout)
|
||||
- `KEY_E` → `'e'`
|
||||
- `KEY_E + SHIFT` → `'E'`
|
||||
|
||||
---
|
||||
|
||||
### Usage
|
||||
|
||||
- Control signals are used for command handling and system interaction
|
||||
- Non-ASCII characters are used for text input and require proper encoding support
|
||||
|
||||
|
||||
71
docs/architecture/memory/memory_manager.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Kernel Memory Manager Architecture
|
||||
|
||||
BoredOS utilizes a highly optimized, two-tier kernel memory manager (`memory_manager.c`) designed for performance, concurrency safety, and long-term stability. The API provides the standard POSIX-like `kmalloc`, `krealloc`, and `kfree` functions used universally throughout the kernel.
|
||||
|
||||
## 1. High-Level Design
|
||||
|
||||
The memory manager delegates allocation requests to one of two internal sub-systems based on the requested size and alignment parameters:
|
||||
|
||||
1. **Slab Allocator**: Optimally handles all small allocations (<= 512 bytes) with an alignment restriction of <= 8 bytes.
|
||||
2. **Block-List Allocator**: Handles large allocations (> 512 bytes) and any request requiring aggressive alignment (such as page-aligned buffers).
|
||||
|
||||
All operations within the memory manager are secured by a global interrupt-safe spinlock (`mm_lock`), rendering the memory subsystem completely atomic and safe to use from any CPU or interrupt handler without triggering a race condition.
|
||||
|
||||
---
|
||||
|
||||
## 2. The Slab Allocator (Small Objects)
|
||||
|
||||
For frequent, small data structures, the overhead of standard heap fragmentation is unacceptable. The Slab Allocator addresses this by pre-allocating blocks of identical size.
|
||||
|
||||
### Classes & Geometry
|
||||
There are 7 active slab classes defined by `slab_sizes[]`: `8, 16, 32, 64, 128, 256, 512` bytes.
|
||||
Whenever an allocation requests a size within these bounds, it is rounded up to the nearest valid class.
|
||||
|
||||
Each active slab page maps precisely to one standard system `PAGE_SIZE` (4096 bytes).
|
||||
- The page header (`SlabPage`) is embedded at the very top (byte offset 0).
|
||||
- The rest of the page is sliced seamlessly into perfectly sized object slots.
|
||||
|
||||
### Intrusive LIFO Free-List
|
||||
To minimize metadata overhead, the Slab Allocator uses an *intrusive* LIFO (Last-In-First-Out) free-list to track empty object slots. The first 8 bytes of any unallocated slot act as a `next` pointer to the next free slot in that page. When a pointer is freed, it is immediately pushed back to the head of this list, making it the most likely candidate for the *next* allocation. This maximizes CPU cache locality.
|
||||
|
||||
### Guardrails & Safety
|
||||
The Slab Allocator implements highly restrictive checks to guard against fatal kernel errors:
|
||||
- **Canonical Address Checks:** The allocator verifies that the freelist head remains in the higher-half address space (`0xFFFF000000000000` or above), proactively detecting structural corruption.
|
||||
- **Strict Pointer Admittance:** Before freeing a pointer to a slab, the allocator validates a dual magic-number footprint, limits the pointer's bounds to verify it belongs geographically to the page, and executes a linked-list walk.
|
||||
- **Double-Free Detection:** When a slab is freed, the allocator walks the internal free-list. If the freed pointer is already in the free-list, the allocator intercepts the double-free attempt before the internal state can be damaged.
|
||||
|
||||
---
|
||||
|
||||
## 3. The Block-List Allocator (Large Objects)
|
||||
|
||||
If an allocation is larger than 512 bytes, the memory manager falls back to the Block-List allocator.
|
||||
|
||||
### First-Fit Search & Splitting
|
||||
The Block Allocator tracks all system memory chunks using an array of `MemBlock` structs ordered dynamically by address.
|
||||
- It iterates through the array utilizing a **First-Fit Search**. The first contiguous, unallocated block that satisfies the `size` requirement is immediately claimed.
|
||||
- If the requested alignment dictates it, the allocator splits the parent block. It yields up to three new fragments: `[head padding | exact requested allocation | tail remainder]`.
|
||||
|
||||
### Bootstrapping & Heap Migration
|
||||
To avoid infinite recursion when allocating memory to track new memory blocks, the block list is initially statically allocated in a `.bss` array (`_bootstrap_blocks`) with an initial capacity of 64 `MemBlocks`.
|
||||
|
||||
When the system runs out of capacity to track new blocks, the block list calls `grow_block_list()`, which reallocates the array space into the primary heap. It utilizes a `growing` lock-flag to prevent recursive faults while performing this relocation.
|
||||
|
||||
### Coalescing
|
||||
Upon `kfree()`, the chunk is marked as unallocated. The allocator inspects its immediate left and right address neighbors. If they are also free, the adjacent blocks are merged (coalesced) into one continuous block to reduce overall memory fragmentation.
|
||||
|
||||
---
|
||||
|
||||
## 4. API Caveats & Contracts
|
||||
|
||||
### Alignment guarantees
|
||||
`kmalloc` inherently returns a naturally aligned pointer (minimum 8-byte boundary) sufficient to satisfy scalar types natively on x86-64 without fetching faults. `kmalloc_aligned` can be utilized for strict power-of-two alignment boundaries (e.g., page directories that demand 4096 alignment).
|
||||
|
||||
### Resizing limits
|
||||
`krealloc` accepts an existing allocated pointer and transforms it to meet a new size requirement. To prevent memory starvation over long lifetimes, `krealloc` employs aggressive optimization strategies depending on the allocator layer:
|
||||
- **Block Allocator (Shrink-in-Place):** Large blocks actively support shrink-in-place maneuvers. If the reduction saves at least 32 bytes, the unused trailing memory is sliced off, injected into the free pool, and physically coalesced with adjacent free neighbors. The original pointer remains identical.
|
||||
- **Slab Allocator (Down-Migration):** Since slab slots have rigid geometries, true shrink-in-place is impossible. However, if a pointer shrinks enough to cleanly fall into a smaller slab class, `krealloc` triggers an internal copy-migration. This instantly relinquishes the highly-contested larger slab slot back to the system.
|
||||
|
||||
---
|
||||
|
||||
## 5. Telemetry & Metrics
|
||||
The `memory_get_stats()` API exports complete transparency over the current topological state of the system memory map. It calculates variables such as peak memory, overall fragmentation % (the ratio of stranded memory outside the largest single block), and explicit slab efficiency counters.
|
||||
52
docs/architecture/network/network_stack.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# Networking Stack
|
||||
|
||||
BoredOS features a robust networking stack capable of handling Ethernet, IPv4, TCP, UDP, ICMP, DHCP, and DNS. The stack is built on top of the **lwIP (Lightweight IP)** library, which is integrated with a custom hardware driver layer.
|
||||
|
||||
## 1. Architecture Overview
|
||||
|
||||
The network stack is split into three main layers:
|
||||
1. **Hardware/Driver Layer (`src/net/nic/`)**: Communicates with physical and virtual Network Interface Cards (NICs), handling raw Ethernet frame transmission and reception. Supported drivers include the Intel E1000 (`e1000.c`), Realtek RTL8139 (`rtl8139.c`), Realtek RTL8111 (`rtl8111.c`), and VirtIO network devices (`virtio_net.c`). A generic interface is provided via `nic.c`.
|
||||
2. **Protocol Layer (lwIP)**: Processes Ethernet frames, handles ARP resolution, routes IPv4 packets, and manages TCP state machines.
|
||||
3. **OS Interface Layer (`src/net/network.c`)**: Wraps the asynchronous lwIP API into a synchronous, easy-to-use API for BoredOS applications and the kernel.
|
||||
|
||||
## 2. Initialization & Polling
|
||||
|
||||
### `network_init()`
|
||||
When the kernel boots, it initializes the network subsystem by:
|
||||
1. Probing the PCI bus for supported NICs (e.g., the Intel E1000).
|
||||
2. Initializing the lwIP core (`lwip_init()`) and DNS subsystem.
|
||||
3. Binding the hardware NIC to lwIP using `netif_add`.
|
||||
4. Automatically attempting to acquire an IP address via DHCP (`network_dhcp_acquire()`).
|
||||
|
||||
### The Polling Mechanism (`network_process_frames`)
|
||||
Unlike some operating systems that process network packets entirely inside hardware interrupt handlers, BoredOS uses a **polled approach** to avoid re-entrancy issues in the TCP/IP stack.
|
||||
|
||||
The `network_process_frames()` function is called periodically (e.g., from the Window Manager loop or during blocking network calls). It calls:
|
||||
- `nic_netif_poll()`: Pulls raw packets from the NIC ring buffer and feeds them to lwIP (`ethernet_input`).
|
||||
- `sys_check_timeouts()`: Fires lwIP internal timers for TCP retransmissions, ARP cache expiration, and DHCP lease renewals.
|
||||
|
||||
A `network_processing` flag acts as a lightweight spinlock to prevent nested execution of the network poll loop.
|
||||
|
||||
## 3. TCP Implementation & Application API
|
||||
|
||||
While lwIP provides a callback-based raw API, BoredOS wraps this into a sequential API for userland applications.
|
||||
|
||||
Currently, the OS supports **one active TCP connection globally across the entire system**. The connection state is managed via a global Protocol Control Block (`current_tcp_pcb`). To prevent unauthorized cleanup, the OS tracks which process initiated the connection (`tcp_owner_pid`). If a new process attempts to connect while a connection is active, the existing connection is forcefully aborted.
|
||||
|
||||
### `network_tcp_connect(ip, port)`
|
||||
1. Allocates a new Protocol Control Block (`tcp_new()`).
|
||||
2. Registers callbacks for receive (`tcp_recv_callback`), error, and connection success.
|
||||
3. Blocks (while polling the network) until the connection succeeds or times out after 15 seconds.
|
||||
|
||||
### `network_tcp_recv(buf, max_len)`
|
||||
When packets arrive, `tcp_recv_callback` chains them into a `tcp_recv_queue` (`struct pbuf`).
|
||||
The `network_tcp_recv` function blocks until data is available in this queue, then copies it into the application's buffer and frees the `pbuf`. A non-blocking variant (`network_tcp_recv_nb`) is also provided.
|
||||
|
||||
### Process Cleanup (`network_cleanup`)
|
||||
If an application crashes or exits without closing its socket, the kernel's process manager calls `network_cleanup()`. This checks if the exiting process owns the current TCP PCB (`tcp_owner_pid`) and forcibly aborts the connection to prevent resource leaks.
|
||||
|
||||
## 4. Helper Protocols
|
||||
|
||||
- **DHCP:** Managed entirely by lwIP. BoredOS simply waits up to 10 seconds during boot for a lease.
|
||||
- **DNS (`network_dns_lookup`):** Uses lwIP's `dns_gethostbyname`. It blocks and polls until the callback is triggered with the resolved IP address.
|
||||
- **ICMP (Ping):** The kernel provides a `network_icmp_single_ping` function using an lwIP raw socket (`raw_pcb`) to construct, checksum, and transmit an ICMP Echo Request, blocking until a reply is received to calculate the Round-Trip Time (RTT).
|
||||
40
docs/architecture/storage/ahci_drivers.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# AHCI Storage Driver
|
||||
|
||||
BoredOS implements an Advanced Host Controller Interface (AHCI) driver to interface with Serial ATA (SATA) mass storage devices. The driver is located in `src/dev/ahci.c` and allows the OS to read and write sectors directly to physical hard drives or solid-state drives using DMA (Direct Memory Access).
|
||||
|
||||
## 1. Discovery and Initialization
|
||||
|
||||
The AHCI initialization process (`ahci_init`) starts by querying the PCI subsystem:
|
||||
1. It searches for a PCI device with Class `0x01` (Mass Storage) and Subclass `0x06` (SATA).
|
||||
2. It calls `pci_enable_bus_mastering` and `pci_enable_mmio` to ensure the controller can perform DMA and its registers are accessible.
|
||||
3. It retrieves the **ABAR** (AHCI Base Address Register) from PCI BAR5.
|
||||
4. The ABAR points to the `HBA_MEM` structure (Host Bus Adapter Memory Registers). The kernel iterates through the `pi` (Ports Implemented) bitmask to find active SATA ports.
|
||||
|
||||
## 2. Port Configuration
|
||||
|
||||
For every active SATA port found, the driver must allocate memory structures that the hardware will use to process commands:
|
||||
1. **Command List Base (`clb`)**: A 1KB memory region holding 32 Command Headers.
|
||||
2. **FIS Base (`fb`)**: A 256-byte memory region where the HBA writes incoming Frame Information Structures (FIS) from the drive.
|
||||
3. **Command Tables (`ctba`)**: A larger memory region allocated for each Command Header, containing the actual SATA command bytes and the scatter/gather lists (PRDT).
|
||||
|
||||
*Note:* All AHCI data structures must be allocated in physically contiguous memory and properly aligned (e.g., 1KB or 256-byte boundaries) because the HBA reads them directly from physical RAM via DMA.
|
||||
|
||||
## 3. Physical Region Descriptor Tables (PRDT)
|
||||
|
||||
When reading or writing data, BoredOS must tell the AHCI controller where in RAM the data should be stored or fetched. This is done using PRDT entries.
|
||||
|
||||
Each `HBA_PRDT_ENTRY` specifies:
|
||||
- A physical Data Base Address (`dba`).
|
||||
- A Byte Count (`dbc`), limited to a maximum of 4MB per entry.
|
||||
|
||||
If a read/write request spans multiple fragmented pages or exceeds 4MB, the driver constructs multiple PRDT entries within the Command Table to form a scatter/gather list. The AHCI hardware seamlessly processes these entries as a single contiguous disk operation.
|
||||
|
||||
## 4. Reading and Writing Sectors
|
||||
|
||||
To execute a command (e.g., `ahci_read_sectors` or `ahci_write_sectors`):
|
||||
1. The driver finds a free slot in the Command List.
|
||||
2. It populates the Command Header, setting the `cfl` (Command FIS Length) and `w` (Write) bit.
|
||||
3. It builds a Host-to-Device Register FIS (`FIS_REG_H2D`) in the Command Table, issuing the `ATA_CMD_READ_DMA_EX` or `ATA_CMD_WRITE_DMA_EX` command and specifying the starting LBA (Logical Block Address) and sector count.
|
||||
4. It sets up the PRDT entries pointing to the physical memory of the provided buffer.
|
||||
5. It sets the corresponding bit in the Port's Command Issue register (`ci`).
|
||||
6. The driver then polls the `ci` register (or waits for an interrupt) until the bit clears, indicating the hardware has completed the DMA transfer.
|
||||
@@ -34,7 +34,7 @@ BoredOS uses **Limine** as its primary bootloader.
|
||||
5. **Driver Initialization**: PCI buses are scanned, finding the network card or disk controllers. The filesystem is mounted.
|
||||
6. **Window Manager**: The UI is drawn on top of the Limine-provided framebuffer.
|
||||
|
||||
## 🧵 Multi-Core & Scheduling
|
||||
## Multi-Core & Scheduling
|
||||
|
||||
BoredOS utilizes Symmetric Multi-Processing (SMP) to distribute workloads across all available CPU cores.
|
||||
|
||||
66
docs/architecture/system/processes.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# Process Management & Scheduling
|
||||
|
||||
BoredOS implements a lightweight, symmetric multiprocessing (SMP) capable multitasking environment. This document outlines the architecture of the scheduler, process structures, context switching, and ELF binary loading.
|
||||
|
||||
## 1. Process Structure (`process_t`)
|
||||
|
||||
The core of the process management system is the `process_t` structure, defined in `src/sys/process.h`. Due to kernel memory constraints, BoredOS supports a maximum of 16 concurrent processes (`MAX_PROCESSES`), stored in a statically allocated array.
|
||||
|
||||
Key fields include:
|
||||
- **Identification:** `pid`, `parent_pid`, `pgid` (Process Group ID), and `name`.
|
||||
- **Memory & Context:**
|
||||
- `rsp`: The saved stack pointer during a context switch.
|
||||
- `pml4_phys`: The physical address of the Page Map Level 4 table (VMM root) for this process.
|
||||
- `kernel_stack` & `user_stack_alloc`: Pointers to allocated stack memory.
|
||||
- **Scheduler State:** `ticks`, `sleep_until`, `is_idle`, `cpu_affinity`.
|
||||
- **Resources:**
|
||||
- `fds`: File descriptor table tracking open files, pipes, and sockets (up to `MAX_PROCESS_FDS` = 16).
|
||||
- `gui_events`: A circular queue for Window Manager events (keyboard, mouse).
|
||||
- **Signals:** POSIX-like signal tracking via `signal_mask` and `signal_pending`.
|
||||
|
||||
## 2. The Scheduler
|
||||
|
||||
BoredOS uses a **Preemptive Round-Robin** scheduler implemented as a circular linked list.
|
||||
|
||||
### Symmetric Multiprocessing (SMP)
|
||||
Each CPU core maintains its own `current_process` pointer (`current_process[my_cpu]`). When a new user process is spawned via `process_create_elf`, the kernel assigns it to an Application Processor (AP) core using a simple round-robin assignment policy (`next_cpu_assign`), avoiding Core 0 (BSP) which is typically reserved for kernel tasks and driver interrupts.
|
||||
|
||||
### The `process_schedule` Loop
|
||||
When the timer interrupt fires, it calls `process_schedule(current_rsp)`:
|
||||
1. It saves the `current_rsp` into the current process's structure.
|
||||
2. It handles cleanup of killed processes (`kill_pending`).
|
||||
3. It traverses the circular linked list (`cur->next`) looking for a process where `cpu_affinity == my_cpu`.
|
||||
4. It checks if the process is sleeping (`sleep_until > now`).
|
||||
5. It switches the hardware context:
|
||||
- Updates the Task State Segment (TSS) ring 0 stack pointer.
|
||||
- Switches the page directory by writing the new `pml4_phys` to `CR3`.
|
||||
- Returns the new process's `rsp`, which the interrupt handler then pops into registers.
|
||||
|
||||
## 3. Context Switching
|
||||
|
||||
Context switching is achieved by manually constructing an interrupt stack frame (IRETQ frame).
|
||||
|
||||
When a process is created, the kernel sets up the top of its kernel stack with:
|
||||
- `SS` (Stack Segment: `0x1B` for user, `0x10` for kernel)
|
||||
- `RSP` (The process's stack pointer)
|
||||
- `RFLAGS` (`0x202` to ensure interrupts are enabled)
|
||||
- `CS` (Code Segment: `0x23` for user, `0x08` for kernel)
|
||||
- `RIP` (The entry point of the binary or function)
|
||||
- Zeroed space for General Purpose Registers and a 512-byte `fxsave` region for FPU/SSE state.
|
||||
|
||||
When `process_schedule` returns the new `rsp`, the assembly interrupt stub uses `pop` instructions to restore the general-purpose registers, and finally executes `iretq`, transitioning execution to the new process seamlessly.
|
||||
|
||||
## 4. ELF Loading
|
||||
|
||||
Userland applications in BoredOS are standard 64-bit ELF binaries.
|
||||
|
||||
The function `process_create_elf` orchestrates this:
|
||||
1. **Memory Allocation:** Creates a new PML4 page table for the user process.
|
||||
2. **Parsing:** Calls `elf_load(filepath, pml4, &size)` to parse the ELF headers, allocate required physical memory, and copy the executable segments (text, data, bss) into the process's virtual address space at the locations specified by the ELF program headers.
|
||||
3. **Stack Setup:** Allocates a 256KB user stack mapped at `0x800000`.
|
||||
4. **Argument Passing:** Parses the `args_str` passed to the executable and pushes an `argv` array onto the newly allocated user stack.
|
||||
5. **Execution:** Sets the stack frame's `RIP` to the ELF entry point and links the process into the scheduler's run queue.
|
||||
|
||||
## 5. Process Termination
|
||||
|
||||
When a process exits (or is killed), it is not immediately freed. The scheduler sets `kill_pending = true`. The actual destruction of the PML4 table and stack allocations is deferred to the next tick inside `process_schedule` to avoid freeing the memory of the code currently executing the cleanup.
|
||||
110
docs/architecture/versioning.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# BoredOS Versioning
|
||||
|
||||
BoredOS uses two independent version numbers: one for the **OS release** and one for the **kernel**. They evolve at different rates and follow different conventions.
|
||||
|
||||
---
|
||||
|
||||
## OS Version
|
||||
|
||||
The OS version follows a **date-based** scheme:
|
||||
|
||||
```
|
||||
YY.M[.x]
|
||||
```
|
||||
|
||||
| Component | Meaning |
|
||||
|-----------|---------|
|
||||
| `YY` | Two-digit year (e.g. `26` for 2026) |
|
||||
| `M` | Month number, no leading zero (e.g. `4` for April, `12` for December) |
|
||||
| `.x` | Optional patch identifier — a small sequential integer that has **no relation to a specific day** |
|
||||
|
||||
### Examples
|
||||
|
||||
| Version | Meaning |
|
||||
|----------|---------|
|
||||
| `26.4` | Base release for April 2026 |
|
||||
| `26.5` | Base release for May 2026 |
|
||||
| `26.5.1` | First patch on top of the May 2026 release |
|
||||
| `26.5.2` | Second patch on top of the May 2026 release |
|
||||
| `26.12` | Base release for December 2026 |
|
||||
|
||||
### Rules
|
||||
|
||||
- The **base release** (`YY.M`) is cut once per month when a milestone is ready.
|
||||
- Patch releases (`YY.M.x`) are issued for fixes or smaller additions that land between two monthly milestones. The `.x` counter starts at `1` and increments sequentially — it is **not** tied to a calendar day.
|
||||
- A `-dev` or `-rc` suffix may be appended to any version string during active development (e.g. `26.5-dev`, `26.5.1-rc1`).
|
||||
- The version string is defined in [`src/core/version.c`](../../src/core/version.c) as `os_version`.
|
||||
|
||||
---
|
||||
|
||||
## Kernel Version
|
||||
|
||||
The kernel version follows **Semantic Versioning**:
|
||||
|
||||
```
|
||||
MAJOR.MINOR.PATCH
|
||||
```
|
||||
|
||||
| Component | When to increment |
|
||||
|-----------|------------------|
|
||||
| `MAJOR` | A breaking or fundamentally large architectural change (e.g. rewriting the syscall layer, introducing a new memory model) |
|
||||
| `MINOR` | A meaningful new feature or a notable internal improvement that does not break existing interfaces |
|
||||
| `PATCH` | A small fix, refactor, or incremental improvement |
|
||||
|
||||
### Examples
|
||||
|
||||
| Transition | Reason |
|
||||
|---------------------|--------|
|
||||
| `4.2.0` → `5.0.0` | Major kernel rework (e.g. full syscall dispatch-table refactor, new scheduler) |
|
||||
| `4.2.0` → `4.3.0` | New subsystem or feature addition (e.g. adding Lua runtime, new VFS driver) |
|
||||
| `4.2.0` → `4.2.1` | Small fix or minor tweak (e.g. PIT calibration fix, terminal newline correction) |
|
||||
|
||||
### Rules
|
||||
|
||||
- When `MAJOR` is bumped, `MINOR` and `PATCH` reset to `0`.
|
||||
- When `MINOR` is bumped, `PATCH` resets to `0`.
|
||||
- A `-dev` suffix may be appended during active development (e.g. `5.0.0-dev`).
|
||||
- The version string is defined in [`src/core/version.c`](../../src/core/version.c) as `kernel_version`.
|
||||
|
||||
---
|
||||
|
||||
## Where Versions Are Declared
|
||||
|
||||
Both version strings live in a single file:
|
||||
|
||||
```c
|
||||
// src/core/version.c
|
||||
|
||||
const char *os_version = "26.5-dev";
|
||||
const char *kernel_version = "4.2.0-dev";
|
||||
```
|
||||
|
||||
When cutting a release, update both strings, remove the `-dev` suffix, tag the commit (`git tag v26.5`), and then immediately bump to the next `-dev` version.
|
||||
|
||||
---
|
||||
|
||||
## Codename
|
||||
|
||||
Each release may carry an informal **codename**. A single word that gives the release a human-friendly identity. Codenames are stored in [`src/core/version.c`](../../src/core/version.c) as `os_codename` and exposed to userspace via the `get_os_info` syscall.
|
||||
|
||||
### Convention
|
||||
|
||||
- Codenames **generally change with each monthly base release** (`YY.M`), but this is not a hard rule. A codename may carry over into the next month if the release feels like a natural continuation of the previous one.
|
||||
- Patch releases (`YY.M.x`) **always keep the same codename** as the base release they belong to.
|
||||
- There is no enforced theme, but names tend to be short, memorable single words.
|
||||
|
||||
### Examples
|
||||
|
||||
| OS Version | Codename
|
||||
|------------|-----------|
|
||||
| `26.4` | Voyager
|
||||
| `26.5` | Genesis
|
||||
|
||||
### Where It Is Declared
|
||||
|
||||
```c
|
||||
// src/core/version.c
|
||||
|
||||
const char *os_codename = "Genesis";
|
||||
```
|
||||
|
||||
33
docs/build/toolchain.md
vendored
@@ -18,35 +18,4 @@ To build BoredOS, you need the following tools:
|
||||
- *Why?* `xorriso` packages the compiled kernel, Limine bootloader, and asset files (fonts, images, userland binaries) into the final bootable `boredos.iso` CD-ROM image.
|
||||
|
||||
4. **QEMU** (Optional but highly recommended for testing):
|
||||
- `qemu-system-x86_64` is used for rapid emulation and testing.
|
||||
|
||||
## Installation (macOS)
|
||||
|
||||
You can easily install the complete toolchain using Homebrew:
|
||||
|
||||
```sh
|
||||
brew install x86_64-elf-binutils x86_64-elf-gcc nasm xorriso qemu
|
||||
```
|
||||
|
||||
## Installation (Linux)
|
||||
|
||||
Depending on your distribution, the installation commands vary. Note that some distributions may require you to build the `x86_64-elf` cross-compiler from source if it isn't available in their default repositories.
|
||||
|
||||
### Debian / Ubuntu
|
||||
```sh
|
||||
sudo apt update
|
||||
sudo apt install build-essential bison flex libgmp3-dev libmpc-dev libmpfr-dev texinfo nasm xorriso qemu-system-x86
|
||||
```
|
||||
*(Note: You will need to build the `x86_64-elf` cross-compiler from source or find a compatible PPA, as it is not in the default Debian/Ubuntu repositories.)*
|
||||
|
||||
### Arch Linux
|
||||
Arch Linux provides the regular tools in its standard repositories and the cross-compiler via the AUR:
|
||||
```sh
|
||||
sudo pacman -S nasm xorriso qemu-full
|
||||
yay -S x86_64-elf-gcc x86_64-elf-binutils
|
||||
```
|
||||
|
||||
### Fedora
|
||||
```sh
|
||||
sudo dnf install make gcc gcc-c++ bison flex gmp-devel mpfr-devel libmpc-devel texinfo nasm xorriso qemu
|
||||
```
|
||||
- `qemu-system-x86_64` is used to virtualize the OS for testing or to mess around.
|
||||
|
||||
13
docs/build/usage.md
vendored
@@ -33,14 +33,21 @@ To run BoredOS successfully (either in emulation or on bare metal), your target
|
||||
|
||||
To test the generated ISO quickly without real hardware, use the QEMU emulator:
|
||||
|
||||
For MacOS:
|
||||
```sh
|
||||
make run
|
||||
make run-mac
|
||||
```
|
||||
For Linux:
|
||||
```sh
|
||||
make run-linux
|
||||
```
|
||||
For Windows:
|
||||
```sh
|
||||
make run-windows
|
||||
```
|
||||
|
||||
This command invokes QEMU with specific arguments:
|
||||
- `-m 4G`: Allocates 4 Gigabytes of RAM.
|
||||
- `-cdrom boredos.iso`: Mounts the built OS image as a CD-ROM.
|
||||
- `-netdev user...`: Sets up a basic NAT network interface for the OS's networking stack.
|
||||
- `-smp 4`: Enables 4 CPU cores.
|
||||
- `-drive file=disk.img...`: Attaches a raw disk image included in this release of BoredOS.
|
||||
|
||||
|
||||
33
docs/usage/booting.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Booting BoredOS
|
||||
|
||||
BoredOS uses the Limine bootloader, which provides a flexible way to configure the boot process and pass parameters to the kernel.
|
||||
|
||||
## Boot Parameters
|
||||
|
||||
You can modify system behavior at startup by passing specific boot flags.
|
||||
|
||||
### Verbose Boot (`-v`)
|
||||
|
||||
The `-v` flag enables the kernel console (`kconsole`) during the boot process. When enabled, the kernel will display detailed initialization logs on the screen. By default, this is often disabled in the included configuration for a cleaner "splash-only" boot experience.
|
||||
|
||||
#### Toggling Verbose Boot at Runtime
|
||||
|
||||
You can enable or disable the verbose boot log directly from the Limine boot menu without modifying the source files:
|
||||
|
||||
1. **Select Entry**: When the Limine boot menu appears, highlight the **BoredOS** entry.
|
||||
2. **Edit**: Press `E` to enter the entry editor.
|
||||
3. **Modify Flag**: Find the line containing `cmdline: -v`.
|
||||
- To **Enable**: Remove the `#` character if the line is commented out (change `# cmdline: -v` to `cmdline: -v`).
|
||||
- To **Disable**: Add a `# ` at the start of the line.
|
||||
4. **Boot**: Press `F10` to boot using the modified parameters.
|
||||
|
||||
#### Persistent Configuration
|
||||
|
||||
To change the default behavior permanently, modify the `limine.conf` file in the repository root before building the ISO:
|
||||
|
||||
```conf
|
||||
/BoredOS
|
||||
protocol: limine
|
||||
path: boot():/boredos.elf
|
||||
cmdline: -v
|
||||
```
|
||||
35
docs/usage/desktop.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Using the Desktop
|
||||
|
||||
The BoredOS desktop environment is designed to be intuitive while providing powerful window management and icons for quick access to your files and applications.
|
||||
|
||||
## Window Management
|
||||
|
||||
BoredOS uses a stacking window manager (BoredWM) that allows you to overlap and organize multiple windows.
|
||||
|
||||
### Basic Actions
|
||||
- **Focus**: Click anywhere on a window to bring it to the front and make it the active window.
|
||||
- **Move**: Click and drag the **title bar** (the top bar of the window) to reposition it on the screen.
|
||||
- **Close**: Click the red traffic light close button in the top-left corner of the window.
|
||||
|
||||
### System-wide Shortcuts
|
||||
BoredOS includes several global shortcuts to help you manage your workflow:
|
||||
- **`Ctrl + P`**: Take a screenshot. The image will be saved to `/root/Desktop` as `screenshot.jpg`.
|
||||
- **`Shift + Ctrl + Space`**: Toggle **Lumos** search (see the [Lumos guide](lumos.md)).
|
||||
|
||||
## Desktop Icons
|
||||
|
||||
Your desktop represents the contents of the `/root/Desktop` directory.
|
||||
|
||||
- **Launching**: Double-click an icon to open the file or launch the application.
|
||||
- **Snapping**: Icons automatically snap to a grid for a clean look. You can toggle "Snap to Grid" and "Auto Align" in the [Settings app](../launching_apps.md).
|
||||
- **Context Menu**: Right-click on the desktop background to create new files, folders, or refresh the layout.
|
||||
|
||||
## The Bottom Dock
|
||||
|
||||
The dock at the bottom of the screen provides quick shortcuts to your most-used applications, with for example:
|
||||
- **Files**: Browse the entire filesystem.
|
||||
- **Terminal**: Access the command-line interface.
|
||||
- **Calculator / Notepad / Grapher**: Essential productivity tools.
|
||||
|
||||
---
|
||||
[Return to Documentation Index](../README.md)
|
||||
31
docs/usage/launching_apps.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Launching Applications
|
||||
|
||||
BoredOS provides several ways to launch applications and files, depending on your preferred workflow.
|
||||
|
||||
## 1. Using the File Explorer
|
||||
|
||||
The File Explorer is the primary way to navigate the filesystem and launch any `.elf` binary or associated document.
|
||||
|
||||
1. Open the **Explorer** from the dock or desktop.
|
||||
2. Navigate to `/bin` for system applications or your own user folders.
|
||||
3. **Double-click** any executable (`.elf`) to run it.
|
||||
4. Standard files (like `.jpg` or `.txt`) will automatically open in their default viewer.
|
||||
|
||||
## 2. Desktop Shortcuts and Icons
|
||||
|
||||
Commonly used applications are placed directly on the desktop.
|
||||
|
||||
- Simply **Double-click** any icon on the desktop to launch it.
|
||||
- You can also create desktop shortcuts by right-clicking on a file and selecting **"Create Shortcut"**.
|
||||
|
||||
## 3. Using Lumos (Global Search)
|
||||
|
||||
For the fastest access, use **Lumos** to search and launch by name:
|
||||
|
||||
1. Press **`Shift + Ctrl + Space`**.
|
||||
2. Type the name of the app (e.g., "DOOM.elf").
|
||||
3. Press **Enter** to launch.
|
||||
|
||||
|
||||
---
|
||||
[Return to Documentation Index](../README.md)
|
||||
29
docs/usage/lumos.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Lumos: System Search
|
||||
|
||||
**Lumos** is the powerful, system-wide search and launch assistant for BoredOS. It allows you to find applications, documents, and system files instantly without navigating through folders.
|
||||
|
||||
## Opening Lumos
|
||||
|
||||
To activate Lumos at any time, use the global keyboard shortcut:
|
||||
|
||||
**`Shift + Ctrl + Space`**
|
||||
|
||||
The Lumos search modal will appear in the center of your screen, ready for input.
|
||||
|
||||
## Features
|
||||
|
||||
- **Fuzzy Searching**: You don't need to type the exact name. Lumos uses fuzzy matching to find the most relevant results as you type.
|
||||
- **Deep Indexing**: Lumos indexes files across the entire system.
|
||||
- **Quick Launch**: Once you find what you're looking for, launching it is as simple as pressing `Enter`.
|
||||
|
||||
## Navigation
|
||||
|
||||
When the Lumos window is open:
|
||||
- **Type**: Just start typing to filter results.
|
||||
- **Arrow Keys (Up/Down)**: Move the selection highlight through the list of results.
|
||||
- **Enter**: Launch the selected file or application.
|
||||
- **Backspace**: Delete characters in your search query.
|
||||
- **Escape**: Close Lumos and return to the desktop.
|
||||
|
||||
---
|
||||
[Return to Documentation Index](../README.md)
|
||||
60
docs/usage/terminal.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# Terminal & Command Line
|
||||
|
||||
The BoredOS Terminal provides a powerful command-line interface (CLI) for advanced users and developers. It supports standard Unix-like features and provides direct access to the kernel's system calls.
|
||||
|
||||
## The Shell
|
||||
|
||||
The default shell in BoredOS is **BoredShell (Bsh)**, a userspace shell with a dedicated terminal app. It features:
|
||||
- **ANSI Color Support**: Rich text output with colors and styles.
|
||||
- **Command History**: Use the **Up** and **Down** arrow keys to navigate through your previous commands (up to 64 history entries).
|
||||
- **Output Redirection**:
|
||||
- `command > file`: Write output to a new file (or overwrite existing).
|
||||
- `command >> file`: Append output to an existing file.
|
||||
- **Piping**:
|
||||
- `command1 | command2`: Pass the output of the first command as input to the second.
|
||||
|
||||
### Bsh Configuration
|
||||
|
||||
Bsh loads its configuration from:
|
||||
|
||||
`/Library/bsh/bshrc`
|
||||
|
||||
This file is similar to `.zshrc` or `.bashrc` and can define:
|
||||
- `PATH` for command lookup
|
||||
- `STARTUP` for interactive shell startup scripts
|
||||
- `BOOT_SCRIPT` for a once-per-boot script
|
||||
- prompt templates (`PROMPT_LEFT`, `PROMPT_RIGHT`)
|
||||
|
||||
Prompt tokens:
|
||||
- `%n` username
|
||||
- `%h` hostname
|
||||
- `%~` cwd ("~" for `/root`)
|
||||
- `%T` time (HH:MM)
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
PATH=/bin:/root/Apps
|
||||
PROMPT_LEFT=%n@%h:%~$
|
||||
STARTUP=/Library/bsh/startup.bsh
|
||||
BOOT_SCRIPT=/Library/bsh/boot.bsh
|
||||
```
|
||||
|
||||
## Common Commands
|
||||
|
||||
Below are some of the most used commands available in `/bin`:
|
||||
|
||||
| Command | Description |
|
||||
| :--- | :--- |
|
||||
| `ls` | List files and directories in the current path. |
|
||||
| `cd` | Change the current working directory. |
|
||||
| `cat` | Display the contents of a file. |
|
||||
| `ls` | List directory contents. |
|
||||
| `rm` | Remove a file. |
|
||||
| `mkdir` | Create a new directory. |
|
||||
| `man` | View the manual for a specific command (e.g., `man ls`). |
|
||||
| `sysfetch` | Display system and hardware information. |
|
||||
|
||||
|
||||
---
|
||||
[Return to Documentation Index](../README.md)
|
||||
@@ -13,3 +13,4 @@ backdrop: 000000
|
||||
/BoredOS
|
||||
protocol: limine
|
||||
path: boot():/boredos.elf
|
||||
cmdline: -v
|
||||
|
||||
BIN
screenshot.jpg
|
Before Width: | Height: | Size: 342 KiB After Width: | Height: | Size: 416 KiB |
@@ -7,12 +7,13 @@ extern syscall_handler_c
|
||||
section .text
|
||||
|
||||
; Syscall ABI:
|
||||
; RDI = syscall_num
|
||||
; RSI = arg1
|
||||
; RDX = arg2
|
||||
; R10 = arg3
|
||||
; R8 = arg4
|
||||
; R9 = arg5
|
||||
; RAX = syscall_num
|
||||
; RDI = arg1
|
||||
; RSI = arg2
|
||||
; RDX = arg3
|
||||
; R10 = arg4
|
||||
; R8 = arg5
|
||||
; R9 = arg6
|
||||
|
||||
syscall_entry:
|
||||
swapgs
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
; Copyright (c) 2023-2026 Chris (boreddevnl)
|
||||
; This software is released under the GNU General Public License v3.0. See LICENSE file for details.
|
||||
; This header needs to maintain in any file it is present in, as per the GPL license terms.
|
||||
global test_syscall
|
||||
section .text
|
||||
|
||||
test_syscall:
|
||||
; syscall number in RDI
|
||||
mov rdi, 1
|
||||
; string pointer in RSI
|
||||
lea rsi, [rel test_msg]
|
||||
|
||||
; The SYSCALL instruction
|
||||
syscall
|
||||
|
||||
ret
|
||||
|
||||
section .rodata
|
||||
test_msg: db "Hello from Syscall!", 10, 0
|
||||
@@ -1,25 +0,0 @@
|
||||
; Copyright (c) 2023-2026 Chris (boreddevnl)
|
||||
; This software is released under the GNU General Public License v3.0. See LICENSE file for details.
|
||||
; This header needs to maintain in any file it is present in, as per the GPL license terms.
|
||||
global user_test_function
|
||||
|
||||
section .text
|
||||
user_test_function:
|
||||
; Syscall convention
|
||||
.loop:
|
||||
; Invoke SYS_WRITE (Syscall #1)
|
||||
mov rdi, 1 ; arg1: fd = 1 (stdout)
|
||||
lea rsi, [rel msg] ; arg2: buffer (RIP-relative)
|
||||
mov rdx, 15 ; arg3: length
|
||||
mov eax, 1 ; syscall_num = 1 (SYS_WRITE)
|
||||
syscall
|
||||
|
||||
; Some delay loop
|
||||
mov rcx, 100000000
|
||||
.delay:
|
||||
dec rcx
|
||||
jnz .delay
|
||||
|
||||
jmp .loop
|
||||
|
||||
msg: db "Hello syscall!", 10
|
||||
100
src/core/kconsole.c
Normal file
@@ -0,0 +1,100 @@
|
||||
#include "kconsole.h"
|
||||
#include "graphics.h"
|
||||
#include "sys/spinlock.h"
|
||||
#include <stddef.h>
|
||||
|
||||
static spinlock_t console_lock = SPINLOCK_INIT;
|
||||
static int cursor_x = 0;
|
||||
static int cursor_y = 0;
|
||||
static bool kconsole_active = false;
|
||||
static uint32_t text_color = 0xFFFFFFFF; // White
|
||||
|
||||
#define CHAR_WIDTH 8
|
||||
#define CHAR_HEIGHT 10
|
||||
|
||||
void kconsole_init(void) {
|
||||
cursor_x = 10;
|
||||
cursor_y = 10;
|
||||
kconsole_active = false;
|
||||
|
||||
// Initial clear screen during boot
|
||||
graphics_clear_back_buffer(0x00000000);
|
||||
graphics_mark_screen_dirty();
|
||||
graphics_flip_buffer();
|
||||
}
|
||||
|
||||
void kconsole_set_active(bool active) {
|
||||
kconsole_active = active;
|
||||
}
|
||||
|
||||
void kconsole_set_color(uint32_t color) {
|
||||
uint64_t flags = spinlock_acquire_irqsave(&console_lock);
|
||||
text_color = color;
|
||||
spinlock_release_irqrestore(&console_lock, flags);
|
||||
}
|
||||
|
||||
static void kconsole_scroll(void) {
|
||||
if (cursor_y + CHAR_HEIGHT >= get_screen_height() - 10) {
|
||||
graphics_scroll_back_buffer(CHAR_HEIGHT);
|
||||
cursor_y -= CHAR_HEIGHT;
|
||||
graphics_mark_screen_dirty();
|
||||
graphics_flip_buffer();
|
||||
}
|
||||
}
|
||||
|
||||
static void kconsole_putc_nolock(char c) {
|
||||
if (!kconsole_active) return;
|
||||
|
||||
if (c == '\n') {
|
||||
cursor_x = 10;
|
||||
cursor_y += CHAR_HEIGHT;
|
||||
kconsole_scroll();
|
||||
graphics_flip_buffer();
|
||||
return;
|
||||
}
|
||||
|
||||
if (c == '\r') {
|
||||
cursor_x = 10;
|
||||
return;
|
||||
}
|
||||
|
||||
if (c == '\t') {
|
||||
cursor_x += CHAR_WIDTH * 4;
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw character
|
||||
draw_char_bitmap(cursor_x, cursor_y, c, text_color);
|
||||
graphics_mark_screen_dirty();
|
||||
|
||||
cursor_x += CHAR_WIDTH;
|
||||
if (cursor_x + CHAR_WIDTH >= get_screen_width() - 10) {
|
||||
cursor_x = 10;
|
||||
cursor_y += CHAR_HEIGHT;
|
||||
kconsole_scroll();
|
||||
}
|
||||
}
|
||||
|
||||
void kconsole_putc(char c) {
|
||||
uint64_t flags = spinlock_acquire_irqsave(&console_lock);
|
||||
kconsole_putc_nolock(c);
|
||||
spinlock_release_irqrestore(&console_lock, flags);
|
||||
}
|
||||
|
||||
void kconsole_write(const char *s) {
|
||||
if (!s) return;
|
||||
|
||||
uint64_t flags = spinlock_acquire_irqsave(&console_lock);
|
||||
if (!kconsole_active) {
|
||||
spinlock_release_irqrestore(&console_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
while (*s) {
|
||||
kconsole_putc_nolock(*s++);
|
||||
}
|
||||
|
||||
// Flip once after a write batch to keep console updates coherent.
|
||||
graphics_flip_buffer();
|
||||
spinlock_release_irqrestore(&console_lock, flags);
|
||||
}
|
||||
13
src/core/kconsole.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef KCONSOLE_H
|
||||
#define KCONSOLE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void kconsole_init(void);
|
||||
void kconsole_set_color(uint32_t color);
|
||||
void kconsole_putc(char c);
|
||||
void kconsole_write(const char *s);
|
||||
void kconsole_set_active(bool active);
|
||||
|
||||
#endif // KCONSOLE_H
|
||||
@@ -155,3 +155,17 @@ void k_beep_process(void) {
|
||||
}
|
||||
}
|
||||
|
||||
char *k_strstr(const char *haystack, const char *needle) {
|
||||
if (!*needle) return (char *)haystack;
|
||||
for (; *haystack; haystack++) {
|
||||
const char *h = haystack;
|
||||
const char *n = needle;
|
||||
while (*h && *n && *h == *n) {
|
||||
h++;
|
||||
n++;
|
||||
}
|
||||
if (!*n) return (char *)haystack;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,5 +26,6 @@ void k_reboot(void);
|
||||
void k_shutdown(void);
|
||||
void k_beep(int freq, int ms);
|
||||
void k_beep_process(void);
|
||||
char *k_strstr(const char *haystack, const char *needle);
|
||||
|
||||
#endif
|
||||
|
||||
304
src/core/main.c
@@ -18,6 +18,8 @@
|
||||
#include "fat32.h"
|
||||
#include "tar.h"
|
||||
#include "vfs.h"
|
||||
#include "core/kconsole.h"
|
||||
#include "core/kutils.h"
|
||||
#include "memory_manager.h"
|
||||
#include "platform.h"
|
||||
#include "wallpaper.h"
|
||||
@@ -26,8 +28,12 @@
|
||||
#include "lapic.h"
|
||||
#include "fs/sysfs.h"
|
||||
#include "fs/procfs.h"
|
||||
#include "fs/bootfs.h"
|
||||
#include "sys/kernel_subsystem.h"
|
||||
#include "sys/module_manager.h"
|
||||
#include "sys/bootfs_state.h"
|
||||
#include "input/keymap.h"
|
||||
#include "input/keyboard.h"
|
||||
|
||||
extern void sysfs_init_subsystems(void);
|
||||
|
||||
@@ -60,12 +66,26 @@ static volatile struct limine_smp_request smp_request = {
|
||||
.flags = 0
|
||||
};
|
||||
|
||||
__attribute__((used, section(".requests")))
|
||||
static volatile struct limine_bootloader_info_request bootloader_info_request = {
|
||||
.id = LIMINE_BOOTLOADER_INFO_REQUEST,
|
||||
.revision = 0
|
||||
};
|
||||
|
||||
__attribute__((used, section(".requests")))
|
||||
static volatile struct limine_kernel_file_request kernel_file_request = {
|
||||
.id = LIMINE_KERNEL_FILE_REQUEST,
|
||||
.revision = 0
|
||||
};
|
||||
|
||||
__attribute__((used, section(".requests_start")))
|
||||
static volatile struct limine_request *const requests_start_marker[] = {
|
||||
(struct limine_request *)&framebuffer_request,
|
||||
(struct limine_request *)&memmap_request,
|
||||
(struct limine_request *)&module_request,
|
||||
(struct limine_request *)&smp_request,
|
||||
(struct limine_request *)&bootloader_info_request,
|
||||
(struct limine_request *)&kernel_file_request,
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -91,26 +111,103 @@ static void init_serial() {
|
||||
outb(0x3F8 + 4, 0x0B);
|
||||
}
|
||||
|
||||
static spinlock_t serial_lock = SPINLOCK_INIT;
|
||||
|
||||
void serial_write(const char *str) {
|
||||
while (*str) {
|
||||
uint64_t flags = spinlock_acquire_irqsave(&serial_lock);
|
||||
const char *p = str;
|
||||
while (*p) {
|
||||
char c = *p++;
|
||||
while ((inb(0x3F8 + 5) & 0x20) == 0);
|
||||
outb(0x3F8, *str++);
|
||||
outb(0x3F8, c);
|
||||
}
|
||||
kconsole_write(str);
|
||||
spinlock_release_irqrestore(&serial_lock, flags);
|
||||
}
|
||||
|
||||
static void serial_write_num_locked(uint32_t n) {
|
||||
if (n >= 10) serial_write_num_locked(n / 10);
|
||||
char c = '0' + (n % 10);
|
||||
while ((inb(0x3F8 + 5) & 0x20) == 0);
|
||||
outb(0x3F8, c);
|
||||
kconsole_putc(c);
|
||||
}
|
||||
|
||||
void serial_write_num(uint32_t n) {
|
||||
if (n >= 10) serial_write_num(n / 10);
|
||||
uint64_t flags = spinlock_acquire_irqsave(&serial_lock);
|
||||
serial_write_num_locked(n);
|
||||
spinlock_release_irqrestore(&serial_lock, flags);
|
||||
}
|
||||
|
||||
static void serial_write_hex_locked(uint64_t n) {
|
||||
char *hex = "0123456789ABCDEF";
|
||||
if (n >= 16) serial_write_hex_locked(n / 16);
|
||||
char c = hex[n % 16];
|
||||
while ((inb(0x3F8 + 5) & 0x20) == 0);
|
||||
outb(0x3F8, '0' + (n % 10));
|
||||
outb(0x3F8, c);
|
||||
kconsole_putc(c);
|
||||
}
|
||||
|
||||
void serial_write_hex(uint64_t n) {
|
||||
char *hex = "0123456789ABCDEF";
|
||||
if (n >= 16) serial_write_hex(n / 16);
|
||||
while ((inb(0x3F8 + 5) & 0x20) == 0);
|
||||
outb(0x3F8, hex[n % 16]);
|
||||
uint64_t flags = spinlock_acquire_irqsave(&serial_lock);
|
||||
serial_write_hex_locked(n);
|
||||
spinlock_release_irqrestore(&serial_lock, flags);
|
||||
}
|
||||
|
||||
void log_ok(const char *msg) {
|
||||
serial_write("[ ");
|
||||
kconsole_set_color(0xFF00FF00);
|
||||
serial_write("OK");
|
||||
kconsole_set_color(0xFFFFFFFF);
|
||||
serial_write(" ] ");
|
||||
serial_write(msg);
|
||||
serial_write("\n");
|
||||
}
|
||||
|
||||
void log_fail(const char *msg) {
|
||||
serial_write("[ ");
|
||||
kconsole_set_color(0xFFFF0000);
|
||||
serial_write("FAIL");
|
||||
kconsole_set_color(0xFFFFFFFF);
|
||||
serial_write(" ] ");
|
||||
serial_write(msg);
|
||||
serial_write("\n");
|
||||
}
|
||||
|
||||
static void print_verbose_boot_banner(void) {
|
||||
kconsole_set_color(0xFFB589D6);
|
||||
serial_write("==================== ");
|
||||
kconsole_set_color(0xFFFFFFFF);
|
||||
serial_write("__ ____ ____ \n");
|
||||
|
||||
kconsole_set_color(0xFFB589D6);
|
||||
serial_write("=================== ");
|
||||
kconsole_set_color(0xFFFFFFFF);
|
||||
serial_write("/ /_ / __ \\/ ___\\\n");
|
||||
|
||||
kconsole_set_color(0xFF569CD6);
|
||||
serial_write("================== ");
|
||||
kconsole_set_color(0xFFFFFFFF);
|
||||
serial_write("/ __ \\/ / / /\\___ \\\n");
|
||||
|
||||
kconsole_set_color(0xFF569CD6);
|
||||
serial_write("================= ");
|
||||
kconsole_set_color(0xFFFFFFFF);
|
||||
serial_write("/ /_/ / /_/ /____/ /\n");
|
||||
|
||||
kconsole_set_color(0xFF4EC9B0);
|
||||
serial_write("================ ");
|
||||
kconsole_set_color(0xFFFFFFFF);
|
||||
serial_write("/_.___/\\____//_____/ \n");
|
||||
|
||||
kconsole_set_color(0xFF4EC9B0);
|
||||
serial_write("=============== \n");
|
||||
|
||||
kconsole_set_color(0xFFFFFFFF);
|
||||
serial_write("\n");
|
||||
}
|
||||
|
||||
|
||||
// Kernel Entry Point
|
||||
|
||||
static void fat32_mkdir_recursive(const char *path) {
|
||||
@@ -138,67 +235,122 @@ static void fat32_mkdir_recursive(const char *path) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool usage_policy_prompt(void) {
|
||||
kconsole_set_active(true);
|
||||
serial_write("BoredOS - Please read the Usage Policy provided with this software before continuing.\n");
|
||||
serial_write("Do you agree to the terms? [y/N]\n");
|
||||
|
||||
while (1) {
|
||||
if ((inb(0x64) & 1) == 0) {
|
||||
asm volatile("pause");
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t scancode = inb(0x60);
|
||||
keyboard_event_t ev;
|
||||
if (!keyboard_handle_set1_scancode(scancode, &ev)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ev.pressed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ev.keycode == KEY_ENTER || ev.keycode == KEY_KP_ENTER) {
|
||||
serial_write("\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ev.is_text) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ev.codepoint == 'y' || ev.codepoint == 'Y') {
|
||||
serial_write("\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ev.codepoint == 'n' || ev.codepoint == 'N') {
|
||||
serial_write("\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void kmain(void) {
|
||||
init_serial();
|
||||
vfs_init();
|
||||
serial_write("\n[DEBUG] Entering kmain...\n");
|
||||
serial_write("\n");
|
||||
|
||||
platform_init();
|
||||
serial_write("[DEBUG] platform_init OK\n");
|
||||
log_ok("Platform initialized");
|
||||
|
||||
extern uint64_t hhdm_offset;
|
||||
extern uint64_t kernel_phys_base;
|
||||
extern uint64_t kernel_virt_base;
|
||||
|
||||
serial_write("[DEBUG] HHDM Offset: 0x");
|
||||
serial_write("[INIT] HHDM Offset: 0x");
|
||||
serial_write_hex(hhdm_offset);
|
||||
serial_write("\n");
|
||||
serial_write("[DEBUG] Kernel Phys: 0x");
|
||||
serial_write("[INIT] Kernel Phys: 0x");
|
||||
serial_write_hex(kernel_phys_base);
|
||||
serial_write("\n");
|
||||
serial_write("[DEBUG] Kernel Virt: 0x");
|
||||
serial_write("[INIT] Kernel Virt: 0x");
|
||||
serial_write_hex(kernel_virt_base);
|
||||
serial_write("\n");
|
||||
|
||||
if (memmap_request.response != NULL) {
|
||||
// The memory manager will now scan the memory map and manage all usable regions.
|
||||
memory_manager_init_from_memmap(memmap_request.response);
|
||||
serial_write("[DEBUG] memory_manager_init OK\n");
|
||||
smp_init_bsp();
|
||||
serial_write("[DEBUG] smp_init_bsp OK\n");
|
||||
} else {
|
||||
serial_write("[DEBUG] ERROR: No usable memory for heap! Check Limine memmap.\n");
|
||||
hcf();
|
||||
}
|
||||
|
||||
if (framebuffer_request.response == NULL || framebuffer_request.response->framebuffer_count < 1) {
|
||||
serial_write("[DEBUG] No framebuffer! Halting.\n");
|
||||
serial_write("[INIT] No framebuffer! Halting.\n");
|
||||
hcf();
|
||||
}
|
||||
|
||||
struct limine_framebuffer *fb = framebuffer_request.response->framebuffers[0];
|
||||
graphics_init(fb);
|
||||
serial_write("[DEBUG] graphics_init OK\n");
|
||||
kconsole_init();
|
||||
|
||||
// Check for verbose boot flag
|
||||
if (kernel_file_request.response != NULL && kernel_file_request.response->kernel_file != NULL) {
|
||||
const char *cmdline = kernel_file_request.response->kernel_file->cmdline;
|
||||
if (cmdline != NULL && k_strstr(cmdline, "-v") != NULL) {
|
||||
kconsole_set_active(true);
|
||||
}
|
||||
}
|
||||
|
||||
log_ok("Graphics and Console ready");
|
||||
|
||||
if (memmap_request.response != NULL) {
|
||||
memory_manager_init_from_memmap(memmap_request.response);
|
||||
log_ok("Memory manager ready");
|
||||
smp_init_bsp();
|
||||
log_ok("SMP BSP initialized");
|
||||
} else {
|
||||
log_fail("No usable memory for heap! Check Limine memmap.");
|
||||
hcf();
|
||||
}
|
||||
|
||||
gdt_init();
|
||||
serial_write("[DEBUG] gdt_init OK\n");
|
||||
log_ok("GDT initialized");
|
||||
|
||||
paging_init();
|
||||
serial_write("[DEBUG] paging_init OK\n");
|
||||
log_ok("Paging ready");
|
||||
|
||||
syscall_init();
|
||||
serial_write("[DEBUG] syscall_init OK\n");
|
||||
log_ok("Syscalls ready");
|
||||
|
||||
idt_init();
|
||||
idt_register_interrupts();
|
||||
idt_load();
|
||||
serial_write("[DEBUG] idt_init OK\n");
|
||||
log_ok("IDT ready");
|
||||
print_verbose_boot_banner();
|
||||
kconsole_set_color(0xFFFFFF55);
|
||||
serial_write("Welcome to BoredOS!\n");
|
||||
kconsole_set_color(0xFFFFFFFF);
|
||||
|
||||
process_init();
|
||||
|
||||
|
||||
fat32_init();
|
||||
serial_write("[DEBUG] fat32_init OK\n");
|
||||
log_ok("FAT32 ready");
|
||||
fat32_mkdir("/bin");
|
||||
fat32_mkdir("/Library");
|
||||
fat32_mkdir("/Library/images");
|
||||
@@ -206,19 +358,74 @@ void kmain(void) {
|
||||
fat32_mkdir("/Library/images/gif");
|
||||
fat32_mkdir("/Library/Fonts");
|
||||
fat32_mkdir("/Library/DOOM");
|
||||
fat32_mkdir("/Library/conf");
|
||||
fat32_mkdir("/Library/bsh");
|
||||
fat32_mkdir("/docs");
|
||||
fat32_mkdir("/root");
|
||||
fat32_mkdir("/root/Desktop");
|
||||
fat32_mkdir("/root/Pictures");
|
||||
fat32_mkdir("/root/Documents");
|
||||
fat32_mkdir("/root/Downloads");
|
||||
|
||||
// Initialize Virtual Filesystems
|
||||
sysfs_init_subsystems();
|
||||
vfs_mount("/sys", "sysfs", "sysfs", sysfs_get_ops(), NULL);
|
||||
vfs_mount("/proc", "procfs", "procfs", procfs_get_ops(), NULL);
|
||||
|
||||
bootfs_init();
|
||||
|
||||
if (bootloader_info_request.response != NULL) {
|
||||
if (bootloader_info_request.response->name) {
|
||||
k_strcpy(g_bootfs_state.bootloader_name, bootloader_info_request.response->name);
|
||||
}
|
||||
if (bootloader_info_request.response->version) {
|
||||
k_strcpy(g_bootfs_state.bootloader_version, bootloader_info_request.response->version);
|
||||
}
|
||||
}
|
||||
|
||||
if (kernel_file_request.response != NULL && kernel_file_request.response->kernel_file != NULL) {
|
||||
g_bootfs_state.kernel_size = kernel_file_request.response->kernel_file->size;
|
||||
serial_write("[INIT] Kernel size from bootloader: ");
|
||||
serial_write_hex(g_bootfs_state.kernel_size);
|
||||
serial_write(" bytes\n");
|
||||
}
|
||||
|
||||
extern uint32_t wm_get_ticks(void);
|
||||
g_bootfs_state.boot_time_ms = wm_get_ticks();
|
||||
|
||||
if (module_request.response != NULL) {
|
||||
g_bootfs_state.num_modules = module_request.response->module_count;
|
||||
|
||||
serial_write("[INIT] Scanning modules for bootfs state...\n");
|
||||
for (uint64_t i = 0; i < module_request.response->module_count; i++) {
|
||||
struct limine_file *mod = module_request.response->modules[i];
|
||||
const char *path = mod->path;
|
||||
|
||||
if (fs_starts_with(path, "boot():")) path += 7;
|
||||
else if (fs_starts_with(path, "boot:///")) path += 8;
|
||||
|
||||
int path_len = 0;
|
||||
while (path[path_len]) path_len++;
|
||||
|
||||
serial_write("[INIT] Module: ");
|
||||
serial_write(path);
|
||||
serial_write(" (");
|
||||
serial_write_hex(mod->size);
|
||||
serial_write(" bytes)\n");
|
||||
|
||||
if (path_len >= 5 && path[path_len-4] == '.' && path[path_len-3] == 't' &&
|
||||
path[path_len-2] == 'a' && path[path_len-1] == 'r') {
|
||||
g_bootfs_state.initrd_size = mod->size;
|
||||
serial_write("[INIT] -> Initrd detected\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vfs_mount("/boot", "bootfs", "bootfs", bootfs_get_ops(), NULL);
|
||||
|
||||
if (module_request.response == NULL) {
|
||||
serial_write("[DEBUG] ERROR: Limine Module Response is NULL!\n");
|
||||
log_fail("Limine module response NULL");
|
||||
} else {
|
||||
serial_write("[DEBUG] Limine Module Response found. Count: ");
|
||||
serial_write_num(module_request.response->module_count);
|
||||
serial_write("\n");
|
||||
log_ok("Limine modules loaded");
|
||||
for (uint64_t i = 0; i < module_request.response->module_count; i++) {
|
||||
struct limine_file *mod = module_request.response->modules[i];
|
||||
|
||||
@@ -230,7 +437,7 @@ void kmain(void) {
|
||||
while(clean_path[len]) len++;
|
||||
|
||||
if (len >= 4 && clean_path[len-4] == '.' && clean_path[len-3] == 't' && clean_path[len-2] == 'a' && clean_path[len-1] == 'r') {
|
||||
serial_write("[DEBUG] Parsing TAR initrd: ");
|
||||
serial_write("[INIT] Parsing TAR initrd: ");
|
||||
serial_write(clean_path);
|
||||
serial_write("\n");
|
||||
tar_parse(mod->address, mod->size);
|
||||
@@ -252,15 +459,13 @@ void kmain(void) {
|
||||
fat32_close(fh);
|
||||
}
|
||||
}
|
||||
// Register all discovered modules in our module manager for /sys/module
|
||||
module_manager_register(clean_path, (uint64_t)mod->address, mod->size);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize fonts now that FAT32 and modules are loaded
|
||||
uint64_t current_rsp;
|
||||
asm volatile("mov %%rsp, %0" : "=r"(current_rsp));
|
||||
serial_write("[DEBUG] Stack Alignment: 0x");
|
||||
serial_write("[INIT] Stack Alignment: 0x");
|
||||
serial_write_hex(current_rsp);
|
||||
serial_write("\n");
|
||||
|
||||
@@ -270,24 +475,31 @@ void kmain(void) {
|
||||
ps2_init();
|
||||
asm("sti");
|
||||
|
||||
// Initialize LAPIC for IPI support
|
||||
keymap_init();
|
||||
serial_write("[INIT] Keymap initialized");
|
||||
|
||||
lapic_init();
|
||||
|
||||
// Initialize SMP
|
||||
if (smp_request.response != NULL) {
|
||||
uint32_t online = smp_init(smp_request.response);
|
||||
serial_write("[DEBUG] SMP init complete, CPUs online: ");
|
||||
serial_write_num(online);
|
||||
serial_write("\n");
|
||||
log_ok("SMP initialized");
|
||||
} else {
|
||||
serial_write("[DEBUG] No SMP response from bootloader\n");
|
||||
serial_write("[INIT] No SMP response from bootloader\n");
|
||||
smp_init(NULL);
|
||||
}
|
||||
|
||||
if (!usage_policy_prompt()) {
|
||||
log_fail("Usage policy not accepted, halting");
|
||||
hcf();
|
||||
}
|
||||
|
||||
wm_init();
|
||||
|
||||
asm volatile("sti");
|
||||
|
||||
extern void bootfs_refresh_from_disk(void);
|
||||
bootfs_refresh_from_disk();
|
||||
|
||||
while (1) {
|
||||
wm_process_input();
|
||||
wm_process_deferred_thumbs();
|
||||
|
||||
@@ -15,7 +15,7 @@ static size_t man_strlen(const char *str) {
|
||||
|
||||
static void write_man_file(const char *name, const char *content) {
|
||||
char path[128] = "/Library/man/";
|
||||
int i = 15;
|
||||
int i = 13;
|
||||
while (*name) path[i++] = *name++;
|
||||
path[i++] = '.';
|
||||
path[i++] = 't';
|
||||
@@ -56,6 +56,7 @@ void create_man_entries(void) {
|
||||
write_man_file("cc", "CC - C Compiler\n\nUsage: cc <file.c>\n\nThe BoredOS C Compiler. Compiles C source files into executables. (execute these with ./>file<)");
|
||||
write_man_file("crash", "CRASH - Trigger kernel exception\n\nUsage: crash\n\nIntentionally triggers a null pointer dereference to test handlers.");
|
||||
write_man_file("sysfetch", "SYSFETCH - Show OS information\n\nUsage: sysfetch\n\nDisplays system information in a neofetch-like layout. Configurable via /Library/conf/sysfetch.cfg.");
|
||||
write_man_file("uname", "UNAME - Print system information\n\nUsage: uname [-amnoprsv]\n\nOptions:\n -a Print all information\n -s Kernel name\n -n Node name\n -r Kernel release\n -v Kernel build date and time\n -m Machine hardware name\n -p Processor type\n -o Operating system name");
|
||||
write_man_file("meminfo", "MEMINFO - Memory usage stats\n\nUsage: meminfo\n\nDisplays current physical and virtual memory allocation statistics.");
|
||||
write_man_file("pci_list", "PCI_LIST - Scan PCI bus\n\nUsage: pci_list\n\nScans the PCI bus and lists all detected hardware devices.");
|
||||
write_man_file("reboot", "REBOOT - Restart system\n\nUsage: reboot\n\nRestarts the computer immediately.");
|
||||
@@ -69,6 +70,7 @@ void create_man_entries(void) {
|
||||
write_man_file("math", "MATH - Expression evaluator\n\nUsage: math <expression>\n\nEvaluates simple arithmetic expressions from the command line.");
|
||||
write_man_file("viewer", "VIEWER - Image viewer\n\nUsage: viewer <file.ppm>\n\nA graphical application for viewing image files.");
|
||||
write_man_file("settings", "SETTINGS - System settings\n\nUsage: settings\n\nOpens the graphical system configuration tool.");
|
||||
write_man_file("2048", "2048 - Classic game\n\nUsage: 2048\n\nPlays the classic 2048 game.");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "limine.h"
|
||||
#include <stddef.h>
|
||||
#include "platform.h"
|
||||
#include "kutils.h"
|
||||
static volatile struct limine_hhdm_request hhdm_request __attribute__((used, section(".requests"))) = {
|
||||
.id = LIMINE_HHDM_REQUEST,
|
||||
.revision = 0,
|
||||
@@ -80,3 +81,73 @@ void platform_get_cpu_vendor(char *vendor) {
|
||||
*((uint32_t *)&p[8]) = ecx;
|
||||
p[12] = '\0';
|
||||
}
|
||||
|
||||
void platform_get_cpu_info(cpu_info_t *info) {
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
|
||||
// CPUID leaf 1: basic feature information
|
||||
asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(1));
|
||||
|
||||
info->stepping = eax & 0xF;
|
||||
info->model = (eax >> 4) & 0xF;
|
||||
info->family = (eax >> 8) & 0xF;
|
||||
info->microcode = (ebx >> 8) & 0xFF;
|
||||
info->flags = ((uint64_t)ecx << 32) | edx; // ECX and EDX contain feature flags
|
||||
info->cache_size = (ebx >> 16) & 0xFF; // Cache line size in bytes
|
||||
}
|
||||
|
||||
void platform_get_cpu_flags(char *flags_str) {
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
|
||||
flags_str[0] = '\0';
|
||||
|
||||
// CPUID leaf 1
|
||||
asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(1));
|
||||
|
||||
// ECX flags
|
||||
if (ecx & (1 << 0)) k_strcpy(flags_str + k_strlen(flags_str), "sse3 ");
|
||||
if (ecx & (1 << 1)) k_strcpy(flags_str + k_strlen(flags_str), "pclmulqdq ");
|
||||
if (ecx & (1 << 3)) k_strcpy(flags_str + k_strlen(flags_str), "monitor ");
|
||||
if (ecx & (1 << 6)) k_strcpy(flags_str + k_strlen(flags_str), "ssse3 ");
|
||||
if (ecx & (1 << 9)) k_strcpy(flags_str + k_strlen(flags_str), "sdbg ");
|
||||
if (ecx & (1 << 12)) k_strcpy(flags_str + k_strlen(flags_str), "fma ");
|
||||
if (ecx & (1 << 13)) k_strcpy(flags_str + k_strlen(flags_str), "cx16 ");
|
||||
if (ecx & (1 << 19)) k_strcpy(flags_str + k_strlen(flags_str), "sse4_1 ");
|
||||
if (ecx & (1 << 20)) k_strcpy(flags_str + k_strlen(flags_str), "sse4_2 ");
|
||||
if (ecx & (1 << 23)) k_strcpy(flags_str + k_strlen(flags_str), "popcnt ");
|
||||
if (ecx & (1 << 25)) k_strcpy(flags_str + k_strlen(flags_str), "aes ");
|
||||
if (ecx & (1 << 26)) k_strcpy(flags_str + k_strlen(flags_str), "xsave ");
|
||||
if (ecx & (1 << 28)) k_strcpy(flags_str + k_strlen(flags_str), "avx ");
|
||||
|
||||
// EDX flags
|
||||
if (edx & (1 << 0)) k_strcpy(flags_str + k_strlen(flags_str), "fpu ");
|
||||
if (edx & (1 << 3)) k_strcpy(flags_str + k_strlen(flags_str), "pse ");
|
||||
if (edx & (1 << 4)) k_strcpy(flags_str + k_strlen(flags_str), "tsc ");
|
||||
if (edx & (1 << 6)) k_strcpy(flags_str + k_strlen(flags_str), "pae ");
|
||||
if (edx & (1 << 8)) k_strcpy(flags_str + k_strlen(flags_str), "cx8 ");
|
||||
if (edx & (1 << 9)) k_strcpy(flags_str + k_strlen(flags_str), "apic ");
|
||||
if (edx & (1 << 11)) k_strcpy(flags_str + k_strlen(flags_str), "sep ");
|
||||
if (edx & (1 << 15)) k_strcpy(flags_str + k_strlen(flags_str), "cmov ");
|
||||
if (edx & (1 << 23)) k_strcpy(flags_str + k_strlen(flags_str), "mmx ");
|
||||
if (edx & (1 << 24)) k_strcpy(flags_str + k_strlen(flags_str), "fxsr ");
|
||||
if (edx & (1 << 25)) k_strcpy(flags_str + k_strlen(flags_str), "sse ");
|
||||
if (edx & (1 << 26)) k_strcpy(flags_str + k_strlen(flags_str), "sse2 ");
|
||||
|
||||
// Extended leaf 0x80000001 for advanced flags
|
||||
asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(0x80000001));
|
||||
|
||||
if (edx & (1 << 11)) k_strcpy(flags_str + k_strlen(flags_str), "syscall ");
|
||||
if (edx & (1 << 20)) k_strcpy(flags_str + k_strlen(flags_str), "nx ");
|
||||
if (edx & (1 << 26)) k_strcpy(flags_str + k_strlen(flags_str), "pdpe1gb ");
|
||||
if (edx & (1 << 27)) k_strcpy(flags_str + k_strlen(flags_str), "rdtscp ");
|
||||
if (edx & (1 << 29)) k_strcpy(flags_str + k_strlen(flags_str), "lm ");
|
||||
|
||||
if (ecx & (1 << 0)) k_strcpy(flags_str + k_strlen(flags_str), "lahf_lm ");
|
||||
if (ecx & (1 << 5)) k_strcpy(flags_str + k_strlen(flags_str), "abm ");
|
||||
|
||||
// Remove trailing space
|
||||
int len = k_strlen(flags_str);
|
||||
if (len > 0 && flags_str[len-1] == ' ') {
|
||||
flags_str[len-1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,21 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
uint32_t family;
|
||||
uint32_t model;
|
||||
uint32_t stepping;
|
||||
uint32_t microcode;
|
||||
uint64_t flags;
|
||||
uint32_t cache_size;
|
||||
} cpu_info_t;
|
||||
|
||||
void platform_init(void);
|
||||
uint64_t p2v(uint64_t phys);
|
||||
uint64_t v2p(uint64_t virt);
|
||||
void platform_get_cpu_model(char *model);
|
||||
void platform_get_cpu_vendor(char *vendor);
|
||||
void platform_get_cpu_info(cpu_info_t *info);
|
||||
void platform_get_cpu_flags(char *flags_str);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -13,10 +13,10 @@ void get_os_info(os_info_t *info) {
|
||||
for (size_t i = 0; i < sizeof(os_info_t); i++) p[i] = 0;
|
||||
|
||||
const char *os_name = "BoredOS";
|
||||
const char *os_version = "26.4";
|
||||
const char *os_codename = "Voyager";
|
||||
const char *os_version = "26.5.1-stable";
|
||||
const char *os_codename = "Genesis";
|
||||
const char *kernel_name = "Boredkernel";
|
||||
const char *kernel_version = "4.0.0-stable";
|
||||
const char *kernel_version = "4.2.1-stable";
|
||||
const char *build_date = __DATE__;
|
||||
const char *build_time = __TIME__;
|
||||
const char *build_arch = "x86_64";
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "paging.h"
|
||||
#include "io.h"
|
||||
#include <stddef.h>
|
||||
#include "../sys/spinlock.h"
|
||||
|
||||
extern void serial_write(const char *str);
|
||||
extern void serial_write_num(uint64_t num);
|
||||
@@ -30,6 +31,7 @@ typedef struct {
|
||||
HBA_CMD_HEADER *cmd_list; // 1KB, 1KB aligned
|
||||
void *fis_base; // 256B, 256B aligned
|
||||
HBA_CMD_TBL *cmd_tbl; // Command table for slot 0
|
||||
spinlock_t lock; // Port-level lock for thread-safety
|
||||
} ahci_port_state_t;
|
||||
|
||||
static ahci_port_state_t ports[MAX_AHCI_PORTS];
|
||||
@@ -150,6 +152,7 @@ int ahci_read_sectors(int port_num, uint64_t lba, uint32_t count, uint8_t *buffe
|
||||
ahci_port_state_t *ps = &ports[port_num];
|
||||
if (!ps->active) return -1;
|
||||
|
||||
uint64_t rflags = spinlock_acquire_irqsave(&ps->lock);
|
||||
HBA_PORT *port = ps->port;
|
||||
|
||||
// Clear any pending interrupts/errors
|
||||
@@ -198,9 +201,8 @@ int ahci_read_sectors(int port_num, uint64_t lba, uint32_t count, uint8_t *buffe
|
||||
while (timeout-- > 0) {
|
||||
if (!(port->ci & (1 << slot))) break;
|
||||
if (port->is & (1 << 30)) { // Task File Error
|
||||
serial_write("[AHCI] Read error on port ");
|
||||
serial_write_num(port_num);
|
||||
serial_write("\n");
|
||||
spinlock_release_irqrestore(&ps->lock, rflags);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -209,9 +211,11 @@ int ahci_read_sectors(int port_num, uint64_t lba, uint32_t count, uint8_t *buffe
|
||||
serial_write("[AHCI] Read timeout on port ");
|
||||
serial_write_num(port_num);
|
||||
serial_write("\n");
|
||||
spinlock_release_irqrestore(&ps->lock, rflags);
|
||||
return -1;
|
||||
}
|
||||
|
||||
spinlock_release_irqrestore(&ps->lock, rflags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -220,6 +224,7 @@ int ahci_write_sectors(int port_num, uint64_t lba, uint32_t count, const uint8_t
|
||||
ahci_port_state_t *ps = &ports[port_num];
|
||||
if (!ps->active) return -1;
|
||||
|
||||
uint64_t rflags = spinlock_acquire_irqsave(&ps->lock);
|
||||
HBA_PORT *port = ps->port;
|
||||
|
||||
port->is = 0xFFFFFFFF;
|
||||
@@ -266,6 +271,7 @@ int ahci_write_sectors(int port_num, uint64_t lba, uint32_t count, const uint8_t
|
||||
serial_write("[AHCI] Write error on port ");
|
||||
serial_write_num(port_num);
|
||||
serial_write("\n");
|
||||
spinlock_release_irqrestore(&ps->lock, rflags);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -274,9 +280,11 @@ int ahci_write_sectors(int port_num, uint64_t lba, uint32_t count, const uint8_t
|
||||
serial_write("[AHCI] Write timeout on port ");
|
||||
serial_write_num(port_num);
|
||||
serial_write("\n");
|
||||
spinlock_release_irqrestore(&ps->lock, rflags);
|
||||
return -1;
|
||||
}
|
||||
|
||||
spinlock_release_irqrestore(&ps->lock, rflags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -387,9 +395,8 @@ void ahci_init(void) {
|
||||
for (int i = 0; i < 32; i++) {
|
||||
ports[i].active = false;
|
||||
|
||||
if (!(pi & (1 << i))) continue;
|
||||
|
||||
HBA_PORT *port = &abar->ports[i];
|
||||
ports[i].lock = SPINLOCK_INIT;
|
||||
int type = ahci_check_port_type(port);
|
||||
|
||||
if (type == 0) { // SATA drive
|
||||
|
||||
@@ -21,6 +21,8 @@ static int next_sd_index = 0; // For sda, sdb, sdc...
|
||||
|
||||
extern void serial_write(const char *str);
|
||||
extern void serial_write_num(uint64_t num);
|
||||
extern void log_ok(const char *msg);
|
||||
extern void log_fail(const char *msg);
|
||||
|
||||
// === String Helpers ===
|
||||
|
||||
@@ -306,14 +308,16 @@ void disk_register_partition(Disk *parent, uint32_t lba_offset, uint32_t sector_
|
||||
dm_strcpy(mount_path + 5, part->devname);
|
||||
|
||||
if (vfs_mount(mount_path, part->devname, "fat32", fat32_get_realfs_ops(), vol)) {
|
||||
serial_write("[VFS] Mounted ");
|
||||
serial_write(mount_path);
|
||||
serial_write(" to VFS\n");
|
||||
char ok_msg[64];
|
||||
dm_strcpy(ok_msg, "Mounted ");
|
||||
dm_strcpy(ok_msg + 8, mount_path);
|
||||
log_ok(ok_msg);
|
||||
wm_notify_fs_change();
|
||||
} else {
|
||||
serial_write("[VFS] Failed to mount ");
|
||||
serial_write(mount_path);
|
||||
serial_write("\n");
|
||||
char fail_msg[64];
|
||||
dm_strcpy(fail_msg, "Failed to mount ");
|
||||
dm_strcpy(fail_msg + 16, mount_path);
|
||||
log_fail(fail_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -499,7 +503,7 @@ void disk_manager_init(void) {
|
||||
next_sd_index = 0;
|
||||
next_drive_letter_idx = 0;
|
||||
|
||||
serial_write("[DISK] Disk manager initialized (VFS mode)\n");
|
||||
log_ok("Disk manager ready");
|
||||
// NOTE: Ramdisk (A:) is no longer registered here.
|
||||
// RAMFS is managed directly by fat32.c and mounted at "/" via VFS.
|
||||
}
|
||||
@@ -509,12 +513,13 @@ void disk_manager_scan(void) {
|
||||
ahci_init();
|
||||
|
||||
if (ahci_get_port_count() == 0) {
|
||||
serial_write("[DISK] No AHCI ports found, falling back to legacy IDE PIO...\n");
|
||||
serial_write("[DISK] No AHCI ports found, falling back to legacy IDE...\n");
|
||||
try_add_ata_drive(ATA_PRIMARY_IO, false, "IDE Primary Master");
|
||||
try_add_ata_drive(ATA_PRIMARY_IO, true, "IDE Primary Slave");
|
||||
try_add_ata_drive(ATA_SECONDARY_IO, false, "IDE Secondary Master");
|
||||
try_add_ata_drive(ATA_SECONDARY_IO, true, "IDE Secondary Slave");
|
||||
log_ok("IDE probing complete");
|
||||
} else {
|
||||
serial_write("[DISK] AHCI initialized successfully, skipping legacy IDE.\n");
|
||||
log_ok("AHCI ports initialized, skipping IDE");
|
||||
}
|
||||
}
|
||||
112
src/dev/ps2.c
@@ -8,6 +8,8 @@
|
||||
#include "lapic.h"
|
||||
#include "smp.h"
|
||||
#include <stdbool.h>
|
||||
#include "input/keyboard.h"
|
||||
#include "input/keymap.h"
|
||||
|
||||
extern void serial_print(const char *s);
|
||||
extern void serial_print_hex(uint64_t n);
|
||||
@@ -37,11 +39,6 @@ uint64_t timer_handler(registers_t *regs) {
|
||||
}
|
||||
|
||||
// --- Keyboard ---
|
||||
static bool shift_pressed = false;
|
||||
static bool caps_lock_on = false;
|
||||
bool ps2_ctrl_pressed = false;
|
||||
static bool extended_scancode = false;
|
||||
|
||||
static void ps2_kbd_wait_write(void) {
|
||||
uint32_t timeout = 100000;
|
||||
while (timeout--) {
|
||||
@@ -51,7 +48,11 @@ static void ps2_kbd_wait_write(void) {
|
||||
|
||||
static void ps2_update_leds(void) {
|
||||
uint8_t led_status = 0;
|
||||
if (caps_lock_on) led_status |= 4;
|
||||
uint32_t mods = keyboard_get_modifiers();
|
||||
|
||||
if (mods & KB_MOD_CAPS) led_status |= 4;
|
||||
if (mods & KB_MOD_NUM) led_status |= 2;
|
||||
if (mods & KB_MOD_SCROLL) led_status |= 1;
|
||||
|
||||
ps2_kbd_wait_write();
|
||||
outb(0x60, 0xED);
|
||||
@@ -59,97 +60,17 @@ static void ps2_update_leds(void) {
|
||||
outb(0x60, led_status);
|
||||
}
|
||||
|
||||
static char scancode_map[128] = {
|
||||
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
|
||||
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
|
||||
21, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0,
|
||||
'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, '*',
|
||||
22, ' ', 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
static char scancode_map_shift[128] = {
|
||||
0, 27, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b',
|
||||
'\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',
|
||||
21, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', 0,
|
||||
'|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0, '*',
|
||||
22, ' ', 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
uint64_t keyboard_handler(registers_t *regs) {
|
||||
uint8_t scancode = inb(0x60);
|
||||
|
||||
if (scancode == 0xE0) {
|
||||
extended_scancode = true;
|
||||
outb(0x20, 0x20);
|
||||
return (uint64_t)regs;
|
||||
keyboard_event_t ev;
|
||||
if (keyboard_handle_set1_scancode(scancode, &ev)) {
|
||||
// Update LEDs if a lock key state changed
|
||||
if (ev.keycode == KEY_CAPS_LOCK || ev.keycode == KEY_NUM_LOCK || ev.keycode == KEY_SCROLL_LOCK) {
|
||||
if (ev.pressed) ps2_update_leds();
|
||||
}
|
||||
|
||||
if (scancode == 0x1D) {
|
||||
ps2_ctrl_pressed = true;
|
||||
extended_scancode = false;
|
||||
} else if (scancode == 0x9D) {
|
||||
ps2_ctrl_pressed = false;
|
||||
extended_scancode = false;
|
||||
}
|
||||
|
||||
if (ps2_ctrl_pressed && scancode == 0x2E) {
|
||||
extern process_t* process_get_current(void);
|
||||
process_t* proc = process_get_current();
|
||||
if (proc && proc->is_user && proc->is_terminal_proc && proc->ui_window) {
|
||||
if (((Window*)proc->ui_window)->focused) {
|
||||
extern uint64_t process_terminate_current(void);
|
||||
outb(0x20, 0x20);
|
||||
return process_terminate_current();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (scancode == 0x2A || scancode == 0x36) { // Shift Down
|
||||
shift_pressed = true;
|
||||
} else if (scancode == 0xAA || scancode == 0xB6) { // Shift Up
|
||||
shift_pressed = false;
|
||||
} else if (scancode == 0x3A) { // Caps Lock Down
|
||||
caps_lock_on = !caps_lock_on;
|
||||
ps2_update_leds();
|
||||
} else if (!(scancode & 0x80)) { // Key Press
|
||||
if (extended_scancode) {
|
||||
extended_scancode = false;
|
||||
switch (scancode) {
|
||||
case 0x48: wm_handle_key(17, true); break; // Up arrow
|
||||
case 0x50: wm_handle_key(18, true); break; // Down arrow
|
||||
case 0x4B: wm_handle_key(19, true); break; // Left arrow
|
||||
case 0x4D: wm_handle_key(20, true); break; // Right arrow
|
||||
}
|
||||
} else {
|
||||
char c = shift_pressed ? scancode_map_shift[scancode] : scancode_map[scancode];
|
||||
if (c) {
|
||||
if (caps_lock_on) {
|
||||
if (c >= 'a' && c <= 'z') c -= 32;
|
||||
else if (c >= 'A' && c <= 'Z') c += 32;
|
||||
}
|
||||
wm_handle_key(c, true);
|
||||
}
|
||||
}
|
||||
} else if (scancode & 0x80) { // Key release
|
||||
if (extended_scancode) {
|
||||
extended_scancode = false;
|
||||
switch (scancode & 0x7F) { // Strip the release bit
|
||||
case 0x48: wm_handle_key(17, false); break; // Up arrow
|
||||
case 0x50: wm_handle_key(18, false); break; // Down arrow
|
||||
case 0x4B: wm_handle_key(19, false); break; // Left arrow
|
||||
case 0x4D: wm_handle_key(20, false); break; // Right arrow
|
||||
}
|
||||
} else {
|
||||
uint8_t base_scancode = scancode & 0x7F;
|
||||
char c = shift_pressed ? scancode_map_shift[base_scancode] : scancode_map[base_scancode];
|
||||
if (c) {
|
||||
if (caps_lock_on) {
|
||||
if (c >= 'a' && c <= 'z') c -= 32;
|
||||
else if (c >= 'A' && c <= 'Z') c += 32;
|
||||
}
|
||||
wm_handle_key(c, false);
|
||||
}
|
||||
}
|
||||
wm_handle_key_event(ev.keycode, ev.codepoint, ev.mods, ev.pressed);
|
||||
}
|
||||
|
||||
outb(0x20, 0x20); // EOI
|
||||
@@ -267,5 +188,12 @@ uint64_t mouse_handler(registers_t *regs) {
|
||||
}
|
||||
|
||||
void ps2_init(void) {
|
||||
keymap_init();
|
||||
keyboard_init();
|
||||
mouse_init();
|
||||
ps2_update_leds();
|
||||
}
|
||||
|
||||
bool ps2_shift_pressed(void) {
|
||||
return keyboard_shift_pressed();
|
||||
}
|
||||
@@ -13,4 +13,6 @@ uint64_t timer_handler(registers_t *regs);
|
||||
uint64_t keyboard_handler(registers_t *regs);
|
||||
uint64_t mouse_handler(registers_t *regs);
|
||||
|
||||
bool ps2_shift_pressed(void);
|
||||
|
||||
#endif
|
||||
|
||||
BIN
src/fonts/Cantarell-Regular.ttf
Normal file
BIN
src/fonts/FiraCode-Regular.ttf
Normal file
BIN
src/fonts/FiraSans-Regular.ttf
Normal file
BIN
src/fonts/Hack-Regular.ttf
Normal file
BIN
src/fonts/Inconsolata.ttf
Normal file
BIN
src/fonts/IosevkaTerm.ttc
Normal file
BIN
src/fonts/JetBrainsMono-Regular.ttf
Normal file
BIN
src/fonts/NotoSans.ttf
Normal file
BIN
src/fonts/OpenSans.ttf
Normal file
BIN
src/fonts/Roboto.ttf
Normal file
541
src/fs/bootfs.c
Normal file
@@ -0,0 +1,541 @@
|
||||
// Copyright (c) 2023-2026 Chris (boreddevnl)
|
||||
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
|
||||
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
||||
|
||||
#include "bootfs.h"
|
||||
#include "../sys/bootfs_state.h"
|
||||
#include "vfs.h"
|
||||
#include "core/kutils.h"
|
||||
#include "core/platform.h"
|
||||
#include "core/kconsole.h"
|
||||
#include "memory_manager.h"
|
||||
|
||||
extern void serial_write(const char *str);
|
||||
extern void serial_write_hex(uint64_t value);
|
||||
|
||||
typedef struct {
|
||||
char path[512];
|
||||
int offset;
|
||||
bool is_root;
|
||||
bool is_metadata_dir;
|
||||
} bootfs_handle_t;
|
||||
|
||||
static void* bootfs_open(void *fs_private, const char *path, const char *mode);
|
||||
static void bootfs_close(void *fs_private, void *handle);
|
||||
static int bootfs_read(void *fs_private, void *handle, void *buf, int size);
|
||||
static int bootfs_write(void *fs_private, void *handle, const void *buf, int size);
|
||||
static int bootfs_seek(void *fs_private, void *handle, int offset, int whence);
|
||||
static int bootfs_readdir(void *fs_private, const char *rel_path, vfs_dirent_t *entries, int max);
|
||||
static bool bootfs_mkdir(void *fs_private, const char *rel_path);
|
||||
static bool bootfs_rmdir(void *fs_private, const char *rel_path);
|
||||
static bool bootfs_unlink(void *fs_private, const char *rel_path);
|
||||
static bool bootfs_rename(void *fs_private, const char *old_path, const char *new_path);
|
||||
static bool bootfs_exists(void *fs_private, const char *rel_path);
|
||||
static bool bootfs_is_dir(void *fs_private, const char *rel_path);
|
||||
static int bootfs_get_info(void *fs_private, const char *rel_path, vfs_dirent_t *info);
|
||||
static uint32_t bootfs_get_position(void *file_handle);
|
||||
static uint32_t bootfs_get_size(void *file_handle);
|
||||
|
||||
static vfs_fs_ops_t bootfs_ops = {
|
||||
.open = bootfs_open,
|
||||
.close = bootfs_close,
|
||||
.read = bootfs_read,
|
||||
.write = bootfs_write,
|
||||
.seek = bootfs_seek,
|
||||
.readdir = bootfs_readdir,
|
||||
.mkdir = bootfs_mkdir,
|
||||
.rmdir = bootfs_rmdir,
|
||||
.unlink = bootfs_unlink,
|
||||
.rename = bootfs_rename,
|
||||
.exists = bootfs_exists,
|
||||
.is_dir = bootfs_is_dir,
|
||||
.get_info = bootfs_get_info,
|
||||
.get_position = bootfs_get_position,
|
||||
.get_size = bootfs_get_size,
|
||||
};
|
||||
|
||||
bootfs_state_t g_bootfs_state = {0};
|
||||
|
||||
static bool is_metadata_path(const char *path) {
|
||||
if (!path) return false;
|
||||
return k_strncmp(path, "metadata", 8) == 0;
|
||||
}
|
||||
|
||||
static bool is_metadata_file(const char *path) {
|
||||
if (k_strcmp(path, "metadata/boot_time") == 0) return true;
|
||||
if (k_strcmp(path, "metadata/boot_flags") == 0) return true;
|
||||
if (k_strcmp(path, "metadata/version") == 0) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void* bootfs_open(void *fs_private, const char *path, const char *mode) {
|
||||
if (!path) path = "";
|
||||
if (path[0] == '/') path++;
|
||||
|
||||
bootfs_handle_t *h = (bootfs_handle_t*)kmalloc(sizeof(bootfs_handle_t));
|
||||
if (!h) return NULL;
|
||||
|
||||
k_memset(h, 0, sizeof(bootfs_handle_t));
|
||||
k_strcpy(h->path, path);
|
||||
h->offset = 0;
|
||||
|
||||
if (path[0] == '\0') {
|
||||
h->is_root = true;
|
||||
} else if (is_metadata_path(path) && path[8] == '\0') {
|
||||
h->is_metadata_dir = true;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
static void bootfs_close(void *fs_private, void *handle) {
|
||||
if (handle) kfree(handle);
|
||||
}
|
||||
|
||||
static int generate_metadata_content(const char *file, char *buffer, int max_size) {
|
||||
if (!buffer || max_size <= 0) return 0;
|
||||
|
||||
buffer[0] = '\0';
|
||||
int len = 0;
|
||||
|
||||
if (k_strcmp(file, "metadata/boot_time") == 0) {
|
||||
extern uint32_t wm_get_ticks(void);
|
||||
uint32_t ticks = wm_get_ticks();
|
||||
|
||||
k_strcpy(buffer, "Boot time: ");
|
||||
char time_buf[32];
|
||||
k_itoa(g_bootfs_state.boot_time_ms, time_buf);
|
||||
k_strcpy(buffer + k_strlen(buffer), time_buf);
|
||||
k_strcpy(buffer + k_strlen(buffer), " ms\nTicks: ");
|
||||
k_itoa(ticks, time_buf);
|
||||
k_strcpy(buffer + k_strlen(buffer), time_buf);
|
||||
k_strcpy(buffer + k_strlen(buffer), "\n");
|
||||
len = k_strlen(buffer);
|
||||
} else if (k_strcmp(file, "metadata/version") == 0) {
|
||||
k_strcpy(buffer, "Bootloader: ");
|
||||
k_strcpy(buffer + k_strlen(buffer), g_bootfs_state.bootloader_name);
|
||||
k_strcpy(buffer + k_strlen(buffer), "\nVersion: ");
|
||||
k_strcpy(buffer + k_strlen(buffer), g_bootfs_state.bootloader_version);
|
||||
k_strcpy(buffer + k_strlen(buffer), "\n");
|
||||
len = k_strlen(buffer);
|
||||
} else if (k_strcmp(file, "metadata/boot_flags") == 0) {
|
||||
k_strcpy(buffer, "Boot flags: 0x");
|
||||
char flags_buf[8];
|
||||
uint8_t flags = g_bootfs_state.boot_flags;
|
||||
int hex_digit = (flags >> 4) & 0xF;
|
||||
flags_buf[0] = hex_digit < 10 ? '0' + hex_digit : 'a' + (hex_digit - 10);
|
||||
hex_digit = flags & 0xF;
|
||||
flags_buf[1] = hex_digit < 10 ? '0' + hex_digit : 'a' + (hex_digit - 10);
|
||||
flags_buf[2] = '\n';
|
||||
flags_buf[3] = '\0';
|
||||
k_strcpy(buffer + k_strlen(buffer), flags_buf);
|
||||
len = k_strlen(buffer);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int bootfs_read(void *fs_private, void *handle, void *buf, int size) {
|
||||
bootfs_handle_t *h = (bootfs_handle_t*)handle;
|
||||
if (!h || !buf || size <= 0) return -1;
|
||||
|
||||
char *content_buffer = (char*)kmalloc(4096);
|
||||
if (!content_buffer) return -1;
|
||||
|
||||
int content_len = 0;
|
||||
|
||||
if (k_strcmp(h->path, "limine.conf") == 0) {
|
||||
k_memcpy(content_buffer, g_bootfs_state.limine_conf,
|
||||
g_bootfs_state.limine_conf_len);
|
||||
content_len = g_bootfs_state.limine_conf_len;
|
||||
} else if (k_strcmp(h->path, "kernel") == 0) {
|
||||
k_strcpy(content_buffer, "Kernel reference\nSize: ");
|
||||
char size_buf[32];
|
||||
k_itoa(g_bootfs_state.kernel_size, size_buf);
|
||||
k_strcpy(content_buffer + k_strlen(content_buffer), size_buf);
|
||||
k_strcpy(content_buffer + k_strlen(content_buffer), " bytes\n");
|
||||
content_len = k_strlen(content_buffer);
|
||||
} else if (k_strcmp(h->path, "initrd") == 0) {
|
||||
k_strcpy(content_buffer, "Initial ramdisk reference\nSize: ");
|
||||
char size_buf[32];
|
||||
k_itoa(g_bootfs_state.initrd_size, size_buf);
|
||||
k_strcpy(content_buffer + k_strlen(content_buffer), size_buf);
|
||||
k_strcpy(content_buffer + k_strlen(content_buffer), " bytes\n");
|
||||
content_len = k_strlen(content_buffer);
|
||||
} else if (is_metadata_file(h->path)) {
|
||||
content_len = generate_metadata_content(h->path, content_buffer, 4096);
|
||||
} else {
|
||||
kfree(content_buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Handle offset and reading
|
||||
if (h->offset >= content_len) {
|
||||
kfree(content_buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int available = content_len - h->offset;
|
||||
int read_size = (available < size) ? available : size;
|
||||
|
||||
k_memcpy(buf, content_buffer + h->offset, read_size);
|
||||
h->offset += read_size;
|
||||
|
||||
kfree(content_buffer);
|
||||
return read_size;
|
||||
}
|
||||
|
||||
static int bootfs_write(void *fs_private, void *handle, const void *buf, int size) {
|
||||
bootfs_handle_t *h = (bootfs_handle_t*)handle;
|
||||
if (!h || !buf || size <= 0) return -1;
|
||||
|
||||
if (k_strcmp(h->path, "limine.conf") != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int max_write = 2048 - h->offset;
|
||||
if (max_write <= 0) return -1;
|
||||
|
||||
int write_size = (size < max_write) ? size : max_write;
|
||||
k_memcpy(g_bootfs_state.limine_conf + h->offset, buf, write_size);
|
||||
h->offset += write_size;
|
||||
|
||||
if (h->offset > g_bootfs_state.limine_conf_len) {
|
||||
g_bootfs_state.limine_conf_len = h->offset;
|
||||
}
|
||||
|
||||
extern vfs_file_t* vfs_open(const char *path, const char *mode);
|
||||
extern int vfs_write(vfs_file_t *file, const void *buf, int size);
|
||||
extern void vfs_close(vfs_file_t *file);
|
||||
|
||||
vfs_file_t *fat_conf = vfs_open("/limine.conf", "w");
|
||||
if (fat_conf) {
|
||||
vfs_write(fat_conf, g_bootfs_state.limine_conf, g_bootfs_state.limine_conf_len);
|
||||
vfs_close(fat_conf);
|
||||
}
|
||||
|
||||
return write_size;
|
||||
}
|
||||
|
||||
static int bootfs_seek(void *fs_private, void *handle, int offset, int whence) {
|
||||
bootfs_handle_t *h = (bootfs_handle_t*)handle;
|
||||
if (!h) return -1;
|
||||
|
||||
switch (whence) {
|
||||
case 0: // SEEK_SET
|
||||
h->offset = offset;
|
||||
break;
|
||||
case 1: // SEEK_CUR
|
||||
h->offset += offset;
|
||||
break;
|
||||
case 2: // SEEK_END
|
||||
return -1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return h->offset;
|
||||
}
|
||||
|
||||
static int bootfs_readdir(void *fs_private, const char *rel_path, vfs_dirent_t *entries, int max) {
|
||||
if (!entries || max <= 0) return 0;
|
||||
|
||||
if (!rel_path) rel_path = "";
|
||||
if (rel_path[0] == '/') rel_path++;
|
||||
|
||||
int count = 0;
|
||||
|
||||
if (rel_path[0] == '\0') {
|
||||
if (count < max) {
|
||||
k_strcpy(entries[count].name, "limine.conf");
|
||||
entries[count].size = g_bootfs_state.limine_conf_len;
|
||||
entries[count].is_directory = 0;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count < max) {
|
||||
k_strcpy(entries[count].name, "kernel");
|
||||
entries[count].size = g_bootfs_state.kernel_size;
|
||||
entries[count].is_directory = 0;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count < max) {
|
||||
k_strcpy(entries[count].name, "initrd");
|
||||
entries[count].size = g_bootfs_state.initrd_size;
|
||||
entries[count].is_directory = 0;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count < max) {
|
||||
k_strcpy(entries[count].name, "metadata");
|
||||
entries[count].size = 0;
|
||||
entries[count].is_directory = 1;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
else if (k_strcmp(rel_path, "metadata") == 0) {
|
||||
const char *meta_files[] = {
|
||||
"boot_time",
|
||||
"boot_flags",
|
||||
"version"
|
||||
};
|
||||
|
||||
for (int i = 0; i < 3 && count < max; i++) {
|
||||
k_strcpy(entries[count].name, meta_files[i]);
|
||||
entries[count].size = 0;
|
||||
entries[count].is_directory = 0;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static bool bootfs_mkdir(void *fs_private, const char *rel_path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool bootfs_rmdir(void *fs_private, const char *rel_path) {
|
||||
if (!rel_path) rel_path = "";
|
||||
if (rel_path[0] == '/') rel_path++;
|
||||
|
||||
if (k_strcmp(rel_path, "metadata") == 0) {
|
||||
return false; /* metadata directory is protected */
|
||||
}
|
||||
|
||||
return false; /* no other directories to remove */
|
||||
}
|
||||
|
||||
static bool bootfs_unlink(void *fs_private, const char *rel_path) {
|
||||
if (!rel_path) return false;
|
||||
if (rel_path[0] == '/') rel_path++;
|
||||
|
||||
/* Only limine.conf can be deleted */
|
||||
if (k_strcmp(rel_path, "limine.conf") != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Clear the bootfs state */
|
||||
g_bootfs_state.limine_conf[0] = '\0';
|
||||
g_bootfs_state.limine_conf_len = 0;
|
||||
|
||||
/* Delete from partition */
|
||||
extern bool vfs_delete(const char *path);
|
||||
|
||||
bool result = vfs_delete("/limine.conf");
|
||||
|
||||
if (result) {
|
||||
serial_write("[BOOTFS] Deleted limine.conf from partition\n");
|
||||
} else {
|
||||
serial_write("[BOOTFS] Warning: Could not delete limine.conf from partition\n");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool bootfs_rename(void *fs_private, const char *old_path, const char *new_path) {
|
||||
if (!old_path || !new_path) return false;
|
||||
|
||||
const char *old_rel = old_path;
|
||||
const char *new_rel = new_path;
|
||||
|
||||
if (old_rel[0] == '/') old_rel++;
|
||||
if (new_rel[0] == '/') new_rel++;
|
||||
|
||||
/* Only limine.conf can be renamed */
|
||||
if (k_strcmp(old_rel, "limine.conf") != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* kernel and initrd are protected */
|
||||
if (k_strcmp(new_rel, "kernel") == 0 || k_strcmp(new_rel, "initrd") == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* metadata directory is protected */
|
||||
if (k_strncmp(new_rel, "metadata", 8) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
extern bool vfs_rename(const char *old_path, const char *new_path);
|
||||
|
||||
char new_partition_path[256];
|
||||
k_strcpy(new_partition_path, "/");
|
||||
|
||||
/* Manually append new_rel to new_partition_path */
|
||||
int path_len = 0;
|
||||
while (new_partition_path[path_len]) path_len++;
|
||||
|
||||
int rel_len = 0;
|
||||
while (new_rel[rel_len]) rel_len++;
|
||||
|
||||
if (path_len + rel_len >= 256) {
|
||||
serial_write("[BOOTFS] Error: new path too long\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
k_memcpy(new_partition_path + path_len, new_rel, rel_len + 1);
|
||||
|
||||
/* Rename on partition filesystem */
|
||||
bool result = vfs_rename("/limine.conf", new_partition_path);
|
||||
|
||||
if (result) {
|
||||
serial_write("[BOOTFS] Renamed limine.conf to ");
|
||||
serial_write(new_rel);
|
||||
serial_write("\n");
|
||||
} else {
|
||||
serial_write("[BOOTFS] Warning: Could not rename limine.conf to ");
|
||||
serial_write(new_rel);
|
||||
serial_write("\n");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool bootfs_exists(void *fs_private, const char *rel_path) {
|
||||
if (!rel_path) rel_path = "";
|
||||
if (rel_path[0] == '/') rel_path++;
|
||||
|
||||
if (rel_path[0] == '\0') return true;
|
||||
|
||||
if (k_strcmp(rel_path, "limine.conf") == 0) return true;
|
||||
if (k_strcmp(rel_path, "kernel") == 0) return true;
|
||||
if (k_strcmp(rel_path, "initrd") == 0) return true;
|
||||
|
||||
if (k_strcmp(rel_path, "metadata") == 0) return true;
|
||||
if (is_metadata_file(rel_path)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool bootfs_is_dir(void *fs_private, const char *rel_path) {
|
||||
if (!rel_path) rel_path = "";
|
||||
if (rel_path[0] == '/') rel_path++;
|
||||
|
||||
if (rel_path[0] == '\0') return true;
|
||||
if (k_strcmp(rel_path, "metadata") == 0) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int bootfs_get_info(void *fs_private, const char *rel_path, vfs_dirent_t *info) {
|
||||
if (!info) return -1;
|
||||
if (!rel_path) rel_path = "";
|
||||
if (rel_path[0] == '/') rel_path++;
|
||||
|
||||
k_memset(info, 0, sizeof(vfs_dirent_t));
|
||||
|
||||
if (rel_path[0] == '\0') {
|
||||
k_strcpy(info->name, "/");
|
||||
info->is_directory = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (k_strcmp(rel_path, "limine.conf") == 0) {
|
||||
k_strcpy(info->name, "limine.conf");
|
||||
info->size = g_bootfs_state.limine_conf_len;
|
||||
info->is_directory = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (k_strcmp(rel_path, "kernel") == 0) {
|
||||
k_strcpy(info->name, "kernel");
|
||||
info->size = g_bootfs_state.kernel_size;
|
||||
info->is_directory = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (k_strcmp(rel_path, "initrd") == 0) {
|
||||
k_strcpy(info->name, "initrd");
|
||||
info->size = g_bootfs_state.initrd_size;
|
||||
info->is_directory = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (k_strcmp(rel_path, "metadata") == 0) {
|
||||
k_strcpy(info->name, "metadata");
|
||||
info->is_directory = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_metadata_file(rel_path)) {
|
||||
char temp_buf[4096];
|
||||
int len = generate_metadata_content(rel_path, temp_buf, 4096);
|
||||
k_strcpy(info->name, rel_path + 9);
|
||||
info->size = len;
|
||||
info->is_directory = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static uint32_t bootfs_get_position(void *file_handle) {
|
||||
bootfs_handle_t *h = (bootfs_handle_t*)file_handle;
|
||||
if (!h) return 0;
|
||||
return h->offset;
|
||||
}
|
||||
|
||||
static uint32_t bootfs_get_size(void *file_handle) {
|
||||
bootfs_handle_t *h = (bootfs_handle_t*)file_handle;
|
||||
if (!h) return 0;
|
||||
|
||||
if (k_strcmp(h->path, "limine.conf") == 0) {
|
||||
return g_bootfs_state.limine_conf_len;
|
||||
} else if (k_strcmp(h->path, "kernel") == 0) {
|
||||
return g_bootfs_state.kernel_size;
|
||||
} else if (k_strcmp(h->path, "initrd") == 0) {
|
||||
return g_bootfs_state.initrd_size;
|
||||
} else if (is_metadata_file(h->path)) {
|
||||
char temp_buf[4096];
|
||||
return generate_metadata_content(h->path, temp_buf, 4096);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
vfs_fs_ops_t* bootfs_get_ops(void) {
|
||||
return &bootfs_ops;
|
||||
}
|
||||
|
||||
void bootfs_state_init(void) {
|
||||
k_memset(&g_bootfs_state, 0, sizeof(bootfs_state_t));
|
||||
|
||||
k_strcpy(g_bootfs_state.bootloader_name, "Limine");
|
||||
k_strcpy(g_bootfs_state.bootloader_version, "6.0.0");
|
||||
|
||||
|
||||
g_bootfs_state.limine_conf[0] = '\0';
|
||||
g_bootfs_state.limine_conf_len = 0;
|
||||
|
||||
g_bootfs_state.kernel_size = 0;
|
||||
g_bootfs_state.initrd_size = 0;
|
||||
g_bootfs_state.boot_time_ms = 0;
|
||||
}
|
||||
|
||||
void bootfs_init(void) {
|
||||
bootfs_state_init();
|
||||
}
|
||||
|
||||
void bootfs_refresh_from_disk(void) {
|
||||
extern vfs_file_t* vfs_open(const char *path, const char *mode);
|
||||
extern int vfs_read(vfs_file_t *file, void *buf, int size);
|
||||
extern void vfs_close(vfs_file_t *file);
|
||||
|
||||
vfs_file_t *boot_conf = vfs_open("/limine.conf", "r");
|
||||
if (boot_conf) {
|
||||
int bytes_read = vfs_read(boot_conf, g_bootfs_state.limine_conf, 2047);
|
||||
if (bytes_read > 0) {
|
||||
g_bootfs_state.limine_conf[bytes_read] = '\0';
|
||||
g_bootfs_state.limine_conf_len = bytes_read;
|
||||
serial_write("[BOOTFS] Loaded limine.conf from partition: ");
|
||||
extern void serial_write_hex(uint64_t value);
|
||||
serial_write_hex(bytes_read);
|
||||
serial_write(" bytes\n");
|
||||
}
|
||||
vfs_close(boot_conf);
|
||||
} else {
|
||||
serial_write("[BOOTFS] Warning: /limine.conf not found on partition\n");
|
||||
}
|
||||
}
|
||||
13
src/fs/bootfs.h
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) 2023-2026 Chris (boreddevnl)
|
||||
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
|
||||
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
||||
#ifndef BOOTFS_H
|
||||
#define BOOTFS_H
|
||||
|
||||
#include "vfs.h"
|
||||
|
||||
void bootfs_init(void);
|
||||
void bootfs_refresh_from_disk(void);
|
||||
vfs_fs_ops_t* bootfs_get_ops(void);
|
||||
|
||||
#endif
|
||||
239
src/fs/fat32.c
@@ -15,7 +15,6 @@
|
||||
static spinlock_t ramfs_lock = SPINLOCK_INIT; // Protects the RAM-based filesystem (/)
|
||||
|
||||
|
||||
#define MAX_FILES 256
|
||||
#define MAX_CLUSTERS 8192
|
||||
#define MAX_OPEN_HANDLES 32
|
||||
|
||||
@@ -23,8 +22,7 @@ static spinlock_t ramfs_lock = SPINLOCK_INIT; // Protects the RAM-based filesyst
|
||||
static uint32_t fat_table[MAX_CLUSTERS];
|
||||
static uint8_t cluster_data[MAX_CLUSTERS][FAT32_CLUSTER_SIZE];
|
||||
|
||||
// File/Directory tracking
|
||||
typedef struct {
|
||||
typedef struct FileEntry {
|
||||
char full_path[FAT32_MAX_PATH];
|
||||
char filename[FAT32_MAX_FILENAME];
|
||||
uint32_t start_cluster;
|
||||
@@ -32,9 +30,10 @@ typedef struct {
|
||||
uint32_t attributes;
|
||||
bool used;
|
||||
char parent_path[FAT32_MAX_PATH];
|
||||
struct FileEntry *next;
|
||||
} FileEntry;
|
||||
|
||||
static FileEntry files[MAX_FILES];
|
||||
static FileEntry *file_list_head = NULL;
|
||||
static uint32_t next_cluster = 3; // Start after reserved clusters 0, 1, 2
|
||||
static FAT32_FileHandle open_handles[MAX_OPEN_HANDLES];
|
||||
static char current_dir[FAT32_MAX_PATH] = "/";
|
||||
@@ -55,6 +54,7 @@ typedef struct {
|
||||
bool mounted;
|
||||
uint32_t cached_fat_sector;
|
||||
uint8_t cached_fat_buf[512];
|
||||
uint32_t last_allocated_cluster; // Hint for faster allocation
|
||||
spinlock_t lock; // Per-volume lock for physical disk operations
|
||||
} FAT32_Volume;
|
||||
|
||||
@@ -233,9 +233,9 @@ static FileEntry* ramfs_find_file(const char *path) {
|
||||
if (!normalized) return NULL;
|
||||
fat32_normalize_path(path, normalized);
|
||||
FileEntry *ret = NULL;
|
||||
for (int i = 0; i < MAX_FILES; i++) {
|
||||
if (files[i].used && fs_strcmp(files[i].full_path, normalized) == 0) {
|
||||
ret = &files[i];
|
||||
for (FileEntry *n = file_list_head; n; n = n->next) {
|
||||
if (fs_strcmp(n->full_path, normalized) == 0) {
|
||||
ret = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -243,11 +243,29 @@ static FileEntry* ramfs_find_file(const char *path) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static FileEntry* ramfs_find_free_entry(void) {
|
||||
for (int i = 0; i < MAX_FILES; i++) {
|
||||
if (!files[i].used) return &files[i];
|
||||
static FileEntry* ramfs_alloc_entry(void) {
|
||||
FileEntry *e = (FileEntry*)kmalloc(sizeof(FileEntry));
|
||||
if (!e) return NULL;
|
||||
for (int i = 0; i < (int)sizeof(FileEntry); i++) ((char*)e)[i] = 0;
|
||||
e->used = true;
|
||||
e->next = file_list_head;
|
||||
file_list_head = e;
|
||||
return e;
|
||||
}
|
||||
|
||||
static void ramfs_free_entry(FileEntry *entry) {
|
||||
if (!entry) return;
|
||||
if (file_list_head == entry) {
|
||||
file_list_head = entry->next;
|
||||
} else {
|
||||
for (FileEntry *n = file_list_head; n && n->next; n = n->next) {
|
||||
if (n->next == entry) {
|
||||
n->next = entry->next;
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
kfree(entry);
|
||||
}
|
||||
|
||||
static FAT32_FileHandle* ramfs_find_free_handle(void) {
|
||||
@@ -266,10 +284,8 @@ static uint32_t ramfs_allocate_cluster(void) {
|
||||
|
||||
static int ramfs_count_files_in_dir(const char *normalized_path) {
|
||||
int count = 0;
|
||||
for (int i = 0; i < MAX_FILES; i++) {
|
||||
if (files[i].used && fs_strcmp(files[i].parent_path, normalized_path) == 0) {
|
||||
count++;
|
||||
}
|
||||
for (FileEntry *n = file_list_head; n; n = n->next) {
|
||||
if (fs_strcmp(n->parent_path, normalized_path) == 0) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
@@ -305,14 +321,13 @@ static FAT32_FileHandle* ramfs_open(const char *normalized_path, const char *mod
|
||||
} else if (mode[0] == 'w' || (mode[0] == 'a')) {
|
||||
if (!entry) {
|
||||
if (!check_desktop_limit(normalized_path)) return NULL;
|
||||
entry = ramfs_find_free_entry();
|
||||
entry = ramfs_alloc_entry();
|
||||
if (!entry) return NULL;
|
||||
entry->used = true;
|
||||
fs_strcpy(entry->full_path, normalized_path);
|
||||
extract_filename(normalized_path, entry->filename);
|
||||
extract_parent_path(normalized_path, entry->parent_path);
|
||||
entry->start_cluster = ramfs_allocate_cluster();
|
||||
if (!entry->start_cluster) return NULL;
|
||||
if (!entry->start_cluster) { ramfs_free_entry(entry); return NULL; }
|
||||
entry->size = 0;
|
||||
entry->attributes = 0;
|
||||
}
|
||||
@@ -410,9 +425,9 @@ static int ramfs_write(FAT32_FileHandle *handle, const void *buffer, int size) {
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_FILES; i++) {
|
||||
if (files[i].used && files[i].start_cluster == handle->start_cluster) {
|
||||
files[i].size = handle->size;
|
||||
for (FileEntry *n = file_list_head; n; n = n->next) {
|
||||
if (n->start_cluster == handle->start_cluster) {
|
||||
n->size = handle->size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -455,6 +470,7 @@ static bool realfs_mount_volume(FAT32_Volume *vol, Disk *disk) {
|
||||
vol->total_sectors = bpb->total_sectors_32;
|
||||
vol->mounted = true;
|
||||
vol->cached_fat_sector = 0xFFFFFFFF;
|
||||
vol->last_allocated_cluster = 2;
|
||||
|
||||
fs_serial_str("[FAT32] Mounted volume: /dev/");
|
||||
fs_serial_str(disk->devname);
|
||||
@@ -971,8 +987,10 @@ static bool realfs_find_contiguous_free(FAT32_Volume *vol, uint32_t dir_start_cl
|
||||
}
|
||||
|
||||
static uint32_t realfs_allocate_cluster(FAT32_Volume *vol) {
|
||||
uint32_t current = 2;
|
||||
uint32_t current = vol->last_allocated_cluster;
|
||||
if (current < 2) current = 2;
|
||||
uint32_t fat_entries = (vol->fat_size * 512) / 4;
|
||||
uint32_t first_search = current;
|
||||
|
||||
// Skip cluster 2 as it's reserved for the root directory in FAT32
|
||||
if (current == vol->root_cluster) current++;
|
||||
@@ -998,10 +1016,13 @@ static uint32_t realfs_allocate_cluster(FAT32_Volume *vol) {
|
||||
if (vol->cached_fat_sector == sector) {
|
||||
vol->cached_fat_sector = 0xFFFFFFFF;
|
||||
}
|
||||
vol->last_allocated_cluster = current;
|
||||
kfree(fat_buf);
|
||||
return current;
|
||||
}
|
||||
current++;
|
||||
if (current >= fat_entries) current = 2;
|
||||
if (current == first_search) break;
|
||||
}
|
||||
kfree(fat_buf);
|
||||
return 0; // Full
|
||||
@@ -1043,11 +1064,31 @@ static int realfs_write_file(FAT32_FileHandle *handle, const void *buffer, int s
|
||||
while (bytes_written < size) {
|
||||
uint32_t offset = handle->position % cluster_size;
|
||||
|
||||
if (offset == 0 && handle->position > 0) {
|
||||
uint32_t next = realfs_next_cluster(vol, handle->cluster);
|
||||
if (next >= 0x0FFFFFF8) {
|
||||
uint32_t new_cluster = realfs_allocate_cluster(vol);
|
||||
if (new_cluster == 0) break;
|
||||
|
||||
uint32_t fs = vol->fat_begin_lba + (handle->cluster * 4) / 512;
|
||||
uint32_t fo = (handle->cluster * 4) % 512;
|
||||
uint8_t fbuf[512];
|
||||
if (vol->disk->read_sector(vol->disk, fs, fbuf) == 0) {
|
||||
uint32_t old = *(uint32_t*)&fbuf[fo];
|
||||
*(uint32_t*)&fbuf[fo] = (old & 0xF0000000) | (new_cluster & 0x0FFFFFFF);
|
||||
vol->disk->write_sector(vol->disk, fs, fbuf);
|
||||
if (vol->cached_fat_sector == fs) vol->cached_fat_sector = 0xFFFFFFFF;
|
||||
}
|
||||
next = new_cluster;
|
||||
}
|
||||
handle->cluster = next;
|
||||
}
|
||||
|
||||
// Always zero the buffer first to ensure clean state
|
||||
for (int i = 0; i < (int)cluster_size; i++) cluster_buf[i] = 0;
|
||||
|
||||
// If we're in the middle of a cluster, read the existing data first
|
||||
if (offset > 0) {
|
||||
if (offset > 0 || (handle->position < handle->size)) {
|
||||
if (realfs_read_cluster(vol, handle->cluster, cluster_buf) != 0) break;
|
||||
}
|
||||
|
||||
@@ -1065,27 +1106,6 @@ static int realfs_write_file(FAT32_FileHandle *handle, const void *buffer, int s
|
||||
bytes_written += to_copy;
|
||||
handle->position += to_copy;
|
||||
if (handle->position > handle->size) handle->size = handle->position;
|
||||
|
||||
if (handle->position % cluster_size == 0 && bytes_written < size) {
|
||||
uint32_t next = realfs_next_cluster(vol, handle->cluster);
|
||||
if (next >= 0x0FFFFFF8) {
|
||||
uint32_t new_cluster = realfs_allocate_cluster(vol);
|
||||
if (new_cluster == 0) break;
|
||||
|
||||
// Link current to new
|
||||
uint32_t fs = vol->fat_begin_lba + (handle->cluster * 4) / 512;
|
||||
uint32_t fo = (handle->cluster * 4) % 512;
|
||||
uint8_t fbuf[512];
|
||||
if (vol->disk->read_sector(vol->disk, fs, fbuf) == 0) {
|
||||
uint32_t old = *(uint32_t*)&fbuf[fo];
|
||||
*(uint32_t*)&fbuf[fo] = (old & 0xF0000000) | (new_cluster & 0x0FFFFFFF);
|
||||
vol->disk->write_sector(vol->disk, fs, fbuf);
|
||||
if (vol->cached_fat_sector == fs) vol->cached_fat_sector = 0xFFFFFFFF;
|
||||
}
|
||||
next = new_cluster;
|
||||
}
|
||||
handle->cluster = next;
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes_written > 0) realfs_update_dir_entry_size(vol, handle);
|
||||
@@ -1461,27 +1481,26 @@ static int vfs_ramfs_readdir(void *fs_private, const char *rel_path, vfs_dirent_
|
||||
vfs_ramfs_get_abs_path(rel_path, abs);
|
||||
|
||||
uint64_t rflags = spinlock_acquire_irqsave(&ramfs_lock);
|
||||
for (int i = 0; i < MAX_FILES && count < max; i++) {
|
||||
for (FileEntry *n = file_list_head; n && count < max; n = n->next) {
|
||||
bool match = false;
|
||||
if (files[i].used && files[i].filename[0] != '\0') {
|
||||
if (fs_strcmp(files[i].parent_path, abs) == 0) match = true;
|
||||
if (n->filename[0] != '\0') {
|
||||
if (fs_strcmp(n->parent_path, abs) == 0) match = true;
|
||||
|
||||
// Root unification: Treat "", "/", and "A:/" as root parent
|
||||
if (!match && abs[0] == '/' && abs[1] == '\0') {
|
||||
if (files[i].parent_path[0] == '\0' ||
|
||||
fs_strcmp(files[i].parent_path, "/") == 0 ||
|
||||
fs_strcmp(files[i].parent_path, "A:/") == 0) {
|
||||
if (n->parent_path[0] == '\0' ||
|
||||
fs_strcmp(n->parent_path, "/") == 0 ||
|
||||
fs_strcmp(n->parent_path, "A:/") == 0) {
|
||||
match = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
fs_strcpy(entries[count].name, files[i].filename);
|
||||
entries[count].size = files[i].size;
|
||||
entries[count].is_directory = (files[i].attributes & ATTR_DIRECTORY) ? 1 : 0;
|
||||
entries[count].start_cluster = files[i].start_cluster;
|
||||
entries[count].write_date = 0; // Not tracked in RAMFS for now
|
||||
fs_strcpy(entries[count].name, n->filename);
|
||||
entries[count].size = n->size;
|
||||
entries[count].is_directory = (n->attributes & ATTR_DIRECTORY) ? 1 : 0;
|
||||
entries[count].start_cluster = n->start_cluster;
|
||||
entries[count].write_date = 0;
|
||||
entries[count].write_time = 0;
|
||||
count++;
|
||||
}
|
||||
@@ -1646,12 +1665,22 @@ static int vfs_realfs_read(void *fs_private, void *file_handle, void *buf, int s
|
||||
uint8_t *cluster_buf = (uint8_t*)kmalloc(cluster_size);
|
||||
if (!cluster_buf) return -1;
|
||||
|
||||
int total_read = 0;
|
||||
while (total_read < size) {
|
||||
int to_read = size - total_read;
|
||||
if (to_read > (int)cluster_size) to_read = (int)cluster_size;
|
||||
|
||||
uint64_t rflags = spinlock_acquire_irqsave(&vol->lock);
|
||||
int ret = realfs_read_file(handle, buf, size, cluster_buf);
|
||||
int ret = realfs_read_file(handle, (uint8_t*)buf + total_read, to_read, cluster_buf);
|
||||
spinlock_release_irqrestore(&vol->lock, rflags);
|
||||
|
||||
if (ret <= 0) break;
|
||||
total_read += ret;
|
||||
if (ret < to_read) break;
|
||||
}
|
||||
|
||||
kfree(cluster_buf);
|
||||
return ret;
|
||||
return total_read;
|
||||
}
|
||||
|
||||
static int vfs_realfs_write(void *fs_private, void *file_handle, const void *buf, int size) {
|
||||
@@ -1664,12 +1693,22 @@ static int vfs_realfs_write(void *fs_private, void *file_handle, const void *buf
|
||||
uint8_t *cluster_buf = (uint8_t*)kmalloc(cluster_size);
|
||||
if (!cluster_buf) return -1;
|
||||
|
||||
int total_written = 0;
|
||||
while (total_written < size) {
|
||||
int to_write = size - total_written;
|
||||
if (to_write > (int)cluster_size) to_write = (int)cluster_size;
|
||||
|
||||
uint64_t rflags = spinlock_acquire_irqsave(&vol->lock);
|
||||
int ret = realfs_write_file(handle, buf, size, cluster_buf);
|
||||
int ret = realfs_write_file(handle, (const uint8_t*)buf + total_written, to_write, cluster_buf);
|
||||
spinlock_release_irqrestore(&vol->lock, rflags);
|
||||
|
||||
if (ret <= 0) break;
|
||||
total_written += ret;
|
||||
if (ret < to_write) break;
|
||||
}
|
||||
|
||||
kfree(cluster_buf);
|
||||
return ret;
|
||||
return total_written;
|
||||
}
|
||||
|
||||
static int vfs_realfs_seek(void *fs_private, void *file_handle, int offset, int whence) {
|
||||
@@ -1814,16 +1853,13 @@ void* fat32_mount_volume(void *disk_ptr) {
|
||||
// === Public API (Dispatch) ===
|
||||
|
||||
void fat32_init(void) {
|
||||
// Explicitly zero out all structures for RAMFS safety
|
||||
for (int i = 0; i < MAX_FILES; i++) {
|
||||
files[i].used = false;
|
||||
files[i].full_path[0] = 0;
|
||||
files[i].filename[0] = 0;
|
||||
files[i].parent_path[0] = 0;
|
||||
files[i].size = 0;
|
||||
files[i].attributes = 0;
|
||||
files[i].start_cluster = 0;
|
||||
FileEntry *node = file_list_head;
|
||||
while (node) {
|
||||
FileEntry *next = node->next;
|
||||
kfree(node);
|
||||
node = next;
|
||||
}
|
||||
file_list_head = NULL;
|
||||
|
||||
// Initialize FAT table for RAMFS
|
||||
for (int i = 0; i < MAX_CLUSTERS; i++) {
|
||||
@@ -1891,11 +1927,6 @@ FAT32_FileHandle* fat32_open_nolock(const char *path, const char *mode) {
|
||||
}
|
||||
}
|
||||
} else if (path[0] == '/') {
|
||||
// Absolute VFS path - bypass legacy drive letters
|
||||
// This is safe to call WITHOUT the fat32_lock because vfs_open was called formerly
|
||||
// and it will resolve to one of our mounts which will then acquire the lock.
|
||||
// HOWEVER, if we are already inside a fat32_lock call, we SHOULD NOT call vfs_open.
|
||||
// For now, absolute paths starting with / are handled by VFS entry points.
|
||||
vfs_file_t *vf = vfs_open(path, mode);
|
||||
if (vf && vf->fs_handle) {
|
||||
return (FAT32_FileHandle*)vf->fs_handle;
|
||||
@@ -2197,7 +2228,7 @@ bool fat32_mkdir(const char *path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FileEntry *entry = ramfs_find_free_entry();
|
||||
FileEntry *entry = ramfs_alloc_entry();
|
||||
if (!entry) {
|
||||
kfree(normalized);
|
||||
spinlock_release_irqrestore(&ramfs_lock, rflags);
|
||||
@@ -2237,7 +2268,7 @@ bool fat32_rmdir(const char *path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
entry->used = false;
|
||||
ramfs_free_entry(entry);
|
||||
kfree(normalized);
|
||||
wm_notify_fs_change();
|
||||
spinlock_release_irqrestore(&ramfs_lock, rflags);
|
||||
@@ -2261,7 +2292,7 @@ bool fat32_delete(const char *path) {
|
||||
|
||||
FileEntry *entry = ramfs_find_file(normalized);
|
||||
if (entry && !(entry->attributes & ATTR_DIRECTORY)) {
|
||||
entry->used = false;
|
||||
ramfs_free_entry(entry);
|
||||
result = true;
|
||||
}
|
||||
kfree(normalized);
|
||||
@@ -2400,27 +2431,26 @@ bool fat32_rename(const char *old_path, const char *new_path) {
|
||||
char *suffix = (char*)kmalloc(FAT32_MAX_PATH);
|
||||
if (!suffix) { spinlock_release_irqrestore(&ramfs_lock, rflags); return false; }
|
||||
|
||||
for (int i = 0; i < MAX_FILES; i++) {
|
||||
if (!files[i].used) continue;
|
||||
if (fs_strcmp(files[i].full_path, old_path) == 0) {
|
||||
fs_strcpy(files[i].full_path, new_path);
|
||||
extract_filename(new_path, files[i].filename);
|
||||
extract_parent_path(new_path, files[i].parent_path);
|
||||
} else if (fs_strlen(files[i].full_path) > old_len &&
|
||||
fs_starts_with(files[i].full_path, old_path) &&
|
||||
files[i].full_path[old_len] == '/') {
|
||||
fs_strcpy(suffix, files[i].full_path + old_len);
|
||||
fs_strcpy(files[i].full_path, new_path);
|
||||
fs_strcat(files[i].full_path, suffix);
|
||||
for (FileEntry *n = file_list_head; n; n = n->next) {
|
||||
if (fs_strcmp(n->full_path, old_path) == 0) {
|
||||
fs_strcpy(n->full_path, new_path);
|
||||
extract_filename(new_path, n->filename);
|
||||
extract_parent_path(new_path, n->parent_path);
|
||||
} else if (fs_strlen(n->full_path) > old_len &&
|
||||
fs_starts_with(n->full_path, old_path) &&
|
||||
n->full_path[old_len] == '/') {
|
||||
fs_strcpy(suffix, n->full_path + old_len);
|
||||
fs_strcpy(n->full_path, new_path);
|
||||
fs_strcat(n->full_path, suffix);
|
||||
}
|
||||
if (fs_strcmp(files[i].parent_path, old_path) == 0) {
|
||||
fs_strcpy(files[i].parent_path, new_path);
|
||||
} else if (fs_strlen(files[i].parent_path) > old_len &&
|
||||
fs_starts_with(files[i].parent_path, old_path) &&
|
||||
files[i].parent_path[old_len] == '/') {
|
||||
fs_strcpy(suffix, files[i].parent_path + old_len);
|
||||
fs_strcpy(files[i].parent_path, new_path);
|
||||
fs_strcat(files[i].parent_path, suffix);
|
||||
if (fs_strcmp(n->parent_path, old_path) == 0) {
|
||||
fs_strcpy(n->parent_path, new_path);
|
||||
} else if (fs_strlen(n->parent_path) > old_len &&
|
||||
fs_starts_with(n->parent_path, old_path) &&
|
||||
n->parent_path[old_len] == '/') {
|
||||
fs_strcpy(suffix, n->parent_path + old_len);
|
||||
fs_strcpy(n->parent_path, new_path);
|
||||
fs_strcat(n->parent_path, suffix);
|
||||
}
|
||||
}
|
||||
kfree(suffix);
|
||||
@@ -2498,15 +2528,16 @@ int fat32_list_directory(const char *path, FAT32_FileInfo *entries, int max_entr
|
||||
if (!normalized) { spinlock_release_irqrestore(&ramfs_lock, rflags); return 0; }
|
||||
fat32_normalize_path(p, normalized);
|
||||
|
||||
for (int i = 0; i < MAX_FILES && count < max_entries; i++) {
|
||||
if (files[i].used && fs_strcmp(files[i].parent_path, normalized) == 0) {
|
||||
fs_strcpy(entries[count].name, files[i].filename);
|
||||
entries[count].size = files[i].size;
|
||||
entries[count].is_directory = (files[i].attributes & ATTR_DIRECTORY) != 0;
|
||||
entries[count].start_cluster = files[i].start_cluster;
|
||||
for (FileEntry *_n = file_list_head; _n && count < max_entries; _n = _n->next) {
|
||||
if (fs_strcmp(_n->parent_path, normalized) != 0) continue;
|
||||
fs_strcpy(entries[count].name, _n->filename);
|
||||
entries[count].size = _n->size;
|
||||
entries[count].is_directory = (_n->attributes & ATTR_DIRECTORY) != 0;
|
||||
entries[count].start_cluster = _n->start_cluster;
|
||||
entries[count].write_date = 0;
|
||||
entries[count].write_time = 0;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
kfree(normalized);
|
||||
}
|
||||
|
||||
|
||||
201
src/fs/procfs.c
@@ -4,6 +4,7 @@
|
||||
#include "../dev/disk.h"
|
||||
#include "memory_manager.h"
|
||||
#include "core/kutils.h"
|
||||
#include "core/platform.h"
|
||||
|
||||
typedef struct {
|
||||
uint32_t pid;
|
||||
@@ -55,7 +56,8 @@ int procfs_read(void *fs_private, void *handle, void *buf, int size) {
|
||||
procfs_handle_t *h = (procfs_handle_t*)handle;
|
||||
if (!h) return -1;
|
||||
|
||||
char out[1024];
|
||||
char *out = (char*)kmalloc(16384);
|
||||
if (!out) return -1;
|
||||
out[0] = 0;
|
||||
|
||||
if (h->pid == 0xFFFFFFFF) {
|
||||
@@ -88,34 +90,173 @@ int procfs_read(void *fs_private, void *handle, void *buf, int size) {
|
||||
} else if (k_strcmp(h->type, "cpuinfo") == 0) {
|
||||
extern uint32_t smp_cpu_count(void);
|
||||
extern void platform_get_cpu_model(char *model);
|
||||
char model[64];
|
||||
platform_get_cpu_model(model);
|
||||
extern void platform_get_cpu_vendor(char *vendor);
|
||||
extern void platform_get_cpu_info(cpu_info_t *info);
|
||||
extern void platform_get_cpu_flags(char *flags_str);
|
||||
|
||||
k_strcpy(out, "Processor: ");
|
||||
char model[64];
|
||||
char vendor[16];
|
||||
char flags[1024];
|
||||
cpu_info_t info;
|
||||
|
||||
platform_get_cpu_model(model);
|
||||
platform_get_cpu_vendor(vendor);
|
||||
platform_get_cpu_info(&info);
|
||||
platform_get_cpu_flags(flags);
|
||||
|
||||
uint32_t cpu_count = smp_cpu_count();
|
||||
out[0] = '\0';
|
||||
|
||||
// Output info for each processor
|
||||
for (uint32_t i = 0; i < cpu_count; i++) {
|
||||
char buf[32];
|
||||
|
||||
k_strcpy(out + k_strlen(out), "processor\t: ");
|
||||
k_itoa(i, buf);
|
||||
k_strcpy(out + k_strlen(out), buf);
|
||||
k_strcpy(out + k_strlen(out), "\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "vendor_id\t: ");
|
||||
k_strcpy(out + k_strlen(out), vendor);
|
||||
k_strcpy(out + k_strlen(out), "\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "cpu family\t: ");
|
||||
k_itoa(info.family, buf);
|
||||
k_strcpy(out + k_strlen(out), buf);
|
||||
k_strcpy(out + k_strlen(out), "\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "model\t\t: ");
|
||||
k_itoa(info.model, buf);
|
||||
k_strcpy(out + k_strlen(out), buf);
|
||||
k_strcpy(out + k_strlen(out), "\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "model name\t: ");
|
||||
k_strcpy(out + k_strlen(out), model);
|
||||
k_strcpy(out + k_strlen(out), "\nCores: ");
|
||||
char c_s[16]; k_itoa(smp_cpu_count(), c_s);
|
||||
k_strcpy(out + k_strlen(out), c_s);
|
||||
k_strcpy(out + k_strlen(out), "\nArchitecture: x86_64\n");
|
||||
k_strcpy(out + k_strlen(out), "\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "stepping\t: ");
|
||||
k_itoa(info.stepping, buf);
|
||||
k_strcpy(out + k_strlen(out), buf);
|
||||
k_strcpy(out + k_strlen(out), "\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "microcode\t: 0x");
|
||||
char hex[16];
|
||||
int temp = info.microcode;
|
||||
int hex_pos = 0;
|
||||
for (int j = 7; j >= 0; j--) {
|
||||
int digit = (temp >> (j * 4)) & 0xF;
|
||||
hex[hex_pos++] = digit < 10 ? '0' + digit : 'a' + (digit - 10);
|
||||
}
|
||||
hex[hex_pos] = '\0';
|
||||
k_strcpy(out + k_strlen(out), hex);
|
||||
k_strcpy(out + k_strlen(out), "\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "cache size\t: ");
|
||||
k_itoa(info.cache_size, buf);
|
||||
k_strcpy(out + k_strlen(out), buf);
|
||||
k_strcpy(out + k_strlen(out), " KB\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "physical id\t: 0\n");
|
||||
k_strcpy(out + k_strlen(out), "siblings\t: ");
|
||||
k_itoa(cpu_count, buf);
|
||||
k_strcpy(out + k_strlen(out), buf);
|
||||
k_strcpy(out + k_strlen(out), "\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "core id\t\t: ");
|
||||
k_itoa(i, buf);
|
||||
k_strcpy(out + k_strlen(out), buf);
|
||||
k_strcpy(out + k_strlen(out), "\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "cpu cores\t: ");
|
||||
k_itoa(cpu_count, buf);
|
||||
k_strcpy(out + k_strlen(out), buf);
|
||||
k_strcpy(out + k_strlen(out), "\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "apicid\t\t: ");
|
||||
k_itoa(i, buf);
|
||||
k_strcpy(out + k_strlen(out), buf);
|
||||
k_strcpy(out + k_strlen(out), "\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "initial apicid\t: ");
|
||||
k_itoa(i, buf);
|
||||
k_strcpy(out + k_strlen(out), buf);
|
||||
k_strcpy(out + k_strlen(out), "\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "fpu\t\t: yes\n");
|
||||
k_strcpy(out + k_strlen(out), "fpu_exception\t: yes\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "cpuid level\t: 13\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "wp\t\t: yes\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "flags\t\t: ");
|
||||
k_strcpy(out + k_strlen(out), flags);
|
||||
k_strcpy(out + k_strlen(out), "\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "bugs\t\t: \n");
|
||||
k_strcpy(out + k_strlen(out), "bogomips\t: 4800.00\n");
|
||||
|
||||
if (i < cpu_count - 1) {
|
||||
k_strcpy(out + k_strlen(out), "\n");
|
||||
}
|
||||
}
|
||||
} else if (k_strcmp(h->type, "meminfo") == 0) {
|
||||
extern MemStats memory_get_stats(void);
|
||||
MemStats stats = memory_get_stats();
|
||||
k_strcpy(out, "MemTotal: ");
|
||||
char m_s[32]; k_itoa(stats.total_memory / 1024, m_s);
|
||||
char m_s[32];
|
||||
|
||||
k_strcpy(out, "MemTotal:\t");
|
||||
k_itoa(stats.total_memory / 1024, m_s);
|
||||
k_strcpy(out + k_strlen(out), m_s);
|
||||
k_strcpy(out + k_strlen(out), " kB\nMemFree: ");
|
||||
k_strcpy(out + k_strlen(out), " kB\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "MemFree:\t");
|
||||
k_itoa(stats.available_memory / 1024, m_s);
|
||||
k_strcpy(out + k_strlen(out), m_s);
|
||||
k_strcpy(out + k_strlen(out), " kB\nMemUsed: ");
|
||||
k_strcpy(out + k_strlen(out), " kB\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "MemAvailable:\t");
|
||||
k_itoa(stats.available_memory / 1024, m_s);
|
||||
k_strcpy(out + k_strlen(out), m_s);
|
||||
k_strcpy(out + k_strlen(out), " kB\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "Buffers:\t0 kB\n");
|
||||
k_strcpy(out + k_strlen(out), "Cached:\t\t0 kB\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "MemUsed:\t");
|
||||
k_itoa(stats.used_memory / 1024, m_s);
|
||||
k_strcpy(out + k_strlen(out), m_s);
|
||||
k_strcpy(out + k_strlen(out), " kB\nPeak: ");
|
||||
k_strcpy(out + k_strlen(out), " kB\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "MemPeak:\t");
|
||||
k_itoa(stats.peak_memory_used / 1024, m_s);
|
||||
k_strcpy(out + k_strlen(out), m_s);
|
||||
k_strcpy(out + k_strlen(out), " kB\nBlocks: ");
|
||||
k_strcpy(out + k_strlen(out), " kB\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "SwapTotal:\t0 kB\n");
|
||||
k_strcpy(out + k_strlen(out), "SwapFree:\t0 kB\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "Dirty:\t\t0 kB\n");
|
||||
k_strcpy(out + k_strlen(out), "Writeback:\t0 kB\n");
|
||||
k_strcpy(out + k_strlen(out), "AnonPages:\t");
|
||||
k_itoa(stats.used_memory / 1024, m_s);
|
||||
k_strcpy(out + k_strlen(out), m_s);
|
||||
k_strcpy(out + k_strlen(out), " kB\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "Mapped:\t\t0 kB\n");
|
||||
k_strcpy(out + k_strlen(out), "Shmem:\t\t0 kB\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "Blocks:\t\t");
|
||||
k_itoa(stats.allocated_blocks, m_s);
|
||||
k_strcpy(out + k_strlen(out), m_s);
|
||||
k_strcpy(out + k_strlen(out), "\nFragmentation: ");
|
||||
k_strcpy(out + k_strlen(out), "\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "FreeBlocks:\t");
|
||||
k_itoa(stats.free_blocks, m_s);
|
||||
k_strcpy(out + k_strlen(out), m_s);
|
||||
k_strcpy(out + k_strlen(out), "\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "Fragmentation:\t");
|
||||
k_itoa(stats.fragmentation_percent, m_s);
|
||||
k_strcpy(out + k_strlen(out), m_s);
|
||||
k_strcpy(out + k_strlen(out), "%\n");
|
||||
@@ -123,24 +264,42 @@ int procfs_read(void *fs_private, void *handle, void *buf, int size) {
|
||||
extern int disk_get_count(void);
|
||||
extern Disk* disk_get_by_index(int index);
|
||||
int dcount = disk_get_count();
|
||||
k_strcpy(out, "Block Devices:\n");
|
||||
out[0] = '\0';
|
||||
|
||||
k_strcpy(out, "Character devices:\n");
|
||||
k_strcpy(out + k_strlen(out), " 1 mem\n");
|
||||
k_strcpy(out + k_strlen(out), " 4 tty\n");
|
||||
k_strcpy(out + k_strlen(out), " 5 cua\n");
|
||||
k_strcpy(out + k_strlen(out), " 7 vcs\n");
|
||||
k_strcpy(out + k_strlen(out), " 8 stdin\n");
|
||||
k_strcpy(out + k_strlen(out), " 13 input\n");
|
||||
k_strcpy(out + k_strlen(out), " 14 sound\n");
|
||||
k_strcpy(out + k_strlen(out), " 29 fb\n");
|
||||
k_strcpy(out + k_strlen(out), "189 usb\n\n");
|
||||
|
||||
k_strcpy(out + k_strlen(out), "Block devices:\n");
|
||||
for (int i = 0; i < dcount; i++) {
|
||||
Disk *d = disk_get_by_index(i);
|
||||
if (d) {
|
||||
k_strcpy(out + k_strlen(out), " - ");
|
||||
if (d && !d->is_partition) {
|
||||
k_strcpy(out + k_strlen(out), " 8 ");
|
||||
k_strcpy(out + k_strlen(out), d->devname);
|
||||
k_strcpy(out + k_strlen(out), "\n");
|
||||
}
|
||||
}
|
||||
k_strcpy(out + k_strlen(out), " 11 sr\n");
|
||||
k_strcpy(out + k_strlen(out), "253 virtblk\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
process_t *proc = process_get_by_pid(h->pid);
|
||||
if (!proc) return -1;
|
||||
if (!proc) { kfree(out); return -1; }
|
||||
|
||||
if (k_strcmp(h->type, "name") == 0 || k_strcmp(h->type, "cmdline") == 0) {
|
||||
k_strcpy(out, proc->name);
|
||||
k_strcpy(out + k_strlen(out), "\n");
|
||||
} else if (k_strcmp(h->type, "cwd") == 0) {
|
||||
k_strcpy(out, proc->cwd);
|
||||
k_strcpy(out + k_strlen(out), "\n");
|
||||
} else if (k_strcmp(h->type, "status") == 0) {
|
||||
k_strcpy(out, "Name: ");
|
||||
k_strcpy(out + k_strlen(out), proc->name);
|
||||
@@ -165,13 +324,14 @@ int procfs_read(void *fs_private, void *handle, void *buf, int size) {
|
||||
}
|
||||
|
||||
int len = k_strlen(out);
|
||||
if (h->offset >= len) return 0;
|
||||
if (h->offset >= len) { kfree(out); return 0; }
|
||||
|
||||
int to_copy = len - h->offset;
|
||||
if (to_copy > size) to_copy = size;
|
||||
|
||||
k_memcpy(buf, out + h->offset, to_copy);
|
||||
h->offset += to_copy;
|
||||
kfree(out);
|
||||
return to_copy;
|
||||
}
|
||||
|
||||
@@ -230,6 +390,7 @@ int procfs_readdir(void *fs_private, const char *path, vfs_dirent_t *entries, in
|
||||
k_strcpy(entries[out++].name, "name");
|
||||
k_strcpy(entries[out++].name, "status");
|
||||
k_strcpy(entries[out++].name, "cmdline");
|
||||
k_strcpy(entries[out++].name, "cwd");
|
||||
k_strcpy(entries[out++].name, "signal");
|
||||
for(int i=0; i<out; i++) entries[i].is_directory = 0;
|
||||
return out;
|
||||
|
||||
@@ -189,7 +189,7 @@ void vfs_init(void) {
|
||||
}
|
||||
mount_count = 0;
|
||||
|
||||
serial_write("[VFS] Virtual File System initialized\n");
|
||||
serial_write("[VFS] Ready\n");
|
||||
}
|
||||
|
||||
// ===============
|
||||
|
||||
BIN
src/images/icons/colloid/0ad.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src/images/icons/colloid/2048.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
src/images/icons/colloid/4kvideodownloader.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
src/images/icons/colloid/AppImageLauncher.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
src/images/icons/colloid/DV_Uninstall.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src/images/icons/colloid/GPU.Screen.Recorder.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
674
src/images/icons/colloid/LICENSE.txt
Normal file
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
BIN
src/images/icons/colloid/NoMachine-icon.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
src/images/icons/colloid/Qcm.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
src/images/icons/colloid/R.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src/images/icons/colloid/Ripcord_Icon.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
src/images/icons/colloid/Seamly2D_logo.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
src/images/icons/colloid/Smash.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
src/images/icons/colloid/Steam++.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
src/images/icons/colloid/World-of-Warcraft.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
src/images/icons/colloid/Zoom.png
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
src/images/icons/colloid/a-boy-and-his-blob.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
src/images/icons/colloid/aaaaxy.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
src/images/icons/colloid/access.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
src/images/icons/colloid/accessories-camera.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
src/images/icons/colloid/accessories-character-map.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src/images/icons/colloid/accessories-dictionary.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
src/images/icons/colloid/accessories-document-viewer.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src/images/icons/colloid/accessories-media-converter.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src/images/icons/colloid/accessories-podcast.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
src/images/icons/colloid/accessories-screenshot.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
src/images/icons/colloid/accessories-system-cleaner.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
src/images/icons/colloid/accessories-text-editor.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
src/images/icons/colloid/acroread.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
src/images/icons/colloid/add-times.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
src/images/icons/colloid/addressbook.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
src/images/icons/colloid/adw-steam-gtk.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
src/images/icons/colloid/aegisub.png
Normal file
|
After Width: | Height: | Size: 12 KiB |