mirror of
https://github.com/JannisHeydemann/BoredOS.git
synced 2026-05-30 10:26:59 +00:00
Compare commits
238 Commits
| 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 | ||
|
|
a1b6d58b77 | ||
|
|
cbc196a4b1 | ||
|
|
b4c14af48d | ||
|
|
700839e6be | ||
|
|
921e8a5658 | ||
|
|
437d57312f | ||
|
|
afc4e16fcf | ||
|
|
38ed0b5ffa | ||
|
|
5933483009 | ||
|
|
6b6a22d518 | ||
|
|
85427041de | ||
|
|
8b77e8c48e | ||
|
|
1ce08c70b0 | ||
|
|
fca67f68a9 | ||
|
|
c330382436 | ||
|
|
f0c2963793 | ||
|
|
3b24bc882c | ||
|
|
2b44e59e9f | ||
|
|
7a2769e8e3 | ||
|
|
1a6e30b52e | ||
|
|
69847adee6 | ||
|
|
f402e5e4f0 | ||
|
|
684ed774ee | ||
|
|
9ed8eac3e5 | ||
|
|
c6d512b0f2 | ||
|
|
0b7a134282 | ||
|
|
91b67bd8d5 | ||
|
|
e60f232812 | ||
|
|
3169ec51cb | ||
|
|
beb2c724ff | ||
|
|
bf3c2cb578 | ||
|
|
823e9c0ce7 | ||
|
|
0ddb1e7610 | ||
|
|
32a6bb4d72 | ||
|
|
d8e680604c | ||
|
|
2e28f860cb | ||
|
|
9634ebb086 | ||
|
|
d7d97b5a97 | ||
|
|
4a3752583c | ||
|
|
9de8ee143c | ||
|
|
8d5fa53d3e | ||
|
|
ad8db32305 | ||
|
|
92928e55fb | ||
|
|
31eb7afdc6 | ||
|
|
ad9fac3e28 | ||
|
|
70cd296d19 | ||
|
|
b7020152c1 | ||
|
|
63749b8734 | ||
|
|
4e8ea5acd2 | ||
|
|
5c199e028a | ||
|
|
ec2a9d1883 | ||
|
|
4c46650c64 | ||
|
|
1ee2fcad9e | ||
|
|
5c29ac1473 | ||
|
|
81743261bf | ||
|
|
4eeb907342 | ||
|
|
e527f63af7 | ||
|
|
1e19963a8d | ||
|
|
60ab70a49d | ||
|
|
d9bcc4aff7 | ||
|
|
5604866882 | ||
|
|
e95c82b162 | ||
|
|
9fb307e603 | ||
|
|
a7c3cccce7 | ||
|
|
7eb55f3a59 | ||
|
|
72baf6506d | ||
|
|
2817ad51da | ||
|
|
5b10127e02 | ||
|
|
1404a6ae4f | ||
|
|
7b7f134e27 | ||
|
|
0491c4ad0f | ||
|
|
c6fe9971d8 | ||
|
|
88f178e368 | ||
|
|
d824b4610a | ||
|
|
a4f16b0604 | ||
|
|
83413fdd2b | ||
|
|
2a918bc7ba | ||
|
|
2624b4f8df | ||
|
|
be67c27f58 | ||
|
|
65f362feab | ||
|
|
6b18d44fab | ||
|
|
8b172a69a1 | ||
|
|
0846ed27b2 | ||
|
|
1cb8425653 | ||
|
|
f403816acf | ||
|
|
5af6b8ec5c | ||
|
|
cea0b59c93 | ||
|
|
c5111cdcb5 | ||
|
|
803ebdaefa | ||
|
|
884af3857f | ||
|
|
b427b1d4ac | ||
|
|
d01c309166 | ||
|
|
fc83d7941b | ||
|
|
3da1496e4f | ||
|
|
90e5125913 | ||
|
|
30f1b66b05 | ||
|
|
6c273e0f2f | ||
|
|
4bab8949e7 | ||
|
|
df73f00efd | ||
|
|
b05b221c41 | ||
|
|
95c465ca39 | ||
|
|
569adabf10 |
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -1,2 +0,0 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
62
.github/workflows/nightly.yml
vendored
Normal file
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 }}
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -20,13 +20,14 @@ limine 2/limine.dSYM/Contents/Resources/DWARF/limine
|
||||
limine 2/limine.exe
|
||||
boredos.dump
|
||||
qemu-debug.log
|
||||
build/
|
||||
iso_root/
|
||||
limine/
|
||||
src/kernel/userland/bin/
|
||||
src/userland/bin/
|
||||
boredos.iso
|
||||
disk.img
|
||||
limine
|
||||
**/.DS_Store
|
||||
.DS_Store
|
||||
src/.DS_Store
|
||||
limine
|
||||
/build/
|
||||
*.o
|
||||
disk.img
|
||||
|
||||
8
LICENSE
8
LICENSE
@@ -1,7 +1,7 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright(C) Chris(boreddevnl) 2024-2026
|
||||
Copyright(C) Chris (boreddevnl) 2024-2026
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
@@ -647,7 +647,7 @@ the "copyright" line and a pointer to where the full notice is found.
|
||||
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/>.
|
||||
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.
|
||||
|
||||
@@ -666,11 +666,11 @@ 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/>.
|
||||
<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>.
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html\>.
|
||||
|
||||
324
Makefile
324
Makefile
@@ -10,27 +10,66 @@ LD = x86_64-elf-ld
|
||||
NASM = nasm
|
||||
XORRISO = xorriso
|
||||
|
||||
SRC_DIR = src/kernel
|
||||
SRC_DIR = src
|
||||
BUILD_DIR = build
|
||||
ISO_DIR = iso_root
|
||||
|
||||
KERNEL_ELF = $(BUILD_DIR)/boredos.elf
|
||||
ISO_IMAGE = boredos.iso
|
||||
|
||||
C_SOURCES = $(wildcard $(SRC_DIR)/*.c) \
|
||||
$(wildcard $(SRC_DIR)/lwip/core/*.c) \
|
||||
$(wildcard $(SRC_DIR)/lwip/core/ipv4/*.c) \
|
||||
$(SRC_DIR)/lwip/netif/ethernet.c \
|
||||
$(SRC_DIR)/lwip/netif/bridgeif.c
|
||||
BLUE = \033[1;34m
|
||||
GREEN = \033[1;32m
|
||||
YELLOW= \033[1;33m
|
||||
RESET = \033[0m
|
||||
|
||||
ASM_SOURCES = $(wildcard $(SRC_DIR)/*.asm)
|
||||
OBJ_FILES = $(patsubst $(SRC_DIR)/%.c, $(BUILD_DIR)/%.o, $(C_SOURCES)) \
|
||||
$(patsubst $(SRC_DIR)/%.asm, $(BUILD_DIR)/%.o, $(ASM_SOURCES))
|
||||
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/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/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)/lwip
|
||||
-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
|
||||
@@ -40,125 +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)/limine.h ]; then \
|
||||
echo "Copying limine.h..."; \
|
||||
cp limine/limine.h $(SRC_DIR)/limine.h; \
|
||||
@if [ ! -f $(SRC_DIR)/core/limine.h ]; then \
|
||||
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)/%.asm | $(BUILD_DIR)
|
||||
$(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/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)/test_syscall.asm | $(BUILD_DIR)
|
||||
$(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)/user_test.asm | $(BUILD_DIR)
|
||||
$(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)/process_asm.asm | $(BUILD_DIR)
|
||||
$(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."
|
||||
|
||||
$(ISO_IMAGE): $(KERNEL_ELF) limine.conf limine-setup
|
||||
$(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 \
|
||||
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 \
|
||||
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 \
|
||||
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 \
|
||||
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 \
|
||||
printf " -> $$f"; \
|
||||
cp "$$f" $(BUILD_DIR)/initrd/Library/Fonts/Emoji/; \
|
||||
fi \
|
||||
done
|
||||
|
||||
@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
|
||||
|
||||
@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)/
|
||||
mkdir -p $(ISO_DIR)/bin
|
||||
@for f in $(SRC_DIR)/userland/bin/*.elf; do \
|
||||
if [ -f "$$f" ]; then \
|
||||
basename=$$(basename "$$f"); \
|
||||
cp "$$f" $(ISO_DIR)/bin/; \
|
||||
echo " module_path: boot():/bin/$$basename" >> $(ISO_DIR)/limine.conf; \
|
||||
fi \
|
||||
done
|
||||
|
||||
@if [ -f README.md ]; then cp README.md $(ISO_DIR)/; fi
|
||||
@if [ -f $(SRC_DIR)/userland/doom/doom1.wad ]; then \
|
||||
mkdir -p $(ISO_DIR)/Library/DOOM; \
|
||||
cp $(SRC_DIR)/userland/doom/doom1.wad $(ISO_DIR)/Library/DOOM/; \
|
||||
echo " module_path: boot():/Library/DOOM/doom1.wad" >> $(ISO_DIR)/limine.conf; \
|
||||
fi
|
||||
@printf "$(YELLOW)[COPY]$(RESET) Initrd..."
|
||||
cp $(BUILD_DIR)/initrd.tar $(ISO_DIR)/
|
||||
|
||||
mkdir -p $(ISO_DIR)/Library/images/Wallpapers
|
||||
@for f in $(SRC_DIR)/images/wallpapers/*; do \
|
||||
if [ -f "$$f" ]; then \
|
||||
basename=$$(basename "$$f"); \
|
||||
cp "$$f" $(ISO_DIR)/Library/images/Wallpapers/; \
|
||||
echo " module_path: boot():/Library/images/Wallpapers/$$basename" >> $(ISO_DIR)/limine.conf; \
|
||||
fi \
|
||||
done
|
||||
@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
|
||||
|
||||
mkdir -p $(ISO_DIR)/Library/images/gif
|
||||
@for f in $(SRC_DIR)/images/gif/*.gif; do \
|
||||
if [ -f "$$f" ]; then \
|
||||
basename=$$(basename "$$f"); \
|
||||
cp "$$f" $(ISO_DIR)/Library/images/gif/; \
|
||||
echo " module_path: boot():/Library/images/gif/$$basename" >> $(ISO_DIR)/limine.conf; \
|
||||
fi \
|
||||
done
|
||||
@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/
|
||||
|
||||
mkdir -p $(ISO_DIR)/Library/Fonts
|
||||
@for f in $(SRC_DIR)/fonts/*.ttf; do \
|
||||
if [ -f "$$f" ]; then \
|
||||
basename=$$(basename "$$f"); \
|
||||
cp "$$f" $(ISO_DIR)/Library/Fonts/; \
|
||||
echo " module_path: boot():/Library/Fonts/$$basename" >> $(ISO_DIR)/limine.conf; \
|
||||
fi \
|
||||
done
|
||||
|
||||
$(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 e1000,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
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*
|
||||
205
README.md
205
README.md
@@ -2,167 +2,92 @@
|
||||
|
||||
<div align="center">
|
||||
<img src="boredos.svg" alt="BoredOS Logo" width="450" />
|
||||
<p><em>A modern x86_64 hobbyist operating system built from the ground up.</em></p>
|
||||
|
||||
[](https://www.gnu.org/licenses/gpl-3.0)
|
||||

|
||||

|
||||

|
||||
</div>
|
||||
BoredOS is a simple x86_64 hobbyist operating system.
|
||||
It features a DE (and WM), a FAT32 filesystem, customizable UI and much much more!
|
||||
|
||||
---
|
||||
|
||||
BoredOS is a x86_64 operating system featuring a custom Desktop Environment (DE), a dedicated Window Manager (BoredWM), and a FAT32 filesystem. It balances low-level kernel exploration with a surprisingly capable userspace.
|
||||
|
||||

|
||||
*this screenshot might be outdated*
|
||||
> [!NOTE]
|
||||
> *The screenshot above may represent a previous build and is subject to change as the UI evolves.*
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
- userspace
|
||||
- JPG image support
|
||||
- Disk manager
|
||||
- Drag and drop mouse centered UI
|
||||
- Customizable UI
|
||||
- Basic Networking Stack
|
||||
- Bored WM
|
||||
- FAT32 filesystem
|
||||
- 64-bit long mode support
|
||||
- Multiboot2 compliant
|
||||
- Text editor
|
||||
- Markdown Viewer
|
||||
- Minesweeper
|
||||
- Markdown Viewer
|
||||
- GUI Text editor
|
||||
- Paint application
|
||||
- IDT
|
||||
- Ability to run on actual x86_64 hardware
|
||||
- CLI
|
||||
- (Limited) C Compiler
|
||||
|
||||
## Prerequisites
|
||||
### System Architecture
|
||||
* **64-bit Long Mode:** Fully utilizing the x86_64 architecture.
|
||||
* **Symmetric Multi-Processing (SMP):** Full support for multi-core CPUs via Limine SMP.
|
||||
* **LAPIC & IPI Scheduling:** Advanced interrupt handling and inter-processor communication for task distribution.
|
||||
* **SMP-Safe Spinlocks:** Robust kernel-wide synchronization for VFS, process management, and the GUI.
|
||||
* **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 and a basic web browser.
|
||||
|
||||
To build BoredOS, you'll need the following tools installed:
|
||||
### 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. (PNG, GIF, JPEG, TGA, BMP)
|
||||
|
||||
- **x86_64 ELF Toolchain**: `x86_64-elf-gcc`, `x86_64-elf-ld`
|
||||
- **NASM**: Netwide Assembler for compiling assembly code
|
||||
- **xorriso**: For creating bootable ISO images
|
||||
- **QEMU** (optional): For testing the kernel in an emulator
|
||||
### Included Applications
|
||||
* **Productivity:** GUI Text Editor calculator, Markdown Viewer, a simple browser and BoredWord.
|
||||
* **Creativity:** A Paint application.
|
||||
* **Utilities:** Terminal, Task Manager, File Explorer, Clock and a (limited) C Compiler.
|
||||
* **Games:** Minesweeper and DOOM.
|
||||
|
||||
On macOS, you can install these using Homebrew:
|
||||
```sh
|
||||
brew install x86_64-elf-binutils x86_64-elf-gcc nasm xorriso qemu
|
||||
```
|
||||
---
|
||||
|
||||
## Building
|
||||
## 📚 Documentation
|
||||
|
||||
Simply run `make` from the project root:
|
||||
Explore the internal workings of BoredOS via our comprehensive guides in the [`docs/`](docs/) directory.
|
||||
|
||||
```sh
|
||||
make
|
||||
```
|
||||
* 📖 **[Documentation Index](docs/README.md)** – Start here.
|
||||
* 🏗️ **[Architecture Overview](docs/architecture/core.md)** – Deep dive into the kernel.
|
||||
* 🔨 **[Building and Running](docs/build/usage.md)** – Setup your build environment.
|
||||
* 🚀 **[AppDev SDK](docs/appdev/custom_apps.md)** – Build your own apps for BoredOS.
|
||||
|
||||
This will:
|
||||
1. Compile all kernel C sources and assembly files
|
||||
2. Link the kernel ELF binary
|
||||
3. Generate a bootable ISO image (`boredos.iso`)
|
||||
---
|
||||
|
||||
The build output is organized as follows:
|
||||
- Compiled object files: `build/`
|
||||
- ISO root filesystem: `iso_root/`
|
||||
- Final ISO image: `boredos.iso`
|
||||
## Support the Journey
|
||||
|
||||
## Running
|
||||
If you find this project interesting or helpful, consider fueling the development with a coffee!
|
||||
|
||||
### QEMU Emulation
|
||||
|
||||
Run the kernel in QEMU:
|
||||
|
||||
```sh
|
||||
make run
|
||||
```
|
||||
|
||||
Or manually:
|
||||
```sh
|
||||
qemu-system-x86_64 -m 2G -serial stdio -cdrom boredos.iso -boot d
|
||||
```
|
||||
|
||||
### Running on Real Hardware
|
||||
|
||||
*Warning: This is at YOUR OWN RISK. This software comes with ZERO warranty and may break your system.*
|
||||
|
||||
1. **Create bootable USB**: Use [Balena Etcher](https://www.balena.io/etcher/) to flash `boredos.iso` to a USB drive
|
||||
|
||||
2. **Prepare the system**:
|
||||
- Enable legacy (BIOS) boot in your system BIOS/UEFI settings
|
||||
- Disable Secure Boot if needed
|
||||
|
||||
3. **Boot**: Insert the USB drive and select it in the boot menu during startup
|
||||
|
||||
**Networking requires an Intel E1000 network card or similar while using Ethernet.**
|
||||
|
||||
4. **Tested Hardware**:
|
||||
- HP EliteDesk 705 G4 DM (AMD Ryzen 5 PRO 2400G, Radeon Vega) **Tested, no networking.**
|
||||
- Lenovo ThinkPad A475 20KL002VMH (AMD Pro A12-8830B, Radeon R7) **Tested, no networking.**
|
||||
- Acer Aspire E5-573-311M (Intel Core i3-5005U, Intel HD Graphics) **Tested, no networking.**
|
||||
|
||||
|
||||
## Project Structure
|
||||
|
||||
- `src/kernel/` - Main kernel implementation
|
||||
- `boot.asm` - Boot assembly code
|
||||
- `main.c` - Kernel entry point
|
||||
- `*.c / *.h` - Core kernel modules (graphics, interrupts, filesystem, etc.)
|
||||
- `cli_apps/` - Command-line applications
|
||||
- `build/` - Compiled object files (generated during build)
|
||||
- `iso_root/` - ISO filesystem layout (generated during build)
|
||||
- `limine/` - Limine bootloader files (downloaded automatically)
|
||||
- `linker.ld` - Linker script for x86_64 ELF
|
||||
- `limine.conf` - Limine bootloader configuration
|
||||
- `Makefile` - Build configuration and targets
|
||||
|
||||
|
||||
|
||||
|
||||
###
|
||||
###
|
||||
|
||||
<h2 align="left">Help me brew some coffee! ☕️</h2>
|
||||
|
||||
###
|
||||
|
||||
<p align="left">
|
||||
If you enjoy this project, and like what i'm doing here, consider buying me a coffee!
|
||||
<br><br>
|
||||
<a href="https://buymeacoffee.com/boreddevnl" target="_blank">
|
||||
<a href="https://buymeacoffee.com/boreddevhq" target="_blank">
|
||||
<img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="50" style="border-radius: 8px;" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
###
|
||||
</a>
|
||||
|
||||
|
||||
## This project was previously labeled as "BrewKernel"
|
||||
Brewkernel was a text only very simple (and messy) project i started 3 years ago. It was my first work in OSDev and i absolutely loved it. It sadly just got too messy and i myself couldn't understand my own code anymore. About a year ago i started work on BoredOS, and pushed a *"working"* version of it a few days ago as of writing this *(Feb. 10 2026)*
|
||||
Brewkernel has already been deprecated and will not be accepting any pull requests or fix any issues as it is now a public archive.
|
||||
Thanks to everyone who helped me with Brewkernel, even if it were just ideas, and intend to keep working on this for the forseeable future!
|
||||
---
|
||||
|
||||
## Project Disclaimer & Heritage
|
||||
|
||||
**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.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Please ensure all issues, discussions, and contributions are directed to this repository. Legacy BrewKernel code is preserved for historical purposes only and is not compatible with BoredOS.
|
||||
|
||||
---
|
||||
|
||||
## Contributors
|
||||
|
||||
- **BoredDevNL** — Project creator and lead maintainer.
|
||||
- **Lluciocc** — Contributor.
|
||||
|
||||
## License
|
||||
|
||||
Copyright (C) 2024-2026 boreddevnl
|
||||
**Copyright (C) 2023-2026 boreddevnl**
|
||||
|
||||
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.
|
||||
Distributed under the **GNU General Public License v3**. See the `LICENSE` file for details.
|
||||
|
||||
NOTICE
|
||||
------
|
||||
|
||||
This product includes software developed by Chris ("boreddevnl") as part of the BoredOS (Previously Brewkernel/BrewOS) project.
|
||||
|
||||
Copyright (C) 2024–2026 Chris / boreddevnl (previously boreddevhq)
|
||||
|
||||
All source files in this repository contain copyright and license
|
||||
headers that must be preserved in redistributions and derivative works.
|
||||
|
||||
If you distribute or modify this project (in whole or in part),
|
||||
you MUST:
|
||||
|
||||
- Retain all copyright and license headers at the top of each file.
|
||||
- Include this NOTICE file along with any redistributions or
|
||||
derivative works.
|
||||
- Provide clear attribution to the original author in documentation
|
||||
or credits where appropriate.
|
||||
|
||||
The above attribution requirements are informational and intended to
|
||||
ensure proper credit is given. They do not alter or supersede the
|
||||
terms of the GNU General Public License (GPL), which governs this work.
|
||||
> [!IMPORTANT]
|
||||
> This product includes software developed by Chris ("boreddevnl"). You must retain all copyright headers and include the original attribution in any redistributions or derivative works. See the `NOTICE` file for more details.
|
||||
|
||||
BIN
boredos.iso
BIN
boredos.iso
Binary file not shown.
@@ -1,4 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 130" width="100%">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 415 130" width="100%">
|
||||
<style>
|
||||
text {
|
||||
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
|
||||
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
533
build.log
533
build.log
@@ -1,533 +0,0 @@
|
||||
mkdir -p build
|
||||
mkdir -p build
|
||||
Building Limine host utility...
|
||||
make[1]: Nothing to be done for `all'.
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/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/kernel -Isrc/kernel/lwip -c src/kernel/disk_manager.c -o build/disk_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/kernel -Isrc/kernel/lwip -c src/kernel/e1000.c -o build/e1000.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/kernel -Isrc/kernel/lwip -c src/kernel/e1000_netif.c -o build/e1000_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/kernel -Isrc/kernel/lwip -c src/kernel/elf.c -o build/elf.o
|
||||
src/kernel/elf.c:12:13: warning: 'print_hex' defined but not used [-Wunused-function]
|
||||
12 | static void print_hex(uint64_t n) {
|
||||
| ^~~~~~~~~
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/explorer.c -o build/explorer.o
|
||||
src/kernel/explorer.c: In function 'explorer_draw_file_icon':
|
||||
src/kernel/explorer.c:887:73: warning: unused parameter 'color' [-Wunused-parameter]
|
||||
887 | static void explorer_draw_file_icon(int x, int y, bool is_dir, uint32_t color, const char *filename, const char *current_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/kernel -Isrc/kernel/lwip -c src/kernel/fat32.c -o build/fat32.o
|
||||
src/kernel/fat32.c: In function 'fat32_normalize_path':
|
||||
src/kernel/fat32.c:151:10: warning: unused variable 'drive' [-Wunused-variable]
|
||||
151 | char drive = parse_drive_from_path(&p);
|
||||
| ^~~~~
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/font_manager.c -o build/font_manager.o
|
||||
In file included from src/kernel/font_manager.c:4:
|
||||
src/kernel/stb_truetype.h: In function 'stbtt_FreeShape':
|
||||
src/kernel/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/kernel/stb_truetype.h: In function 'stbtt__hheap_alloc':
|
||||
src/kernel/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/kernel/stb_truetype.h: In function 'stbtt__hheap_cleanup':
|
||||
src/kernel/stb_truetype.h:2797:58: warning: unused parameter 'userdata' [-Wunused-parameter]
|
||||
2797 | static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata)
|
||||
| ~~~~~~^~~~~~~~
|
||||
src/kernel/stb_truetype.h: In function 'stbtt_FlattenCurves':
|
||||
src/kernel/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/kernel/stb_truetype.h: In function 'stbtt_FreeBitmap':
|
||||
src/kernel/stb_truetype.h:3708:62: warning: unused parameter 'userdata' [-Wunused-parameter]
|
||||
3708 | STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata)
|
||||
| ~~~~~~^~~~~~~~
|
||||
src/kernel/stb_truetype.h: In function 'stbtt_FreeSDF':
|
||||
src/kernel/stb_truetype.h:4767:59: warning: unused parameter 'userdata' [-Wunused-parameter]
|
||||
4767 | STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata)
|
||||
| ~~~~~~^~~~~~~~
|
||||
src/kernel/font_manager.c: In function 'font_manager_load':
|
||||
src/kernel/font_manager.c:93:9: warning: unused variable 'read' [-Wunused-variable]
|
||||
93 | int read = fat32_read(fh, buffer, fsize);
|
||||
| ^~~~
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/gdt.c -o build/gdt.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/kernel -Isrc/kernel/lwip -c src/kernel/graphics.c -o build/graphics.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/kernel -Isrc/kernel/lwip -c src/kernel/idt.c -o build/idt.o
|
||||
src/kernel/idt.c: In function 'pic_remap':
|
||||
src/kernel/idt.c:110:17: warning: variable 'a2' set but not used [-Wunused-but-set-variable]
|
||||
110 | uint8_t a1, a2;
|
||||
| ^~
|
||||
src/kernel/idt.c:110:13: warning: variable 'a1' set but not used [-Wunused-but-set-variable]
|
||||
110 | 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/kernel -Isrc/kernel/lwip -c src/kernel/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/kernel -Isrc/kernel/lwip -c src/kernel/licensewr.c -o build/licensewr.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/kernel -Isrc/kernel/lwip -c src/kernel/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/kernel -Isrc/kernel/lwip -c src/kernel/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/kernel -Isrc/kernel/lwip -c src/kernel/memory_manager.c -o build/memory_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/kernel -Isrc/kernel/lwip -c src/kernel/nanojpeg.c -o build/nanojpeg.o
|
||||
src/kernel/nanojpeg.c: In function 'njGetVLC':
|
||||
src/kernel/nanojpeg.c:686:24: warning: left shift of negative value [-Wshift-negative-value]
|
||||
686 | value += ((-1) << bits) + 1;
|
||||
| ^~
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/network.c -o build/network.o
|
||||
src/kernel/network.c: In function 'network_dhcp_acquire':
|
||||
src/kernel/network.c:181:9: warning: unused variable 'loops' [-Wunused-variable]
|
||||
181 | int loops = 0;
|
||||
| ^~~~~
|
||||
src/kernel/network.c: In function 'network_init':
|
||||
src/kernel/network.c:97:9: warning: 'ip.bytes[0]' may be used uninitialized [-Wmaybe-uninitialized]
|
||||
97 | k_itoa(ip.bytes[0], buf); serial_write(buf); serial_write(".");
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~
|
||||
src/kernel/network.c:92:24: note: 'ip.bytes[0]' was declared here
|
||||
92 | ipv4_address_t ip;
|
||||
| ^~
|
||||
src/kernel/network.c:98:9: warning: 'ip.bytes[1]' may be used uninitialized [-Wmaybe-uninitialized]
|
||||
98 | k_itoa(ip.bytes[1], buf); serial_write(buf); serial_write(".");
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~
|
||||
src/kernel/network.c:92:24: note: 'ip.bytes[1]' was declared here
|
||||
92 | ipv4_address_t ip;
|
||||
| ^~
|
||||
src/kernel/network.c:99:9: warning: 'ip.bytes[2]' may be used uninitialized [-Wmaybe-uninitialized]
|
||||
99 | k_itoa(ip.bytes[2], buf); serial_write(buf); serial_write(".");
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~
|
||||
src/kernel/network.c:92:24: note: 'ip.bytes[2]' was declared here
|
||||
92 | ipv4_address_t ip;
|
||||
| ^~
|
||||
src/kernel/network.c:100:9: warning: 'ip.bytes[3]' may be used uninitialized [-Wmaybe-uninitialized]
|
||||
100 | k_itoa(ip.bytes[3], buf); serial_write(buf); serial_write("\n");
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~
|
||||
src/kernel/network.c:92:24: note: 'ip.bytes[3]' was declared here
|
||||
92 | ipv4_address_t ip;
|
||||
| ^~
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/nj_kernel.c -o build/nj_kernel.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/kernel -Isrc/kernel/lwip -c src/kernel/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/kernel -Isrc/kernel/lwip -c src/kernel/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/kernel -Isrc/kernel/lwip -c src/kernel/pci.c -o build/pci.o
|
||||
src/kernel/pci.c: In function 'pci_enumerate_devices':
|
||||
src/kernel/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/kernel -Isrc/kernel/lwip -c src/kernel/platform.c -o build/platform.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/kernel -Isrc/kernel/lwip -c src/kernel/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/kernel -Isrc/kernel/lwip -c src/kernel/ps2.c -o build/ps2.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/kernel -Isrc/kernel/lwip -c src/kernel/rtc.c -o build/rtc.o
|
||||
src/kernel/rtc.c: In function 'rtc_get_datetime':
|
||||
src/kernel/rtc.c:28:13: warning: unused variable 'last_century' [-Wunused-variable]
|
||||
28 | uint8_t last_century;
|
||||
| ^~~~~~~~~~~~
|
||||
src/kernel/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/kernel -Isrc/kernel/lwip -c src/kernel/syscall.c -o build/syscall.o
|
||||
src/kernel/syscall.c: In function 'syscall_handler_inner':
|
||||
src/kernel/syscall.c:399:28: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
|
||||
399 | float scale = *(float*)&scale_bits;
|
||||
| ^~~~~~~~~~~~~~~~~~~
|
||||
src/kernel/syscall.c:509:28: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
|
||||
509 | float scale = *(float*)&scale_bits;
|
||||
| ^~~~~~~~~~~~~~~~~~~
|
||||
src/kernel/syscall.c:528:28: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
|
||||
528 | float scale = *(float*)&scale_bits;
|
||||
| ^~~~~~~~~~~~~~~~~~~
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/vm.c -o build/vm.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/kernel -Isrc/kernel/lwip -c src/kernel/wallpaper.c -o build/wallpaper.o
|
||||
src/kernel/wallpaper.c:83:13: warning: 'serial_num' defined but not used [-Wunused-function]
|
||||
83 | static void serial_num(int n) {
|
||||
| ^~~~~~~~~~
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/wm.c -o build/wm.o
|
||||
src/kernel/wm.c: In function 'wm_handle_click':
|
||||
src/kernel/wm.c:1570:29: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
|
||||
1570 | if (col < 0) col = 0; if (row < 0) row = 0;
|
||||
| ^~
|
||||
src/kernel/wm.c:1570:51: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
|
||||
1570 | if (col < 0) col = 0; if (row < 0) row = 0;
|
||||
| ^~
|
||||
src/kernel/wm.c: In function 'wm_handle_mouse':
|
||||
src/kernel/wm.c:2214:41: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
|
||||
2214 | if (col < 0) col = 0; if (row < 0) row = 0;
|
||||
| ^~
|
||||
src/kernel/wm.c:2214:63: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
|
||||
2214 | if (col < 0) col = 0; if (row < 0) row = 0;
|
||||
| ^~
|
||||
src/kernel/wm.c: At top level:
|
||||
src/kernel/wm.c:1124:13: warning: 'erase_cursor' defined but not used [-Wunused-function]
|
||||
1124 | static void erase_cursor(int x, int y) {
|
||||
| ^~~~~~~~~~~~
|
||||
src/kernel/wm.c:1014:13: warning: 'draw_dock_editor' defined but not used [-Wunused-function]
|
||||
1014 | static void draw_dock_editor(int x, int y) {
|
||||
| ^~~~~~~~~~~~~~~~
|
||||
src/kernel/wm.c:87:13: warning: 'cursor_visible' defined but not used [-Wunused-variable]
|
||||
87 | static bool cursor_visible = true;
|
||||
| ^~~~~~~~~~~~~~
|
||||
src/kernel/wm.c:84:12: warning: 'desktop_refresh_timer' defined but not used [-Wunused-variable]
|
||||
84 | static int desktop_refresh_timer = 0;
|
||||
| ^~~~~~~~~~~~~~~~~~~~~
|
||||
mkdir -p build/lwip/core/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/altcp.c -o build/lwip/core/altcp.o
|
||||
mkdir -p build/lwip/core/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/altcp_alloc.c -o build/lwip/core/altcp_alloc.o
|
||||
mkdir -p build/lwip/core/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/altcp_tcp.c -o build/lwip/core/altcp_tcp.o
|
||||
mkdir -p build/lwip/core/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/def.c -o build/lwip/core/def.o
|
||||
mkdir -p build/lwip/core/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/dns.c -o build/lwip/core/dns.o
|
||||
mkdir -p build/lwip/core/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/inet_chksum.c -o build/lwip/core/inet_chksum.o
|
||||
mkdir -p build/lwip/core/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/init.c -o build/lwip/core/init.o
|
||||
mkdir -p build/lwip/core/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/ip.c -o build/lwip/core/ip.o
|
||||
mkdir -p build/lwip/core/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/mem.c -o build/lwip/core/mem.o
|
||||
mkdir -p build/lwip/core/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/memp.c -o build/lwip/core/memp.o
|
||||
mkdir -p build/lwip/core/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/netif.c -o build/lwip/core/netif.o
|
||||
mkdir -p build/lwip/core/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/pbuf.c -o build/lwip/core/pbuf.o
|
||||
mkdir -p build/lwip/core/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/raw.c -o build/lwip/core/raw.o
|
||||
mkdir -p build/lwip/core/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/stats.c -o build/lwip/core/stats.o
|
||||
mkdir -p build/lwip/core/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/sys.c -o build/lwip/core/sys.o
|
||||
mkdir -p build/lwip/core/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/tcp.c -o build/lwip/core/tcp.o
|
||||
mkdir -p build/lwip/core/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/tcp_in.c -o build/lwip/core/tcp_in.o
|
||||
mkdir -p build/lwip/core/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/tcp_out.c -o build/lwip/core/tcp_out.o
|
||||
mkdir -p build/lwip/core/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/timeouts.c -o build/lwip/core/timeouts.o
|
||||
mkdir -p build/lwip/core/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/udp.c -o build/lwip/core/udp.o
|
||||
mkdir -p build/lwip/core/ipv4/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/ipv4/autoip.c -o build/lwip/core/ipv4/autoip.o
|
||||
mkdir -p build/lwip/core/ipv4/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/ipv4/dhcp.c -o build/lwip/core/ipv4/dhcp.o
|
||||
mkdir -p build/lwip/core/ipv4/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/ipv4/etharp.c -o build/lwip/core/ipv4/etharp.o
|
||||
mkdir -p build/lwip/core/ipv4/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/ipv4/icmp.c -o build/lwip/core/ipv4/icmp.o
|
||||
mkdir -p build/lwip/core/ipv4/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/ipv4/igmp.c -o build/lwip/core/ipv4/igmp.o
|
||||
mkdir -p build/lwip/core/ipv4/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/ipv4/ip4.c -o build/lwip/core/ipv4/ip4.o
|
||||
mkdir -p build/lwip/core/ipv4/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/ipv4/ip4_addr.c -o build/lwip/core/ipv4/ip4_addr.o
|
||||
mkdir -p build/lwip/core/ipv4/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/core/ipv4/ip4_frag.c -o build/lwip/core/ipv4/ip4_frag.o
|
||||
mkdir -p build/lwip/netif/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/netif/ethernet.c -o build/lwip/netif/ethernet.o
|
||||
mkdir -p build/lwip/netif/
|
||||
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/kernel -Isrc/kernel/lwip -c src/kernel/lwip/netif/bridgeif.c -o build/lwip/netif/bridgeif.o
|
||||
nasm -f elf64 src/kernel/boot.asm -o build/boot.o
|
||||
nasm -f elf64 src/kernel/gdt_asm.asm -o build/gdt_asm.o
|
||||
nasm -f elf64 src/kernel/interrupts.asm -o build/interrupts.o
|
||||
nasm -f elf64 src/kernel/process_asm.asm -o build/process_asm.o
|
||||
nasm -f elf64 src/kernel/syscalls.asm -o build/syscalls.o
|
||||
nasm -f elf64 src/kernel/test_syscall.asm -o build/test_syscall.o
|
||||
nasm -f elf64 src/kernel/user_test.asm -o build/user_test.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -pie --no-dynamic-linker -z text -z max-page-size=0x1000 -T linker.ld -o build/boredos.elf build/cmd.o build/disk_manager.o build/e1000.o build/e1000_netif.o build/elf.o build/explorer.o build/fat32.o build/font_manager.o build/gdt.o build/graphics.o build/idt.o build/kutils.o build/licensewr.o build/lwip_port.o build/main.o build/memory_manager.o build/nanojpeg.o build/network.o build/nj_kernel.o build/paging.o build/panic.o build/pci.o build/platform.o build/process.o build/ps2.o build/rtc.o build/syscall.o build/vm.o build/wallpaper.o build/wm.o build/lwip/core/altcp.o build/lwip/core/altcp_alloc.o build/lwip/core/altcp_tcp.o build/lwip/core/def.o build/lwip/core/dns.o build/lwip/core/inet_chksum.o build/lwip/core/init.o build/lwip/core/ip.o build/lwip/core/mem.o build/lwip/core/memp.o build/lwip/core/netif.o build/lwip/core/pbuf.o build/lwip/core/raw.o build/lwip/core/stats.o build/lwip/core/sys.o build/lwip/core/tcp.o build/lwip/core/tcp_in.o build/lwip/core/tcp_out.o build/lwip/core/timeouts.o build/lwip/core/udp.o build/lwip/core/ipv4/autoip.o build/lwip/core/ipv4/dhcp.o build/lwip/core/ipv4/etharp.o build/lwip/core/ipv4/icmp.o build/lwip/core/ipv4/igmp.o build/lwip/core/ipv4/ip4.o build/lwip/core/ipv4/ip4_addr.o build/lwip/core/ipv4/ip4_frag.o build/lwip/netif/ethernet.o build/lwip/netif/bridgeif.o build/boot.o build/gdt_asm.o build/interrupts.o build/process_asm.o build/syscalls.o build/test_syscall.o build/user_test.o
|
||||
x86_64-elf-ld: warning: build/boredos.elf has a LOAD segment with RWX permissions
|
||||
/Library/Developer/CommandLineTools/usr/bin/make -C src/kernel/userland
|
||||
mkdir -p bin
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c libc/libui.c -o bin/libui.o
|
||||
libc/libui.c: In function 'ui_draw_string_scaled':
|
||||
libc/libui.c:64:28: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
|
||||
64 | uint32_t scale_bits = *(uint32_t*)&scale;
|
||||
| ^~~~~~~~~~~~~~~~~
|
||||
libc/libui.c: In function 'ui_get_string_width_scaled':
|
||||
libc/libui.c:70:28: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
|
||||
70 | uint32_t scale_bits = *(uint32_t*)&scale;
|
||||
| ^~~~~~~~~~~~~~~~~
|
||||
libc/libui.c: In function 'ui_get_font_height_scaled':
|
||||
libc/libui.c:75:28: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
|
||||
75 | uint32_t scale_bits = *(uint32_t*)&scale;
|
||||
| ^~~~~~~~~~~~~~~~~
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c libc/stdlib.c -o bin/stdlib.o
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c libc/syscall.c -o bin/syscall.o
|
||||
nasm -f elf64 crt0.asm -o bin/crt0.o
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c about.c -o bin/about.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/about.o -o bin/about.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c beep.c -o bin/beep.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/beep.o -o bin/beep.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c browser.c -o bin/browser.o
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c nanojpeg.c -o bin/nanojpeg.o
|
||||
nanojpeg.c: In function 'njGetVLC':
|
||||
nanojpeg.c:685:24: warning: left shift of negative value [-Wshift-negative-value]
|
||||
685 | value += ((-1) << bits) + 1;
|
||||
| ^~
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/browser.o bin/nanojpeg.o -o bin/browser.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c calculator.c -o bin/calculator.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/calculator.o -o bin/calculator.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c cat.c -o bin/cat.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/cat.o -o bin/cat.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c cc.c -o bin/cc.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/cc.o -o bin/cc.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c clear.c -o bin/clear.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/clear.o -o bin/clear.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c clock.c -o bin/clock.o
|
||||
clock.c: In function 'clock_paint':
|
||||
clock.c:89:36: warning: comparison of integer expressions of different signedness: 'tab_t' and 'int' [-Wsign-compare]
|
||||
89 | uint32_t bg = (current_tab == i) ? COLOR_TAB_ACTIVE : COLOR_DARK_PANEL;
|
||||
| ^~
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/clock.o -o bin/clock.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c cowsay.c -o bin/cowsay.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/cowsay.o -o bin/cowsay.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c cp.c -o bin/cp.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/cp.o -o bin/cp.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c crash.c -o bin/crash.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/crash.o -o bin/crash.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c curl.c -o bin/curl.o
|
||||
curl.c: In function 'main':
|
||||
curl.c:60:9: warning: unused variable 'host_len' [-Wunused-variable]
|
||||
60 | int host_len = i;
|
||||
| ^~~~~~~~
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/curl.o -o bin/curl.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c date.c -o bin/date.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/date.o -o bin/date.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c echo.c -o bin/echo.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/echo.o -o bin/echo.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c hello.c -o bin/hello.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/hello.o -o bin/hello.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c help.c -o bin/help.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/help.o -o bin/help.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c ls.c -o bin/ls.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/ls.o -o bin/ls.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c man.c -o bin/man.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/man.o -o bin/man.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c markdown.c -o bin/markdown.o
|
||||
markdown.c:59:12: warning: 'md_strncpy' defined but not used [-Wunused-function]
|
||||
59 | static int md_strncpy(char *dest, const char *src, int n) {
|
||||
| ^~~~~~~~~~
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/markdown.o -o bin/markdown.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c math.c -o bin/math.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/math.o -o bin/math.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c meminfo.c -o bin/meminfo.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/meminfo.o -o bin/meminfo.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c minesweeper.c -o bin/minesweeper.o
|
||||
minesweeper.c: In function 'minesweeper_handle_click':
|
||||
minesweeper.c:195:50: warning: unused parameter 'win' [-Wunused-parameter]
|
||||
195 | static void minesweeper_handle_click(ui_window_t win, int x, int y, int button) {
|
||||
| ~~~~~~~~~~~~^~~
|
||||
minesweeper.c: At top level:
|
||||
minesweeper.c:17:13: warning: 'debug_print' defined but not used [-Wunused-function]
|
||||
17 | static void debug_print(const char *msg) {
|
||||
| ^~~~~~~~~~~
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/minesweeper.o -o bin/minesweeper.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c mkdir.c -o bin/mkdir.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/mkdir.o -o bin/mkdir.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c mv.c -o bin/mv.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/mv.o -o bin/mv.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c net.c -o bin/net.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/net.o -o bin/net.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c notepad.c -o bin/notepad.o
|
||||
notepad.c: In function 'notepad_key':
|
||||
notepad.c:149:37: warning: unused parameter 'win' [-Wunused-parameter]
|
||||
149 | static void notepad_key(ui_window_t win, int h, char c) {
|
||||
| ~~~~~~~~~~~~^~~
|
||||
notepad.c: In function 'main':
|
||||
notepad.c:234:14: warning: unused parameter 'argc' [-Wunused-parameter]
|
||||
234 | int main(int argc, char **argv) {
|
||||
| ~~~~^~~~
|
||||
notepad.c:234:27: warning: unused parameter 'argv' [-Wunused-parameter]
|
||||
234 | int main(int argc, char **argv) {
|
||||
| ~~~~~~~^~~~
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/notepad.o -o bin/notepad.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c paint.c -o bin/paint.o
|
||||
paint.c: In function 'wm_show_message':
|
||||
paint.c:156:41: warning: unused parameter 'title' [-Wunused-parameter]
|
||||
156 | static void wm_show_message(const char *title, const char *msg) {
|
||||
| ~~~~~~~~~~~~^~~~~
|
||||
paint.c:156:60: warning: unused parameter 'msg' [-Wunused-parameter]
|
||||
156 | static void wm_show_message(const char *title, const char *msg) {
|
||||
| ~~~~~~~~~~~~^~~
|
||||
paint.c: At top level:
|
||||
paint.c:38:13: warning: 'debug_print' defined but not used [-Wunused-function]
|
||||
38 | static void debug_print(const char *msg) {
|
||||
| ^~~~~~~~~~~
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/paint.o -o bin/paint.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c pci_list.c -o bin/pci_list.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/pci_list.o -o bin/pci_list.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c ping.c -o bin/ping.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/ping.o -o bin/ping.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c pwd.c -o bin/pwd.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/pwd.o -o bin/pwd.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c reboot.c -o bin/reboot.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/reboot.o -o bin/reboot.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c rm.c -o bin/rm.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/rm.o -o bin/rm.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c settings.c -o bin/settings.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/settings.o bin/nanojpeg.o -o bin/settings.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c shutdown.c -o bin/shutdown.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/shutdown.o -o bin/shutdown.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c sweden.c -o bin/sweden.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/sweden.o -o bin/sweden.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c sysfetch.c -o bin/sysfetch.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/sysfetch.o -o bin/sysfetch.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c telnet.c -o bin/telnet.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/telnet.o -o bin/telnet.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c touch.c -o bin/touch.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/touch.o -o bin/touch.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c txtedit.c -o bin/txtedit.o
|
||||
txtedit.c: In function 'editor_paint':
|
||||
txtedit.c:330:10: warning: unused variable 'status_text' [-Wunused-variable]
|
||||
330 | char status_text[128];
|
||||
| ^~~~~~~~~~~
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/txtedit.o -o bin/txtedit.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c uptime.c -o bin/uptime.o
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/uptime.o -o bin/uptime.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -c viewer.c -o bin/viewer.o
|
||||
viewer.c: In function 'viewer_handle_click':
|
||||
viewer.c:104:45: warning: unused parameter 'win' [-Wunused-parameter]
|
||||
104 | static void viewer_handle_click(ui_window_t win, int x, int y) {
|
||||
| ~~~~~~~~~~~~^~~
|
||||
x86_64-elf-ld -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start bin/libui.o bin/stdlib.o bin/syscall.o bin/crt0.o bin/viewer.o bin/nanojpeg.o -o bin/viewer.elf
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -Wno-error -Idoom -c doom/am_map.c -o bin/am_map.o
|
||||
doom/am_map.c: In function 'AM_initVariables':
|
||||
doom/am_map.c:427:5: warning: missing initializer for field 'data4' of 'event_t' [-Wmissing-field-initializers]
|
||||
427 | static event_t st_notify = { ev_keyup, AM_MSGENTERED, 0, 0 };
|
||||
| ^~~~~~
|
||||
In file included from doom/st_stuff.h:25,
|
||||
from doom/am_map.c:27:
|
||||
doom/d_event.h:67:30: note: 'data4' declared here
|
||||
67 | int data1, data2, data3, data4;
|
||||
| ^~~~~
|
||||
doom/am_map.c: In function 'AM_Stop':
|
||||
doom/am_map.c:543:5: warning: missing initializer for field 'data4' of 'event_t' [-Wmissing-field-initializers]
|
||||
543 | static event_t st_notify = { 0, ev_keyup, AM_MSGEXITED, 0 };
|
||||
| ^~~~~~
|
||||
doom/d_event.h:67:30: note: 'data4' declared here
|
||||
67 | int data1, data2, data3, data4;
|
||||
| ^~~~~
|
||||
doom/am_map.c: In function 'AM_drawThings':
|
||||
doom/am_map.c:1293:9: warning: unused parameter 'colorrange' [-Wunused-parameter]
|
||||
1293 | int colorrange)
|
||||
| ~~~~~~^~~~~~~~~~
|
||||
x86_64-elf-gcc -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc -Wno-error -Idoom -c doom/boredos_libc.c -o bin/boredos_libc.o
|
||||
doom/boredos_libc.c:6:27: error: 'false' undeclared here (not in a function)
|
||||
6 | static FILE _stderr = {2, false, false};
|
||||
| ^~~~~
|
||||
doom/boredos_libc.c:3:1: note: 'false' is defined in header '<stdbool.h>'; this is probably fixable by adding '#include <stdbool.h>'
|
||||
2 | #include <syscall.h>
|
||||
+++ |+#include <stdbool.h>
|
||||
3 |
|
||||
doom/boredos_libc.c:6:1: warning: missing initializer for field 'eof' of 'FILE' [-Wmissing-field-initializers]
|
||||
6 | static FILE _stderr = {2, false, false};
|
||||
| ^~~~~~
|
||||
In file included from doom/boredos_libc.c:1:
|
||||
doom/boredos_libc.h:17:9: note: 'eof' declared here
|
||||
17 | int eof;
|
||||
| ^~~
|
||||
doom/boredos_libc.c:7:1: warning: missing initializer for field 'eof' of 'FILE' [-Wmissing-field-initializers]
|
||||
7 | static FILE _stdout = {1, false, false};
|
||||
| ^~~~~~
|
||||
doom/boredos_libc.h:17:9: note: 'eof' declared here
|
||||
17 | int eof;
|
||||
| ^~~
|
||||
doom/boredos_libc.c: In function 'fread':
|
||||
doom/boredos_libc.c:37:25: error: 'true' undeclared (first use in this function)
|
||||
37 | stream->error = true;
|
||||
| ^~~~
|
||||
doom/boredos_libc.c:37:25: note: 'true' is defined in header '<stdbool.h>'; this is probably fixable by adding '#include <stdbool.h>'
|
||||
doom/boredos_libc.c:37:25: note: each undeclared identifier is reported only once for each function it appears in
|
||||
doom/boredos_libc.c: In function 'fwrite':
|
||||
doom/boredos_libc.c:52:25: error: 'true' undeclared (first use in this function)
|
||||
52 | stream->error = true;
|
||||
| ^~~~
|
||||
doom/boredos_libc.c:52:25: note: 'true' is defined in header '<stdbool.h>'; this is probably fixable by adding '#include <stdbool.h>'
|
||||
doom/boredos_libc.c: In function 'rename':
|
||||
doom/boredos_libc.c:73:24: warning: unused parameter 'oldpath' [-Wunused-parameter]
|
||||
73 | int rename(const char *oldpath, const char *newpath) {
|
||||
| ~~~~~~~~~~~~^~~~~~~
|
||||
doom/boredos_libc.c:73:45: warning: unused parameter 'newpath' [-Wunused-parameter]
|
||||
73 | int rename(const char *oldpath, const char *newpath) {
|
||||
| ~~~~~~~~~~~~^~~~~~~
|
||||
doom/boredos_libc.c: In function 'mkdir':
|
||||
doom/boredos_libc.c:94:37: warning: unused parameter 'mode' [-Wunused-parameter]
|
||||
94 | int mkdir(const char *pathname, int mode) {
|
||||
| ~~~~^~~~
|
||||
doom/boredos_libc.c: In function 'access':
|
||||
doom/boredos_libc.c:98:38: warning: unused parameter 'mode' [-Wunused-parameter]
|
||||
98 | int access(const char *pathname, int mode) {
|
||||
| ~~~~^~~~
|
||||
doom/boredos_libc.c: In function 'fprintf':
|
||||
doom/boredos_libc.c:179:19: warning: unused parameter 'stream' [-Wunused-parameter]
|
||||
179 | int fprintf(FILE *stream, const char *format, ...) { return 0; }
|
||||
| ~~~~~~^~~~~~
|
||||
doom/boredos_libc.c:179:39: warning: unused parameter 'format' [-Wunused-parameter]
|
||||
179 | int fprintf(FILE *stream, const char *format, ...) { return 0; }
|
||||
| ~~~~~~~~~~~~^~~~~~
|
||||
doom/boredos_libc.c: In function 'sprintf':
|
||||
doom/boredos_libc.c:180:19: warning: unused parameter 'str' [-Wunused-parameter]
|
||||
180 | int sprintf(char *str, const char *format, ...) { return 0; }
|
||||
| ~~~~~~^~~
|
||||
doom/boredos_libc.c:180:36: warning: unused parameter 'format' [-Wunused-parameter]
|
||||
180 | int sprintf(char *str, const char *format, ...) { return 0; }
|
||||
| ~~~~~~~~~~~~^~~~~~
|
||||
doom/boredos_libc.c: In function 'snprintf':
|
||||
doom/boredos_libc.c:181:20: warning: unused parameter 'str' [-Wunused-parameter]
|
||||
181 | int snprintf(char *str, size_t size, const char *format, ...) { return 0; }
|
||||
| ~~~~~~^~~
|
||||
doom/boredos_libc.c:181:32: warning: unused parameter 'size' [-Wunused-parameter]
|
||||
181 | int snprintf(char *str, size_t size, const char *format, ...) { return 0; }
|
||||
| ~~~~~~~^~~~
|
||||
doom/boredos_libc.c:181:50: warning: unused parameter 'format' [-Wunused-parameter]
|
||||
181 | int snprintf(char *str, size_t size, const char *format, ...) { return 0; }
|
||||
| ~~~~~~~~~~~~^~~~~~
|
||||
doom/boredos_libc.c: In function 'vsnprintf':
|
||||
doom/boredos_libc.c:182:21: warning: unused parameter 'str' [-Wunused-parameter]
|
||||
182 | int vsnprintf(char *str, size_t size, const char *format, va_list ap) { return 0; }
|
||||
| ~~~~~~^~~
|
||||
doom/boredos_libc.c:182:33: warning: unused parameter 'size' [-Wunused-parameter]
|
||||
182 | int vsnprintf(char *str, size_t size, const char *format, va_list ap) { return 0; }
|
||||
| ~~~~~~~^~~~
|
||||
doom/boredos_libc.c:182:51: warning: unused parameter 'format' [-Wunused-parameter]
|
||||
182 | int vsnprintf(char *str, size_t size, const char *format, va_list ap) { return 0; }
|
||||
| ~~~~~~~~~~~~^~~~~~
|
||||
doom/boredos_libc.c:182:67: warning: unused parameter 'ap' [-Wunused-parameter]
|
||||
182 | int vsnprintf(char *str, size_t size, const char *format, va_list ap) { return 0; }
|
||||
| ~~~~~~~~^~
|
||||
doom/boredos_libc.c: In function 'sscanf':
|
||||
doom/boredos_libc.c:183:24: warning: unused parameter 'str' [-Wunused-parameter]
|
||||
183 | int sscanf(const char *str, const char *format, ...) { return 0; }
|
||||
| ~~~~~~~~~~~~^~~
|
||||
doom/boredos_libc.c:183:41: warning: unused parameter 'format' [-Wunused-parameter]
|
||||
183 | int sscanf(const char *str, const char *format, ...) { return 0; }
|
||||
| ~~~~~~~~~~~~^~~~~~
|
||||
make[1]: *** [bin/boredos_libc.o] Error 1
|
||||
rm bin/pwd.o bin/minesweeper.o bin/ls.o bin/echo.o bin/pci_list.o bin/date.o bin/mkdir.o bin/help.o bin/markdown.o bin/cc.o bin/sweden.o bin/rm.o bin/notepad.o bin/man.o bin/clock.o bin/clear.o bin/cat.o bin/cp.o bin/paint.o bin/crash.o bin/reboot.o bin/beep.o bin/meminfo.o bin/net.o bin/calculator.o bin/cowsay.o bin/telnet.o bin/hello.o bin/math.o bin/curl.o bin/uptime.o bin/about.o bin/sysfetch.o bin/ping.o bin/mv.o bin/txtedit.o bin/touch.o bin/shutdown.o
|
||||
make: *** [build/boredos.elf] Error 2
|
||||
BIN
build/cmd.o
BIN
build/cmd.o
Binary file not shown.
Binary file not shown.
BIN
build/e1000.o
BIN
build/e1000.o
Binary file not shown.
BIN
build/explorer.o
BIN
build/explorer.o
Binary file not shown.
BIN
build/fat32.o
BIN
build/fat32.o
Binary file not shown.
BIN
build/graphics.o
BIN
build/graphics.o
Binary file not shown.
BIN
build/idt.o
BIN
build/idt.o
Binary file not shown.
BIN
build/main.o
BIN
build/main.o
Binary file not shown.
Binary file not shown.
BIN
build/pci.o
BIN
build/pci.o
Binary file not shown.
BIN
build/platform.o
BIN
build/platform.o
Binary file not shown.
BIN
build/ps2.o
BIN
build/ps2.o
Binary file not shown.
BIN
build/rtc.o
BIN
build/rtc.o
Binary file not shown.
70
docs/README.md
Normal file
70
docs/README.md
Normal file
@@ -0,0 +1,70 @@
|
||||
<div align="center">
|
||||
<h1>BoredOS Documentation</h1>
|
||||
<p><em>Internal guides, architecture, and application development.</em></p>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
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
|
||||
|
||||
The documentation is organized into three main categories:
|
||||
|
||||
### 1. [Architecture](architecture/)
|
||||
Explains the logical layout of the kernel and internal components.
|
||||
|
||||
#### 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/)
|
||||
The SDK and toolchain guides for creating your own `.elf` userland binaries.
|
||||
- [`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.
|
||||
|
||||
---
|
||||
90
docs/appdev/custom_apps.md
Normal file
90
docs/appdev/custom_apps.md
Normal file
@@ -0,0 +1,90 @@
|
||||
<div align="center">
|
||||
<h1>Creating a Custom App</h1>
|
||||
<p><em>A step-by-step tutorial on writing a new graphical C application.</em></p>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
This guide explains how to write a new "Hello World" application locally, compile it as an `.elf` binary into the `bin/` folder, and launch it inside BoredOS.
|
||||
|
||||
> [!TIP]
|
||||
> **Looking for working code?** Check out the [Examples Directory](examples/README.md) for full source code demonstrating basic CLI, Windows, Animations, and TCP Networking.
|
||||
|
||||
## Step 1: Write the C Source
|
||||
|
||||
Applications reside entirely in the `src/userland/` directory. Create a new file, for example, `src/userland/gui/hello.c`.
|
||||
|
||||
> [!TIP]
|
||||
> Group CLI apps into `src/userland/cli/` and windowed apps into `src/userland/gui/` for organization.
|
||||
|
||||
```c
|
||||
// src/userland/gui/hello.c
|
||||
#include <stdlib.h>
|
||||
#include <libui.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(void) {
|
||||
// Attempt to open a 300x200 window
|
||||
ui_window_t wid = ui_window_create("My Custom App", 100, 100, 300, 200);
|
||||
if (wid < 0) {
|
||||
printf("Error creating window!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Write text in center
|
||||
ui_draw_string(wid, 50, 90, "Hello, BoredOS!!", 0xFFFFFFFF);
|
||||
|
||||
// Commit drawing to screen
|
||||
ui_mark_dirty(wid, 0, 0, 300, 200);
|
||||
|
||||
gui_event_t event;
|
||||
while (1) {
|
||||
if (ui_get_event(wid, &event)) {
|
||||
if (event.type == GUI_EVENT_CLOSE) {
|
||||
break; // Exit loop if 'X' is clicked
|
||||
}
|
||||
}
|
||||
|
||||
sys_yield();
|
||||
}
|
||||
|
||||
return 0; // Returning 0 smoothly exits the process via crt0.asm
|
||||
}
|
||||
```
|
||||
|
||||
## Step 2: Edit the Makefile
|
||||
|
||||
Now you need to tell the build system to compile `hello.c`. Fortunately, the `src/userland/Makefile` is designed to detect new C files largely automatically!
|
||||
|
||||
1. Open `src/userland/Makefile`.
|
||||
2. Find the line specifying `APP_SOURCES_FULL`:
|
||||
```make
|
||||
APP_SOURCES_FULL = $(wildcard cli/*.c gui/*.c sys/*.c games/*.c *.c)
|
||||
```
|
||||
Since you placed the file in `gui/hello.c`, the wildcard logic will pick it up automatically.
|
||||
3. The Makefile will generate `bin/hello.elf` during the build phase.
|
||||
|
||||
## Step 3: Bundle it into the OS
|
||||
|
||||
The main overarching `Makefile` (in the project root) takes binaries from `src/userland/bin/*.elf` and places them into the `iso_root/bin/` directory, while also adding them to `limine.conf` as loadable boot modules.
|
||||
|
||||
1. Go back to the root of the OS:
|
||||
```sh
|
||||
cd ../..
|
||||
```
|
||||
2. Compile the entire project to build the ISO and test in QEMU:
|
||||
```sh
|
||||
make clean && make run
|
||||
```
|
||||
|
||||
## Step 4: Run it inside BoredOS
|
||||
|
||||
1. When BoredOS boots, launch the **Terminal** application.
|
||||
2. The OS automatically maps built applications to standard shell commands. Simply type your application's filename (without the `.elf` extension).
|
||||
3. Type `hello` in the terminal and press Enter.
|
||||
4. Your custom window will appear!
|
||||
|
||||
> [!NOTE]
|
||||
> You can also open your app by opening the file explorer, navigating to the `bin` directory, and double-clicking the executable.
|
||||
|
||||
---
|
||||
307
docs/appdev/elf_metadata.md
Normal file
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.*
|
||||
55
docs/appdev/examples/01_hello_cli.md
Normal file
55
docs/appdev/examples/01_hello_cli.md
Normal file
@@ -0,0 +1,55 @@
|
||||
<div align="center">
|
||||
<h1>Example 01: Hello CLI</h1>
|
||||
<p><em>The absolute basics. Writing a terminal program.</em></p>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
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
|
||||
* 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`)
|
||||
|
||||
```c
|
||||
// BOREDOS_APP_DESC: Hello World — a minimal CLI demo.
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Standard library initialization is handled automatically by crt0.asm
|
||||
|
||||
// Print a simple string to the terminal
|
||||
printf("Hello, World from BoredOS Userland!\n");
|
||||
|
||||
// Print some formatted data
|
||||
int favorite_number = 67;
|
||||
printf("Did you know my favorite number is %d?\n", favorite_number);
|
||||
|
||||
// Returning from main automatically terminates the process cleanly
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
If you build the project, you can open the Terminal and type:
|
||||
```sh
|
||||
/ # hello_world
|
||||
Hello, World from BoredOS Userland!
|
||||
Did you know my favorite number is 67?
|
||||
/ #
|
||||
```
|
||||
74
docs/appdev/examples/02_basic_window.md
Normal file
74
docs/appdev/examples/02_basic_window.md
Normal file
@@ -0,0 +1,74 @@
|
||||
<div align="center">
|
||||
<h1>Example 02: Basic Window</h1>
|
||||
<p><em>An introduction to libui and creating graphical apps.</em></p>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
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
|
||||
* 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`)
|
||||
|
||||
```c
|
||||
// BOREDOS_APP_DESC: Basic Window — a minimal graphical window demo.
|
||||
#include <stdlib.h>
|
||||
#include <libui.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(void) {
|
||||
// 1. Ask the Window Manager to create a new window
|
||||
// Arguments are: Title, X Position, Y Position, Width, Height
|
||||
ui_window_t wid = ui_window_create("My First GUI", 100, 100, 400, 300);
|
||||
|
||||
if (wid < 0) {
|
||||
printf("Failed to create the window!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 2. Define our event object
|
||||
gui_event_t event;
|
||||
|
||||
// 3. Enter the main event loop
|
||||
while (1) {
|
||||
// ui_get_event is non-blocking. It returns true if an event was waiting.
|
||||
if (ui_get_event(wid, &event)) {
|
||||
|
||||
// Check what type of event occurred
|
||||
if (event.type == GUI_EVENT_CLOSE) {
|
||||
// The user clicked the 'X' button in the titlebar!
|
||||
printf("Window closed cleanly by user.\n");
|
||||
break; // Break the infinite loop
|
||||
}
|
||||
}
|
||||
|
||||
// 4. CRITICAL: Yield the remainder of our timeslice
|
||||
// If we don't do this, the while(1) loop will consume 100% of the CPU
|
||||
// and starve the rest of the OS!
|
||||
sys_yield();
|
||||
}
|
||||
|
||||
// Returning from main will automatically destroy the window and exit the process.
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## 🛠️ How it Works
|
||||
|
||||
1. **Window Handle (`wid`)**: `ui_window_create` sends a request to the kernel. The kernel allocates the memory for the window and returns a numerical ID (the handle) that we use for all future interactions with that specific window.
|
||||
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
|
||||
|
||||
Launch the Terminal and type `basic_window`. You'll see an empty window appear that you can move around the screen!
|
||||
96
docs/appdev/examples/03_bouncing_ball.md
Normal file
96
docs/appdev/examples/03_bouncing_ball.md
Normal file
@@ -0,0 +1,96 @@
|
||||
<div align="center">
|
||||
<h1>Example 03: Bouncing Ball</h1>
|
||||
<p><em>Animating graphics and managing application state.</em></p>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
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
|
||||
* 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`)
|
||||
|
||||
```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>
|
||||
|
||||
// Window Dimensions
|
||||
#define W_WIDTH 400
|
||||
#define W_HEIGHT 300
|
||||
// Square Dimensions
|
||||
#define SQ_SIZE 30
|
||||
|
||||
int main(void) {
|
||||
ui_window_t wid = ui_window_create("Bouncing Box Animation", 50, 50, W_WIDTH, W_HEIGHT);
|
||||
if (wid < 0) return 1;
|
||||
|
||||
// Define object state variables
|
||||
int pos_x = 50;
|
||||
int pos_y = 50;
|
||||
int vel_x = 2; // Move 2 pixels per frame horizontally
|
||||
int vel_y = 2; // Move 2 pixels per frame vertically
|
||||
|
||||
gui_event_t event;
|
||||
while (1) {
|
||||
// 1. Process Events
|
||||
while (ui_get_event(wid, &event)) {
|
||||
if (event.type == GUI_EVENT_CLOSE) {
|
||||
return 0; // Exit cleanly
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Physics & Logic Update
|
||||
pos_x += vel_x;
|
||||
pos_y += vel_y;
|
||||
|
||||
// Collision logic (Bounce off edges)
|
||||
// The window has a 20px title bar, so the usable client height is W_HEIGHT - 20.
|
||||
if (pos_x <= 0 || pos_x + SQ_SIZE >= W_WIDTH) {
|
||||
vel_x = -vel_x; // Reverse horizontal direction
|
||||
}
|
||||
if (pos_y <= 0 || pos_y + SQ_SIZE >= W_HEIGHT - 20) {
|
||||
vel_y = -vel_y; // Reverse vertical direction
|
||||
}
|
||||
|
||||
// 3. Rendering Update
|
||||
// Step A: Clear the entire background to Black (0xFF000000)
|
||||
ui_draw_rect(wid, 0, 0, W_WIDTH, W_HEIGHT, 0xFF000000);
|
||||
|
||||
// Step B: Draw our shape in Red (0xFFFF0000) at the new position
|
||||
ui_draw_rect(wid, pos_x, pos_y, SQ_SIZE, SQ_SIZE, 0xFFFF0000);
|
||||
|
||||
// Step C: Draw some UI text over the animation in White
|
||||
ui_draw_string(wid, 10, 10, "BoredOS Animation Demo!", 0xFFFFFFFF);
|
||||
|
||||
// Step D: Instruct the compositor to flush our drawing buffer to the physical screen
|
||||
ui_mark_dirty(wid, 0, 0, W_WIDTH, W_HEIGHT);
|
||||
|
||||
// 4. Yield and throttle
|
||||
sys_yield();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## 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.
|
||||
96
docs/appdev/examples/04_tcp_client.md
Normal file
96
docs/appdev/examples/04_tcp_client.md
Normal file
@@ -0,0 +1,96 @@
|
||||
<div align="center">
|
||||
<h1>Example 04: TCP HTTP Client</h1>
|
||||
<p><em>Utilizing lwIP to establish an outbound TCP connection.</em></p>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
This advanced example demonstrates the steps required to use the raw network system calls to establish a connection with an external HTTP server and dump the response over the terminal.
|
||||
|
||||
## 📝 Concepts Introduced
|
||||
* Verifying the network state (`sys_network_is_initialized`, `sys_network_has_ip`).
|
||||
* 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`)
|
||||
|
||||
```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>
|
||||
|
||||
int main(void) {
|
||||
if (!sys_network_is_initialized() || !sys_network_has_ip()) {
|
||||
printf("Network is unreachable! Make sure you inited the network first!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 1. Resolve host name to IP
|
||||
const char *target_host = "boreddev.nl";
|
||||
net_ipv4_address_t server_ip;
|
||||
|
||||
printf("Resolving %s...\n", target_host);
|
||||
if (sys_dns_lookup(target_host, &server_ip) < 0) {
|
||||
printf("DNS Lookup failed.\n");
|
||||
return 1;
|
||||
}
|
||||
printf("Resolved to: %d.%d.%d.%d\n", server_ip.bytes[0], server_ip.bytes[1],
|
||||
server_ip.bytes[2], server_ip.bytes[3]);
|
||||
|
||||
// 2. Establish a TCP connection on port 80 (HTTP)
|
||||
printf("Connecting...\n");
|
||||
if (sys_tcp_connect(&server_ip, 80) < 0) {
|
||||
printf("Connection failed.\n");
|
||||
return 1;
|
||||
}
|
||||
printf("Connected! Sending GET request...\n");
|
||||
|
||||
// 3. Format and send the raw HTTP Request
|
||||
char request[256];
|
||||
strcpy(request, "GET / HTTP/1.1\r\nHost: ");
|
||||
strcat(request, target_host);
|
||||
strcat(request, "\r\nConnection: close\r\n\r\n");
|
||||
|
||||
if (sys_tcp_send(request, strlen(request)) < 0) {
|
||||
printf("Failed to send data.\n");
|
||||
sys_tcp_close();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 4. Block and wait for response data
|
||||
char recv_buf[512];
|
||||
int bytes_received;
|
||||
|
||||
printf("\n--- RESPONSE ---\n");
|
||||
while ((bytes_received = sys_tcp_recv(recv_buf, sizeof(recv_buf) - 1)) > 0) {
|
||||
recv_buf[bytes_received] = '\0'; // Null-terminate the chunk
|
||||
printf("%s", recv_buf); // Print the chunk to stdout
|
||||
}
|
||||
|
||||
// 5. Cleanup
|
||||
printf("\n--- END RESPONSE ---\n");
|
||||
sys_tcp_close();
|
||||
printf("Connection closed.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
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!
|
||||
28
docs/appdev/examples/README.md
Normal file
28
docs/appdev/examples/README.md
Normal file
@@ -0,0 +1,28 @@
|
||||
<div align="center">
|
||||
<h1>Example Applications</h1>
|
||||
<p><em>From basic output to complex Graphical and Network applications.</em></p>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
Welcome to the examples directory! These guides are designed to help you understand how to write C applications for the BoredOS userland, utilizing the custom `libc` SDK.
|
||||
|
||||
The examples are listed in order of increasing complexity. Click on a tutorial to view the complete source code and an explanation of the concepts it introduces.
|
||||
|
||||
## 🟢 Beginner
|
||||
|
||||
* **[`01_hello_cli.md`](01_hello_cli.md)**: The absolute basics. Learn how to write a simple Terminal program that outputs text and processes standard system calls.
|
||||
* **[`02_basic_window.md`](02_basic_window.md)**: An introduction to `libui.h`. Learn how to create an empty window, set up a basic event loop, and handle the "Close" button cleanly.
|
||||
|
||||
## 🟡 Intermediate
|
||||
|
||||
* **[`03_bouncing_ball.md`](03_bouncing_ball.md)**: Dive deeper into graphical rendering. This example introduces the `ui_mark_dirty` command, framerate independence via `sys_yield()`, and state management to animate a shape moving around the screen and bouncing off the window edges.
|
||||
|
||||
## 🔴 Advanced
|
||||
|
||||
* **[`04_tcp_client.md`](04_tcp_client.md)**: Using the lwIP networking stack. This example demonstrates how to perform a DNS lookup, connect to an external server over TCP (like an HTTP server), send a raw request, and print the response to the terminal.
|
||||
|
||||
---
|
||||
|
||||
> [!TIP]
|
||||
> If you want to test these out, simply create a new `.c` file in `src/userland/cli/` (for terminal apps) or `src/userland/gui/` (for windowed apps), paste the example code, then run `make clean && make run` from the project root!
|
||||
345
docs/appdev/grapher.md
Normal file
345
docs/appdev/grapher.md
Normal file
@@ -0,0 +1,345 @@
|
||||
<div align="center">
|
||||
<h1>Grapher</h1>
|
||||
<p><em>An interactive mathematical expression plotter for BoredOS, supporting both 2D and 3D visualizations.</em></p>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
Grapher is a built-in GUI application that lets you type any mathematical equation and see it plotted in real time. It supports 2D explicit and implicit curves as well as full 3D surface visualization — including both explicit surfaces (`z = f(x, y)`) and implicit surfaces (`f(x, y, z) = c`).
|
||||
|
||||
> [!NOTE]
|
||||
> Grapher is located at `src/userland/gui/grapher.c`. It runs as a standard BoredOS GUI process and can be launched from the terminal or from the dock.
|
||||
|
||||
---
|
||||
|
||||
## Features at a Glance
|
||||
|
||||
| Feature | Details |
|
||||
|---|---|
|
||||
| **2D Explicit** | Plot `y = f(x)` curves |
|
||||
| **2D Implicit** | Plot any `f(x, y) = g(x, y)` contour via marching squares |
|
||||
| **3D Explicit** | Plot `z = f(x, y)` surfaces |
|
||||
| **3D Implicit** | Plot any `f(x, y, z) = c` surface |
|
||||
| **Rendering modes** | Wireframe and filled polygon modes |
|
||||
| **Height coloring** | Surfaces are colored by a blue→green→yellow→red gradient based on Z height |
|
||||
| **Phong-style shading** | Filled mode computes per-face normals and applies diffuse + ambient lighting |
|
||||
| **Parallel rendering** | Evaluation and projection are distributed across 4 worker threads via `sys_parallel_run` |
|
||||
| **Preset equations** | 7 built-in presets accessible from the toolbar |
|
||||
| **Auto-fit** | 2D view auto-fits the Y axis to the plotted curve on first plot |
|
||||
| **Atomic Color-Depth Buffer** | All 3D drawing uses a 64-bit atomic buffer to prevent depth/color race conditions |
|
||||
|
||||
---
|
||||
|
||||
## Launching Grapher
|
||||
|
||||
From the BoredOS terminal:
|
||||
```sh
|
||||
grapher
|
||||
```
|
||||
|
||||
Or click the **Grapher icon** in the system dock.
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
### Toolbar Controls
|
||||
|
||||
| Control | Function |
|
||||
|---|---|
|
||||
| **Equation box** | Type your mathematical expression, then press **Enter** or **Plot** |
|
||||
| **Plot button** | Parse and render the current equation |
|
||||
| **Wire / Filled button** | Toggle wireframe vs. shaded polygon mode (3D only) |
|
||||
| **Presets button** | Open a dropdown of example equations |
|
||||
|
||||
### Status Bar Controls (3D mode)
|
||||
|
||||
| Control | Function |
|
||||
|---|---|
|
||||
| **`+` button** | Increase the 3D world range (zoom out in world space) |
|
||||
| **`-` button** | Decrease the 3D world range (zoom in in world space) |
|
||||
|
||||
---
|
||||
|
||||
## Keyboard Shortcuts
|
||||
|
||||
| Shortcut | Action |
|
||||
|---|---|
|
||||
| **Enter** (in equation box) | Plot the equation |
|
||||
| **Ctrl + R** | Reset the view to defaults |
|
||||
| **F** | Toggle filled / wireframe rendering (3D mode) |
|
||||
| **Scroll wheel** | Zoom in/out (2D mode adjusts viewport; 3D mode adjusts camera zoom) |
|
||||
| **Right-click drag** | Rotate the 3D surface |
|
||||
|
||||
---
|
||||
|
||||
## Writing Equations
|
||||
|
||||
Grapher parses equations entered as plain text. It supports a subset of mathematical notation with automatic implicit multiplication.
|
||||
|
||||
### Supported Functions
|
||||
|
||||
| Syntax | Meaning |
|
||||
|---|---|
|
||||
| `sin(x)` | Sine |
|
||||
| `cos(x)` | Cosine |
|
||||
| `tan(x)` | Tangent |
|
||||
| `sqrt(x)` | Square root |
|
||||
| `abs(x)` | Absolute value |
|
||||
| `log(x)` | Natural logarithm (base *e*) |
|
||||
|
||||
### Supported Operators
|
||||
|
||||
| Operator | Meaning |
|
||||
|---|---|
|
||||
| `+` `-` `*` `/` | Arithmetic |
|
||||
| `^` | Exponentiation (right-associative) |
|
||||
| `(` `)` | Grouping |
|
||||
|
||||
### Special Values
|
||||
|
||||
| Token | Value |
|
||||
|---|---|
|
||||
| `pi` or `PI` | π ≈ 3.14159… |
|
||||
|
||||
### Implicit Multiplication
|
||||
|
||||
Adjacent tokens that would normally require a `*` are multiplied automatically:
|
||||
|
||||
```
|
||||
2x → 2 * x
|
||||
3sin(x) → 3 * sin(x)
|
||||
(x+1)(x) → (x+1) * x
|
||||
```
|
||||
|
||||
### How Equations Are Classified
|
||||
|
||||
Grapher looks at which variables appear in your equation to automatically choose the rendering mode:
|
||||
|
||||
| Equation form | Auto-detected as |
|
||||
|---|---|
|
||||
| `y = f(x)` or just `f(x)` | 2D explicit |
|
||||
| `f(x, y) = g(x, y)` | 2D implicit |
|
||||
| `z = f(x, y)` | 3D explicit |
|
||||
| `f(x, y, z) = c` | 3D implicit |
|
||||
|
||||
If you omit the `=` sign, Grapher treats the input as `y = <expression>` when no `y` or `z` is present, or as `<expression> = 0` otherwise.
|
||||
|
||||
---
|
||||
|
||||
## Example Equations
|
||||
|
||||
### 2D Examples
|
||||
|
||||
```
|
||||
y = sin(x)
|
||||
y = x^2
|
||||
y = cos(x)*x
|
||||
y = abs(x) - 2
|
||||
x^2 + y^2 = 25 ← circle (implicit)
|
||||
y = log(x)
|
||||
```
|
||||
|
||||
### 3D Explicit Examples
|
||||
|
||||
```
|
||||
z = sin(x)*cos(y)
|
||||
z = x^2 - y^2 ← saddle surface
|
||||
z = sqrt(25 - x^2 - y^2)
|
||||
```
|
||||
|
||||
### 3D Implicit Examples
|
||||
|
||||
```
|
||||
x^2 + y^2 + z^2 = 25 ← sphere
|
||||
x^2 + y^2 = 16 ← cylinder
|
||||
x^2 + y^2 - z^2 = 1 ← hyperboloid
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Navigation Controls
|
||||
|
||||
### 2D Mode
|
||||
|
||||
| Input | Action |
|
||||
|---|---|
|
||||
| **Scroll up** | Zoom in |
|
||||
| **Scroll down** | Zoom out |
|
||||
| **Ctrl+R** | Reset to default view (`x: [-10, 10]`) |
|
||||
|
||||
### 3D Mode
|
||||
|
||||
| Input | Action |
|
||||
|---|---|
|
||||
| **Right-click drag** | Rotate the surface (orbit camera) |
|
||||
| **Scroll up** | Zoom camera in |
|
||||
| **Scroll down** | Zoom camera out |
|
||||
| **`+` / `-` buttons** | Increase / decrease world range |
|
||||
| **Ctrl+R** | Reset rotation and zoom |
|
||||
|
||||
> [!TIP]
|
||||
> In 3D mode, the surface auto-rotates slowly by default. This can be disabled by setting `#define ROTATE 0` in the source file.
|
||||
|
||||
---
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
Grapher is implemented as a single self-contained C file. Below is a high-level breakdown of its major components:
|
||||
|
||||
### Math Library
|
||||
|
||||
Grapher uses the BoredOS freestanding **`libc/math.h`** library, which provides all the math functions it needs without depending on a host standard library:
|
||||
|
||||
| Function | Description |
|
||||
|---|---|
|
||||
| `sin`, `cos`, `tan` | Trigonometry via Taylor series (8 terms, range-reduced to `[-π, π]`) |
|
||||
| `sqrt` | Newton-Raphson iteration (25 steps) |
|
||||
| `log` | Natural logarithm via Padé-style series |
|
||||
| `log2`, `log10` | Derived from `log` |
|
||||
| `exp` | Range-reduced Taylor series for `e^x` |
|
||||
| `pow` | Integer exponents use fast binary exponentiation; fractional exponents use `exp(e * log(b))` |
|
||||
| `fabs`, `fmod` | Absolute value and floating-point remainder |
|
||||
| `floor`, `ceil` | Rounding |
|
||||
| `sinh`, `cosh`, `tanh` | Hyperbolic functions |
|
||||
| `hypot`, `fmin`, `fmax`, `fclamp` | Utility helpers |
|
||||
|
||||
The constants `M_PI`, `M_E`, `M_LN2`, `M_SQRT2` are also defined in the header.
|
||||
|
||||
This library is automatically linked into every userland ELF — any app can `#include "math.h"` to use it.
|
||||
|
||||
### Expression Parser
|
||||
|
||||
Equations are parsed in three stages:
|
||||
|
||||
1. **Tokenizer** (`tokenize`) — converts the input string into a flat token array. Handles implicit multiplication by inserting `*` tokens where needed.
|
||||
2. **Recursive Descent Parser** (`parse_expr`, `parse_term`, `parse_power`, `parse_unary`, `parse_atom`) — produces an Abstract Syntax Tree (AST) with up to `MAX_NODES = 128` nodes.
|
||||
3. **Bytecode Compiler** (`compile_ast`) — walks the AST in post-order and emits a flat instruction sequence for a simple stack machine. This avoids recursive evaluation during rendering hot paths.
|
||||
|
||||
The resulting bytecode is then executed by `run_bc` for every sample point.
|
||||
|
||||
### Rendering Pipeline
|
||||
|
||||
#### 2D Rendering
|
||||
|
||||
- **Explicit** — evaluates `y = f(x)` at every pixel column and connects adjacent samples with Bresenham lines.
|
||||
- **Implicit** — applies **marching squares** on a 200×130 grid to find sign changes in `f(x,y) - g(x,y)` and plots intersection pixels.
|
||||
|
||||
#### 3D Rendering
|
||||
|
||||
The 3D pipeline uses a multi-pass system parallelized across worker threads:
|
||||
|
||||
| Pass | Function | Description |
|
||||
|---|---|---|
|
||||
| 1 | **Evaluation** | Samples the surface at grid points. For implicit surfaces, this uses **tri-axis marching**. |
|
||||
| 2 | **Projection** | Projects 3D world coordinates to 2D screen coordinates with perspective. |
|
||||
| 3 | **Drawing** | Rasterizes wireframe lines or filled triangles with Z-buffering. |
|
||||
|
||||
##### Tri-Axis Marching (Implicit Surfaces)
|
||||
|
||||
Unlike explicit surfaces that only need one evaluation per grid point, implicit surfaces require finding roots of $f(x, y, z) = 0$. To ensure complete surface connectivity and eliminate "cracks," Grapher marches along all three primary axes:
|
||||
|
||||
1. **X-Axis Pass**: For every $(y, z)$ pair, march along $x$.
|
||||
2. **Y-Axis Pass**: For every $(x, z)$ pair, march along $y$.
|
||||
3. **Z-Axis Pass**: For every $(x, y)$ pair, march along $z$.
|
||||
|
||||
Each pass uses a multi-stage root finder (170 linear steps followed by 15 bisection iterations). By sampling along all three axes, the engine "catches" surfaces that are nearly parallel to any specific marching direction, ensuring that vertical walls and steep gradients are rendered solidly from any viewing angle.
|
||||
|
||||
##### Atomic Color-Depth Buffer
|
||||
|
||||
To prevent "z-fighting" and race conditions between parallel threads, Grapher uses a 64-bit atomic buffer (`graph_czb`). Each 64-bit word stores:
|
||||
- **Upper 32 bits**: Z-depth (integer).
|
||||
- **Lower 32 bits**: Pixel color (0xAARRGGBB).
|
||||
|
||||
A single `__atomic_compare_exchange_n` operation ensures that a pixel's color and depth are updated together only if the new depth is closer to the camera than the existing one.
|
||||
|
||||
Surface normals are estimated using central finite differences of the implicit function.
|
||||
|
||||
#### Filled Mod
|
||||
|
||||
When filled mode is active, each quad cell is split into two triangles. The average surface normal across the four corner vertices is computed and fed into `apply_shading`, which calculates:
|
||||
|
||||
```
|
||||
intensity = ambient(0.3) + diffuse(0.7) * dot(normal, light_direction)
|
||||
```
|
||||
|
||||
The light direction is fixed at `(0.577, 0.707, 0.408)` (normalized diagonal).
|
||||
|
||||
#### Z-Buffer
|
||||
|
||||
The depth buffer (`graph_zb`) stores integer depth values. `gfb_pixel_z` uses a **compare-and-swap (CAS) loop** via `__atomic_compare_exchange_n` so multiple parallel draw threads cannot produce race conditions.
|
||||
|
||||
### Coordinate Systems
|
||||
|
||||
#### 2D
|
||||
|
||||
World coordinates map linearly to screen pixels:
|
||||
|
||||
```c
|
||||
screen_x = (wx - view_x_min) / (view_x_max - view_x_min) * graph_w
|
||||
screen_y = (view_y_max - wy) / (view_y_max - view_y_min) * graph_h
|
||||
```
|
||||
|
||||
#### 3D
|
||||
|
||||
Points are first rotated by two Euler angles (`rot_y`, `rot_x`) then projected with a simple perspective divide:
|
||||
|
||||
```
|
||||
persp = d / (pz + d) // d = range_3d * 5
|
||||
sx = px * scale * persp + screen_cx
|
||||
sy = -py * scale * persp + screen_cy
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration Constants
|
||||
|
||||
These can be changed at the top of `grapher.c` to tune behaviour:
|
||||
|
||||
| Constant | Default | Effect |
|
||||
|---|---|---|
|
||||
| `ROTATE` | `1` | Set to `0` to disable auto-rotation in 3D mode |
|
||||
| `GRID_3D` | `41` | Grid resolution for 3D sampling. Higher = more detail, much slower |
|
||||
|
||||
> [!WARNING]
|
||||
> Setting `GRID_3D` too high (e.g. 9000) will exhaust available memory. The `surf` grid and `surf_x`/`surf_y_3d` arrays are statically allocated at compile time: memory usage grows as **O(GRID_3D²)**. Values above ~512 are not recommended.
|
||||
|
||||
> [!TIP]
|
||||
> `GRID_3D = 256` gives a good balance of detail and performance on typical BoredOS hardware emulation.
|
||||
|
||||
---
|
||||
|
||||
## Color Palette
|
||||
|
||||
|
||||
3D surfaces are colored by height using a 4-stop rainbow ramp:
|
||||
|
||||
```
|
||||
Low → Blue → Cyan → Green → Yellow → Red → High
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Preset Equations
|
||||
|
||||
The built-in presets are shown in the dropdown when you click **Presets**:
|
||||
|
||||
| Label | Type |
|
||||
|---|---|
|
||||
| `y = sin(x)` | 2D explicit |
|
||||
| `y = x^2` | 2D explicit |
|
||||
| `y = cos(x)*x` | 2D explicit |
|
||||
| `z = sin(x)*cos(y)` | 3D explicit |
|
||||
| `z = x^2 - y^2` | 3D explicit |
|
||||
| `x^2+y^2+z^2=25` | 3D implicit (sphere) |
|
||||
| `x^2+y^2=16` | 3D implicit (cylinder) |
|
||||
|
||||
---
|
||||
|
||||
## Known Limitations
|
||||
|
||||
- **No parameter slider** — equations are static; there is no way to animate a parameter.
|
||||
- **No multiple equations** — only one equation can be graphed at a time.
|
||||
- **Implicit surface precision** — extremely thin or high-frequency implicit surfaces may still have small artifacts if the grid resolution (`GRID_3D`) is too low.
|
||||
- **3D implicit performance** — tri-axis marching evaluates the function significantly more times than explicit rendering; high resolutions will impact frame rate.
|
||||
- **Integer axis labels only for large values** — very large axis values are capped at `>2G` or `<-2G` due to `itoa` limitations.
|
||||
251
docs/appdev/inputs_api_(utf8).md
Normal file
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
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.
|
||||
52
docs/appdev/sdk_reference.md
Normal file
52
docs/appdev/sdk_reference.md
Normal file
@@ -0,0 +1,52 @@
|
||||
<div align="center">
|
||||
<h1>Userland SDK Reference</h1>
|
||||
<p><em>Overview and entry point for BoredOS userland development.</em></p>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
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.
|
||||
|
||||
## SDK Structure
|
||||
|
||||
Primary headers are in `src/userland/libc/` and UI helpers are in `src/wm/`.
|
||||
|
||||
- `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
|
||||
|
||||
## Detailed References
|
||||
|
||||
- [`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
|
||||
|
||||
## Typical Include Set
|
||||
|
||||
```c
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <syscall.h>
|
||||
```
|
||||
|
||||
For GUI apps:
|
||||
|
||||
```c
|
||||
#include <libui.h>
|
||||
#include <libwidget.h>
|
||||
```
|
||||
|
||||
## 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`.
|
||||
|
||||
|
||||
154
docs/appdev/syscalls.md
Normal file
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.
|
||||
111
docs/appdev/ui_api.md
Normal file
111
docs/appdev/ui_api.md
Normal file
@@ -0,0 +1,111 @@
|
||||
<div align="center">
|
||||
<h1>UI API (<code>libui.h</code>)</h1>
|
||||
<p><em>Comprehensive manual for interacting with the Window Manager.</em></p>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
The UI library (`libui.h`) is the sole mechanism for Graphical Userland Applications to draw to the screen and receive input events in BoredOS. It wraps `SYS_GUI` kernel calls.
|
||||
|
||||
## Window Management
|
||||
|
||||
A "Window" is a reserved drawing canvas managed by the compositor.
|
||||
|
||||
* `ui_window_t ui_window_create(const char *title, int x, int y, int w, int h);`
|
||||
Creates a new window at `(x, y)` with dimensions `w`x`h`. Returns a window handle.
|
||||
**Flags** are currently embedded in the syscall; standard windows include decorations (titlebar, borders).
|
||||
* `void ui_window_set_title(ui_window_t win, const char *title);`
|
||||
Dynamically update the text displayed in the window's titlebar.
|
||||
* `void ui_window_set_resizable(ui_window_t win, bool resizable);`
|
||||
Enable or disable the user's ability to resize the window by dragging its edges.
|
||||
* `void ui_get_screen_size(uint64_t *out_w, uint64_t *out_h);`
|
||||
Query the global screen resolution of the display.
|
||||
|
||||
## Drawing Primitives
|
||||
|
||||
All drawing functions write to an off-screen buffer associated with the window. **You must call `ui_mark_dirty()` to instruct the compositor to push your changes to the physical screen.**
|
||||
|
||||
* `void ui_draw_rect(ui_window_t win, int x, int y, int w, int h, uint32_t color);`
|
||||
Draw a solid filled rectangle.
|
||||
* `void ui_draw_rounded_rect_filled(ui_window_t win, int x, int y, int w, int h, int radius, uint32_t color);`
|
||||
Fill a rectangle with rounded corners of a specified `radius`.
|
||||
* `void ui_draw_image(ui_window_t win, int x, int y, int w, int h, uint32_t *image_data);`
|
||||
Blit a raw ARGB pixel buffer (`image_data`) directly into the window canvas.
|
||||
* `void ui_mark_dirty(ui_window_t win, int x, int y, int w, int h);`
|
||||
Mark a specific rectangular region of the window as "dirty". The Window Manager will redraw this area on the next compositing pass.
|
||||
|
||||
> [!TIP]
|
||||
> Colors are defined as 32-bit unsigned integers in **ARGB** format: `0xAARRGGBB`.
|
||||
> E.g., `0xFF000000` is opaque black, `0xFFFF0000` is opaque red.
|
||||
|
||||
## Text Rendering
|
||||
|
||||
BoredOS provides multiple text rendering methodologies, including a default system font and scaled/bitmap alternatives.
|
||||
|
||||
* `void ui_draw_string(ui_window_t win, int x, int y, const char *str, uint32_t color);`
|
||||
Draw text using the default system typeface.
|
||||
* `void ui_draw_string_bitmap(ui_window_t win, int x, int y, const char *str, uint32_t color);`
|
||||
Draw text using a secondary fast bitmap font renderer.
|
||||
* `void ui_draw_string_scaled(ui_window_t win, int x, int y, const char *str, uint32_t color, float scale);`
|
||||
Draw text scaled up or down by a floating-point multiplier.
|
||||
* `void ui_draw_string_scaled_sloped(ui_window_t win, int x, int y, const char *str, uint32_t color, float scale, float slope);`
|
||||
Draw scaled text with an italic-like slope/shear applied.
|
||||
* `void ui_set_font(ui_window_t win, const char *path);`
|
||||
Load and set a custom `.ttf` or bitmap font from the filesystem for this window.
|
||||
|
||||
### Font Metrics
|
||||
Used for calculating layout bounds before drawing:
|
||||
* `uint32_t ui_get_string_width(const char *str);`
|
||||
* `uint32_t ui_get_font_height(void);`
|
||||
* `uint32_t ui_get_string_width_scaled(const char *str, float scale);`
|
||||
* `uint32_t ui_get_font_height_scaled(float scale);`
|
||||
|
||||
## Event Handling
|
||||
|
||||
Applications must continuously poll for events inside an infinite `$while(1)` loop.
|
||||
|
||||
* `bool ui_get_event(ui_window_t win, gui_event_t *ev);`
|
||||
Returns `true` if an event was waiting in the queue, populating the `ev` structure. Returns `false` if the queue is empty.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Because `ui_get_event` is non-blocking, you must call `sys_yield();` inside your event loop if no event was received. In BoredOS's **Multi-Core (SMP)** architecture, failing to yield will pin a CPU core to 100% usage, potentially starving other processes.
|
||||
>
|
||||
> All UI syscalls are **Thread-Safe** at the kernel level via the global GUI spinlock.
|
||||
|
||||
### Graphical Event Structure
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
int type; // Specifies the event class (see below)
|
||||
int arg1; // Generic argument 1
|
||||
int arg2; // Generic argument 2
|
||||
int arg3; // Generic argument 3
|
||||
} gui_event_t;
|
||||
```
|
||||
|
||||
### Event Types & Arguments
|
||||
|
||||
| Event Constant | `type` ID | Trigger | `arg1` | `arg2` | `arg3` |
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
| `GUI_EVENT_NONE` | `0` | Empty event | - | - | - |
|
||||
| `GUI_EVENT_PAINT` | `1` | Window needs redrawing | - | - | - |
|
||||
| `GUI_EVENT_CLICK` | `2` | Mouse click down | X Coord | Y Coord | Button State |
|
||||
| `GUI_EVENT_RIGHT_CLICK` | `3` | Mouse right-click down | X Coord | Y Coord | Button State |
|
||||
| `GUI_EVENT_CLOSE` | `4` | User clicked 'X' button | - | - | - |
|
||||
| `GUI_EVENT_KEY` | `5` | Keyboard key pressed | Keycode | Modifiers | - |
|
||||
| `GUI_EVENT_KEYUP` | `10` | Keyboard key released | Keycode | Modifiers | - |
|
||||
| `GUI_EVENT_MOUSE_DOWN` | `6` | Generic mouse button down | X Coord | Y Coord | Button State |
|
||||
| `GUI_EVENT_MOUSE_UP` | `7` | Generic mouse button release | X Coord | Y Coord | Button State |
|
||||
| `GUI_EVENT_MOUSE_MOVE` | `8` | Mouse cursor moved | X Coord | Y Coord | - |
|
||||
| `GUI_EVENT_MOUSE_WHEEL` | `9` | Scroll wheel rotated | Scroll Delta | - | - |
|
||||
| `GUI_EVENT_RESIZE` | `11` | Window dimensions changed| New Width | New Height | - |
|
||||
|
||||
*(Note: Coordinate arguments (`arg1`, `arg2`) for mouse events are typically relative to the top-left corner of the window's client area).*
|
||||
|
||||
---
|
||||
|
||||
> [!TIP]
|
||||
> **Looking for Buttons, TextBoxes, or Scrollbars?**
|
||||
> While `libui.h` provides the foundation for drawing, most applications should use the higher-level [**Widget API**](widget_api.md) (`libwidget.h`) for standard interactive components.
|
||||
|
||||
---
|
||||
108
docs/appdev/widget_api.md
Normal file
108
docs/appdev/widget_api.md
Normal file
@@ -0,0 +1,108 @@
|
||||
<div align="center">
|
||||
<h1>Widget API (<code>libwidget.h</code>)</h1>
|
||||
<p><em>High-level UI components for BoredOS applications.</em></p>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
The Widget library (`libwidget.h`) provides a set of reusable UI components built on top of `libui.h`. It uses an abstract `widget_context_t` to decouple component logic from specific drawing implementations, making it easier to build complex graphical interfaces.
|
||||
|
||||
## Widget Context
|
||||
|
||||
To use any widget, you must first define a `widget_context_t`. This structure contains function pointers for basic drawing operations (rects, strings) and theme preferences.
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
void *user_data;
|
||||
void (*draw_rect)(void *user_data, int x, int y, int w, int h, uint32_t color);
|
||||
void (*draw_rounded_rect_filled)(void *user_data, int x, int y, int w, int h, int r, uint32_t color);
|
||||
void (*draw_string)(void *user_data, int x, int y, const char *str, uint32_t color);
|
||||
int (*measure_string_width)(void *user_data, const char *str);
|
||||
void (*mark_dirty)(void *user_data, int x, int y, int w, int h);
|
||||
bool use_light_theme;
|
||||
} widget_context_t;
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> Usually, `user_data` is set to your `ui_window_t` handle, and the functions are simple wrappers around `ui_draw_rect`, `ui_draw_string`, etc.
|
||||
|
||||
---
|
||||
|
||||
## Button (`widget_button_t`)
|
||||
|
||||
Standard interactive button with hover and click states.
|
||||
|
||||
* `void widget_button_init(widget_button_t *btn, int x, int y, int w, int h, const char *text);`
|
||||
* `void widget_button_draw(widget_context_t *ctx, widget_button_t *btn);`
|
||||
* `bool widget_button_handle_mouse(widget_button_t *btn, int mx, int my, bool mouse_down, bool mouse_clicked, void *user_data);`
|
||||
|
||||
### Usage Example:
|
||||
```c
|
||||
widget_button_t my_btn;
|
||||
widget_button_init(&my_btn, 10, 10, 80, 25, "Click Me");
|
||||
my_btn.on_click = my_callback_func;
|
||||
|
||||
// In your event loop:
|
||||
widget_button_handle_mouse(&my_btn, ev.arg1, ev.arg2, is_down, is_clicked, my_data);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Scrollbar (`widget_scrollbar_t`)
|
||||
|
||||
Vertical scrollbar supporting dragging and track-paging.
|
||||
|
||||
* `void widget_scrollbar_init(widget_scrollbar_t *sb, int x, int y, int w, int h);`
|
||||
* `void widget_scrollbar_update(widget_scrollbar_t *sb, int content_height, int scroll_y);`
|
||||
* `void widget_scrollbar_draw(widget_context_t *ctx, widget_scrollbar_t *sb);`
|
||||
* `bool widget_scrollbar_handle_mouse(widget_scrollbar_t *sb, int mx, int my, bool mouse_down, void *user_data);`
|
||||
|
||||
> [!NOTE]
|
||||
> The scrollbar automatically calculates the "thumb" size based on the ratio of `h` to `content_height`.
|
||||
|
||||
---
|
||||
|
||||
## TextBox (`widget_textbox_t`)
|
||||
|
||||
Editable text field with focus support and keyboard handling.
|
||||
|
||||
* `void widget_textbox_init(widget_textbox_t *tb, int x, int y, int w, int h, char *buffer, int max_len);`
|
||||
* `void widget_textbox_draw(widget_context_t *ctx, widget_textbox_t *tb);`
|
||||
* `bool widget_textbox_handle_mouse(widget_textbox_t *tb, int mx, int my, bool mouse_clicked, void *user_data);`
|
||||
* `bool widget_textbox_handle_key(widget_textbox_t *tb, char c, void *user_data);`
|
||||
|
||||
---
|
||||
|
||||
## Dropdown (`widget_dropdown_t`)
|
||||
|
||||
Selection menu for picking one item from a list.
|
||||
|
||||
* `void widget_dropdown_init(widget_dropdown_t *dd, int x, int y, int w, int h, const char **items, int count);`
|
||||
* `void widget_dropdown_draw(widget_context_t *ctx, widget_dropdown_t *dd);`
|
||||
* `bool widget_dropdown_handle_mouse(widget_dropdown_t *dd, int mx, int my, bool mouse_clicked, void *user_data);`
|
||||
|
||||
---
|
||||
|
||||
## Checkbox / Radio (`widget_checkbox_t`)
|
||||
|
||||
Toggleable options with support for circular "Radio" style or square "Checkbox" style.
|
||||
|
||||
* `void widget_checkbox_init(widget_checkbox_t *cb, int x, int y, int w, int h, const char *text, bool is_radio);`
|
||||
* `void widget_checkbox_draw(widget_context_t *ctx, widget_checkbox_t *cb);`
|
||||
* `bool widget_checkbox_handle_mouse(widget_checkbox_t *cb, int mx, int my, bool mouse_clicked, void *user_data);`
|
||||
|
||||
---
|
||||
|
||||
## Event Integration
|
||||
|
||||
Widgets are designed to be polled within your `libui` event loop. Most handle-mouse functions return `true` if the event was "consumed" by the widget, allowing you to stop further processing for that event.
|
||||
|
||||
```c
|
||||
if (ui_get_event(win, &ev)) {
|
||||
bool handled = false;
|
||||
handled |= widget_button_handle_mouse(&btn, ev.arg1, ev.arg2, is_down, is_clicked, NULL);
|
||||
if (!handled) {
|
||||
// Handle global window events...
|
||||
}
|
||||
}
|
||||
```
|
||||
48
docs/architecture/graphics/window_manager.md
Normal file
48
docs/architecture/graphics/window_manager.md
Normal file
@@ -0,0 +1,48 @@
|
||||
<div align="center">
|
||||
<h1>Window Manager (WM)</h1>
|
||||
<p><em>The native graphical subsystem compositing and event routing.</em></p>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
BoredOS features a fully custom, graphical Window Manager built directly into the kernel, residing in the `src/wm/` directory. It is responsible for compositing the screen, handling window logic, rendering text, and dispatching UI events.
|
||||
|
||||
## Framebuffer and Rendering
|
||||
|
||||
1. **Limine Framebuffer**: During boot, the Limine bootloader requests a graphical framebuffer from the hardware (e.g., GOP in UEFI environments) and passes a pointer to this linear memory buffer to the kernel.
|
||||
2. **Double Buffering**: To prevent screen tearing, the WM does not draw directly to the screen. It allocates a "back buffer" in kernel memory equal to the size of the screen. All drawing operations (lines, rectangles, windows) happen on this back buffer.
|
||||
3. **Compositing**: Once per frame or upon request, the entire back buffer (or dirty regions) is copied to the actual Limine physical framebuffer memory, making the changes visible instantly.
|
||||
|
||||
> [!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`)
|
||||
|
||||
The windowing system is built around a linked list of `Window` structures.
|
||||
|
||||
- **Z-Ordering**: The list determines the draw order. Windows at the back of the list are drawn first, and the active window is drawn last (on top).
|
||||
- **Window Structures**: Each window object tracks its dimensions (`x`, `y`, `width`, `height`), title, background color, and an internal buffer if it's acting as a canvas for userland apps.
|
||||
- **Decorations**: The kernel handles drawing window borders, title bars, and close buttons automatically unless a borderless style is specified.
|
||||
|
||||
## Input Handling and Events
|
||||
|
||||
The WM acts as the central hub for input routing.
|
||||
|
||||
1. **Mouse Driver**: The PS/2 mouse driver (`dev/mouse.c`) detects movement and button clicks. It raises interrupts that update global cursor coordinates.
|
||||
2. **Hit Testing**: The WM checks these coordinates against the bounding boxes of existing windows. It handles dragging logic (if the user clicks a title bar) or focus changes.
|
||||
3. **Event Queue**: If a userland application owns the window that was clicked, the WM packages the input (coordinates, button state) into an event message and drops it into the owning process's event queue. The application can retrieve these via the custom libc UI functions.
|
||||
|
||||
- **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
|
||||
|
||||
With the introduction of Symmetric Multi-Processing (SMP), the Window Manager (WM) was redesigned to ensure stability and high performance across multiple cores.
|
||||
|
||||
1. **Granular Window Locks**: Each `Window` object possesses its own `spinlock_t lock;`. User applications concurrently draw directly into their own window buffers without stalling the rest of the system. The global `wm_lock` is reserved strictly for altering global structures like window z-order or syncing buffers to the screen compositing layer.
|
||||
2. **Per-CPU Rendering State**: To facilitate simultaneous GUI system calls across all CPU cores, the low-level rendering context (`g_render_target` array) is isolated per-CPU using the core ID. This allows completely lockless multi-core pixel rasterization, drastically reducing rendering bottlenecks.
|
||||
3. **Deferred Compositing**: Final screen composition (`wm_paint`) is scheduled to the main kernel idle loop on the Bootstrap Processor (BSP). This enables application cores to continue processing logic seamlessly while the GUI asynchronously handles flipping the physical framebuffer.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Because application rendering (rasterizing geometry into a window's backbuffer) is SMP-safe and lock-free across cores, GUI performance scales linearly with the number of CPUs active.
|
||||
|
||||
---
|
||||
41
docs/architecture/hardware/pci.md
Normal file
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
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
|
||||
|
||||
|
||||
40
docs/architecture/memory/memory.md
Normal file
40
docs/architecture/memory/memory.md
Normal file
@@ -0,0 +1,40 @@
|
||||
<div align="center">
|
||||
<h1>Memory Management</h1>
|
||||
<p><em>Physical and Virtual Memory coordination in x86_64 Long Mode.</em></p>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
Memory management in BoredOS is split into physical and virtual layers, designed to support both kernel operations and userland isolation on the x86_64 architecture.
|
||||
|
||||
## Physical Memory Management (PMM)
|
||||
|
||||
The PMM is responsible for tracking which physical RAM frames (usually 4KB each) are free and which are in use.
|
||||
|
||||
1. **Memory Map**: During boot, Limine provides a memory map detailing the available, reserved, and unusable physical memory regions.
|
||||
2. **Bitmap Allocator**: The core PMM uses a bitmap-based allocation strategy. Each bit in the bitmap represents a single physical page (frame). If a bit is `1`, the page is in use; if `0`, it is free.
|
||||
3. **Allocation**: When a new page is requested (e.g., for userland space or kernel heap), the PMM scans the bitmap for the first available zero bit, marks it as used, and returns the physical address.
|
||||
4. **SMP Safety**: In a multi-core environment, the PMM and VMM are protected by **Spinlocks** to prevent two CPUs from allocating the same frame or modifying page tables simultaneously.
|
||||
|
||||
> [!NOTE]
|
||||
> 4KB frame sizes strike a balance between allocation speed and minimal memory fragmentation, fitting directly with the page tables.
|
||||
|
||||
## Virtual Memory Management (VMM) and Paging
|
||||
|
||||
BoredOS uses 4-level paging (PML4), a requirement for x86_64 long mode, dividing the virtual address space between the kernel and userland.
|
||||
|
||||
- **Kernel Space**: The kernel relies on a higher-half design where its code, data, and heap are mapped to high addresses (typically above `0xFFFF800000000000`).
|
||||
- **Per-CPU Structures**: Each CPU core maintains its own architectural state in memory:
|
||||
* **Per-CPU GDT**: Each core is initialized with its own Global Descriptor Table.
|
||||
* **Per-CPU TSS**: Each core has a dedicated Task State Segment containing the `RSP0` pointer for its own kernel stack, ensuring safe interrupt handling across cores.
|
||||
- **User Space**: Userland applications are loaded into lower virtual addresses.
|
||||
- **Page Faults**: The `mem/` subsystem registers an Interrupt Service Routine (ISR) for page faults (Interrupt 14). If a process accesses unmapped memory, the handler determines whether to allocate a new frame or terminate the process.
|
||||
|
||||
## Kernel Heap
|
||||
|
||||
Dynamic allocation within the kernel (`kmalloc` and `kfree`) is layered on top of the physical allocator. The kernel maintains its own heap area in virtual memory. When the heap requires more space, it requests physical frames from the PMM and maps them into the kernel's virtual address space.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> The kernel heap is a shared resource; therefore, all `kmalloc` and `kfree` operations are guarded by a global spinlock to ensure thread safety during multi-core execution.
|
||||
|
||||
---
|
||||
71
docs/architecture/memory/memory_manager.md
Normal file
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
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
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.
|
||||
37
docs/architecture/storage/filesystem.md
Normal file
37
docs/architecture/storage/filesystem.md
Normal file
@@ -0,0 +1,37 @@
|
||||
<div align="center">
|
||||
<h1>Filesystem Architecture</h1>
|
||||
<p><em>Virtual File System layer and FAT32 abstraction in BoredOS.</em></p>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
BoredOS implements a rudimentary but functional filesystem layer designed to support reading system assets and user applications during runtime.
|
||||
|
||||
## Virtual File System (VFS)
|
||||
|
||||
The Virtual File System acts as an abstraction layer across different underlying storage mechanisms (even if, currently, only one type is fully utilized). System calls targeting files (`SYS_FS`) route through the VFS rather than interacting with the disk directly.
|
||||
|
||||
Key VFS functionalities include:
|
||||
- **File Descriptors**: Mapping integer IDs to internal file structures for userland processes.
|
||||
- **Standard Operations**: Standardizing `open()`, `read()`, `write()`, `close()`, `seek()`, and directory listings.
|
||||
- **Path Parsing**: Resolving absolute and relative paths.
|
||||
- **SMP Safety**: All VFS and underlying FAT32 operations are protected by a global **Spinlock**. This ensures that multiple cores can safely read from the filesystem simultaneously without corrupting internal file seek pointers or directory cache states.
|
||||
|
||||
## FAT32 Implementation
|
||||
|
||||
The primary filesystem logic in `fat32.c` handles both in-memory RAM-based filesystem simulation and physical ATA block devices.
|
||||
|
||||
### Storage Support
|
||||
|
||||
BoredOS supports two main types of storage for its FAT32 implementation:
|
||||
|
||||
1. **RAMFS (Boot Modules)**: During boot, Limine loads necessary files (such as userland `.elf` binaries, fonts, and wallpapers) into memory as standard boot modules. The FAT32 code parses these loaded memory modules and automatically constructs a synthetic FAT32 directory tree inside RAM (mounted as `A:`).
|
||||
2. **ATA Drives**: The kernel includes a basic PIO-based ATA driver that can detect and read/write to physical IDE/PATA hard disks.
|
||||
- **GPT is NOT supported**: Currently, only **MBR (Master Boot Record)** partition tables or **raw (partitionless)** disks are supported.
|
||||
- **Filesystem**: The partition must be formatted as **FAT32**.
|
||||
|
||||
### Auto-detection
|
||||
The `Disk Manager` automatically probes primary and secondary IDE channels during initialization. If a valid FAT32 partition is found (either directly at sector 0 or via an MBR partition table), the disk is assigned a drive letter (starting from `B:`) and becomes accessible to the VFS.
|
||||
|
||||
|
||||
---
|
||||
58
docs/architecture/system/core.md
Normal file
58
docs/architecture/system/core.md
Normal file
@@ -0,0 +1,58 @@
|
||||
<div align="center">
|
||||
<h1>Core Architecture</h1>
|
||||
<p><em>Overview of BoredOS kernel layout, boot process, and userspace transition.</em></p>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
BoredOS is a 64-bit hobbyist operating system designed for the x86_64 architecture. While it features kernel-space drivers and a built-in window manager, it supports fully-isolated userspace applications and includes a networking stack.
|
||||
|
||||
This document serves as an overview of the core architecture and the layout of the kernel source code.
|
||||
|
||||
## Source Code Layout (`src/`)
|
||||
|
||||
The OS heavily relies on module separation. The `src/` directory is logically split into several domains:
|
||||
|
||||
- **`arch/`**: Contains the assembly routines needed for bootstrapping the system (`boot.asm`) and setting up the CPU state for userland execution (`process_asm.asm`). It also handles architecture-specific mechanisms like the Global Descriptor Table (GDT) and Interrupt Descriptor Table (IDT).
|
||||
- **`core/`**: The initialization sequence of the OS lives here. `main.c` is the entry point from the bootloader. This directory also contains essential kernel utilities (`kutils.c`), panic handlers (`panic.c`), and built-in command parsing logic (`cmd.c`).
|
||||
- **`dev/`**: Device drivers. This includes the PCI scanner, disk management infrastructure, input drivers (keyboard and mouse), and the Real Time Clock (RTC).
|
||||
- **`fs/`**: Filesystem implementations. The system uses a Virtual File System (VFS) abstraction alongside an in-memory FAT32 filesystem with support for drives over ATA that are formatted as FAT32 (plain/MBR).
|
||||
- **`mem/`**: Physical and virtual memory management. It controls page frame allocation, paging, and kernel heap operations.
|
||||
- **`net/`**: The networking stack. BoredOS relies on `lwIP` for processing IPv4 and TCP/UDP traffic, interacting with a range of NICs via `net/nic/`.
|
||||
- **`sys/`**: System calls and process management. The ELF loader resides here, alongside the Symmetric Multi-Processing (**smp.c**) bringup and Local APIC (**lapic.c**) management logic.
|
||||
- **`wm/`**: The graphical subsystem. It handles drawing primitives, window structures, font rendering, and double-buffering.
|
||||
- **`userland/`**: Out-of-kernel components. This includes the custom SDK/compiler environment (`libc/`) and user applications (`cli/`, `gui/`, `games/`).
|
||||
|
||||
## Boot Process
|
||||
|
||||
BoredOS uses **Limine** as its primary bootloader.
|
||||
|
||||
1. **Limine Initialization**: The machine firmware (BIOS or UEFI) loads Limine. Limine parses `limine.conf`, sets up an early graphical framebuffer, and reads the kernel ELF file into memory.
|
||||
2. **Multiboot2 & SMP Protocol**: The kernel expects the Limine boot protocol. It makes a specific **SMP Request** to Limine to locate and bring up all available CPU cores.
|
||||
3. **Kernel Entry (`main.c`)**: The entry point `_start` is called on the Bootstrap Processor (BSP). It initializes the serial port, GDT/IDT, memory management, and paging.
|
||||
4. **AP Bringup**: The BSP calls `smp_init()`, which sends the Startup Inter-Processor Interrupt (SIPI) sequence to all Application Processors (APs). Each AP initializes its own local GDT, TSS, and Page Tables before entering an idle loop.
|
||||
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
|
||||
|
||||
BoredOS utilizes Symmetric Multi-Processing (SMP) to distribute workloads across all available CPU cores.
|
||||
|
||||
- **LAPIC & IPIs**: Each CPU has its own Local APIC. The kernel uses Inter-Processor Interrupts (IPIs) for inter-core communication, specifically for triggering the scheduler on other cores (`vector 0x41`).
|
||||
- **Scheduler**: A round-robin scheduler runs on each core. Processes are pinned to specific CPUs (CPU Affinity) to maintain cache locality. The BSP timer interrupt (`60Hz`) broadcasts a scheduling IPI to all core to ensure balanced execution.
|
||||
- **Spinlocks**: Since multiple cores can access kernel structures (VFS, Process List) simultaneously, the kernel uses **interrupt-safe spinlocks** to prevent race conditions.
|
||||
|
||||
## Userland Transition
|
||||
|
||||
The OS supports privilege separation (Ring 0 vs. Ring 3). When an application is launched, the kernel:
|
||||
|
||||
1. Loads the ELF file from the filesystem.
|
||||
2. Assigns the process to a CPU core via a round-robin distribution strategy.
|
||||
3. Allocates a new virtual address space (Page Directory) for the process.
|
||||
4. Maps the executable segments according to the ELF headers.
|
||||
5. Switches to User Mode (Ring 3) via the `iretq` instruction.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Programs interact with the core kernel using system calls (`syscall.c`). Multitasking is achieved by pre-empting user processes on their respective cores.
|
||||
|
||||
---
|
||||
66
docs/architecture/system/processes.md
Normal file
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
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";
|
||||
```
|
||||
|
||||
21
docs/build/toolchain.md
vendored
Normal file
21
docs/build/toolchain.md
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Build Toolchain
|
||||
|
||||
BoredOS is built cross-compiled from a host system (such as macOS or Linux) to target the generic `x86_64-elf` platform.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
To build BoredOS, you need the following tools:
|
||||
|
||||
1. **x86_64 ELF GCC Cross-Compiler**:
|
||||
- `x86_64-elf-gcc`: The C compiler targeting the freestanding overarching ELF environment.
|
||||
- `x86_64-elf-ld`: The linker to combine object files into the final `boredos.elf` kernel binary and userland variables.
|
||||
|
||||
2. **NASM**:
|
||||
- Required to compile the `.asm` files in `src/arch/` and `src/userland/crt0.asm`. It formats the output as `elf64` objects to be linked alongside the C code.
|
||||
|
||||
3. **xorriso**:
|
||||
- A specialized tool to create ISO 9660 filesystem images.
|
||||
- *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 to virtualize the OS for testing or to mess around.
|
||||
65
docs/build/usage.md
vendored
Normal file
65
docs/build/usage.md
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
# Building, Running, and Deployment
|
||||
|
||||
BoredOS uses a single top-level `Makefile` to orchestrate the build process.
|
||||
|
||||
## The Build Process
|
||||
|
||||
When you run `make` in the root directory, the following stages occur automatically:
|
||||
|
||||
1. **Limine Setup (`limine-setup`)**:
|
||||
If the Limine bootloader binaries are missing, the Makefile automatically clones the appropriate Limine binary release from GitHub and compiles its host utility.
|
||||
2. **Kernel Compilation**:
|
||||
All `.c` files in `src/core`, `src/mem`, `src/dev`, `src/sys`, `src/fs`, `src/wm`, and `src/net` are compiled into object files (`.o`) inside the `build/` directory using `x86_64-elf-gcc`.
|
||||
3. **Kernel Assembly**:
|
||||
All `.asm` files in `src/arch/` are assembled into object files using `nasm`.
|
||||
4. **Kernel Linking**:
|
||||
`x86_64-elf-ld` links the kernel object files together, instructed by the `linker.ld` script, outputting the `boredos.elf` kernel binary.
|
||||
5. **Userland Compilation**:
|
||||
The Makefile shifts into the `src/userland` directory, compiling the custom `libc` and generating `bin/*.elf` executable user applications.
|
||||
6. **ISO Generation**:
|
||||
The `iso_root` directory is staged. The kernel, Limine configuration, fonts, images, and userland applications are copied in. Finally, `xorriso` generates the `boredos.iso` bootable image.
|
||||
|
||||
## Minimum System Requirements
|
||||
|
||||
To run BoredOS successfully (either in emulation or on bare metal), your target machine should meet the following minimum requirements:
|
||||
|
||||
- **CPU**: An `x86_64` (64-bit) compatible processor.
|
||||
- **Memory**: Approximately `~256 MB` of RAM.
|
||||
- **Display**: A VGA-compatible display (required for the GUI Window Manager).
|
||||
- **Networking (Optional)**: A compatible Network Interface Card (NIC) is required if you want to use the networking stack (e.g., an Intel E1000 or similar supported by the [`net/nic/`](../../src/net/nic/) drivers). Networking is not strictly required for the OS to boot or run offline applications.
|
||||
|
||||
|
||||
## Running in Emulation
|
||||
|
||||
To test the generated ISO quickly without real hardware, use the QEMU emulator:
|
||||
|
||||
For MacOS:
|
||||
```sh
|
||||
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.
|
||||
- `-smp 4`: Enables 4 CPU cores.
|
||||
- `-drive file=disk.img...`: Attaches a raw disk image included in this release of BoredOS.
|
||||
|
||||
## Running on Bare Metal
|
||||
|
||||
> [!CAUTION]
|
||||
> Running hobby operating systems on real hardware is at your own risk and may cause undefined behavior.
|
||||
|
||||
To boot BoredOS on a physical PC:
|
||||
|
||||
1. Build the OS to get `boredos.iso`.
|
||||
2. Use a flashing tool like **Balena Etcher** or `dd` to write the ISO to a USB flash drive.
|
||||
3. Reboot your target computer, enter the BIOS/UEFI setup.
|
||||
4. **Boot Configuration**: BoredOS supports booting on both modern **UEFI** systems and legacy **BIOS** systems natively via Limine. Ensure **Secure Boot** is disabled in your firmware settings.
|
||||
5. Select the USB drive from the boot menu.
|
||||
33
docs/usage/booting.md
Normal file
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
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
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
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
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)
|
||||
1
limine
1
limine
Submodule limine deleted from 38ff2c855a
@@ -13,3 +13,4 @@ backdrop: 000000
|
||||
/BoredOS
|
||||
protocol: limine
|
||||
path: boot():/boredos.elf
|
||||
cmdline: -v
|
||||
|
||||
BIN
screenshot.jpg
BIN
screenshot.jpg
Binary file not shown.
|
Before Width: | Height: | Size: 317 KiB After Width: | Height: | Size: 416 KiB |
BIN
src/.DS_Store
vendored
BIN
src/.DS_Store
vendored
Binary file not shown.
@@ -7,9 +7,13 @@ global isr1_wrapper
|
||||
global isr8_wrapper
|
||||
global isr12_wrapper
|
||||
global isr14_wrapper
|
||||
global isr128_wrapper
|
||||
global isr_sched_ipi_wrapper
|
||||
extern timer_handler
|
||||
extern keyboard_handler
|
||||
extern mouse_handler
|
||||
extern sched_ipi_handler
|
||||
extern syscall_handler_c
|
||||
extern exception_handler_c
|
||||
|
||||
; Helper to send EOI (End of Interrupt) to PIC
|
||||
@@ -41,7 +45,11 @@ isr%2_wrapper:
|
||||
push r14
|
||||
push r15
|
||||
|
||||
; Save SSE/FPU state
|
||||
test qword [rsp + 144], 3
|
||||
jz %%skip_swap
|
||||
swapgs
|
||||
%%skip_swap:
|
||||
|
||||
sub rsp, 512
|
||||
fxsave [rsp]
|
||||
|
||||
@@ -72,6 +80,12 @@ isr%2_wrapper:
|
||||
pop rcx
|
||||
pop rbx
|
||||
pop rax
|
||||
|
||||
test qword [rsp + 24], 3
|
||||
jz %%skip_swap_back
|
||||
swapgs
|
||||
%%skip_swap_back:
|
||||
|
||||
add rsp, 16 ; drop dummy vector and error code
|
||||
iretq
|
||||
%endmacro
|
||||
@@ -85,6 +99,12 @@ isr1_wrapper:
|
||||
isr12_wrapper:
|
||||
ISR_NOERRCODE mouse_handler, 44
|
||||
|
||||
isr_sched_ipi_wrapper:
|
||||
ISR_NOERRCODE sched_ipi_handler, 65
|
||||
|
||||
isr128_wrapper:
|
||||
ISR_NOERRCODE syscall_handler_c, 128
|
||||
|
||||
; Common exception macro for exceptions WITHOUT error code
|
||||
%macro EXCEPTION_NOERRCODE 1
|
||||
global exc%1_wrapper
|
||||
@@ -154,7 +174,11 @@ exception_common:
|
||||
push r14
|
||||
push r15
|
||||
|
||||
; Save SSE/FPU state
|
||||
test qword [rsp + 144], 3
|
||||
jz .skip_swap_exc
|
||||
swapgs
|
||||
.skip_swap_exc:
|
||||
|
||||
sub rsp, 512
|
||||
fxsave [rsp]
|
||||
|
||||
@@ -186,6 +210,12 @@ exception_common:
|
||||
pop rcx
|
||||
pop rbx
|
||||
pop rax
|
||||
|
||||
test qword [rsp + 24], 3
|
||||
jz .skip_swap_back_exc
|
||||
swapgs
|
||||
.skip_swap_back_exc:
|
||||
|
||||
add rsp, 16 ; drop vector and error code
|
||||
iretq
|
||||
|
||||
@@ -7,23 +7,23 @@ 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:
|
||||
; 1. Switch to Kernel Stack safely
|
||||
; Note: For true SMP safety, we need per-CPU storage (via swapgs).
|
||||
; For now, we use a global scratch which is only safe because we mask interrupts on entry.
|
||||
mov [rel user_rsp_scratch], rsp
|
||||
mov rsp, [rel kernel_syscall_stack]
|
||||
swapgs
|
||||
|
||||
; 2. Build iretq frame (compatible with registers_t)
|
||||
mov [gs:40], rsp
|
||||
mov rsp, [gs:48]
|
||||
|
||||
; 2. Build iretq frame
|
||||
push 0x1B ; SS (User Data)
|
||||
push qword [rel user_rsp_scratch] ; RSP
|
||||
push qword [gs:40] ; RSP
|
||||
push r11 ; RFLAGS (captured by syscall)
|
||||
push 0x23 ; CS (User Code)
|
||||
push rcx ; RIP (return address from syscall)
|
||||
@@ -81,14 +81,7 @@ syscall_entry:
|
||||
pop rax
|
||||
add rsp, 16 ; drop int_no/err_code
|
||||
|
||||
; Debug: check RIP before iretq
|
||||
; We can't easily print from here without destroying registers,
|
||||
; but we can at least check if it's canonical.
|
||||
|
||||
swapgs
|
||||
iretq
|
||||
|
||||
section .bss
|
||||
global kernel_syscall_stack
|
||||
global user_rsp_scratch
|
||||
kernel_syscall_stack: resq 1
|
||||
user_rsp_scratch: resq 1
|
||||
100
src/core/kconsole.c
Normal file
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
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
|
||||
@@ -30,6 +30,16 @@ int k_strcmp(const char *s1, const char *s2) {
|
||||
return *(const unsigned char*)s1 - *(const unsigned char*)s2;
|
||||
}
|
||||
|
||||
int k_strncmp(const char *s1, const char *s2, size_t n) {
|
||||
while (n && *s1 && (*s1 == *s2)) {
|
||||
s1++;
|
||||
s2++;
|
||||
n--;
|
||||
}
|
||||
if (n == 0) return 0;
|
||||
return *(const unsigned char*)s1 - *(const unsigned char*)s2;
|
||||
}
|
||||
|
||||
void k_strcpy(char *dest, const char *src) {
|
||||
while (*src) *dest++ = *src++;
|
||||
*dest = 0;
|
||||
@@ -108,17 +118,54 @@ void k_reboot(void) {
|
||||
}
|
||||
|
||||
void k_shutdown(void) {
|
||||
outw(0x604, 0x2000);
|
||||
outw(0xB004, 0x2000); // QEMU older / some pc machines
|
||||
outw(0x604, 0x2000); // QEMU newer (i440fx/q35)
|
||||
outw(0x4004, 0x3400); // VirtualBox fallback
|
||||
}
|
||||
|
||||
volatile uint64_t beep_end_tick = 0;
|
||||
bool beep_active = false;
|
||||
|
||||
void k_beep(int freq, int ms) {
|
||||
if (freq <= 0) return;
|
||||
if (freq <= 0) {
|
||||
outb(0x61, inb(0x61) & 0xFC);
|
||||
beep_active = false;
|
||||
return;
|
||||
}
|
||||
int div = 1193180 / freq;
|
||||
outb(0x43, 0xB6);
|
||||
outb(0x42, div & 0xFF);
|
||||
outb(0x42, (div >> 8) & 0xFF);
|
||||
outb(0x61, inb(0x61) | 0x03);
|
||||
k_sleep(ms);
|
||||
outb(0x61, inb(0x61) & 0xFC);
|
||||
|
||||
uint32_t ticks = ms / 16;
|
||||
if (ticks == 0 && ms > 0) ticks = 1;
|
||||
extern volatile uint64_t kernel_ticks;
|
||||
beep_end_tick = kernel_ticks + ticks;
|
||||
beep_active = true;
|
||||
}
|
||||
|
||||
void k_beep_process(void) {
|
||||
if (beep_active) {
|
||||
extern volatile uint64_t kernel_ticks;
|
||||
if (kernel_ticks >= beep_end_tick) {
|
||||
outb(0x61, inb(0x61) & 0xFC);
|
||||
beep_active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -6,12 +6,14 @@
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// Kernel string utilities
|
||||
void k_memset(void *dest, int val, size_t len);
|
||||
void k_memcpy(void *dest, const void *src, size_t len);
|
||||
size_t k_strlen(const char *str);
|
||||
int k_strcmp(const char *s1, const char *s2);
|
||||
int k_strncmp(const char *s1, const char *s2, size_t n);
|
||||
void k_strcpy(char *dest, const char *src);
|
||||
int k_atoi(const char *str);
|
||||
void k_itoa(int n, char *buf);
|
||||
@@ -23,5 +25,7 @@ void k_sleep(int ms);
|
||||
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
|
||||
509
src/core/main.c
Normal file
509
src/core/main.c
Normal file
@@ -0,0 +1,509 @@
|
||||
// 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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "limine.h"
|
||||
#include "graphics.h"
|
||||
#include "gdt.h"
|
||||
#include "idt.h"
|
||||
#include "paging.h"
|
||||
#include "syscall.h"
|
||||
#include "process.h"
|
||||
#include "ps2.h"
|
||||
#include "wm.h"
|
||||
#include "io.h"
|
||||
#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"
|
||||
#include "smp.h"
|
||||
#include "work_queue.h"
|
||||
#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);
|
||||
|
||||
// --- Limine Requests ---
|
||||
__attribute__((used, section(".requests")))
|
||||
static volatile LIMINE_BASE_REVISION(2);
|
||||
|
||||
__attribute__((used, section(".requests")))
|
||||
static volatile struct limine_framebuffer_request framebuffer_request = {
|
||||
.id = LIMINE_FRAMEBUFFER_REQUEST,
|
||||
.revision = 1
|
||||
};
|
||||
|
||||
__attribute__((used, section(".requests")))
|
||||
static volatile struct limine_memmap_request memmap_request = {
|
||||
.id = LIMINE_MEMMAP_REQUEST,
|
||||
.revision = 0
|
||||
};
|
||||
|
||||
__attribute__((used, section(".requests")))
|
||||
static volatile struct limine_module_request module_request = {
|
||||
.id = LIMINE_MODULE_REQUEST,
|
||||
.revision = 0
|
||||
};
|
||||
|
||||
__attribute__((used, section(".requests")))
|
||||
static volatile struct limine_smp_request smp_request = {
|
||||
.id = LIMINE_SMP_REQUEST,
|
||||
.revision = 0,
|
||||
.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
|
||||
};
|
||||
|
||||
__attribute__((used, section(".requests_end")))
|
||||
static volatile struct limine_request *const requests_end_marker[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static void hcf(void) {
|
||||
asm("cli");
|
||||
for (;;) {
|
||||
asm("hlt");
|
||||
}
|
||||
}
|
||||
|
||||
static void init_serial() {
|
||||
outb(0x3F8 + 1, 0x00);
|
||||
outb(0x3F8 + 3, 0x80);
|
||||
outb(0x3F8 + 0, 0x03);
|
||||
outb(0x3F8 + 1, 0x00);
|
||||
outb(0x3F8 + 3, 0x03);
|
||||
outb(0x3F8 + 2, 0xC7);
|
||||
outb(0x3F8 + 4, 0x0B);
|
||||
}
|
||||
|
||||
static spinlock_t serial_lock = SPINLOCK_INIT;
|
||||
|
||||
void serial_write(const char *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, 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) {
|
||||
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, c);
|
||||
kconsole_putc(c);
|
||||
}
|
||||
|
||||
void serial_write_hex(uint64_t n) {
|
||||
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) {
|
||||
char temp[256];
|
||||
int i = 0;
|
||||
|
||||
// Skip initial slash
|
||||
if (path[0] == '/') {
|
||||
temp[0] = '/';
|
||||
i = 1;
|
||||
}
|
||||
|
||||
while (path[i] && i < 255) {
|
||||
temp[i] = path[i];
|
||||
if (path[i] == '/') {
|
||||
temp[i] = '\0';
|
||||
fat32_mkdir(temp);
|
||||
temp[i] = '/';
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (i > 0 && temp[i-1] != '/') {
|
||||
temp[i] = '\0';
|
||||
fat32_mkdir(temp);
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
platform_init();
|
||||
log_ok("Platform initialized");
|
||||
|
||||
extern uint64_t hhdm_offset;
|
||||
extern uint64_t kernel_phys_base;
|
||||
extern uint64_t kernel_virt_base;
|
||||
|
||||
serial_write("[INIT] HHDM Offset: 0x");
|
||||
serial_write_hex(hhdm_offset);
|
||||
serial_write("\n");
|
||||
serial_write("[INIT] Kernel Phys: 0x");
|
||||
serial_write_hex(kernel_phys_base);
|
||||
serial_write("\n");
|
||||
serial_write("[INIT] Kernel Virt: 0x");
|
||||
serial_write_hex(kernel_virt_base);
|
||||
serial_write("\n");
|
||||
|
||||
if (framebuffer_request.response == NULL || framebuffer_request.response->framebuffer_count < 1) {
|
||||
serial_write("[INIT] No framebuffer! Halting.\n");
|
||||
hcf();
|
||||
}
|
||||
|
||||
struct limine_framebuffer *fb = framebuffer_request.response->framebuffers[0];
|
||||
graphics_init(fb);
|
||||
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();
|
||||
log_ok("GDT initialized");
|
||||
|
||||
paging_init();
|
||||
log_ok("Paging ready");
|
||||
|
||||
syscall_init();
|
||||
log_ok("Syscalls ready");
|
||||
|
||||
idt_init();
|
||||
idt_register_interrupts();
|
||||
idt_load();
|
||||
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();
|
||||
log_ok("FAT32 ready");
|
||||
fat32_mkdir("/bin");
|
||||
fat32_mkdir("/Library");
|
||||
fat32_mkdir("/Library/images");
|
||||
fat32_mkdir("/Library/images/Wallpapers");
|
||||
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");
|
||||
|
||||
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) {
|
||||
log_fail("Limine module response NULL");
|
||||
} else {
|
||||
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];
|
||||
|
||||
const char *clean_path = mod->path;
|
||||
if (fs_starts_with(clean_path, "boot():")) clean_path += 7;
|
||||
else if (fs_starts_with(clean_path, "boot:///")) clean_path += 8;
|
||||
|
||||
int len = 0;
|
||||
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("[INIT] Parsing TAR initrd: ");
|
||||
serial_write(clean_path);
|
||||
serial_write("\n");
|
||||
tar_parse(mod->address, mod->size);
|
||||
} else {
|
||||
char dir_path[256];
|
||||
int last_slash = -1;
|
||||
for (int j = 0; clean_path[j]; j++) {
|
||||
if (clean_path[j] == '/') last_slash = j;
|
||||
}
|
||||
if (last_slash > 0) {
|
||||
for (int j = 0; j < last_slash; j++) dir_path[j] = clean_path[j];
|
||||
dir_path[last_slash] = '\0';
|
||||
fat32_mkdir_recursive(dir_path);
|
||||
}
|
||||
|
||||
FAT32_FileHandle *fh = fat32_open(clean_path, "w");
|
||||
if (fh && fh->valid) {
|
||||
fat32_write(fh, mod->address, mod->size);
|
||||
fat32_close(fh);
|
||||
}
|
||||
}
|
||||
module_manager_register(clean_path, (uint64_t)mod->address, mod->size);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t current_rsp;
|
||||
asm volatile("mov %%rsp, %0" : "=r"(current_rsp));
|
||||
serial_write("[INIT] Stack Alignment: 0x");
|
||||
serial_write_hex(current_rsp);
|
||||
serial_write("\n");
|
||||
|
||||
graphics_init_fonts();
|
||||
|
||||
asm("cli");
|
||||
ps2_init();
|
||||
asm("sti");
|
||||
|
||||
keymap_init();
|
||||
serial_write("[INIT] Keymap initialized");
|
||||
|
||||
lapic_init();
|
||||
|
||||
if (smp_request.response != NULL) {
|
||||
uint32_t online = smp_init(smp_request.response);
|
||||
log_ok("SMP initialized");
|
||||
} else {
|
||||
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();
|
||||
wallpaper_process_pending();
|
||||
asm("hlt");
|
||||
}
|
||||
}
|
||||
@@ -14,8 +14,8 @@ static size_t man_strlen(const char *str) {
|
||||
}
|
||||
|
||||
static void write_man_file(const char *name, const char *content) {
|
||||
char path[128] = "A:/Library/man/";
|
||||
int i = 15;
|
||||
char path[128] = "/Library/man/";
|
||||
int i = 13;
|
||||
while (*name) path[i++] = *name++;
|
||||
path[i++] = '.';
|
||||
path[i++] = 't';
|
||||
@@ -31,8 +31,8 @@ static void write_man_file(const char *name, const char *content) {
|
||||
}
|
||||
|
||||
void create_man_entries(void) {
|
||||
fat32_mkdir("A:/Library");
|
||||
fat32_mkdir("A:/Library/man");
|
||||
fat32_mkdir("/Library");
|
||||
fat32_mkdir("/Library/man");
|
||||
|
||||
write_man_file("ping", "PING - Send ICMP echo requests\n\nUsage: ping <ip>\n\nSends ICMP echo requests to the specified IP address and displays the response times.");
|
||||
write_man_file("net", "NET - Network utilities\n\nUsage: net init\nnet info\nnet ipset >ip<\nnet udpsend >ip< >port< >message< net ping >ip< net help\n\nA collection of network-related commands.");
|
||||
@@ -55,7 +55,8 @@ void create_man_entries(void) {
|
||||
write_man_file("touch", "TOUCH - Create empty file\n\nUsage: touch <filename>\n\nCreates a new empty file if it doesn't exist.");
|
||||
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 A:/Library/conf/sysfetch.cfg.");
|
||||
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
|
||||
153
src/core/platform.c
Normal file
153
src/core/platform.c
Normal file
@@ -0,0 +1,153 @@
|
||||
// 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 <stdint.h>
|
||||
#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,
|
||||
.response = NULL
|
||||
};
|
||||
static volatile struct limine_kernel_address_request kernel_addr_request __attribute__((used, section(".requests"))) = {
|
||||
.id = LIMINE_KERNEL_ADDRESS_REQUEST,
|
||||
.revision = 0,
|
||||
.response = NULL
|
||||
};
|
||||
uint64_t hhdm_offset = 0;
|
||||
uint64_t kernel_phys_base = 0;
|
||||
uint64_t kernel_virt_base = 0;
|
||||
void platform_init(void) {
|
||||
if (hhdm_request.response) { hhdm_offset = hhdm_request.response->offset; }
|
||||
if (kernel_addr_request.response) {
|
||||
kernel_phys_base = kernel_addr_request.response->physical_base;
|
||||
kernel_virt_base = kernel_addr_request.response->virtual_base;
|
||||
}
|
||||
|
||||
// Enable FPU and SSE
|
||||
uint64_t cr0;
|
||||
asm volatile("mov %%cr0, %0" : "=r"(cr0));
|
||||
cr0 &= ~(1ULL << 2); // Clear EM (Emulation)
|
||||
cr0 |= (1ULL << 1); // Set MP (Monitor Coprocessor)
|
||||
cr0 |= (1ULL << 5); // Set NE (Numeric Error)
|
||||
asm volatile("mov %0, %%cr0" : : "r"(cr0));
|
||||
|
||||
uint64_t cr4;
|
||||
asm volatile("mov %%cr4, %0" : "=r"(cr4));
|
||||
cr4 |= (1ULL << 9); // Set OSFXSR (FXSAVE/FXRSTOR support)
|
||||
cr4 |= (1ULL << 10); // Set OSXMMEXCPT (SIMD exception support)
|
||||
asm volatile("mov %0, %%cr4" : : "r"(cr4));
|
||||
|
||||
// Initialize FPU
|
||||
asm volatile("fninit");
|
||||
}
|
||||
uint64_t p2v(uint64_t phys) { return phys + hhdm_offset; }
|
||||
uint64_t v2p(uint64_t virt) {
|
||||
if (kernel_virt_base && virt >= kernel_virt_base) {
|
||||
return virt - kernel_virt_base + kernel_phys_base;
|
||||
}
|
||||
if (hhdm_offset && virt >= hhdm_offset) {
|
||||
return virt - hhdm_offset;
|
||||
}
|
||||
return virt;
|
||||
}
|
||||
void platform_get_cpu_model(char *model) {
|
||||
uint32_t brand[12];
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
|
||||
for (uint32_t i = 0; i < 3; i++) {
|
||||
asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(0x80000002 + i));
|
||||
brand[i * 4 + 0] = eax;
|
||||
brand[i * 4 + 1] = ebx;
|
||||
brand[i * 4 + 2] = ecx;
|
||||
brand[i * 4 + 3] = edx;
|
||||
}
|
||||
|
||||
char *p = (char *)brand;
|
||||
for (int i = 0; i < 48; i++) {
|
||||
model[i] = p[i];
|
||||
}
|
||||
model[48] = '\0';
|
||||
}
|
||||
void platform_get_cpu_vendor(char *vendor) {
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(0));
|
||||
|
||||
char *p = (char *)vendor;
|
||||
*((uint32_t *)&p[0]) = ebx;
|
||||
*((uint32_t *)&p[4]) = edx;
|
||||
*((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,9 +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
|
||||
33
src/core/version.c
Normal file
33
src/core/version.c
Normal file
@@ -0,0 +1,33 @@
|
||||
// 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 "syscall.h"
|
||||
#include <stddef.h>
|
||||
|
||||
extern void mem_memcpy(void *dest, const void *src, size_t len);
|
||||
|
||||
void get_os_info(os_info_t *info) {
|
||||
if (!info) return;
|
||||
|
||||
char *p = (char *)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.5.1-stable";
|
||||
const char *os_codename = "Genesis";
|
||||
const char *kernel_name = "Boredkernel";
|
||||
const char *kernel_version = "4.2.1-stable";
|
||||
const char *build_date = __DATE__;
|
||||
const char *build_time = __TIME__;
|
||||
const char *build_arch = "x86_64";
|
||||
|
||||
int j;
|
||||
j = 0; while (os_name[j] && j < 63) { info->os_name[j] = os_name[j]; j++; } info->os_name[j] = '\0';
|
||||
j = 0; while (os_version[j] && j < 63) { info->os_version[j] = os_version[j]; j++; } info->os_version[j] = '\0';
|
||||
j = 0; while (os_codename[j] && j < 63) { info->os_codename[j] = os_codename[j]; j++; } info->os_codename[j] = '\0';
|
||||
j = 0; while (kernel_name[j] && j < 63) { info->kernel_name[j] = kernel_name[j]; j++; } info->kernel_name[j] = '\0';
|
||||
j = 0; while (kernel_version[j] && j < 63) { info->kernel_version[j] = kernel_version[j]; j++; } info->kernel_version[j] = '\0';
|
||||
j = 0; while (build_date[j] && j < 63) { info->build_date[j] = build_date[j]; j++; } info->build_date[j] = '\0';
|
||||
j = 0; while (build_time[j] && j < 63) { info->build_time[j] = build_time[j]; j++; } info->build_time[j] = '\0';
|
||||
j = 0; while (build_arch[j] && j < 63) { info->build_arch[j] = build_arch[j]; j++; } info->build_arch[j] = '\0';
|
||||
}
|
||||
516
src/dev/ahci.c
Normal file
516
src/dev/ahci.c
Normal file
@@ -0,0 +1,516 @@
|
||||
// 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 "ahci.h"
|
||||
#include "pci.h"
|
||||
#include "disk.h"
|
||||
#include "memory_manager.h"
|
||||
#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);
|
||||
extern void serial_write_hex(uint32_t val);
|
||||
|
||||
// ============================================================================
|
||||
// AHCI Driver State
|
||||
// ============================================================================
|
||||
|
||||
static HBA_MEM *abar = NULL; // MMIO-mapped AHCI Base Address
|
||||
static bool ahci_initialized = false;
|
||||
static int active_port_count = 0;
|
||||
|
||||
#define MAX_AHCI_PORTS 32
|
||||
|
||||
typedef struct {
|
||||
bool active;
|
||||
int port_num;
|
||||
HBA_PORT *port;
|
||||
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];
|
||||
|
||||
// ============================================================================
|
||||
// String Helpers
|
||||
// ============================================================================
|
||||
|
||||
static void ahci_strcpy(char *d, const char *s) {
|
||||
while ((*d++ = *s++));
|
||||
}
|
||||
|
||||
// Kernel virtual to physical address conversion
|
||||
extern uint64_t v2p(uint64_t vaddr);
|
||||
|
||||
// ============================================================================
|
||||
// Port Setup
|
||||
// ============================================================================
|
||||
|
||||
static void ahci_stop_cmd(HBA_PORT *port) {
|
||||
// Clear ST (Start)
|
||||
port->cmd &= ~HBA_PORT_CMD_ST;
|
||||
|
||||
// Clear FRE (FIS Receive Enable)
|
||||
port->cmd &= ~HBA_PORT_CMD_FRE;
|
||||
|
||||
// Wait until FR and CR clear
|
||||
int timeout = 500000;
|
||||
while (timeout-- > 0) {
|
||||
if (port->cmd & HBA_PORT_CMD_FR) continue;
|
||||
if (port->cmd & HBA_PORT_CMD_CR) continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ahci_start_cmd(HBA_PORT *port) {
|
||||
// Wait until CR clears
|
||||
while (port->cmd & HBA_PORT_CMD_CR);
|
||||
|
||||
// Set FRE and ST
|
||||
port->cmd |= HBA_PORT_CMD_FRE;
|
||||
port->cmd |= HBA_PORT_CMD_ST;
|
||||
}
|
||||
|
||||
static int ahci_check_port_type(HBA_PORT *port) {
|
||||
uint32_t ssts = port->ssts;
|
||||
uint8_t ipm = (ssts >> 8) & 0x0F;
|
||||
uint8_t det = ssts & 0x0F;
|
||||
|
||||
if (det != 3) return -1; // No device detected
|
||||
if (ipm != 1) return -1; // Not in active state
|
||||
|
||||
switch (port->sig) {
|
||||
case SATA_SIG_ATA: return 0; // SATA drive
|
||||
case SATA_SIG_ATAPI: return 1; // SATAPI drive
|
||||
case SATA_SIG_SEMB: return 2; // SEMB
|
||||
case SATA_SIG_PM: return 3; // Port multiplier
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void ahci_port_rebase(ahci_port_state_t *ps) {
|
||||
HBA_PORT *port = ps->port;
|
||||
|
||||
ahci_stop_cmd(port);
|
||||
|
||||
// Allocate command list (1KB, 1024-byte aligned)
|
||||
ps->cmd_list = (HBA_CMD_HEADER*)kmalloc_aligned(1024, 1024);
|
||||
if (!ps->cmd_list) return;
|
||||
mem_memset(ps->cmd_list, 0, 1024);
|
||||
|
||||
uint64_t clb_phys = v2p((uint64_t)ps->cmd_list);
|
||||
port->clb = (uint32_t)(clb_phys & 0xFFFFFFFF);
|
||||
port->clbu = (uint32_t)(clb_phys >> 32);
|
||||
|
||||
// Allocate FIS receive area (256 bytes, 256-byte aligned)
|
||||
ps->fis_base = kmalloc_aligned(256, 256);
|
||||
if (!ps->fis_base) return;
|
||||
mem_memset(ps->fis_base, 0, 256);
|
||||
|
||||
uint64_t fb_phys = v2p((uint64_t)ps->fis_base);
|
||||
port->fb = (uint32_t)(fb_phys & 0xFFFFFFFF);
|
||||
port->fbu = (uint32_t)(fb_phys >> 32);
|
||||
|
||||
// Allocate command table for slot 0 (256-byte aligned, room for 8 PRDT entries)
|
||||
int cmd_tbl_size = sizeof(HBA_CMD_TBL) + 8 * sizeof(HBA_PRDT_ENTRY);
|
||||
ps->cmd_tbl = (HBA_CMD_TBL*)kmalloc_aligned(cmd_tbl_size, 256);
|
||||
if (!ps->cmd_tbl) return;
|
||||
mem_memset(ps->cmd_tbl, 0, cmd_tbl_size);
|
||||
|
||||
// Set command header 0 to point to our command table
|
||||
uint64_t ctba_phys = v2p((uint64_t)ps->cmd_tbl);
|
||||
ps->cmd_list[0].ctba = (uint32_t)(ctba_phys & 0xFFFFFFFF);
|
||||
ps->cmd_list[0].ctbau = (uint32_t)(ctba_phys >> 32);
|
||||
ps->cmd_list[0].prdtl = 1; // 1 PRDT entry default
|
||||
|
||||
// Clear error and interrupt status
|
||||
port->serr = 0xFFFFFFFF;
|
||||
port->is = 0xFFFFFFFF;
|
||||
|
||||
ahci_start_cmd(port);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Sector I/O
|
||||
// ============================================================================
|
||||
|
||||
static int ahci_find_free_slot(HBA_PORT *port) {
|
||||
uint32_t slots = (port->sact | port->ci);
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (!(slots & (1 << i))) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ahci_read_sectors(int port_num, uint64_t lba, uint32_t count, uint8_t *buffer) {
|
||||
if (!ahci_initialized || port_num < 0 || port_num >= MAX_AHCI_PORTS) return -1;
|
||||
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
|
||||
port->is = 0xFFFFFFFF;
|
||||
|
||||
int slot = ahci_find_free_slot(port);
|
||||
if (slot < 0) return -1;
|
||||
|
||||
HBA_CMD_HEADER *cmd_hdr = &ps->cmd_list[slot];
|
||||
cmd_hdr->cfl = sizeof(FIS_REG_H2D) / sizeof(uint32_t);
|
||||
cmd_hdr->w = 0; // Read
|
||||
cmd_hdr->prdtl = 1;
|
||||
|
||||
HBA_CMD_TBL *cmd_tbl = ps->cmd_tbl;
|
||||
mem_memset(cmd_tbl, 0, sizeof(HBA_CMD_TBL) + sizeof(HBA_PRDT_ENTRY));
|
||||
|
||||
// Setup PRDT
|
||||
uint64_t buf_phys = v2p((uint64_t)buffer);
|
||||
cmd_tbl->prdt[0].dba = (uint32_t)(buf_phys & 0xFFFFFFFF);
|
||||
cmd_tbl->prdt[0].dbau = (uint32_t)(buf_phys >> 32);
|
||||
cmd_tbl->prdt[0].dbc = (count * 512) - 1; // 0-based byte count
|
||||
cmd_tbl->prdt[0].i = 1;
|
||||
|
||||
// Setup Command FIS
|
||||
FIS_REG_H2D *fis = (FIS_REG_H2D*)&cmd_tbl->cfis;
|
||||
fis->fis_type = FIS_TYPE_REG_H2D;
|
||||
fis->c = 1; // Command
|
||||
fis->command = ATA_CMD_READ_DMA_EX;
|
||||
|
||||
fis->lba0 = (uint8_t)(lba);
|
||||
fis->lba1 = (uint8_t)(lba >> 8);
|
||||
fis->lba2 = (uint8_t)(lba >> 16);
|
||||
fis->device = 1 << 6; // LBA mode
|
||||
fis->lba3 = (uint8_t)(lba >> 24);
|
||||
fis->lba4 = (uint8_t)(lba >> 32);
|
||||
fis->lba5 = (uint8_t)(lba >> 40);
|
||||
|
||||
fis->countl = (uint8_t)(count);
|
||||
fis->counth = (uint8_t)(count >> 8);
|
||||
|
||||
// Issue command
|
||||
port->ci = (1 << slot);
|
||||
|
||||
// Wait for completion
|
||||
int timeout = 1000000;
|
||||
while (timeout-- > 0) {
|
||||
if (!(port->ci & (1 << slot))) break;
|
||||
if (port->is & (1 << 30)) { // Task File Error
|
||||
serial_write("\n");
|
||||
spinlock_release_irqrestore(&ps->lock, rflags);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout <= 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
int ahci_write_sectors(int port_num, uint64_t lba, uint32_t count, const uint8_t *buffer) {
|
||||
if (!ahci_initialized || port_num < 0 || port_num >= MAX_AHCI_PORTS) return -1;
|
||||
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;
|
||||
|
||||
int slot = ahci_find_free_slot(port);
|
||||
if (slot < 0) return -1;
|
||||
|
||||
HBA_CMD_HEADER *cmd_hdr = &ps->cmd_list[slot];
|
||||
cmd_hdr->cfl = sizeof(FIS_REG_H2D) / sizeof(uint32_t);
|
||||
cmd_hdr->w = 1; // Write
|
||||
cmd_hdr->prdtl = 1;
|
||||
|
||||
HBA_CMD_TBL *cmd_tbl = ps->cmd_tbl;
|
||||
mem_memset(cmd_tbl, 0, sizeof(HBA_CMD_TBL) + sizeof(HBA_PRDT_ENTRY));
|
||||
|
||||
uint64_t buf_phys = v2p((uint64_t)buffer);
|
||||
cmd_tbl->prdt[0].dba = (uint32_t)(buf_phys & 0xFFFFFFFF);
|
||||
cmd_tbl->prdt[0].dbau = (uint32_t)(buf_phys >> 32);
|
||||
cmd_tbl->prdt[0].dbc = (count * 512) - 1;
|
||||
cmd_tbl->prdt[0].i = 1;
|
||||
|
||||
FIS_REG_H2D *fis = (FIS_REG_H2D*)&cmd_tbl->cfis;
|
||||
fis->fis_type = FIS_TYPE_REG_H2D;
|
||||
fis->c = 1;
|
||||
fis->command = ATA_CMD_WRITE_DMA_EX;
|
||||
|
||||
fis->lba0 = (uint8_t)(lba);
|
||||
fis->lba1 = (uint8_t)(lba >> 8);
|
||||
fis->lba2 = (uint8_t)(lba >> 16);
|
||||
fis->device = 1 << 6;
|
||||
fis->lba3 = (uint8_t)(lba >> 24);
|
||||
fis->lba4 = (uint8_t)(lba >> 32);
|
||||
fis->lba5 = (uint8_t)(lba >> 40);
|
||||
|
||||
fis->countl = (uint8_t)(count);
|
||||
fis->counth = (uint8_t)(count >> 8);
|
||||
|
||||
port->ci = (1 << slot);
|
||||
|
||||
int timeout = 1000000;
|
||||
while (timeout-- > 0) {
|
||||
if (!(port->ci & (1 << slot))) break;
|
||||
if (port->is & (1 << 30)) {
|
||||
serial_write("[AHCI] Write error on port ");
|
||||
serial_write_num(port_num);
|
||||
serial_write("\n");
|
||||
spinlock_release_irqrestore(&ps->lock, rflags);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout <= 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// AHCI Disk Integration — wrap AHCI into Disk read/write_sector
|
||||
// ============================================================================
|
||||
|
||||
typedef struct {
|
||||
int ahci_port;
|
||||
} AHCIDriverData;
|
||||
|
||||
static int ahci_disk_read_sector(Disk *disk, uint32_t sector, uint8_t *buffer) {
|
||||
AHCIDriverData *data = (AHCIDriverData*)disk->driver_data;
|
||||
|
||||
// For partitions, add offset and use parent's port
|
||||
if (disk->is_partition && disk->parent) {
|
||||
AHCIDriverData *pdata = (AHCIDriverData*)disk->parent->driver_data;
|
||||
return ahci_read_sectors(pdata->ahci_port,
|
||||
(uint64_t)sector + disk->partition_lba_offset, 1, buffer);
|
||||
}
|
||||
|
||||
return ahci_read_sectors(data->ahci_port, (uint64_t)sector, 1, buffer);
|
||||
}
|
||||
|
||||
static int ahci_disk_write_sector(Disk *disk, uint32_t sector, const uint8_t *buffer) {
|
||||
AHCIDriverData *data = (AHCIDriverData*)disk->driver_data;
|
||||
|
||||
if (disk->is_partition && disk->parent) {
|
||||
AHCIDriverData *pdata = (AHCIDriverData*)disk->parent->driver_data;
|
||||
return ahci_write_sectors(pdata->ahci_port,
|
||||
(uint64_t)sector + disk->partition_lba_offset, 1, buffer);
|
||||
}
|
||||
|
||||
return ahci_write_sectors(data->ahci_port, (uint64_t)sector, 1, buffer);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Initialization
|
||||
// ============================================================================
|
||||
|
||||
int ahci_get_port_count(void) {
|
||||
return active_port_count;
|
||||
}
|
||||
|
||||
bool ahci_port_is_active(int port_num) {
|
||||
if (port_num < 0 || port_num >= MAX_AHCI_PORTS) return false;
|
||||
return ports[port_num].active;
|
||||
}
|
||||
|
||||
void ahci_init(void) {
|
||||
serial_write("[AHCI] Scanning PCI for AHCI controller...\n");
|
||||
|
||||
// Find AHCI controller (Class 0x01, Subclass 0x06)
|
||||
pci_device_t pci_dev;
|
||||
if (!pci_find_device_by_class(PCI_CLASS_MASS_STORAGE, PCI_SUBCLASS_SATA, &pci_dev)) {
|
||||
serial_write("[AHCI] No AHCI controller found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
serial_write("[AHCI] Found AHCI controller (");
|
||||
serial_write("vendor=0x");
|
||||
serial_write_hex(pci_dev.vendor_id);
|
||||
serial_write(", device=0x");
|
||||
serial_write_hex(pci_dev.device_id);
|
||||
serial_write(")\n");
|
||||
|
||||
// Enable Bus Mastering and MMIO
|
||||
pci_enable_bus_mastering(&pci_dev);
|
||||
pci_enable_mmio(&pci_dev);
|
||||
|
||||
// Read ABAR (BAR5)
|
||||
uint32_t abar_raw = pci_get_bar(&pci_dev, 5);
|
||||
uint64_t abar_phys = abar_raw & 0xFFFFF000; // Mask out lower bits
|
||||
|
||||
if (abar_phys == 0) {
|
||||
serial_write("[AHCI] Invalid ABAR address\n");
|
||||
return;
|
||||
}
|
||||
|
||||
serial_write("[AHCI] ABAR physical address: 0x");
|
||||
serial_write_hex((uint32_t)abar_phys);
|
||||
serial_write("\n");
|
||||
|
||||
// Map ABAR region into kernel virtual address space
|
||||
// Identity-map several pages to cover the HBA memory (at least 0x1100 bytes)
|
||||
uint64_t abar_virt = abar_phys; // Use identity mapping
|
||||
for (uint64_t offset = 0; offset < 0x2000; offset += 4096) {
|
||||
paging_map_page(paging_get_pml4_phys(), abar_virt + offset,
|
||||
abar_phys + offset,
|
||||
PT_PRESENT | PT_RW | PT_CACHE_DISABLE);
|
||||
}
|
||||
|
||||
abar = (HBA_MEM*)abar_virt;
|
||||
|
||||
// Enable AHCI mode
|
||||
abar->ghc |= (1 << 31); // AE (AHCI Enable)
|
||||
|
||||
serial_write("[AHCI] Version: ");
|
||||
serial_write_num(abar->vs >> 16);
|
||||
serial_write(".");
|
||||
serial_write_num(abar->vs & 0xFFFF);
|
||||
serial_write("\n");
|
||||
|
||||
// Probe ports
|
||||
uint32_t pi = abar->pi;
|
||||
active_port_count = 0;
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
ports[i].active = false;
|
||||
|
||||
HBA_PORT *port = &abar->ports[i];
|
||||
ports[i].lock = SPINLOCK_INIT;
|
||||
int type = ahci_check_port_type(port);
|
||||
|
||||
if (type == 0) { // SATA drive
|
||||
serial_write("[AHCI] Port ");
|
||||
serial_write_num(i);
|
||||
serial_write(": SATA drive detected\n");
|
||||
|
||||
ports[i].port_num = i;
|
||||
ports[i].port = port;
|
||||
ahci_port_rebase(&ports[i]);
|
||||
ports[i].active = true;
|
||||
active_port_count++;
|
||||
|
||||
// Register as a block device
|
||||
Disk *disk = (Disk*)kmalloc(sizeof(Disk));
|
||||
if (disk) {
|
||||
AHCIDriverData *drv = (AHCIDriverData*)kmalloc(sizeof(AHCIDriverData));
|
||||
drv->ahci_port = i;
|
||||
|
||||
disk->devname[0] = 0; // Auto-assign
|
||||
disk->type = DISK_TYPE_SATA;
|
||||
ahci_strcpy(disk->label, "SATA Drive");
|
||||
disk->read_sector = ahci_disk_read_sector;
|
||||
disk->write_sector = ahci_disk_write_sector;
|
||||
disk->driver_data = drv;
|
||||
disk->partition_lba_offset = 0;
|
||||
disk->total_sectors = 0;
|
||||
disk->parent = NULL;
|
||||
disk->is_partition = false;
|
||||
disk->is_fat32 = false;
|
||||
|
||||
disk_register(disk);
|
||||
|
||||
// Let disk_manager parse partitions — we call a scan function
|
||||
extern void disk_manager_scan_partitions(Disk *disk);
|
||||
// Inline MBR parse for this disk
|
||||
extern void serial_write(const char *str);
|
||||
serial_write("[AHCI] Probing partitions on /dev/");
|
||||
serial_write(disk->devname);
|
||||
serial_write("...\n");
|
||||
|
||||
// Read MBR sector 0
|
||||
uint8_t *mbr_buf = (uint8_t*)kmalloc(512);
|
||||
if (mbr_buf) {
|
||||
if (ahci_disk_read_sector(disk, 0, mbr_buf) == 0) {
|
||||
if (mbr_buf[510] == 0x55 && mbr_buf[511] == 0xAA) {
|
||||
// Parse MBR partition table
|
||||
typedef struct {
|
||||
uint8_t status;
|
||||
uint8_t chs_first[3];
|
||||
uint8_t type;
|
||||
uint8_t chs_last[3];
|
||||
uint32_t lba_start;
|
||||
uint32_t sector_count;
|
||||
} __attribute__((packed)) MBR_Part;
|
||||
|
||||
MBR_Part *parts = (MBR_Part*)&mbr_buf[446];
|
||||
int pn = 1;
|
||||
for (int p = 0; p < 4; p++) {
|
||||
if (parts[p].type == 0x00 || parts[p].sector_count == 0)
|
||||
continue;
|
||||
|
||||
bool fat32 = false;
|
||||
if (parts[p].type == 0x0B || parts[p].type == 0x0C) {
|
||||
// Verify BPB
|
||||
uint8_t *pbuf = (uint8_t*)kmalloc(512);
|
||||
if (pbuf) {
|
||||
if (ahci_disk_read_sector(disk, parts[p].lba_start, pbuf) == 0) {
|
||||
if (pbuf[510] == 0x55 && pbuf[511] == 0xAA) {
|
||||
uint16_t bps = *(uint16_t*)&pbuf[11];
|
||||
uint16_t spf16 = *(uint16_t*)&pbuf[22];
|
||||
uint32_t spf32 = *(uint32_t*)&pbuf[36];
|
||||
if (bps == 512 && spf16 == 0 && spf32 > 0)
|
||||
fat32 = true;
|
||||
}
|
||||
}
|
||||
kfree(pbuf);
|
||||
}
|
||||
}
|
||||
|
||||
disk_register_partition(disk, parts[p].lba_start,
|
||||
parts[p].sector_count, fat32, pn);
|
||||
pn++;
|
||||
}
|
||||
|
||||
// Fallback: raw FAT32
|
||||
if (pn == 1) {
|
||||
uint16_t bps = *(uint16_t*)&mbr_buf[11];
|
||||
uint16_t spf16 = *(uint16_t*)&mbr_buf[22];
|
||||
uint32_t spf32 = *(uint32_t*)&mbr_buf[36];
|
||||
if (bps == 512 && spf16 == 0 && spf32 > 0) {
|
||||
disk->is_fat32 = true;
|
||||
disk->partition_lba_offset = 0;
|
||||
serial_write("[AHCI] Raw FAT32 volume detected\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
kfree(mbr_buf);
|
||||
}
|
||||
}
|
||||
} else if (type == 1) {
|
||||
serial_write("[AHCI] Port ");
|
||||
serial_write_num(i);
|
||||
serial_write(": SATAPI drive (ignored)\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (active_port_count > 0) {
|
||||
ahci_initialized = true;
|
||||
serial_write("[AHCI] Initialization complete: ");
|
||||
serial_write_num(active_port_count);
|
||||
serial_write(" SATA port(s) active\n");
|
||||
} else {
|
||||
serial_write("[AHCI] No active SATA ports found\n");
|
||||
}
|
||||
}
|
||||
174
src/dev/ahci.h
Normal file
174
src/dev/ahci.h
Normal file
@@ -0,0 +1,174 @@
|
||||
// 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 AHCI_H
|
||||
#define AHCI_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// ============================================================================
|
||||
// FIS (Frame Information Structure) Types
|
||||
// ============================================================================
|
||||
|
||||
typedef enum {
|
||||
FIS_TYPE_REG_H2D = 0x27, // Register FIS — Host to Device
|
||||
FIS_TYPE_REG_D2H = 0x34, // Register FIS — Device to Host
|
||||
FIS_TYPE_DMA_ACT = 0x39, // DMA Activate FIS
|
||||
FIS_TYPE_DMA_SETUP = 0x41, // DMA Setup FIS
|
||||
FIS_TYPE_DATA = 0x46, // Data FIS
|
||||
FIS_TYPE_BIST = 0x58, // BIST Activate FIS
|
||||
FIS_TYPE_PIO_SETUP = 0x5F, // PIO Setup FIS
|
||||
FIS_TYPE_DEV_BITS = 0xA1, // Set Device Bits FIS
|
||||
} FIS_TYPE;
|
||||
|
||||
// ============================================================================
|
||||
// HBA Register Structures (MMIO-mapped from ABAR)
|
||||
// ============================================================================
|
||||
|
||||
// Port Registers (one set per port, at ABAR + 0x100 + portno*0x80)
|
||||
typedef volatile struct {
|
||||
uint32_t clb; // 0x00: Command List Base Address (lower 32 bits)
|
||||
uint32_t clbu; // 0x04: Command List Base Address (upper 32 bits)
|
||||
uint32_t fb; // 0x08: FIS Base Address (lower 32 bits)
|
||||
uint32_t fbu; // 0x0C: FIS Base Address (upper 32 bits)
|
||||
uint32_t is; // 0x10: Interrupt Status
|
||||
uint32_t ie; // 0x14: Interrupt Enable
|
||||
uint32_t cmd; // 0x18: Command and Status
|
||||
uint32_t rsv0; // 0x1C: Reserved
|
||||
uint32_t tfd; // 0x20: Task File Data
|
||||
uint32_t sig; // 0x24: Signature
|
||||
uint32_t ssts; // 0x28: SATA Status (SStatus)
|
||||
uint32_t sctl; // 0x2C: SATA Control (SControl)
|
||||
uint32_t serr; // 0x30: SATA Error (SError)
|
||||
uint32_t sact; // 0x34: SATA Active (SCR3)
|
||||
uint32_t ci; // 0x38: Command Issue
|
||||
uint32_t sntf; // 0x3C: SATA Notification (SCR4)
|
||||
uint32_t fbs; // 0x40: FIS-based Switch Control
|
||||
uint32_t rsv1[11]; // 0x44~0x6F
|
||||
uint32_t vendor[4]; // 0x70~0x7F
|
||||
} HBA_PORT;
|
||||
|
||||
// Global HBA Memory Registers (at ABAR)
|
||||
typedef volatile struct {
|
||||
uint32_t cap; // 0x00: Host Capability
|
||||
uint32_t ghc; // 0x04: Global Host Control
|
||||
uint32_t is; // 0x08: Interrupt Status
|
||||
uint32_t pi; // 0x0C: Port Implemented
|
||||
uint32_t vs; // 0x10: Version
|
||||
uint32_t ccc_ctl; // 0x14: Command Completion Coalescing Control
|
||||
uint32_t ccc_pts; // 0x18: Command Completion Coalescing Ports
|
||||
uint32_t em_loc; // 0x1C: Enclosure Management Location
|
||||
uint32_t em_ctl; // 0x20: Enclosure Management Control
|
||||
uint32_t cap2; // 0x24: Host Capabilities Extended
|
||||
uint32_t bohc; // 0x28: BIOS/OS Handoff Control and Status
|
||||
uint8_t rsv[0xA0 - 0x2C];
|
||||
uint8_t vendor[0x100 - 0xA0];
|
||||
HBA_PORT ports[]; // Port 0 at offset 0x100 (flexible array member)
|
||||
} HBA_MEM;
|
||||
|
||||
// ============================================================================
|
||||
// Command List / Table Structures (DMA)
|
||||
// ============================================================================
|
||||
|
||||
// Command Header (32 bytes each, 32 entries per port = 1KB)
|
||||
typedef struct {
|
||||
uint8_t cfl:5; // Command FIS Length (in DWORDs)
|
||||
uint8_t a:1; // ATAPI
|
||||
uint8_t w:1; // Write (1=H2D, 0=D2H)
|
||||
uint8_t p:1; // Prefetchable
|
||||
|
||||
uint8_t r:1; // Reset
|
||||
uint8_t b:1; // BIST
|
||||
uint8_t c:1; // Clear Busy upon R_OK
|
||||
uint8_t rsv0:1;
|
||||
uint8_t pmp:4; // Port Multiplier Port
|
||||
|
||||
uint16_t prdtl; // Physical Region Descriptor Table Length (entries)
|
||||
|
||||
volatile uint32_t prdbc; // PRD Byte Count transferred
|
||||
|
||||
uint32_t ctba; // Command Table Descriptor Base Address (lower 32)
|
||||
uint32_t ctbau; // Command Table Descriptor Base Address (upper 32)
|
||||
|
||||
uint32_t rsv1[4]; // Reserved
|
||||
} __attribute__((packed)) HBA_CMD_HEADER;
|
||||
|
||||
// Physical Region Descriptor Table Entry
|
||||
typedef struct {
|
||||
uint32_t dba; // Data Base Address (lower 32)
|
||||
uint32_t dbau; // Data Base Address (upper 32)
|
||||
uint32_t rsv0; // Reserved
|
||||
uint32_t dbc:22; // Byte Count (0-based, max 4MB)
|
||||
uint32_t rsv1:9; // Reserved
|
||||
uint32_t i:1; // Interrupt on Completion
|
||||
} __attribute__((packed)) HBA_PRDT_ENTRY;
|
||||
|
||||
// Host-to-Device Register FIS
|
||||
typedef struct {
|
||||
uint8_t fis_type; // FIS_TYPE_REG_H2D
|
||||
uint8_t pmport:4; // Port Multiplier
|
||||
uint8_t rsv0:3; // Reserved
|
||||
uint8_t c:1; // 1=Command, 0=Control
|
||||
uint8_t command; // Command register
|
||||
uint8_t featurel; // Feature register (7:0)
|
||||
uint8_t lba0; // LBA (7:0)
|
||||
uint8_t lba1; // LBA (15:8)
|
||||
uint8_t lba2; // LBA (23:16)
|
||||
uint8_t device; // Device register
|
||||
uint8_t lba3; // LBA (31:24)
|
||||
uint8_t lba4; // LBA (39:32)
|
||||
uint8_t lba5; // LBA (47:40)
|
||||
uint8_t featureh; // Feature register (15:8)
|
||||
uint8_t countl; // Count (7:0)
|
||||
uint8_t counth; // Count (15:8)
|
||||
uint8_t icc; // Isochronous Command Completion
|
||||
uint8_t control; // Control register
|
||||
uint8_t rsv1[4]; // Reserved
|
||||
} __attribute__((packed)) FIS_REG_H2D;
|
||||
|
||||
// Command Table (256-byte aligned)
|
||||
typedef struct {
|
||||
uint8_t cfis[64]; // Command FIS
|
||||
uint8_t acmd[16]; // ATAPI Command
|
||||
uint8_t rsv[48]; // Reserved
|
||||
HBA_PRDT_ENTRY prdt[]; // PRDT entries (variable, at least 1)
|
||||
} __attribute__((packed)) HBA_CMD_TBL;
|
||||
|
||||
// ============================================================================
|
||||
// Port Signature Values
|
||||
// ============================================================================
|
||||
|
||||
#define SATA_SIG_ATA 0x00000101 // SATA drive
|
||||
#define SATA_SIG_ATAPI 0xEB140101 // SATAPI drive
|
||||
#define SATA_SIG_SEMB 0xC33C0101 // Enclosure management bridge
|
||||
#define SATA_SIG_PM 0x96690101 // Port multiplier
|
||||
|
||||
// ============================================================================
|
||||
// Port Command Bits
|
||||
// ============================================================================
|
||||
|
||||
#define HBA_PORT_CMD_ST 0x0001 // Start
|
||||
#define HBA_PORT_CMD_FRE 0x0010 // FIS Receive Enable
|
||||
#define HBA_PORT_CMD_FR 0x4000 // FIS Receive Running
|
||||
#define HBA_PORT_CMD_CR 0x8000 // Command List Running
|
||||
|
||||
// ============================================================================
|
||||
// ATA Commands
|
||||
// ============================================================================
|
||||
|
||||
#define ATA_CMD_READ_DMA_EX 0x25
|
||||
#define ATA_CMD_WRITE_DMA_EX 0x35
|
||||
#define ATA_CMD_IDENTIFY 0xEC
|
||||
|
||||
// ============================================================================
|
||||
// Public API
|
||||
// ============================================================================
|
||||
|
||||
void ahci_init(void);
|
||||
int ahci_read_sectors(int port_num, uint64_t lba, uint32_t count, uint8_t *buffer);
|
||||
int ahci_write_sectors(int port_num, uint64_t lba, uint32_t count, const uint8_t *buffer);
|
||||
int ahci_get_port_count(void);
|
||||
bool ahci_port_is_active(int port_num);
|
||||
|
||||
#endif
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#define SECTOR_SIZE 512
|
||||
#define MAX_DISKS 16
|
||||
|
||||
typedef enum {
|
||||
DISK_TYPE_RAM,
|
||||
@@ -17,11 +18,12 @@ typedef enum {
|
||||
} DiskType;
|
||||
|
||||
typedef struct Disk {
|
||||
char letter;
|
||||
char devname[16]; // Device name: "sda", "sdb", "sda1", etc.
|
||||
DiskType type;
|
||||
bool is_fat32;
|
||||
char name[32];
|
||||
uint32_t partition_lba_offset; // LBA offset of FAT32 partition (0 for raw)
|
||||
char label[32]; // Human-readable label
|
||||
uint32_t partition_lba_offset; // LBA offset of partition (0 for whole disk)
|
||||
uint32_t total_sectors; // Total sectors on this device/partition
|
||||
|
||||
// Function pointers for driver operations
|
||||
int (*read_sector)(struct Disk *disk, uint32_t sector, uint8_t *buffer);
|
||||
@@ -29,14 +31,32 @@ typedef struct Disk {
|
||||
|
||||
// Private driver data
|
||||
void *driver_data;
|
||||
|
||||
// Parent disk (for partitions — points to the whole-disk Disk)
|
||||
struct Disk *parent;
|
||||
bool is_partition;
|
||||
bool registered;
|
||||
} Disk;
|
||||
|
||||
// Initialization and scanning
|
||||
void disk_manager_init(void);
|
||||
void disk_manager_scan(void); // Scans for new disks
|
||||
Disk* disk_get_by_letter(char letter);
|
||||
char disk_get_next_free_letter(void);
|
||||
void disk_manager_scan(void);
|
||||
|
||||
// Device registration
|
||||
void disk_register(Disk *disk);
|
||||
void disk_register_partition(Disk *parent, uint32_t lba_offset, uint32_t sector_count,
|
||||
bool is_fat32, int part_num);
|
||||
|
||||
// Lookup
|
||||
Disk* disk_get_by_name(const char *devname);
|
||||
int disk_get_count(void);
|
||||
Disk* disk_get_by_index(int index);
|
||||
|
||||
// Auto-naming helpers
|
||||
const char* disk_get_next_dev_name(void); // Returns "sda", "sdb", etc.
|
||||
|
||||
// Backward compat (deprecated — wraps disk_get_by_name)
|
||||
Disk* disk_get_by_letter(char letter);
|
||||
char disk_get_next_free_letter(void);
|
||||
|
||||
#endif
|
||||
525
src/dev/disk_manager.c
Normal file
525
src/dev/disk_manager.c
Normal file
@@ -0,0 +1,525 @@
|
||||
// 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 "disk.h"
|
||||
#include "pci.h"
|
||||
#include "memory_manager.h"
|
||||
#include "io.h"
|
||||
#include "wm.h"
|
||||
#include "ahci.h"
|
||||
#include "../fs/vfs.h"
|
||||
#include "../fs/fat32.h"
|
||||
#include "../sys/spinlock.h"
|
||||
#include <stddef.h>
|
||||
|
||||
static spinlock_t ide_lock = SPINLOCK_INIT;
|
||||
|
||||
static Disk *disks[MAX_DISKS];
|
||||
static int disk_count = 0;
|
||||
static int next_drive_letter_idx = 0; // For backward compat
|
||||
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 ===
|
||||
|
||||
static void dm_strcpy(char *dest, const char *src) {
|
||||
while (*src) *dest++ = *src++;
|
||||
*dest = 0;
|
||||
}
|
||||
|
||||
static int dm_strcmp(const char *a, const char *b) {
|
||||
while (*a && *a == *b) { a++; b++; }
|
||||
return (unsigned char)*a - (unsigned char)*b;
|
||||
}
|
||||
|
||||
static int dm_strlen(const char *s) {
|
||||
int n = 0;
|
||||
while (s[n]) n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
// === ATA Definitions (Legacy IDE PIO — kept as fallback) ===
|
||||
|
||||
#define ATA_PRIMARY_IO 0x1F0
|
||||
#define ATA_PRIMARY_CTRL 0x3F6
|
||||
#define ATA_SECONDARY_IO 0x170
|
||||
#define ATA_SECONDARY_CTRL 0x376
|
||||
|
||||
#define ATA_REG_DATA 0x00
|
||||
#define ATA_REG_ERROR 0x01
|
||||
#define ATA_REG_FEATURES 0x01
|
||||
#define ATA_REG_SEC_COUNT0 0x02
|
||||
#define ATA_REG_LBA0 0x03
|
||||
#define ATA_REG_LBA1 0x04
|
||||
#define ATA_REG_LBA2 0x05
|
||||
#define ATA_REG_HDDEVSEL 0x06
|
||||
#define ATA_REG_COMMAND 0x07
|
||||
#define ATA_REG_STATUS 0x07
|
||||
|
||||
#define ATA_CMD_READ_PIO 0x20
|
||||
#define ATA_CMD_WRITE_PIO 0x30
|
||||
#define ATA_CMD_IDENTIFY 0xEC
|
||||
|
||||
#define ATA_SR_BSY 0x80
|
||||
#define ATA_SR_DRDY 0x40
|
||||
#define ATA_SR_DF 0x20
|
||||
#define ATA_SR_DSC 0x10
|
||||
#define ATA_SR_DRQ 0x08
|
||||
#define ATA_SR_CORR 0x04
|
||||
#define ATA_SR_IDX 0x02
|
||||
#define ATA_SR_ERR 0x01
|
||||
|
||||
typedef struct {
|
||||
uint16_t port_base;
|
||||
bool slave;
|
||||
} ATADriverData;
|
||||
|
||||
// === ATA PIO Driver ===
|
||||
|
||||
static int ata_wait_bsy(uint16_t port_base) {
|
||||
int timeout = 10000000;
|
||||
while ((inb(port_base + ATA_REG_STATUS) & ATA_SR_BSY) && --timeout > 0);
|
||||
return timeout <= 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
static int ata_wait_drq(uint16_t port_base) {
|
||||
int timeout = 10000000;
|
||||
while (!(inb(port_base + ATA_REG_STATUS) & (ATA_SR_DRQ | ATA_SR_ERR)) && --timeout > 0);
|
||||
if (timeout <= 0 || (inb(port_base + ATA_REG_STATUS) & ATA_SR_ERR)) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ata_identify(uint16_t port_base, bool slave) {
|
||||
outb(port_base + ATA_REG_HDDEVSEL, slave ? 0xB0 : 0xA0);
|
||||
outb(port_base + ATA_REG_SEC_COUNT0, 0);
|
||||
outb(port_base + ATA_REG_LBA0, 0);
|
||||
outb(port_base + ATA_REG_LBA1, 0);
|
||||
outb(port_base + ATA_REG_LBA2, 0);
|
||||
|
||||
outb(port_base + ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
|
||||
|
||||
uint8_t status = inb(port_base + ATA_REG_STATUS);
|
||||
if (status == 0) return 0;
|
||||
|
||||
int timeout = 10000;
|
||||
while ((inb(port_base + ATA_REG_STATUS) & ATA_SR_BSY) && --timeout > 0) {
|
||||
status = inb(port_base + ATA_REG_STATUS);
|
||||
if (status == 0) return 0;
|
||||
}
|
||||
if (timeout <= 0) return 0;
|
||||
|
||||
if (inb(port_base + ATA_REG_STATUS) & ATA_SR_ERR) return 0;
|
||||
|
||||
if (ata_wait_drq(port_base) != 0) return 0;
|
||||
|
||||
if (inb(port_base + ATA_REG_STATUS) & ATA_SR_ERR) return 0;
|
||||
|
||||
uint32_t sectors = 0;
|
||||
for (int i = 0; i < 256; i++) {
|
||||
uint16_t data = inw(port_base + ATA_REG_DATA);
|
||||
if (i == 60) sectors |= (uint32_t)data;
|
||||
if (i == 61) sectors |= (uint32_t)data << 16;
|
||||
}
|
||||
|
||||
return sectors;
|
||||
}
|
||||
|
||||
static int ata_read_sector(Disk *disk, uint32_t lba, uint8_t *buffer) {
|
||||
ATADriverData *data = (ATADriverData*)disk->driver_data;
|
||||
uint16_t port_base = data->port_base;
|
||||
bool slave = data->slave;
|
||||
|
||||
// For partition reads, add the partition LBA offset
|
||||
if (disk->is_partition && disk->parent) {
|
||||
lba += disk->partition_lba_offset;
|
||||
// Use parent's driver
|
||||
data = (ATADriverData*)disk->parent->driver_data;
|
||||
port_base = data->port_base;
|
||||
slave = data->slave;
|
||||
}
|
||||
|
||||
uint64_t flags = spinlock_acquire_irqsave(&ide_lock);
|
||||
|
||||
if (ata_wait_bsy(port_base) != 0) {
|
||||
spinlock_release_irqrestore(&ide_lock, flags);
|
||||
return -1;
|
||||
}
|
||||
|
||||
outb(port_base + ATA_REG_HDDEVSEL, 0xE0 | (slave << 4) | ((lba >> 24) & 0x0F));
|
||||
outb(port_base + ATA_REG_FEATURES, 0x00);
|
||||
outb(port_base + ATA_REG_SEC_COUNT0, 1);
|
||||
outb(port_base + ATA_REG_LBA0, (uint8_t)(lba));
|
||||
outb(port_base + ATA_REG_LBA1, (uint8_t)(lba >> 8));
|
||||
outb(port_base + ATA_REG_LBA2, (uint8_t)(lba >> 16));
|
||||
outb(port_base + ATA_REG_COMMAND, ATA_CMD_READ_PIO);
|
||||
|
||||
if (ata_wait_bsy(port_base) != 0) {
|
||||
spinlock_release_irqrestore(&ide_lock, flags);
|
||||
return -1;
|
||||
}
|
||||
if (ata_wait_drq(port_base) != 0) {
|
||||
spinlock_release_irqrestore(&ide_lock, flags);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint16_t *ptr = (uint16_t*)buffer;
|
||||
for (int i = 0; i < 256; i++) {
|
||||
ptr[i] = inw(port_base + ATA_REG_DATA);
|
||||
}
|
||||
|
||||
spinlock_release_irqrestore(&ide_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ata_write_sector(Disk *disk, uint32_t lba, const uint8_t *buffer) {
|
||||
ATADriverData *data = (ATADriverData*)disk->driver_data;
|
||||
uint16_t port_base = data->port_base;
|
||||
bool slave = data->slave;
|
||||
|
||||
// For partition writes, add the partition LBA offset
|
||||
if (disk->is_partition && disk->parent) {
|
||||
lba += disk->partition_lba_offset;
|
||||
data = (ATADriverData*)disk->parent->driver_data;
|
||||
port_base = data->port_base;
|
||||
slave = data->slave;
|
||||
}
|
||||
|
||||
uint64_t flags = spinlock_acquire_irqsave(&ide_lock);
|
||||
|
||||
if (ata_wait_bsy(port_base) != 0) {
|
||||
spinlock_release_irqrestore(&ide_lock, flags);
|
||||
return -1;
|
||||
}
|
||||
|
||||
outb(port_base + ATA_REG_HDDEVSEL, 0xE0 | (slave << 4) | ((lba >> 24) & 0x0F));
|
||||
outb(port_base + ATA_REG_FEATURES, 0x00);
|
||||
outb(port_base + ATA_REG_SEC_COUNT0, 1);
|
||||
outb(port_base + ATA_REG_LBA0, (uint8_t)(lba));
|
||||
outb(port_base + ATA_REG_LBA1, (uint8_t)(lba >> 8));
|
||||
outb(port_base + ATA_REG_LBA2, (uint8_t)(lba >> 16));
|
||||
outb(port_base + ATA_REG_COMMAND, ATA_CMD_WRITE_PIO);
|
||||
|
||||
if (ata_wait_bsy(port_base) != 0) {
|
||||
spinlock_release_irqrestore(&ide_lock, flags);
|
||||
return -1;
|
||||
}
|
||||
if (ata_wait_drq(port_base) != 0) {
|
||||
spinlock_release_irqrestore(&ide_lock, flags);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint16_t *ptr = (const uint16_t*)buffer;
|
||||
for (int i = 0; i < 256; i++) {
|
||||
outw(port_base + ATA_REG_DATA, ptr[i]);
|
||||
}
|
||||
|
||||
outb(port_base + ATA_REG_COMMAND, 0xE7); // Cache Flush
|
||||
if (ata_wait_bsy(port_base) != 0) {
|
||||
spinlock_release_irqrestore(&ide_lock, flags);
|
||||
return -1;
|
||||
}
|
||||
|
||||
spinlock_release_irqrestore(&ide_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// === Device Naming ===
|
||||
|
||||
const char* disk_get_next_dev_name(void) {
|
||||
static char name[8];
|
||||
name[0] = 's';
|
||||
name[1] = 'd';
|
||||
name[2] = 'a' + next_sd_index;
|
||||
name[3] = 0;
|
||||
next_sd_index++;
|
||||
return name;
|
||||
}
|
||||
|
||||
// === Registration ===
|
||||
|
||||
void disk_register(Disk *disk) {
|
||||
if (disk_count >= MAX_DISKS) return;
|
||||
|
||||
// Auto-assign devname if empty
|
||||
if (disk->devname[0] == 0) {
|
||||
const char *n = disk_get_next_dev_name();
|
||||
dm_strcpy(disk->devname, n);
|
||||
}
|
||||
|
||||
disk->registered = true;
|
||||
disks[disk_count++] = disk;
|
||||
|
||||
serial_write("[DISK] Registered /dev/");
|
||||
serial_write(disk->devname);
|
||||
serial_write(" (");
|
||||
serial_write(disk->label);
|
||||
serial_write(")\n");
|
||||
}
|
||||
|
||||
void disk_register_partition(Disk *parent, uint32_t lba_offset, uint32_t sector_count,
|
||||
bool is_fat32, int part_num) {
|
||||
if (disk_count >= MAX_DISKS) return;
|
||||
|
||||
Disk *part = (Disk*)kmalloc(sizeof(Disk));
|
||||
if (!part) return;
|
||||
|
||||
// Build name: parent_devname + partition number (e.g. "sda1")
|
||||
int len = dm_strlen(parent->devname);
|
||||
for (int i = 0; i < len; i++) part->devname[i] = parent->devname[i];
|
||||
part->devname[len] = '0' + part_num;
|
||||
part->devname[len + 1] = 0;
|
||||
|
||||
part->type = parent->type;
|
||||
part->is_fat32 = is_fat32;
|
||||
dm_strcpy(part->label, is_fat32 ? "FAT32 Partition" : "Unknown Partition");
|
||||
part->partition_lba_offset = lba_offset;
|
||||
part->total_sectors = sector_count;
|
||||
part->read_sector = parent->read_sector;
|
||||
part->write_sector = parent->write_sector;
|
||||
part->driver_data = parent->driver_data;
|
||||
part->parent = parent;
|
||||
part->is_partition = true;
|
||||
part->registered = true;
|
||||
|
||||
disks[disk_count++] = part;
|
||||
|
||||
serial_write("[DISK] Registered /dev/");
|
||||
serial_write(part->devname);
|
||||
serial_write(" (LBA offset ");
|
||||
serial_write_num(lba_offset);
|
||||
serial_write(", ");
|
||||
serial_write_num(sector_count);
|
||||
serial_write(" sectors, FAT32=");
|
||||
serial_write(" sectors, FAT32=");
|
||||
serial_write(is_fat32 ? "yes" : "no");
|
||||
serial_write(")\n");
|
||||
|
||||
if (is_fat32) {
|
||||
// Try to initialize and mount FAT32 volume to VFS
|
||||
void *vol = fat32_mount_volume(part);
|
||||
if (vol) {
|
||||
char mount_path[32];
|
||||
mount_path[0] = '/';
|
||||
mount_path[1] = 'd'; mount_path[2] = 'e'; mount_path[3] = 'v'; mount_path[4] = '/';
|
||||
dm_strcpy(mount_path + 5, part->devname);
|
||||
|
||||
if (vfs_mount(mount_path, part->devname, "fat32", fat32_get_realfs_ops(), vol)) {
|
||||
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 {
|
||||
char fail_msg[64];
|
||||
dm_strcpy(fail_msg, "Failed to mount ");
|
||||
dm_strcpy(fail_msg + 16, mount_path);
|
||||
log_fail(fail_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// === Lookup ===
|
||||
|
||||
Disk* disk_get_by_name(const char *devname) {
|
||||
if (!devname) return NULL;
|
||||
for (int i = 0; i < disk_count; i++) {
|
||||
if (dm_strcmp(disks[i]->devname, devname) == 0) {
|
||||
return disks[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int disk_get_count(void) {
|
||||
return disk_count;
|
||||
}
|
||||
|
||||
Disk* disk_get_by_index(int index) {
|
||||
if (index < 0 || index >= disk_count) return NULL;
|
||||
return disks[index];
|
||||
}
|
||||
|
||||
// === Backward Compat (deprecated) ===
|
||||
|
||||
char disk_get_next_free_letter(void) {
|
||||
char letter = 'B' + next_drive_letter_idx++;
|
||||
if (letter > 'Z') return 0;
|
||||
return letter;
|
||||
}
|
||||
|
||||
Disk* disk_get_by_letter(char letter) {
|
||||
// Maps old letter scheme: A=ramfs (not a block device), B+=first real disk, etc.
|
||||
if (letter >= 'a' && letter <= 'z') letter -= 32;
|
||||
|
||||
// A: was the ramdisk — return NULL since ramfs is now VFS-managed
|
||||
if (letter == 'A') return NULL;
|
||||
|
||||
// B-Z map to disk indices 0, 1, 2...
|
||||
// Find real disks (non-RAM, non-partition-parent)
|
||||
int real_idx = 0;
|
||||
for (int i = 0; i < disk_count; i++) {
|
||||
if (disks[i]->is_partition && disks[i]->is_fat32) {
|
||||
if (real_idx == (letter - 'B')) {
|
||||
return disks[i];
|
||||
}
|
||||
real_idx++;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// === MBR Partition Table ===
|
||||
|
||||
typedef struct {
|
||||
uint8_t status;
|
||||
uint8_t chs_first[3];
|
||||
uint8_t type;
|
||||
uint8_t chs_last[3];
|
||||
uint32_t lba_start;
|
||||
uint32_t sector_count;
|
||||
} __attribute__((packed)) MBR_PartitionEntry;
|
||||
|
||||
#define PART_TYPE_FAT32 0x0B
|
||||
#define PART_TYPE_FAT32_LBA 0x0C
|
||||
|
||||
static bool is_fat32_bpb(const uint8_t *sector) {
|
||||
if (sector[510] != 0x55 || sector[511] != 0xAA) return false;
|
||||
|
||||
if (sector[82] == 'F' && sector[83] == 'A' && sector[84] == 'T' &&
|
||||
sector[85] == '3' && sector[86] == '2') {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t bps = *(uint16_t*)§or[11];
|
||||
uint16_t spf16 = *(uint16_t*)§or[22];
|
||||
uint32_t spf32 = *(uint32_t*)§or[36];
|
||||
if (bps == 512 && spf16 == 0 && spf32 > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse MBR and register each partition as a child block device
|
||||
static void parse_mbr_partitions(Disk *disk) {
|
||||
uint8_t *buffer = (uint8_t*)kmalloc(512);
|
||||
if (!buffer) return;
|
||||
|
||||
if (disk->read_sector(disk, 0, buffer) != 0) {
|
||||
kfree(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for valid MBR signature
|
||||
if (buffer[510] != 0x55 || buffer[511] != 0xAA) {
|
||||
kfree(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
MBR_PartitionEntry *partitions = (MBR_PartitionEntry*)&buffer[446];
|
||||
int part_num = 1;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
uint32_t start = partitions[i].lba_start;
|
||||
uint32_t size = partitions[i].sector_count;
|
||||
uint8_t type = partitions[i].type;
|
||||
|
||||
if (type == 0x00) continue; // Empty entry
|
||||
if (size == 0) continue;
|
||||
if (start >= disk->total_sectors) continue; // Invalid start
|
||||
|
||||
bool fat32 = false;
|
||||
if (type == PART_TYPE_FAT32 || type == PART_TYPE_FAT32_LBA) {
|
||||
// Verify by reading the BPB
|
||||
uint8_t *pbuf = (uint8_t*)kmalloc(512);
|
||||
if (pbuf) {
|
||||
if (disk->read_sector(disk, start, pbuf) == 0) {
|
||||
fat32 = is_fat32_bpb(pbuf);
|
||||
}
|
||||
kfree(pbuf);
|
||||
}
|
||||
}
|
||||
|
||||
disk_register_partition(disk, partitions[i].lba_start,
|
||||
partitions[i].sector_count, fat32, part_num);
|
||||
part_num++;
|
||||
}
|
||||
|
||||
// Fallback: if no partitions found, check if entire disk is a raw FAT32 volume
|
||||
if (part_num == 1 && is_fat32_bpb(buffer)) {
|
||||
serial_write("[DISK] No MBR partitions — raw FAT32 volume on /dev/");
|
||||
serial_write(disk->devname);
|
||||
serial_write("\n");
|
||||
disk->is_fat32 = true;
|
||||
disk->partition_lba_offset = 0;
|
||||
}
|
||||
|
||||
kfree(buffer);
|
||||
}
|
||||
|
||||
// === ATA Drive Discovery ===
|
||||
|
||||
static void try_add_ata_drive(uint16_t port, bool slave, const char *name) {
|
||||
uint32_t sectors = ata_identify(port, slave);
|
||||
if (sectors > 0) {
|
||||
Disk *new_disk = (Disk*)kmalloc(sizeof(Disk));
|
||||
if (!new_disk) return;
|
||||
|
||||
ATADriverData *data = (ATADriverData*)kmalloc(sizeof(ATADriverData));
|
||||
data->port_base = port;
|
||||
data->slave = slave;
|
||||
|
||||
new_disk->devname[0] = 0; // Auto-assign
|
||||
new_disk->type = DISK_TYPE_IDE;
|
||||
dm_strcpy(new_disk->label, name);
|
||||
new_disk->read_sector = ata_read_sector;
|
||||
new_disk->write_sector = ata_write_sector;
|
||||
new_disk->driver_data = data;
|
||||
new_disk->partition_lba_offset = 0;
|
||||
new_disk->total_sectors = sectors;
|
||||
new_disk->parent = NULL;
|
||||
new_disk->is_partition = false;
|
||||
new_disk->is_fat32 = false;
|
||||
|
||||
disk_register(new_disk);
|
||||
|
||||
// Parse MBR to find partitions
|
||||
parse_mbr_partitions(new_disk);
|
||||
}
|
||||
}
|
||||
|
||||
// === Init & Scan ===
|
||||
|
||||
void disk_manager_init(void) {
|
||||
for (int i = 0; i < MAX_DISKS; i++) {
|
||||
disks[i] = NULL;
|
||||
}
|
||||
disk_count = 0;
|
||||
next_sd_index = 0;
|
||||
next_drive_letter_idx = 0;
|
||||
|
||||
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.
|
||||
}
|
||||
|
||||
void disk_manager_scan(void) {
|
||||
serial_write("[DISK] Initializing AHCI (SATA DMA)...\n");
|
||||
ahci_init();
|
||||
|
||||
if (ahci_get_port_count() == 0) {
|
||||
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 {
|
||||
log_ok("AHCI ports initialized, skipping IDE");
|
||||
}
|
||||
}
|
||||
@@ -97,3 +97,23 @@ int pci_find_device_by_class(uint8_t class_code, uint8_t subclass, pci_device_t*
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t pci_get_bar(pci_device_t *dev, int bar_num) {
|
||||
if (!dev || bar_num < 0 || bar_num > 5) return 0;
|
||||
uint8_t offset = 0x10 + (bar_num * 4);
|
||||
return pci_read_config(dev->bus, dev->device, dev->function, offset);
|
||||
}
|
||||
|
||||
void pci_enable_bus_mastering(pci_device_t *dev) {
|
||||
if (!dev) return;
|
||||
uint32_t cmd = pci_read_config(dev->bus, dev->device, dev->function, 0x04);
|
||||
cmd |= (1 << 2); // Set Bus Master bit
|
||||
pci_write_config(dev->bus, dev->device, dev->function, 0x04, cmd);
|
||||
}
|
||||
|
||||
void pci_enable_mmio(pci_device_t *dev) {
|
||||
if (!dev) return;
|
||||
uint32_t cmd = pci_read_config(dev->bus, dev->device, dev->function, 0x04);
|
||||
cmd |= (1 << 1); // Set Memory Space bit
|
||||
pci_write_config(dev->bus, dev->device, dev->function, 0x04, cmd);
|
||||
}
|
||||
@@ -22,6 +22,9 @@ typedef struct {
|
||||
|
||||
#define PCI_CLASS_NETWORK_CONTROLLER 0x02
|
||||
#define PCI_CLASS_ETHERNET_CONTROLLER 0x00
|
||||
#define PCI_CLASS_MASS_STORAGE 0x01
|
||||
#define PCI_SUBCLASS_SATA 0x06
|
||||
#define PCI_SUBCLASS_IDE 0x01
|
||||
|
||||
uint32_t pci_read_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset);
|
||||
void pci_write_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value);
|
||||
@@ -35,4 +38,9 @@ int pci_enumerate_devices(pci_device_t* devices, int max_devices);
|
||||
int pci_find_device(uint16_t vendor_id, uint16_t device_id, pci_device_t* device);
|
||||
int pci_find_device_by_class(uint8_t class_code, uint8_t subclass, pci_device_t* device);
|
||||
|
||||
// BAR access and bus mastering helpers
|
||||
uint32_t pci_get_bar(pci_device_t *dev, int bar_num);
|
||||
void pci_enable_bus_mastering(pci_device_t *dev);
|
||||
void pci_enable_mmio(pci_device_t *dev);
|
||||
|
||||
#endif
|
||||
199
src/dev/ps2.c
Normal file
199
src/dev/ps2.c
Normal file
@@ -0,0 +1,199 @@
|
||||
// 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 "ps2.h"
|
||||
#include "io.h"
|
||||
#include "wm.h"
|
||||
#include "network.h"
|
||||
#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);
|
||||
|
||||
// --- Timer Handler ---
|
||||
volatile uint64_t kernel_ticks = 0;
|
||||
|
||||
uint64_t timer_handler(registers_t *regs) {
|
||||
if (smp_this_cpu_id() == 0) {
|
||||
kernel_ticks++;
|
||||
wm_timer_tick();
|
||||
network_process_frames();
|
||||
|
||||
extern void k_beep_process(void);
|
||||
k_beep_process();
|
||||
}
|
||||
|
||||
outb(0x20, 0x20);
|
||||
extern uint64_t process_schedule(uint64_t current_rsp);
|
||||
uint64_t new_rsp = process_schedule((uint64_t)regs);
|
||||
|
||||
if (smp_cpu_count() > 1) {
|
||||
lapic_send_ipi_all();
|
||||
}
|
||||
|
||||
return new_rsp;
|
||||
}
|
||||
|
||||
// --- Keyboard ---
|
||||
static void ps2_kbd_wait_write(void) {
|
||||
uint32_t timeout = 100000;
|
||||
while (timeout--) {
|
||||
if ((inb(0x64) & 2) == 0) return;
|
||||
}
|
||||
}
|
||||
|
||||
static void ps2_update_leds(void) {
|
||||
uint8_t led_status = 0;
|
||||
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);
|
||||
ps2_kbd_wait_write();
|
||||
outb(0x60, led_status);
|
||||
}
|
||||
|
||||
uint64_t keyboard_handler(registers_t *regs) {
|
||||
uint8_t scancode = inb(0x60);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
wm_handle_key_event(ev.keycode, ev.codepoint, ev.mods, ev.pressed);
|
||||
}
|
||||
|
||||
outb(0x20, 0x20); // EOI
|
||||
return (uint64_t)regs;
|
||||
}
|
||||
|
||||
// --- Mouse ---
|
||||
static uint8_t mouse_cycle = 0;
|
||||
static int8_t mouse_byte[4];
|
||||
static bool mouse_has_wheel = false;
|
||||
|
||||
void mouse_wait(uint8_t type) {
|
||||
uint32_t timeout = 100000;
|
||||
if (type == 0) { // Write
|
||||
while (timeout--) {
|
||||
if ((inb(0x64) & 2) == 0) return;
|
||||
}
|
||||
} else { // Read
|
||||
while (timeout--) {
|
||||
if ((inb(0x64) & 1) == 1) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mouse_write(uint8_t write) {
|
||||
mouse_wait(0);
|
||||
outb(0x64, 0xD4);
|
||||
mouse_wait(0);
|
||||
outb(0x60, write);
|
||||
}
|
||||
|
||||
uint8_t mouse_read(void) {
|
||||
mouse_wait(1);
|
||||
return inb(0x60);
|
||||
}
|
||||
|
||||
void mouse_init(void) {
|
||||
uint8_t status;
|
||||
|
||||
// Enable Aux Device
|
||||
mouse_wait(0);
|
||||
outb(0x64, 0xA8);
|
||||
|
||||
// Enable Interrupts
|
||||
mouse_wait(0);
|
||||
outb(0x64, 0x20);
|
||||
mouse_wait(1);
|
||||
status = inb(0x60) | 2;
|
||||
mouse_wait(0);
|
||||
outb(0x64, 0x60);
|
||||
mouse_wait(0);
|
||||
outb(0x60, status);
|
||||
|
||||
// Set Defaults
|
||||
mouse_write(0xF6);
|
||||
mouse_read();
|
||||
|
||||
// Enable Wheel
|
||||
mouse_write(0xF3); mouse_read(); mouse_write(200); mouse_read();
|
||||
mouse_write(0xF3); mouse_read(); mouse_write(100); mouse_read();
|
||||
mouse_write(0xF3); mouse_read(); mouse_write(80); mouse_read();
|
||||
|
||||
mouse_write(0xF2);
|
||||
mouse_read();
|
||||
uint8_t id = mouse_read();
|
||||
if (id == 3) mouse_has_wheel = true;
|
||||
|
||||
// Enable Streaming
|
||||
mouse_write(0xF4);
|
||||
mouse_read();
|
||||
}
|
||||
|
||||
uint64_t mouse_handler(registers_t *regs) {
|
||||
uint8_t status = inb(0x64);
|
||||
if (!(status & 0x20)) {
|
||||
outb(0x20, 0x20);
|
||||
outb(0xA0, 0x20);
|
||||
return (uint64_t)regs;
|
||||
}
|
||||
|
||||
uint8_t b = inb(0x60);
|
||||
|
||||
if (mouse_cycle == 0) {
|
||||
if ((b & 0x08) == 0) {
|
||||
// Out of sync
|
||||
} else {
|
||||
mouse_byte[0] = b;
|
||||
mouse_cycle++;
|
||||
}
|
||||
} else if (mouse_cycle == 1) {
|
||||
mouse_byte[1] = b;
|
||||
mouse_cycle++;
|
||||
} else if (mouse_cycle == 2) {
|
||||
mouse_byte[2] = b;
|
||||
if (mouse_has_wheel) {
|
||||
mouse_cycle++;
|
||||
} else {
|
||||
mouse_cycle = 0;
|
||||
int8_t dx = mouse_byte[1];
|
||||
int8_t dy = mouse_byte[2];
|
||||
wm_handle_mouse(dx, -dy, mouse_byte[0] & 0x07, 0);
|
||||
}
|
||||
} else if (mouse_cycle == 3) {
|
||||
mouse_byte[3] = b;
|
||||
mouse_cycle = 0;
|
||||
int8_t dx = mouse_byte[1];
|
||||
int8_t dy = mouse_byte[2];
|
||||
int8_t dz = mouse_byte[3];
|
||||
wm_handle_mouse(dx, -dy, mouse_byte[0] & 0x07, -dz);
|
||||
}
|
||||
|
||||
outb(0x20, 0x20);
|
||||
outb(0xA0, 0x20);
|
||||
return (uint64_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/Cantarell-Regular.ttf
Normal file
Binary file not shown.
BIN
src/fonts/Emoji/NotoEmoji-VariableFont_wght.ttf
Normal file
BIN
src/fonts/Emoji/NotoEmoji-VariableFont_wght.ttf
Normal file
Binary file not shown.
BIN
src/fonts/FiraCode-Regular.ttf
Normal file
BIN
src/fonts/FiraCode-Regular.ttf
Normal file
Binary file not shown.
BIN
src/fonts/FiraSans-Regular.ttf
Normal file
BIN
src/fonts/FiraSans-Regular.ttf
Normal file
Binary file not shown.
BIN
src/fonts/Hack-Regular.ttf
Normal file
BIN
src/fonts/Hack-Regular.ttf
Normal file
Binary file not shown.
BIN
src/fonts/Inconsolata.ttf
Normal file
BIN
src/fonts/Inconsolata.ttf
Normal file
Binary file not shown.
BIN
src/fonts/IosevkaTerm.ttc
Normal file
BIN
src/fonts/IosevkaTerm.ttc
Normal file
Binary file not shown.
BIN
src/fonts/JetBrainsMono-Regular.ttf
Normal file
BIN
src/fonts/JetBrainsMono-Regular.ttf
Normal file
Binary file not shown.
BIN
src/fonts/NotoSans.ttf
Normal file
BIN
src/fonts/NotoSans.ttf
Normal file
Binary file not shown.
BIN
src/fonts/OpenSans.ttf
Normal file
BIN
src/fonts/OpenSans.ttf
Normal file
Binary file not shown.
BIN
src/fonts/Roboto.ttf
Normal file
BIN
src/fonts/Roboto.ttf
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user