MAJOR RESTRUCTURE

This commit is contained in:
2024-12-28 21:23:58 +01:00
parent 12b07a9f70
commit 2e0b030324
81 changed files with 1168 additions and 579 deletions
+22 -16
View File
@@ -1,23 +1,29 @@
.DS_Store
# Don't ignore these
!.gitattributes
!.gitignore
# Config
make.config
# Binaries
bin/
*.bin
makedisk
# Object files
# Outputs
/bin
*.o
*.out
*.obj
*.d
*.a
*.exe
*.EFI
*.bin
*.bin.gz
*.tar*
*.elf
*.hdd
*.iso
*.sys
*.dtb
*~
# Font source files
src/fonts/**.asm
# Vim swap files
# Local
DS_Store
/.vscode
*.swp
*.swo
/.clangd
/.cache
+26
View File
@@ -0,0 +1,26 @@
kern.
=====
_Idk why i called it that it was 3am and i needed sleep._
About
-----
Kern is a 32-bit OS based on the x86 architecture written in NASM Assembly and C.
I'm working on a basic command line as well as a custom unix-esque filesystem.
It has a simple shell with some commands (use 'help' for a list of available ones).
Since there's always more to do, here are the TODO.
Features
--------
* Shell
* Filesystem
* Userspace
* Font support
* Graphics mode
* Physical memory manager
* Virtual memory manager
* System calls
Old Version: https://github.com/Tom-on64/old-kern
-64
View File
@@ -1,64 +0,0 @@
# kern.
---
Idk why i called it that it was 3am and i needed sleep
## About
Kern is a 32-bit OS based on the x86 architecture written in NASM Assembly and C.
I'm working on a basic command line as well as a custom unix-esque filesystem.
It has a simple shell with some commands. (Use 'help' for a list of available ones)
Since there's always more to do, here are the [todos](todo.txt).
### Features
- Filesystem
- Interactive Shell
- Disk I/O
- Font support (funky format)
- 1920x1080 Resolution, 32bpp
- Physical memory manager
- Virtual memory manager
- Syscalls
## Building & Running
If you want to try kern for some reason, you can.
### Tools
- [NASM](https://www.nasm.us/)
- [QEMU](https://www.qemu.org/) (for emulation)
**Unix Like Systems**
- [GCC](https://gcc.gnu.org/)
**On MacOS**
- A cross compiler: `$ brew tap nativeos/i386-elf-toolchain && brew install i386-elf-binutils i386-elf-gcc`
### Commands
```bash
$ make # Or 'make os'
$ make run # Run QEMU
```
_I personally wouldn't recommend running this on real hardware, because it's untested and will just probably break you pc, but if you really want to, you can try it, but don't blame me if something goes wrong._
## Some images
Interactive Shell: \
![Example shell output](docs/img/shell.png)
Filesystem: \
![Ls command output and some file reading](docs/img/filesystem.png)
Graphics test: \
![Some colorfull shapes :)](docs/img/graphics.png)
_These images may be outdated, Idk_
## Known issues
- fillCircle() in graphics.h is broken. No idea why, so no filled circles for you (i commented out the boundaryFill call in the function)
- convertColor() doesn't work right, because i should be using floating point, but -mgeneral-regs-only doesn't let me :(
- The soundtest command and sleep commands cause an unknown exception. Sleep() syscall issue
- Not really an issue, bit QEMU's PIT is really slow and inacurate
## [Old Version](https://github.com/Tom-on64/old-kern)
View File
+12
View File
@@ -0,0 +1,12 @@
#
# KBOOT Makefile
#
include make.defaults
$(BOOTSECT): $(BOOTSECT_SRC)
$(AS) -fbin $(BOOT_DIR)/bootsect.s -o $(BOOTSECT)
$(BOOTLOAD): $(BOOTLOAD_SRC)
@echo TODO
+405
View File
@@ -0,0 +1,405 @@
#include <syscalls/syscalls.h>
#include <memory/addresses.h>
#include <memory/physical.h>
#include <memory/virtual.h>
#include <memory/malloc.h>
#include <drivers/keyboard.h>
#include <drivers/serial.h>
#include <drivers/timer.h>
#include <drivers/pcspk.h>
#include <drivers/disk.h>
#include <drivers/rtc.h>
#include <screen/graphics.h>
#include <screen/gfxmode.h>
#include <screen/text.h>
#include <screen/tty.h>
#include <cpu/system.h>
#include <cpu/isr.h>
#include <fs/kernfs.h>
#include <fs/fs.h>
#include <sys/notes.h>
#include <sys/gfx.h>
#include <syscall.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
/* Little teaser
#include <math.h>
void mathTest() {
printf("|-4| = %d\n", abs(-4));
printf("|-3.14| = %f\n", fabs(-3.14));
printf("e^3 = %f\n", exp(3));
printf("e^5 = %f\n", exp2(5));
printf("ln(2) = %f\n", log(2));
printf("log2(69) = %f\n", log2(69));
printf("log10(100) = %f\n", log10(100));
printf("sqrt(2) = %f\n", sqrt(2));
printf("cbrt(27) = %f\n", cbrt(27));
printf("hyp(8, 6) = %f\n", hypot(8, 6));
printf("3^4 = %f\n", pow(3, 4));
}
*/
#define PROMPT "#>"
// FS things
char* cwd;
// Function declarations
void listFiles();
void printRegs();
void printPhysicalMemmap();
void initOpenFileTable();
__attribute__ ((section("entry")))
void main() {
// Retrieve global variables
currentPd = (pageDirectory_t*)*(uint32_t*)CURRENT_PAGE_DIR_ADDR; // Don't ask
memoryMap = (uint32_t*)MEMMAP_AREA;
maxBlocks = *(uint32_t*)PHYS_MEM_MAX_BLOCKS;
usedBlocks = *(uint32_t*)PHYS_MEM_USED_BLOCKS;
// Setup serial output for debugf()
if (setupSerial(PORT_COM1) != 0) { printf("\x1b[1MFailed to initialize serial interface\x1b[8M\n"); }
else {
debugf("\x1b[H\x1b[J"); // Clear
debugf("kern. \x1b[36m(Serial console)\x1b[0m\n\n");
}
// Interrupt setup
setupIsrs();
// Programmable Interval Timer
registerIrq(0, timerHandler);
setPitPhase(0, 2, 1000); // 1000Hz
// Real Time Clock
registerIrq(8, rtcHandler);
enableRtc();
// Keyboard
registerIrq(1, keyboardHandler);
// Setup kernel malloc variables
mallocNode_t* kernelMallocListHead = 0;
uint32_t kernelMallocVirtualAddr = KERNEL_MALLOC_AREA;
uint32_t kernelMallocPhysicalAddr = (uint32_t)allocBlocks(16); // TODO: Kernel may use more than 64kB?
uint32_t kernelMallocPages = 1;
mapPage((void*)kernelMallocPhysicalAddr, (void*)kernelMallocVirtualAddr);
ptEntry_t* kernelMallocPage = getPage(kernelMallocVirtualAddr);
SET_ATTR(kernelMallocPage, PTE_READ_WRITE);
kernelMallocListHead = (mallocNode_t*)kernelMallocVirtualAddr;
kernelMallocListHead->size = PAGE_SIZE - sizeof(mallocNode_t);
kernelMallocListHead->free = true;
kernelMallocListHead->next = NULL;
mallocListHead = kernelMallocListHead;
mallocVirtualAddr = kernelMallocVirtualAddr;
mallocPhysicalAddr = kernelMallocPhysicalAddr;
mallocPages = kernelMallocPages;
// FS Setup
initOpenFileTable();
cwd = malloc(1024);
strcpy(cwd, "/");
// Terminal setup
console->fg = FG_COLOR;
console->bg = BG_COLOR;
printf("\x1b[J"); // Clear
printf("kern.\n\n");
while (1) {
printf("\x1b[6M%s \x1b[2M%s \x1b[8M", cwd, PROMPT);
char input[256];
char* inPtr = &input[0];
gets(inPtr, 256);
}
}
int _m() {
// Run Interactive Shell Program
// TODO: Make it in another file
while (1) {
printf("\x1b[6M%s \x1b[2M%s ", cwd, PROMPT);
char input[256];
char* inputPtr = input;
gets(input, 256);
if (*input == '\0') continue;
int argc = 0;
char* argv[10] = { NULL };
while (*inputPtr == ' ') inputPtr++;
argv[argc++] = inputPtr;
while (*inputPtr != '\0') {
if (*inputPtr == ' ') {
*inputPtr++ = '\0';
while (*inputPtr == ' ') inputPtr++; // Skip extra spaces
argv[argc++] = inputPtr;
} else {
inputPtr++;
}
}
if (strcmp(argv[0], "clear") == 0) {
printf("\x1b[J");
} else if (strcmp(argv[0], "echo") == 0) {
if (argc < 2) continue;
char* str = argv[1];
char* printStr = argv[1];
while (*argv[1] != '\0') {
if (*argv[1] == '\\') {
argv[1]++;
if (*argv[1] == 'n') *str++ = '\n';
else if (*argv[1] == 'b') *str++ = '\b';
else if (*argv[1] == 'e') *str++ = '\x1b';
else if (*argv[1] == '\\') *str++ = '\\';
else {
*str++ = '\\';
*str++ = *argv[1];
}
argv[1]++;
} else {
*str++ = *argv[1]++;
}
}
*str = '\0';
printf("%s\n", printStr);
} else if (strcmp(argv[0], "exit") == 0) {
break;
} else if (strcmp(argv[0], "gfx") == 0) {
printf("\x1b[J");
// Draw some stuff :)
for (size_t i = 0; i < 120; i++) {
for (size_t j = 0; j < 120; j++) {
drawPixel(200 + i, 200 + j, GREEN);
}
}
fillRect(200, 200, 320, 320, GREEN);
drawLine(200, 200, 320, 320, RED);
drawLine(320, 200, 200, 320, RED);
drawLine(800, 300, 900, 400, BLUE);
drawLine(900, 400, 1000, 300, BLUE);
drawLine(1000, 300, 900, 200, BLUE);
drawLine(900, 200, 800, 300, BLUE);
drawLine(400, 350, 420, 100, rgb(0xee, 0x9f, 0x00));
drawTriangle(200, 400, 400, 600, 200, 600, MAGENTA);
fillTriangle(750, 400, 800, 450, 700, 450, CYAN);
drawTriangle(960, 400, 1000, 500, 990, 580, YELLOW);
drawRect(100, 650, 800, 900, rgb(0xe0, 0x0a, 0x3a));
drawCircle(1500, 600, 300, WHITE);
fillCircle(950, 750, 75, rgb(0xa2, 0xd6, 0xf9));
getc(stdin); // Wait until we get a keystroke
printf("\x1b[J");
} else if (strcmp(argv[0], "help") == 0) {
printf("Available Commands:\n");
printf(" clear | Clears the screen\n");
printf(" echo | Prints a message to stdout\n");
printf(" exit | Exits shell\n");
printf(" gfx | Does a graphics test\n");
printf(" help | Prints this message\n");
printf(" ls | Lists files in current directory\n");
printf(" memmap | Prints the memory map and info\n");
printf(" reboot | Reboots the system\n");
printf(" regs | Prints register values\n");
printf(" sleep | Sleeps for input number of seconds\n");
printf(" soundtest | Plays a tune :)\n");
} else if (strcmp(argv[0], "ls") == 0) {
listFiles();
} else if (strcmp(argv[0], "memmap") == 0) {
printPhysicalMemmap();
} else if (strcmp(argv[0], "reboot") == 0) {
outb(0x64, 0xFE);
} else if (strcmp(argv[0], "regs") == 0) {
printRegs();
} else if (strcmp(argv[0], "sleep") == 0) {
if (*argv[1] == '\0') continue;
uint32_t ms = atoi(argv[1]) * 1000; // Convert seconds to miliseconds
if (ms == 0) continue;
msleep(ms);
} else if (strcmp(argv[0], "soundtest") == 0) {
printf("Playing...\n");
enableSpeaker();
/*
* Megalovania - Toby Fox
* |-D-D-d--A---Ab--G--F--D-F-G-| (Goofy ahh notation)
* (The timing may be off)
*/
for (uint8_t i = 0; i < 4; i++) {
note_t first[4] = { D4, C4, H3, Hb3 };
playNote(first[i], 120);
playNote(first[i], 120);
playNote(D5, 240);
playNote(A4, 360);
playNote(Ab4, 240);
playNote(G4, 240);
playNote(F4, 240);
playNote(D4, 120);
playNote(F4, 120);
playNote(G4, 120);
}
rest(120);
disableSpeaker();
} else { // TODO: Use cwd for this
char* fileName = argv[0];
FILE* _f = fopen(fileName, "rb");
if (_f == NULL) {
printf("Command not found: %s\n", fileName);
continue;
}
FILE* fp = fsInfo->openFileTable + _f->_file;
printf("%d: 0x%x Bytes\n", fp->_file, fp->_size);
for (size_t i = 0; i < fp->_size; i++) {
if (i % 32 == 0) {
if (i != 0) {
printf(" ");
size_t oldi = i;
i -= 32;
while (i < oldi) {
char c = fp->_ptr[i++];
printf("%c", c < 32 ? '.' : c);
}
putc('\n', stdout);
}
printf("%04x: ", i);
}
printf("%02x ", fp->_ptr[i]);
}
if (fp->_size % 32 != 0) {
for (size_t i = 0; i < 32-(fp->_size % 32); i++) {
printf(" ");
}
}
printf(" ");
for (size_t i = fp->_size-(fp->_size%32); i < fp->_size; i++) {
char c = fp->_ptr[i];
printf("%c", c < 32 ? '.' : c);
}
printf("\n");
free(_f);
fclose(fp);
}
}
outw(0x604, 0x2000); // QEMU - Quit emulator
while (1); // Just hang
}
void listFiles() {
inode_t* root = (inode_t*)impl_superblock->rootInodePtr;
diskRead(root->extent[0].block * 8, root->extent[0].length * 8, (void*)SCRATCH_BLOCK_LOC);
dirEntry_t* dentry = (dirEntry_t*)SCRATCH_BLOCK_LOC;
uint32_t total = 0;
while ((dentry + total)->name[0] != '\0') { total++; }
putc(' ', stdout); // TODO
printf("\bTotal %d\n", total);
while (dentry->name[0] != '\0') {
inode_t* inode = (inode_t*)BOOT_FIRST_INODE_LOC + dentry->id;
printf("%s", dentry->name);
for (uint32_t pad = (16 - strlen(dentry->name)); pad > 0; pad--) { putc(' ', stdout); }
switch (inode->type) {
case FT_FILE: printf("%dB\n", inode->sizeBytes); break;
case FT_DIR: printf("[dir]\n"); break;
}
dentry++;
}
}
void printRegs() {
uint32_t val;
// a, b, c, d
__asm__ volatile ("movl %%eax, %0" : "=r"(val));
printf("eax 0x%08x\n", val);
__asm__ volatile ("movl %%ebx, %0" : "=r"(val));
printf("ebx 0x%08x\n", val);
__asm__ volatile ("movl %%ecx, %0" : "=r"(val));
printf("ecx 0x%08x\n", val);
__asm__ volatile ("movl %%edx, %0" : "=r"(val));
printf("edx 0x%08x\n", val);
// si, di
__asm__ volatile ("movl %%esi, %0" : "=r"(val));
printf("esi 0x%08x\n", val);
__asm__ volatile ("movl %%edi, %0" : "=r"(val));
printf("edi 0x%08x\n", val);
// cs, ds, es, ss
__asm__ volatile ("movl %%cs, %0" : "=r"(val));
printf("cs 0x%08x\n", val);
__asm__ volatile ("movl %%ds, %0" : "=r"(val));
printf("ds 0x%08x\n", val);
__asm__ volatile ("movl %%es, %0" : "=r"(val));
printf("es 0x%08x\n", val);
__asm__ volatile ("movl %%ss, %0" : "=r"(val));
printf("ss 0x%08x\n", val);
// stack
__asm__ volatile ("movl %%esp, %0" : "=r"(val));
printf("esp 0x%08x\n", val);
__asm__ volatile ("movl %%ebp, %0" : "=r"(val));
printf("ebp 0x%08x\n", val);
}
void printPhysicalMemmap() {
uint32_t entryCount = *(uint32_t*)SMAP_ENTRY_COUNT;
smapEntry_t* smapEntry = (smapEntry_t*)SMAP_ENTRIES;
for (uint32_t i = 0; i < entryCount; i++) {
printf("Region %02d - base: 0x%08x length: 0x%08x type: %2d ", i, (uint32_t)smapEntry->baseAddress, (uint32_t)smapEntry->length, smapEntry->type);
switch (smapEntry->type) {
case 1: printf("(Available)\n"); break;
case 2: printf("(Reserved)\n"); break;
case 3: printf("(ACPI Reclaim)\n"); break;
case 4: printf("(ACPI NVS)\n"); break;
default: printf("(Reserved)\n"); break;
}
smapEntry++;
}
smapEntry--; // We incremented it after the last entry
printf("\nTotal memory: 0x%x Bytes\n", smapEntry->baseAddress + smapEntry->length - 1);
printf("Total 4kB Blocks: %d\n", maxBlocks);
printf("Used or reserved blocks: %d\n", usedBlocks);
printf("Free blocks: %d\n\n", maxBlocks - usedBlocks);
}
@@ -4,7 +4,7 @@
#include <stdint.h>
#include <stdbool.h>
typedef struct {
struct console {
uint32_t x; // X Position of cursor in characters
uint32_t y; // Y Position of cursor in characters
uint32_t bg; // Printed character background
@@ -13,9 +13,9 @@ typedef struct {
uint32_t height; // Height in characters
char cursorChar; // Character to use as a cursor
bool hideCursor; // Should we display the cursor
} console_t;
}
extern console_t* console;
extern struct console* console;
int32_t consoleWrite(const void* buf, uint32_t len);
void toggleCursor();
+7 -10
View File
@@ -18,34 +18,31 @@ LDFLAGS = -z notext -nostdlib -melf_i386
ASFLAGS =
# Directories
# Outputs
BIN = ./bin
BOOTLOADER = $(BIN)/stage1.bin $(BIN)/stage2.bin $(BIN)/stage3.bin
KERNEL = $(BIN)/kernel.bin
LIBC = $(BIN)/libc.o
LIBK = $(BIN)/libk.o
IMG = kern.img
# Kernel
KERNEL = $(BIN)/kernel.bin
KERNEL_DIR = ./kernel
KERNEL_SRC = $(KERNEL_DIR)/kernel.c
# Bootloader
BOOTSECT = $(BIN)/bootsect.bin
BOOTLOAD = $(BIN)/bootload.bin
BOOT_DIR = ./boot
BOOT_SRC_ASM = $(shell find $(BOOT_DIR) -type f -name "**.s")
BOOT_SRC_C = $(shell find $(BOOT_DIR) -type f -name "**.c")
# Libc
LIBC = $(BIN)/libc.o
LIBC_DIR = ./libc
LIBC_SRC = $(shell find $(LIBC_DIR) -type f -name "**.c")
# Libk
LIBK_DIR = ./libk
LIBK_SRC = $(shell find $(LIBK_DIR) -type f -name "**.c")
# Userspace
FONT_DIR = ./usr/fonts
FONTS = testfont term16n
# Include directories
LIBC_INC = $(LIBC_DIR)/include
LIBK_INC = $(LIBK_DIR)/include
KERNEL_INC = $(KERNEL_DIR)/include
View File
+44
View File
@@ -0,0 +1,44 @@
#
# Main kern makefile
#
export VERSION = 0.2.2
# Configurable variables (eg. CC, CFLAGS, ...)
include make.defaults
# The directories containing other makefiles
SUBDIRS = libc libk boot kernel
all: msg $(IMG)
msg:
@echo\
"\x1b[36mBuilding \x1b[1mkern.\x1b[22m V$(VERSION)\x1b[0m\n\x1b[32m (c) Tom-on 2024\x1b[0m\n"
# Build the final disk image
$(IMG): $(SUBDIRS) $(FONTS)
$(HOSTCC) ./makedisk.c -I$(LIBK_INC)/fs -o ./makedisk
./makedisk
@echo "\n\x1b[32mDone!\x1b[0m\n"
$(SUBDIRS):
mkdir -p $(BIN)/$@
$(MAKE) -C . -f $@/makefile
$(FONTS):
cp $(FONT_DIR)/$@.fnt $(BIN)/$@.fnt
.PHONY: all $(SUBDIRS) fonts clean qemu
clean:
rm -rf $(BIN)
rm -rf $(IMG)
rm -f makedisk
qemu:
qemu-system-x86_64\
-drive format=raw,file=$(IMG),index=0,media=disk\
-m 256M -accel tcg -monitor stdio\
-rtc base=localtime,clock=host,driftfix=slew\
-audiodev coreaudio,id=audio0 -machine pcspk-audiodev=audio0
+328
View File
@@ -0,0 +1,328 @@
#include <stdlib.h>
#include <stdio.h>
#include "shell.h"
#define COMMAND_COUNT 11
#define MAX_INPUT 256
#define MAX_ARGC 9 // 10 - 1 (because 0 is also an arg)
typedef struct {
char* command;
int (*handler)(int argc, char** argv);
char* help;
} command_t;
command_t commands[COMMAND_COUNT] = {
{ "clear", cmd_clear, "Clears the screen" },
{ "echo", cmd_echo, "Prints a message to stdout" },
{ "exit", cmd_exit, "Exits shell" },
{ "gfxtest", cmd_gfxtest, "Does a graphics test" },
{ "help", cmd_help, "Prints this message" },
{ "ls", cmd_ls, "Lists files in current directory" },
{ "memmap", cmd_memmap, "Prints the memory map and info" },
{ "reboot", cmd_reboot, "Reboots the system" },
{ "regs", cmd_regs, "Prints register values" },
{ "sleep", cmd_sleep, "Sleeps for input number of seconds" },
{ "soundtest", cmd_soundtest, "Plays a tune :)" },
};
int prompt() {
printf("\x1b[6M%s \x1b[2M%s ", cwd, PROMPT);
char input[256];
gets(input, 256);
// Empty line
if (*input == '\0') return 0;
// Parse argc & argv
char* inptr = input;
int argc;
char* argv[10] = { NULL };
while (*inptr == ' ') inptr++;
argv[argc++] = inptr;
while (*inptr != '\0') {
if (*inptr == ' ') {
*inptr++ = '\0';
while (*inptr == ' ') inptr++; // Skip extra spaces
argv[argc++] = inptr;
} else {
inptr++;
}
}
return eval(argc, argv);
}
int eval(int argc, char** argv) {
for (size_t i = 0; i < COMMAND_COUNT; i++) {
if (strcmp(argv[0], commands[i].name) == 0) {
return commands[i].handler(argc, argv);
}
}
// TODO: read PATH
return 1;
}
int cmd_clear(int argc, char** argv) {
printf("\x1b[J");
return 0;
}
int cmd_echo(int argc, char** argv) {
if (argc < 2) continue;
char* str = argv[1];
char* printStr = argv[1];
while (*argv[1] != '\0') {
if (*argv[1] == '\\') {
argv[1]++;
if (*argv[1] == 'n') *str++ = '\n';
else if (*argv[1] == 'b') *str++ = '\b';
else if (*argv[1] == 'e') *str++ = '\x1b';
else if (*argv[1] == '\\') *str++ = '\\';
else {
*str++ = '\\';
*str++ = *argv[1];
}
argv[1]++;
} else {
*str++ = *argv[1]++;
}
}
*str = '\0';
printf("%s\n", printStr);
return 0;
}
int cmd_exit(int argc, char** argv) {
outw(0x604, 0x2000); // QEMU - Quit emulator
while (1) { __asm__ volatile ("cli; hlt"); }
return 1; // Unreachable
}
int cmd_gfxtest(int argc, char** argv) {
printf("\x1b[J");
// Draw some stuff :)
for (size_t i = 0; i < 120; i++) {
for (size_t j = 0; j < 120; j++) {
drawPixel(200 + i, 200 + j, GREEN);
}
}
fillRect(200, 200, 320, 320, GREEN);
drawLine(200, 200, 320, 320, RED);
drawLine(320, 200, 200, 320, RED);
drawLine(800, 300, 900, 400, BLUE);
drawLine(900, 400, 1000, 300, BLUE);
drawLine(1000, 300, 900, 200, BLUE);
drawLine(900, 200, 800, 300, BLUE);
drawLine(400, 350, 420, 100, rgb(0xee, 0x9f, 0x00));
drawTriangle(200, 400, 400, 600, 200, 600, MAGENTA);
fillTriangle(750, 400, 800, 450, 700, 450, CYAN);
drawTriangle(960, 400, 1000, 500, 990, 580, YELLOW);
drawRect(100, 650, 800, 900, rgb(0xe0, 0x0a, 0x3a));
drawCircle(1500, 600, 300, WHITE);
fillCircle(950, 750, 75, rgb(0xa2, 0xd6, 0xf9));
getc(stdin); // Wait until we get a keystroke
printf("\x1b[J");
return 0;
}
int cmd_help(int argc, char** argv) {
printf("Available commands:\n");
for (int i = 0; i < COMMAND_COUNT; i++) {
printf(" %11s | %s\n", commands[i].command, commands[i].help);
}
return 0;
}
int cmd_ls(int argc, char** argv) {
inode_t* root = (inode_t*)impl_superblock->rootInodePtr;
diskRead(root->extent[0].block * 8, root->extent[0].length * 8, (void*)SCRATCH_BLOCK_LOC);
dirEntry_t* dentry = (dirEntry_t*)SCRATCH_BLOCK_LOC;
uint32_t total = 0;
while ((dentry + total)->name[0] != '\0') { total++; }
putc(' ', stdout); // TODO
printf("\bTotal %d\n", total);
while (dentry->name[0] != '\0') {
inode_t* inode = (inode_t*)BOOT_FIRST_INODE_LOC + dentry->id;
printf("%s", dentry->name);
for (uint32_t pad = (16 - strlen(dentry->name)); pad > 0; pad--) { putc(' ', stdout); }
switch (inode->type) {
case FT_FILE: printf("%dB\n", inode->sizeBytes); break;
case FT_DIR: printf("[dir]\n"); break;
}
dentry++;
}
return 0;
}
int cmd_memmap(int argc, char** argv) {
uint32_t entryCount = *(uint32_t*)SMAP_ENTRY_COUNT;
smapEntry_t* smapEntry = (smapEntry_t*)SMAP_ENTRIES;
for (uint32_t i = 0; i < entryCount; i++) {
printf("Region %02d - base: 0x%08x length: 0x%08x type: %2d ", i, (uint32_t)smapEntry->baseAddress, (uint32_t)smapEntry->length, smapEntry->type);
switch (smapEntry->type) {
case 1: printf("(Available)\n"); break;
case 2: printf("(Reserved)\n"); break;
case 3: printf("(ACPI Reclaim)\n"); break;
case 4: printf("(ACPI NVS)\n"); break;
default: printf("(Reserved)\n"); break;
}
smapEntry++;
}
smapEntry--; // We incremented it after the last entry
printf("\nTotal memory: 0x%x Bytes\n", smapEntry->baseAddress + smapEntry->length - 1);
printf("Total 4kB Blocks: %d\n", maxBlocks);
printf("Used or reserved blocks: %d\n", usedBlocks);
printf("Free blocks: %d\n\n", maxBlocks - usedBlocks);
return 0;
}
int cmd_reboot(int argc, char** argv) {
outb(0x64, 0xFE);
return 1;
}
int cmd_regs(int argc, char** argv) {
uint32_t val;
// a, b, c, d
__asm__ volatile ("movl %%eax, %0" : "=r"(val));
printf("eax 0x%08x\n", val);
__asm__ volatile ("movl %%ebx, %0" : "=r"(val));
printf("ebx 0x%08x\n", val);
__asm__ volatile ("movl %%ecx, %0" : "=r"(val));
printf("ecx 0x%08x\n", val);
__asm__ volatile ("movl %%edx, %0" : "=r"(val));
printf("edx 0x%08x\n", val);
// si, di
__asm__ volatile ("movl %%esi, %0" : "=r"(val));
printf("esi 0x%08x\n", val);
__asm__ volatile ("movl %%edi, %0" : "=r"(val));
printf("edi 0x%08x\n", val);
// cs, ds, es, ss
__asm__ volatile ("movl %%cs, %0" : "=r"(val));
printf("cs 0x%08x\n", val);
__asm__ volatile ("movl %%ds, %0" : "=r"(val));
printf("ds 0x%08x\n", val);
__asm__ volatile ("movl %%es, %0" : "=r"(val));
printf("es 0x%08x\n", val);
__asm__ volatile ("movl %%ss, %0" : "=r"(val));
printf("ss 0x%08x\n", val);
// stack
__asm__ volatile ("movl %%esp, %0" : "=r"(val));
printf("esp 0x%08x\n", val);
__asm__ volatile ("movl %%ebp, %0" : "=r"(val));
printf("ebp 0x%08x\n", val);
return 0;
}
int cmd_sleep(int argc, char** argv) {
if (*argv[1] == '\0') continue;
uint32_t ms = atoi(argv[1]) * 1000; // Convert seconds to miliseconds
if (ms == 0) continue;
msleep(ms);
return 0;
}
int cmd_soundtest(int argc, char** argv) {
printf("Playing...\n");
enableSpeaker();
/*
* Megalovania - Toby Fox
* |-D-D-d--A---Ab--G--F--D-F-G-| (Goofy ahh notation)
* (The timing may be off)
*/
for (uint8_t i = 0; i < 4; i++) {
note_t first[4] = { D4, C4, H3, Hb3 };
playNote(first[i], 120);
playNote(first[i], 120);
playNote(D5, 240);
playNote(A4, 360);
playNote(Ab4, 240);
playNote(G4, 240);
playNote(F4, 240);
playNote(D4, 120);
playNote(F4, 120);
playNote(G4, 120);
}
rest(120);
disableSpeaker();
return 0;
}
_m() {
char* fileName = argv[0];
FILE* _f = fopen(fileName, "rb");
if (_f == NULL) {
printf("Command not found: %s\n", fileName);
continue;
}
FILE* fp = fsInfo->openFileTable + _f->_file;
printf("%d: 0x%x Bytes\n", fp->_file, fp->_size);
for (size_t i = 0; i < fp->_size; i++) {
if (i % 32 == 0) {
if (i != 0) {
printf(" ");
size_t oldi = i;
i -= 32;
while (i < oldi) {
char c = fp->_ptr[i++];
printf("%c", c < 32 ? '.' : c);
}
putc('\n', stdout);
}
printf("%04x: ", i);
}
printf("%02x ", fp->_ptr[i]);
}
if (fp->_size % 32 != 0) {
for (size_t i = 0; i < 32-(fp->_size % 32); i++) {
printf(" ");
}
}
printf(" ");
for (size_t i = fp->_size-(fp->_size%32); i < fp->_size; i++) {
char c = fp->_ptr[i];
printf("%c", c < 32 ? '.' : c);
}
printf("\n");
free(_f);
fclose(fp);
}
View File
View File
View File
View File
+2 -6
View File
@@ -90,8 +90,8 @@ start:
; Far jump to protected mode
jmp code_seg:vector
%include "disk.s" ; Disk I/O helper functions
%include "gdt.s" ; Global Descriptor Table
%include "boot/disk.s" ; Disk I/O helper functions
%include "boot/gdt.s" ; Global Descriptor Table
; Handles an error
err:
@@ -131,7 +131,3 @@ vector:
times 510-($-$$) db 0
dw 0xaa55
; === STAGE 2 ===
align 16
incbin 'stage2.bin'
View File
+3
View File
@@ -0,0 +1,3 @@
#
# kern. makefile defaults
#
+17
View File
@@ -0,0 +1,17 @@
Bootloader
============
Kern uses a two stage bootloader. The first stage is the 512 byte bootsector.
This code loads the 2nd stage, which is in the next seven sectors.
Together this whole bootloader takes up the first filesystem block (4kiB).
Bootframe
---------
When the bootloader runs the kernel, it pushes a 32-bit address that points
to the bootframe It follows the following structure:
* Memory map
* Video memory
* ...todo
It is defined in the libk header 'boot.h'
+25
View File
@@ -0,0 +1,25 @@
Building & Running
==================
_If you want to try kern for some reason, you can._
Tools
-----
* [NASM](https://www.nasm.us/)
* [QEMU](https://www.qemu.org/) (for emulation)
Unix-Like Systems
*****************
* [GCC](https://gcc.gnu.org/)
On MacOS
********
* A cross compiler: `$ brew tap nativeos/i386-elf-toolchain && brew install i386-elf-binutils i386-elf-gcc`
Commands
--------
```sh
$ make # Or 'make os'
$ make run # Run QEMU
```
_I personally wouldn't recommend running this on real hardware, because it's untested and will just probably break you pc, but if you really want to, you can try it, but don't blame me if something goes wrong._
+188
View File
@@ -0,0 +1,188 @@
Coding Style
============
Indentation
-----------
All indents must be a tab character ('\t'). It is recommended to display tabs
as eight spaces to avoid extensive indentation. You shouldn't have more than
3 levels of indentation.
Braces
------
All braces should be placed on the same line as the statement they belong to.
```c
int main(void) {
return 0;
}
```
The closing brace should be on it's own line, unless it's being followed by
a continuation of the statement (e.g. 'else' after an 'if').
```c
if (condition) {
doSomething();
} else {
doSomethingElse();
}
```
There may be a single statement without braces if it fits on a single line.
```c
// This is good
if (condition) doSomething();
// This is too long => bad
if (condition) doSomethingButLong(someParameter, someNumber * otherNumber, "A literal string");
```
Spaces
------
Spaces should be after most statements like 'while', 'for', 'if', etc.
Spaces should not be placed after 'sizeof' and 'alignof' statements.
There should not be spaces around the inside of a parenthesized expression, e.g.:
`int x = ( y * x ); // This is bad`
The '*' in pointer declarations, it is prefered to be appended to the
type name, e.g.:
```c
char* string; // Good
char** strings; // Good
int *intptr; // Bad
int *a, *b; // Allowed, but should be split into multiple declarations
```
Spaces should also be placed between binary and ternary operators, but
should not be placed after/before unary operators or member access operators.
Naming
------
_The hardest thing in programming_
Identifiers should use camelCase (starting with lowercase). In special
cases (e.g. syscall handlers) a short prefix separated with an underscore
may be used (e.g. 'sys_malloc').
Global variables (that should be sparse) and global functions need good,
descriptive names. A disk reading function shouldn't be called 'dskrd()'.
Local variables and functions don't need descriptive names, a loop counter
should be named 'i' and not loopCounter.
Some good naming examples:
```c
// Random good function names
int32_t findFreeBlock(uint32_t count);
int32_t ttyWrite(const void* buf, size_t len);
uint8_t getRtcRegister(uint8_t reg);
// Serial functions all start with 'serial'
int serialSetup();
void serialWrite(uint8_t byte);
uint8_t serialRead();
// Syscall handlers are prefixed with 'sys_'
int sys_malloc(struct intFrame iframe);
int sys_free(struct intFrame iframe);
```
Labels, for 'goto' statements or assembly, should be snake_case.
Typedefs vs Structs
-------------------
Typedefs should only be used if:
* It's a struct whose members shouldn't be accessed externally, e.g. FILE
* It clears confusion, e.g. 'i32' or 'int32_t' is better than just 'int'
There may be more, but it's better to not use them.
Functions
---------
Functions should be short and do one thing. If a function does multiple things,
see if you can split it up into multiple functions. Some indicators
of a good function are:
* It fits into 1-2 screenfulls (let those be 80x24)
* There shouldn't be more than ~10 local variables
In function prototypes, parameter names should be included. It can give more
insight into what it is supposed to be.
Goto
----
Using the 'goto' statement is fair in these cases:
* Exiting nested code
* Easier to read code
* Getting rid of redundant code
* Exiting from multiple points
Label names should be descriptive, should specify exactly what the goto
does (e.g. 'exit_free_buffer'). Avoid numbering these labels incase of having
to renumber the later.
Comments
--------
Write comments telling What code does, not How. Comments shouldn't be inside
a function body. There may be small comments on some trick or ugly thing in
a function, but avoid doing that too much. If you need to comment on how
everything in a function works, it's probably a really bad function.
Multiline comments should be over multiple lines. Don't write `/* Something */`.
They should look like this:
```c
/*
* This is a multiline comment
* The beggining and ending comment characters have their own lines.
* Each row also starts with an asterisk, making a nice column.
*/
```
Also it is recommended to comment on data in structs, since members may have
more abstract names.
Macros & Enums
--------------
_Yeah, we do a little magic_
Constant define macros must be UPPERCASE.
`#define FUNNY_NUM 0x69`
If there are multiple related constants, please use an enum.
CAPITALIZED macro names are appreciated, but function-like macros may have
lowercase names. Generally, inline functions are prefered over macros.
If a macro uses more than one statement, enclose them in their own scope.
```c
#define MAGIC(_x)\
if (_x > 0) doSomething(_x);
```
Things to look out for:
* Macros that affect controll flow. `#define FOO(_x) { if (_x < 0) return 1; }
* Macros that depend on local variables
* Macros used as l-values
* Forgetting about precedence. Just wrap everything in parenthesis
* Namespace collision, prefix everything in the macro with underscores
Other Stuff
----------
Here are some rules/recommendations that don't deserve their own category.
Inline Assembly
***************
If you don't need to, don't. But for architecture specific stuff, you may need
to. So just don't jump between functions and don't break anything. Also if you
think you can optimize better than the compiler, you're wrong.
Conditional Compilation
***********************
Try to avoid preprocessor conditionals inside .c source files. Instead write
conditionals inside the header and give a NOP version for the #else case.
These functions can be called uncoditionally. Empty inline functions work too.
Using Bool
**********
You may use bool, but are not required to. It does improve readability
Allocating Memory
*****************
The prefered way of allocating memory for a struct is:
`ptr = kmalloc(sizeof(*ptr));`
Casting the returned void pointer is redundant since C converts void pointers
to any other pointers.
+47 -38
View File
@@ -1,48 +1,57 @@
= fsys =
Filesystem
============
Sector = 512 Bytes
Block = 4096 Bytes
Reserved sectors:
Sector 0..3 - Bootblock, will be loaded by the Bios into memory and executed (512B)
Sector 4..7 - Superblock, contains metadata about the filesystem itself (4KiB)
Reserved sectors
----------------
* Sector 0..7 - Bootblock, constains bootloader code that gets ran by the BIOS (4KiB)
* Sector 8..F - Superblock, contains metadata about the filesystem itself (4KiB)
Superblock structure: (4096B)
Device ID
Max File Size
INode Count
INode Bitmap Block
INodes Start
INode Block Count
INodes per sector
Data Bitmap Block
Data Start
Data Block Count
Root INode Pointer
First Unreserved INode
Superblock structure (4096B)
--------------------
* Device ID
* Max File Size
* INode Count
* INode Bitmap Block
* INodes Start
* INode Block Count
* INodes per sector
* Data Bitmap Block
* Data Start
* Data Block Count
* Root INode Pointer
* First Unreserved INode
INode structure: (64B)
Type
Size (bytes)
Sector Count (size in sectors)
Mode
Extent[4]
Single Indirect
Double Indirect?
INode structure (64B)
---------------
* Type
* Size (bytes)
* Sector Count (size in sectors)
* Mode
* Extent[4]
* Single Indirect
* Double Indirect?
Extent: (8B)
Block
Length
Extent (8B)
------
* Block
* Length
Directory Entry: (64B)
INode Number
Name (max length 60 Bytes)
Directory Entry (64B)
---------------
* INode Number
* Name (max length 60 Bytes)
Filetypes:
File
Directory
#TODO
Link
Device
Stream?
Filetypes
---------
* File
* Directory
# TODO
* Link
* Device
* Stream?
These structs are defined in the libk header 'fs/fs.h'
+36
View File
@@ -0,0 +1,36 @@
Kern Dev Struct
===============
Independant Modules
-------------------
* Each MUST have their own directory (eg. 'kernel/', 'boot/')
* Each MAY have their own internal independant submodules (eg. userspace programs in 'usr/')
* A module MAY be dependant on it's own submodules, but it's submodules MUST be independant of each other
* Each MUST have a makefile in their directory (eg. 'libc/makefile')
* Each module MUST be listed in the 'make.defaults' directory
* Each module MUST be self-contained and independentally compilable
kern (Root "module", is dependant on all of it's submodules)
|- boot
| |- bootsect (stage1)
| '- bootload (stage2)
|- kernel
| '- libk
|- libc (C Standard Library)
'- user !EXCEPTION: Userspace programs are dependant upon libc!
|- coreutils
|- fdisk
|- init
|- mkfs
|- sh
..
TODO
====
[ ] boot
[ ] kernel
[x] libc
[ ] user
[ ] makefile
[ ] make.defaults
BIN
View File
Binary file not shown.
-404
View File
@@ -1,404 +0,0 @@
#include <syscalls/syscalls.h>
#include <memory/addresses.h>
#include <memory/physical.h>
#include <memory/virtual.h>
#include <memory/malloc.h>
#include <drivers/keyboard.h>
#include <drivers/serial.h>
#include <drivers/timer.h>
#include <drivers/pcspk.h>
#include <drivers/disk.h>
#include <drivers/rtc.h>
#include <screen/graphics.h>
#include <screen/gfxmode.h>
#include <screen/text.h>
#include <screen/tty.h>
#include <cpu/system.h>
#include <cpu/isr.h>
#include <fs/kernfs.h>
#include <fs/fs.h>
#include <sys/notes.h>
#include <sys/gfx.h>
#include <syscall.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
/* Little teaser
#include <math.h>
void mathTest() {
printf("|-4| = %d\n", abs(-4));
printf("|-3.14| = %f\n", fabs(-3.14));
printf("e^3 = %f\n", exp(3));
printf("e^5 = %f\n", exp2(5));
printf("ln(2) = %f\n", log(2));
printf("log2(69) = %f\n", log2(69));
printf("log10(100) = %f\n", log10(100));
printf("sqrt(2) = %f\n", sqrt(2));
printf("cbrt(27) = %f\n", cbrt(27));
printf("hyp(8, 6) = %f\n", hypot(8, 6));
printf("3^4 = %f\n", pow(3, 4));
}
*/
#define PROMPT "#>"
// FS things
char* cwd;
// Function declarations
void listFiles();
void printRegs();
void printPhysicalMemmap();
void initOpenFileTable();
__attribute__ ((section("entry")))
void main() {
// Retrieve global variables
currentPd = (pageDirectory_t*)*(uint32_t*)CURRENT_PAGE_DIR_ADDR; // Don't ask
memoryMap = (uint32_t*)MEMMAP_AREA;
maxBlocks = *(uint32_t*)PHYS_MEM_MAX_BLOCKS;
usedBlocks = *(uint32_t*)PHYS_MEM_USED_BLOCKS;
// Setup serial output for debugf()
if (setupSerial(PORT_COM1) != 0) { printf("\x1b[1MFailed to initialize serial interface\x1b[8M\n"); }
else {
debugf("\x1b[H\x1b[J"); // Clear
debugf("kern. \x1b[36m(Serial console)\x1b[0m\n\n");
}
// Interrupt setup
setupIsrs();
// Programmable Interval Timer
registerIrq(0, timerHandler);
setPitPhase(0, 2, 1000); // 1000Hz
// Real Time Clock
registerIrq(8, rtcHandler);
enableRtc();
// Keyboard
registerIrq(1, keyboardHandler);
// Setup kernel malloc variables
mallocNode_t* kernelMallocListHead = 0;
uint32_t kernelMallocVirtualAddr = KERNEL_MALLOC_AREA;
uint32_t kernelMallocPhysicalAddr = (uint32_t)allocBlocks(16); // TODO: Kernel may use more than 64kB?
uint32_t kernelMallocPages = 1;
mapPage((void*)kernelMallocPhysicalAddr, (void*)kernelMallocVirtualAddr);
ptEntry_t* kernelMallocPage = getPage(kernelMallocVirtualAddr);
SET_ATTR(kernelMallocPage, PTE_READ_WRITE);
kernelMallocListHead = (mallocNode_t*)kernelMallocVirtualAddr;
kernelMallocListHead->size = PAGE_SIZE - sizeof(mallocNode_t);
kernelMallocListHead->free = true;
kernelMallocListHead->next = NULL;
mallocListHead = kernelMallocListHead;
mallocVirtualAddr = kernelMallocVirtualAddr;
mallocPhysicalAddr = kernelMallocPhysicalAddr;
mallocPages = kernelMallocPages;
// FS Setup
initOpenFileTable();
cwd = malloc(1024);
strcpy(cwd, "/");
// Terminal setup
console->fg = FG_COLOR;
console->bg = BG_COLOR;
printf("\x1b[J"); // Clear
printf("kern.\n\n");
while (1) {
printf("\x1b[6M%s \x1b[2M%s \x1b[8M", cwd, PROMPT);
char input[256];
char* inPtr = &input[0];
gets(inPtr, 256);
}
}
int _m() {
// Run Interactive Shell Program
// TODO: Make it in another file
while (1) {
printf("\x1b[6M%s \x1b[2M%s ", cwd, PROMPT);
char input[256];
char* inputPtr = input;
gets(input, 256);
if (*input == '\0') continue;
int argc = 0;
char* argv[10] = { NULL };
while (*inputPtr == ' ') inputPtr++;
argv[argc++] = inputPtr;
while (*inputPtr != '\0') {
if (*inputPtr == ' ') {
*inputPtr++ = '\0';
while (*inputPtr == ' ') inputPtr++; // Skip extra spaces
argv[argc++] = inputPtr;
} else {
inputPtr++;
}
}
if (strcmp(argv[0], "clear") == 0) {
printf("\x1b[J");
} else if (strcmp(argv[0], "echo") == 0) {
if (argc < 2) continue;
char* str = argv[1];
char* printStr = argv[1];
while (*argv[1] != '\0') {
if (*argv[1] == '\\') {
argv[1]++;
if (*argv[1] == 'n') *str++ = '\n';
else if (*argv[1] == 'b') *str++ = '\b';
else if (*argv[1] == 'e') *str++ = '\x1b';
else if (*argv[1] == '\\') *str++ = '\\';
else {
*str++ = '\\';
*str++ = *argv[1];
}
argv[1]++;
} else {
*str++ = *argv[1]++;
}
}
*str = '\0';
printf("%s\n", printStr);
} else if (strcmp(argv[0], "exit") == 0) {
break;
} else if (strcmp(argv[0], "gfx") == 0) {
printf("\x1b[J");
// Draw some stuff :)
for (size_t i = 0; i < 120; i++) {
for (size_t j = 0; j < 120; j++) {
drawPixel(200 + i, 200 + j, GREEN);
}
}
fillRect(200, 200, 320, 320, GREEN);
drawLine(200, 200, 320, 320, RED);
drawLine(320, 200, 200, 320, RED);
drawLine(800, 300, 900, 400, BLUE);
drawLine(900, 400, 1000, 300, BLUE);
drawLine(1000, 300, 900, 200, BLUE);
drawLine(900, 200, 800, 300, BLUE);
drawLine(400, 350, 420, 100, rgb(0xee, 0x9f, 0x00));
drawTriangle(200, 400, 400, 600, 200, 600, MAGENTA);
fillTriangle(750, 400, 800, 450, 700, 450, CYAN);
drawTriangle(960, 400, 1000, 500, 990, 580, YELLOW);
drawRect(100, 650, 800, 900, rgb(0xe0, 0x0a, 0x3a));
drawCircle(1500, 600, 300, WHITE);
fillCircle(950, 750, 75, rgb(0xa2, 0xd6, 0xf9));
getc(stdin); // Wait until we get a keystroke
printf("\x1b[J");
} else if (strcmp(argv[0], "help") == 0) {
printf("Available Commands:\n");
printf(" clear | Clears the screen\n");
printf(" echo | Prints a message to stdout\n");
printf(" exit | Exits shell\n");
printf(" gfx | Does a graphics test\n");
printf(" help | Prints this message\n");
printf(" ls | Lists files in current directory\n");
printf(" memmap | Prints the memory map and info\n");
printf(" reboot | Reboots the system\n");
printf(" regs | Prints register values\n");
printf(" sleep | Sleeps for input number of seconds\n");
printf(" soundtest | Plays a tune :)\n");
} else if (strcmp(argv[0], "ls") == 0) {
listFiles();
} else if (strcmp(argv[0], "memmap") == 0) {
printPhysicalMemmap();
} else if (strcmp(argv[0], "reboot") == 0) {
outb(0x64, 0xFE);
} else if (strcmp(argv[0], "regs") == 0) {
printRegs();
} else if (strcmp(argv[0], "sleep") == 0) {
if (*argv[1] == '\0') continue;
uint32_t ms = atoi(argv[1]) * 1000; // Convert seconds to miliseconds
if (ms == 0) continue;
msleep(ms);
} else if (strcmp(argv[0], "soundtest") == 0) {
printf("Playing...\n");
enableSpeaker();
/*
* Megalovania - Toby Fox
* |-D-D-d--A---Ab--G--F--D-F-G-| (Goofy ahh notation)
* (The timing may be off)
*/
for (uint8_t i = 0; i < 4; i++) {
note_t first[4] = { D4, C4, H3, Hb3 };
playNote(first[i], 120);
playNote(first[i], 120);
playNote(D5, 240);
playNote(A4, 360);
playNote(Ab4, 240);
playNote(G4, 240);
playNote(F4, 240);
playNote(D4, 120);
playNote(F4, 120);
playNote(G4, 120);
}
rest(120);
disableSpeaker();
} else { // TODO: Use cwd for this
char* fileName = argv[0];
FILE* _f = fopen(fileName, "rb");
if (_f == NULL) {
printf("Command not found: %s\n", fileName);
continue;
}
FILE* fp = fsInfo->openFileTable + _f->_file;
printf("%d: 0x%x Bytes\n", fp->_file, fp->_size);
for (size_t i = 0; i < fp->_size; i++) {
if (i % 32 == 0) {
if (i != 0) {
printf(" ");
size_t oldi = i;
i -= 32;
while (i < oldi) {
char c = fp->_ptr[i++];
printf("%c", c < 32 ? '.' : c);
}
putc('\n', stdout);
}
printf("%04x: ", i);
}
printf("%02x ", fp->_ptr[i]);
}
if (fp->_size % 32 != 0) {
for (size_t i = 0; i < 32-(fp->_size % 32); i++) {
printf(" ");
}
}
printf(" ");
for (size_t i = fp->_size-(fp->_size%32); i < fp->_size; i++) {
char c = fp->_ptr[i];
printf("%c", c < 32 ? '.' : c);
}
printf("\n");
free(_f);
fclose(fp);
}
}
outw(0x604, 0x2000); // QEMU - Quit emulator
while (1); // Just hang
}
void listFiles() {
inode_t* root = (inode_t*)impl_superblock->rootInodePtr;
diskRead(root->extent[0].block * 8, root->extent[0].length * 8, (void*)SCRATCH_BLOCK_LOC);
dirEntry_t* dentry = (dirEntry_t*)SCRATCH_BLOCK_LOC;
uint32_t total = 0;
while ((dentry + total)->name[0] != '\0') { total++; }
putc(' ', stdout); // TODO
printf("\bTotal %d\n", total);
while (dentry->name[0] != '\0') {
inode_t* inode = (inode_t*)BOOT_FIRST_INODE_LOC + dentry->id;
printf("%s", dentry->name);
for (uint32_t pad = (16 - strlen(dentry->name)); pad > 0; pad--) { putc(' ', stdout); }
switch (inode->type) {
case FT_FILE: printf("%dB\n", inode->sizeBytes); break;
case FT_DIR: printf("[dir]\n"); break;
}
dentry++;
}
}
void printRegs() {
uint32_t val;
// a, b, c, d
__asm__ volatile ("movl %%eax, %0" : "=r"(val));
printf("eax 0x%08x\n", val);
__asm__ volatile ("movl %%ebx, %0" : "=r"(val));
printf("ebx 0x%08x\n", val);
__asm__ volatile ("movl %%ecx, %0" : "=r"(val));
printf("ecx 0x%08x\n", val);
__asm__ volatile ("movl %%edx, %0" : "=r"(val));
printf("edx 0x%08x\n", val);
// si, di
__asm__ volatile ("movl %%esi, %0" : "=r"(val));
printf("esi 0x%08x\n", val);
__asm__ volatile ("movl %%edi, %0" : "=r"(val));
printf("edi 0x%08x\n", val);
// cs, ds, es, ss
__asm__ volatile ("movl %%cs, %0" : "=r"(val));
printf("cs 0x%08x\n", val);
__asm__ volatile ("movl %%ds, %0" : "=r"(val));
printf("ds 0x%08x\n", val);
__asm__ volatile ("movl %%es, %0" : "=r"(val));
printf("es 0x%08x\n", val);
__asm__ volatile ("movl %%ss, %0" : "=r"(val));
printf("ss 0x%08x\n", val);
// stack
__asm__ volatile ("movl %%esp, %0" : "=r"(val));
printf("esp 0x%08x\n", val);
__asm__ volatile ("movl %%ebp, %0" : "=r"(val));
printf("ebp 0x%08x\n", val);
}
void printPhysicalMemmap() {
uint32_t entryCount = *(uint32_t*)SMAP_ENTRY_COUNT;
smapEntry_t* smapEntry = (smapEntry_t*)SMAP_ENTRIES;
for (uint32_t i = 0; i < entryCount; i++) {
printf("Region %02d - base: 0x%08x length: 0x%08x type: %2d ", i, (uint32_t)smapEntry->baseAddress, (uint32_t)smapEntry->length, smapEntry->type);
switch (smapEntry->type) {
case 1: printf("(Available)\n"); break;
case 2: printf("(Reserved)\n"); break;
case 3: printf("(ACPI Reclaim)\n"); break;
case 4: printf("(ACPI NVS)\n"); break;
default: printf("(Reserved)\n"); break;
}
smapEntry++;
}
smapEntry--; // We incremented it after the last entry
printf("\nTotal memory: 0x%x Bytes\n", smapEntry->baseAddress + smapEntry->length - 1);
printf("Total 4kB Blocks: %d\n", maxBlocks);
printf("Used or reserved blocks: %d\n", usedBlocks);
printf("Free blocks: %d\n\n", maxBlocks - usedBlocks);
}
+3 -38
View File
@@ -1,44 +1,9 @@
#
# Main kern makefile
# Root kern. makefile
# (c) 2023-2025 Tomas Kubecek
#
export VERSION = 0.2.2
include defaults.mk
# Configurable variables (eg. CC, CFLAGS, ...)
include make.defaults
# The directories containing other makefiles
SUBDIRS = libc libk boot kernel
all: msg $(IMG)
msg:
@echo\
"\x1b[36mBuilding \x1b[1mkern.\x1b[22m V$(VERSION)\x1b[0m\n\x1b[32m (c) Tom-on 2024\x1b[0m\n"
# Build the final disk image
$(IMG): $(SUBDIRS) $(FONTS)
$(HOSTCC) ./makedisk.c -I$(LIBK_INC)/fs -o ./makedisk
./makedisk
@echo "\n\x1b[32mDone!\x1b[0m\n"
$(SUBDIRS):
mkdir -p $(BIN)/$@
$(MAKE) -C . -f $@/makefile
$(FONTS):
cp $(FONT_DIR)/$@.fnt $(BIN)/$@.fnt
.PHONY: all $(SUBDIRS) fonts clean qemu
clean:
rm -rf $(BIN)
rm -rf $(IMG)
rm -f makedisk
qemu:
qemu-system-x86_64\
-drive format=raw,file=$(IMG),index=0,media=disk\
-m 256M -accel tcg -monitor stdio\
-rtc base=localtime,clock=host,driftfix=slew\
-audiodev coreaudio,id=audio0 -machine pcspk-audiodev=audio0