...
This commit is contained in:
7
.clang-format
Normal file
7
.clang-format
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
IndentWidth: 4
|
||||||
|
ColumnLimit: 120
|
||||||
|
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
AllowShortBlocksOnASingleLine: Never
|
||||||
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
2
.clangd
Normal file
2
.clangd
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
CompileFlags:
|
||||||
|
Add: [ -m32, -ffreestanding, -fno-stack-protector, -nostdlib, -nostdinc, -Wall, -Wextra, -std=c23 ]
|
||||||
14
makefile
14
makefile
@@ -1,16 +1,16 @@
|
|||||||
CC = x86_64-elf-gcc
|
CC = i686-elf-gcc
|
||||||
LD = x86_64-elf-ld
|
LD = i686-elf-ld
|
||||||
AS = nasm
|
AS = nasm
|
||||||
|
|
||||||
# Modify these settings here for defines and debug info
|
# Modify these settings here for defines and debug info
|
||||||
# CFLAGS = -g -D DEBUG
|
CFLAGS = -g -D DEBUG
|
||||||
# LDFLAGS = -g
|
LDFLAGS = -g
|
||||||
# ASFLAGS = -g -F dwarf
|
ASFLAGS = -g -F dwarf
|
||||||
|
|
||||||
# Do not modify
|
# Do not modify
|
||||||
CFLAGS += -m64 -ffreestanding -nostdinc -nostdlib -Wall -Wextra -Wshadow -std=c23
|
CFLAGS += -m32 -ffreestanding -fno-stack-protector -nostdlib -nostdinc -Wall -Wextra -std=c23
|
||||||
LDFLAGS +=
|
LDFLAGS +=
|
||||||
ASFLAGS += -f elf64
|
ASFLAGS += -f elf32
|
||||||
|
|
||||||
SRC_C := $(shell find src -name '*.c')
|
SRC_C := $(shell find src -name '*.c')
|
||||||
SRC_ASM := $(shell find src -name '*.asm')
|
SRC_ASM := $(shell find src -name '*.asm')
|
||||||
|
|||||||
19
src/boot.asm
19
src/boot.asm
@@ -1,4 +1,5 @@
|
|||||||
global entry
|
global _start
|
||||||
|
extern kmain
|
||||||
|
|
||||||
%define MAGIC 0xe85250d6
|
%define MAGIC 0xe85250d6
|
||||||
%define ARCH 0x0
|
%define ARCH 0x0
|
||||||
@@ -18,7 +19,19 @@ header:
|
|||||||
dd 8
|
dd 8
|
||||||
.end:
|
.end:
|
||||||
|
|
||||||
|
section .bss
|
||||||
|
align 4096
|
||||||
|
stack:
|
||||||
|
.bottom:
|
||||||
|
resb 1024 * 16
|
||||||
|
.top:
|
||||||
|
|
||||||
section .text
|
section .text
|
||||||
bits 32
|
bits 32
|
||||||
entry:
|
_start:
|
||||||
jmp $
|
mov esp, stack.top
|
||||||
|
call kmain
|
||||||
|
.halt:
|
||||||
|
cli
|
||||||
|
hlt
|
||||||
|
jmp .halt
|
||||||
98
src/console.c
Normal file
98
src/console.c
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
#include "console.h"
|
||||||
|
|
||||||
|
#define ROWS 25
|
||||||
|
#define COLUMNS 80
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u8 character;
|
||||||
|
u8 color;
|
||||||
|
} vga_char_t;
|
||||||
|
|
||||||
|
static vga_char_t *vga_buffer = (vga_char_t *)0xb8000;
|
||||||
|
static u8 cursor_row = 0;
|
||||||
|
static u8 cursor_col = 0;
|
||||||
|
|
||||||
|
void console_putchar(char c, u8 color) {
|
||||||
|
switch (c) {
|
||||||
|
case '\n': {
|
||||||
|
cursor_row += 1;
|
||||||
|
cursor_col = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '\r': {
|
||||||
|
cursor_col = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '\t': {
|
||||||
|
u8 remainder = 4 - (cursor_col % 4);
|
||||||
|
cursor_col += remainder;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '\b': {
|
||||||
|
if (cursor_col > 0) {
|
||||||
|
cursor_col -= 1;
|
||||||
|
} else if (cursor_row > 0) {
|
||||||
|
cursor_row -= 1;
|
||||||
|
|
||||||
|
cursor_col = 0;
|
||||||
|
for (int col = COLUMNS - 1; col >= 0; col--) {
|
||||||
|
vga_char_t cell = vga_buffer[cursor_row * COLUMNS + col];
|
||||||
|
if (cell.character != ' ') {
|
||||||
|
cursor_col = col;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vga_buffer[cursor_row * COLUMNS + cursor_col] = (vga_char_t){
|
||||||
|
.character = ' ',
|
||||||
|
.color = VGA_DEFAULT_COLOR,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
vga_buffer[COLUMNS * cursor_row + cursor_col] = (vga_char_t){
|
||||||
|
.character = c,
|
||||||
|
.color = color,
|
||||||
|
};
|
||||||
|
cursor_col += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor_col >= COLUMNS) {
|
||||||
|
cursor_col = 0;
|
||||||
|
cursor_row += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor_row >= ROWS) {
|
||||||
|
for (size_t row = 1; row < ROWS; row++) {
|
||||||
|
for (size_t col = 0; col < COLUMNS; col++) {
|
||||||
|
vga_buffer[COLUMNS * (row - 1) + col] = vga_buffer[COLUMNS * row + col];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t col = 0; col < COLUMNS; col++) {
|
||||||
|
vga_buffer[COLUMNS * (ROWS - 1) + col] = (vga_char_t){
|
||||||
|
.character = ' ',
|
||||||
|
.color = VGA_DEFAULT_COLOR,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
cursor_row = ROWS - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void console_clear() {
|
||||||
|
for (size_t row = 0; row < ROWS; row++) {
|
||||||
|
for (size_t col = 0; col < COLUMNS; col++) {
|
||||||
|
vga_buffer[COLUMNS * row + col] = (vga_char_t){
|
||||||
|
.character = ' ',
|
||||||
|
.color = VGA_DEFAULT_COLOR,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor_row = 0;
|
||||||
|
cursor_col = 0;
|
||||||
|
}
|
||||||
27
src/console.h
Normal file
27
src/console.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "def.h"
|
||||||
|
|
||||||
|
#define VGA_BLACK 0
|
||||||
|
#define VGA_BLUE 1
|
||||||
|
#define VGA_GREEN 2
|
||||||
|
#define VGA_CYAN 3
|
||||||
|
#define VGA_RED 4
|
||||||
|
#define VGA_MAGENTA 5
|
||||||
|
#define VGA_BROWN 6
|
||||||
|
#define VGA_LIGHT_GRAY 7
|
||||||
|
#define VGA_DARK_GRAY 8
|
||||||
|
#define VGA_LIGHT_BLUE 9
|
||||||
|
#define VGA_LIGHT_GREEN 10
|
||||||
|
#define VGA_LIGHT_CYAN 11
|
||||||
|
#define VGA_LIGHT_RED 12
|
||||||
|
#define VGA_LIGHT_MAGENTA 13
|
||||||
|
#define VGA_YELLOW 14
|
||||||
|
#define VGA_WHITE 15
|
||||||
|
|
||||||
|
#define VGA_COLOR(fg, bg) (fg | bg << 4)
|
||||||
|
|
||||||
|
#define VGA_DEFAULT_COLOR VGA_COLOR(VGA_LIGHT_GRAY, VGA_BLACK)
|
||||||
|
|
||||||
|
void console_putchar(char character, u8 color);
|
||||||
|
void console_clear();
|
||||||
56
src/def.h
Normal file
56
src/def.h
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef __builtin_va_list va_list;
|
||||||
|
|
||||||
|
#define va_start(ap, last) __builtin_va_start(ap, last)
|
||||||
|
#define va_arg(ap, type) __builtin_va_arg(ap, type)
|
||||||
|
#define va_end(ap) __builtin_va_end(ap)
|
||||||
|
#define va_copy(dest, src) __builtin_va_copy(dest, src)
|
||||||
|
|
||||||
|
#ifndef NULL
|
||||||
|
#define NULL ((void *)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef unsigned long size_t;
|
||||||
|
typedef unsigned long uintptr_t;
|
||||||
|
|
||||||
|
#define offsetof(type, member) __builtin_offsetof(type, member)
|
||||||
|
|
||||||
|
typedef unsigned char u8;
|
||||||
|
typedef signed char i8;
|
||||||
|
typedef unsigned short u16;
|
||||||
|
typedef signed short i16;
|
||||||
|
typedef unsigned int u32;
|
||||||
|
typedef signed int i32;
|
||||||
|
|
||||||
|
#define I8_MIN (-128)
|
||||||
|
#define I8_MAX 127
|
||||||
|
|
||||||
|
#define U8_MIN 0x0
|
||||||
|
#define U8_MAX 0xff
|
||||||
|
|
||||||
|
#define I16_MIN (-32768)
|
||||||
|
#define I16_MAX 32767
|
||||||
|
|
||||||
|
#define U16_MIN 0x0
|
||||||
|
#define U16_MAX 0xffff
|
||||||
|
|
||||||
|
#define I32_MIN (-2147483647 - 1)
|
||||||
|
#define I32_MAX 2147483647
|
||||||
|
|
||||||
|
#define U32_MIN 0x0
|
||||||
|
#define U32_MAX 0xffffffffU
|
||||||
|
|
||||||
|
#define I8_C(x) x
|
||||||
|
#define U8_C(x) x##U
|
||||||
|
|
||||||
|
#define I16_C(x) x
|
||||||
|
#define U16_C(x) x##U
|
||||||
|
|
||||||
|
#define I32_C(x) x
|
||||||
|
#define U32_C(x) x##U
|
||||||
|
|
||||||
|
#define KiB(count) (U64_C(count) * U64_C(1024))
|
||||||
|
#define MiB(count) (U64_C(count) * U64_C(1024) * U64_C(1024))
|
||||||
|
#define GiB(count) (U64_C(count) * U64_C(1024) * U64_C(1024) * U64_C(1024))
|
||||||
|
#define TiB(count) (U64_C(count) * U64_C(1024) * U64_C(1024) * U64_C(1024) * U64_C(1024))
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
ENTRY(entry)
|
ENTRY(_start)
|
||||||
|
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
|
|||||||
8
src/main.c
Normal file
8
src/main.c
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#include "console.h"
|
||||||
|
#include "print.h"
|
||||||
|
|
||||||
|
// Multiboot 2 puts us in 32-bit protected mode with interrupts disabled
|
||||||
|
void kmain(void) {
|
||||||
|
console_clear();
|
||||||
|
kprintf("booting nub-os\n");
|
||||||
|
}
|
||||||
73
src/print.c
Normal file
73
src/print.c
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
#include "print.h"
|
||||||
|
#include "console.h"
|
||||||
|
#include "def.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
// Supported formats:
|
||||||
|
// - `d`: i32 (decimal)
|
||||||
|
// - `u`: u32 (decimal)
|
||||||
|
// - `x`: u32 (hex)
|
||||||
|
// - `c`: char (ascii)
|
||||||
|
// - `s`: char* (ascii string)
|
||||||
|
//
|
||||||
|
// ```c
|
||||||
|
// printf(
|
||||||
|
// "The answer is %d is located at offset %x in file %s",
|
||||||
|
// 42,
|
||||||
|
// 0x2000
|
||||||
|
// "hitchhiker.txt"
|
||||||
|
// );
|
||||||
|
// ```
|
||||||
|
void kprintf(const char *fmt, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
|
||||||
|
bool should_format = false;
|
||||||
|
|
||||||
|
for (size_t i = 0; fmt[i] != '\0'; i++) {
|
||||||
|
if (should_format) {
|
||||||
|
should_format = false;
|
||||||
|
|
||||||
|
if (fmt[i] == '%') {
|
||||||
|
console_putchar('%', VGA_DEFAULT_COLOR);
|
||||||
|
} else if (fmt[i] == 's') {
|
||||||
|
const char *str = va_arg(args, const char *);
|
||||||
|
for (size_t j = 0; str[j] != '\0'; j++) {
|
||||||
|
console_putchar(str[j], VGA_DEFAULT_COLOR);
|
||||||
|
}
|
||||||
|
} else if (fmt[i] == 'c') {
|
||||||
|
char character = (char)va_arg(args, u32);
|
||||||
|
console_putchar(character, VGA_DEFAULT_COLOR);
|
||||||
|
} else if (fmt[i] == 'd') {
|
||||||
|
u32 val = va_arg(args, u32);
|
||||||
|
char buf[21];
|
||||||
|
itoa(val, buf);
|
||||||
|
for (size_t j = 0; buf[j] != '\0'; j++) {
|
||||||
|
console_putchar(buf[j], VGA_DEFAULT_COLOR);
|
||||||
|
}
|
||||||
|
} else if (fmt[i] == 'u') {
|
||||||
|
u32 val = va_arg(args, u32);
|
||||||
|
char buf[21];
|
||||||
|
uitoa(val, buf);
|
||||||
|
for (size_t j = 0; buf[j] != '\0'; j++) {
|
||||||
|
console_putchar(buf[j], VGA_DEFAULT_COLOR);
|
||||||
|
}
|
||||||
|
} else if (fmt[i] == 'x') {
|
||||||
|
u32 val = va_arg(args, u32);
|
||||||
|
char buf[17];
|
||||||
|
uitoa_hex(val, buf);
|
||||||
|
for (size_t j = 0; buf[j] != '\0'; j++) {
|
||||||
|
console_putchar(buf[j], VGA_DEFAULT_COLOR);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console_putchar(fmt[i], VGA_DEFAULT_COLOR);
|
||||||
|
}
|
||||||
|
} else if (fmt[i] == '%') {
|
||||||
|
should_format = true;
|
||||||
|
} else {
|
||||||
|
console_putchar(fmt[i], VGA_DEFAULT_COLOR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
3
src/print.h
Normal file
3
src/print.h
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void kprintf(const char *fmt, ...);
|
||||||
105
src/string.c
Normal file
105
src/string.c
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
int strcmp(const char *a, const char *b) {
|
||||||
|
while ((*a != '\0' && *b != '\0') && *a == *b) {
|
||||||
|
a++;
|
||||||
|
b++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (*a == *b) ? 0 : (*a > *b) ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reverse(char *str, size_t length) {
|
||||||
|
int start = 0;
|
||||||
|
int end = length - 1;
|
||||||
|
while (start < end) {
|
||||||
|
char temp = str[start];
|
||||||
|
str[start] = str[end];
|
||||||
|
str[end] = temp;
|
||||||
|
start++;
|
||||||
|
end--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void itoa(i32 value, char *buffer) {
|
||||||
|
char temp[21];
|
||||||
|
int i = 0, j = 0;
|
||||||
|
int negative = 0;
|
||||||
|
|
||||||
|
if (value < 0) {
|
||||||
|
negative = 1;
|
||||||
|
if (value == I32_MIN) {
|
||||||
|
const char *min_str = "9223372036854775808";
|
||||||
|
for (i = 0; min_str[i] != '\0'; i++)
|
||||||
|
temp[i] = min_str[i];
|
||||||
|
i = 19;
|
||||||
|
} else {
|
||||||
|
value = -value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value == 0 && !negative) {
|
||||||
|
buffer[0] = '0';
|
||||||
|
buffer[1] = '\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(negative && value == I32_MIN)) {
|
||||||
|
while (value > 0) {
|
||||||
|
temp[i++] = '0' + (value % 10);
|
||||||
|
value /= 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (negative) {
|
||||||
|
temp[i++] = '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i > 0) {
|
||||||
|
buffer[j++] = temp[--i];
|
||||||
|
}
|
||||||
|
buffer[j] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void uitoa(u32 value, char *buffer) {
|
||||||
|
char temp[21];
|
||||||
|
int i = 0, j = 0;
|
||||||
|
|
||||||
|
if (value == 0) {
|
||||||
|
buffer[0] = '0';
|
||||||
|
buffer[1] = '\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (value > 0) {
|
||||||
|
temp[i++] = '0' + (value % 10);
|
||||||
|
value /= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i > 0) {
|
||||||
|
buffer[j++] = temp[--i];
|
||||||
|
}
|
||||||
|
buffer[j] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void uitoa_hex(u32 value, char *buffer) {
|
||||||
|
const char *digits = "0123456789abcdef";
|
||||||
|
char temp[17];
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
if (value == 0) {
|
||||||
|
buffer[0] = '0';
|
||||||
|
buffer[1] = '\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (value > 0 && pos < 16) {
|
||||||
|
temp[pos++] = digits[value & 0xF];
|
||||||
|
value >>= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < pos; i++) {
|
||||||
|
buffer[i] = temp[pos - i - 1];
|
||||||
|
}
|
||||||
|
buffer[pos] = '\0';
|
||||||
|
}
|
||||||
10
src/string.h
Normal file
10
src/string.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "def.h"
|
||||||
|
|
||||||
|
int strcmp(const char *a, const char *b);
|
||||||
|
void reverse(char *str, size_t length);
|
||||||
|
|
||||||
|
void itoa(i32 value, char *buffer);
|
||||||
|
void uitoa(u32 value, char *buffer);
|
||||||
|
void uitoa_hex(u32 value, char *buffer);
|
||||||
Reference in New Issue
Block a user