ring 3, reorganization
This commit is contained in:
parent
9fec34806e
commit
8e0c51ae5e
38 changed files with 1406 additions and 128 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
-std=c23
|
-std=c23
|
||||||
|
-ffreestanding
|
||||||
-I
|
-I
|
||||||
dependencies/limine
|
dependencies/limine
|
||||||
-I
|
-I
|
||||||
kernel/include
|
include
|
||||||
|
|
|
||||||
31
include/calcite/calcite.h
Normal file
31
include/calcite/calcite.h
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
/* Calcite, include/calcite/calcite.h
|
||||||
|
* Copyright 2025 Benji Dial
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
[[noreturn]] void end_thread();
|
||||||
|
|
||||||
|
struct framebuffer_info {
|
||||||
|
uint8_t *fb_base;
|
||||||
|
int fb_width;
|
||||||
|
int fb_height;
|
||||||
|
int fb_pitch;
|
||||||
|
};
|
||||||
|
|
||||||
|
void map_framebuffer(struct framebuffer_info *info_out);
|
||||||
23
include/kernel-public/syscall-numbers.h
Normal file
23
include/kernel-public/syscall-numbers.h
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
/* Calcite, include/kernel-public/syscall-numbers.h
|
||||||
|
* Copyright 2025 Benji Dial
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SYSCALL_END_THREAD,
|
||||||
|
SYSCALL_MAP_FRAMEBUFFER
|
||||||
|
};
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
COMMON_CC_EXTRA_FLAGS="-O3 -Wall -Wextra"
|
COMMON_CC_EXTRA_FLAGS="-O3 -Wall -Wextra"
|
||||||
COMMON_CC_FLAGS="-std=c23 ${COMMON_CC_EXTRA_FLAGS}"
|
COMMON_CC_FLAGS="-std=c23 -ffreestanding -I include ${COMMON_CC_EXTRA_FLAGS}"
|
||||||
KERNEL_CC_FLAGS="-I dependencies/limine -I kernel/include -mno-sse -ffreestanding ${COMMON_CC_FLAGS}"
|
KERNEL_CC_FLAGS="-mno-sse -I dependencies/limine ${COMMON_CC_FLAGS}"
|
||||||
|
#in the future user code will be allowed to use sse
|
||||||
|
USER_CC_FLAGS="-mno-sse ${COMMON_CC_FLAGS}"
|
||||||
|
|
||||||
if [ -e build.ninja ]; then
|
if [ -e build.ninja ]; then
|
||||||
echo build.ninja already exists.
|
echo build.ninja already exists.
|
||||||
|
|
@ -18,34 +20,81 @@ echo "rule kernel_cc" >> build.ninja
|
||||||
echo " depfile = \$out.d" >> build.ninja
|
echo " depfile = \$out.d" >> build.ninja
|
||||||
echo " command = cc -c -MD -MF \$out.d ${KERNEL_CC_FLAGS} \$in -o \$out" >> build.ninja
|
echo " command = cc -c -MD -MF \$out.d ${KERNEL_CC_FLAGS} \$in -o \$out" >> build.ninja
|
||||||
|
|
||||||
|
echo "rule user_cc" >> build.ninja
|
||||||
|
echo " depfile = \$out.d" >> build.ninja
|
||||||
|
echo " command = cc -c -MD -MF \$out.d ${USER_CC_FLAGS} \$in -o \$out" >> build.ninja
|
||||||
|
|
||||||
echo "rule kernel_ld" >> build.ninja
|
echo "rule kernel_ld" >> build.ninja
|
||||||
echo " command = ld -T kernel/link.ld \$in -o \$out" >> build.ninja
|
echo " command = ld -T src/kernel/link.ld \$in -o \$out" >> build.ninja
|
||||||
|
|
||||||
ALL_KERNEL_OBJECTS=""
|
echo "rule user_lib_ld" >> build.ninja
|
||||||
|
echo " command = ld -r \$in -o \$out" >> build.ninja
|
||||||
|
|
||||||
for f in kernel/src/*.asm; do
|
#eventually maybe a libc will be linked in
|
||||||
f=$(echo $f | sed -e 's/^kernel\/src\///')
|
echo "rule user_app_ld" >> build.ninja
|
||||||
echo "build build/kernel/$f.o: nasm kernel/src/$f" >> build.ninja
|
echo " command = ld \$in -o \$out" >> build.ninja
|
||||||
ALL_KERNEL_OBJECTS="${ALL_KERNEL_OBJECTS} build/kernel/$f.o"
|
|
||||||
|
#builds everything in a directory
|
||||||
|
# $1 - source directory
|
||||||
|
# $2 - cc rule
|
||||||
|
# $3 - ld rule
|
||||||
|
# $4 - linked object name
|
||||||
|
# $5 - extra objects to link in
|
||||||
|
build_all() {
|
||||||
|
|
||||||
|
sources="$1/*.asm $1/*.c"
|
||||||
|
objects="$5"
|
||||||
|
|
||||||
|
for src in $sources; do
|
||||||
|
if echo $src | grep -q -v '*'; then
|
||||||
|
build=$(echo $src | sed -e 's/^src/build/').o
|
||||||
|
if echo $src | grep -q '.c$'; then
|
||||||
|
echo "build $build: $2 $src" >> build.ninja
|
||||||
|
else
|
||||||
|
echo "build $build: nasm $src" >> build.ninja
|
||||||
|
fi
|
||||||
|
objects="$objects $build"
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
for f in kernel/src/*.c; do
|
build_dir=$(echo $1 | sed -e 's/^src/build/')
|
||||||
f=$(echo $f | sed -e 's/^kernel\/src\///')
|
echo "build $build_dir/$4: $3 $objects" >> build.ninja
|
||||||
echo "build build/kernel/$f.o: kernel_cc kernel/src/$f" >> build.ninja
|
|
||||||
ALL_KERNEL_OBJECTS="${ALL_KERNEL_OBJECTS} build/kernel/$f.o"
|
}
|
||||||
|
|
||||||
|
build_all src/kernel kernel_cc kernel_ld kernel.elf
|
||||||
|
|
||||||
|
for dir in src/user-libs/*; do
|
||||||
|
lib_name=$(echo $dir | sed -e 's/^src\/user-libs\///')
|
||||||
|
build_all $dir user_cc user_lib_ld lib$lib_name.o
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "build build/kernel/kernel.elf: kernel_ld ${ALL_KERNEL_OBJECTS}" >> build.ninja
|
apps=""
|
||||||
|
|
||||||
|
for dir in src/user-apps/*; do
|
||||||
|
|
||||||
|
if [ -e $dir/libraries.txt ]; then
|
||||||
|
lib_paths=$(cat $dir/libraries.txt | sed -e 's/^.*$/build\/user-libs\/\0\/lib\0.o/')
|
||||||
|
else
|
||||||
|
lib_paths=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
app_name=$(echo $dir | sed -e 's/^src\/user-apps\///')
|
||||||
|
build_all $dir user_cc user_app_ld $app_name.elf $lib_paths
|
||||||
|
build_dir=$(echo $dir | sed -e 's/^src/build/')
|
||||||
|
apps="$apps $build_dir/$app_name.elf"
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
echo "rule initfs" >> build.ninja
|
echo "rule initfs" >> build.ninja
|
||||||
echo " command =" \
|
echo " command =" \
|
||||||
"rm -rf build/initfs &&" \
|
"rm -rf build/initfs &&" \
|
||||||
"mkdir -p build/initfs/resx &&" \
|
"mkdir -p build/initfs/apps &&" \
|
||||||
"echo Hello! > build/initfs/resx/hello.txt &&" \
|
"cp build/user-apps/hello/hello.elf build/initfs/apps/ &&" \
|
||||||
"cd build/initfs &&" \
|
"cd build/initfs &&" \
|
||||||
"tar cf ../initfs.tar *" >> build.ninja
|
"tar cf ../initfs.tar *" >> build.ninja
|
||||||
|
|
||||||
echo "build build/initfs.tar: initfs" >> build.ninja
|
echo "build build/initfs.tar: initfs $apps" >> build.ninja
|
||||||
|
|
||||||
echo "rule disk" >> build.ninja
|
echo "rule disk" >> build.ninja
|
||||||
echo " command =" \
|
echo " command =" \
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,34 @@
|
||||||
/* Calcite, kernel/src/entry.c
|
/* Calcite, src/kernel/entry.c
|
||||||
* Copyright 2025 Benji Dial
|
* Copyright 2025 Benji Dial
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or (at
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
* more details.
|
* for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <framebuffer.h>
|
#include "framebuffer.h"
|
||||||
#include <interrupts.h>
|
#include "interrupts.h"
|
||||||
#include <utility.h>
|
#include "kernel-public/syscall-numbers.h"
|
||||||
#include <initfs.h>
|
#include "scheduler.h"
|
||||||
|
#include "syscalls.h"
|
||||||
|
#include "process.h"
|
||||||
|
#include "utility.h"
|
||||||
|
#include "initfs.h"
|
||||||
|
#include "paging.h"
|
||||||
|
#include "panic.h"
|
||||||
|
#include "heap.h"
|
||||||
|
#include "ps2.h"
|
||||||
|
|
||||||
#include <limine.h>
|
#include <limine.h>
|
||||||
#include <paging.h>
|
|
||||||
#include <panic.h>
|
|
||||||
#include <ps2.h>
|
|
||||||
|
|
||||||
LIMINE_BASE_REVISION(3)
|
LIMINE_BASE_REVISION(3)
|
||||||
|
|
||||||
|
|
@ -145,10 +151,9 @@ static uint64_t initfs_length;
|
||||||
|
|
||||||
//we round up to a multiple of a page.
|
//we round up to a multiple of a page.
|
||||||
uint64_t fb_length = ((fb->height * fb->pitch - 1) / 4096 + 1) * 4096;
|
uint64_t fb_length = ((fb->height * fb->pitch - 1) / 4096 + 1) * 4096;
|
||||||
|
fb_physical_base = (uint64_t)fb->address - hhdm_request.response->offset;
|
||||||
fb_base = find_free_kernel_region(fb_length);
|
fb_base = find_free_kernel_region(fb_length);
|
||||||
map_kernel_region(
|
map_kernel_region(fb_physical_base, fb_base, fb_length, 1, 0);
|
||||||
(uint64_t)fb->address - hhdm_request.response->offset,
|
|
||||||
fb_base, fb_length, 1, 0);
|
|
||||||
|
|
||||||
//store rest of framebuffer information
|
//store rest of framebuffer information
|
||||||
|
|
||||||
|
|
@ -187,9 +192,35 @@ static uint64_t initfs_length;
|
||||||
set_irq_handler(0x0c, &on_mouse_irq);
|
set_irq_handler(0x0c, &on_mouse_irq);
|
||||||
enable_interrupts();
|
enable_interrupts();
|
||||||
|
|
||||||
//halt repeatedly
|
//set up syscalls
|
||||||
|
|
||||||
while (1)
|
init_syscalls();
|
||||||
__asm__ ("hlt");
|
register_syscall(SYSCALL_END_THREAD, (void *)&syscall_end_thread);
|
||||||
|
register_syscall(SYSCALL_MAP_FRAMEBUFFER, (void *)&syscall_map_framebuffer);
|
||||||
|
|
||||||
|
//load hello and start it
|
||||||
|
|
||||||
|
init_scheduler();
|
||||||
|
|
||||||
|
const uint8_t *hello_start;
|
||||||
|
uint64_t hello_length;
|
||||||
|
look_up_initfs_file("apps/hello.elf", &hello_start, &hello_length);
|
||||||
|
|
||||||
|
struct process *hello = heap_alloc(sizeof(struct process));
|
||||||
|
uint64_t hello_entry;
|
||||||
|
create_process(hello);
|
||||||
|
load_elf(hello, &hello_entry, hello_start, hello_length);
|
||||||
|
|
||||||
|
struct thread *hello_thread = heap_alloc(sizeof(struct thread));
|
||||||
|
create_thread(hello, hello_thread);
|
||||||
|
|
||||||
|
create_user_task(
|
||||||
|
hello->p4_physical_base,
|
||||||
|
hello_entry,
|
||||||
|
(uint64_t)hello_thread->stack_top);
|
||||||
|
|
||||||
|
running_thread = hello_thread;
|
||||||
|
|
||||||
|
resume_next_continuation();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,22 +1,23 @@
|
||||||
/* Calcite, kernel/src/framebuffer.c
|
/* Calcite, src/kernel/framebuffer.c
|
||||||
* Copyright 2025 Benji Dial
|
* Copyright 2025 Benji Dial
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or (at
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
* more details.
|
* for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <framebuffer.h>
|
#include "framebuffer.h"
|
||||||
|
|
||||||
|
uint64_t fb_physical_base;
|
||||||
uint8_t *fb_base;
|
uint8_t *fb_base;
|
||||||
int fb_width;
|
int fb_width;
|
||||||
int fb_height;
|
int fb_height;
|
||||||
|
|
@ -1,22 +1,25 @@
|
||||||
/* Calcite, kernel/include/framebuffer.h
|
/* Calcite, src/kernel/framebuffer.h
|
||||||
* Copyright 2025 Benji Dial
|
* Copyright 2025 Benji Dial
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or (at
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
* more details.
|
* for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
extern uint64_t fb_physical_base;
|
||||||
extern uint8_t *fb_base;
|
extern uint8_t *fb_base;
|
||||||
extern int fb_width;
|
extern int fb_width;
|
||||||
extern int fb_height;
|
extern int fb_height;
|
||||||
104
src/kernel/heap.c
Normal file
104
src/kernel/heap.c
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
/* Calcite, src/kernel/heap.c
|
||||||
|
* Copyright 2025 Benji Dial
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "paging.h"
|
||||||
|
#include "heap.h"
|
||||||
|
|
||||||
|
struct dealloc_record {
|
||||||
|
//0 for unused
|
||||||
|
uint64_t length;
|
||||||
|
void *start;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dealloc_record_page {
|
||||||
|
struct dealloc_record records[255];
|
||||||
|
struct dealloc_record_page *prev_page;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dealloc_record_page *last_page;
|
||||||
|
|
||||||
|
static void *map_pages(uint64_t page_count) {
|
||||||
|
|
||||||
|
void *vma = find_free_kernel_region(page_count * 4096);
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i < page_count; ++i) {
|
||||||
|
uint64_t pma = take_free_physical_page();
|
||||||
|
map_in_kernel_page_table(pma, vma + i * 4096, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return vma;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct dealloc_record *get_unused_record() {
|
||||||
|
|
||||||
|
for (struct dealloc_record_page *page = last_page;
|
||||||
|
page != 0; page = page->prev_page)
|
||||||
|
for (int i = 0; i < 255; ++i)
|
||||||
|
if (page->records[i].length == 0)
|
||||||
|
return &page->records[i];
|
||||||
|
|
||||||
|
struct dealloc_record_page *page = map_pages(1);
|
||||||
|
page->prev_page = last_page;
|
||||||
|
last_page = page;
|
||||||
|
|
||||||
|
page->records[0].start = (void *)page + 4096 - 8;
|
||||||
|
page->records[0].length = 8;
|
||||||
|
|
||||||
|
for (int i = 2; i < 255; ++i)
|
||||||
|
page->records[i].length = 0;
|
||||||
|
|
||||||
|
return &page->records[1];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void *heap_alloc(uint64_t length) {
|
||||||
|
|
||||||
|
for (struct dealloc_record_page *page = last_page;
|
||||||
|
page != 0; page = page->prev_page)
|
||||||
|
for (int i = 0; i < 255; ++i)
|
||||||
|
if (page->records[i].length == length) {
|
||||||
|
page->records[i].length = 0;
|
||||||
|
return page->records[i].start;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (struct dealloc_record_page *page = last_page;
|
||||||
|
page != 0; page = page->prev_page)
|
||||||
|
for (int i = 0; i < 255; ++i)
|
||||||
|
if (page->records[i].length > length) {
|
||||||
|
page->records[i].length -= length;
|
||||||
|
return page->records[i].start + page->records[i].length;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t pages = (length - 1) / 4096 + 1;
|
||||||
|
void *vma = map_pages(pages);
|
||||||
|
|
||||||
|
if (pages * 4096 != length) {
|
||||||
|
struct dealloc_record *record = get_unused_record();
|
||||||
|
record->start = vma + length;
|
||||||
|
record->length = pages * 4096 - length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return vma;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void heap_dealloc(void *start, uint64_t length) {
|
||||||
|
struct dealloc_record *record = get_unused_record();
|
||||||
|
record->start = start;
|
||||||
|
record->length = length;
|
||||||
|
}
|
||||||
23
src/kernel/heap.h
Normal file
23
src/kernel/heap.h
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
/* Calcite, src/kernel/heap.h
|
||||||
|
* Copyright 2025 Benji Dial
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void *heap_alloc(uint64_t length);
|
||||||
|
void heap_dealloc(void *start, uint64_t length);
|
||||||
|
|
@ -1,21 +1,21 @@
|
||||||
/* Calcite, kernel/src/initfs.c
|
/* Calcite, src/kernel/initfs.c
|
||||||
* Copyright 2025 Benji Dial
|
* Copyright 2025 Benji Dial
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or (at
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
* more details.
|
* for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <initfs.h>
|
#include "initfs.h"
|
||||||
|
|
||||||
static const uint8_t *initfs_start;
|
static const uint8_t *initfs_start;
|
||||||
static uint64_t initfs_length;
|
static uint64_t initfs_length;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
/* Calcite, kernel/include/initfs.h
|
/* Calcite, src/kernel/initfs.h
|
||||||
* Copyright 2025 Benji Dial
|
* Copyright 2025 Benji Dial
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
; Calcite, kernel/src/interrupts.asm
|
; Calcite, src/kernel/interrupts.asm
|
||||||
; Copyright 2025 Benji Dial
|
; Copyright 2025 Benji Dial
|
||||||
;
|
;
|
||||||
; This program is free software: you can redistribute it and/or modify
|
; This program is free software: you can redistribute it and/or modify
|
||||||
; it under the terms of the GNU General Public License as published by
|
; it under the terms of the GNU General Public License as published by
|
||||||
; the Free Software Foundation, either version 3 of the License, or (at
|
; the Free Software Foundation, either version 3 of the License, or
|
||||||
; your option) any later version.
|
; (at your option) any later version.
|
||||||
;
|
;
|
||||||
; This program is distributed in the hope that it will be useful, but
|
; This program is distributed in the hope that it will be useful, but
|
||||||
; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
; more details.
|
; for more details.
|
||||||
;
|
;
|
||||||
; You should have received a copy of the GNU General Public License along with
|
; You should have received a copy of the GNU General Public License along
|
||||||
; this program. If not, see <https://www.gnu.org/licenses/>.
|
; with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
bits 64
|
bits 64
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
/* Calcite, kernel/src/interrupts.c
|
/* Calcite, src/kernel/interrupts.c
|
||||||
* Copyright 2025 Benji Dial
|
* Copyright 2025 Benji Dial
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
|
@ -21,8 +21,8 @@
|
||||||
// https://osdev.wiki/wiki/Interrupt_Descriptor_Table
|
// https://osdev.wiki/wiki/Interrupt_Descriptor_Table
|
||||||
// https://osdev.wiki/wiki/Task_State_Segment
|
// https://osdev.wiki/wiki/Task_State_Segment
|
||||||
|
|
||||||
#include <interrupts.h>
|
#include "interrupts.h"
|
||||||
#include <panic.h>
|
#include "panic.h"
|
||||||
|
|
||||||
struct [[gnu::packed]] exception_parameter {
|
struct [[gnu::packed]] exception_parameter {
|
||||||
uint64_t r15;
|
uint64_t r15;
|
||||||
|
|
@ -212,6 +212,18 @@ void enable_interrupts() {
|
||||||
tss_entry->base_24 = (tss_base >> 24) & 0xff;
|
tss_entry->base_24 = (tss_base >> 24) & 0xff;
|
||||||
tss_entry->base_32 = tss_base >> 32;
|
tss_entry->base_32 = tss_base >> 32;
|
||||||
|
|
||||||
|
struct gdt_entry *user_data_entry = &the_gdt[3];
|
||||||
|
user_data_entry->access_byte =
|
||||||
|
GDT_AB_CODE_DATA_ACCESSED | GDT_AB_DATA_WRITABLE |
|
||||||
|
GDT_AB_TYPE_DATA | GDT_AB_DPL_THREE | GDT_AB_PRESENT;
|
||||||
|
user_data_entry->flags = GDT_FLAG_LONG;
|
||||||
|
|
||||||
|
struct gdt_entry *user_code_entry = &the_gdt[4];
|
||||||
|
user_code_entry->access_byte =
|
||||||
|
GDT_AB_CODE_DATA_ACCESSED | GDT_AB_TYPE_CODE |
|
||||||
|
GDT_AB_DPL_THREE | GDT_AB_PRESENT;
|
||||||
|
user_code_entry->flags = GDT_FLAG_LONG;
|
||||||
|
|
||||||
struct gdt_entry *kernel_code_entry = &the_gdt[5];
|
struct gdt_entry *kernel_code_entry = &the_gdt[5];
|
||||||
kernel_code_entry->access_byte =
|
kernel_code_entry->access_byte =
|
||||||
GDT_AB_CODE_DATA_ACCESSED | GDT_AB_TYPE_CODE |
|
GDT_AB_CODE_DATA_ACCESSED | GDT_AB_TYPE_CODE |
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
/* Calcite, kernel/include/interrupts.h
|
/* Calcite, src/kernel/interrupts.h
|
||||||
* Copyright 2025 Benji Dial
|
* Copyright 2025 Benji Dial
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
; Calcite, kernel/src/paging.asm
|
; Calcite, src/kernel/paging.asm
|
||||||
; Copyright 2025 Benji Dial
|
; Copyright 2025 Benji Dial
|
||||||
;
|
;
|
||||||
; This program is free software: you can redistribute it and/or modify
|
; This program is free software: you can redistribute it and/or modify
|
||||||
; it under the terms of the GNU General Public License as published by
|
; it under the terms of the GNU General Public License as published by
|
||||||
; the Free Software Foundation, either version 3 of the License, or (at
|
; the Free Software Foundation, either version 3 of the License, or
|
||||||
; your option) any later version.
|
; (at your option) any later version.
|
||||||
;
|
;
|
||||||
; This program is distributed in the hope that it will be useful, but
|
; This program is distributed in the hope that it will be useful, but
|
||||||
; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
; more details.
|
; for more details.
|
||||||
;
|
;
|
||||||
; You should have received a copy of the GNU General Public License along with
|
; You should have received a copy of the GNU General Public License along
|
||||||
; this program. If not, see <https://www.gnu.org/licenses/>.
|
; with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
bits 64
|
bits 64
|
||||||
|
|
@ -25,6 +25,12 @@ init_stack_length equ 16384
|
||||||
|
|
||||||
section .text
|
section .text
|
||||||
|
|
||||||
|
;referenced in paging.c
|
||||||
|
extern invlpg
|
||||||
|
invlpg:
|
||||||
|
invlpg byte [rdi]
|
||||||
|
ret
|
||||||
|
|
||||||
extern switch_to_kernel_page_tables
|
extern switch_to_kernel_page_tables
|
||||||
switch_to_kernel_page_tables:
|
switch_to_kernel_page_tables:
|
||||||
|
|
||||||
|
|
@ -1,22 +1,22 @@
|
||||||
/* Calcite, kernel/src/paging.c
|
/* Calcite, src/kernel/paging.c
|
||||||
* Copyright 2025 Benji Dial
|
* Copyright 2025 Benji Dial
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or (at
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
* more details.
|
* for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <paging.h>
|
#include "paging.h"
|
||||||
#include <panic.h>
|
#include "panic.h"
|
||||||
|
|
||||||
#define MAX_PHYSICAL_GB 64ULL
|
#define MAX_PHYSICAL_GB 64ULL
|
||||||
|
|
||||||
|
|
@ -38,6 +38,8 @@ static uint8_t physical_map[MAX_PHYSICAL_GB << 15];
|
||||||
//referenced from paging.asm
|
//referenced from paging.asm
|
||||||
uint64_t kernel_p4_physical_address;
|
uint64_t kernel_p4_physical_address;
|
||||||
|
|
||||||
|
uint64_t kernel_p3_physical_address;
|
||||||
|
|
||||||
alignas(4096) static uint64_t kernel_p4[512];
|
alignas(4096) static uint64_t kernel_p4[512];
|
||||||
alignas(4096) static uint64_t kernel_p3[512];
|
alignas(4096) static uint64_t kernel_p3[512];
|
||||||
alignas(4096) static uint64_t kernel_p2[512];
|
alignas(4096) static uint64_t kernel_p2[512];
|
||||||
|
|
@ -55,6 +57,7 @@ void init_paging(uint64_t kernel_physical_base, void *kernel_virtual_base) {
|
||||||
(uint64_t)kernel_virtual_base - kernel_physical_base;
|
(uint64_t)kernel_virtual_base - kernel_physical_base;
|
||||||
|
|
||||||
kernel_p4_physical_address = (uint64_t)kernel_p4 - kernel_load_offset;
|
kernel_p4_physical_address = (uint64_t)kernel_p4 - kernel_load_offset;
|
||||||
|
kernel_p3_physical_address = (uint64_t)kernel_p3 - kernel_load_offset;
|
||||||
|
|
||||||
kernel_p4[511] = ((uint64_t)kernel_p3 - kernel_load_offset) | 0x3;
|
kernel_p4[511] = ((uint64_t)kernel_p3 - kernel_load_offset) | 0x3;
|
||||||
for (int i = 0; i < 511; ++i)
|
for (int i = 0; i < 511; ++i)
|
||||||
|
|
@ -98,6 +101,9 @@ void mark_physical_memory_free(uint64_t base, uint64_t length) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//defined in paging.asm
|
||||||
|
void invlpg(void *address);
|
||||||
|
|
||||||
void map_in_kernel_page_table(
|
void map_in_kernel_page_table(
|
||||||
uint64_t physical_base, void *virtual_base,
|
uint64_t physical_base, void *virtual_base,
|
||||||
int writable, int executable) {
|
int writable, int executable) {
|
||||||
|
|
@ -112,6 +118,39 @@ void map_in_kernel_page_table(
|
||||||
physical_base | (writable ? 0x3 : 0x1) |
|
physical_base | (writable ? 0x3 : 0x1) |
|
||||||
(executable ? 0 : 0x8000000000000000);
|
(executable ? 0 : 0x8000000000000000);
|
||||||
|
|
||||||
|
invlpg(virtual_base);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void unmap_kernel_page(void *virtual_base) {
|
||||||
|
|
||||||
|
uint64_t virtual_base_u64 = (uint64_t)virtual_base;
|
||||||
|
assert(virtual_base_u64 >= 0xffffffffc0000000);
|
||||||
|
|
||||||
|
uint64_t p1s_index = (virtual_base_u64 - 0xffffffffc0000000) >> 12;
|
||||||
|
assert(kernel_p1s[p1s_index] != 0);
|
||||||
|
|
||||||
|
kernel_p1s[p1s_index] = 0;
|
||||||
|
|
||||||
|
invlpg(virtual_base);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void unmap_and_free_kernel_page(void *virtual_base) {
|
||||||
|
|
||||||
|
uint64_t virtual_base_u64 = (uint64_t)virtual_base;
|
||||||
|
assert(virtual_base_u64 >= 0xffffffffc0000000);
|
||||||
|
|
||||||
|
uint64_t p1s_index = (virtual_base_u64 - 0xffffffffc0000000) >> 12;
|
||||||
|
assert(kernel_p1s[p1s_index] != 0);
|
||||||
|
|
||||||
|
uint64_t pma = kernel_p1s[p1s_index] & 0x7ffffffffffff000;
|
||||||
|
mark_physical_memory_free(pma, 4096);
|
||||||
|
|
||||||
|
kernel_p1s[p1s_index] = 0;
|
||||||
|
|
||||||
|
invlpg(virtual_base);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *find_free_kernel_region(uint64_t length) {
|
void *find_free_kernel_region(uint64_t length) {
|
||||||
|
|
@ -127,9 +166,7 @@ void *find_free_kernel_region(uint64_t length) {
|
||||||
if (run_length == length)
|
if (run_length == length)
|
||||||
return (void *)(run_start * 4096 + 0xffffffffc0000000);
|
return (void *)(run_start * 4096 + 0xffffffffc0000000);
|
||||||
if (next == 512 * 512)
|
if (next == 512 * 512)
|
||||||
//die. TODO: handle this nicer.
|
panic("out of kernel virtual memory");
|
||||||
while (1)
|
|
||||||
__asm__ ("hlt");
|
|
||||||
if (kernel_p1s[next] == 0)
|
if (kernel_p1s[next] == 0)
|
||||||
++run_length;
|
++run_length;
|
||||||
else {
|
else {
|
||||||
|
|
@ -140,3 +177,13 @@ void *find_free_kernel_region(uint64_t length) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t take_free_physical_page() {
|
||||||
|
for (uint64_t i = 0; i < (MAX_PHYSICAL_GB << 15); ++i)
|
||||||
|
for (int j = 0; j < 8; ++j)
|
||||||
|
if (physical_map[i] & (1 << j)) {
|
||||||
|
physical_map[i] &= ~(1 << j);
|
||||||
|
return (i << 15) + (j << 12);
|
||||||
|
}
|
||||||
|
panic("out of physical memory");
|
||||||
|
}
|
||||||
|
|
@ -1,24 +1,26 @@
|
||||||
/* Calcite, kernel/include/paging.h
|
/* Calcite, src/kernel/paging.h
|
||||||
* Copyright 2025 Benji Dial
|
* Copyright 2025 Benji Dial
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or (at
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
* more details.
|
* for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
extern uint64_t kernel_p3_physical_address;
|
||||||
|
|
||||||
//kernel physical and virtual bases are passed so that we can compute the
|
//kernel physical and virtual bases are passed so that we can compute the
|
||||||
//physical addresses of the kernel's statically allocated paging structures.
|
//physical addresses of the kernel's statically allocated paging structures.
|
||||||
void init_paging(uint64_t kernel_physical_base, void *kernel_virtual_base);
|
void init_paging(uint64_t kernel_physical_base, void *kernel_virtual_base);
|
||||||
|
|
@ -31,9 +33,18 @@ void mark_physical_memory_free(uint64_t base, uint64_t length);
|
||||||
void map_in_kernel_page_table(
|
void map_in_kernel_page_table(
|
||||||
uint64_t physical_base, void *virtual_base, int writable, int executable);
|
uint64_t physical_base, void *virtual_base, int writable, int executable);
|
||||||
|
|
||||||
|
//unmaps one page. base should be page-aligned and within kernel range.
|
||||||
|
void unmap_kernel_page(void *virtual_base);
|
||||||
|
|
||||||
|
//unmaps one page, and frees the corresponding physical page.
|
||||||
|
//base should be page-aligned and within kernel range.
|
||||||
|
void unmap_and_free_kernel_page(void *virtual_base);
|
||||||
|
|
||||||
//returns a region of contiguous pages in kernel virtual memory where nothing
|
//returns a region of contiguous pages in kernel virtual memory where nothing
|
||||||
//is mapped. length should be page-aligned.
|
//is mapped. length should be page-aligned.
|
||||||
void *find_free_kernel_region(uint64_t length);
|
void *find_free_kernel_region(uint64_t length);
|
||||||
|
|
||||||
|
uint64_t take_free_physical_page();
|
||||||
|
|
||||||
//implemented in paging.asm. the continuation should be noreturn.
|
//implemented in paging.asm. the continuation should be noreturn.
|
||||||
[[noreturn]] void switch_to_kernel_page_tables(void (*continuation)());
|
[[noreturn]] void switch_to_kernel_page_tables(void (*continuation)());
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
/* Calcite, kernel/src/panic.c
|
/* Calcite, src/kernel/panic.c
|
||||||
* Copyright 2025 Benji Dial
|
* Copyright 2025 Benji Dial
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
/* Calcite, kernel/include/panic.h
|
/* Calcite, src/kernel/panic.h
|
||||||
* Copyright 2025 Benji Dial
|
* Copyright 2025 Benji Dial
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
|
@ -15,6 +15,8 @@
|
||||||
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
[[noreturn]] void panic_core(
|
[[noreturn]] void panic_core(
|
||||||
const char *file, const char *function, int line, const char *message);
|
const char *file, const char *function, int line, const char *message);
|
||||||
|
|
||||||
357
src/kernel/process.c
Normal file
357
src/kernel/process.c
Normal file
|
|
@ -0,0 +1,357 @@
|
||||||
|
/* Calcite, src/kernel/process.c
|
||||||
|
* Copyright 2025 Benji Dial
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "framebuffer.h"
|
||||||
|
#include "scheduler.h"
|
||||||
|
#include "process.h"
|
||||||
|
#include "utility.h"
|
||||||
|
#include "paging.h"
|
||||||
|
#include "panic.h"
|
||||||
|
#include "heap.h"
|
||||||
|
|
||||||
|
void create_process(struct process *process_out) {
|
||||||
|
|
||||||
|
process_out->p4_physical_base = take_free_physical_page();
|
||||||
|
process_out->p4_virtual_base = find_free_kernel_region(4096);
|
||||||
|
map_in_kernel_page_table(
|
||||||
|
process_out->p4_physical_base, process_out->p4_virtual_base, 1, 0);
|
||||||
|
|
||||||
|
process_out->p3_physical_base = take_free_physical_page();
|
||||||
|
process_out->p3_virtual_base = find_free_kernel_region(4096);
|
||||||
|
map_in_kernel_page_table(
|
||||||
|
process_out->p3_physical_base, process_out->p3_virtual_base, 1, 0);
|
||||||
|
|
||||||
|
process_out->p4_virtual_base[0] = process_out->p3_physical_base | 0x7;
|
||||||
|
process_out->p4_virtual_base[511] = kernel_p3_physical_address | 0x3;
|
||||||
|
for (int i = 1; i < 511; ++i)
|
||||||
|
process_out->p4_virtual_base[i] = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 512; ++i) {
|
||||||
|
process_out->p3_virtual_base[i] = 0;
|
||||||
|
process_out->p2_virtual_bases[i] = 0;
|
||||||
|
process_out->p1_virtual_bases[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
process_out->n_threads = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void map_page_for_process(
|
||||||
|
struct process *process, uint64_t physical_base,
|
||||||
|
void *virtual_base, int writable, int executable) {
|
||||||
|
|
||||||
|
assert(physical_base % 4096 == 0)
|
||||||
|
|
||||||
|
uint64_t vma = (uint64_t)virtual_base;
|
||||||
|
assert(vma % 4096 == 0)
|
||||||
|
assert(vma != 0)
|
||||||
|
assert(vma < 0x0000008000000000)
|
||||||
|
|
||||||
|
int p1i = (vma >> 12) & 0x1ff;
|
||||||
|
int p2i = (vma >> 21) & 0x1ff;
|
||||||
|
int p3i = (vma >> 30) & 0x1ff;
|
||||||
|
|
||||||
|
if (process->p3_virtual_base[p3i] == 0) {
|
||||||
|
uint64_t p2_pma = take_free_physical_page();
|
||||||
|
uint64_t *p2_vma = find_free_kernel_region(4096);
|
||||||
|
map_in_kernel_page_table(p2_pma, p2_vma, 1, 0);
|
||||||
|
process->p3_virtual_base[p3i] = p2_pma | 0x7;
|
||||||
|
process->p2_virtual_bases[p3i] = p2_vma;
|
||||||
|
process->p1_virtual_bases[p3i] = heap_alloc(4096);
|
||||||
|
for (int i = 0; i < 512; ++i) {
|
||||||
|
p2_vma[i] = 0;
|
||||||
|
process->p1_virtual_bases[p3i][i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process->p2_virtual_bases[p3i][p2i] == 0) {
|
||||||
|
uint64_t p1_pma = take_free_physical_page();
|
||||||
|
uint64_t *p1_vma = find_free_kernel_region(4096);
|
||||||
|
map_in_kernel_page_table(p1_pma, p1_vma, 1, 0);
|
||||||
|
process->p2_virtual_bases[p3i][p2i] = p1_pma | 0x7;
|
||||||
|
process->p1_virtual_bases[p3i][p2i] = p1_vma;
|
||||||
|
for (int i = 0; i < 512; ++i)
|
||||||
|
p1_vma[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(process->p1_virtual_bases[p3i][p2i][p1i] == 0)
|
||||||
|
|
||||||
|
process->p1_virtual_bases[p3i][p2i][p1i] =
|
||||||
|
physical_base | 0x5 | (writable ? 0x2 : 0x0) |
|
||||||
|
(executable ? 0 : 0x8000000000000000);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void unmap_page_for_process(
|
||||||
|
struct process *process, void *virtual_base) {
|
||||||
|
|
||||||
|
uint64_t vma = (uint64_t)virtual_base;
|
||||||
|
assert(vma % 4096 == 0)
|
||||||
|
assert(vma != 0)
|
||||||
|
assert(vma < 0x0000008000000000)
|
||||||
|
|
||||||
|
int p1i = (vma >> 12) & 0x1ff;
|
||||||
|
int p2i = (vma >> 21) & 0x1ff;
|
||||||
|
int p3i = (vma >> 30) & 0x1ff;
|
||||||
|
|
||||||
|
assert(
|
||||||
|
process->p1_virtual_bases[p3i] &&
|
||||||
|
process->p1_virtual_bases[p3i][p2i] &&
|
||||||
|
process->p1_virtual_bases[p3i][p2i][p1i])
|
||||||
|
|
||||||
|
process->p1_virtual_bases[p3i][p2i][p1i] = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_mapped_writable(struct process *process, void *start, uint64_t length) {
|
||||||
|
|
||||||
|
uint64_t vma_start = (uint64_t)start;
|
||||||
|
uint64_t vma_end = vma_start + length;
|
||||||
|
vma_start = (vma_start / 4096) * 4096;
|
||||||
|
vma_end = ((vma_end - 1) / 4096 + 1) * 4096;
|
||||||
|
|
||||||
|
for (uint64_t vma = vma_start; vma < vma_end; vma += 4096) {
|
||||||
|
|
||||||
|
if (vma == 0 || vma >= 0x0000008000000000)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int p1i = (vma >> 12) & 0x1ff;
|
||||||
|
int p2i = (vma >> 21) & 0x1ff;
|
||||||
|
int p3i = (vma >> 30) & 0x1ff;
|
||||||
|
|
||||||
|
if (!process->p1_virtual_bases[p3i] ||
|
||||||
|
!process->p1_virtual_bases[p3i][p2i] ||
|
||||||
|
!process->p1_virtual_bases[p3i][p2i][p1i] ||
|
||||||
|
!(process->p1_virtual_bases[p3i][p2i][p1i] & 0x2))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void *find_free_process_region(
|
||||||
|
struct process *process, uint64_t page_count) {
|
||||||
|
|
||||||
|
uint64_t start = 512 * 512 * 4096;
|
||||||
|
uint64_t length = 0;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
|
||||||
|
if (length >= page_count * 4096)
|
||||||
|
break;
|
||||||
|
|
||||||
|
uint64_t vma = start + length;
|
||||||
|
if (vma >= 0x0000008000000000)
|
||||||
|
goto no_mem;
|
||||||
|
|
||||||
|
int p1i = (vma >> 12) & 0x1ff;
|
||||||
|
int p2i = (vma >> 21) & 0x1ff;
|
||||||
|
int p3i = (vma >> 30) & 0x1ff;
|
||||||
|
|
||||||
|
if (p2i == 0 && p1i == 0 && process->p2_virtual_bases[p3i] == 0) {
|
||||||
|
length += 512 * 512 * 4096;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p1i == 0 && process->p1_virtual_bases[p3i][p2i] == 0) {
|
||||||
|
length += 512 * 4096;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process->p1_virtual_bases[p3i][p2i][p1i] == 0) {
|
||||||
|
length += 4096;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
start = start + length + 4096;
|
||||||
|
length = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return (void *)start;
|
||||||
|
|
||||||
|
no_mem:
|
||||||
|
panic("process out of virtual memory")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_elf(
|
||||||
|
struct process *process, uint64_t *entry_out,
|
||||||
|
const void *elf_start, uint64_t elf_length) {
|
||||||
|
|
||||||
|
if (elf_length < 58)
|
||||||
|
panic("malformed elf")
|
||||||
|
|
||||||
|
*entry_out = *(uint64_t *)(elf_start + 24);
|
||||||
|
|
||||||
|
uint64_t phead_start = *(uint64_t *)(elf_start + 32);
|
||||||
|
uint16_t phead_entry_size = *(uint16_t *)(elf_start + 54);
|
||||||
|
uint16_t phead_entry_count = *(uint16_t *)(elf_start + 56);
|
||||||
|
|
||||||
|
if (elf_length < phead_start + phead_entry_count * phead_entry_size)
|
||||||
|
panic("malformed elf")
|
||||||
|
|
||||||
|
for (uint16_t i = 0; i < phead_entry_count; ++i) {
|
||||||
|
|
||||||
|
uint64_t *entry =
|
||||||
|
(uint64_t *)(elf_start + phead_start + i * phead_entry_size);
|
||||||
|
|
||||||
|
if ((entry[0] & 0xffffffff) != 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int executable = (entry[0] >> 32) & 0x1;
|
||||||
|
int writable = (entry[0] >> 33) & 0x1;
|
||||||
|
|
||||||
|
uint64_t file_start = entry[1];
|
||||||
|
void *virtual_start = (void *)entry[2];
|
||||||
|
uint64_t file_length = entry[4];
|
||||||
|
uint64_t virtual_length = ((entry[5] - 1) / 4096 + 1) * 4096;
|
||||||
|
|
||||||
|
if (elf_length < file_start + file_length)
|
||||||
|
panic("malformed elf")
|
||||||
|
if (file_length > virtual_length)
|
||||||
|
panic("malformed elf")
|
||||||
|
|
||||||
|
if ((uint64_t)virtual_start % 4096 != 0 || virtual_length % 4096 != 0)
|
||||||
|
panic("unaligned elf")
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i < virtual_length; i += 4096) {
|
||||||
|
|
||||||
|
uint64_t pma = take_free_physical_page();
|
||||||
|
map_page_for_process(
|
||||||
|
process, pma, virtual_start + i, writable, executable);
|
||||||
|
|
||||||
|
void *kvma = find_free_kernel_region(4096);
|
||||||
|
map_in_kernel_page_table(pma, kvma, 1, 0);
|
||||||
|
|
||||||
|
if (i + 4096 <= file_length)
|
||||||
|
memcpy(kvma, elf_start + file_start + i, 4096);
|
||||||
|
else if (i >= file_length)
|
||||||
|
memzero(kvma, 4096);
|
||||||
|
else {
|
||||||
|
memcpy(kvma, elf_start + file_start + i, file_length & 0xfff);
|
||||||
|
memzero(kvma + (file_length & 0xfff), 4096 - (file_length & 0xfff));
|
||||||
|
}
|
||||||
|
|
||||||
|
unmap_kernel_page(kvma);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_process(struct process *process) {
|
||||||
|
for (int p3i = 0; p3i < 512; ++p3i)
|
||||||
|
if (process->p3_virtual_base[p3i]) {
|
||||||
|
for (int p2i = 0; p2i < 512; ++p2i)
|
||||||
|
if (process->p2_virtual_bases[p3i][p2i]) {
|
||||||
|
for (int p1i = 0; p1i < 512; ++p1i)
|
||||||
|
mark_physical_memory_free(
|
||||||
|
process->p1_virtual_bases[p3i][p2i][p1i] & 0x7ffffffffffff000,
|
||||||
|
4096);
|
||||||
|
unmap_and_free_kernel_page(process->p1_virtual_bases[p3i][p2i]);
|
||||||
|
}
|
||||||
|
unmap_and_free_kernel_page(process->p2_virtual_bases[p3i]);
|
||||||
|
heap_dealloc(process->p1_virtual_bases[p3i], 4096);
|
||||||
|
}
|
||||||
|
unmap_and_free_kernel_page(process->p3_virtual_base);
|
||||||
|
unmap_and_free_kernel_page(process->p4_virtual_base);
|
||||||
|
heap_dealloc(process, sizeof(struct process));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define INITIAL_STACK_SIZE (16 << 20)
|
||||||
|
|
||||||
|
void create_thread(struct process *process, struct thread *thread_out) {
|
||||||
|
|
||||||
|
//TODO: allocate stack as needed on page faults, have guard pages, etc.
|
||||||
|
|
||||||
|
void *stack_bottom_vma =
|
||||||
|
find_free_process_region(process, INITIAL_STACK_SIZE / 4096);
|
||||||
|
|
||||||
|
for (int i = 0; i < INITIAL_STACK_SIZE / 4096; ++i) {
|
||||||
|
|
||||||
|
uint64_t pma = take_free_physical_page();
|
||||||
|
map_page_for_process(process, pma, stack_bottom_vma + i * 4096, 1, 0);
|
||||||
|
|
||||||
|
void *kvma = find_free_kernel_region(4096);
|
||||||
|
map_in_kernel_page_table(pma, kvma, 1, 0);
|
||||||
|
memzero(kvma, 4096);
|
||||||
|
unmap_kernel_page(kvma);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_out->process = process;
|
||||||
|
thread_out->stack_bottom = stack_bottom_vma;
|
||||||
|
thread_out->stack_top = stack_bottom_vma + INITIAL_STACK_SIZE;
|
||||||
|
|
||||||
|
++process->n_threads;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct thread *running_thread = 0;
|
||||||
|
|
||||||
|
[[noreturn]] void syscall_end_thread() {
|
||||||
|
|
||||||
|
assert(running_thread != 0)
|
||||||
|
assert(running_thread->process->n_threads >= 1)
|
||||||
|
|
||||||
|
if (running_thread->process->n_threads == 1)
|
||||||
|
destroy_process(running_thread->process);
|
||||||
|
|
||||||
|
else {
|
||||||
|
|
||||||
|
--running_thread->process->n_threads;
|
||||||
|
|
||||||
|
for (void *p = running_thread->stack_bottom;
|
||||||
|
p < running_thread->stack_top; p += 4096)
|
||||||
|
unmap_page_for_process(running_thread->process, p);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
heap_dealloc(running_thread, sizeof(struct thread));
|
||||||
|
|
||||||
|
running_thread = 0;
|
||||||
|
resume_next_continuation();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void syscall_map_framebuffer(struct syscall_framebuffer_info *info_out) {
|
||||||
|
|
||||||
|
if (!is_mapped_writable(
|
||||||
|
running_thread->process, info_out,
|
||||||
|
sizeof(struct syscall_framebuffer_info)))
|
||||||
|
panic("bad syscall");
|
||||||
|
|
||||||
|
uint64_t pages_needed = (fb_pitch * fb_height - 1) / 4096 + 1;
|
||||||
|
|
||||||
|
void *base = find_free_process_region(running_thread->process, pages_needed);
|
||||||
|
|
||||||
|
for (uint64_t i = 0; i < pages_needed; ++i)
|
||||||
|
map_page_for_process(
|
||||||
|
running_thread->process,
|
||||||
|
fb_physical_base + i * 4096,
|
||||||
|
base + i * 4096, 1, 0);
|
||||||
|
|
||||||
|
info_out->fb_base = base;
|
||||||
|
info_out->fb_pitch = fb_pitch;
|
||||||
|
info_out->fb_height = fb_height;
|
||||||
|
info_out->fb_width = fb_width;
|
||||||
|
|
||||||
|
}
|
||||||
88
src/kernel/process.h
Normal file
88
src/kernel/process.h
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
/* Calcite, src/kernel/process.h
|
||||||
|
* Copyright 2025 Benji Dial
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct process {
|
||||||
|
|
||||||
|
uint64_t p4_physical_base;
|
||||||
|
uint64_t *p4_virtual_base;
|
||||||
|
uint64_t p3_physical_base;
|
||||||
|
uint64_t *p3_virtual_base;
|
||||||
|
|
||||||
|
int n_threads;
|
||||||
|
|
||||||
|
//0 for missing levels. just bottom p3 of address space.
|
||||||
|
uint64_t *p2_virtual_bases[512];
|
||||||
|
uint64_t **p1_virtual_bases[512];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct thread {
|
||||||
|
|
||||||
|
struct process *process;
|
||||||
|
|
||||||
|
//both page-aligned
|
||||||
|
void *stack_bottom;
|
||||||
|
void *stack_top;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct thread *running_thread;
|
||||||
|
|
||||||
|
void create_process(struct process *process_out);
|
||||||
|
void create_thread(struct process *process, struct thread *thread_out);
|
||||||
|
|
||||||
|
//physical and virtual bases must be page-aligned.
|
||||||
|
//virtual base must be in bottom p3 and not zero.
|
||||||
|
void map_page_for_process(
|
||||||
|
struct process *process, uint64_t physical_base,
|
||||||
|
void *virtual_base, int writable, int executable);
|
||||||
|
|
||||||
|
//virtual base must be page-aligned, in bottom p3, and not zero.
|
||||||
|
void unmap_page_for_process(
|
||||||
|
struct process *process, void *virtual_base);
|
||||||
|
|
||||||
|
//finds a free memory region in the bottom p3
|
||||||
|
//of the address space, and not the bottom p2.
|
||||||
|
void *find_free_process_region(
|
||||||
|
struct process *process, uint64_t page_count);
|
||||||
|
|
||||||
|
//loaded sections are copied to new pages. once storage drivers are written,
|
||||||
|
//this should probably just take a file handle so it can load and parse the
|
||||||
|
//header and then load sections directly into user pages.
|
||||||
|
void load_elf(
|
||||||
|
struct process *process, uint64_t *entry_out,
|
||||||
|
const void *elf_start, uint64_t elf_length);
|
||||||
|
|
||||||
|
void destroy_process(struct process *process);
|
||||||
|
|
||||||
|
//returs 1 if [start, start + length) is writable by process, otherwise 0.
|
||||||
|
int is_mapped_writable(struct process *process, void *start, uint64_t length);
|
||||||
|
|
||||||
|
[[noreturn]] void syscall_end_thread();
|
||||||
|
|
||||||
|
struct syscall_framebuffer_info {
|
||||||
|
uint8_t *fb_base;
|
||||||
|
int fb_width;
|
||||||
|
int fb_height;
|
||||||
|
int fb_pitch;
|
||||||
|
};
|
||||||
|
|
||||||
|
void syscall_map_framebuffer(struct syscall_framebuffer_info *info_out);
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
; Calcite, kernel/src/ps2.asm
|
; Calcite, src/kernel/ps2.asm
|
||||||
; Copyright 2025 Benji Dial
|
; Copyright 2025 Benji Dial
|
||||||
;
|
;
|
||||||
; This program is free software: you can redistribute it and/or modify
|
; This program is free software: you can redistribute it and/or modify
|
||||||
; it under the terms of the GNU General Public License as published by
|
; it under the terms of the GNU General Public License as published by
|
||||||
; the Free Software Foundation, either version 3 of the License, or (at
|
; the Free Software Foundation, either version 3 of the License, or
|
||||||
; your option) any later version.
|
; (at your option) any later version.
|
||||||
;
|
;
|
||||||
; This program is distributed in the hope that it will be useful, but
|
; This program is distributed in the hope that it will be useful, but
|
||||||
; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
; more details.
|
; for more details.
|
||||||
;
|
;
|
||||||
; You should have received a copy of the GNU General Public License along with
|
; You should have received a copy of the GNU General Public License along
|
||||||
; this program. If not, see <https://www.gnu.org/licenses/>.
|
; with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
bits 64
|
bits 64
|
||||||
|
|
@ -1,23 +1,23 @@
|
||||||
/* Calcite, kernel/src/ps2.c
|
/* Calcite, src/kernel/ps2.c
|
||||||
* Copyright 2025 Benji Dial
|
* Copyright 2025 Benji Dial
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or (at
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
* more details.
|
* for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <framebuffer.h>
|
#include "framebuffer.h"
|
||||||
#include <panic.h>
|
#include "panic.h"
|
||||||
#include <ps2.h>
|
#include "ps2.h"
|
||||||
|
|
||||||
//defined in ps2.asm
|
//defined in ps2.asm
|
||||||
//returns -1 if no byte available
|
//returns -1 if no byte available
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
/* Calcite, kernel/include/ps2.h
|
/* Calcite, src/kernel/ps2.h
|
||||||
* Copyright 2025 Benji Dial
|
* Copyright 2025 Benji Dial
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
57
src/kernel/scheduler.asm
Normal file
57
src/kernel/scheduler.asm
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
; Calcite, src/kernel/scheduler.c
|
||||||
|
; Copyright 2025 Benji Dial
|
||||||
|
;
|
||||||
|
; This program is free software: you can redistribute it and/or modify
|
||||||
|
; it under the terms of the GNU General Public License as published by
|
||||||
|
; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
; (at your option) any later version.
|
||||||
|
;
|
||||||
|
; This program is distributed in the hope that it will be useful, but
|
||||||
|
; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
; for more details.
|
||||||
|
;
|
||||||
|
; You should have received a copy of the GNU General Public License along
|
||||||
|
; with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
bits 64
|
||||||
|
|
||||||
|
;referenced in scheduler.c
|
||||||
|
global user_task_start
|
||||||
|
user_task_start:
|
||||||
|
|
||||||
|
mov cr3, rbx
|
||||||
|
mov rcx, rbp
|
||||||
|
mov r11, 0x200
|
||||||
|
|
||||||
|
xor rax, rax
|
||||||
|
xor rbx, rbx
|
||||||
|
xor rdx, rdx
|
||||||
|
xor rdi, rdi
|
||||||
|
xor rsi, rsi
|
||||||
|
xor rbp, rbp
|
||||||
|
xor r8, r8
|
||||||
|
xor r9, r9
|
||||||
|
xor r10, r10
|
||||||
|
xor r12, r12
|
||||||
|
xor r13, r13
|
||||||
|
xor r14, r14
|
||||||
|
xor r15, r15
|
||||||
|
|
||||||
|
o64 sysret
|
||||||
|
|
||||||
|
;referenced in scheduler.c
|
||||||
|
global resume_continuation
|
||||||
|
resume_continuation:
|
||||||
|
|
||||||
|
mov rax, qword [rdi]
|
||||||
|
mov rbx, qword [rdi + 8]
|
||||||
|
mov rbp, qword [rdi + 16]
|
||||||
|
mov rsp, qword [rdi + 24]
|
||||||
|
mov r12, qword [rdi + 32]
|
||||||
|
mov r13, qword [rdi + 40]
|
||||||
|
mov r14, qword [rdi + 48]
|
||||||
|
mov r15, qword [rdi + 56]
|
||||||
|
|
||||||
|
jmp rax
|
||||||
118
src/kernel/scheduler.c
Normal file
118
src/kernel/scheduler.c
Normal file
|
|
@ -0,0 +1,118 @@
|
||||||
|
/* Calcite, src/kernel/scheduler.c
|
||||||
|
* Copyright 2025 Benji Dial
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "scheduler.h"
|
||||||
|
#include "utility.h"
|
||||||
|
#include "heap.h"
|
||||||
|
|
||||||
|
struct continuation_info {
|
||||||
|
uint64_t rip;
|
||||||
|
uint64_t rbx;
|
||||||
|
uint64_t rbp;
|
||||||
|
uint64_t rsp;
|
||||||
|
uint64_t r12;
|
||||||
|
uint64_t r13;
|
||||||
|
uint64_t r14;
|
||||||
|
uint64_t r15;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct continuation_info **ready_continuations = 0;
|
||||||
|
static int rc_buffer_length = 0;
|
||||||
|
static int rc_read_ptr = 0;
|
||||||
|
static int rc_count = 0;
|
||||||
|
|
||||||
|
#define INITIAL_RC_BUFFER_LENGTH 128
|
||||||
|
|
||||||
|
void init_scheduler() {
|
||||||
|
ready_continuations = heap_alloc(INITIAL_RC_BUFFER_LENGTH * sizeof(void *));
|
||||||
|
rc_buffer_length = INITIAL_RC_BUFFER_LENGTH;
|
||||||
|
for (int i = 0; i < INITIAL_RC_BUFFER_LENGTH; ++i)
|
||||||
|
ready_continuations[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void queue_continuation(struct continuation_info *info) {
|
||||||
|
|
||||||
|
if (rc_count == rc_buffer_length) {
|
||||||
|
|
||||||
|
struct continuation_info **new_rc_buffer =
|
||||||
|
heap_alloc(2 * rc_buffer_length * sizeof(void *));
|
||||||
|
|
||||||
|
memcpy(
|
||||||
|
new_rc_buffer,
|
||||||
|
ready_continuations + rc_read_ptr,
|
||||||
|
(rc_buffer_length - rc_read_ptr) * sizeof(void *));
|
||||||
|
|
||||||
|
memcpy(
|
||||||
|
new_rc_buffer + rc_buffer_length - rc_read_ptr,
|
||||||
|
ready_continuations,
|
||||||
|
rc_read_ptr * sizeof(void *));
|
||||||
|
|
||||||
|
heap_dealloc(ready_continuations, rc_buffer_length * sizeof(void *));
|
||||||
|
|
||||||
|
new_rc_buffer[rc_buffer_length] = info;
|
||||||
|
for (int i = rc_buffer_length + 1; i < 2 * rc_buffer_length; ++i)
|
||||||
|
new_rc_buffer[i] = 0;
|
||||||
|
|
||||||
|
ready_continuations = new_rc_buffer;
|
||||||
|
rc_buffer_length *= 2;
|
||||||
|
rc_read_ptr = 0;
|
||||||
|
++rc_count;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
ready_continuations[(rc_read_ptr + rc_count) % rc_buffer_length] = info;
|
||||||
|
++rc_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//defined in scheduler.asm
|
||||||
|
void user_task_start();
|
||||||
|
|
||||||
|
void create_user_task(
|
||||||
|
uint64_t cr3, uint64_t rip, uint64_t rsp) {
|
||||||
|
|
||||||
|
struct continuation_info *info =
|
||||||
|
heap_alloc(sizeof(struct continuation_info));
|
||||||
|
|
||||||
|
info->rip = (uint64_t)&user_task_start;
|
||||||
|
info->rsp = (uint64_t)rsp;
|
||||||
|
info->rbx = cr3;
|
||||||
|
info->rbp = rip;
|
||||||
|
|
||||||
|
queue_continuation(info);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//defined in scheduler.asm
|
||||||
|
[[noreturn]] void resume_continuation(struct continuation_info *info);
|
||||||
|
|
||||||
|
[[noreturn]] void resume_next_continuation() {
|
||||||
|
|
||||||
|
while (rc_count == 0)
|
||||||
|
__asm__ ("hlt");
|
||||||
|
|
||||||
|
struct continuation_info *info = ready_continuations[rc_read_ptr];
|
||||||
|
|
||||||
|
ready_continuations[rc_read_ptr] = 0;
|
||||||
|
rc_read_ptr = (rc_read_ptr + 1) % rc_buffer_length;
|
||||||
|
--rc_count;
|
||||||
|
|
||||||
|
resume_continuation(info);
|
||||||
|
|
||||||
|
}
|
||||||
27
src/kernel/scheduler.h
Normal file
27
src/kernel/scheduler.h
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
/* Calcite, src/kernel/scheduler.h
|
||||||
|
* Copyright 2025 Benji Dial
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void init_scheduler();
|
||||||
|
|
||||||
|
void create_user_task(
|
||||||
|
uint64_t cr3, uint64_t rip, uint64_t rsp);
|
||||||
|
|
||||||
|
[[noreturn]] void resume_next_continuation();
|
||||||
71
src/kernel/syscalls.asm
Normal file
71
src/kernel/syscalls.asm
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
; Calcite, src/kernel/syscalls.asm
|
||||||
|
; Copyright 2025 Benji Dial
|
||||||
|
;
|
||||||
|
; This program is free software: you can redistribute it and/or modify
|
||||||
|
; it under the terms of the GNU General Public License as published by
|
||||||
|
; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
; (at your option) any later version.
|
||||||
|
;
|
||||||
|
; This program is distributed in the hope that it will be useful, but
|
||||||
|
; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
; for more details.
|
||||||
|
;
|
||||||
|
; You should have received a copy of the GNU General Public License along
|
||||||
|
; with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
bits 64
|
||||||
|
|
||||||
|
extern syscall_entry_c
|
||||||
|
|
||||||
|
section .bss
|
||||||
|
|
||||||
|
;this should have guard pages blah blah blah
|
||||||
|
resb 16 << 20
|
||||||
|
syscall_stack_top:
|
||||||
|
|
||||||
|
section .text
|
||||||
|
|
||||||
|
;system call number is in rax.
|
||||||
|
;system call arguments are in rdi, rsi, rdx.
|
||||||
|
;system call returns a value in rax.
|
||||||
|
syscall_entry:
|
||||||
|
mov qword [syscall_stack_top - 8], rsp
|
||||||
|
mov rsp, syscall_stack_top - 8
|
||||||
|
push r11
|
||||||
|
push rcx
|
||||||
|
|
||||||
|
mov rcx, rax
|
||||||
|
call syscall_entry_c
|
||||||
|
|
||||||
|
pop rcx
|
||||||
|
pop r11
|
||||||
|
pop rsp
|
||||||
|
o64 sysret
|
||||||
|
|
||||||
|
global init_syscalls
|
||||||
|
init_syscalls:
|
||||||
|
|
||||||
|
mov ecx, 0xc0000080
|
||||||
|
rdmsr
|
||||||
|
or al, 0x01
|
||||||
|
wrmsr
|
||||||
|
|
||||||
|
mov edx, 0x00130028
|
||||||
|
xor eax, eax
|
||||||
|
mov ecx, 0xc0000081
|
||||||
|
wrmsr
|
||||||
|
|
||||||
|
mov rdx, syscall_entry
|
||||||
|
mov eax, edx
|
||||||
|
shr rdx, 32
|
||||||
|
mov ecx, 0xc0000082
|
||||||
|
wrmsr
|
||||||
|
|
||||||
|
xor edx, edx
|
||||||
|
xor eax, eax
|
||||||
|
mov ecx, 0xc0000084
|
||||||
|
wrmsr
|
||||||
|
|
||||||
|
ret
|
||||||
46
src/kernel/syscalls.c
Normal file
46
src/kernel/syscalls.c
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
/* Calcite, src/kernel/syscalls.c
|
||||||
|
* Copyright 2025 Benji Dial
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "syscalls.h"
|
||||||
|
#include "panic.h"
|
||||||
|
|
||||||
|
#define MAX_SYSCALL_NUMBER 99
|
||||||
|
|
||||||
|
static uint64_t (*syscall_handlers[MAX_SYSCALL_NUMBER])(
|
||||||
|
uint64_t, uint64_t, uint64_t);
|
||||||
|
|
||||||
|
void register_syscall(
|
||||||
|
int number,
|
||||||
|
uint64_t (*handler)(uint64_t, uint64_t, uint64_t)) {
|
||||||
|
|
||||||
|
assert(number >= 0 && number <= MAX_SYSCALL_NUMBER)
|
||||||
|
assert(syscall_handlers[number] == 0)
|
||||||
|
|
||||||
|
syscall_handlers[number] = handler;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//referenced in syscalls.asm
|
||||||
|
uint64_t syscall_entry_c(
|
||||||
|
uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t number) {
|
||||||
|
|
||||||
|
if (number > MAX_SYSCALL_NUMBER || syscall_handlers[number] == 0)
|
||||||
|
panic("TODO: bad syscall");
|
||||||
|
|
||||||
|
return (*syscall_handlers[number])(arg1, arg2, arg3);
|
||||||
|
|
||||||
|
}
|
||||||
27
src/kernel/syscalls.h
Normal file
27
src/kernel/syscalls.h
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
/* Calcite, src/kernel/syscalls.h
|
||||||
|
* Copyright 2025 Benji Dial
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel-public/syscall-numbers.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void init_syscalls();
|
||||||
|
|
||||||
|
void register_syscall(
|
||||||
|
int number,
|
||||||
|
uint64_t (*handler)(uint64_t arg1, uint64_t arg2, uint64_t arg3));
|
||||||
33
src/kernel/utility.asm
Normal file
33
src/kernel/utility.asm
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
; Calcite, src/kernel/utility.asm
|
||||||
|
; Copyright 2025 Benji Dial
|
||||||
|
;
|
||||||
|
; This program is free software: you can redistribute it and/or modify
|
||||||
|
; it under the terms of the GNU General Public License as published by
|
||||||
|
; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
; (at your option) any later version.
|
||||||
|
;
|
||||||
|
; This program is distributed in the hope that it will be useful, but
|
||||||
|
; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
; for more details.
|
||||||
|
;
|
||||||
|
; You should have received a copy of the GNU General Public License along
|
||||||
|
; with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
bits 64
|
||||||
|
|
||||||
|
section .text
|
||||||
|
|
||||||
|
;global memcpy
|
||||||
|
;memcpy:
|
||||||
|
; mov rcx, rdx
|
||||||
|
; rep movsb
|
||||||
|
; ret
|
||||||
|
|
||||||
|
;global memzero
|
||||||
|
;memzero:
|
||||||
|
; xor al, al
|
||||||
|
; mov rcx, rsi
|
||||||
|
; rep stosb
|
||||||
|
; ret
|
||||||
|
|
@ -1,21 +1,21 @@
|
||||||
/* Calcite, kernel/src/utility.c
|
/* Calcite, src/kernel/utility.c
|
||||||
* Copyright 2025 Benji Dial
|
* Copyright 2025 Benji Dial
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or (at
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
* more details.
|
* for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <utility.h>
|
#include "utility.h"
|
||||||
|
|
||||||
int strequ(const char *str1, const char *str2) {
|
int strequ(const char *str1, const char *str2) {
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
@ -27,3 +27,13 @@ int strequ(const char *str1, const char *str2) {
|
||||||
++str2;
|
++str2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void memcpy(void *to, const void *from, uint64_t bytes) {
|
||||||
|
for (uint64_t i = 0; i < bytes; ++i)
|
||||||
|
*(uint8_t *)(to + i) = *(const uint8_t *)(from + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void memzero(void *start, uint64_t bytes) {
|
||||||
|
for (uint64_t i = 0; i < bytes; ++i)
|
||||||
|
*(uint8_t *)(start + i) = 0;
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
/* Calcite, kernel/include/utility.h
|
/* Calcite, src/kernel/utility.h
|
||||||
* Copyright 2025 Benji Dial
|
* Copyright 2025 Benji Dial
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
|
@ -17,5 +17,10 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
//returns 1 if equal, 0 if not.
|
//returns 1 if equal, 0 if not.
|
||||||
int strequ(const char *str1, const char *str2);
|
int strequ(const char *str1, const char *str2);
|
||||||
|
|
||||||
|
void memcpy(void *to, const void *from, uint64_t bytes);
|
||||||
|
void memzero(void *start, uint64_t bytes);
|
||||||
35
src/user-apps/hello/hello.c
Normal file
35
src/user-apps/hello/hello.c
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
/* Calcite, src/user-apps/hello/hello.c
|
||||||
|
* Copyright 2025 Benji Dial
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <calcite/calcite.h>
|
||||||
|
|
||||||
|
[[noreturn]]
|
||||||
|
void _start() {
|
||||||
|
|
||||||
|
struct framebuffer_info fb_info;
|
||||||
|
map_framebuffer(&fb_info);
|
||||||
|
|
||||||
|
for (int y = 0; y < fb_info.fb_height; ++y)
|
||||||
|
for (int x = 0; x < fb_info.fb_width; ++x) {
|
||||||
|
uint8_t *pixel = fb_info.fb_base + y * fb_info.fb_pitch + x * 4;
|
||||||
|
pixel[0] = x * 256 / fb_info.fb_width;
|
||||||
|
pixel[1] = y * 256 / fb_info.fb_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
end_thread();
|
||||||
|
|
||||||
|
}
|
||||||
1
src/user-apps/hello/libraries.txt
Normal file
1
src/user-apps/hello/libraries.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
calcite
|
||||||
27
src/user-libs/calcite/syscalls.asm
Normal file
27
src/user-libs/calcite/syscalls.asm
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
; Calcite, src/user-libs/calcite/syscalls.asm
|
||||||
|
; Copyright 2025 Benji Dial
|
||||||
|
;
|
||||||
|
; This program is free software: you can redistribute it and/or modify
|
||||||
|
; it under the terms of the GNU General Public License as published by
|
||||||
|
; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
; (at your option) any later version.
|
||||||
|
;
|
||||||
|
; This program is distributed in the hope that it will be useful, but
|
||||||
|
; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
; for more details.
|
||||||
|
;
|
||||||
|
; You should have received a copy of the GNU General Public License along
|
||||||
|
; with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
bits 64
|
||||||
|
|
||||||
|
section .text
|
||||||
|
|
||||||
|
;referenced in syscalls.c
|
||||||
|
global do_syscall
|
||||||
|
do_syscall:
|
||||||
|
mov rax, rcx
|
||||||
|
syscall
|
||||||
|
ret
|
||||||
32
src/user-libs/calcite/syscalls.c
Normal file
32
src/user-libs/calcite/syscalls.c
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
/* Calcite, src/user-libs/calcite/syscalls.c
|
||||||
|
* Copyright 2025 Benji Dial
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <kernel-public/syscall-numbers.h>
|
||||||
|
#include <calcite/calcite.h>
|
||||||
|
|
||||||
|
//defined in syscalls.asm
|
||||||
|
uint64_t do_syscall
|
||||||
|
(uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t number);
|
||||||
|
|
||||||
|
[[noreturn]] void end_thread() {
|
||||||
|
do_syscall(0, 0, 0, SYSCALL_END_THREAD);
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void map_framebuffer(struct framebuffer_info *info_out) {
|
||||||
|
do_syscall((uint64_t)info_out, 0, 0, SYSCALL_MAP_FRAMEBUFFER);
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue