Compare commits

...

36 Commits

Author SHA1 Message Date
974e23987e small fix 2026-07-20 22:52:47 -05:00
256346534a more terminaal stuff 2026-07-17 14:23:07 -05:00
b6681b74c9 vga now working with term and shell program 2026-07-16 23:19:54 -05:00
3246dbbd19 build system refresh 2026-07-16 16:09:12 -05:00
b588634253 working on exposing vga to userspace 2026-07-16 14:44:08 -05:00
37aa46c847 vga, again 2026-07-15 23:02:24 -05:00
0c6aaa1aed deleted some files 2026-07-15 08:32:24 -05:00
44a0c9aeba blue! 2026-07-15 08:07:06 -05:00
c77d9e1725 script edits 2026-07-14 23:15:37 -05:00
7f6ef0fdc2 removed .json files 2026-07-14 23:06:50 -05:00
54f0f4ed9e removed clone clone 2026-07-14 23:00:09 -05:00
1b75ac7578 more vga crap 2026-07-14 22:44:53 -05:00
6a79a20cf6 console vga stuff 2026-07-14 17:40:30 -05:00
454de8feed trying to get VGA fb mode to work.. 2026-07-14 00:07:50 -05:00
5c7febbbf0 shell can launch another user processgit add .git add .! 2026-07-12 20:13:13 -05:00
e2ab130324 got the screen cleared, vga cursor moving, looking good 2026-07-12 11:42:49 -05:00
d60036a4bd added some useless shell commands 2026-07-12 04:37:46 -05:00
3c6fd8cb65 got some of the pty actually working in userspace 2026-07-12 03:56:25 -05:00
992ffd1f6b sumting 2026-07-11 10:36:30 -05:00
92748fd258 still working on a more robust vfs 2026-07-11 10:33:08 -05:00
032a35206a refining vfs 2026-07-10 07:46:46 -05:00
4d98d73f5e almost got the term emu working and shell 2026-07-08 21:15:30 -05:00
ec3cbb4794 FORKgit add .git add .! 2026-07-08 19:11:39 -05:00
e42ee8eb85 heading to laptop 2026-07-07 18:52:22 -05:00
177a0b8fe9 starting to work on pty drivers, fork(), and scheduler redesign 2026-07-07 00:13:24 -05:00
6d7a23d747 removed pdclib, strange things were happening..., user shell kinda works now 2026-07-06 22:13:57 -05:00
7d76f0ec73 quick script 2026-07-04 02:09:16 -05:00
17ccde3556 f'd myself over of course, scheduler can now run user programs.... 2026-07-04 01:59:19 -05:00
0b98ac0273 getting there... 2026-07-04 00:26:20 -05:00
ab5a1ecb6b still fighting an issue 2026-07-03 22:25:24 -05:00
48df965268 working on getting a unified stack setup for user and kernel tasks 2026-07-01 22:09:01 -05:00
b6ee4fc3de more userspace stuff 2026-07-01 20:00:22 -05:00
af6c1c94cf working on reading elf from initrd, and getting it launched with the new scheduler 2026-06-30 19:26:31 -05:00
ce81d4eb31 loading initrd now... 2026-06-30 00:03:21 -05:00
5983212da0 removed cache filder for clangdeeznuts 2026-06-29 17:01:22 -05:00
432d160b7a modified some syscall code in rlibc, fs stuff 2026-06-29 17:00:07 -05:00
408 changed files with 3317 additions and 48166 deletions

7
.gitignore vendored
View File

@@ -3,11 +3,12 @@
*.o *.o
*.bin *.bin
*.elf *.elf
*.json
.cache
.idea .idea
.vscode .vscode
build sysroot
isodir isodir
compiler*/

16
build.sh Executable file
View 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
View File

@@ -0,0 +1,6 @@
#!/bin/bash
./build.sh
make run

17
build_libs.sh Executable file
View 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
View 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
View 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
View 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

View File

@@ -1,444 +0,0 @@
[
{
"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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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"
},
{
"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"
}
]

5
copy_resources.sh Executable file
View File

@@ -0,0 +1,5 @@
#!/bin/bash
cp -r resources/fonts/. sysroot/usr/fonts
cp -r kernel/. sysroot/kernel

View File

@@ -1,3 +1,4 @@
menuentry "RockOS" { menuentry "RockOS" {
multiboot /boot/rockos multiboot /boot/rockos/
module /boot/initrd.img
} }

View File

@@ -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

View File

@@ -29,14 +29,19 @@ 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
@@ -121,3 +126,8 @@ outsw:
fetch_cr3: fetch_cr3:
mov %cr3, %eax mov %cr3, %eax
ret ret
.global kpanic
kpanic:
cli
hlt

View File

@@ -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
View 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;
}

View 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

View 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;
}

View File

@@ -0,0 +1,8 @@
#ifndef D_DEVFS_H
#define D_DEVFS_H
#include <vfs.h>
vfs_node_t* create_devfs();
#endif

View File

@@ -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

View File

@@ -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() {
@@ -69,3 +76,23 @@ int init_ps2() {
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;
}

View File

@@ -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
View 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
View 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

View 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
}

View 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

View File

@@ -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;
for (size_t y = 0; y < VGA_HEIGHT; y++) { kprintf("mapping vga pages\n");
for (size_t x = 0; x < VGA_WIDTH; x++) {
const size_t index = y * VGA_WIDTH + x; uint32_t fb_size_bytes = fb_height * fb_pitch;
terminal_buffer[index] = vga_entry(' ', terminal_color); 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);
dev->flags = VFS_CHARDEVICE;
dev->mmap = vga_mmap;
dev->ioctl = vga_ioctl;
} }
void vga_putchar(char c) { uint32_t vga_get_framebuffer() {
if (c == '\n') { return VGA_FRAMEBUFFER;
terminal_row++; }
terminal_column = 0;
return; uint32_t vga_get_width() {
} return framebuffer_width;
}
if (c == '\t') {
for (int i = 0; i < 4; i++) { uint32_t vga_get_height() {
vga_putchar(' '); return framebuffer_height;
} }
return;
} uint32_t vga_get_pitch() {
return framebuffer_pitch;
const size_t index = terminal_row * VGA_WIDTH + terminal_column; }
terminal_buffer[index] = vga_entry(c, terminal_color);
if (++terminal_column == VGA_WIDTH) { uint8_t vga_get_bpp() {
terminal_column = 0; return framebuffer_bpp;
if (++terminal_row == VGA_HEIGHT) }
terminal_row = 0;
} 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;
}
}
}
}
} }

View File

@@ -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
View 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;
}

View File

@@ -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

View File

@@ -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
@@ -46,40 +46,10 @@ typedef struct __attribute__((packed)) {
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;

View File

@@ -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

View File

@@ -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,6 +68,7 @@ isr32:
call send_eoi_master call send_eoi_master
pop %ds
popal popal
sti sti
iret iret

View File

@@ -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
View 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
View 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();

View File

@@ -1,12 +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 "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>
@@ -16,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>
@@ -23,46 +31,143 @@
extern char __kernel_start; extern char __kernel_start;
extern char __kernel_end; extern char __kernel_end;
void first_task() { #define SERIAL_DBG
kprintf("task started\n");
int i = 5; extern uint32_t page_directory[1024];
while (i--) { void* kernel_cr3 = page_directory;
sleep(1000);
kprintf("task awake [%d]\n", i); void parse_multiboot_modules(uint32_t mbi_vaddr) {
// find where grub put the boot module containing initrd
multiboot_info* mbi = (multiboot_info*)mbi_vaddr;
uint32_t mod_count = mbi->mods_count;
multiboot_module_t* mod = (multiboot_module_t*)((uint32_t)mbi->mods_addr + 0xC0000000);
for (uint32_t i = 0; i < mod_count; i++) {
uint32_t start = mod[i].mod_start;
uint32_t end = mod[i].mod_end;
uint32_t cmdline = mod[i].cmdline;
multiboot_module_info_table[i].mod_start = start + 0xC0000000;
multiboot_module_info_table[i].mod_end = end + 0xC0000000;
multiboot_module_info_table[i].cmdline = cmdline + 0xC0000000;
} }
kprintf("exiting\n");
exit();
} }
void kmain(uint32_t magic, multiboot_info* mbi) { vfs_node_t* load_initrd() {
disable_interrupts(); multiboot_module_t* initrd_module = &multiboot_module_info_table[0];
if (!(mbi->flags & (1 << 6))) { kprintf("initrd found @ [v] 0x%x\n", initrd_module->mod_start);
return cpio_read_fs(initrd_module->mod_start);
}
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; return;
} }
vga_init(); 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 mmap_virtual_addr = mbi->mmap_addr + 0xC0000000; uint32_t* u_esp = (uint32_t*)stack_top;
init_pmm((void*)mmap_virtual_addr, mbi->mmap_length); *(--u_esp) = 0; // envp = NULL
kprintf("memory detection complete. total free memory: %dMB\n", total_free_memory() / 1024 / 1024); *(--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();
init_serial();
// need mmap and fb info
if (!(mbi->flags & (1 << 6)) || !(mbi->flags & (1 << 12))) {
return;
}
parse_multiboot_modules((uint32_t)mbi);
uint32_t vga_fb_address = mbi->framebuffer_addr;
uint32_t vga_fb_width = mbi->framebuffer_width;
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();
kprintf("basic initializations complete\n"); disable_interrupts();
disable_interrupts(); // just paranoid... do it again
init_scheduler(); init_scheduler();
enable_interrupts(); enable_interrupts();
create_task((uint32_t)first_task, fetch_cr3()); vfs_node_t* vfs_root = vfs_create_root();
vfs_node_t* initrd_root = load_initrd();
while(1) { if (!initrd_root) {
sleep(5000); kprintf("failed to load initrd\n");
kprintf("kernel awake\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
View 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
View 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
View 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
View 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

View File

@@ -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;
} }
@@ -38,6 +38,34 @@ int strlen(const char* str) {
return len; return len;
} }
int strncmp(const char *s1, const char *s2, size_t n) {
// If n is 0, we don't compare anything and strings are "equal"
while (n > 0) {
// If characters don't match, or we hit the null-terminator of s1
if (*s1 != *s2) {
return *(unsigned char *)s1 - *(unsigned char *)s2;
}
// If we reached the end of the strings simultaneously
if (*s1 == '\0') {
break;
}
s1++;
s2++;
n--;
}
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;
@@ -107,3 +135,7 @@ void* kalloc(size_t sz) {
return kalloc(sz); return kalloc(sz);
} }
void kfree(void* ptr) {
}

View File

@@ -5,13 +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 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

View File

@@ -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
View 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
View 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
View 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
View 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;
}

View File

@@ -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;
@@ -109,7 +98,7 @@ void* p_alloc_frame() {
return 0; return 0;
} }
static void p_free_frame(void* addr) { void p_free_frame(void* addr) {
mark_free((uint32_t)addr); mark_free((uint32_t)addr);
} }
@@ -117,8 +106,8 @@ static 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];
return (void*)task_pd_addr;
}
void* clone_current_pd() {
uint32_t task_pd_addr = (uint32_t)p_alloc_frame();
if (task_pd_addr == 0) {
return NULL; // outta mem
} }
task_pd[1023] = (uint32_t)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_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() {
uint32_t pde = TEMP_MAPPING_VADDR >> 22;
uint32_t pte = (TEMP_MAPPING_VADDR >> 12) & 0x3FF;
uint32_t* kernel_pt = (uint32_t*)(PAGE_TABLES + (pde * PAGE_SIZE));
kernel_pt[pte] = 0;
return (void*)pd_address;
} }

View File

@@ -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

3
kernel/multiboot.c Normal file
View File

@@ -0,0 +1,3 @@
#include "multiboot.h"
multiboot_module_t multiboot_module_info_table[32];

View File

@@ -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 {
@@ -31,6 +54,8 @@ typedef struct {
uint32_t mod_end; // Physical end address of user.elf uint32_t mod_end; // Physical end address of user.elf
uint32_t cmdline; // Pointer to a string (e.g., "/boot/user.elf") uint32_t cmdline; // Pointer to a string (e.g., "/boot/user.elf")
uint32_t pad; uint32_t pad;
} __attribute__((packed)) multiboot_module_entry; } __attribute__((packed)) multiboot_module_t;
extern multiboot_module_t multiboot_module_info_table[32];
#endif #endif

View File

@@ -3,20 +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 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

View File

@@ -6,26 +6,31 @@
yield: # void yield() yield: # void yield()
cli cli
pushfl popl %ecx
pushl %cs
movl 8(%esp), %eax pushfl // EFLAGS
pushl %eax pushl %cs // CS
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

View File

@@ -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);
}
*(--esp) = 0x0202; // EFLAGS void* kstack_bottom = kalloc(PAGE_SIZE);
*(--esp) = 0x08; // CS uint32_t kstack_top = (uint32_t)kstack_bottom + PAGE_SIZE;
*(--esp) = entry_point; // EIP process->kstack_top = kstack_top;
uint32_t* esp = (uint32_t*)kstack_top;
if (user) {
*(--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,25 +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* rtn = current_process;
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;
}

View File

@@ -1,14 +1,24 @@
#ifndef KSCHEDULER_H #ifndef KSCHEDULER_H
#define KSCHEDULER_H #define KSCHEDULER_H
#include "process.h"
#include <stdint.h> #include <stdint.h>
void init_scheduler(); void lock_scheduler();
void unlock_scheduler();
int create_task(uint32_t entry_point, uint32_t cr3); void init_scheduler();
void init_task(process_t* process, uint32_t entry_point, uint32_t cr3, int user, uint32_t u_esp);
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
View 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

View File

@@ -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

View File

@@ -1,43 +1,299 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h>
#include "drivers/serial/serial.h"
#include "lib/memory.h"
#include "lib/ringbuf.h"
#include "memory/mm.h"
#include "process.h"
#include "scheduler.h" #include "scheduler.h"
#include "vfs.h"
#include "elf.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;
int32_t sys_exit(); static int32_t sys_exit(int status) {
int32_t sys_read(); process_t* task = current_task();
int32_t sys_write(); task->state = STATE_DEAD;
int32_t sys_open(); task->exit_status = status;
int32_t sys_close(); if (task->waiting) {
int32_t sys_brk(); wake(task->waiting);
int32_t syscall(registers_t* regs) {
switch(regs->eax) {
case 1: return sys_exit();
case 3: return sys_read();
case 4: return sys_write();
case 5: return sys_open();
case 6: return sys_close();
case 12: return sys_brk();
default:
return -1;
} }
}
int32_t sys_exit() {
exit(); exit();
return 0; return 0;
} }
int32_t sys_read() { static int32_t sys_write(int fd, const void* buf, size_t count) {
if (fd < 0 || fd >= MAX_PROCESS_FDS) return -1;
file_t* f = current_task()->fd_table[fd];
if (!f || !f->node) return -1;
uint32_t rd = f->node->write(f->node, f->offset, count, (uint8_t*)buf);
f->offset += rd;
return rd;
}
static int32_t sys_read(int fd, void* buf, size_t count) {
if (fd < 0 || fd >= MAX_PROCESS_FDS) return -1;
file_t* f = current_task()->fd_table[fd];
if (!f || !f->node) return -1;
uint32_t rd = f->node->read(f->node, f->offset, count, (uint8_t*)buf);
f->offset += rd;
return rd;
}
static int32_t sys_open(const char* filename, int flags) {
return vfs_open(filename, flags);
}
static int32_t sys_close(int fd) {
process_t* task = current_task();
task->fd_table[fd] = NULL;
return 1;
}
static int32_t sys_brk(uint32_t new_break) {
process_t* current = current_task();
if (new_break == 0) {
return current->heap_end;
}
if (new_break < current->heap_end) {
current->heap_end = new_break;
return current->heap_end;
}
uint32_t page_start = (current->heap_end + 4095) & ~4095;
uint32_t page_end = (new_break + 4095) & ~4095;
for (uint32_t addr = page_start; addr < page_end; addr += 4096) {
// 1. Allocate a physical frame using your PMM (Physical Memory Manager)
void* phys = p_alloc_frame();
// 2. Map it into the current page directory using your VMM (Virtual Memory Manager)
map_page(addr, (uint32_t)phys, PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER);
}
current->heap_end = new_break;
return current->heap_end;
}
static int32_t sys_sbrk(int32_t inc) {
process_t* current = current_task();
if (inc <= 0) { // can't shrink yet
return current->heap_end;
}
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; return 0;
} }
int32_t sys_write() { static int32_t sys_dup2(int src, int dst) {
return 0; 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 Normal file
View File

@@ -0,0 +1,130 @@
#include <vfs.h>
#include <process.h>
#include <scheduler.h>
#include <lib/memory.h>
#include <lib/string.h>
#include <lib/print.h>
vfs_node_t* root = NULL;
vfs_node_t* vfs_create_root() {
root = kalloc(sizeof(vfs_node_t));
memset((uint8_t*)root, 0, sizeof(vfs_node_t));
strcpy(root->name, "root");
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;
}

65
kernel/vfs.h Normal file
View File

@@ -0,0 +1,65 @@
#ifndef KVFS_H
#define KVFS_H
#include <stdint.h>
#include <stddef.h>
#define VFS_FILE 0x01
#define VFS_DIRECTORY 0x02
#define VFS_CHARDEVICE 0x03
#define VFS_BLOCKDEVICE 0x04
#define VFS_PIPE 0x05
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 (*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* (*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 {
char name[128];
uint32_t flags; // File, directory, device, etc.
uint32_t size; // Size of file in bytes
struct vfs_node* first_child;
struct vfs_node* next_sibling;
read_type_t read;
write_type_t write;
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* mnt;
void* data;
} vfs_node_t;
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

5
make_img.sh Executable file
View File

@@ -0,0 +1,5 @@
#!/bin/bash
cd sysroot
find . -depth -print | cpio -o -H newc > ../isodir/boot/initrd.img
cd ..

View File

@@ -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/

View File

@@ -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

View File

@@ -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

View File

@@ -1,8 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
printf("Hello, World from RockOS!\n");
return 0;
}

View File

@@ -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
View File

@@ -0,0 +1 @@
rocksh

21
programs/rocksh/crt0.S Normal file
View 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
View 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
View 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
View File

@@ -0,0 +1 @@
rockterm

21
programs/rockterm/crt0.S Normal file
View 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

View 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
View 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);
}
}
}

View 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

Binary file not shown.

10
rlibc/include/stdio.h Normal file
View 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
View 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
View 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

View 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
View 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
View 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
View 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

View File

@@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View File

20
rlibgui/makefile Normal file
View 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
View File

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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