forked from PoliEcho-holding-org/kern
MAJOR RESTRUCTURE
This commit is contained in:
+22
-16
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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: \
|
||||

|
||||
|
||||
Filesystem: \
|
||||

|
||||
|
||||
Graphics test: \
|
||||

|
||||
|
||||
_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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
+2
-6
@@ -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'
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#
|
||||
# kern. makefile defaults
|
||||
#
|
||||
@@ -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'
|
||||
|
||||
@@ -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._
|
||||
@@ -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
@@ -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'
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
-404
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user