rename src/kernel/panic to src/kernel/debug, add serial logging

This commit is contained in:
Benji Dial 2026-01-01 00:05:11 -05:00
parent 527498a491
commit a69dbc3c7a
20 changed files with 344 additions and 34 deletions

View file

@ -4,3 +4,5 @@
dependencies/limine dependencies/limine
-I -I
include include
-D
CALCITE_DEBUG

View file

@ -3,23 +3,23 @@
COMMON_CC_EXTRA_FLAGS="-Wall -Wextra" COMMON_CC_EXTRA_FLAGS="-Wall -Wextra"
COMMON_LD_EXTRA_FLAGS="" COMMON_LD_EXTRA_FLAGS=""
COMMON_CC_FLAGS="-std=c23 -ffreestanding -I include ${COMMON_CC_EXTRA_FLAGS}"
COMMON_LD_FLAGS="${COMMON_LD_EXTRA_FLAGS}"
if [ "$1" = debug ]; then if [ "$1" = debug ]; then
COMMON_CC_EXTRA_FLAGS="-O0 -ggdb ${COMMON_CC_EXTRA_FLAGS}" COMMON_CC_FLAGS="-O0 -ggdb -D CALCITE_DEBUG ${COMMON_CC_FLAGS}"
elif [ "$1" = release ]; then elif [ "$1" = release ]; then
COMMON_CC_EXTRA_FLAGS="-O3 ${COMMON_CC_EXTRA_FLAGS}" COMMON_CC_FLAGS="-O3 -D CALCITE_RELEASE ${COMMON_CC_FLAGS}"
COMMON_LD_EXTRA_FLAGS="-s ${COMMON_LD_EXTRA_FLAGS}" COMMON_LD_FLAGS="-s ${COMMON_LD_FLAGS}"
else else
echo pass either "debug" or "release" as an argument. echo pass either "debug" or "release" as an argument.
exit exit
fi fi
COMMON_CC_FLAGS="-std=c23 -ffreestanding -I include ${COMMON_CC_EXTRA_FLAGS}"
KERNEL_CC_FLAGS="-mno-sse -I dependencies/limine ${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 #in the future user code will be allowed to use sse
USER_CC_FLAGS="-mno-sse ${COMMON_CC_FLAGS}" USER_CC_FLAGS="-mno-sse ${COMMON_CC_FLAGS}"
COMMON_LD_FLAGS="${COMMON_LD_EXTRA_FLAGS}"
if [ -e build.ninja ]; then if [ -e build.ninja ]; then
echo build.ninja already exists. echo build.ninja already exists.
exit exit

109
src/kernel/debug.c Normal file
View file

@ -0,0 +1,109 @@
/* Calcite, src/kernel/debug.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 "serial.h"
#include "debug.h"
#include <stdarg.h>
void log_core(const char *file, const char *function, const char *format, ...) {
int file_length = 0;
while (file[file_length] != 0)
++file_length;
int function_length = 0;
while (function[function_length] != 0)
++function_length;
write_serial_string_n(file, file_length);
write_serial_string_n(" ", 1);
write_serial_string_n(function, function_length);
write_serial_string_n(" -", 2);
for (int i = file_length + function_length + 3; i < 49; ++i)
write_serial_string_n("-", 1);
write_serial_string_n(" ", 1);
va_list args;
va_start(args, format);
while (1) {
int next_percent = 0;
while (format[next_percent] != '%') {
if (format[next_percent] == 0) {
write_serial_string_n(format, next_percent);
va_end(args);
write_serial_string_n("\r\n", 2);
return;
}
++next_percent;
}
write_serial_string_n(format, next_percent);
switch (format[next_percent + 1]) {
case 's': {
const char *arg = va_arg(args, const char *);
write_serial_string(arg);
break;
}
case 'd': {
int arg = va_arg(args, int);
write_serial_integer(arg);
break;
}
case 'h': {
uint64_t arg1 = va_arg(args, uint64_t);
int arg2 = va_arg(args, int);
write_serial_hex(arg1, arg2);
break;
}
case 'B': {
uint64_t arg = va_arg(args, uint64_t);
if (arg < 10000) {
write_serial_integer(arg);
write_serial_string_n(" B", 2);
}
else if ((arg + 512) / 1024 < 10000) {
write_serial_integer((arg + 512) / 1024);
write_serial_string_n(" kiB", 4);
}
else if ((arg + 512 * 1024) / (1024 * 1024) < 10000) {
write_serial_integer((arg + 512 * 1024) / (1024 * 1024));
write_serial_string_n(" MiB", 4);
}
else if ((arg + 512 * 1024 * 1024) / (1024 * 1024 * 1024) < 10000) {
write_serial_integer((arg + 512 * 1024 * 1024) / (1024 * 1024 * 1024));
write_serial_string_n(" GiB", 4);
}
else {
write_serial_integer((arg + 512 * 1024 * 1024 * 1024ULL) / (1024 * 1024 * 1024 * 1024ULL));
write_serial_string_n(" TiB", 4);
}
break;
}
default:
panic("bad format string")
}
format = &format[next_percent + 2];
}
}

View file

@ -1,4 +1,4 @@
/* Calcite, src/kernel/panic.h /* Calcite, src/kernel/debug.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,10 +17,23 @@
#pragma once #pragma once
[[noreturn]] void panic_core( void log_core(const char *file, const char *function, const char *format, ...);
const char *file, const char *function, int line, const char *message);
#define panic(message) panic_core(__FILE__, __func__, __LINE__, message); #ifdef CALCITE_DEBUG
#define debug_log(...) { \
log_core(__FILE__, __func__, __VA_ARGS__); \
}
#elif CALCITE_RELEASE
#define debug_log(format, ...) {}
#else
#error neither CALCITE_DEBUG nor CALCITE_RELEASE defined
#endif
#define panic(message) { \
log_core(__FILE__, __func__, "kernel panic: %s", message); \
while (1) \
__asm__ ("hlt"); \
}
#define assert(condition) \ #define assert(condition) \
{ \ { \

View file

@ -23,8 +23,9 @@
#include "utility.h" #include "utility.h"
#include "drives.h" #include "drives.h"
#include "paging.h" #include "paging.h"
#include "serial.h"
#include "debug.h"
#include "input.h" #include "input.h"
#include "panic.h"
#include "timer.h" #include "timer.h"
#include "heap.h" #include "heap.h"
#include "pci.h" #include "pci.h"
@ -187,6 +188,8 @@ static const char *cmdline_look_up(const char *key) {
[[noreturn]] static void with_kernel_page_tables() { [[noreturn]] static void with_kernel_page_tables() {
init_serial();
//store cmdline as key-value pairs //store cmdline as key-value pairs
if (cmdline_copy[0] == 0) if (cmdline_copy[0] == 0)
@ -242,6 +245,10 @@ static const char *cmdline_look_up(const char *key) {
} }
debug_log("command line:")
for (int i = 0; i < cmdline_pair_count; ++i)
debug_log(" %s = %s", cmdline_pairs[i].key, cmdline_pairs[i].value)
//set up interrupts //set up interrupts
init_timer(); init_timer();
@ -302,6 +309,10 @@ static const char *cmdline_look_up(const char *key) {
if (start_elf("root://calcite/apps/init/init.elf") == 0) if (start_elf("root://calcite/apps/init/init.elf") == 0)
panic("could not start init.elf") panic("could not start init.elf")
debug_log("about to switch to init")
debug_log(" free physical memory %B", count_free_pram())
debug_log(" free kernel virtual memory %B", count_free_kernel_vram())
resume_next_continuation(); resume_next_continuation();
} }

View file

@ -17,7 +17,7 @@
#include "iso9660.h" #include "iso9660.h"
#include "utility.h" #include "utility.h"
#include "panic.h" #include "debug.h"
#include "heap.h" #include "heap.h"
#include "fs.h" #include "fs.h"

View file

@ -17,8 +17,8 @@
#include "scheduler.h" #include "scheduler.h"
#include "process.h" #include "process.h"
#include "debug.h"
#include "input.h" #include "input.h"
#include "panic.h"
static int is_somebody_waiting_for_mouse_packet = 0; static int is_somebody_waiting_for_mouse_packet = 0;
static struct continuation_info waiting_continuation; static struct continuation_info waiting_continuation;

View file

@ -22,7 +22,7 @@
// https://osdev.wiki/wiki/Task_State_Segment // https://osdev.wiki/wiki/Task_State_Segment
#include "interrupts.h" #include "interrupts.h"
#include "panic.h" #include "debug.h"
struct [[gnu::packed]] exception_parameter { struct [[gnu::packed]] exception_parameter {
uint64_t r15; uint64_t r15;

View file

@ -18,7 +18,7 @@
#include "ipc-dgram.h" #include "ipc-dgram.h"
#include "scheduler.h" #include "scheduler.h"
#include "utility.h" #include "utility.h"
#include "panic.h" #include "debug.h"
#include "heap.h" #include "heap.h"
#include <kernel-public/ipc.h> #include <kernel-public/ipc.h>

View file

@ -16,9 +16,10 @@
*/ */
#include "iso9660.h" #include "iso9660.h"
#include "kernel-public/files.h"
#include "utility.h" #include "utility.h"
#include "drives.h" #include "drives.h"
#include "panic.h" #include "debug.h"
#include "heap.h" #include "heap.h"
#include "fs.h" #include "fs.h"
@ -370,6 +371,12 @@ enum fs_access_result create_iso9660_info(const struct drive_info *drive, struct
fs_out->look_up_file = &look_up_file_iso9660; fs_out->look_up_file = &look_up_file_iso9660;
fs_out->stat_file = &stat_file_iso9660; fs_out->stat_file = &stat_file_iso9660;
fs_out->read_file = &read_file_iso9660; fs_out->read_file = &read_file_iso9660;
debug_log("created iso9660 file system")
debug_log(" drive name %s", drive->name)
debug_log(" path table start block %d", path_table_start)
debug_log(" path table block count %d", path_table_length_rounded_up / 2048)
return FAR_SUCCESS; return FAR_SUCCESS;
} }

