more WIP
This commit is contained in:
12
Makefile
12
Makefile
@@ -9,6 +9,7 @@ SOURCE_DIR := src
|
|||||||
BUILD_DIR := build
|
BUILD_DIR := build
|
||||||
|
|
||||||
CONTAINER_CMD := podman run -v "$(shell pwd)":"/scratch" \
|
CONTAINER_CMD := podman run -v "$(shell pwd)":"/scratch" \
|
||||||
|
--rm \
|
||||||
--workdir="/scratch" \
|
--workdir="/scratch" \
|
||||||
--network=none \
|
--network=none \
|
||||||
-e TERM \
|
-e TERM \
|
||||||
@@ -16,7 +17,7 @@ CONTAINER_CMD := podman run -v "$(shell pwd)":"/scratch" \
|
|||||||
cc-i686:latest
|
cc-i686:latest
|
||||||
|
|
||||||
QEMU := qemu-system-i386
|
QEMU := qemu-system-i386
|
||||||
QEMU_FLAGS := -d int -no-reboot
|
QEMU_FLAGS := -no-reboot -serial stdio # -d int
|
||||||
|
|
||||||
CC := $(CONTAINER_CMD) i686-elf-gcc
|
CC := $(CONTAINER_CMD) i686-elf-gcc
|
||||||
LD := $(CONTAINER_CMD) i686-elf-ld
|
LD := $(CONTAINER_CMD) i686-elf-ld
|
||||||
@@ -29,7 +30,7 @@ OBJECTS := $(patsubst $(SOURCE_DIR)/%, $(BUILD_DIR)/%, $(C_SOURCES:.c=.o) $(
|
|||||||
DEPENDS := $(patsubst $(SOURCE_DIR)/%, $(BUILD_DIR)/%, $(C_SOURCES:.c=.d))
|
DEPENDS := $(patsubst $(SOURCE_DIR)/%, $(BUILD_DIR)/%, $(C_SOURCES:.c=.d))
|
||||||
|
|
||||||
CFLAGS := -ffreestanding -nostdlib -std=c2x -MMD -I$(SOURCE_DIR)/lib/include -I$(SOURCE_DIR) -no-pie
|
CFLAGS := -ffreestanding -nostdlib -std=c2x -MMD -I$(SOURCE_DIR)/lib/include -I$(SOURCE_DIR) -no-pie
|
||||||
CFLAGS += -O1 -g3
|
CFLAGS += -O0 -g
|
||||||
CFLAGS += -Wall -Wextra -Werror
|
CFLAGS += -Wall -Wextra -Werror
|
||||||
CFLAGS += -fstack-protector-strong -g3
|
CFLAGS += -fstack-protector-strong -g3
|
||||||
CFLAGS += -Wno-unused-function
|
CFLAGS += -Wno-unused-function
|
||||||
@@ -81,10 +82,9 @@ $(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.S Makefile
|
|||||||
|
|
||||||
TEST_BUILD_DIR := $(BUILD_DIR)/tests
|
TEST_BUILD_DIR := $(BUILD_DIR)/tests
|
||||||
|
|
||||||
#TEST_SOURCES := $(shell find $(SOURCE_DIR) -name '*_test.c')
|
TEST_SOURCES := $(shell find $(SOURCE_DIR) -name '*_test.c')
|
||||||
#TEST_DEPENDS := $(patsubst $(SOURCE_DIR)/%, $(TEST_BUILD_DIR)/%, $(TEST_SOURCES:.c=.d))
|
TEST_DEPENDS := $(patsubst $(SOURCE_DIR)/%, $(TEST_BUILD_DIR)/%, $(TEST_SOURCES:.c=.d))
|
||||||
#TEST_OUTPUT := $(patsubst $(SOURCE_DIR)/%, $(TEST_BUILD_DIR)/%, $(TEST_SOURCES:.c=))
|
TEST_OUTPUT := $(patsubst $(SOURCE_DIR)/%, $(TEST_BUILD_DIR)/%, $(TEST_SOURCES:.c=))
|
||||||
|
|
||||||
|
|
||||||
tests: $(TEST_OUTPUT)
|
tests: $(TEST_OUTPUT)
|
||||||
$(info TEST_SOURCES is $(TEST_SOURCES))
|
$(info TEST_SOURCES is $(TEST_SOURCES))
|
||||||
|
|||||||
@@ -52,3 +52,71 @@ struct gdt_table_entry gdt_encode_entry(struct gdt_entry_content content)
|
|||||||
// );
|
// );
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
void gdt_flush_granular(uint32_t code,
|
||||||
|
uint32_t data,
|
||||||
|
uint32_t extra_segment,
|
||||||
|
uint32_t general_segment_1,
|
||||||
|
uint32_t general_segment_2,
|
||||||
|
uint32_t stack_segment)
|
||||||
|
{
|
||||||
|
__asm__ volatile (
|
||||||
|
// Far jump to reload the CS register
|
||||||
|
"push %[cs]\n"
|
||||||
|
"push $reload_CS_granular\n"
|
||||||
|
"retf\n"
|
||||||
|
|
||||||
|
"reload_CS_granular:\n"
|
||||||
|
"movw %[ds], %%ax\n"
|
||||||
|
"movw %%ax, %%ds\n"
|
||||||
|
"movw %[es], %%ax\n"
|
||||||
|
"movw %%ax, %%es\n"
|
||||||
|
"movw %[fs], %%ax\n"
|
||||||
|
"movw %%ax, %%fs\n"
|
||||||
|
"movw %[gs], %%ax\n"
|
||||||
|
"movw %%ax, %%gs\n"
|
||||||
|
"movw %[ss], %%ax\n"
|
||||||
|
"movw %%ax, %%ss\n"
|
||||||
|
: // No output operands
|
||||||
|
: [cs] "m"(code),
|
||||||
|
[ds] "m"(data),
|
||||||
|
[es] "m"(extra_segment),
|
||||||
|
[fs] "m"(general_segment_1),
|
||||||
|
[gs] "m"(general_segment_2),
|
||||||
|
[ss] "m"(stack_segment)
|
||||||
|
: "ax" // Clobbered register
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdt_load(struct gdt_table_entry base[], uint16_t gdt_size, segment_t data, segment_t code)
|
||||||
|
{
|
||||||
|
/* the lgdt instruction requires a packed alignment */
|
||||||
|
struct __attribute__((packed)) {
|
||||||
|
uint16_t size;
|
||||||
|
uint32_t base;
|
||||||
|
} gdt = {
|
||||||
|
.size = gdt_size,
|
||||||
|
.base = (uint32_t)base,
|
||||||
|
};
|
||||||
|
|
||||||
|
__asm__ volatile (
|
||||||
|
"lgdt %[gdt]\n"
|
||||||
|
// Far jump to reload the CS register
|
||||||
|
"push %[cs]\n"
|
||||||
|
"push $reload_CS\n"
|
||||||
|
"retf\n"
|
||||||
|
|
||||||
|
"reload_CS:\n"
|
||||||
|
// Load data segment into AX and then move it to all segment registers
|
||||||
|
"movw %[ds], %%ax\n"
|
||||||
|
"movw %%ax, %%ds\n"
|
||||||
|
"movw %%ax, %%es\n"
|
||||||
|
"movw %%ax, %%fs\n"
|
||||||
|
"movw %%ax, %%gs\n"
|
||||||
|
"movw %%ax, %%ss\n"
|
||||||
|
: // No output operands
|
||||||
|
: [gdt] "m"(gdt),
|
||||||
|
[ds] "m"(data),
|
||||||
|
[cs] "m"(code)
|
||||||
|
: "ax" // Clobbered register
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -56,64 +56,11 @@ enum gdt_flags : uint8_t {
|
|||||||
struct gdt_table_entry gdt_encode_entry(struct gdt_entry_content content);
|
struct gdt_table_entry gdt_encode_entry(struct gdt_entry_content content);
|
||||||
|
|
||||||
// only compiles with O1 or higher ¯\_(ツ)_/¯, might have to make this a macro
|
// only compiles with O1 or higher ¯\_(ツ)_/¯, might have to make this a macro
|
||||||
static inline void gdt_flush_granular(uint32_t code,
|
void gdt_flush_granular(uint32_t code,
|
||||||
uint32_t data,
|
uint32_t data,
|
||||||
uint32_t extra_segment,
|
uint32_t extra_segment,
|
||||||
uint32_t general_segment_1,
|
uint32_t general_segment_1,
|
||||||
uint32_t general_segment_2,
|
uint32_t general_segment_2,
|
||||||
uint32_t stack_segment)
|
uint32_t stack_segment);
|
||||||
{
|
|
||||||
__asm__ volatile (
|
|
||||||
// Far jump to reload the CS register
|
|
||||||
"jmp %[cs], $reload_CS\n"
|
|
||||||
"reload_CS:\n"
|
|
||||||
"movw %[ds], %%ax\n"
|
|
||||||
"movw %%ax, %%ds\n"
|
|
||||||
"movw %[es], %%ax\n"
|
|
||||||
"movw %%ax, %%es\n"
|
|
||||||
"movw %[fs], %%ax\n"
|
|
||||||
"movw %%ax, %%fs\n"
|
|
||||||
"movw %[gs], %%ax\n"
|
|
||||||
"movw %%ax, %%gs\n"
|
|
||||||
"movw %[ss], %%ax\n"
|
|
||||||
"movw %%ax, %%ss\n"
|
|
||||||
: // No output operands
|
|
||||||
: [cs] "i"(code),
|
|
||||||
[ds] "i"(data),
|
|
||||||
[es] "i"(extra_segment),
|
|
||||||
[fs] "i"(general_segment_1),
|
|
||||||
[gs] "i"(general_segment_2),
|
|
||||||
[ss] "i"(stack_segment)
|
|
||||||
: "ax" // Clobbered register
|
|
||||||
);
|
|
||||||
}
|
|
||||||
static inline void gdt_load(struct gdt_table_entry base[], uint16_t gdt_size, segment_t data, segment_t code)
|
|
||||||
{
|
|
||||||
/* the lgdt instruction requires a packed alignment */
|
|
||||||
struct __attribute__((packed)) {
|
|
||||||
uint16_t size;
|
|
||||||
uint32_t base;
|
|
||||||
} gdt = {
|
|
||||||
.size = gdt_size,
|
|
||||||
.base = (uint32_t)base,
|
|
||||||
};
|
|
||||||
|
|
||||||
__asm__ volatile (
|
void gdt_load(struct gdt_table_entry base[], uint16_t gdt_size, segment_t data, segment_t code);
|
||||||
"lgdt %[gdt]\n"
|
|
||||||
// Far jump to reload the CS register
|
|
||||||
"jmp %[cs], $reload_CS\n"
|
|
||||||
"reload_CS:\n"
|
|
||||||
// Load data segment into AX and then move it to all segment registers
|
|
||||||
"movw %[ds], %%ax\n"
|
|
||||||
"movw %%ax, %%ds\n"
|
|
||||||
"movw %%ax, %%es\n"
|
|
||||||
"movw %%ax, %%fs\n"
|
|
||||||
"movw %%ax, %%gs\n"
|
|
||||||
"movw %%ax, %%ss\n"
|
|
||||||
: // No output operands
|
|
||||||
: [gdt] "m"(gdt),
|
|
||||||
[ds] "i"(data),
|
|
||||||
[cs] "i"(code)
|
|
||||||
: "ax" // Clobbered register
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -17,16 +17,15 @@ struct __attribute__((packed)) interrupt_frame {
|
|||||||
uword_t ss;
|
uword_t ss;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void print_interrupt_frame(struct interrupt_frame* f)
|
void print_interrupt_frame(struct interrupt_frame* f)
|
||||||
{
|
{
|
||||||
printf(str_attach(
|
printf(str_attach(
|
||||||
"Interrupt frame:\n"
|
"Interrupt frame:\n"
|
||||||
"================\n"
|
" - ip: {x32}\n"
|
||||||
"ip: {x32}\n"
|
" - cs: {x32} ({cs})\n"
|
||||||
"cs: {x32} == {cs}\n"
|
" - flags: {x32}\n"
|
||||||
"flags: {x32}\n"
|
" - sp: {x32}\n"
|
||||||
"sp: {x32}\n"
|
" - ss: {x32}\n"),
|
||||||
"ss: {x32}\n"),
|
|
||||||
f->ip,
|
f->ip,
|
||||||
f->cs,
|
f->cs,
|
||||||
f->flags,
|
f->flags,
|
||||||
@@ -106,38 +105,51 @@ void exception_handler_page_fault(struct interrupt_frame* frame, int err)
|
|||||||
}
|
}
|
||||||
terminal_set_color(VGA_COLOR_WHITE, VGA_COLOR_RED);
|
terminal_set_color(VGA_COLOR_WHITE, VGA_COLOR_RED);
|
||||||
printf(str_attach(
|
printf(str_attach(
|
||||||
"page fault :(, err: 0x{x32}: ["),
|
"=============\n"
|
||||||
|
"PAGE FAULT :(\n"
|
||||||
|
"=============\n"
|
||||||
|
"Error: 0x{x32}: \n"),
|
||||||
err);
|
err);
|
||||||
|
|
||||||
/* page fault error bits */
|
/* page fault error bits */
|
||||||
enum {
|
enum {
|
||||||
present = 1<<0,
|
present = 0,
|
||||||
write = 1<<1,
|
write = 1,
|
||||||
user = 1<<2,
|
user = 2,
|
||||||
reserved_write = 1<<3,
|
reserved_write = 3,
|
||||||
instruction_fetch = 1<<4,
|
instruction_fetch = 4,
|
||||||
protection_key = 1<<5,
|
protection_key = 5,
|
||||||
shadow_stack = 1<<6,
|
shadow_stack = 6,
|
||||||
software_guard_ex = 1<<15,
|
software_guard_ex = 15,
|
||||||
|
|
||||||
|
page_fault_error_count
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct str error_names[] = {
|
static const struct str error_flag_str[page_fault_error_count] = {
|
||||||
[0] = str_attach("present"),
|
[present] = str_attach("Caused by a page-protection violation"),
|
||||||
[1] = str_attach("write"),
|
[write] = str_attach("Caused by a write access"),
|
||||||
[2] = str_attach("user"),
|
[user] = str_attach("Caused while CPL == 3 (not neccessarily a privilige escalation)"),
|
||||||
[3] = str_attach("reserved_write"),
|
[reserved_write] = str_attach("One or more page directory entries contain reserved bits which are set to 1"),
|
||||||
[4] = str_attach("instruction_fetch"),
|
[instruction_fetch] = str_attach("Caused by an instruction fetch"),
|
||||||
[5] = str_attach("protection_key"),
|
[protection_key] = str_attach("Caused by a protection-key violation"),
|
||||||
[6] = str_attach("shadow_stack"),
|
[shadow_stack] = str_attach("Caused by a shadow stack access"),
|
||||||
[15] = str_attach("software_guard_ex"),
|
[software_guard_ex] = str_attach("Caused by an SGX violation"),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof error_names / sizeof *error_names; i++) {
|
static const struct str error_flag_zero_str[page_fault_error_count] = {
|
||||||
if ((err & (1<<i)) && error_names[i].data) {
|
[present] = str_attach("Caused by a non-present page"),
|
||||||
printf(str_attach("{str} | "), error_names[i]);
|
[write] = str_attach("Caused by a read access"),
|
||||||
|
[user] = str_attach("Caused while CPL != 3"),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < page_fault_error_count; i++) {
|
||||||
|
if ((err & (1<<i)) && error_flag_str[i].data) {
|
||||||
|
printf(str_attach(" - {str}\n"), error_flag_str[i]);
|
||||||
|
} else if (error_flag_zero_str[i].data) {
|
||||||
|
printf(str_attach(" - {str}\n"), error_flag_zero_str[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf(str_attach("0]\n"));
|
printf(str_attach("\n"));
|
||||||
|
|
||||||
print_interrupt_frame(frame);
|
print_interrupt_frame(frame);
|
||||||
|
|
||||||
@@ -161,18 +173,6 @@ void interrupt_default(struct interrupt_frame* frame)
|
|||||||
kernel.nested_exception_counter = 0;
|
kernel.nested_exception_counter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((interrupt))
|
|
||||||
void interrupt_handler_1(struct interrupt_frame* frame)
|
|
||||||
{
|
|
||||||
if (kernel.nested_exception_counter++ > EXCEPTION_DEPTH_MAX) {
|
|
||||||
panic(str_attach("fatal: too many nested exceptions\n"));
|
|
||||||
}
|
|
||||||
(void)frame;
|
|
||||||
printf(str_attach("interrupt_handler_1 called!\n"));
|
|
||||||
|
|
||||||
kernel.nested_exception_counter = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IRQs
|
* IRQs
|
||||||
* ====
|
* ====
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ __attribute__((interrupt, noreturn))
|
|||||||
void interrupt_default(struct interrupt_frame* frame);
|
void interrupt_default(struct interrupt_frame* frame);
|
||||||
|
|
||||||
__attribute__((interrupt))
|
__attribute__((interrupt))
|
||||||
void interrupt_handler_1(struct interrupt_frame* frame);
|
void interrupt_handler_syscall(struct interrupt_frame* frame);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IRQs
|
* IRQs
|
||||||
|
|||||||
@@ -2,35 +2,43 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "file_system.h"
|
||||||
#include "gdt.h"
|
#include "gdt.h"
|
||||||
#include "tss.h"
|
|
||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
#include "interrupts.h"
|
#include "interrupts.h"
|
||||||
#include "types.h"
|
|
||||||
#include "kernel_state.h"
|
#include "kernel_state.h"
|
||||||
#include "pic.h"
|
|
||||||
|
|
||||||
#include "page.h"
|
#include "page.h"
|
||||||
|
#include "pic.h"
|
||||||
|
#include "serial.h"
|
||||||
|
#include "tss.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
// Future user-space
|
// Future user-space
|
||||||
#include "libc.h"
|
#include "libc.h"
|
||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
#include "str.h"
|
#include "str.h"
|
||||||
#include "bitmap.h"
|
#include "bitmap.h"
|
||||||
|
#include "syscall.h"
|
||||||
|
|
||||||
uint32_t page_directory[1024] __attribute__((aligned(4096)));
|
#define syscall(number, b, c, d) \
|
||||||
uint32_t page_table[1024] __attribute__((aligned(4096)));
|
__asm__ volatile( \
|
||||||
_Static_assert(((uint32_t)page_table & 0xfff) == 0);
|
"int $0x80\n" \
|
||||||
_Static_assert(((uint32_t)page_directory & 0xfff) == 0);
|
: \
|
||||||
|
: "a"(number), \
|
||||||
|
"b"(b), \
|
||||||
|
"c"(c), \
|
||||||
|
"d"(d) \
|
||||||
|
: "memory" \
|
||||||
|
);
|
||||||
|
|
||||||
static void user_mode_code(void*)
|
static void user_mode_code(void*)
|
||||||
{
|
{
|
||||||
printf(str_attach("hello from user-space before interrupt :)\n"));
|
//printf(str_attach("hello from user-space before interrupt :)\n"));
|
||||||
__asm__ volatile ("int $0x80");
|
//__asm__ volatile ("int $0x80");
|
||||||
|
int output;
|
||||||
|
syscall(SYSCALL_PRINT, &str_attach("hello from ring 3\n"), 0, 0);
|
||||||
#if 0
|
#if 0
|
||||||
printf(str_attach("hello from user-space before exception :)\n"));
|
syscall(SYSCALL_PRINT, &str_attach("trying to divide by zero :)\n"), 0, 0);
|
||||||
/* test division by 0 exception */
|
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wdiv-by-zero"
|
#pragma GCC diagnostic ignored "-Wdiv-by-zero"
|
||||||
volatile int a = 5/0;
|
volatile int a = 5/0;
|
||||||
@@ -38,9 +46,13 @@ static void user_mode_code(void*)
|
|||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
// should not happen
|
// should not happen
|
||||||
printf(str_attach("hello from userspace after interrupt and exception!\n"));
|
syscall(SYSCALL_PRINT, &str_attach("hello from userspace after interrupt and exception!\n"), 0, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
syscall(SYSCALL_EXIT, 0, 0, 0);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ring3_mode(segment_t udata_segment, segment_t ucode_segment, func_t callback)
|
static void ring3_mode(segment_t udata_segment, segment_t ucode_segment, func_t callback)
|
||||||
@@ -60,9 +72,9 @@ static void ring3_mode(segment_t udata_segment, segment_t ucode_segment, func_t
|
|||||||
"push %[callback]\n"
|
"push %[callback]\n"
|
||||||
"iret"
|
"iret"
|
||||||
:
|
:
|
||||||
: [udata] "i"(udata_segment),
|
: [udata] "m"(udata_segment),
|
||||||
[ucode] "i"(ucode_segment),
|
[ucode] "m"(ucode_segment),
|
||||||
[callback] "i"(callback)
|
[callback] "m"(callback)
|
||||||
: "eax"
|
: "eax"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -78,6 +90,13 @@ void kernel_main(void)
|
|||||||
__asm__ volatile("cli");
|
__asm__ volatile("cli");
|
||||||
|
|
||||||
|
|
||||||
|
/* Set up the serial port
|
||||||
|
* ======================
|
||||||
|
*/
|
||||||
|
if (serial_init(SERIAL_COM1, 3) != 0) {
|
||||||
|
panic(str_attach("serial_init failed"));
|
||||||
|
}
|
||||||
|
|
||||||
/* Set up the GDT
|
/* Set up the GDT
|
||||||
* ============== */
|
* ============== */
|
||||||
kernel.gdt[SEGMENT_NULL] = gdt_encode_entry((struct gdt_entry_content){0});
|
kernel.gdt[SEGMENT_NULL] = gdt_encode_entry((struct gdt_entry_content){0});
|
||||||
@@ -190,7 +209,7 @@ void kernel_main(void)
|
|||||||
kernel.idt[IDT_DESC_PIC2 + 7] = mint(irq_handler_15);
|
kernel.idt[IDT_DESC_PIC2 + 7] = mint(irq_handler_15);
|
||||||
|
|
||||||
/* Interrupts */
|
/* Interrupts */
|
||||||
kernel.idt[IDT_DESC_INTERRUPT_SYSCALL] = mint(interrupt_handler_1);
|
kernel.idt[IDT_DESC_INTERRUPT_SYSCALL] = mint(interrupt_handler_syscall);
|
||||||
#undef mtrap
|
#undef mtrap
|
||||||
#undef mint
|
#undef mint
|
||||||
#undef m_idt_default
|
#undef m_idt_default
|
||||||
@@ -208,7 +227,17 @@ void kernel_main(void)
|
|||||||
/* enable interrupts */
|
/* enable interrupts */
|
||||||
__asm__ volatile("sti");
|
__asm__ volatile("sti");
|
||||||
|
|
||||||
printf(str_attach("setting up paging...\n"));
|
/*
|
||||||
|
* File system setup
|
||||||
|
* =================
|
||||||
|
* */
|
||||||
|
printf(str_attach("Testing file system...\n"));
|
||||||
|
{
|
||||||
|
int ok = test_file_system();
|
||||||
|
if (ok != 0) {
|
||||||
|
panic(str_attach("test_file_system() returned non-zero value"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Paging setup
|
* Paging setup
|
||||||
@@ -216,24 +245,35 @@ void kernel_main(void)
|
|||||||
* We align by 1<<12 because page directory and page table entries store
|
* We align by 1<<12 because page directory and page table entries store
|
||||||
* addresses from bit 12-31
|
* addresses from bit 12-31
|
||||||
*
|
*
|
||||||
* For now give user access to pages to avoid a page fault
|
* For now give user access to pages to avoid a page fault, since it's not
|
||||||
|
* implemented properly
|
||||||
*/
|
*/
|
||||||
for (size_t i = 0; i < sizeof page_table / sizeof *page_table; i++) {
|
printf(str_attach("setting up paging...\n"));
|
||||||
page_directory[i] = PDE_WRITE;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof page_table / sizeof *page_table; i++) {
|
static uint32_t page_directory[1024] __attribute__((aligned(4096)));
|
||||||
page_table[i] = PTE_ADDRESS(i) | PTE_WRITE | PTE_PRESENT | PTE_USER;
|
static uint32_t page_table_0[1024] __attribute__((aligned(4096)));
|
||||||
}
|
_Static_assert(((uint32_t)page_directory & 0xfff) == 0);
|
||||||
|
_Static_assert(((uint32_t)page_table_0 & 0xfff) == 0);
|
||||||
|
|
||||||
page_directory[0] = ((uint32_t)page_table) | PDE_WRITE | PDE_PRESENT | PDE_USER_ACCESS;
|
for (size_t i = 0; i < sizeof page_directory / sizeof *page_directory; i++) {
|
||||||
|
page_directory[i] = PDE_WRITE; /* no present bit */
|
||||||
|
}
|
||||||
|
page_directory[1023] = (uint32_t)page_directory;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < sizeof page_table_0 / sizeof *page_table_0; i++) {
|
||||||
|
// for now this page table allows user-space code to access
|
||||||
|
// kernel-space memory (PTE_USER)
|
||||||
|
page_table_0[i] = PTE_ADDRESS(i) | PTE_WRITE | PTE_PRESENT | PTE_USER;
|
||||||
|
}
|
||||||
|
page_directory[0] = ((uint32_t)page_table_0) | PDE_WRITE | PDE_PRESENT | PDE_USER_ACCESS;
|
||||||
|
|
||||||
cr3_set((uint32_t)page_directory);
|
cr3_set((uint32_t)page_directory);
|
||||||
cr0_flags_set(CR0_PAGING);
|
cr0_flags_set(CR0_PAGING | CR0_PROTECTED_MODE);
|
||||||
|
|
||||||
printf(str_attach("done!\n"));
|
printf(str_attach("done!\n"));
|
||||||
|
|
||||||
printf(str_attach("starting code in ring 3...\n"));
|
printf(str_attach("starting code in ring 3...\n"));
|
||||||
|
|
||||||
/* Finally go to ring 3 */
|
/* Finally go to ring 3 */
|
||||||
ring3_mode(segment(SEGMENT_USER_DATA, SEGMENT_GDT, 3),
|
ring3_mode(segment(SEGMENT_USER_DATA, SEGMENT_GDT, 3),
|
||||||
segment(SEGMENT_USER_CODE, SEGMENT_GDT, 3),
|
segment(SEGMENT_USER_CODE, SEGMENT_GDT, 3),
|
||||||
@@ -241,9 +281,6 @@ void kernel_main(void)
|
|||||||
|
|
||||||
printf(str_attach("back to kernel mode...\n"));
|
printf(str_attach("back to kernel mode...\n"));
|
||||||
|
|
||||||
while (1)
|
|
||||||
/* busy loop */;
|
|
||||||
|
|
||||||
__asm__ volatile ("hlt");
|
__asm__ volatile ("hlt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,24 @@ enum idt_desc_index : size_t {
|
|||||||
|
|
||||||
/* IRQ offsets */
|
/* IRQ offsets */
|
||||||
IDT_DESC_PIC1 = 32,
|
IDT_DESC_PIC1 = 32,
|
||||||
IDT_DESC_PIC2 = IDT_DESC_PIC1 + 8,
|
IDT_DESC_TIMER = IDT_DESC_PIC1 + 0,
|
||||||
|
IDT_DESC_KEYBOARD = IDT_DESC_PIC1 + 1,
|
||||||
|
IDT_DESC_CASCADE = IDT_DESC_PIC1 + 2,
|
||||||
|
IDT_DESC_COM2 = IDT_DESC_PIC1 + 3,
|
||||||
|
IDT_DESC_COM1 = IDT_DESC_PIC1 + 4,
|
||||||
|
IDT_DESC_LPT2 = IDT_DESC_PIC1 + 5,
|
||||||
|
IDT_DESC_FLOPPY_DISK = IDT_DESC_PIC1 + 6,
|
||||||
|
IDT_DESC_SPURIOUS = IDT_DESC_PIC1 + 7,
|
||||||
|
|
||||||
|
IDT_DESC_PIC2 = 40,
|
||||||
|
IDT_DESC_CMOS = IDT_DESC_PIC2 + 0,
|
||||||
|
IDT_DESC_FREE1 = IDT_DESC_PIC2 + 1,
|
||||||
|
IDT_DESC_FREE2 = IDT_DESC_PIC2 + 2,
|
||||||
|
IDT_DESC_FREE3 = IDT_DESC_PIC2 + 3,
|
||||||
|
IDT_DESC_PS2_MOUSE = IDT_DESC_PIC2 + 4,
|
||||||
|
IDT_DESC_FPU = IDT_DESC_PIC2 + 5,
|
||||||
|
IDT_DESC_ATA1 = IDT_DESC_PIC2 + 6,
|
||||||
|
IDT_DESC_ATA2 = IDT_DESC_PIC2 + 7,
|
||||||
|
|
||||||
/* Software Interrupts */
|
/* Software Interrupts */
|
||||||
IDT_DESC_INTERRUPT_SYSCALL = 128,
|
IDT_DESC_INTERRUPT_SYSCALL = 128,
|
||||||
|
|||||||
@@ -67,25 +67,25 @@ void pic8259_clear_irq_mask(uint16_t mask)
|
|||||||
* https://wiki.osdev.org/8259_PIC#ISR_and_IRR
|
* https://wiki.osdev.org/8259_PIC#ISR_and_IRR
|
||||||
* ===========================================
|
* ===========================================
|
||||||
* */
|
* */
|
||||||
static uint16_t get_irq_reg(int ocw3)
|
//static uint16_t get_irq_reg(int ocw3)
|
||||||
{
|
//{
|
||||||
/* OCW3 to PIC CMD to get the register values. PIC2 is chained, and
|
// /* OCW3 to PIC CMD to get the register values. PIC2 is chained, and
|
||||||
represents IRQs 8-15. PIC1 is IRQs 0-7, with 2 being the chain */
|
// represents IRQs 8-15. PIC1 is IRQs 0-7, with 2 being the chain */
|
||||||
outb(PIC1_COMMAND, ocw3);
|
// outb(PIC1_COMMAND, ocw3);
|
||||||
outb(PIC2_COMMAND, ocw3);
|
// outb(PIC2_COMMAND, ocw3);
|
||||||
return (inb(PIC2_COMMAND) << 8) | inb(PIC1_COMMAND);
|
// return (inb(PIC2_COMMAND) << 8) | inb(PIC1_COMMAND);
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
/* Returns the combined value of the cascaded PICs irq request register */
|
///* Returns the combined value of the cascaded PICs irq request register */
|
||||||
uint16_t pic8259_get_irr(void)
|
//uint16_t pic8259_get_irr(void)
|
||||||
{
|
//{
|
||||||
return get_irq_reg(OCW3_READ_IRR);
|
// return get_irq_reg(OCW3_READ_IRR);
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
/* Returns the combined value of the cascaded PICs in-service register */
|
///* Returns the combined value of the cascaded PICs in-service register */
|
||||||
uint16_t pic8259_get_isr(void)
|
//uint16_t pic8259_get_isr(void)
|
||||||
{
|
//{
|
||||||
return get_irq_reg(OCW3_READ_ISR);
|
// return get_irq_reg(OCW3_READ_ISR);
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
/* =========================================== */
|
///* =========================================== */
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "str.h"
|
#include "str.h"
|
||||||
|
#include "serial.h"
|
||||||
|
|
||||||
enum pic8259_port : uint16_t {
|
enum pic8259_port : uint16_t {
|
||||||
PIC1_COMMAND = 0x20,
|
PIC1_COMMAND = 0x20,
|
||||||
@@ -141,29 +142,6 @@ enum ocw3_command : uint8_t {
|
|||||||
OCW3_SET_SPECIAL_MASK = (1<<3) | OCW3_BIT_ESMM | OCW3_BIT_SMM,
|
OCW3_SET_SPECIAL_MASK = (1<<3) | OCW3_BIT_ESMM | OCW3_BIT_SMM,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void outb(uint16_t port, uint8_t signal)
|
|
||||||
{
|
|
||||||
__asm__ volatile ("outb %[signal], %[port]"
|
|
||||||
:
|
|
||||||
: [signal] "a" (signal),
|
|
||||||
[port] "Nd" (port)
|
|
||||||
: "memory");
|
|
||||||
#ifdef ADD_IO_WAIT
|
|
||||||
/* do an I/O operation on an unused port to wait 1-4 microseconds */
|
|
||||||
outb(0x80, 0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint8_t inb(uint16_t port)
|
|
||||||
{
|
|
||||||
uint8_t ret;
|
|
||||||
__asm__ volatile ( "inb %w1, %b0"
|
|
||||||
: "=a"(ret)
|
|
||||||
: "Nd"(port)
|
|
||||||
: "memory");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pic8259_remap(int offset1, int offset2);
|
void pic8259_remap(int offset1, int offset2);
|
||||||
|
|
||||||
void pic8259_set_irq_mask(uint16_t mask);
|
void pic8259_set_irq_mask(uint16_t mask);
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
#include "libc.h"
|
#include "libc.h"
|
||||||
|
|
||||||
|
#include "serial.h"
|
||||||
|
|
||||||
static struct terminal_state t = {
|
static struct terminal_state t = {
|
||||||
.row = 0,
|
.row = 0,
|
||||||
.column = 0,
|
.column = 0,
|
||||||
@@ -62,6 +64,8 @@ void terminal_scroll(int n)
|
|||||||
|
|
||||||
void terminal_putchar(int c)
|
void terminal_putchar(int c)
|
||||||
{
|
{
|
||||||
|
serial_putchar(SERIAL_COM1, c);
|
||||||
|
|
||||||
/* clear the cursor marker */
|
/* clear the cursor marker */
|
||||||
terminal_putentryat(' ', t.color, t.column, t.row);
|
terminal_putentryat(' ', t.color, t.column, t.row);
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#include "bitmap.h"
|
#include "bitmap.h"
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
static constexpr struct bitmap B = {0};
|
static constexpr struct bitmap B = {0}; /* <-- just used on the line below */
|
||||||
static constexpr size_t bits_per_index = sizeof (B.data[0]) * CHAR_BIT;
|
static constexpr size_t bits_per_index = sizeof (B.data[0]) * CHAR_BIT;
|
||||||
|
|
||||||
#define mask(n) ((1<<(n))-1)
|
#define mask(n) ((1<<(n))-1)
|
||||||
@@ -16,6 +16,19 @@ static inline int trailing_zeroes(int n)
|
|||||||
return __builtin_ctz(n);
|
return __builtin_ctz(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bitmap_find(const struct bitmap* bitmap, int val)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < bitmap->bit_count / bits_per_index; i++) {
|
||||||
|
auto x = val == 0
|
||||||
|
? ~bitmap->data[i]
|
||||||
|
: bitmap->data[i];
|
||||||
|
if (x != 0) {
|
||||||
|
return i * bits_per_index + trailing_zeroes(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int bitmap_set_range(struct bitmap* bitmap, size_t begin, size_t end)
|
int bitmap_set_range(struct bitmap* bitmap, size_t begin, size_t end)
|
||||||
{
|
{
|
||||||
if (end < begin) {
|
if (end < begin) {
|
||||||
|
|||||||
@@ -292,5 +292,24 @@ int main()
|
|||||||
|
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
|
test_begin("test bitmap_find()");
|
||||||
|
do {
|
||||||
|
uint32_t data[4] = {0};
|
||||||
|
struct bitmap b = BITMAP_ATTACH(data, sizeof data);
|
||||||
|
constexpr size_t pos = 42;
|
||||||
|
int ok = bitmap_set(&b, pos);
|
||||||
|
if (ok != 0) {
|
||||||
|
test_fail("bitmap_set() failed while testing bitmap_find()");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int found = bitmap_find(&b, 1);
|
||||||
|
if (found != pos) {
|
||||||
|
test_fail("bitmap_find() failed, expected %zu, got %i", pos, found);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
test_ok("bitmap_find() ok! pos: %zu, found: %i", pos, found);
|
||||||
|
} while (0);
|
||||||
|
|
||||||
return g_status;
|
return g_status;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,10 +14,12 @@ struct bitmap {
|
|||||||
* buf_size: size of buffer in bytes */
|
* buf_size: size of buffer in bytes */
|
||||||
#define BITMAP_ATTACH(buf, buf_size) (struct bitmap){.bit_count = buf_size * CHAR_BIT, .data = buf}
|
#define BITMAP_ATTACH(buf, buf_size) (struct bitmap){.bit_count = buf_size * CHAR_BIT, .data = buf}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the bit value at `index`
|
||||||
|
* */
|
||||||
static inline int bitmap_set(struct bitmap* bitmap, size_t index)
|
static inline int bitmap_set(struct bitmap* bitmap, size_t index)
|
||||||
{
|
{
|
||||||
constexpr size_t bits_per_index = sizeof (bitmap->data[0]) * CHAR_BIT;
|
constexpr size_t bits_per_index = sizeof (bitmap->data[0]) * CHAR_BIT;
|
||||||
_Static_assert(bits_per_index == 32);
|
|
||||||
if (unlikely(index > bitmap->bit_count)) {
|
if (unlikely(index > bitmap->bit_count)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -25,6 +27,9 @@ static inline int bitmap_set(struct bitmap* bitmap, size_t index)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unset the bit value at `index`
|
||||||
|
* */
|
||||||
static inline int bitmap_unset(struct bitmap* bitmap, size_t index)
|
static inline int bitmap_unset(struct bitmap* bitmap, size_t index)
|
||||||
{
|
{
|
||||||
constexpr size_t bits_per_index = sizeof (bitmap->data[0]) * CHAR_BIT;
|
constexpr size_t bits_per_index = sizeof (bitmap->data[0]) * CHAR_BIT;
|
||||||
@@ -35,7 +40,10 @@ static inline int bitmap_unset(struct bitmap* bitmap, size_t index)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int bitmap_get(struct bitmap* bitmap, size_t index)
|
/*
|
||||||
|
* Get the bit value at `index`
|
||||||
|
* */
|
||||||
|
static inline int bitmap_get(const struct bitmap* bitmap, size_t index)
|
||||||
{
|
{
|
||||||
constexpr size_t bits_per_index = sizeof (bitmap->data[0]) * CHAR_BIT;
|
constexpr size_t bits_per_index = sizeof (bitmap->data[0]) * CHAR_BIT;
|
||||||
if (unlikely(index > bitmap->bit_count)) {
|
if (unlikely(index > bitmap->bit_count)) {
|
||||||
@@ -44,6 +52,23 @@ static inline int bitmap_get(struct bitmap* bitmap, size_t index)
|
|||||||
return !!(bitmap->data[index / bits_per_index] & (1ULL << (index % bits_per_index)));
|
return !!(bitmap->data[index / bits_per_index] & (1ULL << (index % bits_per_index)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finds the index of a bit with value `val`.
|
||||||
|
* Returns -1 if none are found
|
||||||
|
* */
|
||||||
|
int bitmap_find(const struct bitmap* bitmap, int val);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets the range begin..end, end exclusive
|
||||||
|
*/
|
||||||
int bitmap_set_range(struct bitmap* bitmap, size_t begin, size_t end);
|
int bitmap_set_range(struct bitmap* bitmap, size_t begin, size_t end);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clears the range begin..end, end exclusive
|
||||||
|
*/
|
||||||
int bitmap_clear_range(struct bitmap* bitmap, size_t begin, size_t end);
|
int bitmap_clear_range(struct bitmap* bitmap, size_t begin, size_t end);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns true if a range is empty
|
||||||
|
*/
|
||||||
int bitmap_range_empty(struct bitmap* bitmap, size_t begin, size_t end);
|
int bitmap_range_empty(struct bitmap* bitmap, size_t begin, size_t end);
|
||||||
|
|||||||
@@ -1,11 +1,21 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "str.h"
|
#include "str.h"
|
||||||
|
|
||||||
__attribute__((noreturn))
|
__attribute__((noreturn))
|
||||||
void panic(struct str s);
|
void panic(struct str s);
|
||||||
|
|
||||||
|
/* bit_ceil returns the smallest power of 2 greater than `n` */
|
||||||
|
static inline uint32_t bit_ceil32(uint32_t n)
|
||||||
|
{
|
||||||
|
/* __builtin_clz is undefined for n = 0 */
|
||||||
|
return n
|
||||||
|
? 1 << (sizeof(n)*CHAR_BIT - __builtin_clz(n))
|
||||||
|
: 1;
|
||||||
|
}
|
||||||
|
|
||||||
void* memmove(void *dest, const void *src, size_t n);
|
void* memmove(void *dest, const void *src, size_t n);
|
||||||
void* memset(void *s, int c, size_t n);
|
void* memset(void *s, int c, size_t n);
|
||||||
void* memcpy(void *dest, const void *src, size_t n);
|
void* memcpy(void *dest, const void *src, size_t n);
|
||||||
|
|||||||
@@ -4,3 +4,8 @@
|
|||||||
#define likely(x) __builtin_expect(!!(x), 1)
|
#define likely(x) __builtin_expect(!!(x), 1)
|
||||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||||
|
|
||||||
|
#define MEMBER_TYPE(parent_type, member) \
|
||||||
|
typeof(((parent_type){0}).member)
|
||||||
|
|
||||||
|
#define MEMBER_SIZE(type, member) \
|
||||||
|
(sizeof (((type){0}).member))
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
#pragma once
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
struct str {
|
struct str {
|
||||||
const char* data;
|
const char* data;
|
||||||
const size_t len;
|
const size_t len;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define str_attach(cstr) (struct str){.data = cstr, .len = sizeof(cstr)-1}
|
#define str_attach(cstr) ((struct str){.data = cstr, .len = sizeof(cstr)-1})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns a slice of `s`, `end`-exclusive
|
||||||
|
* str_slice("hello", 1, 4) would return "ell"
|
||||||
|
* */
|
||||||
static inline struct str str_slice(struct str s, size_t begin, size_t end)
|
static inline struct str str_slice(struct str s, size_t begin, size_t end)
|
||||||
{
|
{
|
||||||
return (struct str) {
|
return (struct str) {
|
||||||
@@ -17,5 +22,16 @@ static inline struct str str_slice(struct str s, size_t begin, size_t end)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a and b are not equal, str_compare returns the index where a and b
|
||||||
|
* diverges. Otherwise returns -1
|
||||||
|
*/
|
||||||
|
bool str_equals(struct str a, struct str b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a and b are equals, str_compare returns true, otherwise returns false
|
||||||
|
*/
|
||||||
|
int str_compare(struct str a, struct str b);
|
||||||
|
|
||||||
#define CSTR_(x) #x
|
#define CSTR_(x) #x
|
||||||
#define CSTR(x) CSTR_(x)
|
#define CSTR(x) CSTR_(x)
|
||||||
|
|||||||
@@ -5,9 +5,15 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <limits.h>
|
||||||
#include "kernel/tty.h"
|
#include "kernel/tty.h"
|
||||||
#include "str.h"
|
#include "str.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Math functions
|
||||||
|
* ==============
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Error handling
|
* Error handling
|
||||||
* ==============
|
* ==============
|
||||||
|
|||||||
@@ -121,12 +121,22 @@ static int print_str(struct printf_state* s, int padding, char pad_char)
|
|||||||
return str.len;
|
return str.len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool isspace(char ch)
|
||||||
|
{
|
||||||
|
return ch == '\n' || ch == ' ' || ch == '\t';
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isprint(char ch)
|
||||||
|
{
|
||||||
|
return (ch >= 32 && ch < 127) || isspace(ch);
|
||||||
|
}
|
||||||
|
|
||||||
static int print_char(struct printf_state* s)
|
static int print_char(struct printf_state* s)
|
||||||
{
|
{
|
||||||
// char is promoted to int when passed through va_arg
|
// char is promoted to int when passed through va_arg
|
||||||
const int ch = va_arg(s->ap, int);
|
const int ch = va_arg(s->ap, int);
|
||||||
|
|
||||||
if (ch >= 32 && ch < 127) {
|
if (isprint(ch)) {
|
||||||
terminal_putchar(ch);
|
terminal_putchar(ch);
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
@@ -134,6 +144,30 @@ static int print_char(struct printf_state* s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int print_cstr(struct printf_state* s, int padding, char pad_char)
|
||||||
|
{
|
||||||
|
// TODO: implement padding
|
||||||
|
(void)padding;
|
||||||
|
(void)pad_char;
|
||||||
|
|
||||||
|
const char* cstr = va_arg(s->ap, const char*);
|
||||||
|
char ch;
|
||||||
|
int written = 0;
|
||||||
|
while ((ch = *(cstr++))) {
|
||||||
|
if (isprint(ch)) {
|
||||||
|
terminal_putchar(ch);
|
||||||
|
} else {
|
||||||
|
terminal_putchar('{');
|
||||||
|
written += print_long(ch, str_attach("0123456789ABCDEF"), false, 0, 0);
|
||||||
|
terminal_putchar('}');
|
||||||
|
written += 2;
|
||||||
|
}
|
||||||
|
written += 1;
|
||||||
|
}
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cs register */
|
||||||
static int print_cs(struct printf_state* s)
|
static int print_cs(struct printf_state* s)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
@@ -161,7 +195,7 @@ static int print_cs(struct printf_state* s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsigned int ring = (cs>>5) & 0b11;
|
unsigned int ring = (cs>>5) & 0b11;
|
||||||
n = printf(str_attach("DPL({uint})"), ring);
|
n = printf(str_attach("DPL:{uint}"), ring);
|
||||||
if (n == -1) {
|
if (n == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -206,6 +240,9 @@ static int parse_format_cmd(struct printf_state* s)
|
|||||||
case 'x32':
|
case 'x32':
|
||||||
return print_x32(s, pad, pad_char);
|
return print_x32(s, pad, pad_char);
|
||||||
|
|
||||||
|
case 'cstr':
|
||||||
|
return print_cstr(s, pad, pad_char);
|
||||||
|
|
||||||
case 'str':
|
case 'str':
|
||||||
return print_str(s, pad, pad_char);
|
return print_str(s, pad, pad_char);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
#include "str.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
int str_compare(struct str a, struct str b)
|
||||||
|
{
|
||||||
|
const size_t min_len = a.len > b.len
|
||||||
|
? b.len
|
||||||
|
: a.len;
|
||||||
|
for (size_t i = 0; i < min_len; i++) {
|
||||||
|
if (a.data[i] != b.data[i]) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool str_equals(struct str a, struct str b)
|
||||||
|
{
|
||||||
|
if (a.len != b.len) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str_compare(a, b) == -1;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user