Compare commits
34 Commits
5983212da0
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 974e23987e | |||
| 256346534a | |||
| b6681b74c9 | |||
| 3246dbbd19 | |||
| b588634253 | |||
| 37aa46c847 | |||
| 0c6aaa1aed | |||
| 44a0c9aeba | |||
| c77d9e1725 | |||
| 7f6ef0fdc2 | |||
| 54f0f4ed9e | |||
| 1b75ac7578 | |||
| 6a79a20cf6 | |||
| 454de8feed | |||
| 5c7febbbf0 | |||
| e2ab130324 | |||
| d60036a4bd | |||
| 3c6fd8cb65 | |||
| 992ffd1f6b | |||
| 92748fd258 | |||
| 032a35206a | |||
| 4d98d73f5e | |||
| ec3cbb4794 | |||
| e42ee8eb85 | |||
| 177a0b8fe9 | |||
| 6d7a23d747 | |||
| 7d76f0ec73 | |||
| 17ccde3556 | |||
| 0b98ac0273 | |||
| ab5a1ecb6b | |||
| 48df965268 | |||
| b6ee4fc3de | |||
| af6c1c94cf | |||
| ce81d4eb31 |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -3,13 +3,12 @@
|
|||||||
*.o
|
*.o
|
||||||
*.bin
|
*.bin
|
||||||
*.elf
|
*.elf
|
||||||
|
*.json
|
||||||
|
|
||||||
.cache
|
.cache
|
||||||
|
|
||||||
.idea
|
.idea
|
||||||
.vscode
|
.vscode
|
||||||
|
|
||||||
build
|
sysroot
|
||||||
isodir
|
isodir
|
||||||
|
|
||||||
compiler*/
|
|
||||||
16
build.sh
Executable file
16
build.sh
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
./build_sysroot.sh
|
||||||
|
|
||||||
|
./build_libs.sh
|
||||||
|
|
||||||
|
./build_programs.sh
|
||||||
|
|
||||||
|
make clean
|
||||||
|
bear -- make
|
||||||
|
|
||||||
|
./copy_resources.sh
|
||||||
|
|
||||||
|
./make_img.sh
|
||||||
|
|
||||||
|
make -B
|
||||||
6
build_and_run.sh
Executable file
6
build_and_run.sh
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
./build.sh
|
||||||
|
|
||||||
|
make run
|
||||||
|
|
||||||
17
build_libs.sh
Executable file
17
build_libs.sh
Executable file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
cp -r kernel/sys/*.h rlibc/include/sys
|
||||||
|
|
||||||
|
cd rlibc
|
||||||
|
make clean
|
||||||
|
bear -- make
|
||||||
|
cp rlibc.a ../sysroot/usr/lib
|
||||||
|
cp -r include/. ../sysroot/usr/include
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
cd rlibgui
|
||||||
|
make clean
|
||||||
|
bear -- make
|
||||||
|
cp rlibgui.a ../sysroot/usr/lib
|
||||||
|
cp -r include/. ../sysroot/usr/include
|
||||||
|
cd ..
|
||||||
16
build_programs.sh
Executable file
16
build_programs.sh
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
cd programs
|
||||||
|
ln -s ../sysroot sysroot 2>/dev/null
|
||||||
|
|
||||||
|
find "." -type f \( -name "Makefile" -o -name "makefile" \) | while read -r makefile_path; do
|
||||||
|
dir_path=$(dirname "$makefile_path")
|
||||||
|
(
|
||||||
|
cd "$dir_path" || exit
|
||||||
|
|
||||||
|
make clean
|
||||||
|
bear -- make
|
||||||
|
)
|
||||||
|
done
|
||||||
|
|
||||||
|
cd ..
|
||||||
12
build_sysroot.sh
Executable file
12
build_sysroot.sh
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
mkdir -p sysroot
|
||||||
|
|
||||||
|
mkdir -p sysroot/usr
|
||||||
|
mkdir -p sysroot/dev
|
||||||
|
mkdir -p sysroot/kernel
|
||||||
|
|
||||||
|
mkdir -p sysroot/usr/include
|
||||||
|
mkdir -p sysroot/usr/lib
|
||||||
|
mkdir -p sysroot/usr/bin
|
||||||
|
mkdir -p sysroot/usr/fonts
|
||||||
29
clean.sh
Executable file
29
clean.sh
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# libc
|
||||||
|
cd rlibc
|
||||||
|
make clean
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# libgui
|
||||||
|
cd rlibgui
|
||||||
|
make clean
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# programs
|
||||||
|
cd programs
|
||||||
|
find . -type f \( -name "Makefile" -o -name "makefile" \) | while read -r makefile_path; do
|
||||||
|
dir_path=$(dirname "$makefile_path")
|
||||||
|
(
|
||||||
|
cd "$dir_path" || exit
|
||||||
|
|
||||||
|
make clean
|
||||||
|
)
|
||||||
|
done
|
||||||
|
rm sysroot
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# kernel
|
||||||
|
make clean
|
||||||
|
|
||||||
|
rm -rf sysroot
|
||||||
@@ -1,478 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/initrd.c.o",
|
|
||||||
"kernel/initrd.c"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/initrd.c",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/initrd.c.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/globals.c.o",
|
|
||||||
"kernel/globals.c"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/globals.c",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/globals.c.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/gdt.c.o",
|
|
||||||
"kernel/gdt.c"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/gdt.c",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/gdt.c.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/drivers/pic/pic.c.o",
|
|
||||||
"kernel/drivers/pic/pic.c"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/drivers/pic/pic.c",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/drivers/pic/pic.c.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/drivers/ps2/ps2.c.o",
|
|
||||||
"kernel/drivers/ps2/ps2.c"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/drivers/ps2/ps2.c",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/drivers/ps2/ps2.c.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/drivers/iso/iso.c.o",
|
|
||||||
"kernel/drivers/iso/iso.c"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/drivers/iso/iso.c",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/drivers/iso/iso.c.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/drivers/ide/ide.c.o",
|
|
||||||
"kernel/drivers/ide/ide.c"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/drivers/ide/ide.c",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/drivers/ide/ide.c.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/drivers/vga/vga.c.o",
|
|
||||||
"kernel/drivers/vga/vga.c"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/drivers/vga/vga.c",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/drivers/vga/vga.c.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/scheduler.c.o",
|
|
||||||
"kernel/scheduler.c"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/scheduler.c",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/scheduler.c.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/interrupts.c.o",
|
|
||||||
"kernel/interrupts.c"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/interrupts.c",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/interrupts.c.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/syscall.c.o",
|
|
||||||
"kernel/syscall.c"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/syscall.c",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/syscall.c.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/kmain.c.o",
|
|
||||||
"kernel/kmain.c"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/kmain.c",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/kmain.c.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/lib/tasks.c.o",
|
|
||||||
"kernel/lib/tasks.c"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/lib/tasks.c",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/lib/tasks.c.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/lib/stream.c.o",
|
|
||||||
"kernel/lib/stream.c"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/lib/stream.c",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/lib/stream.c.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/lib/print.c.o",
|
|
||||||
"kernel/lib/print.c"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/lib/print.c",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/lib/print.c.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/lib/memory.c.o",
|
|
||||||
"kernel/lib/memory.c"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/lib/memory.c",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/lib/memory.c.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/vfs.c.o",
|
|
||||||
"kernel/vfs.c"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/vfs.c",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/vfs.c.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/memory/mm.c.o",
|
|
||||||
"kernel/memory/mm.c"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/memory/mm.c",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/memory/mm.c.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/drivers/pic/pic.S.o",
|
|
||||||
"kernel/drivers/pic/pic.S"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/drivers/pic/pic.S",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/drivers/pic/pic.S.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/drivers/ps2/ps2.S.o",
|
|
||||||
"kernel/drivers/ps2/ps2.S"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/drivers/ps2/ps2.S",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/drivers/ps2/ps2.S.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/drivers/pit/pit.S.o",
|
|
||||||
"kernel/drivers/pit/pit.S"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/drivers/pit/pit.S",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/drivers/pit/pit.S.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/syscall.S.o",
|
|
||||||
"kernel/syscall.S"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/syscall.S",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/syscall.S.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/interrupts.S.o",
|
|
||||||
"kernel/interrupts.S"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/interrupts.S",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/interrupts.S.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/boot/boot.S.o",
|
|
||||||
"kernel/boot/boot.S"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/boot/boot.S",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/boot/boot.S.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/common.S.o",
|
|
||||||
"kernel/common.S"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/common.S",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/common.S.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/scheduler.S.o",
|
|
||||||
"kernel/scheduler.S"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/scheduler.S",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/scheduler.S.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/memory/mm_stubs.S.o",
|
|
||||||
"kernel/memory/mm_stubs.S"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/memory/mm_stubs.S",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/memory/mm_stubs.S.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
|
||||||
"-c",
|
|
||||||
"-ffreestanding",
|
|
||||||
"-O2",
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Ikernel",
|
|
||||||
"-o",
|
|
||||||
"obj/kernel/gdt.S.o",
|
|
||||||
"kernel/gdt.S"
|
|
||||||
],
|
|
||||||
"directory": "/home/slinky/source/RockOS",
|
|
||||||
"file": "/home/slinky/source/RockOS/kernel/gdt.S",
|
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/gdt.S.o"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
5
copy_resources.sh
Executable file
5
copy_resources.sh
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
cp -r resources/fonts/. sysroot/usr/fonts
|
||||||
|
|
||||||
|
cp -r kernel/. sysroot/kernel
|
||||||
@@ -1,14 +1,27 @@
|
|||||||
.set ALIGN, 1<<0 /* align loaded modules on page boundaries */
|
.set ALIGN, 1<<0
|
||||||
.set MEMINFO, 1<<1 /* provide memory map */
|
.set MEMINFO, 1<<1
|
||||||
.set FLAGS, ALIGN | MEMINFO /* this is the Multiboot 'flag' field */
|
.set GRAPHICS, 1<<2
|
||||||
.set MAGIC, 0x1BADB002 /* 'magic number' lets bootloader find the header */
|
|
||||||
.set CHECKSUM, -(MAGIC + FLAGS) /* checksum of above, to prove we are multiboot */
|
.set FLAGS, ALIGN | MEMINFO | GRAPHICS
|
||||||
|
.set MAGIC, 0x1BADB002
|
||||||
|
.set CHECKSUM, -(MAGIC + FLAGS)
|
||||||
|
|
||||||
.section .multiboot, "a"
|
.section .multiboot, "a"
|
||||||
.align 4
|
.align 4
|
||||||
.long MAGIC
|
.long MAGIC
|
||||||
.long FLAGS
|
.long FLAGS
|
||||||
.long CHECKSUM
|
.long CHECKSUM
|
||||||
|
|
||||||
|
.long 0 /* header_addr */
|
||||||
|
.long 0 /* load_addr */
|
||||||
|
.long 0 /* load_end_addr */
|
||||||
|
.long 0 /* bss_end_addr */
|
||||||
|
.long 0 /* entry_addr */
|
||||||
|
|
||||||
|
.long 0 /* Mode Type: 0 = Linear Framebuffer, 1 = Standard EGA Text */
|
||||||
|
.long 1024 /* Width (Pixels) */
|
||||||
|
.long 768 /* Height (Pixels) */
|
||||||
|
.long 32 /* Color Depth (Bits Per Pixel) */
|
||||||
|
|
||||||
.section .text
|
.section .text
|
||||||
.global _start
|
.global _start
|
||||||
@@ -34,7 +47,6 @@ higher:
|
|||||||
mov $0xC0000000, %eax
|
mov $0xC0000000, %eax
|
||||||
add %eax, %ebx
|
add %eax, %ebx
|
||||||
push %ebx
|
push %ebx
|
||||||
push %eax
|
|
||||||
call kmain
|
call kmain
|
||||||
loop:
|
loop:
|
||||||
hlt
|
hlt
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ io_wait:
|
|||||||
liftoff:
|
liftoff:
|
||||||
cli
|
cli
|
||||||
|
|
||||||
mov 4(%esp), %ecx
|
mov 4(%esp), %ecx
|
||||||
mov 8(%esp), %ebx
|
mov 8(%esp), %ebx
|
||||||
|
|
||||||
mov $0x23, %ax
|
mov $0x23, %ax
|
||||||
mov %ax, %ds
|
mov %ax, %ds
|
||||||
@@ -29,15 +29,20 @@ liftoff:
|
|||||||
mov %ax, %fs
|
mov %ax, %fs
|
||||||
mov %ax, %gs
|
mov %ax, %gs
|
||||||
|
|
||||||
push $0x23
|
pushl $0x23 # User Data Segment (SS)
|
||||||
push %ebx
|
pushl %ebx # User Stack Pointer (ESP)
|
||||||
push $0x202
|
pushl $0x202 # EFLAGS (Interrupts enabled, bit 1 standard)
|
||||||
push $0x1B
|
pushl $0x1B # User Code Segment (CS)
|
||||||
push %ecx
|
pushl %ecx # User Entry Point (EIP)
|
||||||
|
|
||||||
xor %eax, %eax
|
xor %eax, %eax
|
||||||
|
xor %ebx, %ebx
|
||||||
|
xor %ecx, %ecx
|
||||||
xor %edx, %edx
|
xor %edx, %edx
|
||||||
|
xor %esi, %esi
|
||||||
|
xor %edi, %edi
|
||||||
|
xor %ebp, %ebp
|
||||||
|
|
||||||
iret
|
iret
|
||||||
|
|
||||||
.global outb
|
.global outb
|
||||||
@@ -120,4 +125,9 @@ outsw:
|
|||||||
.global fetch_cr3
|
.global fetch_cr3
|
||||||
fetch_cr3:
|
fetch_cr3:
|
||||||
mov %cr3, %eax
|
mov %cr3, %eax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
.global kpanic
|
||||||
|
kpanic:
|
||||||
|
cli
|
||||||
|
hlt
|
||||||
@@ -7,4 +7,11 @@ void enable_interrupts();
|
|||||||
void disable_interrupts();
|
void disable_interrupts();
|
||||||
uint32_t fetch_cr3();
|
uint32_t fetch_cr3();
|
||||||
|
|
||||||
|
void kpanic();
|
||||||
|
|
||||||
|
void liftoff(uint32_t entry_point, uint32_t user_stack) __attribute__((noreturn));
|
||||||
|
|
||||||
|
uint8_t inb(uint16_t port);
|
||||||
|
void outb(uint16_t port, uint8_t data);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
128
kernel/drivers/cpio/cpio.c
Normal file
128
kernel/drivers/cpio/cpio.c
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
#include <drivers/cpio/cpio.h>
|
||||||
|
|
||||||
|
#include <lib/memory.h>
|
||||||
|
#include <lib/string.h>
|
||||||
|
#include <lib/print.h>
|
||||||
|
|
||||||
|
#define MAX_INITRD_FILES 64
|
||||||
|
|
||||||
|
static uint32_t parse_hex_ascii(const char *str, int len) {
|
||||||
|
uint32_t result = 0;
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
result <<= 4;
|
||||||
|
if (str[i] >= '0' && str[i] <= '9') result |= (str[i] - '0');
|
||||||
|
else if (str[i] >= 'A' && str[i] <= 'F') result |= (str[i] - 'A' + 10);
|
||||||
|
else if (str[i] >= 'a' && str[i] <= 'f') result |= (str[i] - 'a' + 10);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static vfs_node_t* cpio_find(vfs_node_t* _dir, const char* name) {
|
||||||
|
if (strcmp(name, "tvga") == 0) {
|
||||||
|
kprintf("looking for tvga\n");
|
||||||
|
}
|
||||||
|
if (!(_dir->flags & VFS_DIRECTORY)) return NULL;
|
||||||
|
vfs_node_t* root = _dir;
|
||||||
|
if (_dir->mnt) {
|
||||||
|
root = _dir->mnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
vfs_node_t* child = root->first_child;
|
||||||
|
while (child != NULL) {
|
||||||
|
if (strcmp(child->name, name) == 0) {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
child = child->next_sibling;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t cpio_read(struct vfs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer) {
|
||||||
|
if (offset >= node->size) return 0;
|
||||||
|
if (offset + size > node->size) {
|
||||||
|
size = node->size - offset;
|
||||||
|
}
|
||||||
|
memcpy((uint8_t*)(node->data) + offset, buffer, size);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static vfs_node_t* cpio_find_or_create(vfs_node_t* root_node, const char* path) {
|
||||||
|
if (strcmp(path, "fonts") == 0) {
|
||||||
|
kprintf("found fonts folder\n");
|
||||||
|
}
|
||||||
|
vfs_node_t* current = root_node;
|
||||||
|
|
||||||
|
char path_cpy[256];
|
||||||
|
strcpy(path_cpy, path);
|
||||||
|
|
||||||
|
char* sav = NULL;
|
||||||
|
char* tkn = strtok_r(path_cpy, "/", &sav);
|
||||||
|
|
||||||
|
while (tkn != NULL) {
|
||||||
|
vfs_node_t* next_node = cpio_find(current, tkn);
|
||||||
|
if (!next_node) {
|
||||||
|
next_node = kalloc(sizeof(vfs_node_t));
|
||||||
|
memset((void*)next_node, 0, sizeof(vfs_node_t));
|
||||||
|
|
||||||
|
strcpy(next_node->name, tkn);
|
||||||
|
next_node->flags = VFS_DIRECTORY;
|
||||||
|
next_node->find = cpio_find;
|
||||||
|
|
||||||
|
next_node->next_sibling = current->first_child;
|
||||||
|
current->first_child = next_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = next_node;
|
||||||
|
tkn = strtok_r(NULL, "/", &sav);
|
||||||
|
}
|
||||||
|
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
vfs_node_t* cpio_read_fs(uint32_t _vaddr) {
|
||||||
|
cpio_header_t* header = (cpio_header_t*)_vaddr;
|
||||||
|
|
||||||
|
vfs_node_t* cpio_root = kalloc(sizeof(vfs_node_t));
|
||||||
|
memset((uint8_t*)cpio_root, 0, sizeof(vfs_node_t));
|
||||||
|
strcpy(cpio_root->name, "cpio_root");
|
||||||
|
cpio_root->flags = VFS_DIRECTORY;
|
||||||
|
cpio_root->find = cpio_find;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (strncmp(header->c_magic, "070701", 6) != 0 &&
|
||||||
|
strncmp(header->c_magic, "070702", 6) != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t namesize = parse_hex_ascii(header->c_namesize, 8);
|
||||||
|
uint32_t filesize = parse_hex_ascii(header->c_filesize, 8);
|
||||||
|
uint32_t mode = parse_hex_ascii(header->c_mode, 8);
|
||||||
|
char* filename = (char*)header + sizeof(cpio_header_t);
|
||||||
|
|
||||||
|
if (strcmp(filename, "TRAILER!!!") == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t file_data_offset = (sizeof(cpio_header_t) + namesize + 3) & ~3;
|
||||||
|
uint8_t* file_data = (uint8_t*)header + file_data_offset;
|
||||||
|
|
||||||
|
if (strcmp(".", filename) != 0) {
|
||||||
|
vfs_node_t* current = cpio_find_or_create(cpio_root, filename);
|
||||||
|
if ((mode & 0xF000) == 0x4000) {
|
||||||
|
current->flags = VFS_DIRECTORY;
|
||||||
|
current->find = cpio_find;
|
||||||
|
} else {
|
||||||
|
current->flags = VFS_FILE;
|
||||||
|
current->size = filesize;
|
||||||
|
current->data = file_data;
|
||||||
|
current->read = cpio_read;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t next_header_offset = (file_data_offset + filesize + 3) & ~3;
|
||||||
|
header = (cpio_header_t*)((uint8_t*)header + next_header_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cpio_root;
|
||||||
|
}
|
||||||
25
kernel/drivers/cpio/cpio.h
Normal file
25
kernel/drivers/cpio/cpio.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#ifndef D_CPIO_H
|
||||||
|
#define D_CPIO_H
|
||||||
|
|
||||||
|
#include <vfs.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char c_magic[6]; // "070701" or "070702"
|
||||||
|
char c_ino[8];
|
||||||
|
char c_mode[8]; // File type & permissions
|
||||||
|
char c_uid[8];
|
||||||
|
char c_gid[8];
|
||||||
|
char c_nlink[8];
|
||||||
|
char c_mtime[8];
|
||||||
|
char c_filesize[8]; // File size in hex ASCII
|
||||||
|
char c_devmajor[8];
|
||||||
|
char c_devminor[8];
|
||||||
|
char c_rdevmajor[8];
|
||||||
|
char c_rdevminor[8];
|
||||||
|
char c_namesize[8]; // Length of filename in hex ASCII
|
||||||
|
char c_check[8];
|
||||||
|
} __attribute__((packed)) cpio_header_t;
|
||||||
|
|
||||||
|
vfs_node_t* cpio_read_fs(uint32_t _vaddr);
|
||||||
|
|
||||||
|
#endif
|
||||||
40
kernel/drivers/devfs/devfs.c
Normal file
40
kernel/drivers/devfs/devfs.c
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#include "vfs.h"
|
||||||
|
#include <drivers/devfs/devfs.h>
|
||||||
|
|
||||||
|
#include <lib/memory.h>
|
||||||
|
#include <lib/string.h>
|
||||||
|
#include <lib/print.h>
|
||||||
|
|
||||||
|
static vfs_node_t* devfs_find(vfs_node_t* parent, const char* name) {
|
||||||
|
vfs_node_t* cur = parent->first_child;
|
||||||
|
if (!cur) return NULL;
|
||||||
|
|
||||||
|
while (cur) {
|
||||||
|
if (strcmp(cur->name, name) == 0) break;
|
||||||
|
cur = cur->next_sibling;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
static vfs_node_t* devfs_create(vfs_node_t* parent, const char* name) {
|
||||||
|
vfs_node_t* node = kalloc(sizeof(vfs_node_t*));
|
||||||
|
memset((void*)node, 0, sizeof(vfs_node_t));
|
||||||
|
strcpy(node->name, name);
|
||||||
|
node->flags = VFS_CHARDEVICE;
|
||||||
|
if (parent->first_child) {
|
||||||
|
node->next_sibling = parent->first_child;
|
||||||
|
}
|
||||||
|
parent->first_child = node;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
vfs_node_t* create_devfs() {
|
||||||
|
vfs_node_t* root = kalloc(sizeof(vfs_node_t*));
|
||||||
|
memset((void*)root, 0, sizeof(vfs_node_t));
|
||||||
|
strcpy(root->name, "dev");
|
||||||
|
root->find = devfs_find;
|
||||||
|
root->flags = VFS_DIRECTORY;
|
||||||
|
root->create = devfs_create;
|
||||||
|
return root;
|
||||||
|
}
|
||||||
8
kernel/drivers/devfs/devfs.h
Normal file
8
kernel/drivers/devfs/devfs.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef D_DEVFS_H
|
||||||
|
#define D_DEVFS_H
|
||||||
|
|
||||||
|
#include <vfs.h>
|
||||||
|
|
||||||
|
vfs_node_t* create_devfs();
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -35,7 +35,7 @@ init_pic:
|
|||||||
# mask
|
# mask
|
||||||
mov $0xF8, %al
|
mov $0xF8, %al
|
||||||
outb %al, $PIC1_DATA
|
outb %al, $PIC1_DATA
|
||||||
mov $0x3F, %al
|
mov $0xFF, %al
|
||||||
outb %al, $PIC2_DATA
|
outb %al, $PIC2_DATA
|
||||||
|
|
||||||
ret
|
ret
|
||||||
|
|||||||
@@ -2,13 +2,20 @@
|
|||||||
|
|
||||||
#include <drivers/ps2/ps2.h>
|
#include <drivers/ps2/ps2.h>
|
||||||
|
|
||||||
|
#include <vfs.h>
|
||||||
|
|
||||||
|
static const char scancode_to_ascii[] = {
|
||||||
|
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
|
||||||
|
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
|
||||||
|
0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0,
|
||||||
|
'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, '*', 0, ' '
|
||||||
|
};
|
||||||
|
|
||||||
extern void ps2_wait_input_empty(void);
|
extern void ps2_wait_input_empty(void);
|
||||||
extern void ps2_wait_output_full(void);
|
extern void ps2_wait_output_full(void);
|
||||||
extern void ps2_write_command(uint8_t);
|
extern void ps2_write_command(uint8_t);
|
||||||
extern uint8_t ps2_read_data(void);
|
|
||||||
extern void ps2_write_data(uint8_t);
|
extern void ps2_write_data(uint8_t);
|
||||||
extern void ps2_flush_output_buffer(void);
|
extern void ps2_flush_output_buffer(void);
|
||||||
|
|
||||||
extern void io_wait(void);
|
extern void io_wait(void);
|
||||||
|
|
||||||
static uint8_t read_ccb() {
|
static uint8_t read_ccb() {
|
||||||
@@ -68,4 +75,24 @@ int init_ps2() {
|
|||||||
write_ccb(ccb);
|
write_ccb(ccb);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ps2_init_kbd(vfs_node_t* dev) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
char ps2_get_ascii(uint8_t scancode) {
|
||||||
|
if (scancode & 0x80) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scancode < sizeof(scancode_to_ascii)) {
|
||||||
|
char ascii = scancode_to_ascii[scancode];
|
||||||
|
if (ascii != 0) {
|
||||||
|
return ascii;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,13 @@
|
|||||||
|
|
||||||
#ifndef __ASSEMBLER__
|
#ifndef __ASSEMBLER__
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <vfs.h>
|
||||||
|
|
||||||
int init_ps2();
|
int init_ps2();
|
||||||
|
void ps2_init_kbd(vfs_node_t* dev);
|
||||||
uint8_t ps2_read_data();
|
uint8_t ps2_read_data();
|
||||||
|
|
||||||
|
char ps2_get_ascii(uint8_t scancode);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
65
kernel/drivers/pty/pty.c
Normal file
65
kernel/drivers/pty/pty.c
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#include "lib/ringbuf.h"
|
||||||
|
|
||||||
|
#include <drivers/pty/pty.h>
|
||||||
|
|
||||||
|
#include <lib/print.h>
|
||||||
|
|
||||||
|
uint32_t pty_master_read(struct vfs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer) {
|
||||||
|
pty_t* pty = (pty_t*)node->data;
|
||||||
|
uint32_t bytes_read = 0;
|
||||||
|
while (bytes_read < size) {
|
||||||
|
char c;
|
||||||
|
if (ring_buf_read(&pty->slave_rb, &c) == 0) {
|
||||||
|
buffer[bytes_read++] = c;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pty_master_write(struct vfs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer) {
|
||||||
|
pty_t* pty = (pty_t*)node->data;
|
||||||
|
uint32_t bytes_written = 0;
|
||||||
|
|
||||||
|
while (bytes_written < size) {
|
||||||
|
if (ring_buf_write(&pty->master_rb, buffer[bytes_written]) == 0) {
|
||||||
|
bytes_written++;
|
||||||
|
ring_buf_write(&pty->slave_rb, buffer[bytes_written-1]);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bytes_written;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pty_slave_read(struct vfs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer) {
|
||||||
|
pty_t* pty = (pty_t*)node->data;
|
||||||
|
uint32_t bytes_read = 0;
|
||||||
|
|
||||||
|
while (bytes_read < size) {
|
||||||
|
char c;
|
||||||
|
if (ring_buf_read(&pty->master_rb, &c) == 0) {
|
||||||
|
buffer[bytes_read++] = c;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pty_slave_write(struct vfs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer) {
|
||||||
|
pty_t* pty = (pty_t*)node->data;
|
||||||
|
uint32_t bytes_written = 0;
|
||||||
|
|
||||||
|
while (bytes_written < size) {
|
||||||
|
if (ring_buf_write(&pty->slave_rb, buffer[bytes_written]) == 0) {
|
||||||
|
bytes_written++;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes_written;
|
||||||
|
}
|
||||||
27
kernel/drivers/pty/pty.h
Normal file
27
kernel/drivers/pty/pty.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#ifndef KPTY_H
|
||||||
|
#define KPTY_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <lib/ringbuf.h>
|
||||||
|
#include <vfs.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
} wait_queue_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ring_buf_t master_rb;
|
||||||
|
ring_buf_t slave_rb;
|
||||||
|
wait_queue_t master_wq;
|
||||||
|
wait_queue_t slave_wq;
|
||||||
|
uint32_t flags;
|
||||||
|
uint32_t pid;
|
||||||
|
} pty_t;
|
||||||
|
|
||||||
|
uint32_t pty_master_read(struct vfs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer);
|
||||||
|
uint32_t pty_master_write(struct vfs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer);
|
||||||
|
|
||||||
|
uint32_t pty_slave_read(struct vfs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer);
|
||||||
|
uint32_t pty_slave_write(struct vfs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer);
|
||||||
|
|
||||||
|
#endif
|
||||||
38
kernel/drivers/serial/serial.c
Normal file
38
kernel/drivers/serial/serial.c
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#include <drivers/serial/serial.h>
|
||||||
|
#include <common.h>
|
||||||
|
|
||||||
|
#define COM1 0x3F8
|
||||||
|
|
||||||
|
int is_transmit_empty() {
|
||||||
|
return inb(COM1 + 5) & 0x20;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_serial(char a) {
|
||||||
|
while (is_transmit_empty() == 0);
|
||||||
|
if (a == '\n') outb(COM1, '\r');
|
||||||
|
outb(COM1, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_serial(const char* str) {
|
||||||
|
for (int i = 0; str[i] != '\0'; i++) {
|
||||||
|
write_serial(str[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_serial_hex(uint32_t val) {
|
||||||
|
char hex_chars[] = "0123456789ABCDEF";
|
||||||
|
print_serial("0x");
|
||||||
|
for (int i = 28; i >= 0; i -= 4) {
|
||||||
|
write_serial(hex_chars[(val >> i) & 0x0F]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_serial() {
|
||||||
|
outb(COM1 + 1, 0x00); // Disable all interrupts
|
||||||
|
outb(COM1 + 3, 0x80); // Enable DLAB (set baud rate divisor)
|
||||||
|
outb(COM1 + 0, 0x01); // Set divisor to 1 (lo byte) -> 115200 baud
|
||||||
|
outb(COM1 + 1, 0x00); // (hi byte)
|
||||||
|
outb(COM1 + 3, 0x03); // 8 bits, no parity, one stop bit
|
||||||
|
outb(COM1 + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
|
||||||
|
outb(COM1 + 4, 0x0B); // IRQs enabled, RTS/DSR set
|
||||||
|
}
|
||||||
12
kernel/drivers/serial/serial.h
Normal file
12
kernel/drivers/serial/serial.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#ifndef D_SERIAL_H
|
||||||
|
#define D_SERIAL_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void init_serial();
|
||||||
|
void print_serial_hex(uint32_t val);
|
||||||
|
void print_serial(const char* str);
|
||||||
|
void write_serial(char a);
|
||||||
|
int is_transmit_empty();
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,78 +1,121 @@
|
|||||||
|
#include "vfs.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <lib/stream.h>
|
#include <lib/print.h>
|
||||||
|
|
||||||
#define VGA_WIDTH 80
|
#include <drivers/vga/vga.h>
|
||||||
#define VGA_HEIGHT 25
|
#include <drivers/serial/serial.h>
|
||||||
#define VGA_MEMORY (0xB8000 + 0xC0000000)
|
|
||||||
|
|
||||||
enum vga_color {
|
#include <common.h>
|
||||||
VGA_COLOR_BLACK = 0,
|
#include <memory/mm.h>
|
||||||
VGA_COLOR_BLUE = 1,
|
|
||||||
VGA_COLOR_GREEN = 2,
|
|
||||||
VGA_COLOR_CYAN = 3,
|
|
||||||
VGA_COLOR_RED = 4,
|
|
||||||
VGA_COLOR_MAGENTA = 5,
|
|
||||||
VGA_COLOR_BROWN = 6,
|
|
||||||
VGA_COLOR_LIGHT_GREY = 7,
|
|
||||||
VGA_COLOR_DARK_GREY = 8,
|
|
||||||
VGA_COLOR_LIGHT_BLUE = 9,
|
|
||||||
VGA_COLOR_LIGHT_GREEN = 10,
|
|
||||||
VGA_COLOR_LIGHT_CYAN = 11,
|
|
||||||
VGA_COLOR_LIGHT_RED = 12,
|
|
||||||
VGA_COLOR_LIGHT_MAGENTA = 13,
|
|
||||||
VGA_COLOR_LIGHT_BROWN = 14,
|
|
||||||
VGA_COLOR_WHITE = 15,
|
|
||||||
};
|
|
||||||
|
|
||||||
static size_t terminal_row;
|
#include <sys/video.h>
|
||||||
static size_t terminal_column;
|
|
||||||
static uint8_t terminal_color;
|
|
||||||
static uint16_t* terminal_buffer = (uint16_t*)VGA_MEMORY;
|
|
||||||
|
|
||||||
static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg)
|
static uint32_t framebuffer_address;
|
||||||
{
|
static uint32_t framebuffer_width;
|
||||||
return fg | bg << 4;
|
static uint32_t framebuffer_height;
|
||||||
|
static uint32_t framebuffer_total_pixels;
|
||||||
|
static uint32_t framebuffer_pitch;
|
||||||
|
static uint32_t framebuffer_bpp;
|
||||||
|
|
||||||
|
vga_color_t VGA_COLOR_BLACK = {0, 0, 0, 255};
|
||||||
|
vga_color_t VGA_COLOR_RED = {0, 0, 255, 255};
|
||||||
|
vga_color_t VGA_COLOR_GREEN = {0, 255, 0, 255};
|
||||||
|
vga_color_t VGA_COLOR_BLUE = {255, 0, 0, 255};
|
||||||
|
|
||||||
|
uint32_t vga_mmap(vfs_node_t* node, uint32_t address) {
|
||||||
|
uint32_t fb_size_bytes = framebuffer_height * framebuffer_pitch;
|
||||||
|
uint32_t num_pages = (fb_size_bytes + 4095) / 4096;
|
||||||
|
for (uint32_t i = 0; i < num_pages; i++) {
|
||||||
|
uint32_t phys_addr = framebuffer_address + (i * 4096);
|
||||||
|
uint32_t virt_addr = address + (i * 4096);
|
||||||
|
map_page(virt_addr, phys_addr, PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER | PAGE_MMIO);
|
||||||
|
}
|
||||||
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint16_t vga_entry(unsigned char uc, uint8_t color)
|
uint32_t vga_ioctl(vfs_node_t* node, uint32_t request, void* arg) {
|
||||||
{
|
if (request == FBIOGET_INFO) {
|
||||||
return (uint16_t) uc | (uint16_t) color << 8;
|
fb_info_t* info = (fb_info_t*)arg;
|
||||||
|
info->width = framebuffer_width;
|
||||||
|
info->height = framebuffer_height;
|
||||||
|
info->pitch = framebuffer_pitch;
|
||||||
|
info->fb_size = framebuffer_total_pixels;
|
||||||
|
info->bpp = framebuffer_bpp;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vga_init() {
|
void vga_init(
|
||||||
terminal_row = 0;
|
vfs_node_t* dev,
|
||||||
terminal_column = 0;
|
uint32_t fb_paddr,
|
||||||
terminal_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
|
uint32_t fb_width,
|
||||||
|
uint32_t fb_height,
|
||||||
|
uint32_t fb_pitch,
|
||||||
|
uint8_t fb_bpp
|
||||||
|
) {
|
||||||
|
framebuffer_address = fb_paddr;
|
||||||
|
framebuffer_width = fb_width;
|
||||||
|
framebuffer_height = fb_height;
|
||||||
|
framebuffer_total_pixels = framebuffer_width * framebuffer_height;
|
||||||
|
framebuffer_pitch = fb_pitch;
|
||||||
|
framebuffer_bpp = fb_bpp;
|
||||||
|
|
||||||
|
kprintf("mapping vga pages\n");
|
||||||
|
|
||||||
|
uint32_t fb_size_bytes = fb_height * fb_pitch;
|
||||||
|
uint32_t num_pages = (fb_size_bytes + 4095) / 4096;
|
||||||
|
for (uint32_t i = 0; i < num_pages; i++) {
|
||||||
|
uint32_t phys_addr = fb_paddr + (i * 4096);
|
||||||
|
uint32_t virt_addr = VGA_FRAMEBUFFER + (i * 4096);
|
||||||
|
map_page(virt_addr, phys_addr, PAGE_PRESENT | PAGE_WRITABLE | PAGE_MMIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
vga_clear_scrn(0x00000000);
|
||||||
|
|
||||||
for (size_t y = 0; y < VGA_HEIGHT; y++) {
|
dev->flags = VFS_CHARDEVICE;
|
||||||
for (size_t x = 0; x < VGA_WIDTH; x++) {
|
dev->mmap = vga_mmap;
|
||||||
const size_t index = y * VGA_WIDTH + x;
|
dev->ioctl = vga_ioctl;
|
||||||
terminal_buffer[index] = vga_entry(' ', terminal_color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vga_putchar(char c) {
|
uint32_t vga_get_framebuffer() {
|
||||||
if (c == '\n') {
|
return VGA_FRAMEBUFFER;
|
||||||
terminal_row++;
|
}
|
||||||
terminal_column = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '\t') {
|
uint32_t vga_get_width() {
|
||||||
for (int i = 0; i < 4; i++) {
|
return framebuffer_width;
|
||||||
vga_putchar(' ');
|
}
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t index = terminal_row * VGA_WIDTH + terminal_column;
|
uint32_t vga_get_height() {
|
||||||
terminal_buffer[index] = vga_entry(c, terminal_color);
|
return framebuffer_height;
|
||||||
if (++terminal_column == VGA_WIDTH) {
|
}
|
||||||
terminal_column = 0;
|
|
||||||
if (++terminal_row == VGA_HEIGHT)
|
uint32_t vga_get_pitch() {
|
||||||
terminal_row = 0;
|
return framebuffer_pitch;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
uint8_t vga_get_bpp() {
|
||||||
|
return framebuffer_bpp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vga_clear_scrn(uint32_t color) {
|
||||||
|
uint8_t* fb_bytes = (uint8_t*)VGA_FRAMEBUFFER;
|
||||||
|
uint8_t bytes_per_pixel = framebuffer_bpp / 8;
|
||||||
|
|
||||||
|
for (uint32_t y = 0; y < framebuffer_height; y++) {
|
||||||
|
uint8_t* row = fb_bytes + (y * framebuffer_pitch);
|
||||||
|
|
||||||
|
for (uint32_t x = 0; x < framebuffer_width; x++) {
|
||||||
|
uint8_t* pixel = row + (x * bytes_per_pixel);
|
||||||
|
|
||||||
|
switch(framebuffer_bpp) {
|
||||||
|
case 32: {
|
||||||
|
*(uint32_t*)pixel = color;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,41 @@
|
|||||||
#ifndef DVGA_H
|
#ifndef DVGA_H
|
||||||
#define DVGA_H
|
#define DVGA_H
|
||||||
|
|
||||||
void vga_init();
|
#include <vfs.h>
|
||||||
void vga_putchar(char c);
|
#include <lib/font.h>
|
||||||
|
|
||||||
|
#define VGA_FRAMEBUFFER 0xF0000000
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t b;
|
||||||
|
uint8_t g;
|
||||||
|
uint8_t r;
|
||||||
|
uint8_t a;
|
||||||
|
} vga_color_t;
|
||||||
|
|
||||||
|
extern vga_color_t VGA_COLOR_BLACK;
|
||||||
|
extern vga_color_t VGA_COLOR_RED;
|
||||||
|
extern vga_color_t VGA_COLOR_GREEN;
|
||||||
|
extern vga_color_t VGA_COLOR_BLUE;
|
||||||
|
extern vga_color_t VGA_COLOR_ROCKOS;
|
||||||
|
|
||||||
|
void vga_init(
|
||||||
|
vfs_node_t* dev,
|
||||||
|
uint32_t fb_paddr,
|
||||||
|
uint32_t fb_width,
|
||||||
|
uint32_t fb_height,
|
||||||
|
uint32_t fb_pitch,
|
||||||
|
uint8_t fb_bpp
|
||||||
|
);
|
||||||
|
|
||||||
|
uint32_t vga_get_framebuffer();
|
||||||
|
uint32_t vga_get_width();
|
||||||
|
uint32_t vga_get_height();
|
||||||
|
uint32_t vga_get_pitch();
|
||||||
|
uint8_t vga_get_bpp();
|
||||||
|
|
||||||
|
void vga_clear_scrn(uint32_t color);
|
||||||
|
|
||||||
|
uint32_t vga_write(vfs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buf);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
68
kernel/elf.c
Normal file
68
kernel/elf.c
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#include "elf.h"
|
||||||
|
#include "vfs.h"
|
||||||
|
#include "memory/mm.h"
|
||||||
|
#include "process.h"
|
||||||
|
#include "scheduler.h"
|
||||||
|
|
||||||
|
#include <lib/memory.h>
|
||||||
|
#include <lib/print.h>
|
||||||
|
|
||||||
|
uint32_t load_elf_program(const char* prgm) {
|
||||||
|
int fd = vfs_open(prgm, 0);
|
||||||
|
if (fd == -1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
elf_header_t* e_hdr = kalloc(sizeof(elf_header_t));
|
||||||
|
memset((void*)e_hdr, 0, sizeof(elf_header_t));
|
||||||
|
|
||||||
|
uint32_t bytes_rd = vfs_read(fd, e_hdr, sizeof(elf_header_t));
|
||||||
|
if (bytes_rd <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ph_table_ptr = e_hdr->e_phoff;
|
||||||
|
elf_program_header_t* ph = kalloc(sizeof(elf_program_header_t));
|
||||||
|
uint32_t heap_start = 0;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < e_hdr->e_phnum; i++) {
|
||||||
|
vfs_seek(fd, ph_table_ptr);
|
||||||
|
memset((void*)ph, 0, sizeof(elf_program_header_t));
|
||||||
|
vfs_read(fd, ph, sizeof(elf_program_header_t));
|
||||||
|
|
||||||
|
if (ph->p_type == PT_LOAD) {
|
||||||
|
uint32_t vstart = ph->p_vaddr;
|
||||||
|
uint32_t vend = vstart + ph->p_memsz;
|
||||||
|
|
||||||
|
if (vend > heap_start) {
|
||||||
|
heap_start = vend;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t page_start = vstart & ~(PAGE_SIZE - 1);
|
||||||
|
uint32_t page_end = (vend + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
|
||||||
|
|
||||||
|
for (uint32_t v = page_start; v < page_end; v += PAGE_SIZE) {
|
||||||
|
void* phys_frame = p_alloc_frame();
|
||||||
|
map_page(v, (uint32_t)phys_frame, PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t data_ptr = ph->p_offset;
|
||||||
|
vfs_seek(fd, data_ptr);
|
||||||
|
vfs_read(fd, (void*)vstart, ph->p_filesz);
|
||||||
|
|
||||||
|
// 0 out bss
|
||||||
|
if (ph->p_memsz > ph->p_filesz) {
|
||||||
|
size_t bss_size = ph->p_memsz - ph->p_filesz;
|
||||||
|
memset((void*)(vstart + ph->p_filesz), 0, bss_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ph_table_ptr += sizeof(elf_program_header_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t eip = e_hdr->e_entry;
|
||||||
|
kfree(ph);
|
||||||
|
kfree(e_hdr);
|
||||||
|
|
||||||
|
return eip;
|
||||||
|
}
|
||||||
@@ -34,4 +34,6 @@ typedef struct {
|
|||||||
uint32_t p_align;
|
uint32_t p_align;
|
||||||
} __attribute__((packed)) elf_program_header_t;
|
} __attribute__((packed)) elf_program_header_t;
|
||||||
|
|
||||||
|
uint32_t load_elf_program(const char* prgm);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
40
kernel/gdt.c
40
kernel/gdt.c
@@ -1,4 +1,4 @@
|
|||||||
#include <stdint.h>
|
#include <gdt.h>
|
||||||
|
|
||||||
#define SEG_DESCTYPE(x) ((x) << 0x04) // Descriptor type (0 for system, 1 for code/data)
|
#define SEG_DESCTYPE(x) ((x) << 0x04) // Descriptor type (0 for system, 1 for code/data)
|
||||||
#define SEG_PRES(x) ((x) << 0x07) // Present
|
#define SEG_PRES(x) ((x) << 0x07) // Present
|
||||||
@@ -45,41 +45,11 @@ typedef struct __attribute__((packed)) {
|
|||||||
uint16_t limit;
|
uint16_t limit;
|
||||||
uint32_t base;
|
uint32_t base;
|
||||||
} gdt_ptr_t;
|
} gdt_ptr_t;
|
||||||
|
|
||||||
typedef struct __attribute__((packed)) {
|
|
||||||
uint32_t prev_tss;
|
|
||||||
uint32_t esp0;
|
|
||||||
uint32_t ss0;
|
|
||||||
uint32_t esp1;
|
|
||||||
uint32_t ss1;
|
|
||||||
uint32_t esp2;
|
|
||||||
uint32_t ss2;
|
|
||||||
uint32_t cr3;
|
|
||||||
uint32_t eip;
|
|
||||||
uint32_t eflags;
|
|
||||||
uint32_t eax;
|
|
||||||
uint32_t ecx;
|
|
||||||
uint32_t edx;
|
|
||||||
uint32_t ebx;
|
|
||||||
uint32_t esp;
|
|
||||||
uint32_t ebp;
|
|
||||||
uint32_t esi;
|
|
||||||
uint32_t edi;
|
|
||||||
uint32_t es;
|
|
||||||
uint32_t cs;
|
|
||||||
uint32_t ss;
|
|
||||||
uint32_t ds;
|
|
||||||
uint32_t fs;
|
|
||||||
uint32_t gs;
|
|
||||||
uint32_t ldt;
|
|
||||||
uint16_t trap;
|
|
||||||
uint16_t iomap_base;
|
|
||||||
} tss_entry;
|
|
||||||
|
|
||||||
uint64_t gdt[6];
|
uint64_t gdt[6];
|
||||||
gdt_ptr_t gdtr;
|
gdt_ptr_t gdtr;
|
||||||
|
|
||||||
tss_entry tss;
|
tss_entry_t tss;
|
||||||
|
|
||||||
extern void load_gdt();
|
extern void load_gdt();
|
||||||
extern void tss_flush();
|
extern void tss_flush();
|
||||||
@@ -126,14 +96,14 @@ void init_gdt() {
|
|||||||
gdt[3] = create_descriptor(0, 0x000FFFFF, (GDT_CODE_PL3));
|
gdt[3] = create_descriptor(0, 0x000FFFFF, (GDT_CODE_PL3));
|
||||||
gdt[4] = create_descriptor(0, 0x000FFFFF, (GDT_DATA_PL3));
|
gdt[4] = create_descriptor(0, 0x000FFFFF, (GDT_DATA_PL3));
|
||||||
|
|
||||||
for (uint32_t i = 0; i < sizeof(tss_entry); i++) {
|
for (uint32_t i = 0; i < sizeof(tss_entry_t); i++) {
|
||||||
((char*)&tss)[i] = 0;
|
((char*)&tss)[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
tss.ss0 = 0x10;
|
tss.ss0 = 0x10;
|
||||||
tss.iomap_base = sizeof(tss_entry);
|
tss.iomap_base = sizeof(tss_entry_t);
|
||||||
|
|
||||||
gdt[5] = create_tss_descriptor((uint32_t)&tss, sizeof(tss_entry) - 1);
|
gdt[5] = create_tss_descriptor((uint32_t)&tss, sizeof(tss_entry_t) - 1);
|
||||||
|
|
||||||
gdtr.limit = 6 * sizeof(uint64_t) - 1;
|
gdtr.limit = 6 * sizeof(uint64_t) - 1;
|
||||||
gdtr.base = (uint32_t)&gdt;
|
gdtr.base = (uint32_t)&gdt;
|
||||||
|
|||||||
35
kernel/gdt.h
35
kernel/gdt.h
@@ -1,6 +1,41 @@
|
|||||||
#ifndef KGDT_H
|
#ifndef KGDT_H
|
||||||
#define KGDT_H
|
#define KGDT_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed)) {
|
||||||
|
uint32_t prev_tss;
|
||||||
|
uint32_t esp0;
|
||||||
|
uint32_t ss0;
|
||||||
|
uint32_t esp1;
|
||||||
|
uint32_t ss1;
|
||||||
|
uint32_t esp2;
|
||||||
|
uint32_t ss2;
|
||||||
|
uint32_t cr3;
|
||||||
|
uint32_t eip;
|
||||||
|
uint32_t eflags;
|
||||||
|
uint32_t eax;
|
||||||
|
uint32_t ecx;
|
||||||
|
uint32_t edx;
|
||||||
|
uint32_t ebx;
|
||||||
|
uint32_t esp;
|
||||||
|
uint32_t ebp;
|
||||||
|
uint32_t esi;
|
||||||
|
uint32_t edi;
|
||||||
|
uint32_t es;
|
||||||
|
uint32_t cs;
|
||||||
|
uint32_t ss;
|
||||||
|
uint32_t ds;
|
||||||
|
uint32_t fs;
|
||||||
|
uint32_t gs;
|
||||||
|
uint32_t ldt;
|
||||||
|
uint16_t trap;
|
||||||
|
uint16_t iomap_base;
|
||||||
|
} tss_entry_t;
|
||||||
|
|
||||||
void init_gdt();
|
void init_gdt();
|
||||||
|
void tss_flush();
|
||||||
|
|
||||||
|
extern tss_entry_t tss;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
#include "initrd.h"
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include <lib/print.h>
|
|
||||||
#include <lib/memory.h>
|
|
||||||
|
|
||||||
void parse_cpio(void *initrd_start) {
|
|
||||||
cpio_header_t *head = (cpio_header_t *)initrd_start;
|
|
||||||
|
|
||||||
while (strncmp(head->c_magic, "070701", 6) == 0) {
|
|
||||||
// If we hit the trailer, we are done
|
|
||||||
char *filename = (char *)(head + 1);
|
|
||||||
if (strncmp(filename, "TRAILER!!!", 10) == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t filesize = parse_hex(head->c_filesize);
|
|
||||||
uint32_t namesize = parse_hex(head->c_namesize);
|
|
||||||
|
|
||||||
kprintf("found file of size %d\n", filesize);
|
|
||||||
|
|
||||||
// Calculate where the data begins (accounting for 4-byte padding)
|
|
||||||
uint32_t header_plus_name = 110 + namesize;
|
|
||||||
header_plus_name = (header_plus_name + 3) & ~3; // Align to 4 bytes
|
|
||||||
|
|
||||||
char *file_data = (char *)head + header_plus_name;
|
|
||||||
|
|
||||||
uint32_t total_record_size = header_plus_name + filesize;
|
|
||||||
total_record_size = (total_record_size + 3) & ~3; // Align to 4 bytes
|
|
||||||
|
|
||||||
head = (cpio_header_t *)((char *)head + total_record_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
#ifndef KINITRD_H
|
|
||||||
#define KINITRD_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char c_magic[6];
|
|
||||||
char c_ino[8];
|
|
||||||
char c_mode[8];
|
|
||||||
char c_uid[8];
|
|
||||||
char c_gid[8];
|
|
||||||
char c_nlink[8];
|
|
||||||
char c_mtime[8];
|
|
||||||
char c_filesize[8];
|
|
||||||
char c_devmajor[8];
|
|
||||||
char c_devminor[8];
|
|
||||||
char c_rdevmajor[8];
|
|
||||||
char c_rdevminor[8];
|
|
||||||
char c_namesize[8];
|
|
||||||
char c_check[8];
|
|
||||||
} cpio_header_t;
|
|
||||||
|
|
||||||
static inline uint32_t parse_hex(const char *s) {
|
|
||||||
uint32_t val = 0;
|
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
val <<= 4;
|
|
||||||
if (s[i] >= '0' && s[i] <= '9') val += (s[i] - '0');
|
|
||||||
else if (s[i] >= 'A' && s[i] <= 'F') val += (s[i] - 'A' + 10);
|
|
||||||
else if (s[i] >= 'a' && s[i] <= 'f') val += (s[i] - 'a' + 10);
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
void parse_cpio(void *initrd_start);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -18,10 +18,22 @@ isr\num:
|
|||||||
isr_common_stub:
|
isr_common_stub:
|
||||||
pushal
|
pushal
|
||||||
|
|
||||||
|
xor %eax, %eax
|
||||||
|
mov %ds, %ax
|
||||||
|
pushl %eax
|
||||||
|
|
||||||
|
mov $0x10, %ax
|
||||||
|
mov %ax, %ds
|
||||||
|
mov %ax, %es
|
||||||
|
|
||||||
pushl %esp
|
pushl %esp
|
||||||
call common_interrupt_handler
|
call common_interrupt_handler
|
||||||
addl $4, %esp
|
addl $4, %esp
|
||||||
|
|
||||||
|
popl %eax
|
||||||
|
mov %ax, %ds
|
||||||
|
mov %ax, %es
|
||||||
|
|
||||||
popal
|
popal
|
||||||
addl $8, %esp
|
addl $8, %esp
|
||||||
iret
|
iret
|
||||||
@@ -41,11 +53,14 @@ ISR_ERRCODE 14 # Page Fault (Has Error Code!)
|
|||||||
// This is a special case so we need to handle it for task switching
|
// This is a special case so we need to handle it for task switching
|
||||||
.global isr32
|
.global isr32
|
||||||
.extern switch_context # scheduler.c
|
.extern switch_context # scheduler.c
|
||||||
.extern send_eoi_master # drivers/pic/pic.c
|
.extern send_eoi_master # drivers/pic/pic.S
|
||||||
isr32:
|
isr32:
|
||||||
cli
|
cli
|
||||||
|
pushal
|
||||||
pushal
|
push %ds
|
||||||
|
|
||||||
|
mov $0x10, %ax
|
||||||
|
mov %ax, %ds
|
||||||
|
|
||||||
pushl %esp
|
pushl %esp
|
||||||
call switch_context
|
call switch_context
|
||||||
@@ -53,9 +68,10 @@ isr32:
|
|||||||
|
|
||||||
call send_eoi_master
|
call send_eoi_master
|
||||||
|
|
||||||
|
pop %ds
|
||||||
popal
|
popal
|
||||||
sti
|
sti
|
||||||
iret
|
iret
|
||||||
|
|
||||||
ISR_NOERRCODE 33 # IRQ1 - Keyboard
|
ISR_NOERRCODE 33 # IRQ1 - Keyboard
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,18 @@
|
|||||||
|
|
||||||
#include <lib/print.h>
|
#include <lib/print.h>
|
||||||
|
|
||||||
|
#include <memory/mm.h>
|
||||||
|
|
||||||
|
#include "kbd.h"
|
||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "gdt.h"
|
||||||
|
#include "scheduler.h"
|
||||||
|
#include "process.h"
|
||||||
|
|
||||||
#include <drivers/pic/pic.h>
|
#include <drivers/pic/pic.h>
|
||||||
#include <drivers/ps2/ps2.h>
|
#include <drivers/ps2/ps2.h>
|
||||||
|
#include <lib/memory.h>
|
||||||
|
|
||||||
#define IDT_MAX_DESCRIPTORS 256
|
#define IDT_MAX_DESCRIPTORS 256
|
||||||
#define ATTR_KERN_32 0x8E // active(1), ring 0 (00), interrupt gate(0), 32 bit (1110)
|
#define ATTR_KERN_32 0x8E // active(1), ring 0 (00), interrupt gate(0), 32 bit (1110)
|
||||||
@@ -25,15 +33,6 @@ typedef struct __attribute__((packed)) {
|
|||||||
uint32_t base;
|
uint32_t base;
|
||||||
} idt_ptr;
|
} idt_ptr;
|
||||||
|
|
||||||
typedef struct __attribute__((packed)) {
|
|
||||||
uint32_t edi, esi, ebp, esp_dummy, ebx, edx, ecx, eax;
|
|
||||||
|
|
||||||
uint32_t int_no;
|
|
||||||
uint32_t error_code;
|
|
||||||
|
|
||||||
uint32_t eip, cs, eflags, useresp, ss;
|
|
||||||
} registers;
|
|
||||||
|
|
||||||
// (interrupts.S)
|
// (interrupts.S)
|
||||||
extern void load_idt(void);
|
extern void load_idt(void);
|
||||||
extern void isr0();
|
extern void isr0();
|
||||||
@@ -56,7 +55,9 @@ static void* isr_stub_table[256] = {
|
|||||||
|
|
||||||
static const char* err_messages[32] = {
|
static const char* err_messages[32] = {
|
||||||
[0] = "Divide by 0",
|
[0] = "Divide by 0",
|
||||||
[1] = "",
|
[1] = "Debug",
|
||||||
|
[4] = "Overflow",
|
||||||
|
[6] = "Undefined Opcode",
|
||||||
[8] = "",
|
[8] = "",
|
||||||
[13] = "General Protection Fault",
|
[13] = "General Protection Fault",
|
||||||
[14] = "Page Fault",
|
[14] = "Page Fault",
|
||||||
@@ -83,7 +84,7 @@ void init_idt() {
|
|||||||
if (isr_stub_table[i] != 0) {
|
if (isr_stub_table[i] != 0) {
|
||||||
set_idtr(i, isr_stub_table[i], SEGMENT_KERN, ATTR_KERN_32);
|
set_idtr(i, isr_stub_table[i], SEGMENT_KERN, ATTR_KERN_32);
|
||||||
} else {
|
} else {
|
||||||
set_idtr(i, 0, SEGMENT_KERN, 0);
|
set_idtr(i, 0, SEGMENT_KERN, ATTR_KERN_32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +93,16 @@ void init_idt() {
|
|||||||
load_idt();
|
load_idt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void common_interrupt_handler(registers *args) {
|
typedef struct __attribute__((packed)) {
|
||||||
|
uint32_t ds;
|
||||||
|
uint32_t edi, esi, ebp, dummy, ebx, edx, ecx, eax;
|
||||||
|
|
||||||
|
uint32_t int_no;
|
||||||
|
uint32_t error_code;
|
||||||
|
|
||||||
|
uint32_t eip, cs, eflags, u_esp, u_ss;
|
||||||
|
} intr_regs_t;
|
||||||
|
void common_interrupt_handler(intr_regs_t *args) {
|
||||||
switch (args->int_no) {
|
switch (args->int_no) {
|
||||||
case 0:
|
case 0:
|
||||||
case 1:
|
case 1:
|
||||||
@@ -109,33 +119,99 @@ void common_interrupt_handler(registers *args) {
|
|||||||
case 12:
|
case 12:
|
||||||
case 13:
|
case 13:
|
||||||
case 15:
|
case 15:
|
||||||
case 16:
|
case 16: {
|
||||||
kprintf("CPU Error: %s", err_messages[args->int_no]);
|
process_t* task = current_task();
|
||||||
|
kprintf("\n--- CPU Exception ---\n");
|
||||||
|
kprintf("Current Task PID: %d\n", task->pid);
|
||||||
|
kprintf("Error: [%d] %s\n", args->int_no, err_messages[args->int_no]);
|
||||||
|
kprintf("Error Code: 0x%x\n", args->error_code);
|
||||||
|
kprintf("Instruction Pointer: 0x%x\n", args->eip);
|
||||||
|
kprintf("Current Stack Pointer: 0x%x\n", (void*)args);
|
||||||
|
kprintf("EAX: 0x%x\n", args->eax);
|
||||||
|
kprintf("EFLAGS: 0x%x\n", args->eflags);
|
||||||
|
kprintf("Code Segment: 0x%x\n", args->cs);
|
||||||
|
kprintf("Calling Data Segment: 0x%x\n", args->ds);
|
||||||
|
kprintf("Current cr3: 0x%x\n", fetch_cr3());
|
||||||
|
kprintf("tss.esp0: 0x%x\n", tss.esp0);
|
||||||
|
kprintf("instruction: 0x%x\n", *(uint32_t*)args->eip);
|
||||||
|
kpanic();
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 14:{
|
case 14:{
|
||||||
uint32_t faulting_address;
|
uint32_t faulting_address;
|
||||||
asm volatile("mov %%cr2, %0" : "=r"(faulting_address));
|
asm volatile("mov %%cr2, %0" : "=r"(faulting_address));
|
||||||
|
|
||||||
|
if (is_cow(faulting_address)) {
|
||||||
|
uint32_t pde_entry = faulting_address >> 22;
|
||||||
|
uint32_t pte_entry = (faulting_address >> 12) & 0x3FF;
|
||||||
|
uint32_t* tablev = (uint32_t*)(CUR_PAGE_TABLES + (pde_entry * PAGE_SIZE));
|
||||||
|
|
||||||
|
uint32_t p_dst = (uint32_t)p_alloc_frame();
|
||||||
|
uint32_t p_src = (uint32_t)tablev[pte_entry] & 0xFFFFF000;
|
||||||
|
|
||||||
|
map_page(TEMP_PT_SRC, p_src, PAGE_WRITABLE | PAGE_PRESENT);
|
||||||
|
map_page(TEMP_PT_DST, p_dst, PAGE_WRITABLE | PAGE_PRESENT);
|
||||||
|
|
||||||
|
memcpy((void*)TEMP_PT_SRC, (void*)TEMP_PT_DST, PAGE_SIZE);
|
||||||
|
|
||||||
|
unmap_page(TEMP_PT_SRC);
|
||||||
|
unmap_page(TEMP_PT_DST);
|
||||||
|
|
||||||
|
uint32_t flags = tablev[pte_entry] & 0xFFF;
|
||||||
|
flags &= ~PAGE_COW;
|
||||||
|
tablev[pte_entry] = p_dst | flags | PAGE_WRITABLE;
|
||||||
|
|
||||||
|
flush_tlb();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
process_t* task = current_task();
|
||||||
kprintf("\n--- PAGE FAULT ---\n");
|
kprintf("\n--- PAGE FAULT ---\n");
|
||||||
|
kprintf("Current Task PID: %d\n", task->pid);
|
||||||
kprintf("Faulted Virtual Address: 0x%x\n", faulting_address);
|
kprintf("Faulted Virtual Address: 0x%x\n", faulting_address);
|
||||||
kprintf("Error Code: 0x%x\n", args->error_code);
|
kprintf("Error Code: 0x%x\n", args->error_code);
|
||||||
kprintf("Instruction Pointer: 0x%x\n", args->eip);
|
kprintf("Instruction Pointer: 0x%x\n", args->eip);
|
||||||
|
kprintf("Current Stack Pointer: 0x%x\n", (void*)args);
|
||||||
|
kprintf("EAX: 0x%x\n", args->eax);
|
||||||
|
kprintf("EFLAGS: 0x%x\n", args->eflags);
|
||||||
|
kprintf("Code Segment: 0x%x\n", args->cs);
|
||||||
|
kprintf("Current cr3: 0x%x\n", fetch_cr3());
|
||||||
|
if (args->cs == 0x1b) {
|
||||||
|
kprintf("User ESP: 0x%x\n", args->u_esp);
|
||||||
|
kprintf("ESP: 0x%x\t0x%x\t0x%x\t0x%x\n",
|
||||||
|
*(uint32_t*)args->u_esp,
|
||||||
|
*(uint32_t*)(args->u_esp + 4),
|
||||||
|
*(uint32_t*)(args->u_esp + 8),
|
||||||
|
*(uint32_t*)(args->u_esp + 12));
|
||||||
|
kprintf("User SS: 0x%x\n", args->u_ss);
|
||||||
|
}
|
||||||
kprintf("Caused by: %s, %s, running in %s mode\n",
|
kprintf("Caused by: %s, %s, running in %s mode\n",
|
||||||
(args->error_code & 0x01) ? "Protection Violation" : "Page Not Present",
|
(args->error_code & 0x01) ? "Protection Violation" : "Page Not Present",
|
||||||
(args->error_code & 0x02) ? "Write" : "Read",
|
(args->error_code & 0x02) ? "Write" : "Read",
|
||||||
(args->error_code & 0x04) ? "User" : "Supervisor");
|
(args->error_code & 0x04) ? "User" : "Supervisor");
|
||||||
while(1);
|
kpanic();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 32: {
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 33: {
|
case 33: {
|
||||||
uint8_t data = ps2_read_data();
|
uint8_t data = ps2_read_data();
|
||||||
|
char ascii = ps2_get_ascii(data);
|
||||||
|
if (ascii != 0) {
|
||||||
|
kbd_push(ascii);
|
||||||
|
}
|
||||||
send_eoi_master();
|
send_eoi_master();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 46: { // IDE PRIMARY
|
case 46: { // IDE PRIMARY
|
||||||
|
kprintf("IDE PRIMARY interrupt\n");
|
||||||
send_eoi_slave();
|
send_eoi_slave();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 47: { // IDE SLAVE
|
case 47: { // IDE SLAVE
|
||||||
|
kprintf("IDE SLAVE interrupt\n");
|
||||||
send_eoi_slave();
|
send_eoi_slave();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
86
kernel/kbd.c
Normal file
86
kernel/kbd.c
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
#include "kbd.h"
|
||||||
|
#include "process.h"
|
||||||
|
#include "scheduler.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#include <lib/tasks.h>
|
||||||
|
#include <lib/print.h>
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#define KBD_BUFFER_SIZE 256
|
||||||
|
|
||||||
|
static spinlock_t kbd_lock = {0};
|
||||||
|
static process_t* kbd_waiting_task = NULL;
|
||||||
|
|
||||||
|
static char kbd_buffer[KBD_BUFFER_SIZE];
|
||||||
|
static int kbd_head = 0;
|
||||||
|
static int kbd_tail = 0;
|
||||||
|
|
||||||
|
static void lock_kbd() {
|
||||||
|
disable_interrupts();
|
||||||
|
spin_lock(&kbd_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unlock_kbd() {
|
||||||
|
spin_unlock(&kbd_lock);
|
||||||
|
enable_interrupts();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kbd_set_waiting(process_t* task) {
|
||||||
|
lock_kbd();
|
||||||
|
if (kbd_head == kbd_tail) {
|
||||||
|
kbd_waiting_task = task;
|
||||||
|
}
|
||||||
|
unlock_kbd();
|
||||||
|
}
|
||||||
|
|
||||||
|
static char kbd_pop() {
|
||||||
|
char c = 0;
|
||||||
|
lock_kbd();
|
||||||
|
if (kbd_head != kbd_tail) {
|
||||||
|
c = kbd_buffer[kbd_tail];
|
||||||
|
kbd_tail = (kbd_tail + 1) % KBD_BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
unlock_kbd();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void kbd_push(char c) {
|
||||||
|
spin_lock(&kbd_lock);
|
||||||
|
// push to buffer first, very important
|
||||||
|
int next_head = (kbd_head + 1) % KBD_BUFFER_SIZE;
|
||||||
|
if (next_head != kbd_tail) {
|
||||||
|
kbd_buffer[kbd_head] = c;
|
||||||
|
kbd_head = next_head;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kbd_waiting_task != NULL) {
|
||||||
|
wake(kbd_waiting_task);
|
||||||
|
kbd_waiting_task = NULL;
|
||||||
|
}
|
||||||
|
spin_unlock(&kbd_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
int kbd_ready() {
|
||||||
|
int ready = 0;
|
||||||
|
lock_kbd();
|
||||||
|
ready = (kbd_head != kbd_tail);
|
||||||
|
unlock_kbd();
|
||||||
|
return ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
void kbd_wait() {
|
||||||
|
process_t* task = current_task();
|
||||||
|
while (!kbd_ready()) {
|
||||||
|
task->state = STATE_BLOCKED;
|
||||||
|
kbd_set_waiting(task);
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t kbd_read(struct vfs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer) {
|
||||||
|
if (!kbd_ready()) return -1;
|
||||||
|
buffer[0] = kbd_pop();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
9
kernel/kbd.h
Normal file
9
kernel/kbd.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <vfs.h>
|
||||||
|
|
||||||
|
uint32_t kbd_read(struct vfs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer);
|
||||||
|
void kbd_push(char c);
|
||||||
|
int kbd_ready();
|
||||||
|
void kbd_wait();
|
||||||
134
kernel/kmain.c
134
kernel/kmain.c
@@ -1,13 +1,17 @@
|
|||||||
#include "multiboot.h"
|
#include "multiboot.h"
|
||||||
#include "interrupts.h"
|
#include "interrupts.h"
|
||||||
#include "gdt.h"
|
#include "gdt.h"
|
||||||
#include "scheduler.h"
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "initrd.h"
|
#include "scheduler.h"
|
||||||
|
#include "vfs.h"
|
||||||
|
#include "elf.h"
|
||||||
|
#include "gdt.h"
|
||||||
|
#include "kbd.h"
|
||||||
|
|
||||||
#include <lib/print.h>
|
#include <lib/print.h>
|
||||||
#include <lib/stream.h>
|
#include <lib/stream.h>
|
||||||
#include <lib/memory.h>
|
#include <lib/memory.h>
|
||||||
|
#include <lib/console.h>
|
||||||
|
|
||||||
#include <memory/mm.h>
|
#include <memory/mm.h>
|
||||||
|
|
||||||
@@ -17,6 +21,9 @@
|
|||||||
#include <drivers/ps2/ps2.h>
|
#include <drivers/ps2/ps2.h>
|
||||||
#include <drivers/pit/pit.h>
|
#include <drivers/pit/pit.h>
|
||||||
#include <drivers/vga/vga.h>
|
#include <drivers/vga/vga.h>
|
||||||
|
#include <drivers/cpio/cpio.h>
|
||||||
|
#include <drivers/devfs/devfs.h>
|
||||||
|
#include <drivers/serial/serial.h>
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -24,6 +31,11 @@
|
|||||||
extern char __kernel_start;
|
extern char __kernel_start;
|
||||||
extern char __kernel_end;
|
extern char __kernel_end;
|
||||||
|
|
||||||
|
#define SERIAL_DBG
|
||||||
|
|
||||||
|
extern uint32_t page_directory[1024];
|
||||||
|
void* kernel_cr3 = page_directory;
|
||||||
|
|
||||||
void parse_multiboot_modules(uint32_t mbi_vaddr) {
|
void parse_multiboot_modules(uint32_t mbi_vaddr) {
|
||||||
// find where grub put the boot module containing initrd
|
// find where grub put the boot module containing initrd
|
||||||
multiboot_info* mbi = (multiboot_info*)mbi_vaddr;
|
multiboot_info* mbi = (multiboot_info*)mbi_vaddr;
|
||||||
@@ -31,8 +43,6 @@ void parse_multiboot_modules(uint32_t mbi_vaddr) {
|
|||||||
uint32_t mod_count = mbi->mods_count;
|
uint32_t mod_count = mbi->mods_count;
|
||||||
multiboot_module_t* mod = (multiboot_module_t*)((uint32_t)mbi->mods_addr + 0xC0000000);
|
multiboot_module_t* mod = (multiboot_module_t*)((uint32_t)mbi->mods_addr + 0xC0000000);
|
||||||
|
|
||||||
kprintf("found %d mods starting @ [v]0x%x\n", mod_count, (uint32_t)mod);
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < mod_count; i++) {
|
for (uint32_t i = 0; i < mod_count; i++) {
|
||||||
uint32_t start = mod[i].mod_start;
|
uint32_t start = mod[i].mod_start;
|
||||||
uint32_t end = mod[i].mod_end;
|
uint32_t end = mod[i].mod_end;
|
||||||
@@ -44,40 +54,120 @@ void parse_multiboot_modules(uint32_t mbi_vaddr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_initrd() {
|
vfs_node_t* load_initrd() {
|
||||||
multiboot_module_t* initrd_module = &multiboot_module_info_table[0];
|
multiboot_module_t* initrd_module = &multiboot_module_info_table[0];
|
||||||
kprintf("initrd found @ [v] 0x%x\n", initrd_module->mod_start);
|
kprintf("initrd found @ [v] 0x%x\n", initrd_module->mod_start);
|
||||||
kprintf("reading initrd\n");
|
return cpio_read_fs(initrd_module->mod_start);
|
||||||
|
|
||||||
parse_cpio((void*)initrd_module->mod_start);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void kmain(uint32_t magic, multiboot_info* mbi) {
|
void load_root_program(const char* path) {
|
||||||
|
lock_scheduler();
|
||||||
|
uint32_t kernel_cr3 = fetch_cr3();
|
||||||
|
void* cr3 = create_new_pd();
|
||||||
|
|
||||||
|
load_pd(cr3);
|
||||||
|
flush_tlb();
|
||||||
|
|
||||||
|
uint32_t eip = load_elf_program(path);
|
||||||
|
if (eip == 0) {
|
||||||
|
kprintf("Failed to load elf program file\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t stack_sz = PAGE_SIZE * 16;
|
||||||
|
uint32_t stack_top = 0xBFFF0000;
|
||||||
|
uint32_t stack_bottom = stack_top - stack_sz;
|
||||||
|
for (uint32_t vaddr = stack_bottom; vaddr < stack_top; vaddr += PAGE_SIZE) {
|
||||||
|
void* phys_frame = p_alloc_frame();
|
||||||
|
map_page(vaddr, (uint32_t)phys_frame, PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t* u_esp = (uint32_t*)stack_top;
|
||||||
|
*(--u_esp) = 0; // envp = NULL
|
||||||
|
*(--u_esp) = 0; // argv = NULL
|
||||||
|
*(--u_esp) = 0; // argc = 0
|
||||||
|
|
||||||
|
process_t* process = kalloc(sizeof(process_t));
|
||||||
|
init_task(process, eip, (uint32_t)cr3, 1, (uint32_t)u_esp);
|
||||||
|
add_task(process);
|
||||||
|
|
||||||
|
unlock_scheduler();
|
||||||
|
|
||||||
|
load_pd((void*)kernel_cr3);
|
||||||
|
flush_tlb();
|
||||||
|
}
|
||||||
|
|
||||||
|
void kmain(multiboot_info* mbi) {
|
||||||
disable_interrupts();
|
disable_interrupts();
|
||||||
if (!(mbi->flags & (1 << 6))) {
|
|
||||||
|
init_serial();
|
||||||
|
|
||||||
|
// need mmap and fb info
|
||||||
|
if (!(mbi->flags & (1 << 6)) || !(mbi->flags & (1 << 12))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
vga_init();
|
parse_multiboot_modules((uint32_t)mbi);
|
||||||
|
|
||||||
uint32_t mmap_virtual_addr = mbi->mmap_addr + 0xC0000000;
|
uint32_t vga_fb_address = mbi->framebuffer_addr;
|
||||||
init_pmm((void*)mmap_virtual_addr, mbi->mmap_length);
|
uint32_t vga_fb_width = mbi->framebuffer_width;
|
||||||
kprintf("memory detection complete. total free memory: %dMB\n", total_free_memory() / 1024 / 1024);
|
uint32_t vga_fb_height = mbi->framebuffer_height;
|
||||||
|
uint32_t vga_fb_pitch = mbi->framebuffer_pitch;
|
||||||
|
uint32_t vga_fb_bpp = mbi->framebuffer_bpp;
|
||||||
|
|
||||||
init_gdt();
|
init_gdt();
|
||||||
init_idt();
|
init_idt();
|
||||||
init_pic();
|
init_pic();
|
||||||
init_pit();
|
init_pit();
|
||||||
|
|
||||||
|
uint32_t mmap_virtual_addr = mbi->mmap_addr + 0xC0000000;
|
||||||
|
init_pmm((void*)mmap_virtual_addr, mbi->mmap_length);
|
||||||
init_page_tables();
|
init_page_tables();
|
||||||
|
|
||||||
parse_multiboot_modules((uint32_t)mbi);
|
disable_interrupts();
|
||||||
|
|
||||||
load_initrd();
|
|
||||||
|
|
||||||
kprintf("basic initializations complete\n");
|
|
||||||
|
|
||||||
disable_interrupts(); // just paranoid... do it again
|
|
||||||
init_scheduler();
|
init_scheduler();
|
||||||
enable_interrupts();
|
enable_interrupts();
|
||||||
|
|
||||||
|
vfs_node_t* vfs_root = vfs_create_root();
|
||||||
|
vfs_node_t* initrd_root = load_initrd();
|
||||||
|
|
||||||
|
if (!initrd_root) {
|
||||||
|
kprintf("failed to load initrd\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
vfs_mount(vfs_root, initrd_root);
|
||||||
|
kprintf("initrd read, mounted @ /\n");
|
||||||
|
|
||||||
|
vfs_node_t* devfs = create_devfs();
|
||||||
|
if (!devfs) {
|
||||||
|
kprintf("failed to create devfs\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vfs_node_t* kbd_dev = devfs->create(devfs, "kbd");
|
||||||
|
kbd_dev->read = kbd_read;
|
||||||
|
|
||||||
|
vfs_node_t* vga_dev = devfs->create(devfs, "vga");
|
||||||
|
vga_init(vga_dev,
|
||||||
|
vga_fb_address,
|
||||||
|
vga_fb_width,
|
||||||
|
vga_fb_height,
|
||||||
|
vga_fb_pitch,
|
||||||
|
vga_fb_bpp);
|
||||||
|
|
||||||
|
kprintf("vga initialized\n");
|
||||||
|
|
||||||
|
vfs_node_t* dev = vfs_find("/dev");
|
||||||
|
if (!dev) {
|
||||||
|
kprintf("failed to find dev mnt point\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->mnt = devfs;
|
||||||
|
kprintf("mounted devfs\n");
|
||||||
|
|
||||||
|
kprintf("basic initializations complete\n");
|
||||||
|
kprintf("starting rockos\n");
|
||||||
|
|
||||||
|
load_root_program("/usr/bin/rockterm");
|
||||||
}
|
}
|
||||||
|
|||||||
92
kernel/lib/console.c
Normal file
92
kernel/lib/console.c
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
#include "drivers/serial/serial.h"
|
||||||
|
|
||||||
|
#include <lib/console.h>
|
||||||
|
#include <lib/font.h>
|
||||||
|
#include <lib/print.h>
|
||||||
|
|
||||||
|
#include <drivers/vga/vga.h>
|
||||||
|
|
||||||
|
static psf_font_t* font;
|
||||||
|
|
||||||
|
static uint32_t console_row;
|
||||||
|
static uint32_t console_col;
|
||||||
|
static uint32_t console_width;
|
||||||
|
static uint32_t console_height;
|
||||||
|
static uint32_t console_text_color;
|
||||||
|
static uint32_t console_backgrnd_color;
|
||||||
|
|
||||||
|
static void write_vga_char(char c) {
|
||||||
|
uint32_t vga_pitch = vga_get_pitch();
|
||||||
|
uint8_t* glyph = (uint8_t*)font->glyphs + (c * font->hdr->charsz);
|
||||||
|
|
||||||
|
uint32_t pixel_y_start = console_row * font->hdr->charsz;
|
||||||
|
uint32_t pixel_x_start = console_col * 8;
|
||||||
|
|
||||||
|
for (uint32_t y = 0; y < font->hdr->charsz; y++) {
|
||||||
|
uint8_t bits = glyph[y];
|
||||||
|
uint8_t* row_bytes = (uint8_t*)VGA_FRAMEBUFFER + ((pixel_y_start + y) * vga_pitch);
|
||||||
|
uint32_t* pixel_row = (uint32_t*)row_bytes;
|
||||||
|
|
||||||
|
for (int x = 0; x < 8; x++) {
|
||||||
|
if (bits & (0b10000000 >> x)) {
|
||||||
|
pixel_row[pixel_x_start + x] = console_text_color;
|
||||||
|
} else {
|
||||||
|
pixel_row[pixel_x_start + x] = console_backgrnd_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int set_console_font(const char* path) {
|
||||||
|
font = load_font(path);
|
||||||
|
if (!font) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
console_width = vga_get_width() / 8;
|
||||||
|
console_height = vga_get_height() / font->hdr->charsz;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_console_fg(uint32_t color) {
|
||||||
|
console_text_color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_console_bg(uint32_t color) {
|
||||||
|
console_backgrnd_color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void console_init() {
|
||||||
|
console_row = 0;
|
||||||
|
console_col = 0;
|
||||||
|
|
||||||
|
set_console_fg(0xFFFFFFFF);
|
||||||
|
set_console_bg(0xFF6c7482);
|
||||||
|
vga_clear_scrn(console_backgrnd_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void console_putchar(char c) {
|
||||||
|
if (!font) return;
|
||||||
|
|
||||||
|
if (c == '\n') {
|
||||||
|
console_col = 0;
|
||||||
|
console_row++;
|
||||||
|
if (console_row >= console_height) {
|
||||||
|
console_row = 0;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_vga_char(c);
|
||||||
|
|
||||||
|
console_col++;
|
||||||
|
if (console_col >= console_width) {
|
||||||
|
console_col = 0;
|
||||||
|
console_row++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (console_row >= console_height) {
|
||||||
|
console_row = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
kernel/lib/console.h
Normal file
13
kernel/lib/console.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#ifndef D_CONSOLE_H
|
||||||
|
#define D_CONSOLE_H
|
||||||
|
|
||||||
|
#include <lib/font.h>
|
||||||
|
|
||||||
|
void console_putchar(char c);
|
||||||
|
|
||||||
|
int set_console_font(const char* path);
|
||||||
|
void set_console_fg(uint32_t color);
|
||||||
|
void set_console_bg(uint32_t color);
|
||||||
|
void console_init();
|
||||||
|
|
||||||
|
#endif
|
||||||
48
kernel/lib/font.c
Normal file
48
kernel/lib/font.c
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#include "drivers/serial/serial.h"
|
||||||
|
#include "vfs.h"
|
||||||
|
#include <lib/font.h>
|
||||||
|
#include <lib/memory.h>
|
||||||
|
#include <lib/print.h>
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
psf_font_t* load_font(const char* path) {
|
||||||
|
int fd = vfs_open(path, 0);
|
||||||
|
if (fd == -1) {
|
||||||
|
kprintf("failed to open font file %s\n", path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
psf_hdr_t* header = kalloc(sizeof(psf_hdr_t));
|
||||||
|
int rd = vfs_read(fd, header, sizeof(psf_hdr_t));
|
||||||
|
if (rd <= 0) {
|
||||||
|
kprintf("failed to read font header\n");
|
||||||
|
kfree(header);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t num_glyphs = (header->mode & (1 << 0)) ? 512 : 256;
|
||||||
|
uint32_t glyph_sz = header->charsz;
|
||||||
|
uint32_t glyph_buf_sz = num_glyphs * glyph_sz;
|
||||||
|
|
||||||
|
void* glyphs = kalloc(glyph_buf_sz);
|
||||||
|
|
||||||
|
rd = 0;
|
||||||
|
rd = vfs_read(fd, glyphs, glyph_buf_sz);
|
||||||
|
if (rd <= 0) {
|
||||||
|
kfree(header);
|
||||||
|
kfree(glyphs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
psf_font_t* font = kalloc(sizeof(psf_font_t));
|
||||||
|
font->hdr = header;
|
||||||
|
font->glyphs = glyphs;
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_font(psf_font_t* font) {
|
||||||
|
kfree(font->glyphs);
|
||||||
|
kfree(font->hdr);
|
||||||
|
kfree(font);
|
||||||
|
}
|
||||||
20
kernel/lib/font.h
Normal file
20
kernel/lib/font.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef KFONT_H
|
||||||
|
#define KFONT_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t magic[2];
|
||||||
|
uint8_t mode;
|
||||||
|
uint8_t charsz;
|
||||||
|
} psf_hdr_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
psf_hdr_t* hdr;
|
||||||
|
void* glyphs;
|
||||||
|
} psf_font_t;
|
||||||
|
|
||||||
|
psf_font_t* load_font(const char* path);
|
||||||
|
void free_font(psf_font_t* font);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -15,7 +15,7 @@ void memcpy(const void* src, void* dst, size_t sz) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void memset(const uint8_t* dst, uint8_t val, size_t sz) {
|
void memset(uint8_t* dst, uint8_t val, size_t sz) {
|
||||||
for (size_t i = 0; i < sz; i++) {
|
for (size_t i = 0; i < sz; i++) {
|
||||||
((uint8_t*)dst)[i] = val;
|
((uint8_t*)dst)[i] = val;
|
||||||
}
|
}
|
||||||
@@ -58,6 +58,14 @@ int strncmp(const char *s1, const char *s2, size_t n) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* strcpy(char* dest, const char* src) {
|
||||||
|
char* saved_dest = dest;
|
||||||
|
|
||||||
|
while ((*dest++ = *src++) != '\0') {}
|
||||||
|
|
||||||
|
return saved_dest;
|
||||||
|
}
|
||||||
|
|
||||||
static void* kernel_heap_start = (void*)KHEAP_START;
|
static void* kernel_heap_start = (void*)KHEAP_START;
|
||||||
static void* kernel_heap_end = (void*)KHEAP_START;
|
static void* kernel_heap_end = (void*)KHEAP_START;
|
||||||
alloc_header_t* blk_list = NULL;
|
alloc_header_t* blk_list = NULL;
|
||||||
@@ -126,4 +134,8 @@ void* kalloc(size_t sz) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return kalloc(sz);
|
return kalloc(sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
void kfree(void* ptr) {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -5,14 +5,15 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
void memcpy(const void* src, void* dst, size_t sz);
|
void memcpy(const void* src, void* dst, size_t sz);
|
||||||
void memset(const uint8_t* dst, uint8_t val, size_t sz);
|
void memset(uint8_t* dst, uint8_t val, size_t sz);
|
||||||
|
|
||||||
int strcmp(const char *s1, const char *s2);
|
int strcmp(const char *s1, const char *s2);
|
||||||
int strncmp(const char *s1, const char *s2, size_t n);
|
int strncmp(const char *s1, const char *s2, size_t n);
|
||||||
int strlen(const char* str);
|
int strlen(const char* str);
|
||||||
|
char* strcpy(char* dest, const char* src);
|
||||||
|
|
||||||
void kgrow(size_t pages);
|
void kgrow(size_t pages);
|
||||||
void* kalloc(size_t sz);
|
void* kalloc(size_t sz);
|
||||||
|
void kfree(void* ptr);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,25 +1,33 @@
|
|||||||
#include "print.h"
|
#include "print.h"
|
||||||
|
#include "drivers/serial/serial.h"
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
#include "tasks.h"
|
#include "tasks.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
#include <drivers/vga/vga.h>
|
#include <drivers/vga/vga.h>
|
||||||
|
#include <lib/console.h>
|
||||||
|
|
||||||
spinlock_t kwrite_lock = {0};
|
spinlock_t kwrite_lock = {0};
|
||||||
|
|
||||||
|
extern psf_font_t* kfont;
|
||||||
|
|
||||||
static char* hex_chars = "0123456789abcdef";
|
static char* hex_chars = "0123456789abcdef";
|
||||||
|
|
||||||
|
static void kwrite(char c) {
|
||||||
|
write_serial(c);
|
||||||
|
}
|
||||||
|
|
||||||
static void kprint(const char *str) {
|
static void kprint(const char *str) {
|
||||||
while (*str) {
|
while (*str) {
|
||||||
vga_putchar(*str);
|
kwrite(*str);
|
||||||
str++;
|
str++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kputd(int d) {
|
static void kputd(int d) {
|
||||||
if (d == 0) {
|
if (d == 0) {
|
||||||
vga_putchar('0');
|
kwrite('0');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
char buffer[12];
|
char buffer[12];
|
||||||
@@ -29,13 +37,13 @@ static void kputd(int d) {
|
|||||||
d /= 10;
|
d /= 10;
|
||||||
}
|
}
|
||||||
for (int j = i - 1; j >= 0; j--) {
|
for (int j = i - 1; j >= 0; j--) {
|
||||||
vga_putchar(buffer[j]);
|
kwrite(buffer[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kputx(unsigned int x) {
|
static void kputx(unsigned int x) {
|
||||||
if (x == 0) {
|
if (x == 0) {
|
||||||
vga_putchar('0');
|
kwrite('0');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
char buffer[8];
|
char buffer[8];
|
||||||
@@ -46,13 +54,13 @@ static void kputx(unsigned int x) {
|
|||||||
x >>= 4;
|
x >>= 4;
|
||||||
}
|
}
|
||||||
for (int j = i - 1; j >= 0; j--) {
|
for (int j = i - 1; j >= 0; j--) {
|
||||||
vga_putchar(buffer[j]);
|
kwrite(buffer[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void kputc(const char c) {
|
void kputc(const char c) {
|
||||||
spin_lock(&kwrite_lock);
|
spin_lock(&kwrite_lock);
|
||||||
vga_putchar(c);
|
kwrite(c);
|
||||||
spin_unlock(&kwrite_lock);
|
spin_unlock(&kwrite_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,17 +88,22 @@ void kprintf(const char* fmt, ...) {
|
|||||||
kputx(x);
|
kputx(x);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'c': {
|
||||||
|
int c = va_arg(args, int);
|
||||||
|
kwrite((char)c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case '%':
|
case '%':
|
||||||
vga_putchar('%');
|
kwrite('%');
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
vga_putchar('%');
|
kwrite('%');
|
||||||
vga_putchar(*fmt);
|
kwrite(*fmt);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fmt++;
|
fmt++;
|
||||||
} else {
|
} else {
|
||||||
vga_putchar(*fmt);
|
kwrite(*fmt);
|
||||||
fmt++;
|
fmt++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
34
kernel/lib/ringbuf.c
Normal file
34
kernel/lib/ringbuf.c
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#include <lib/ringbuf.h>
|
||||||
|
|
||||||
|
void ring_buf_init(ring_buf_t* rb) {
|
||||||
|
rb->head = 0;
|
||||||
|
rb->tail = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ring_buf_is_empty(ring_buf_t* rb) {
|
||||||
|
return rb->head == rb->tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ring_buf_is_full(ring_buf_t* rb) {
|
||||||
|
return ((rb->head + 1) % PTY_BUFFER_SIZE) == rb->tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ring_buf_write(ring_buf_t *buf, char c) {
|
||||||
|
if (ring_buf_is_full(buf)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf->data[buf->head] = c;
|
||||||
|
buf->head = (buf->head + 1) % PTY_BUFFER_SIZE;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ring_buf_read(ring_buf_t *buf, char *c) {
|
||||||
|
if (ring_buf_is_empty(buf)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*c = buf->data[buf->tail];
|
||||||
|
buf->tail = (buf->tail + 1) % PTY_BUFFER_SIZE;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
20
kernel/lib/ringbuf.h
Normal file
20
kernel/lib/ringbuf.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef KRINGBUF_H
|
||||||
|
#define KRINGBUF_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#define PTY_BUFFER_SIZE 1024
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char data[PTY_BUFFER_SIZE];
|
||||||
|
size_t head;
|
||||||
|
size_t tail;
|
||||||
|
} ring_buf_t;
|
||||||
|
|
||||||
|
void ring_buf_init(ring_buf_t* rb);
|
||||||
|
int ring_buf_is_empty(ring_buf_t* rb);
|
||||||
|
int ring_buf_is_full(ring_buf_t* rb);
|
||||||
|
int ring_buf_write(ring_buf_t *buf, char c);
|
||||||
|
int ring_buf_read(ring_buf_t *buf, char *c);
|
||||||
|
|
||||||
|
#endif
|
||||||
6
kernel/lib/string.h
Normal file
6
kernel/lib/string.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#ifndef KSTRING_H
|
||||||
|
#define KSTRING_H
|
||||||
|
|
||||||
|
char* strtok_r(char *s, const char *delim, char **saveptr);
|
||||||
|
|
||||||
|
#endif
|
||||||
65
kernel/lib/strtok.c
Normal file
65
kernel/lib/strtok.c
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#include <lib/string.h>
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
static size_t kernel_strspn(const char *s, const char *accept) {
|
||||||
|
const char *p;
|
||||||
|
const char *a;
|
||||||
|
size_t count = 0;
|
||||||
|
|
||||||
|
for (p = s; *p != '\0'; ++p) {
|
||||||
|
for (a = accept; *a != '\0'; ++a) {
|
||||||
|
if (*p == *a)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (*a == '\0')
|
||||||
|
return count;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *kernel_strpbrk(const char *s, const char *accept) {
|
||||||
|
while (*s != '\0') {
|
||||||
|
const char *a = accept;
|
||||||
|
while (*a != '\0') {
|
||||||
|
if (*s == *a) {
|
||||||
|
return (char *)s;
|
||||||
|
}
|
||||||
|
a++;
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strtok_r(char *str, const char *delim, char **saveptr) {
|
||||||
|
char *token;
|
||||||
|
|
||||||
|
if (str == NULL) {
|
||||||
|
str = *saveptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str == NULL || *str == '\0') {
|
||||||
|
*saveptr = NULL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
str += kernel_strspn(str, delim);
|
||||||
|
if (*str == '\0') {
|
||||||
|
*saveptr = NULL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
token = str;
|
||||||
|
str = kernel_strpbrk(token, delim);
|
||||||
|
|
||||||
|
if (str == NULL) {
|
||||||
|
*saveptr = NULL;
|
||||||
|
} else {
|
||||||
|
*str = '\0';
|
||||||
|
*saveptr = str + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
@@ -1,24 +1,13 @@
|
|||||||
#include "memory/mm.h"
|
#include "memory/mm.h"
|
||||||
#include "lib/print.h"
|
|
||||||
#include "multiboot.h"
|
#include "multiboot.h"
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <lib/memory.h>
|
||||||
|
|
||||||
extern uint8_t __kernel_start;
|
extern uint8_t __kernel_start;
|
||||||
extern uint8_t __kernel_end;
|
extern uint8_t __kernel_end;
|
||||||
|
|
||||||
extern uint32_t page_directory[1024];
|
extern uint32_t page_directory[1024];
|
||||||
extern void flush_tlb();
|
|
||||||
extern void disable_pae();
|
|
||||||
|
|
||||||
#define PAGE_SIZE 4096
|
|
||||||
#define MAX_RAM 0xFFFFFFFF // 4GB
|
|
||||||
#define BITMAP_SIZE ((MAX_RAM / PAGE_SIZE) / 8)
|
|
||||||
|
|
||||||
#define PAGE_TABLES 0xFFC00000
|
|
||||||
#define PAGE_DIRECTORY 0xFFFFF000
|
|
||||||
|
|
||||||
#define TEMP_MAPPING_VADDR 0xDFFF0000
|
|
||||||
|
|
||||||
static uint32_t max_address = 0;
|
static uint32_t max_address = 0;
|
||||||
static uint32_t total_available_memory = 0;
|
static uint32_t total_available_memory = 0;
|
||||||
@@ -117,8 +106,8 @@ void p_free_frame(void* addr) {
|
|||||||
void map_page(uint32_t vaddr, uint32_t paddr, uint32_t flags) {
|
void map_page(uint32_t vaddr, uint32_t paddr, uint32_t flags) {
|
||||||
uint32_t pde_entry = vaddr >> 22;
|
uint32_t pde_entry = vaddr >> 22;
|
||||||
uint32_t pte_entry = (vaddr >> 12) & 0x3FF;
|
uint32_t pte_entry = (vaddr >> 12) & 0x3FF;
|
||||||
uint32_t* pd = (uint32_t*)PAGE_DIRECTORY;
|
uint32_t* pd = (uint32_t*)CUR_PAGE_DIRECTORY;
|
||||||
uint32_t* tablev = (uint32_t*)(PAGE_TABLES + (pde_entry * PAGE_SIZE));
|
uint32_t* tablev = (uint32_t*)(CUR_PAGE_TABLES + (pde_entry * PAGE_SIZE));
|
||||||
|
|
||||||
if ((pd[pde_entry] & PAGE_PRESENT) == 0) {
|
if ((pd[pde_entry] & PAGE_PRESENT) == 0) {
|
||||||
uint32_t new_table = (uint32_t)p_alloc_frame();
|
uint32_t new_table = (uint32_t)p_alloc_frame();
|
||||||
@@ -133,6 +122,35 @@ void map_page(uint32_t vaddr, uint32_t paddr, uint32_t flags) {
|
|||||||
flush_tlb();
|
flush_tlb();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void unmap_page(uint32_t vaddr) {
|
||||||
|
uint32_t pde_entry = vaddr >> 22;
|
||||||
|
uint32_t pte_entry = (vaddr >> 12) & 0x3FF;
|
||||||
|
uint32_t* tablev = (uint32_t*)(CUR_PAGE_TABLES + (pde_entry * PAGE_SIZE));
|
||||||
|
tablev[pte_entry] = 0;
|
||||||
|
flush_tlb();
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_cow(uint32_t vaddr) {
|
||||||
|
uint32_t pde_entry = vaddr >> 22;
|
||||||
|
uint32_t pte_entry = (vaddr >> 12) & 0x3FF;
|
||||||
|
uint32_t* pd = (uint32_t*)CUR_PAGE_DIRECTORY;
|
||||||
|
uint32_t* tablev = (uint32_t*)(CUR_PAGE_TABLES + (pde_entry * PAGE_SIZE));
|
||||||
|
|
||||||
|
if (!(pd[pde_entry] & PAGE_PRESENT)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tablev[pte_entry] & PAGE_WRITABLE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(tablev[pte_entry] & PAGE_COW)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void init_pmm(void* mmap_base, uint32_t mmap_limit) {
|
void init_pmm(void* mmap_base, uint32_t mmap_limit) {
|
||||||
for (int i = 0; i < BITMAP_SIZE; i++) {
|
for (int i = 0; i < BITMAP_SIZE; i++) {
|
||||||
memory_bitmap[i] = 0xFF;
|
memory_bitmap[i] = 0xFF;
|
||||||
@@ -163,30 +181,94 @@ uint32_t total_free_memory() {
|
|||||||
return total_available_memory;
|
return total_available_memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* create_task_pd() {
|
void* create_new_pd() {
|
||||||
uint32_t pd_address = (uint32_t)p_alloc_frame();
|
uint32_t task_pd_addr = (uint32_t)p_alloc_frame();
|
||||||
if (pd_address == 0) {
|
if (task_pd_addr == 0) {
|
||||||
return 0;
|
return NULL; // outta mem
|
||||||
}
|
}
|
||||||
|
|
||||||
map_page(TEMP_MAPPING_VADDR, pd_address, PAGE_PRESENT | PAGE_WRITABLE);
|
map_page(TEMP_TASKPD_VADDR, task_pd_addr, PAGE_PRESENT | PAGE_WRITABLE);
|
||||||
|
|
||||||
uint32_t* task_pd = (uint32_t*)TEMP_MAPPING_VADDR;
|
uint32_t* task_pd = (uint32_t*)TEMP_TASKPD_VADDR;
|
||||||
uint32_t* kernel_pd = (uint32_t*)PAGE_DIRECTORY;
|
uint32_t* parent_pd = (uint32_t*)CUR_PAGE_DIRECTORY;
|
||||||
|
|
||||||
|
for(int i = 768; i < 1023; i++) {
|
||||||
|
task_pd[i] = parent_pd[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
task_pd[1023] = task_pd_addr | PAGE_PRESENT | PAGE_WRITABLE;
|
||||||
|
|
||||||
for(int i = 0; i < 768; i++) {
|
for(int i = 0; i < 768; i++) {
|
||||||
task_pd[i] = 0;
|
task_pd[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 768; i < 1023; i++) {
|
unmap_page(TEMP_TASKPD_VADDR);
|
||||||
task_pd[i] = kernel_pd[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
task_pd[1023] = (uint32_t)pd_address | PAGE_PRESENT | PAGE_WRITABLE;
|
|
||||||
|
|
||||||
uint32_t pde = TEMP_MAPPING_VADDR >> 22;
|
return (void*)task_pd_addr;
|
||||||
uint32_t pte = (TEMP_MAPPING_VADDR >> 12) & 0x3FF;
|
}
|
||||||
uint32_t* kernel_pt = (uint32_t*)(PAGE_TABLES + (pde * PAGE_SIZE));
|
|
||||||
kernel_pt[pte] = 0;
|
void* clone_current_pd() {
|
||||||
return (void*)pd_address;
|
uint32_t task_pd_addr = (uint32_t)p_alloc_frame();
|
||||||
|
if (task_pd_addr == 0) {
|
||||||
|
return NULL; // outta mem
|
||||||
|
}
|
||||||
|
|
||||||
|
map_page(TEMP_TASKPD_VADDR, task_pd_addr, PAGE_PRESENT | PAGE_WRITABLE);
|
||||||
|
|
||||||
|
uint32_t* task_pd = (uint32_t*)TEMP_TASKPD_VADDR;
|
||||||
|
uint32_t* parent_pd = (uint32_t*)CUR_PAGE_DIRECTORY;
|
||||||
|
|
||||||
|
for(int i = 768; i < 1023; i++) {
|
||||||
|
task_pd[i] = parent_pd[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
task_pd[1023] = task_pd_addr | PAGE_PRESENT | PAGE_WRITABLE;
|
||||||
|
|
||||||
|
for(int i = 0; i < 768; i++) {
|
||||||
|
task_pd[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 768; i++) {
|
||||||
|
uint32_t pde = parent_pd[i];
|
||||||
|
if (!(pde & PAGE_PRESENT)) continue;
|
||||||
|
|
||||||
|
uint32_t task_pt = (uint32_t)p_alloc_frame();
|
||||||
|
task_pd[i] = task_pt | (pde & 0xFFF);
|
||||||
|
|
||||||
|
uint32_t parent_pt = pde & 0xFFFFF000;
|
||||||
|
|
||||||
|
map_page(TEMP_PT_DST, task_pt, PAGE_PRESENT | PAGE_WRITABLE);
|
||||||
|
map_page(TEMP_PT_SRC, parent_pt, PAGE_PRESENT | PAGE_WRITABLE);
|
||||||
|
|
||||||
|
uint32_t* pt_dst = (uint32_t*)TEMP_PT_DST;
|
||||||
|
uint32_t* pt_src = (uint32_t*)TEMP_PT_SRC;
|
||||||
|
|
||||||
|
for(int j = 0; j < 1024; j++) {
|
||||||
|
uint32_t pte_src = pt_src[j];
|
||||||
|
if (!(pte_src & PAGE_PRESENT)) continue;
|
||||||
|
|
||||||
|
if (!(pte_src & PAGE_WRITABLE) || (pte_src & PAGE_MMIO)) {
|
||||||
|
pt_dst[j] = pt_src[j];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the src page is writable, mark the pte src as read only and COW, then copy to dst pte
|
||||||
|
pt_src[j] &= ~(PAGE_WRITABLE);
|
||||||
|
pt_src[j] |= PAGE_COW;
|
||||||
|
flush_tlb(); // huge performance hit here, and probably everywhere else too where we aren't switching cr3s
|
||||||
|
|
||||||
|
pt_dst[j] = pt_src[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
unmap_page(TEMP_PT_DST);
|
||||||
|
unmap_page(TEMP_PT_SRC);
|
||||||
|
}
|
||||||
|
|
||||||
|
unmap_page(TEMP_TASKPD_VADDR);
|
||||||
|
|
||||||
|
return (void*)task_pd_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_current_pd() {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -3,12 +3,25 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define PAGE_PRESENT 0x1
|
#define PAGE_PRESENT (1 << 0)
|
||||||
#define PAGE_WRITABLE 0x2
|
#define PAGE_WRITABLE (1 << 1)
|
||||||
#define PAGE_USER 0x4
|
#define PAGE_USER (1 << 2)
|
||||||
|
#define PAGE_COW (1 << 9)
|
||||||
|
#define PAGE_MMIO (1 << 10)
|
||||||
|
|
||||||
|
#define TEMP_KERNPD_VADDR 0xDFF90000
|
||||||
|
#define TEMP_TASKPD_VADDR 0xDFFA0000
|
||||||
|
#define TEMP_PT_SRC 0xDFFB0000
|
||||||
|
#define TEMP_PT_DST 0xDFFC0000
|
||||||
|
|
||||||
#define PAGE_SIZE 4096
|
#define PAGE_SIZE 4096
|
||||||
|
|
||||||
|
#define MAX_RAM 0xFFFFFFFF // 4GB
|
||||||
|
#define BITMAP_SIZE ((MAX_RAM / PAGE_SIZE) / 8)
|
||||||
|
|
||||||
|
#define CUR_PAGE_DIRECTORY 0xFFFFF000
|
||||||
|
#define CUR_PAGE_TABLES 0xFFC00000
|
||||||
|
|
||||||
typedef struct __attribute__((packed)) {
|
typedef struct __attribute__((packed)) {
|
||||||
uint32_t addr;
|
uint32_t addr;
|
||||||
} mem_page_t;
|
} mem_page_t;
|
||||||
@@ -20,8 +33,18 @@ void* p_alloc_frame();
|
|||||||
|
|
||||||
uint32_t total_free_memory();
|
uint32_t total_free_memory();
|
||||||
|
|
||||||
void* create_task_pd();
|
void* create_new_pd();
|
||||||
|
void* clone_current_pd();
|
||||||
|
void clear_current_pd();
|
||||||
|
|
||||||
|
int is_cow(uint32_t vaddr);
|
||||||
|
|
||||||
void map_page(uint32_t vaddr, uint32_t paddr, uint32_t flags);
|
void map_page(uint32_t vaddr, uint32_t paddr, uint32_t flags);
|
||||||
|
void unmap_page(uint32_t vaddr);
|
||||||
|
|
||||||
|
void load_pd(void* paddr);
|
||||||
|
|
||||||
|
void flush_tlb();
|
||||||
|
void disable_pae();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -17,6 +17,29 @@ typedef struct {
|
|||||||
uint32_t shndx;
|
uint32_t shndx;
|
||||||
uint32_t mmap_length;
|
uint32_t mmap_length;
|
||||||
uint32_t mmap_addr;
|
uint32_t mmap_addr;
|
||||||
|
uint32_t drives_length;
|
||||||
|
uint32_t drives_addr;
|
||||||
|
uint32_t config_table;
|
||||||
|
uint32_t boot_loader_name;
|
||||||
|
uint32_t apm_table;
|
||||||
|
uint32_t vbe_control_info;
|
||||||
|
uint32_t vbe_mode_info;
|
||||||
|
uint16_t vbe_mode;
|
||||||
|
uint16_t vbe_interface_seg;
|
||||||
|
uint16_t vbe_interface_off;
|
||||||
|
uint16_t vbe_interface_len;
|
||||||
|
uint64_t framebuffer_addr;
|
||||||
|
uint32_t framebuffer_pitch;
|
||||||
|
uint32_t framebuffer_width;
|
||||||
|
uint32_t framebuffer_height;
|
||||||
|
uint8_t framebuffer_bpp;
|
||||||
|
uint8_t framebuffer_type;
|
||||||
|
uint8_t red_field_position;
|
||||||
|
uint8_t red_mask_size;
|
||||||
|
uint8_t green_field_position;
|
||||||
|
uint8_t green_mask_size;
|
||||||
|
uint8_t blue_field_position;
|
||||||
|
uint8_t blue_mask_size;
|
||||||
} __attribute__((packed)) multiboot_info;
|
} __attribute__((packed)) multiboot_info;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@@ -3,21 +3,38 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <vfs.h>
|
||||||
|
|
||||||
|
#define MAX_PROCESS_FDS 32
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
STATE_READY,
|
STATE_READY = 1,
|
||||||
STATE_SLEEPING,
|
STATE_SLEEPING = 2,
|
||||||
STATE_BLOCKED,
|
STATE_BLOCKED = 3,
|
||||||
STATE_DEAD
|
STATE_DEAD = 4,
|
||||||
|
STATE_ZOMBIE = 5,
|
||||||
} process_state_t;
|
} process_state_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef enum {
|
||||||
|
PROCESS_FLAG_NONE = 0,
|
||||||
|
PROCESS_FLAG_KERNEL = 1 << 0,
|
||||||
|
PROCESS_FLAG_USER = 1 << 1
|
||||||
|
} process_flags_t;
|
||||||
|
|
||||||
|
struct process_t;
|
||||||
|
typedef struct process_t {
|
||||||
uint32_t pid;
|
uint32_t pid;
|
||||||
uint32_t esp;
|
uint32_t esp;
|
||||||
|
uint32_t kstack_top;
|
||||||
uint32_t cr3;
|
uint32_t cr3;
|
||||||
process_state_t state;
|
process_state_t state;
|
||||||
uint32_t sleep;
|
uint32_t sleep;
|
||||||
void* next;
|
|
||||||
uint32_t heap_end;
|
uint32_t heap_end;
|
||||||
|
uint32_t flags;
|
||||||
|
file_t* fd_table[MAX_PROCESS_FDS];
|
||||||
|
struct process_t* sched_next;
|
||||||
|
struct process_t* waiting;
|
||||||
|
int exit_status;
|
||||||
} __attribute__((packed)) process_t;
|
} __attribute__((packed)) process_t;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -6,26 +6,31 @@
|
|||||||
yield: # void yield()
|
yield: # void yield()
|
||||||
cli
|
cli
|
||||||
|
|
||||||
pushfl
|
popl %ecx
|
||||||
pushl %cs
|
|
||||||
|
pushfl // EFLAGS
|
||||||
movl 8(%esp), %eax
|
pushl %cs // CS
|
||||||
pushl %eax
|
pushl %ecx // EIP
|
||||||
|
|
||||||
movl 4(%esp), %ebx # Get CS
|
|
||||||
movl %ebx, 8(%esp) # Move CS over Old EIP
|
|
||||||
movl 0(%esp), %ebx # Get Return EIP
|
|
||||||
movl %ebx, 4(%esp) # Move Return EIP over CS
|
|
||||||
addl $4, %esp # Adjust stack pointer up.
|
|
||||||
|
|
||||||
# the stack now looks like a hardware interrupt just happened, even though we never called one.
|
|
||||||
|
|
||||||
pushal
|
pushal
|
||||||
|
call send_eoi_master
|
||||||
|
|
||||||
|
xor %eax, %eax
|
||||||
|
mov %ds, %ax
|
||||||
|
pushl %eax
|
||||||
|
|
||||||
|
mov $0x10, %ax
|
||||||
|
mov %ax, %ds
|
||||||
|
mov %ax, %es
|
||||||
|
|
||||||
pushl %esp
|
pushl %esp
|
||||||
call switch_context
|
call switch_context
|
||||||
movl %eax, %esp
|
movl %eax, %esp
|
||||||
|
|
||||||
|
popl %eax
|
||||||
|
mov %ax, %ds
|
||||||
|
mov %ax, %es
|
||||||
|
|
||||||
popal
|
popal
|
||||||
sti
|
sti
|
||||||
iret
|
iret
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <lib/tasks.h>
|
#include <lib/tasks.h>
|
||||||
|
#include <lib/print.h>
|
||||||
#include <lib/memory.h>
|
#include <lib/memory.h>
|
||||||
|
|
||||||
#include <memory/mm.h>
|
#include <memory/mm.h>
|
||||||
@@ -8,47 +9,36 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
|
#include "gdt.h"
|
||||||
|
|
||||||
static process_t* process_table;
|
static process_t* process_table = NULL;
|
||||||
|
static process_t* current_process = NULL;
|
||||||
|
static process_t* idle_task = NULL;
|
||||||
|
|
||||||
static int current_process = 0;
|
|
||||||
static int total_processes = 0;
|
static int total_processes = 0;
|
||||||
|
|
||||||
#define IDLE_TASK_PID 1
|
void lock_scheduler() {
|
||||||
static void idle_task() {
|
|
||||||
while (1) asm volatile("hlt");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void lock_scheduler() {
|
|
||||||
disable_interrupts();
|
disable_interrupts();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unlock_scheduler() {
|
void unlock_scheduler() {
|
||||||
enable_interrupts();
|
enable_interrupts();
|
||||||
}
|
}
|
||||||
|
|
||||||
// called from isr and yield, interrupts are already disabled and re enabled in the isr/yield func
|
typedef struct registers {
|
||||||
|
uint32_t ds; // push %ds
|
||||||
|
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // pushal
|
||||||
|
uint32_t eip, cs, eflags, useresp, ss; // pushed by cpu
|
||||||
|
} __attribute__((packed)) registers_t;
|
||||||
|
|
||||||
uint32_t switch_context(uint32_t current_esp) {
|
uint32_t switch_context(uint32_t current_esp) {
|
||||||
process_table[current_process].esp = current_esp;
|
registers_t* regs = (registers_t*)current_esp;
|
||||||
|
current_process->esp = current_esp;
|
||||||
|
|
||||||
for (int i = 0; i < total_processes; i++) {
|
process_t* next_process = current_process->sched_next;
|
||||||
if (process_table[i].state == STATE_SLEEPING) {
|
|
||||||
if (process_table[i].sleep > 0) {
|
|
||||||
process_table[i].sleep--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process_table[i].sleep == 0) {
|
|
||||||
process_table[i].state = STATE_READY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int next_process = current_process;
|
|
||||||
int found_ready = 0;
|
int found_ready = 0;
|
||||||
|
while (next_process != NULL) {
|
||||||
while (1) {
|
if (next_process != idle_task && next_process->state == STATE_READY) {
|
||||||
next_process = (next_process + 1) % total_processes;
|
|
||||||
if (next_process != IDLE_TASK_PID && process_table[next_process].state == STATE_READY) {
|
|
||||||
found_ready = 1;
|
found_ready = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -56,71 +46,85 @@ uint32_t switch_context(uint32_t current_esp) {
|
|||||||
if (next_process == current_process) {
|
if (next_process == current_process) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
next_process = (process_t*)next_process->sched_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found_ready) {
|
if (!found_ready) {
|
||||||
if (process_table[current_process].state == STATE_READY) {
|
if (current_process && current_process->state == STATE_READY) {
|
||||||
next_process = current_process;
|
next_process = current_process;
|
||||||
} else {
|
} else {
|
||||||
next_process = IDLE_TASK_PID;
|
next_process = idle_task;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
current_process = next_process;
|
current_process = next_process;
|
||||||
|
|
||||||
if (fetch_cr3() != process_table[current_process].cr3) {
|
uint32_t current_cr3 = fetch_cr3();
|
||||||
extern void load_pd(uint32_t table);
|
if (current_cr3 != current_process->cr3) {
|
||||||
load_pd(process_table[current_process].cr3);
|
load_pd((void*)current_process->cr3);
|
||||||
|
flush_tlb();
|
||||||
}
|
}
|
||||||
|
|
||||||
return process_table[current_process].esp;
|
if (current_process->flags & PROCESS_FLAG_USER) {
|
||||||
|
tss.esp0 = current_process->kstack_top;
|
||||||
|
}
|
||||||
|
|
||||||
|
return current_process->esp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_scheduler() {
|
void init_scheduler() {
|
||||||
process_table = kalloc(16 * sizeof(process_t));
|
process_t* root = kalloc(sizeof(process_t));
|
||||||
total_processes = 0;
|
root->pid = 0;
|
||||||
|
root->esp = 0;
|
||||||
|
root->cr3 = fetch_cr3();
|
||||||
|
root->state = STATE_READY;
|
||||||
|
root->sleep = 0;
|
||||||
|
root->flags = PROCESS_FLAG_KERNEL;
|
||||||
|
root->sched_next = NULL;
|
||||||
|
|
||||||
process_t* process = &process_table[total_processes];
|
current_process = root;
|
||||||
process->pid = total_processes;
|
idle_task = root;
|
||||||
process->esp = 0;
|
process_table = root;
|
||||||
process->cr3 = fetch_cr3();
|
|
||||||
process->state = STATE_READY;
|
|
||||||
process->sleep = 0;
|
|
||||||
total_processes++;
|
|
||||||
|
|
||||||
create_task((uint32_t)idle_task, fetch_cr3());
|
total_processes = 1;
|
||||||
|
|
||||||
current_process = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_task(uint32_t entry_point, uint32_t cr3) {
|
void init_task (
|
||||||
if (total_processes >= 16) {
|
process_t* process,
|
||||||
return 0;
|
uint32_t entry_point,
|
||||||
}
|
uint32_t cr3,
|
||||||
|
int user,
|
||||||
lock_scheduler();
|
uint32_t u_esp
|
||||||
|
) {
|
||||||
// default to a new task, but if we find a dead one, re use it
|
process->pid = get_next_pid();
|
||||||
process_t* process = &process_table[total_processes];
|
|
||||||
uint32_t pid = total_processes;
|
|
||||||
for (uint32_t i = 0; i < total_processes; i++) {
|
|
||||||
if (process_table[i].state == STATE_DEAD) {
|
|
||||||
process = &process_table[i];
|
|
||||||
pid = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
process->pid = pid;
|
|
||||||
process->cr3 = cr3;
|
process->cr3 = cr3;
|
||||||
process->state = STATE_READY;
|
process->state = STATE_READY;
|
||||||
process->sleep = 0;
|
process->sleep = 0;
|
||||||
|
process->flags = user ? PROCESS_FLAG_USER : PROCESS_FLAG_KERNEL;
|
||||||
|
total_processes++;
|
||||||
|
|
||||||
void* stack_bottom = kalloc(4096);
|
if (process->kstack_top != 0) {
|
||||||
uint32_t* esp = (uint32_t*)((uint32_t)stack_bottom + 4096);
|
kfree((void*)process->kstack_top);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* kstack_bottom = kalloc(PAGE_SIZE);
|
||||||
|
uint32_t kstack_top = (uint32_t)kstack_bottom + PAGE_SIZE;
|
||||||
|
process->kstack_top = kstack_top;
|
||||||
|
|
||||||
*(--esp) = 0x0202; // EFLAGS
|
uint32_t* esp = (uint32_t*)kstack_top;
|
||||||
*(--esp) = 0x08; // CS
|
if (user) {
|
||||||
*(--esp) = entry_point; // EIP
|
*(--esp) = 0x23; // User Data Segment (SS) with RPL 3 (0x20 | 3)
|
||||||
|
*(--esp) = u_esp; // User Stack Pointer (ESP) - location mapped in user space
|
||||||
|
*(--esp) = 0x202; // EFLAGS (Interrupts enabled)
|
||||||
|
*(--esp) = 0x1B; // User Code Segment (CS) with RPL 3 (0x18 | 3)
|
||||||
|
*(--esp) = entry_point; // EIP
|
||||||
|
} else {
|
||||||
|
// IRET values for Ring 0
|
||||||
|
*(--esp) = 0x202; // EFLAGS
|
||||||
|
*(--esp) = 0x08; // Kernel Code Segment (CS)
|
||||||
|
*(--esp) = entry_point; // EIP
|
||||||
|
}
|
||||||
|
|
||||||
*(--esp) = 0; // EAX
|
*(--esp) = 0; // EAX
|
||||||
*(--esp) = 0; // ECX
|
*(--esp) = 0; // ECX
|
||||||
@@ -131,32 +135,69 @@ int create_task(uint32_t entry_point, uint32_t cr3) {
|
|||||||
*(--esp) = 0; // ESI
|
*(--esp) = 0; // ESI
|
||||||
*(--esp) = 0; // EDI
|
*(--esp) = 0; // EDI
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
*(--esp) = 0x23; // User Data Segment Selector (RPL 3)
|
||||||
|
} else {
|
||||||
|
*(--esp) = 0x10; // Kernel Data Segment Selector (RPL 0)
|
||||||
|
}
|
||||||
|
|
||||||
process->esp = (uint32_t)esp;
|
process->esp = (uint32_t)esp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_next_pid() {
|
||||||
|
int pid = total_processes;
|
||||||
total_processes++;
|
total_processes++;
|
||||||
unlock_scheduler();
|
return pid;
|
||||||
return 1;
|
}
|
||||||
|
|
||||||
|
void add_task(process_t* task) {
|
||||||
|
if (!task) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process_table->sched_next == NULL) {
|
||||||
|
process_table->sched_next = task;
|
||||||
|
task->sched_next = process_table;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
process_t* curr = process_table;
|
||||||
|
while (curr->sched_next != process_table) {
|
||||||
|
curr = curr->sched_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
curr->sched_next = task;
|
||||||
|
task->sched_next = process_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
process_t* current_task() {
|
process_t* current_task() {
|
||||||
lock_scheduler();
|
process_t* rtn = current_process;
|
||||||
process_t* rtn = &process_table[current_process];
|
|
||||||
unlock_scheduler();
|
|
||||||
return rtn;
|
return rtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sleep(uint32_t ms) {
|
void sleep(uint32_t ms) {
|
||||||
if (ms == 0) return;
|
if (ms == 0) return;
|
||||||
lock_scheduler();
|
current_process->sleep = ms;
|
||||||
process_table[current_process].sleep = ms;
|
current_process->state = STATE_SLEEPING;
|
||||||
process_table[current_process].state = STATE_SLEEPING;
|
|
||||||
yield();
|
yield();
|
||||||
unlock_scheduler();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void exit() {
|
void exit() {
|
||||||
lock_scheduler();
|
current_process->state = STATE_DEAD;
|
||||||
process_table[current_process].state = STATE_DEAD;
|
|
||||||
yield(); // yield forever
|
yield(); // yield forever
|
||||||
unlock_scheduler();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wake(process_t* task) {
|
||||||
|
if (task->state == STATE_SLEEPING || task->state == STATE_BLOCKED) {
|
||||||
|
task->state = STATE_READY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
process_t* get_task_by_pid(uint32_t pid) {
|
||||||
|
process_t* cur = process_table;
|
||||||
|
while (cur) {
|
||||||
|
if (cur->pid == pid) break;
|
||||||
|
cur = cur->sched_next;
|
||||||
|
}
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
@@ -4,13 +4,21 @@
|
|||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void init_scheduler();
|
void lock_scheduler();
|
||||||
|
void unlock_scheduler();
|
||||||
|
|
||||||
|
void init_scheduler();
|
||||||
|
void init_task(process_t* process, uint32_t entry_point, uint32_t cr3, int user, uint32_t u_esp);
|
||||||
|
|
||||||
int create_task(uint32_t entry_point, uint32_t cr3);
|
|
||||||
process_t* current_task();
|
process_t* current_task();
|
||||||
|
process_t* get_task_by_pid(uint32_t pid);
|
||||||
|
|
||||||
|
int get_next_pid();
|
||||||
|
void add_task(process_t* task);
|
||||||
|
|
||||||
void sleep(uint32_t ms);
|
void sleep(uint32_t ms);
|
||||||
void yield();
|
void yield();
|
||||||
void exit();
|
void exit();
|
||||||
|
void wake(process_t* task);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
17
kernel/sys/video.h
Normal file
17
kernel/sys/video.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#ifndef USER_VIDEO_H
|
||||||
|
#define USER_VIDEO_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define FBIOGET_INFO 0x1
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
uint32_t pitch;
|
||||||
|
uint32_t bpp;
|
||||||
|
uint32_t fb_size;
|
||||||
|
} fb_info_t;
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -4,33 +4,16 @@
|
|||||||
syscall_handler:
|
syscall_handler:
|
||||||
cli
|
cli
|
||||||
|
|
||||||
push $0
|
pushal
|
||||||
push $0x80
|
|
||||||
|
|
||||||
pusha
|
|
||||||
|
|
||||||
push %ds
|
push %ds
|
||||||
push %es
|
|
||||||
push %fs
|
|
||||||
push %gs
|
|
||||||
|
|
||||||
mov $0x10, %ax
|
mov $0x10, %ax
|
||||||
mov %ax, %ds
|
mov %ax, %ds
|
||||||
mov %ax, %es
|
|
||||||
mov %ax, %fs
|
|
||||||
mov %ax, %gs
|
|
||||||
|
|
||||||
push %esp
|
push %esp
|
||||||
call syscall
|
call syscall
|
||||||
add $4, %esp
|
add $4, %esp
|
||||||
|
|
||||||
mov 28(%esp), %eax
|
|
||||||
|
|
||||||
pop %gs
|
|
||||||
pop %fs
|
|
||||||
pop %es
|
|
||||||
pop %ds
|
pop %ds
|
||||||
|
popal
|
||||||
popa
|
|
||||||
add $8, %esp
|
|
||||||
iret
|
iret
|
||||||
279
kernel/syscall.c
279
kernel/syscall.c
@@ -1,56 +1,72 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "drivers/serial/serial.h"
|
||||||
|
#include "lib/memory.h"
|
||||||
|
#include "lib/ringbuf.h"
|
||||||
|
|
||||||
#include "memory/mm.h"
|
#include "memory/mm.h"
|
||||||
|
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
|
#include "vfs.h"
|
||||||
|
#include "elf.h"
|
||||||
|
|
||||||
#include <drivers/vga/vga.h>
|
#include <drivers/vga/vga.h>
|
||||||
|
#include <drivers/pty/pty.h>
|
||||||
|
|
||||||
|
#include <lib/print.h>
|
||||||
|
#include <lib/string.h>
|
||||||
|
|
||||||
typedef struct registers {
|
typedef struct registers {
|
||||||
uint32_t gs, fs, es, ds; // Pushed manually
|
uint32_t ds; // push %ds
|
||||||
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed by pusha
|
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // pushal
|
||||||
uint32_t int_no, err_code; // Pushed manually
|
uint32_t eip, cs, eflags, useresp, ss; // pushed by cpu
|
||||||
uint32_t eip, cs, eflags, useresp, ss; // Pushed automatically by CPU
|
} __attribute__((packed)) registers_t;
|
||||||
} registers_t;
|
|
||||||
|
|
||||||
|
|
||||||
static int32_t sys_exit(int status) {
|
static int32_t sys_exit(int status) {
|
||||||
|
process_t* task = current_task();
|
||||||
|
task->state = STATE_DEAD;
|
||||||
|
task->exit_status = status;
|
||||||
|
if (task->waiting) {
|
||||||
|
wake(task->waiting);
|
||||||
|
}
|
||||||
exit();
|
exit();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t sys_write(int fd, const void* buf, size_t count) {
|
static int32_t sys_write(int fd, const void* buf, size_t count) {
|
||||||
if (fd == 1 || fd == 2) { // stdout or stderr
|
if (fd < 0 || fd >= MAX_PROCESS_FDS) return -1;
|
||||||
const char* cbuf = (const char*)buf;
|
|
||||||
for (size_t i = 0; i < count; i++) {
|
file_t* f = current_task()->fd_table[fd];
|
||||||
vga_putchar(cbuf[i]);
|
if (!f || !f->node) return -1;
|
||||||
}
|
|
||||||
return count;
|
uint32_t rd = f->node->write(f->node, f->offset, count, (uint8_t*)buf);
|
||||||
}
|
f->offset += rd;
|
||||||
return -1;
|
|
||||||
|
return rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t sys_read(int fd, void* buf, size_t count) {
|
static int32_t sys_read(int fd, void* buf, size_t count) {
|
||||||
if (fd == 0) { // stdin
|
if (fd < 0 || fd >= MAX_PROCESS_FDS) return -1;
|
||||||
char* cbuf = (char*)buf;
|
|
||||||
size_t bytes_read = 0;
|
file_t* f = current_task()->fd_table[fd];
|
||||||
while (bytes_read < count) {
|
if (!f || !f->node) return -1;
|
||||||
char c = 'r';
|
|
||||||
cbuf[bytes_read++] = c;
|
uint32_t rd = f->node->read(f->node, f->offset, count, (uint8_t*)buf);
|
||||||
if (c == '\n') break;
|
f->offset += rd;
|
||||||
}
|
|
||||||
return bytes_read;
|
return rd;
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t sys_open(const char* filename, int flags) {
|
static int32_t sys_open(const char* filename, int flags) {
|
||||||
return -1;
|
return vfs_open(filename, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t sys_close(int fd) {
|
static int32_t sys_close(int fd) {
|
||||||
return -1;
|
process_t* task = current_task();
|
||||||
|
task->fd_table[fd] = NULL;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t sys_brk(uint32_t new_break) {
|
static int32_t sys_brk(uint32_t new_break) {
|
||||||
@@ -80,15 +96,204 @@ static int32_t sys_brk(uint32_t new_break) {
|
|||||||
return current->heap_end;
|
return current->heap_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t syscall(registers_t* regs) {
|
static int32_t sys_sbrk(int32_t inc) {
|
||||||
switch(regs->eax) {
|
process_t* current = current_task();
|
||||||
case 1: return sys_exit(regs->ebx);
|
|
||||||
case 3: return sys_read(regs->ebx, (void*)regs->ecx, regs->edx);
|
if (inc <= 0) { // can't shrink yet
|
||||||
case 4: return sys_write(regs->ebx, (const void*)regs->ecx, regs->edx);
|
return current->heap_end;
|
||||||
case 5: return sys_open((const char*)regs->ebx, regs->ecx);
|
|
||||||
case 6: return sys_close(regs->ebx);
|
|
||||||
case 12: return sys_brk(regs->ebx);
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t page_start = (current->heap_end + 4095) & ~4095;
|
||||||
|
current->heap_end += inc;
|
||||||
|
uint32_t page_end = (current->heap_end + 4095) & ~4095;
|
||||||
|
|
||||||
|
for (uint32_t addr = page_start; addr < page_end; addr += 4096) {
|
||||||
|
void* phys = p_alloc_frame();
|
||||||
|
map_page(addr, (uint32_t)phys, PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER);
|
||||||
|
}
|
||||||
|
|
||||||
|
return current->heap_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t sys_pty(int* slave_fd) {
|
||||||
|
pty_t* pty = (pty_t*)kalloc(sizeof(pty_t));
|
||||||
|
ring_buf_init(&pty->master_rb);
|
||||||
|
ring_buf_init(&pty->slave_rb);
|
||||||
|
|
||||||
|
vfs_node_t* master =(vfs_node_t*)kalloc(sizeof(vfs_node_t));
|
||||||
|
master->flags = VFS_CHARDEVICE;
|
||||||
|
master->size = 0;
|
||||||
|
master->read = pty_master_read;
|
||||||
|
master->write = pty_master_write;
|
||||||
|
master->find = NULL;
|
||||||
|
master->data = pty;
|
||||||
|
|
||||||
|
vfs_node_t* slave =(vfs_node_t*)kalloc(sizeof(vfs_node_t));
|
||||||
|
slave->flags = VFS_CHARDEVICE;
|
||||||
|
slave->size = 0;
|
||||||
|
slave->read = pty_slave_read;
|
||||||
|
slave->write = pty_slave_write;
|
||||||
|
slave->find = NULL;
|
||||||
|
slave->data = pty;
|
||||||
|
|
||||||
|
file_t* fmaster = (file_t*)kalloc(sizeof(file_t));
|
||||||
|
fmaster->node = master;
|
||||||
|
fmaster->offset = 0;
|
||||||
|
fmaster->flags = 0;
|
||||||
|
|
||||||
|
file_t* fslave = (file_t*)kalloc(sizeof(file_t));
|
||||||
|
fslave->node = slave;
|
||||||
|
fslave->offset = 0;
|
||||||
|
fslave->flags = 0;
|
||||||
|
|
||||||
|
*slave_fd = alloc_fd(fslave);
|
||||||
|
return alloc_fd(fmaster);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t sys_fork(registers_t* parent_regs) {
|
||||||
|
process_t* parent = current_task();
|
||||||
|
process_t* child = kalloc(sizeof(process_t));
|
||||||
|
if (!child) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
child->pid = get_next_pid();
|
||||||
|
child->state = STATE_READY;
|
||||||
|
child->flags = parent->flags;
|
||||||
|
child->heap_end = parent->heap_end;
|
||||||
|
child->sleep = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_PROCESS_FDS; i++) {
|
||||||
|
child->fd_table[i] = parent->fd_table[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t kstack_size = 4096;
|
||||||
|
void* kstack_alloc = kalloc(kstack_size);
|
||||||
|
child->kstack_top = (uint32_t)kstack_alloc + kstack_size;
|
||||||
|
|
||||||
|
registers_t* child_regs = (registers_t*)(child->kstack_top - sizeof(registers_t));
|
||||||
|
memcpy(parent_regs, child_regs, sizeof(registers_t));
|
||||||
|
child_regs->eax = 0;
|
||||||
|
child->esp = (uint32_t)child_regs;
|
||||||
|
|
||||||
|
uint32_t cr3 = (uint32_t)clone_current_pd();
|
||||||
|
child->cr3 = cr3;
|
||||||
|
|
||||||
|
add_task(child);
|
||||||
|
return child->pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t sys_exec(registers_t* regs, const char* prgm) {
|
||||||
|
clear_current_pd();
|
||||||
|
|
||||||
|
uint32_t eip = load_elf_program(prgm);
|
||||||
|
if (eip == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t stack_sz = PAGE_SIZE * 16;
|
||||||
|
uint32_t stack_top = 0xBFFF0000;
|
||||||
|
uint32_t stack_bottom = stack_top - stack_sz;
|
||||||
|
for (uint32_t vaddr = stack_bottom; vaddr < stack_top; vaddr += PAGE_SIZE) {
|
||||||
|
void* phys_frame = p_alloc_frame();
|
||||||
|
map_page(vaddr, (uint32_t)phys_frame, PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t* u_esp = (uint32_t*)stack_top;
|
||||||
|
*(--u_esp) = 0; // envp = NULL
|
||||||
|
*(--u_esp) = 0; // argv = NULL
|
||||||
|
*(--u_esp) = 0; // argc = 0
|
||||||
|
|
||||||
|
regs->eax = 0;
|
||||||
|
regs->ecx = 0;
|
||||||
|
regs->edx = 0;
|
||||||
|
regs->ebp = 0;
|
||||||
|
regs->esi = 0;
|
||||||
|
regs->edi = 0;
|
||||||
|
regs->eip = eip;
|
||||||
|
regs->useresp = (uint32_t)u_esp;
|
||||||
|
|
||||||
|
print_serial("returning from exec\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t sys_dup2(int src, int dst) {
|
||||||
|
process_t* task = current_task();
|
||||||
|
task->fd_table[dst] = task->fd_table[src];
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t sys_lseek(int fd, size_t offset, int whence) {
|
||||||
|
if (fd < 0) return 0;
|
||||||
|
process_t* task = current_task();
|
||||||
|
file_t* file = task->fd_table[fd];
|
||||||
|
if (!file) return 0;
|
||||||
|
file->node->seek(file->node, offset, whence);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t sys_waitpid(int pid, int* exit_status) {
|
||||||
|
process_t* current = current_task();
|
||||||
|
process_t* child = get_task_by_pid(pid);
|
||||||
|
current->state = STATE_BLOCKED;
|
||||||
|
child->waiting = current;
|
||||||
|
yield();
|
||||||
|
*exit_status = child->exit_status;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t sys_mmap(int fd) {
|
||||||
|
if (fd < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
process_t* current = current_task();
|
||||||
|
if (!current) return 0;
|
||||||
|
|
||||||
|
file_t* file = current->fd_table[fd];
|
||||||
|
if (!file) return 0;
|
||||||
|
|
||||||
|
if (!(file->node->flags & VFS_CHARDEVICE)) return 0;
|
||||||
|
|
||||||
|
uint32_t map_vaddr = 0x20000000;
|
||||||
|
return file->node->mmap(file->node, map_vaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t sys_ioctl(int fd, uint32_t request, void* args) {
|
||||||
|
if (fd < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
process_t* current = current_task();
|
||||||
|
if (!current) return 0;
|
||||||
|
|
||||||
|
file_t* file = current->fd_table[fd];
|
||||||
|
if (!file) return 0;
|
||||||
|
|
||||||
|
if (!file->node->ioctl) return 0;
|
||||||
|
|
||||||
|
return file->node->ioctl(file->node, request, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void syscall(registers_t* regs) {
|
||||||
|
int32_t ret;
|
||||||
|
switch(regs->eax) {
|
||||||
|
case 1: ret = sys_exit(regs->ebx); break;
|
||||||
|
case 3: ret = sys_read(regs->ebx, (void*)regs->ecx, regs->edx); break;
|
||||||
|
case 4: ret = sys_write(regs->ebx, (const void*)regs->ecx, regs->edx); break;
|
||||||
|
case 5: ret = sys_open((const char*)regs->ebx, regs->ecx); break;
|
||||||
|
case 6: ret = sys_close(regs->ebx); break;
|
||||||
|
case 12: ret = sys_brk(regs->ebx); break;
|
||||||
|
case 13: ret = sys_sbrk(regs->ebx); break;
|
||||||
|
case 20: ret = sys_pty((int*)regs->ebx); break;
|
||||||
|
case 21: ret = sys_fork(regs); break;
|
||||||
|
case 22: ret = sys_exec(regs, (const char*)regs->ebx); break;
|
||||||
|
case 23: ret = sys_dup2(regs->ebx, regs->ecx); break;
|
||||||
|
case 24: ret = sys_lseek(regs->ebx, regs->ecx, regs->edx); break;
|
||||||
|
case 25: ret = sys_waitpid(regs->ebx, (int*)regs->ecx); break;
|
||||||
|
case 26: ret = sys_mmap(regs->ebx); break;
|
||||||
|
case 27: ret = sys_ioctl(regs->ebx, regs->ecx, (void*)regs->edx); break;
|
||||||
|
default: ret = -1;
|
||||||
|
}
|
||||||
|
regs->eax = ret;
|
||||||
}
|
}
|
||||||
130
kernel/vfs.c
130
kernel/vfs.c
@@ -1,12 +1,130 @@
|
|||||||
#include "vfs.h"
|
#include <vfs.h>
|
||||||
#include "lib/memory.h"
|
#include <process.h>
|
||||||
#include <string.h>
|
#include <scheduler.h>
|
||||||
|
|
||||||
|
#include <lib/memory.h>
|
||||||
|
#include <lib/string.h>
|
||||||
|
#include <lib/print.h>
|
||||||
|
|
||||||
vfs_node_t* root = NULL;
|
vfs_node_t* root = NULL;
|
||||||
|
|
||||||
void vfs_create_root() {
|
vfs_node_t* vfs_create_root() {
|
||||||
root = kalloc(sizeof(vfs_node_t));
|
root = kalloc(sizeof(vfs_node_t));
|
||||||
memset((uint8_t*)root->name, 0, 128);
|
memset((uint8_t*)root, 0, sizeof(vfs_node_t));
|
||||||
memcpy("root", root->name, 4);
|
|
||||||
|
strcpy(root->name, "root");
|
||||||
|
|
||||||
root->flags |= VFS_DIRECTORY;
|
root->flags |= VFS_DIRECTORY;
|
||||||
|
root->size = 0;
|
||||||
|
root->find = NULL;
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vfs_mount(vfs_node_t* _mnt, vfs_node_t* _fs) {
|
||||||
|
if (!_fs || !_mnt || !(_mnt->flags & VFS_DIRECTORY)) return;
|
||||||
|
_mnt->mnt = _fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
vfs_node_t* vfs_find(const char* path) {
|
||||||
|
vfs_node_t* current = root;
|
||||||
|
if (current->mnt) {
|
||||||
|
current = current->mnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* sav = NULL;
|
||||||
|
size_t path_sz = strlen(path) + 1;
|
||||||
|
char* path_cpy = kalloc(path_sz);
|
||||||
|
memset((uint8_t*)path_cpy, 0, path_sz);
|
||||||
|
memcpy(path, path_cpy, path_sz);
|
||||||
|
|
||||||
|
char* tkn = strtok_r(path_cpy, "/", &sav);
|
||||||
|
while (tkn != NULL) {
|
||||||
|
if (current && current->mnt) {
|
||||||
|
current = current->mnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!current || !current->find) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = current->find(current, tkn);
|
||||||
|
|
||||||
|
if (current == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tkn = strtok_r(NULL, "/", &sav);
|
||||||
|
if (tkn && !(current->flags & VFS_DIRECTORY)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(path_cpy);
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
vfs_node_t* vfs_mkdir(vfs_node_t* parent, const char* name) {
|
||||||
|
if (!parent || !name) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(name) == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent->mkdir(parent, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
int vfs_open(const char* _path, int flags) {
|
||||||
|
vfs_node_t* file = vfs_find(_path);
|
||||||
|
if (!file) return -1;
|
||||||
|
|
||||||
|
file_t* f = (file_t*)kalloc(sizeof(file_t));
|
||||||
|
f->node = file;
|
||||||
|
f->offset = 0;
|
||||||
|
f->flags = flags;
|
||||||
|
|
||||||
|
return alloc_fd(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int vfs_read(int fd, void* buf, size_t sz) {
|
||||||
|
process_t* curr_p = current_task();
|
||||||
|
if (fd < 0 || fd >= MAX_PROCESS_FDS || !curr_p->fd_table[fd]->node) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_t* file = curr_p->fd_table[fd];
|
||||||
|
|
||||||
|
if (!file->node->read) return -1;
|
||||||
|
|
||||||
|
uint32_t bytes_read = file->node->read(file->node, file->offset, sz, buf);
|
||||||
|
file->offset += bytes_read;
|
||||||
|
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vfs_seek(int fd, size_t offset) {
|
||||||
|
process_t* curr_p = current_task();
|
||||||
|
if (fd < 0 || fd >= MAX_PROCESS_FDS || !curr_p->fd_table[fd]->node) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_t* file = curr_p->fd_table[fd];
|
||||||
|
file->offset = offset;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int alloc_fd(file_t* f) {
|
||||||
|
process_t* curr_p = current_task();
|
||||||
|
if (!curr_p) return -1;
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_PROCESS_FDS; i++) {
|
||||||
|
if (curr_p->fd_table[i] == NULL) {
|
||||||
|
curr_p->fd_table[i] = f;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
47
kernel/vfs.h
47
kernel/vfs.h
@@ -2,29 +2,64 @@
|
|||||||
#define KVFS_H
|
#define KVFS_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#define VFS_FILE 0x01
|
#define VFS_FILE 0x01
|
||||||
#define VFS_DIRECTORY 0x02
|
#define VFS_DIRECTORY 0x02
|
||||||
|
#define VFS_CHARDEVICE 0x03
|
||||||
|
#define VFS_BLOCKDEVICE 0x04
|
||||||
|
#define VFS_PIPE 0x05
|
||||||
|
|
||||||
struct vfs_node;
|
struct vfs_node;
|
||||||
|
|
||||||
typedef uint32_t (*read_type_t)(struct vfs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer);
|
typedef uint32_t (*read_type_t)(struct vfs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer);
|
||||||
typedef uint32_t (*write_type_t)(struct vfs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer);
|
typedef uint32_t (*write_type_t)(struct vfs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer);
|
||||||
|
typedef uint32_t (*seek_type_t)(struct vfs_node* node, uint32_t offset, int whence);
|
||||||
|
typedef uint32_t (*mmap_type_t)(struct vfs_node* node, uint32_t address);
|
||||||
|
typedef uint32_t (*ioctl_type_t)(struct vfs_node* node, uint32_t request, void* arg);
|
||||||
|
|
||||||
typedef struct vfs_node* (*finddir_type_t)(struct vfs_node* node, const char* name);
|
typedef struct vfs_node* (*finddir_type_t)(struct vfs_node* node, const char* name);
|
||||||
|
typedef struct vfs_node* (*mkdir_type_t)(struct vfs_node* node, const char* name);
|
||||||
|
typedef struct vfs_node* (*create_type_t)(struct vfs_node* node, const char* name);
|
||||||
|
|
||||||
typedef struct vfs_node {
|
typedef struct vfs_node {
|
||||||
char name[128];
|
char name[128];
|
||||||
uint32_t flags; // File, directory, device, etc.
|
uint32_t flags; // File, directory, device, etc.
|
||||||
uint32_t size; // Size of file in bytes
|
uint32_t size; // Size of file in bytes
|
||||||
uint32_t inode; // Unique identifier managed by the specific filesystem
|
|
||||||
|
struct vfs_node* first_child;
|
||||||
|
struct vfs_node* next_sibling;
|
||||||
|
|
||||||
read_type_t read;
|
read_type_t read;
|
||||||
write_type_t write;
|
write_type_t write;
|
||||||
finddir_type_t finddir;
|
finddir_type_t find;
|
||||||
|
mkdir_type_t mkdir;
|
||||||
|
create_type_t create;
|
||||||
|
seek_type_t seek;
|
||||||
|
mmap_type_t mmap;
|
||||||
|
ioctl_type_t ioctl;
|
||||||
|
|
||||||
struct vfs_node* mount;
|
struct vfs_node* mnt;
|
||||||
|
void* data;
|
||||||
} vfs_node_t;
|
} vfs_node_t;
|
||||||
|
|
||||||
void vfs_create_root();
|
typedef struct {
|
||||||
|
vfs_node_t* node; // The actual CPIO/VFS node
|
||||||
|
uint32_t offset; // Current read/write cursor position
|
||||||
|
uint32_t flags; // Permissions (O_RDONLY, etc.)
|
||||||
|
} file_t;
|
||||||
|
|
||||||
|
vfs_node_t* vfs_create_root();
|
||||||
|
vfs_node_t* vfs_mkdir(vfs_node_t* parent, const char* name);
|
||||||
|
|
||||||
|
vfs_node_t* vfs_find(const char* path);
|
||||||
|
|
||||||
|
void vfs_mount(vfs_node_t* _mnt, vfs_node_t* _fs);
|
||||||
|
int vfs_open(const char* path, int flags);
|
||||||
|
int vfs_read(int fd, void* buf, size_t sz);
|
||||||
|
|
||||||
|
int vfs_seek(int fd, size_t offset);
|
||||||
|
|
||||||
|
int alloc_fd(file_t* f);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
5
make_img.sh
Executable file
5
make_img.sh
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
cd sysroot
|
||||||
|
find . -depth -print | cpio -o -H newc > ../isodir/boot/initrd.img
|
||||||
|
cd ..
|
||||||
5
makefile
5
makefile
@@ -33,8 +33,9 @@ obj/%.S.o: %.S
|
|||||||
$(CC) -c $< -o $@ $(CFLAGS)
|
$(CC) -c $< -o $@ $(CFLAGS)
|
||||||
|
|
||||||
run: $(OSNAME).iso
|
run: $(OSNAME).iso
|
||||||
qemu-system-i386 -cdrom $(OSNAME).iso
|
qemu-system-i386 -device VGA,edid=on -cdrom $(OSNAME).iso
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@echo "Cleaning up build artifacts..."
|
@echo "Cleaning up build artifacts..."
|
||||||
rm -rf $(OSNAME).iso $(OSNAME).bin obj isodir
|
rm -rf $(OSNAME).iso $(OSNAME).bin obj isodir compile_commands.json *.img
|
||||||
|
rm -rf .cache/
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
.global _start
|
|
||||||
.intel_syntax noprefix
|
|
||||||
|
|
||||||
.section .text
|
|
||||||
_start:
|
|
||||||
xor ebp, ebp
|
|
||||||
push ebp
|
|
||||||
mov ebp, esp
|
|
||||||
|
|
||||||
mov eax, [esp + 4]
|
|
||||||
lea ebx, [esp + 8]
|
|
||||||
lea ecx, [esp + 12]
|
|
||||||
|
|
||||||
push ecx
|
|
||||||
push ebx
|
|
||||||
push eax
|
|
||||||
|
|
||||||
call main
|
|
||||||
|
|
||||||
push eax
|
|
||||||
call exit
|
|
||||||
|
|
||||||
1: hlt
|
|
||||||
jmp 1b
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
# 0 "crt0.S"
|
|
||||||
# 0 "<built-in>"
|
|
||||||
# 0 "<command-line>"
|
|
||||||
# 1 "crt0.S"
|
|
||||||
.global _start
|
|
||||||
.intel_syntax noprefix
|
|
||||||
|
|
||||||
.section .text
|
|
||||||
_start:
|
|
||||||
xor ebp, ebp
|
|
||||||
push ebp
|
|
||||||
mov ebp, esp
|
|
||||||
|
|
||||||
mov eax, [esp + 4]
|
|
||||||
lea ebx, [esp + 8]
|
|
||||||
lea ecx, [esp + 12]
|
|
||||||
|
|
||||||
push ecx
|
|
||||||
push ebx
|
|
||||||
push eax
|
|
||||||
|
|
||||||
call main
|
|
||||||
|
|
||||||
push eax
|
|
||||||
call exit
|
|
||||||
|
|
||||||
1: hlt
|
|
||||||
jmp 1b
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
|
||||||
printf("Hello, World from RockOS!\n");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
CC = i686-elf-gcc
|
|
||||||
LD = i686-elf-ld
|
|
||||||
|
|
||||||
CFLAGS = -ffreestanding -O2 -Wall -Wextra -I../rocklibc/include
|
|
||||||
LDFLAGS = -m elf_i386 -nostdlib
|
|
||||||
|
|
||||||
TARGET = origin.elf
|
|
||||||
|
|
||||||
all: $(TARGET)
|
|
||||||
|
|
||||||
crt0.o: crt0.s
|
|
||||||
$(CC) $(CFLAGS) -c crt0.s -o crt0.o
|
|
||||||
|
|
||||||
main.o: main.c
|
|
||||||
$(CC) $(CFLAGS) -c main.c -o main.o
|
|
||||||
|
|
||||||
$(TARGET): crt0.o main.o ../rocklibc/rlibc.a
|
|
||||||
$(LD) $(LDFLAGS) -T linker.ld crt0.o main.o ../rocklibc/rlibc.a $(shell $(CC) -print-libgcc-file-name) -o $(TARGET)
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f *.o $(TARGET)
|
|
||||||
|
|
||||||
.PHONY: all clean
|
|
||||||
1
programs/rocksh/.gitignore
vendored
Normal file
1
programs/rocksh/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
rocksh
|
||||||
21
programs/rocksh/crt0.S
Normal file
21
programs/rocksh/crt0.S
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
.global _start
|
||||||
|
.extern exit
|
||||||
|
.section .text
|
||||||
|
_start:
|
||||||
|
xor %ebp, %ebp
|
||||||
|
|
||||||
|
mov (%esp), %eax
|
||||||
|
lea 4(%esp), %ebx
|
||||||
|
lea 8(%esp,%eax,4), %ecx
|
||||||
|
|
||||||
|
and $-16, %esp
|
||||||
|
|
||||||
|
push %ecx
|
||||||
|
push %ebx
|
||||||
|
push %eax
|
||||||
|
|
||||||
|
call main
|
||||||
|
|
||||||
|
push %eax
|
||||||
|
call exit
|
||||||
|
|
||||||
68
programs/rocksh/main.c
Normal file
68
programs/rocksh/main.c
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#include "syscall.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
const char* shell_prompt = "rocksh> ";
|
||||||
|
|
||||||
|
char buf[256];
|
||||||
|
size_t buf_offset = 0;
|
||||||
|
|
||||||
|
char path[256];
|
||||||
|
|
||||||
|
const char* bin_dir = "/usr/bin/";
|
||||||
|
|
||||||
|
void parse_cmd() {
|
||||||
|
if (strcmp(buf, "exit") == 0) {
|
||||||
|
printf("bye!\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(buf, "motd") == 0) {
|
||||||
|
printf("rockos is the best!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(path, bin_dir);
|
||||||
|
strcat(path, buf);
|
||||||
|
|
||||||
|
int pid = fork();
|
||||||
|
if (pid == 0) {
|
||||||
|
if (!exec(path)) {
|
||||||
|
printf("failed to execute %s\n", path);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int status;
|
||||||
|
waitpid(pid, &status);
|
||||||
|
printf("process exited with status %d\n", status);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
memset(buf, 0, 256);
|
||||||
|
buf_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
|
||||||
|
printf(shell_prompt);
|
||||||
|
while (1) {
|
||||||
|
char c;
|
||||||
|
int rd = read(0, &c, 1);
|
||||||
|
if (rd > 0) {
|
||||||
|
if (c == '\n') {
|
||||||
|
parse_cmd();
|
||||||
|
reset();
|
||||||
|
printf(shell_prompt);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
buf[buf_offset++] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
29
programs/rocksh/makefile
Normal file
29
programs/rocksh/makefile
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
CC = i686-elf-gcc
|
||||||
|
LD = i686-elf-ld
|
||||||
|
|
||||||
|
SYSROOT = ../sysroot
|
||||||
|
USR_INCLUDE = $(SYSROOT)/usr/include
|
||||||
|
USR_LIB = $(SYSROOT)/usr/lib
|
||||||
|
|
||||||
|
CFLAGS = -ffreestanding -O2 -Wall -Wextra -I$(USR_INCLUDE)
|
||||||
|
LDFLAGS = -m elf_i386 -nostdlib
|
||||||
|
|
||||||
|
TARGET = rocksh
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
crt0.o: crt0.S
|
||||||
|
$(CC) $(CFLAGS) -c crt0.S -o crt0.o
|
||||||
|
|
||||||
|
main.o: main.c
|
||||||
|
$(CC) $(CFLAGS) -c main.c -o main.o
|
||||||
|
|
||||||
|
$(TARGET): crt0.o main.o $(USR_LIB)/*
|
||||||
|
$(LD) $(LDFLAGS) -T linker.ld crt0.o main.o $(USR_LIB)/* -o $(TARGET)
|
||||||
|
cp $(TARGET) $(SYSROOT)/usr/bin
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o $(TARGET) compile_commands.json
|
||||||
|
rm -rf .cache
|
||||||
|
|
||||||
|
.PHONY: all clean test
|
||||||
1
programs/rockterm/.gitignore
vendored
Normal file
1
programs/rockterm/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
rockterm
|
||||||
21
programs/rockterm/crt0.S
Normal file
21
programs/rockterm/crt0.S
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
.global _start
|
||||||
|
.extern exit
|
||||||
|
.section .text
|
||||||
|
_start:
|
||||||
|
xor %ebp, %ebp
|
||||||
|
|
||||||
|
mov (%esp), %eax
|
||||||
|
lea 4(%esp), %ebx
|
||||||
|
lea 8(%esp,%eax,4), %ecx
|
||||||
|
|
||||||
|
and $-16, %esp
|
||||||
|
|
||||||
|
push %ecx
|
||||||
|
push %ebx
|
||||||
|
push %eax
|
||||||
|
|
||||||
|
call main
|
||||||
|
|
||||||
|
push %eax
|
||||||
|
call exit
|
||||||
|
|
||||||
31
programs/rockterm/linker.ld
Normal file
31
programs/rockterm/linker.ld
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0x40000000;
|
||||||
|
|
||||||
|
.text ALIGN(4K) :
|
||||||
|
{
|
||||||
|
/* Force the crt0.o entry code to be placed FIRST in memory */
|
||||||
|
KEEP(*crt0.o(.text))
|
||||||
|
*(.text .text.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.rodata ALIGN(4K) :
|
||||||
|
{
|
||||||
|
*(.rodata .rodata.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.data ALIGN(4K) :
|
||||||
|
{
|
||||||
|
*(.data .data.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.bss ALIGN(4K) :
|
||||||
|
{
|
||||||
|
_bss_start = .;
|
||||||
|
*(.bss .bss.*)
|
||||||
|
*(COMMON)
|
||||||
|
_bss_end = .;
|
||||||
|
}
|
||||||
|
}
|
||||||
215
programs/rockterm/main.c
Normal file
215
programs/rockterm/main.c
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <sys/video.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t magic[2];
|
||||||
|
uint8_t mode;
|
||||||
|
uint8_t charsz;
|
||||||
|
} psf_hdr_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int fd;
|
||||||
|
psf_hdr_t hdr;
|
||||||
|
void* glyphs;
|
||||||
|
} psf_font_t;
|
||||||
|
|
||||||
|
psf_font_t* load_font(const char* path);
|
||||||
|
void free_font(psf_font_t* font);
|
||||||
|
|
||||||
|
void term_write_char(char c);
|
||||||
|
void render_char(char c);
|
||||||
|
void clear(uint32_t color);
|
||||||
|
void spawn_shell();
|
||||||
|
|
||||||
|
void start_terminal();
|
||||||
|
|
||||||
|
static int ptys;
|
||||||
|
static int ptym;
|
||||||
|
static int vga_fd;
|
||||||
|
|
||||||
|
static void* fb = NULL;
|
||||||
|
static fb_info_t fb_info;
|
||||||
|
|
||||||
|
static uint32_t console_row = 0;
|
||||||
|
static uint32_t console_col = 0;
|
||||||
|
static uint32_t console_width = 0;
|
||||||
|
static uint32_t console_height = 0;
|
||||||
|
static uint32_t console_text_color = 0;
|
||||||
|
static uint32_t console_backgrnd_color = 0;
|
||||||
|
|
||||||
|
static int shell_pid;
|
||||||
|
|
||||||
|
psf_font_t* terminal_font = NULL;
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
|
||||||
|
ptym = pty(&ptys);
|
||||||
|
|
||||||
|
vga_fd = open("/dev/vga");
|
||||||
|
if (vga_fd == -1) return 1;
|
||||||
|
|
||||||
|
int res = ioctl(vga_fd, FBIOGET_INFO, &fb_info);
|
||||||
|
if (!res) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fb = mmap(vga_fd);
|
||||||
|
|
||||||
|
terminal_font = load_font("/usr/fonts/kernel_font.psf");
|
||||||
|
if (!terminal_font) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
console_height = fb_info.height / terminal_font->hdr.charsz;
|
||||||
|
console_width = fb_info.width / 8;
|
||||||
|
console_text_color = 0xFFFFFFFF;
|
||||||
|
console_backgrnd_color = 0xFF6c7482;
|
||||||
|
|
||||||
|
start_terminal();
|
||||||
|
|
||||||
|
free_font(terminal_font);
|
||||||
|
close(vga_fd);
|
||||||
|
close(ptym);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_char(char c) {
|
||||||
|
if (!terminal_font) return;
|
||||||
|
uint32_t vga_pitch = fb_info.pitch;
|
||||||
|
uint8_t* glyph = (uint8_t*)terminal_font->glyphs + (c * terminal_font->hdr.charsz);
|
||||||
|
|
||||||
|
uint32_t pixel_y_start = console_row * terminal_font->hdr.charsz;
|
||||||
|
uint32_t pixel_x_start = console_col * 8;
|
||||||
|
|
||||||
|
for (uint32_t y = 0; y < terminal_font->hdr.charsz; y++) {
|
||||||
|
uint8_t bits = glyph[y];
|
||||||
|
uint8_t* row_bytes = (uint8_t*)fb + ((pixel_y_start + y) * vga_pitch);
|
||||||
|
uint32_t* pixel_row = (uint32_t*)row_bytes;
|
||||||
|
|
||||||
|
for (int x = 0; x < 8; x++) {
|
||||||
|
if (bits & (0b10000000 >> x)) {
|
||||||
|
pixel_row[pixel_x_start + x] = console_text_color;
|
||||||
|
} else {
|
||||||
|
pixel_row[pixel_x_start + x] = console_backgrnd_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void spawn_shell() {
|
||||||
|
if ((shell_pid = fork()) == 0) {
|
||||||
|
close(ptym);
|
||||||
|
close(vga_fd);
|
||||||
|
|
||||||
|
dup2(ptys, 0);
|
||||||
|
dup2(0, 1);
|
||||||
|
dup2(0, 2);
|
||||||
|
if (!exec("/usr/bin/rocksh")) exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(ptys);
|
||||||
|
dup2(ptym, 0);
|
||||||
|
dup2(0, 1);
|
||||||
|
dup2(0, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear(uint32_t color) {
|
||||||
|
for (uint32_t i = 0; i < fb_info.fb_size; i++) {
|
||||||
|
((uint32_t*)fb)[i] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
psf_font_t* load_font(const char* path) {
|
||||||
|
int fd = open(path);
|
||||||
|
if (fd == -1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
psf_hdr_t header;
|
||||||
|
int rd = read(fd, &header, sizeof(psf_hdr_t));
|
||||||
|
if (rd <= 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t num_glyphs = (header.mode & (1 << 0)) ? 512 : 256;
|
||||||
|
uint32_t glyph_sz = header.charsz;
|
||||||
|
size_t glyph_buf_sz = num_glyphs * glyph_sz;
|
||||||
|
|
||||||
|
void* glyphs = malloc(glyph_buf_sz);
|
||||||
|
|
||||||
|
rd = 0;
|
||||||
|
rd = read(fd, glyphs, glyph_buf_sz);
|
||||||
|
if (rd <= 0) {
|
||||||
|
free(glyphs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
psf_font_t* font = (psf_font_t*)malloc(sizeof(psf_font_t));
|
||||||
|
font->fd = fd;
|
||||||
|
font->hdr = header;
|
||||||
|
font->glyphs = glyphs;
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_font(psf_font_t* font) {
|
||||||
|
close(font->fd);
|
||||||
|
free(font->glyphs);
|
||||||
|
free(font);
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_write_char(char c) {
|
||||||
|
if (!terminal_font) return;
|
||||||
|
|
||||||
|
if (c == '\n') {
|
||||||
|
console_col = 0;
|
||||||
|
console_row++;
|
||||||
|
if (console_row >= console_height) {
|
||||||
|
console_row = 0;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
render_char(c);
|
||||||
|
|
||||||
|
console_col++;
|
||||||
|
if (console_col >= console_width) {
|
||||||
|
console_col = 0;
|
||||||
|
console_row++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (console_row >= console_height) {
|
||||||
|
console_row = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void start_terminal() {
|
||||||
|
spawn_shell();
|
||||||
|
|
||||||
|
clear(console_backgrnd_color);
|
||||||
|
|
||||||
|
int kbd_fd = open("/dev/kbd");
|
||||||
|
if (kbd_fd == -1) return;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
char c;
|
||||||
|
int rd = read(STDIN_FILENO, &c, 1);
|
||||||
|
if (rd > 0) {
|
||||||
|
term_write_char(c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
rd = 0;
|
||||||
|
c = 0;
|
||||||
|
rd = read(kbd_fd, &c, 1);
|
||||||
|
if (rd > 0) {
|
||||||
|
write(STDOUT_FILENO, &c, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
29
programs/rockterm/makefile
Normal file
29
programs/rockterm/makefile
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
CC = i686-elf-gcc
|
||||||
|
LD = i686-elf-ld
|
||||||
|
|
||||||
|
SYSROOT = ../sysroot
|
||||||
|
USR_INCLUDE = $(SYSROOT)/usr/include
|
||||||
|
USR_LIB = $(SYSROOT)/usr/lib
|
||||||
|
|
||||||
|
CFLAGS = -ffreestanding -O2 -Wall -Wextra -I$(USR_INCLUDE)
|
||||||
|
LDFLAGS = -m elf_i386 -nostdlib
|
||||||
|
|
||||||
|
TARGET = rockterm
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
crt0.o: crt0.S
|
||||||
|
$(CC) $(CFLAGS) -c crt0.S -o crt0.o
|
||||||
|
|
||||||
|
main.o: main.c
|
||||||
|
$(CC) $(CFLAGS) -c main.c -o main.o
|
||||||
|
|
||||||
|
$(TARGET): crt0.o main.o $(USR_LIB)/*
|
||||||
|
$(LD) $(LDFLAGS) -T linker.ld crt0.o main.o $(USR_LIB)/* -o $(TARGET)
|
||||||
|
cp $(TARGET) $(SYSROOT)/usr/bin
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o $(TARGET) compile_commands.json
|
||||||
|
rm -rf .cache
|
||||||
|
|
||||||
|
.PHONY: all clean test
|
||||||
BIN
resources/fonts/kernel_font.psf
Normal file
BIN
resources/fonts/kernel_font.psf
Normal file
Binary file not shown.
0
rocklibc/.gitignore → rlibc/.gitignore
vendored
0
rocklibc/.gitignore → rlibc/.gitignore
vendored
10
rlibc/include/stdio.h
Normal file
10
rlibc/include/stdio.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef RLIBC_STDIO_H
|
||||||
|
#define RLIBC_STDIO_H
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
int printf(const char *format, ...);
|
||||||
|
|
||||||
|
char getchar(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
9
rlibc/include/stdlib.h
Normal file
9
rlibc/include/stdlib.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef RLIBC_STDLIB_H
|
||||||
|
#define RLIBC_STDLIB_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
void* malloc(size_t size);
|
||||||
|
void free(void* ptr);
|
||||||
|
|
||||||
|
#endif
|
||||||
15
rlibc/include/string.h
Normal file
15
rlibc/include/string.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef RLIBC_STRING_H
|
||||||
|
#define RLIBC_STRING_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
void *memcpy(void *restrict dest, const void *restrict src, size_t n);
|
||||||
|
void *memmove(void *dest, const void *src, size_t n);
|
||||||
|
void *memset(void *s, int c, size_t n);
|
||||||
|
|
||||||
|
size_t strlen(const char *s);
|
||||||
|
int strcmp(const char *s1, const char *s2);
|
||||||
|
char *strcpy(char *dest, const char *src);
|
||||||
|
char* strcat(char *dest, const char* src);
|
||||||
|
|
||||||
|
#endif
|
||||||
8
rlibc/include/sys/types.h
Normal file
8
rlibc/include/sys/types.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef RLIBC_SYS_TYPES_H
|
||||||
|
#define RLIBC_SYS_TYPES_H
|
||||||
|
|
||||||
|
typedef long off_t;
|
||||||
|
|
||||||
|
typedef int ssize_t;
|
||||||
|
|
||||||
|
#endif
|
||||||
17
rlibc/include/sys/video.h
Normal file
17
rlibc/include/sys/video.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#ifndef USER_VIDEO_H
|
||||||
|
#define USER_VIDEO_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define FBIOGET_INFO 0x1
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
uint32_t pitch;
|
||||||
|
uint32_t bpp;
|
||||||
|
uint32_t fb_size;
|
||||||
|
} fb_info_t;
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
46
rlibc/include/syscall.h
Normal file
46
rlibc/include/syscall.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#ifndef RLIBC_SYSCALL_H
|
||||||
|
#define RLIBC_SYSCALL_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#define SYS_EXIT 1
|
||||||
|
#define SYS_READ 3
|
||||||
|
#define SYS_WRITE 4
|
||||||
|
#define SYS_OPEN 5
|
||||||
|
#define SYS_CLOSE 6
|
||||||
|
#define SYS_BRK 12
|
||||||
|
#define SYS_SBRK 13
|
||||||
|
#define SYS_PTY 20
|
||||||
|
#define SYS_FORK 21
|
||||||
|
#define SYS_EXEC 22
|
||||||
|
#define SYS_DUP2 23
|
||||||
|
#define SYS_LSEEK 24
|
||||||
|
#define SYS_WAIT 25
|
||||||
|
#define SYS_MMAP 26
|
||||||
|
#define SYS_IOCTL 27
|
||||||
|
|
||||||
|
int open(const char* path);
|
||||||
|
int write(int fd, const void *buf, size_t count);
|
||||||
|
int read(int fd, void *buf, size_t count);
|
||||||
|
int close(int fd);
|
||||||
|
|
||||||
|
int lseek(int fd, size_t offset, int whence);
|
||||||
|
|
||||||
|
void* mmap(int fd);
|
||||||
|
|
||||||
|
void exit(int status) __attribute__((noreturn));
|
||||||
|
|
||||||
|
void* sbrk(int32_t increment);
|
||||||
|
int brk(void *addr);
|
||||||
|
|
||||||
|
int pty(int* slave);
|
||||||
|
|
||||||
|
int fork();
|
||||||
|
int exec(const char* path);
|
||||||
|
int dup2(int src, int dst);
|
||||||
|
int waitpid(int pid, int* status);
|
||||||
|
|
||||||
|
int ioctl(int fd, uint32_t request, void* arg);
|
||||||
|
|
||||||
|
#endif
|
||||||
15
rlibc/include/unistd.h
Normal file
15
rlibc/include/unistd.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef RLIBC_UNISTD_H
|
||||||
|
#define RLIBC_UNISTD_H
|
||||||
|
|
||||||
|
#include <syscall.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#define STDIN_FILENO 0
|
||||||
|
#define STDOUT_FILENO 1
|
||||||
|
#define STDERR_FILENO 2
|
||||||
|
|
||||||
|
#define SEEK_SET 0
|
||||||
|
#define SEEK_CUR 1
|
||||||
|
#define SEEK_END 2
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
CC = i686-elf-gcc
|
CC = i686-elf-gcc
|
||||||
AR = i686-elf-ar
|
AR = i686-elf-ar
|
||||||
CFLAGS = -ffreestanding -O2 -Wall -Wextra -Iinclude -DHAVE_MMAP=0 -DLACKS_SYS_MMAN_H=1 -DUSE_LOCKS=0 -DLACKS_SYS_PARAM_H=1
|
CFLAGS = -ffreestanding -O2 -Wall -Wextra -Iinclude
|
||||||
TARGET = rlibc.a
|
TARGET = rlibc.a
|
||||||
|
|
||||||
SRCS = $(shell find src -name "*.c")
|
SRCS = $(shell find src -name "*.c")
|
||||||
@@ -15,6 +15,6 @@ $(TARGET): $(OBJS)
|
|||||||
$(CC) $(CFLAGS) -c $< -o $@
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(OBJS) $(TARGET)
|
rm -f $(OBJS) $(TARGET) compile_commands.json
|
||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
74
rlibc/src/malloc.c
Normal file
74
rlibc/src/malloc.c
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <syscall.h>
|
||||||
|
|
||||||
|
#define ALIGN(size) (((size) + 3) & ~3)
|
||||||
|
#define HEADER_SIZE sizeof(struct Header)
|
||||||
|
|
||||||
|
struct Header {
|
||||||
|
size_t size;
|
||||||
|
int is_free;
|
||||||
|
struct Header* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct Header* free_list_head = NULL;
|
||||||
|
|
||||||
|
static struct Header* find_free_block(struct Header** last, size_t size) {
|
||||||
|
struct Header* current = free_list_head;
|
||||||
|
while (current && !(current->is_free && current->size >= size)) {
|
||||||
|
*last = current;
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct Header* request_space(struct Header* last, size_t size) {
|
||||||
|
struct Header* block = sbrk(0);
|
||||||
|
void* request = sbrk(size + HEADER_SIZE);
|
||||||
|
|
||||||
|
if (request == (void*)-1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last) {
|
||||||
|
last->next = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
block->size = size;
|
||||||
|
block->next = NULL;
|
||||||
|
block->is_free = 0;
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* malloc(size_t size) {
|
||||||
|
if (size <= 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = ALIGN(size);
|
||||||
|
|
||||||
|
if (free_list_head == NULL) {
|
||||||
|
struct Header* block = request_space(NULL, size);
|
||||||
|
if (!block) return NULL;
|
||||||
|
free_list_head = block;
|
||||||
|
return (void*)(block + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Header* last = free_list_head;
|
||||||
|
struct Header* block = find_free_block(&last, size);
|
||||||
|
|
||||||
|
if (block) {
|
||||||
|
block->is_free = 0;
|
||||||
|
} else {
|
||||||
|
block = request_space(last, size);
|
||||||
|
if (!block) return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (void*)(block + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void* ptr) {
|
||||||
|
if (!ptr) return;
|
||||||
|
|
||||||
|
struct Header* block = (struct Header*)ptr - 1;
|
||||||
|
block->is_free = 1;
|
||||||
|
}
|
||||||
122
rlibc/src/stdio.c
Normal file
122
rlibc/src/stdio.c
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
static void utoa(unsigned int value, char *buf, int base) {
|
||||||
|
char temp[32];
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
// Handle zero explicitly
|
||||||
|
if (value == 0) {
|
||||||
|
buf[0] = '0';
|
||||||
|
buf[1] = '\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert digits in reverse order
|
||||||
|
while (value > 0) {
|
||||||
|
int remainder = value % base;
|
||||||
|
if (remainder < 10) {
|
||||||
|
temp[i++] = '0' + remainder;
|
||||||
|
} else {
|
||||||
|
temp[i++] = 'a' + (remainder - 10);
|
||||||
|
}
|
||||||
|
value /= base;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse the string into the output destination buffer
|
||||||
|
int j = 0;
|
||||||
|
while (i > 0) {
|
||||||
|
buf[j++] = temp[--i];
|
||||||
|
}
|
||||||
|
buf[j] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helper function to convert a signed integer to a string */
|
||||||
|
static void itoa(int value, char *buf, int base) {
|
||||||
|
if (value < 0 && base == 10) {
|
||||||
|
*buf++ = '-';
|
||||||
|
value = -value;
|
||||||
|
}
|
||||||
|
utoa((unsigned int)value, buf, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
int printf(const char *format, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
|
||||||
|
int written_total = 0;
|
||||||
|
char num_buf[32]; // Stack-allocated scratchpad for string conversions
|
||||||
|
|
||||||
|
while (*format != '\0') {
|
||||||
|
if (*format == '%') {
|
||||||
|
format++; // Move past '%'
|
||||||
|
|
||||||
|
switch (*format) {
|
||||||
|
case 'c': {
|
||||||
|
char c = (char)va_arg(args, int);
|
||||||
|
write(1, &c, 1);
|
||||||
|
written_total++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 's': {
|
||||||
|
char *s = va_arg(args, char *);
|
||||||
|
if (!s) s = "(null)";
|
||||||
|
// Find length manually without dragging headers
|
||||||
|
int len = 0;
|
||||||
|
while (s[len] != '\0') len++;
|
||||||
|
write(1, s, len);
|
||||||
|
written_total += len;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'd':
|
||||||
|
case 'i': {
|
||||||
|
int n = va_arg(args, int);
|
||||||
|
itoa(n, num_buf, 10);
|
||||||
|
int len = 0;
|
||||||
|
while (num_buf[len] != '\0') len++;
|
||||||
|
write(1, num_buf, len);
|
||||||
|
written_total += len;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'x': {
|
||||||
|
unsigned int x = va_arg(args, unsigned int);
|
||||||
|
utoa(x, num_buf, 16);
|
||||||
|
int len = 0;
|
||||||
|
while (num_buf[len] != '\0') len++;
|
||||||
|
write(1, num_buf, len);
|
||||||
|
written_total += len;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '%': {
|
||||||
|
write(1, "%", 1);
|
||||||
|
written_total++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// Unknown conversion, print verbatim
|
||||||
|
write(1, format - 1, 2);
|
||||||
|
written_total += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Standard text character
|
||||||
|
write(1, format, 1);
|
||||||
|
written_total++;
|
||||||
|
}
|
||||||
|
format++;
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
return written_total;
|
||||||
|
}
|
||||||
|
|
||||||
|
char getchar(void) {
|
||||||
|
char c;
|
||||||
|
int res = read(0, &c, 1);
|
||||||
|
|
||||||
|
if (res <= 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (char)c;
|
||||||
|
}
|
||||||
8
rlibc/src/strcat.c
Normal file
8
rlibc/src/strcat.c
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
char* strcat(char* dest, const char* src) {
|
||||||
|
char* start = dest + strlen(dest);
|
||||||
|
strcpy(start, src);
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
68
rlibc/src/string.c
Normal file
68
rlibc/src/string.c
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void *memcpy(void *restrict dest, const void *restrict src, size_t n) {
|
||||||
|
char *d = (char *)dest;
|
||||||
|
const char *s = (const char *)src;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
d[i] = s[i];
|
||||||
|
}
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy memory area: safely handles overlapping regions */
|
||||||
|
void *memmove(void *dest, const void *src, size_t n) {
|
||||||
|
char *d = (char *)dest;
|
||||||
|
const char *s = (const char *)src;
|
||||||
|
|
||||||
|
if (d < s) {
|
||||||
|
// Copy forward
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
d[i] = s[i];
|
||||||
|
}
|
||||||
|
} else if (d > s) {
|
||||||
|
// Copy backward to prevent overwriting uncopied data
|
||||||
|
for (size_t i = n; i > 0; i--) {
|
||||||
|
d[i - 1] = s[i - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill memory block with a constant byte */
|
||||||
|
void *memset(void *s, int c, size_t n) {
|
||||||
|
unsigned char *p = (unsigned char *)s;
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
p[i] = (unsigned char)c;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate the length of a string */
|
||||||
|
size_t strlen(const char *s) {
|
||||||
|
size_t len = 0;
|
||||||
|
while (s[len] != '\0') {
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compare two strings */
|
||||||
|
int strcmp(const char *s1, const char *s2) {
|
||||||
|
while (*s1 && (*s1 == *s2)) {
|
||||||
|
s1++;
|
||||||
|
s2++;
|
||||||
|
}
|
||||||
|
return *(unsigned char *)s1 - *(unsigned char *)s2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy a string from src to dest */
|
||||||
|
char *strcpy(char *dest, const char *src) {
|
||||||
|
size_t i = 0;
|
||||||
|
while (src[i] != '\0') {
|
||||||
|
dest[i] = src[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
dest[i] = '\0';
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
63
rlibc/src/strtok.c
Normal file
63
rlibc/src/strtok.c
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static size_t kernel_strspn(const char *s, const char *accept) {
|
||||||
|
const char *p;
|
||||||
|
const char *a;
|
||||||
|
size_t count = 0;
|
||||||
|
|
||||||
|
for (p = s; *p != '\0'; ++p) {
|
||||||
|
for (a = accept; *a != '\0'; ++a) {
|
||||||
|
if (*p == *a)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (*a == '\0')
|
||||||
|
return count;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *kernel_strpbrk(const char *s, const char *accept) {
|
||||||
|
while (*s != '\0') {
|
||||||
|
const char *a = accept;
|
||||||
|
while (*a != '\0') {
|
||||||
|
if (*s == *a) {
|
||||||
|
return (char *)s;
|
||||||
|
}
|
||||||
|
a++;
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strtok_r(char *str, const char *delim, char **saveptr) {
|
||||||
|
char *token;
|
||||||
|
|
||||||
|
if (str == NULL) {
|
||||||
|
str = *saveptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str == NULL || *str == '\0') {
|
||||||
|
*saveptr = NULL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
str += kernel_strspn(str, delim);
|
||||||
|
if (*str == '\0') {
|
||||||
|
*saveptr = NULL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
token = str;
|
||||||
|
str = kernel_strpbrk(token, delim);
|
||||||
|
|
||||||
|
if (str == NULL) {
|
||||||
|
*saveptr = NULL;
|
||||||
|
} else {
|
||||||
|
*str = '\0';
|
||||||
|
*saveptr = str + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
84
rlibc/src/syscall.c
Normal file
84
rlibc/src/syscall.c
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
#include <syscall.h>
|
||||||
|
|
||||||
|
static inline int syscall1(int num, uint32_t arg1) {
|
||||||
|
int ret;
|
||||||
|
asm volatile (
|
||||||
|
"int $0x80"
|
||||||
|
: "=a"(ret)
|
||||||
|
: "a"(num), "b"(arg1)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int syscall3(int num, uint32_t arg1, uint32_t arg2, uint32_t arg3) {
|
||||||
|
int ret;
|
||||||
|
asm volatile (
|
||||||
|
"int $0x80"
|
||||||
|
: "=a"(ret)
|
||||||
|
: "a"(num), "b"(arg1), "c"(arg2), "d"(arg3)
|
||||||
|
: "memory"
|
||||||
|
);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void exit(int status) {
|
||||||
|
syscall1(SYS_EXIT, (uint32_t)status);
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int open(const char* path) {
|
||||||
|
return syscall3(SYS_OPEN, (uint32_t)path, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int write(int fd, const void* buf, size_t cnt) {
|
||||||
|
return syscall3(SYS_WRITE, (uint32_t)fd, (uint32_t)buf, (uint32_t)cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
int read(int fd, void* buf, size_t cnt) {
|
||||||
|
return syscall3(SYS_READ, (uint32_t)fd, (uint32_t)buf, (uint32_t)cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
int lseek(int fd, size_t offset, int whence) {
|
||||||
|
return syscall3(SYS_LSEEK, (uint32_t)fd, offset, whence);
|
||||||
|
}
|
||||||
|
|
||||||
|
int close(int fd) {
|
||||||
|
return syscall1(SYS_CLOSE, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pty(int* slave) {
|
||||||
|
return syscall1(SYS_PTY, (uint32_t)slave);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fork() {
|
||||||
|
return syscall1(SYS_FORK, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int exec(const char* path) {
|
||||||
|
return syscall1(SYS_EXEC, (uint32_t)path);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dup2(int src, int dst) {
|
||||||
|
return syscall3(SYS_DUP2, src, dst, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int waitpid(int pid, int* status) {
|
||||||
|
return syscall3(SYS_WAIT, pid, (uint32_t)status, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* sbrk(int32_t increment) {
|
||||||
|
return (void*)syscall1(SYS_SBRK, increment);
|
||||||
|
}
|
||||||
|
|
||||||
|
int brk(void *addr) {
|
||||||
|
return syscall1(SYS_BRK, (uint32_t)addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* mmap(int fd) {
|
||||||
|
return (void*)syscall1(SYS_MMAP, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ioctl(int fd, uint32_t request, void* arg) {
|
||||||
|
return syscall3(SYS_IOCTL, fd, request, (uint32_t)arg);
|
||||||
|
}
|
||||||
0
rlibgui/include/psf.h
Normal file
0
rlibgui/include/psf.h
Normal file
20
rlibgui/makefile
Normal file
20
rlibgui/makefile
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
CC = i686-elf-gcc
|
||||||
|
AR = i686-elf-ar
|
||||||
|
CFLAGS = -ffreestanding -O2 -Wall -Wextra -Iinclude
|
||||||
|
TARGET = rlibgui.a
|
||||||
|
|
||||||
|
SRCS = $(shell find src -name "*.c")
|
||||||
|
OBJS = $(SRCS:.c=.o)
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
$(TARGET): $(OBJS)
|
||||||
|
$(AR) rcs $@ $(OBJS)
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJS) $(TARGET) compile_commands.json
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
0
rlibgui/src/psf.c
Normal file
0
rlibgui/src/psf.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,50 +0,0 @@
|
|||||||
/* Diagnostics <assert.h>
|
|
||||||
|
|
||||||
This file is part of the Public Domain C Library (PDCLib).
|
|
||||||
Permission is granted to use, modify, and / or redistribute at will.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "pdclib/_PDCLIB_internal.h"
|
|
||||||
|
|
||||||
#ifndef _PDCLIB_ASSERT_H
|
|
||||||
#define _PDCLIB_ASSERT_H _PDCLIB_ASSERT_H
|
|
||||||
_PDCLIB_PUBLIC void _PDCLIB_assert99( const char * const, const char * const, const char * const );
|
|
||||||
_PDCLIB_PUBLIC void _PDCLIB_assert89( const char * const );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* If NDEBUG is set, assert() is a null operation. */
|
|
||||||
#undef assert
|
|
||||||
|
|
||||||
#ifdef NDEBUG
|
|
||||||
#define assert( ignore ) ( (void) 0 )
|
|
||||||
#else
|
|
||||||
#if __STDC_VERSION__ >= 199901L
|
|
||||||
#define assert( expression ) ( ( expression ) ? (void) 0 \
|
|
||||||
: _PDCLIB_assert99( "Assertion failed: " #expression \
|
|
||||||
", function ", __func__, \
|
|
||||||
", file " __FILE__ \
|
|
||||||
", line " _PDCLIB_value2string( __LINE__ ) \
|
|
||||||
".\n" ) )
|
|
||||||
#else
|
|
||||||
#define assert( expression ) ( ( expression ) ? (void) 0 \
|
|
||||||
: _PDCLIB_assert89( "Assertion failed: " #expression \
|
|
||||||
", file " __FILE__ \
|
|
||||||
", line " _PDCLIB_value2string( __LINE__ ) \
|
|
||||||
".\n" ) )
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Extension hook for downstream projects that want to have non-standard
|
|
||||||
extensions to standard headers.
|
|
||||||
*/
|
|
||||||
#ifdef _PDCLIB_EXTEND_ASSERT_H
|
|
||||||
#include _PDCLIB_EXTEND_ASSERT_H
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
/* Character handling <ctype.h>
|
|
||||||
|
|
||||||
This file is part of the Public Domain C Library (PDCLib).
|
|
||||||
Permission is granted to use, modify, and / or redistribute at will.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _PDCLIB_CTYPE_H
|
|
||||||
#define _PDCLIB_CTYPE_H _PDCLIB_CTYPE_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "pdclib/_PDCLIB_internal.h"
|
|
||||||
|
|
||||||
/* Character classification functions */
|
|
||||||
|
|
||||||
/* Note that there is a difference between "whitespace" (any printing, non-
|
|
||||||
graph character, like horizontal and vertical tab), and "blank" (the literal
|
|
||||||
' ' space character).
|
|
||||||
|
|
||||||
There will be masking macros for each of these later on, but right now I
|
|
||||||
focus on the functions only.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Returns isalpha( c ) || isdigit( c ) */
|
|
||||||
_PDCLIB_PUBLIC int isalnum( int c );
|
|
||||||
|
|
||||||
/* Returns isupper( c ) || islower( c ) in the "C" locale.
|
|
||||||
In any other locale, also returns true for a locale-specific set of
|
|
||||||
alphabetic characters which are neither control characters, digits,
|
|
||||||
punctation, or whitespace.
|
|
||||||
*/
|
|
||||||
_PDCLIB_PUBLIC int isalpha( int c );
|
|
||||||
|
|
||||||
/* Returns true if the character isspace() and used for separating words within
|
|
||||||
a line of text. In the "C" locale, only ' ' and '\t' are considered blanks.
|
|
||||||
*/
|
|
||||||
_PDCLIB_PUBLIC int isblank( int c );
|
|
||||||
|
|
||||||
/* Returns true if the character is a control character. */
|
|
||||||
_PDCLIB_PUBLIC int iscntrl( int c );
|
|
||||||
|
|
||||||
/* Returns true if the character is a decimal digit. Locale-independent. */
|
|
||||||
_PDCLIB_PUBLIC int isdigit( int c );
|
|
||||||
|
|
||||||
/* Returns true for every printing character except space (' ').
|
|
||||||
NOTE: This definition differs from that of iswgraph() in <wctype.h>,
|
|
||||||
which considers any iswspace() character, not only ' '.
|
|
||||||
*/
|
|
||||||
_PDCLIB_PUBLIC int isgraph( int c );
|
|
||||||
|
|
||||||
/* Returns true for lowercase letters in the "C" locale.
|
|
||||||
In any other locale, also returns true for a locale-specific set of
|
|
||||||
characters which are neither control characters, digits, punctation, or
|
|
||||||
space (' '). In a locale other than the "C" locale, a character might test
|
|
||||||
true for both islower() and isupper().
|
|
||||||
*/
|
|
||||||
_PDCLIB_PUBLIC int islower( int c );
|
|
||||||
|
|
||||||
/* Returns true for every printing character including space (' '). */
|
|
||||||
_PDCLIB_PUBLIC int isprint( int c );
|
|
||||||
|
|
||||||
/* Returns true for a locale-specific set of punctuation charcters; these
|
|
||||||
may not be whitespace or alphanumeric. In the "C" locale, returns true
|
|
||||||
for every printing character that is not whitespace or alphanumeric.
|
|
||||||
*/
|
|
||||||
_PDCLIB_PUBLIC int ispunct( int c );
|
|
||||||
|
|
||||||
/* Returns true for every standard whitespace character (' ', '\f', '\n', '\r',
|
|
||||||
'\t', '\v') in the "C" locale. In any other locale, also returns true for a
|
|
||||||
locale-specific set of characters for which isalnum() is false.
|
|
||||||
*/
|
|
||||||
_PDCLIB_PUBLIC int isspace( int c );
|
|
||||||
|
|
||||||
/* Returns true for uppercase letters in the "C" locale.
|
|
||||||
In any other locale, also returns true for a locale-specific set of
|
|
||||||
characters which are neither control characters, digits, punctation, or
|
|
||||||
space (' '). In a locale other than the "C" locale, a character might test
|
|
||||||
true for both islower() and isupper().
|
|
||||||
*/
|
|
||||||
_PDCLIB_PUBLIC int isupper( int c );
|
|
||||||
|
|
||||||
/* Returns true for any hexadecimal-digit character. Locale-independent. */
|
|
||||||
_PDCLIB_PUBLIC int isxdigit( int c );
|
|
||||||
|
|
||||||
/* Character case mapping functions */
|
|
||||||
|
|
||||||
/* Converts an uppercase letter to a corresponding lowercase letter. Input that
|
|
||||||
is not an uppercase letter remains unchanged.
|
|
||||||
*/
|
|
||||||
_PDCLIB_PUBLIC int tolower( int c );
|
|
||||||
|
|
||||||
/* Converts a lowercase letter to a corresponding uppercase letter. Input that
|
|
||||||
is not a lowercase letter remains unchanged.
|
|
||||||
*/
|
|
||||||
_PDCLIB_PUBLIC int toupper( int c );
|
|
||||||
|
|
||||||
/* Extension hook for downstream projects that want to have non-standard
|
|
||||||
extensions to standard headers.
|
|
||||||
*/
|
|
||||||
#ifdef _PDCLIB_EXTEND_CTYPE_H
|
|
||||||
#include _PDCLIB_EXTEND_CTYPE_H
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,202 +0,0 @@
|
|||||||
/* Errors <errno.h>
|
|
||||||
|
|
||||||
This file is part of the Public Domain C Library (PDCLib).
|
|
||||||
Permission is granted to use, modify, and / or redistribute at will.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _PDCLIB_ERRNO_H
|
|
||||||
#define _PDCLIB_ERRNO_H _PDCLIB_ERRNO_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "pdclib/_PDCLIB_lib_ext1.h"
|
|
||||||
#include "pdclib/_PDCLIB_internal.h"
|
|
||||||
|
|
||||||
/* FIXME: With <threads.h>, this needs to be in thread-specific storage. */
|
|
||||||
#define errno (*_PDCLIB_errno_func())
|
|
||||||
|
|
||||||
/* C only requires the following three */
|
|
||||||
|
|
||||||
/* Result too large */
|
|
||||||
#define ERANGE _PDCLIB_ERANGE
|
|
||||||
/* Mathematics argument out of domain of function */
|
|
||||||
#define EDOM _PDCLIB_EDOM
|
|
||||||
/* Illegal byte sequence */
|
|
||||||
#define EILSEQ _PDCLIB_EILSEQ
|
|
||||||
|
|
||||||
/* C++ additionally requires the folloing */
|
|
||||||
|
|
||||||
/* Argument list too long */
|
|
||||||
#define E2BIG _PDCLIB_E2BIG
|
|
||||||
/* Permission denied */
|
|
||||||
#define EACCES _PDCLIB_EACCES
|
|
||||||
/* Address in use */
|
|
||||||
#define EADDRINUSE _PDCLIB_EADDRINUSE
|
|
||||||
/* Address not available */
|
|
||||||
#define EADDRNOTAVAIL _PDCLIB_EADDRNOTAVAIL
|
|
||||||
/* Address family not supported */
|
|
||||||
#define EAFNOSUPPORT _PDCLIB_EAFNOSUPPORT
|
|
||||||
/* Resource unavailable, try again */
|
|
||||||
#define EAGAIN _PDCLIB_EAGAIN
|
|
||||||
/* Connection already in progress */
|
|
||||||
#define EALREADY _PDCLIB_EALREADY
|
|
||||||
/* Bad file descriptor */
|
|
||||||
#define EBADF _PDCLIB_EBADF
|
|
||||||
/* Bad message */
|
|
||||||
#define EBADMSG _PDCLIB_EBADMSG
|
|
||||||
/* Device or resource busy */
|
|
||||||
#define EBUSY _PDCLIB_EBUSY
|
|
||||||
/* Operation canceled */
|
|
||||||
#define ECANCELED _PDCLIB_ECANCELED
|
|
||||||
/* No child processes */
|
|
||||||
#define ECHILD _PDCLIB_ECHILD
|
|
||||||
/* Connection aborted */
|
|
||||||
#define ECONNABORTED _PDCLIB_ECONNABORTED
|
|
||||||
/* Connection refused */
|
|
||||||
#define ECONNREFUSED _PDCLIB_ECONNREFUSED
|
|
||||||
/* Connection reset */
|
|
||||||
#define ECONNRESET _PDCLIB_ECONNRESET
|
|
||||||
/* Resource deadlock would occur */
|
|
||||||
#define EDEADLK _PDCLIB_EDEADLK
|
|
||||||
/* Destination address required */
|
|
||||||
#define EDESTADDRREQ _PDCLIB_EDESTADDRREQ
|
|
||||||
/* File exists */
|
|
||||||
#define EEXIST _PDCLIB_EEXIST
|
|
||||||
/* Bad address */
|
|
||||||
#define EFAULT _PDCLIB_EFAULT
|
|
||||||
/* File too large */
|
|
||||||
#define EFBIG _PDCLIB_EFBIG
|
|
||||||
/* Host is unreachable */
|
|
||||||
#define EHOSTUNREACH _PDCLIB_EHOSTUNREACH
|
|
||||||
/* Identifier removed */
|
|
||||||
#define EIDRM _PDCLIB_EIDRM
|
|
||||||
/* Operation in progress */
|
|
||||||
#define EINPROGRESS _PDCLIB_EINPROGRESS
|
|
||||||
/* Interrupted function */
|
|
||||||
#define EINTR _PDCLIB_EINTR
|
|
||||||
/* Invalid argument */
|
|
||||||
#define EINVAL _PDCLIB_EINVAL
|
|
||||||
/* I/O error */
|
|
||||||
#define EIO _PDCLIB_EIO
|
|
||||||
/* Socket is connected */
|
|
||||||
#define EISCONN _PDCLIB_EISCONN
|
|
||||||
/* Is a directory */
|
|
||||||
#define EISDIR _PDCLIB_EISDIR
|
|
||||||
/* Too many levels of symbolic links */
|
|
||||||
#define ELOOP _PDCLIB_ELOOP
|
|
||||||
/* File descriptor value too large */
|
|
||||||
#define EMFILE _PDCLIB_EMFILE
|
|
||||||
/* Too many links */
|
|
||||||
#define EMLINK _PDCLIB_EMLINK
|
|
||||||
/* Message too large */
|
|
||||||
#define EMSGSIZE _PDCLIB_EMSGSIZE
|
|
||||||
/* Filename too long */
|
|
||||||
#define ENAMETOOLONG _PDCLIB_ENAMETOOLONG
|
|
||||||
/* Network is down */
|
|
||||||
#define ENETDOWN _PDCLIB_ENETDOWN
|
|
||||||
/* Connection aborted by network */
|
|
||||||
#define ENETRESET _PDCLIB_ENETRESET
|
|
||||||
/* Network unreachable */
|
|
||||||
#define ENETUNREACH _PDCLIB_ENETUNREACH
|
|
||||||
/* Too many files open in system */
|
|
||||||
#define ENFILE _PDCLIB_ENFILE
|
|
||||||
/* No buffer space available */
|
|
||||||
#define ENOBUFS _PDCLIB_ENOBUFS
|
|
||||||
/* No message is available on the STREAM head read queue */
|
|
||||||
#define ENODATA _PDCLIB_ENODATA
|
|
||||||
/* No such device */
|
|
||||||
#define ENODEV _PDCLIB_ENODEV
|
|
||||||
/* No such file or directory */
|
|
||||||
#define ENOENT _PDCLIB_ENOENT
|
|
||||||
/* Executable file format error */
|
|
||||||
#define ENOEXEC _PDCLIB_ENOEXEC
|
|
||||||
/* No locks available */
|
|
||||||
#define ENOLCK _PDCLIB_ENOLCK
|
|
||||||
/* Link has been severed */
|
|
||||||
#define ENOLINK _PDCLIB_ENOLINK
|
|
||||||
/* Not enough space */
|
|
||||||
#define ENOMEM _PDCLIB_ENOMEM
|
|
||||||
/* No message of the desired type */
|
|
||||||
#define ENOMSG _PDCLIB_ENOMSG
|
|
||||||
/* Protocol not available */
|
|
||||||
#define ENOPROTOOPT _PDCLIB_ENOPROTOOPT
|
|
||||||
/* No space left on device */
|
|
||||||
#define ENOSPC _PDCLIB_ENOSPC
|
|
||||||
/* No STREAM resources */
|
|
||||||
#define ENOSR _PDCLIB_ENOSR
|
|
||||||
/* Not a STREAM */
|
|
||||||
#define ENOSTR _PDCLIB_ENOSTR
|
|
||||||
/* Function not supported */
|
|
||||||
#define ENOSYS _PDCLIB_ENOSYS
|
|
||||||
/* The socket is not connected */
|
|
||||||
#define ENOTCONN _PDCLIB_ENOTCONN
|
|
||||||
/* Not a directory */
|
|
||||||
#define ENOTDIR _PDCLIB_ENOTDIR
|
|
||||||
/* Directory not empty */
|
|
||||||
#define ENOTEMPTY _PDCLIB_ENOTEMPTY
|
|
||||||
/* State not recoverable */
|
|
||||||
#define ENOTRECOVERABLE _PDCLIB_ENOTRECOVERABLE
|
|
||||||
/* Not a socket */
|
|
||||||
#define ENOTSOCK _PDCLIB_ENOTSOCK
|
|
||||||
/* Not supported */
|
|
||||||
#define ENOTSUP _PDCLIB_ENOTSUP
|
|
||||||
/* Inappropriate I/O control operation */
|
|
||||||
#define ENOTTY _PDCLIB_ENOTTY
|
|
||||||
/* No such device or address */
|
|
||||||
#define ENXIO _PDCLIB_ENXIO
|
|
||||||
/* Operation not supported on socket */
|
|
||||||
#define EOPNOTSUPP _PDCLIB_EOPNOTSUPP
|
|
||||||
/* Value too large to be stored in data type */
|
|
||||||
#define EOVERFLOW _PDCLIB_EOVERFLOW
|
|
||||||
/* Previous owner died */
|
|
||||||
#define EOWNERDEAD _PDCLIB_EOWNERDEAD
|
|
||||||
/* Operation not permitted */
|
|
||||||
#define EPERM _PDCLIB_EPERM
|
|
||||||
/* Broken pipe */
|
|
||||||
#define EPIPE _PDCLIB_EPIPE
|
|
||||||
/* Protocol error */
|
|
||||||
#define EPROTO _PDCLIB_EPROTO
|
|
||||||
/* Protocol not supported */
|
|
||||||
#define EPROTONOSUPPORT _PDCLIB_EPROTONOSUPPORT
|
|
||||||
/* Protocol wrong type for socket */
|
|
||||||
#define EPROTOTYPE _PDCLIB_EPROTOTYPE
|
|
||||||
/* Read-only file system */
|
|
||||||
#define EROFS _PDCLIB_EROFS
|
|
||||||
/* Invalid seek */
|
|
||||||
#define ESPIPE _PDCLIB_ESPIPE
|
|
||||||
/* No such process */
|
|
||||||
#define ESRCH _PDCLIB_ESRCH
|
|
||||||
/* Stream ioctl() timeout */
|
|
||||||
#define ETIME _PDCLIB_ETIME
|
|
||||||
/* Connection timed out */
|
|
||||||
#define ETIMEDOUT _PDCLIB_ETIMEDOUT
|
|
||||||
/* Text file busy */
|
|
||||||
#define ETXTBSY _PDCLIB_ETXTBSY
|
|
||||||
/* Operation would block */
|
|
||||||
#define EWOULDBLOCK _PDCLIB_EWOULDBLOCK
|
|
||||||
/* Cross-device link */
|
|
||||||
#define EXDEV _PDCLIB_EXDEV
|
|
||||||
|
|
||||||
/* Annex K -- Bounds-checking interfaces */
|
|
||||||
|
|
||||||
#if ( __STDC_WANT_LIB_EXT1__ + 0 ) != 0
|
|
||||||
#ifndef _PDCLIB_ERRNO_T_DEFINED
|
|
||||||
#define _PDCLIB_ERRNO_T_DEFINED _PDCLIB_ERRNO_T_DEFINED
|
|
||||||
typedef int errno_t;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Extension hook for downstream projects that want to have non-standard
|
|
||||||
extensions to standard headers.
|
|
||||||
*/
|
|
||||||
#ifdef _PDCLIB_EXTEND_ERRNO_H
|
|
||||||
#include _PDCLIB_EXTEND_ERRNO_H
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#ifndef _FCNTL_H
|
|
||||||
#define _FCNTL_H
|
|
||||||
|
|
||||||
/* File access modes for open() */
|
|
||||||
#define O_RDONLY 00000000
|
|
||||||
#define O_WRONLY 00000001
|
|
||||||
#define O_RDWR 00000002
|
|
||||||
|
|
||||||
/* File creation flags */
|
|
||||||
#define O_CREAT 00000100
|
|
||||||
#define O_EXCL 00000200
|
|
||||||
#define O_NOCTTY 00000400
|
|
||||||
#define O_TRUNC 00001000
|
|
||||||
#define O_APPEND 00002000
|
|
||||||
#define O_NONBLOCK 00004000
|
|
||||||
|
|
||||||
#define AT_FDCWD (-100)
|
|
||||||
|
|
||||||
#endif /* _FCNTL_H */
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user