View file

@ -16,7 +16,7 @@
*/ */
#include "paging.h" #include "paging.h"
#include "panic.h" #include "debug.h"
#define MAX_PHYSICAL_GB 64ULL #define MAX_PHYSICAL_GB 64ULL
@ -203,3 +203,20 @@ void destroy_syscall_stack(void *stack_top) {
for (uint64_t i = 0; i < SYSCALL_STACK_BYTES; i += 4096) for (uint64_t i = 0; i < SYSCALL_STACK_BYTES; i += 4096)
unmap_and_free_kernel_page(stack_top - SYSCALL_STACK_BYTES + i * 4096); unmap_and_free_kernel_page(stack_top - SYSCALL_STACK_BYTES + i * 4096);
} }
uint64_t count_free_pram() {
uint64_t total = 0;
for (uint64_t i = 0; i < (MAX_PHYSICAL_GB << 15); ++i)
for (int j = 0; j < 8; ++j)
if (physical_map[i] & (1 << j))
total += 4096;
return total;
}
uint64_t count_free_kernel_vram() {
uint64_t total = 0;
for (uint64_t i = 0; i < 512 * 512; ++i)
if (kernel_p1s[i] == 0)
total += 4096;
return total;
}

View file

@ -52,3 +52,9 @@ uint64_t take_free_physical_page();
//returns the top //returns the top
void *create_syscall_stack(); void *create_syscall_stack();
void destroy_syscall_stack(void *stack_top); void destroy_syscall_stack(void *stack_top);
//return value in bytes
uint64_t count_free_pram();
//return value in bytes
uint64_t count_free_kernel_vram();

View file

@ -15,12 +15,12 @@
* with this program. If not, see <https://www.gnu.org/licenses/>. * with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "pci.h"
#include "utility.h" #include "utility.h"
#include "drives.h" #include "drives.h"
#include "panic.h" #include "debug.h"
#include "heap.h" #include "heap.h"
#include "pata.h" #include "pata.h"
#include "pci.h"
//some relevant sources: //some relevant sources:
// https://www.isdaman.com/alsos/hardware/hdc/pciide.pdf // https://www.isdaman.com/alsos/hardware/hdc/pciide.pdf
@ -211,6 +211,14 @@ static void probe_pata_drive(uint16_t command_block_base, uint8_t device_byte) {
di->read_blocks = &read_blocks_patapi; di->read_blocks = &read_blocks_patapi;
debug_log("added pata drive:")
debug_log(" drive name %s", di->name)
debug_log(" command block base 0x%h", command_block_base, 4)
debug_log(" device byte 0x%h", device_byte, 2)
debug_log(" block size %d", di->block_size)
debug_log(" block count %d", di->block_count)
debug_log(" total size %B", di->block_count * di->block_size)
} }
void probe_pata_drives(uint32_t pci_address_base, uint32_t pci_class_etc) { void probe_pata_drives(uint32_t pci_address_base, uint32_t pci_class_etc) {

View file

@ -15,6 +15,7 @@
* with this program. If not, see <https://www.gnu.org/licenses/>. * with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "debug.h"
#include "pata.h" #include "pata.h"
#include "pci.h" #include "pci.h"
@ -40,6 +41,7 @@ static void probe_bus(uint32_t bus_address_base) {
else if ((header_type & 0x7f) == 0x00) { else if ((header_type & 0x7f) == 0x00) {
//this is a normal function //this is a normal function
uint32_t class_etc = read_pci_config(function_address_base | 0x08); uint32_t class_etc = read_pci_config(function_address_base | 0x08);
debug_log("pci device with class %h:%h", class_etc >> 24, 2, class_etc >> 16, 2);
switch (class_etc & 0xffff0000) { switch (class_etc & 0xffff0000) {
case 0x01010000: case 0x01010000:
probe_pata_drives(function_address_base, class_etc); probe_pata_drives(function_address_base, class_etc);

View file

@ -21,7 +21,7 @@
#include "process.h" #include "process.h"
#include "utility.h" #include "utility.h"
#include "paging.h" #include "paging.h"
#include "panic.h" #include "debug.h"
#include "heap.h" #include "heap.h"
#include "fs.h" #include "fs.h"
@ -399,6 +399,12 @@ void syscall_create_thread(void (*f)(uint64_t), uint64_t x) {
add_to_queue(&ready_continuations, &ci); add_to_queue(&ready_continuations, &ci);
debug_log("started thread")
debug_log(" process struct at 0xffffffff.%h", thread->process, 8)
debug_log(" thread struct at 0xffffffff.%h", thread, 8)
debug_log(" free physical memory %B", count_free_pram())
debug_log(" free kernel virtual memory %B", count_free_kernel_vram())
} }
int syscall_start_elf(const char *path, const struct process_start_info *info) { int syscall_start_elf(const char *path, const struct process_start_info *info) {
@ -439,6 +445,12 @@ int syscall_start_elf(const char *path, const struct process_start_info *info) {
for (int i = 0; i < info->set_envvar_count; ++i) for (int i = 0; i < info->set_envvar_count; ++i)
set_envvar(process, info->set_envvars[2 * i], info->set_envvars[2 * i + 1]); set_envvar(process, info->set_envvars[2 * i], info->set_envvars[2 * i + 1]);
debug_log("started process")
debug_log(" path %s", path)
debug_log(" process struct at 0xffffffff.%h", process, 8)
debug_log(" free physical memory %B", count_free_pram())
debug_log(" free kernel virtual memory %B", count_free_kernel_vram())
return 1; return 1;
} }

View file

@ -18,7 +18,7 @@
#include "scheduler.h" #include "scheduler.h"
#include "process.h" #include "process.h"
#include "utility.h" #include "utility.h"
#include "panic.h" #include "debug.h"
#include "heap.h" #include "heap.h"
struct continuation_queue ready_continuations; struct continuation_queue ready_continuations;

73
src/kernel/serial.asm Normal file
View file

@ -0,0 +1,73 @@
; Calcite, src/kernel/serial.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
default rel
section .text
global init_serial
init_serial:
mov dx, 0x03f9
mov al, 0x00
out dx, al
mov dl, 0xfb
mov al, 0x80
out dx, al
mov dl, 0xf8
mov al, 0x03
out dx, al
mov dl, 0xf9
mov al, 0x00
out dx, al
mov dl, 0xfb
mov al, 0x03
out dx, al
mov dl, 0xfa
mov al, 0xc7
out dx, al
ret
global write_serial_string_n
write_serial_string_n:
test esi, esi
jz .ret
movzx rcx, esi
.wait_ready:
mov dx, 0x03fd
in al, dx
test al, 0x20
jnz .ready
pause
jmp .wait_ready
.ready:
mov dl, 0xf8
mov al, byte [rdi]
out dx, al
inc rdi
loop .wait_ready
.ret:
ret

54
src/kernel/serial.c Normal file
View file

@ -0,0 +1,54 @@
/* Calcite, src/kernel/serial.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 "serial.h"
#include "debug.h"
void write_serial_string(const char *string) {
int n = 0;
while (string[n] != 0)
++n;
write_serial_string_n(string, n);
}
void write_serial_integer(int integer) {
if (integer == 0) {
write_serial_string_n("0", 1);
return;
}
char buffer[10];
char *ptr = &buffer[9];
while (integer != 0) {
*ptr = '0' + integer % 10;
integer /= 10;
--ptr;
}
write_serial_string_n(ptr + 1, (buffer + 10) - (ptr + 1));
}
void write_serial_hex(uint64_t value, int places) {
assert(places <= 16)
char buffer[16];
for (int i = 0; i < places; ++i)
buffer[i] = "0123456789abcdef"[(value >> (4 * (places - i - 1))) & 0xf];
write_serial_string_n(buffer, places);
}

View file

@ -1,4 +1,4 @@
/* Calcite, src/kernel/panic.c /* Calcite, src/kernel/serial.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,16 +15,12 @@
* with this program. If not, see <https://www.gnu.org/licenses/>. * with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
[[noreturn]] void panic_core( #pragma once
const char *file, const char *function, int line, const char *message) {
//TODO #include <stdint.h>
(void)file; void init_serial();
(void)function; void write_serial_string(const char *string);
(void)line; void write_serial_string_n(const char *string, int n);
(void)message; void write_serial_integer(int integer);
while (1) void write_serial_hex(uint64_t value, int places);
__asm__ ("hlt");
}

View file

@ -16,7 +16,7 @@
*/ */
#include "syscalls.h" #include "syscalls.h"
#include "panic.h" #include "debug.h"
#define MAX_SYSCALL_NUMBER 99 #define MAX_SYSCALL_NUMBER 99