Compare commits
14 commits
dea2d91cdd
...
5ac28f75ee
| Author | SHA1 | Date | |
|---|---|---|---|
| 5ac28f75ee | |||
| 1844224924 | |||
| 0e730bf6ba | |||
| a32efe8e39 | |||
| 4032d153e0 | |||
| dc146741a4 | |||
| 683a125b0e | |||
| d834536e79 | |||
| 371ef3d571 | |||
| ea76c409c3 | |||
| dbcd40f3d7 | |||
| df294bc125 | |||
| 45a3549050 | |||
| 6a424beb6a |
15 changed files with 521 additions and 198 deletions
4
.gdbinit
Normal file
4
.gdbinit
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
file build/boot/sys/core
|
||||
target remote :3117
|
||||
b _start
|
||||
c
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,3 +1,5 @@
|
|||
config.mk
|
||||
build/
|
||||
drive.img
|
||||
/compile_commands.json
|
||||
/opt
|
||||
|
|
|
|||
3
Makefile
3
Makefile
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
include config.mk
|
||||
|
||||
CFLAGS += -ggdb
|
||||
|
||||
# Kernel sources which are specific to the x86_64 architecture.
|
||||
# Add new source files (C or Assembler) here,
|
||||
# preferentially in alphabetical order.
|
||||
|
|
@ -16,7 +18,6 @@ KERNEL_SOURCES_x86_64 := \
|
|||
# preferentially in alphabetical order.
|
||||
KERNEL_SOURCES := \
|
||||
src/kernel.c \
|
||||
src/output.c \
|
||||
src/pci.c \
|
||||
src/tar.c \
|
||||
src/std.c \
|
||||
|
|
|
|||
3
debug-run-qemu.sh
Executable file
3
debug-run-qemu.sh
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
|
||||
qemu-system-x86_64 -drive if=ide,format=raw,file=build/disk.img -drive if=virtio,media=disk,format=raw,file=drive.img "$@" -S -gdb tcp::3117
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
#ifndef KARLOS_OUTPUT_H
|
||||
#define KARLOS_OUTPUT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void putc(char c);
|
||||
void puts(const char *s);
|
||||
void println(const char *s);
|
||||
__attribute__((noreturn))
|
||||
void panic(const char *msg);
|
||||
void assert(bool cond, const char *msg);
|
||||
void print_u8x(uint8_t value);
|
||||
void print_u16x(uint16_t value);
|
||||
void print_u32x(uint32_t value);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef KARLOS_PCI_H
|
||||
#define KARLOS_PCI_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uint16_t pci_bdf_make(uint8_t bus, uint8_t dev, uint8_t fun);
|
||||
uint32_t pci_config_read_u32(uint16_t bdf, uint8_t offset);
|
||||
uint16_t pci_config_read_u16(uint16_t bdf, uint8_t offset);
|
||||
|
|
@ -9,14 +11,14 @@ void pci_config_write_u32(uint16_t bdf, uint8_t offset, uint32_t value);
|
|||
struct pci_bar_desc {
|
||||
#define PCI_BAR_TYPE_MEM 0
|
||||
#define PCI_BAR_TYPE_IO 1
|
||||
uint8_t type;
|
||||
uint8_t type;
|
||||
#define PCI_BAR_LOCATABLE_32 0
|
||||
#define PCI_BAR_LOCATABLE_SMALL 1
|
||||
#define PCI_BAR_LOCATABLE_64 2
|
||||
uint8_t locatable;
|
||||
uint8_t prefetchable;
|
||||
uint32_t address;
|
||||
uint32_t length;
|
||||
uint8_t locatable;
|
||||
uint8_t prefetchable;
|
||||
uint32_t address;
|
||||
uint32_t length;
|
||||
};
|
||||
|
||||
struct pci_bar_desc pci_bar_desc_read(uint16_t bdf, uint8_t barnum);
|
||||
|
|
|
|||
|
|
@ -2,8 +2,52 @@
|
|||
#define KARLOS_STD_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Memory functions
|
||||
void *memset(void *ptr, int value, size_t num);
|
||||
void *memcpy(void *dest, const void *src, size_t n);
|
||||
int memcmp(const void *ptr, const void *ptr2, size_t num);
|
||||
void *memmove(void *dest, const void *src, size_t num);
|
||||
|
||||
// String functions
|
||||
unsigned int strlen(const char *s);
|
||||
bool streq(const char *a, const char *b);
|
||||
void memcpy(void *dst, const void *src, unsigned int n);
|
||||
bool strcontains(const char *s, char c);
|
||||
|
||||
#endif
|
||||
// Low-level output functions
|
||||
void putc(char c);
|
||||
void putln(void);
|
||||
void puts(const char *s);
|
||||
void putsln(const char *s);
|
||||
void put_charbuf(const char *buf, unsigned int len);
|
||||
void putu8x(uint8_t value);
|
||||
void putu16x(uint16_t value);
|
||||
void putu32x(uint32_t value);
|
||||
void putu64x(uint64_t value);
|
||||
|
||||
// String and conversion utilities
|
||||
void itoa(int value, unsigned int base, char *buffer);
|
||||
void utoa(unsigned int value, unsigned int base, char *buffer);
|
||||
void itoa_ll(long long value, unsigned int base, char *buffer);
|
||||
void utoa_ll(unsigned long long value, unsigned int base, char *buffer);
|
||||
unsigned int toa_buf_size(unsigned int bits, unsigned int base);
|
||||
|
||||
// Formatted output
|
||||
void printf(const char *format, ...);
|
||||
|
||||
// Debug helpers
|
||||
#define PANIC(msg) panic(__FILE__, __LINE__, msg)
|
||||
#define ASSERT(cond) do {\
|
||||
if (!(cond)) {\
|
||||
PANIC("assertion failed: " #cond);\
|
||||
}\
|
||||
} while (0)
|
||||
#define TODO() PANIC("not implemented")
|
||||
#define UNREACHABLE() PANIC("unreachable")
|
||||
// don't use this directly, use the macros above
|
||||
__attribute__ ((noreturn))
|
||||
void panic(const char *file, unsigned int line, const char *msg);
|
||||
|
||||
#endif // KARLOS_UTILITY_H
|
||||
|
|
|
|||
72
src/kernel.c
72
src/kernel.c
|
|
@ -28,26 +28,27 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bootboot.h"
|
||||
#include "output.h"
|
||||
|
||||
#include "x86_64/mem.h"
|
||||
#include "x86_64/asm.h"
|
||||
#include "bootboot.h"
|
||||
#include "pci.h"
|
||||
#include "std.h"
|
||||
#include "tar.h"
|
||||
|
||||
/* imported virtual addresses, see linker script */
|
||||
extern BOOTBOOT bootboot; // see bootboot.h
|
||||
extern BOOTBOOT bootboot; // see bootboot.h
|
||||
extern unsigned char environment[4096]; // configuration, UTF-8 text key=value pairs
|
||||
extern uint8_t fb; // linear framebuffer mapped
|
||||
|
||||
void print_virtio_blk_bars() {
|
||||
uint16_t bdf;
|
||||
if (pci_search(0x1AF4, 0x1001, &bdf) && pci_search(0x1AF4, 0x1042, &bdf)) {
|
||||
panic("couldn't find virtio_blk device!");
|
||||
PANIC("couldn't find virtio_blk device!");
|
||||
}
|
||||
puts("found virtio_blk device at bdf ");
|
||||
print_u16x(bdf);
|
||||
println(".");
|
||||
putu16x(bdf);
|
||||
printf(".\n");
|
||||
// read BARs
|
||||
for (int i = 0; i < 6; i++) {
|
||||
struct pci_bar_desc desc = pci_bar_desc_read(bdf, i);
|
||||
|
|
@ -56,65 +57,77 @@ void print_virtio_blk_bars() {
|
|||
}
|
||||
|
||||
void check_initrd() {
|
||||
println("");
|
||||
putln();
|
||||
uint64_t printed_in_line = 0;
|
||||
for (uint64_t off = 0; off < bootboot.initrd_size; off++) {
|
||||
uint8_t byte = ((uint8_t*)bootboot.initrd_ptr)[off];
|
||||
|
||||
print_u8x(byte);
|
||||
putu8x(byte);
|
||||
putc(' ');
|
||||
|
||||
if (++printed_in_line % 32 == 0) {
|
||||
printed_in_line = 0;
|
||||
println("");
|
||||
putln();
|
||||
}
|
||||
}
|
||||
println("");
|
||||
putln();
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Entry point, called by BOOTBOOT Loader *
|
||||
******************************************/
|
||||
void _start()
|
||||
{
|
||||
void _start() {
|
||||
/*** NOTE: this code runs on all cores in parallel ***/
|
||||
int x, y, s=bootboot.fb_scanline, w=bootboot.fb_width, h=bootboot.fb_height;
|
||||
int x, y, s = bootboot.fb_scanline, w = bootboot.fb_width, h = bootboot.fb_height;
|
||||
|
||||
if(s) {
|
||||
if (s) {
|
||||
// cross-hair to see screen dimension detected correctly
|
||||
for(y=0;y<h;y++) { *((uint32_t*)(&fb + s*y + (w*2)))=0x00FFFFFF; }
|
||||
for(x=0;x<w;x++) { *((uint32_t*)(&fb + s*(h/2)+x*4))=0x00FFFFFF; }
|
||||
for (y = 0; y < h; y++) {
|
||||
*((uint32_t *)(&fb + s * y + (w * 2))) = 0x000FFFFF;
|
||||
}
|
||||
for (x = 0; x < w; x++) {
|
||||
*((uint32_t *)(&fb + s * (h / 2) + x * 4)) = 0x00FFFFFF;
|
||||
}
|
||||
|
||||
// red, green, blue boxes in order
|
||||
for(y=0;y<20;y++) { for(x=0;x<20;x++) { *((uint32_t*)(&fb + s*(y+20) + (x+20)*4))=0x00FF0000; } }
|
||||
for(y=0;y<20;y++) { for(x=0;x<20;x++) { *((uint32_t*)(&fb + s*(y+20) + (x+50)*4))=0x0000FF00; } }
|
||||
for(y=0;y<20;y++) { for(x=0;x<20;x++) { *((uint32_t*)(&fb + s*(y+20) + (x+80)*4))=0x000000FF; } }
|
||||
|
||||
// say hello
|
||||
println("Hello from a simple BOOTBOOT kernel");
|
||||
for (y = 0; y < 20; y++) {
|
||||
for (x = 0; x < 20; x++) {
|
||||
*((uint32_t *)(&fb + s * (y + 20) + (x + 20) * 4)) = 0x00FF0000;
|
||||
}
|
||||
}
|
||||
for (y = 0; y < 20; y++) {
|
||||
for (x = 0; x < 20; x++) {
|
||||
*((uint32_t *)(&fb + s * (y + 20) + (x + 50) * 4)) = 0x0000FF00;
|
||||
}
|
||||
}
|
||||
for (y = 0; y < 20; y++) {
|
||||
for (x = 0; x < 20; x++) {
|
||||
*((uint32_t *)(&fb + s * (y + 20) + (x + 80) * 4)) = 0x000000FF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// memory stuff
|
||||
init_gdt();
|
||||
init_idt();
|
||||
|
||||
println("Test after init");
|
||||
printf("Test after init\n");
|
||||
|
||||
// __asm__("int $0x80" :: );
|
||||
|
||||
struct tar_header hd;
|
||||
int res = tar_get_file("hello.txt", &hd);
|
||||
assert(res == 1, "file not found");
|
||||
println(hd.name);
|
||||
print_u32x(hd.size);
|
||||
println("");
|
||||
ASSERT(res == 1);
|
||||
puts(hd.name);
|
||||
putu32x(hd.size);
|
||||
putln();
|
||||
for (uint64_t i = 0; i < hd.size; i++) {
|
||||
putc(((char *)hd.data)[i]);
|
||||
}
|
||||
println("");
|
||||
putln();
|
||||
|
||||
// hang for now
|
||||
panic("end of kernel");
|
||||
PANIC("end of kernel");
|
||||
}
|
||||
|
||||
/**************************
|
||||
|
|
@ -131,4 +144,5 @@ typedef struct {
|
|||
uint32_t width;
|
||||
uint8_t glyphs;
|
||||
} __attribute__((packed)) psf2_t;
|
||||
|
||||
extern volatile unsigned char _binary_font_psf_start;
|
||||
|
|
|
|||
61
src/output.c
61
src/output.c
|
|
@ -1,61 +0,0 @@
|
|||
#include "x86_64/uart.h"
|
||||
#include "output.h"
|
||||
|
||||
void putc(char c) {
|
||||
uart_write_char(c);
|
||||
}
|
||||
|
||||
void puts(const char *s) {
|
||||
for (const char *c = s; *c != '\0'; c++) {
|
||||
uart_write_char(*c);
|
||||
}
|
||||
}
|
||||
|
||||
void println(const char *s) {
|
||||
puts(s);
|
||||
puts("\r\n");
|
||||
}
|
||||
|
||||
__attribute__((noreturn))
|
||||
void panic(const char *msg) {
|
||||
puts("PANIC: ");
|
||||
println(msg);
|
||||
|
||||
// hang for now
|
||||
while (1);
|
||||
}
|
||||
|
||||
void assert(bool cond, const char *msg) {
|
||||
if (!cond) {
|
||||
panic(msg);
|
||||
}
|
||||
}
|
||||
|
||||
#define TO_HEX(n) (((n) < 10) ? '0' + (n) : 'a' + (n) - 10)
|
||||
|
||||
void print_u8x(uint8_t value) {
|
||||
putc('0');
|
||||
putc('x');
|
||||
putc(TO_HEX((value >> 4) & 0xf));
|
||||
putc(TO_HEX(value & 0xf));
|
||||
}
|
||||
|
||||
void print_u16x(uint16_t value) {
|
||||
putc('0');
|
||||
putc('x');
|
||||
for (int i = 0; i < 4; i++) {
|
||||
// 12 8 4 0
|
||||
uint8_t hexval = (value >> ((3 - i) << 2)) & 0xf;
|
||||
putc(TO_HEX(hexval));
|
||||
}
|
||||
}
|
||||
|
||||
void print_u32x(uint32_t value) {
|
||||
putc('0');
|
||||
putc('x');
|
||||
for (int i = 0; i < 8; i++) {
|
||||
uint8_t hexval = (value >> ((7 - i) << 2)) & 0xf;
|
||||
putc(TO_HEX(hexval));
|
||||
}
|
||||
}
|
||||
|
||||
61
src/pci.c
61
src/pci.c
|
|
@ -1,21 +1,18 @@
|
|||
#include "output.h"
|
||||
#include "pci.h"
|
||||
|
||||
#include "x86_64/asm.h"
|
||||
#include "std.h"
|
||||
|
||||
#define PCI_CONFIG_ADDR_PORT 0xCF8
|
||||
#define PCI_CONFIG_DATA_PORT 0xCFC
|
||||
|
||||
uint16_t pci_bdf_make(uint8_t bus, uint8_t dev, uint8_t fun) {
|
||||
if (dev >= 32 || fun >= 8) {
|
||||
panic("pci_bdf_make");
|
||||
}
|
||||
ASSERT(dev < 32 && fun < 8);
|
||||
return ((uint16_t)bus << 8) | ((uint16_t)dev << 3) | (uint16_t)fun;
|
||||
}
|
||||
|
||||
static uint32_t pci_address(uint16_t bdf, uint8_t offset) {
|
||||
return ((uint32_t)bdf << 8)
|
||||
| ((uint32_t)offset & 0xfc)
|
||||
| ((uint32_t)0x80000000);
|
||||
return ((uint32_t)bdf << 8) | ((uint32_t)offset & 0xfc) | ((uint32_t)0x80000000);
|
||||
}
|
||||
|
||||
uint32_t pci_config_read_u32(uint16_t bdf, uint8_t offset) {
|
||||
|
|
@ -34,29 +31,25 @@ void pci_config_write_u32(uint16_t bdf, uint8_t offset, uint32_t value) {
|
|||
}
|
||||
|
||||
struct pci_bar_desc pci_bar_desc_read(uint16_t bdf, uint8_t barnum) {
|
||||
if (barnum >= 6) {
|
||||
panic("pci_config_read_bar");
|
||||
}
|
||||
ASSERT(barnum < 6);
|
||||
|
||||
// get basic information
|
||||
// https://en.wikipedia.org/wiki/PCI_configuration_space
|
||||
// get basic information
|
||||
// https://en.wikipedia.org/wiki/PCI_configuration_space
|
||||
uint8_t offset = 0x10 + (barnum << 2);
|
||||
uint32_t bar = pci_config_read_u32(bdf, offset);
|
||||
struct pci_bar_desc desc;
|
||||
desc.type = bar & 0x1;
|
||||
if (desc.type == PCI_BAR_TYPE_MEM) {
|
||||
desc.locatable = (bar >> 1) & 0x3;
|
||||
if (desc.locatable == 3) {
|
||||
panic("pci_config_read_bar");
|
||||
}
|
||||
ASSERT(desc.locatable != 3);
|
||||
desc.prefetchable = (bar >> 3) & 0x1;
|
||||
desc.address = bar & 0xfffffff0;
|
||||
} else {
|
||||
desc.address = bar & 0xfffffffc;
|
||||
}
|
||||
|
||||
// get length
|
||||
// https://stackoverflow.com/questions/19006632/how-is-a-pci-pcie-bar-size-determined
|
||||
// get length
|
||||
// https://stackoverflow.com/questions/19006632/how-is-a-pci-pcie-bar-size-determined
|
||||
pci_config_write_u32(bdf, offset, 0xffffffff);
|
||||
bar = pci_config_read_u32(bdf, offset);
|
||||
desc.length = (~(bar & 0xfffffff0)) + 1;
|
||||
|
|
@ -65,34 +58,26 @@ struct pci_bar_desc pci_bar_desc_read(uint16_t bdf, uint8_t barnum) {
|
|||
}
|
||||
|
||||
void pci_bar_desc_print(const struct pci_bar_desc *desc) {
|
||||
println("pci_bar_desc {");
|
||||
printf("pci_bar_desc {\n");
|
||||
|
||||
if (desc->type == PCI_BAR_TYPE_MEM) {
|
||||
println(" type = MEM");
|
||||
printf(" type = MEM\n");
|
||||
if (desc->locatable == PCI_BAR_LOCATABLE_32) {
|
||||
println(" locatable = 32");
|
||||
printf(" locatable = 32\n");
|
||||
} else if (desc->locatable == PCI_BAR_LOCATABLE_SMALL) {
|
||||
println(" locatable = SMALL");
|
||||
printf(" locatable = SMALL\n");
|
||||
} else {
|
||||
println(" locatable = 64");
|
||||
printf(" locatable = 64\n");
|
||||
}
|
||||
puts(" prefetchable = ");
|
||||
println(desc->prefetchable ? "true" : "false");
|
||||
puts(" address = ");
|
||||
print_u32x(desc->address);
|
||||
println("");
|
||||
puts(" length = ");
|
||||
print_u32x(desc->length);
|
||||
println("");
|
||||
printf(" prefetchable = %s\n", desc->prefetchable ? "true" : "false");
|
||||
printf(" address = %u\n", desc->address);
|
||||
printf(" length = %u\n", desc->length);
|
||||
} else {
|
||||
println(" type = IO");
|
||||
puts(" address = ");
|
||||
print_u32x(desc->address);
|
||||
println("");
|
||||
puts(" length = ");
|
||||
print_u32x(desc->length);
|
||||
println("");
|
||||
printf(" type = IO\n");
|
||||
printf(" address = %u\n", desc->address);
|
||||
printf(" length = %u\n", desc->length);
|
||||
}
|
||||
println("}");
|
||||
printf("}\n");
|
||||
}
|
||||
|
||||
int pci_search(uint16_t vendor_id, uint16_t device_id, uint16_t *found_out) {
|
||||
|
|
|
|||
355
src/std.c
Normal file
355
src/std.c
Normal file
|
|
@ -0,0 +1,355 @@
|
|||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "std.h"
|
||||
#include "x86_64/uart.h"
|
||||
|
||||
#define BUFFER_SIZE 1024
|
||||
|
||||
/* --- Memory Functions --- */
|
||||
void *memset(void *ptr, int value, size_t num) {
|
||||
unsigned char *byte_ptr = (unsigned char *)ptr;
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
byte_ptr[i] = (unsigned char)value;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *memcpy(void *dest, const void *src, size_t n) {
|
||||
unsigned char *d = (unsigned char *)dest;
|
||||
const unsigned char *s = (const unsigned char *)src;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
d[i] = s[i];
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
int memcmp(const void *ptr, const void *ptr2, size_t num) {
|
||||
unsigned char *d = (unsigned char *)ptr;
|
||||
unsigned char *b = (unsigned char *)ptr2;
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
if (d[i] != b[i]) {
|
||||
return (d[i] - b[i]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *memmove(void *dest, const void *src, size_t num) {
|
||||
unsigned char *d = (unsigned char *)dest;
|
||||
const unsigned char *s = (const unsigned char *)src;
|
||||
if (d < s || d >= (s + num)) {
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
d[i] = s[i];
|
||||
}
|
||||
} else {
|
||||
for (size_t i = num; i > 0; i--) {
|
||||
d[i - 1] = s[i - 1];
|
||||
}
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* --- String functions --- */
|
||||
unsigned int strlen(const char *s) {
|
||||
unsigned int len = 0;
|
||||
while (*s != '\0') {
|
||||
s++;
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
bool streq(const char *a, const char *b) {
|
||||
while (*a != '\0' && *b != '\0') {
|
||||
if (*a != *b) {
|
||||
return false;
|
||||
}
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
// must have same length
|
||||
return *a == '\0' && *b == '\0';
|
||||
}
|
||||
|
||||
bool strcontains(const char *s, char c) {
|
||||
while (*s != '\0') {
|
||||
if (*s++ == c) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* --- Line buffering --- */
|
||||
// DO NOT USE THESE FUNCTIONS ANYWHERE! USE THE PUBLIC API (EVEN IN THIS FILE)!
|
||||
static char linebuf[BUFFER_SIZE];
|
||||
static unsigned int current_buffer_position = 0;
|
||||
|
||||
static void linebuf_flush(void) {
|
||||
for (unsigned int i = 0; i < current_buffer_position; i++) {
|
||||
uart_write_char(linebuf[i]);
|
||||
}
|
||||
current_buffer_position = 0;
|
||||
}
|
||||
|
||||
static void linebuf_putc(char c) {
|
||||
if (current_buffer_position == BUFFER_SIZE) {
|
||||
linebuf_flush();
|
||||
}
|
||||
linebuf[current_buffer_position++] = c;
|
||||
}
|
||||
|
||||
/* --- Low-level output functions --- */
|
||||
void putc(char c) {
|
||||
if (c == '\n') {
|
||||
linebuf_putc('\r');
|
||||
linebuf_putc('\n');
|
||||
linebuf_flush();
|
||||
} else {
|
||||
linebuf_putc(c);
|
||||
}
|
||||
}
|
||||
|
||||
void putln(void) {
|
||||
putc('\n');
|
||||
}
|
||||
|
||||
void puts(const char *s) {
|
||||
while (*s != '\0') {
|
||||
putc(*s++);
|
||||
}
|
||||
}
|
||||
|
||||
void putsln(const char *s) {
|
||||
puts(s);
|
||||
putln();
|
||||
}
|
||||
|
||||
void put_charbuf(const char *buf, unsigned int len) {
|
||||
for (unsigned int i = 0; i < len; i++) {
|
||||
putc(buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#define TO_HEX(n) ((n) < 10 ? (n) + '0' : (n) - 10 + 'a')
|
||||
#define PUTUXX(nd) \
|
||||
do { \
|
||||
putc('0'); \
|
||||
putc('x'); \
|
||||
for (int i = 0; i < nd; i++) { \
|
||||
uint8_t hexval = (value >> ((((nd) - 1) - i) << 2)) & 0xf; \
|
||||
putc(TO_HEX(hexval)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
void putu8x(uint8_t value) {
|
||||
PUTUXX(2);
|
||||
}
|
||||
|
||||
void putu16x(uint16_t value) {
|
||||
PUTUXX(4);
|
||||
}
|
||||
|
||||
void putu32x(uint32_t value) {
|
||||
PUTUXX(8);
|
||||
}
|
||||
|
||||
void putu64x(uint64_t value) {
|
||||
PUTUXX(16);
|
||||
}
|
||||
|
||||
/* --- Number Conversion Functions --- */
|
||||
|
||||
// this does not include null byte
|
||||
#define TOA_MAX_BUF_SIZE 64
|
||||
|
||||
/* Converts an int value to a string in a given base */
|
||||
void itoa(int value, unsigned int base, char *buffer) {
|
||||
itoa_ll(value, base, buffer);
|
||||
}
|
||||
|
||||
/* Converts an unsigned int value to a string in a given base */
|
||||
void utoa(unsigned int value, unsigned int base, char *buffer) {
|
||||
utoa_ll(value, base, buffer);
|
||||
}
|
||||
|
||||
/* Converts a long long value to a string in a given base */
|
||||
void itoa_ll(long long value, unsigned int base, char *buffer) {
|
||||
bool is_negative = false;
|
||||
unsigned long long uvalue;
|
||||
if (base == 10 && value < 0) {
|
||||
is_negative = true;
|
||||
uvalue = -value;
|
||||
} else {
|
||||
uvalue = value;
|
||||
}
|
||||
|
||||
if (is_negative) {
|
||||
buffer[0] = '-';
|
||||
utoa_ll(uvalue, base, buffer + 1);
|
||||
} else {
|
||||
utoa_ll(uvalue, base, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/* Converts an unsigned long long value to a string in a given base */
|
||||
void utoa_ll(unsigned long long value, unsigned int base, char *buffer) {
|
||||
char temp[TOA_MAX_BUF_SIZE];
|
||||
int index = 0;
|
||||
if (value == 0) {
|
||||
temp[index++] = '0';
|
||||
} else {
|
||||
while (value > 0) {
|
||||
unsigned int digit = value % base;
|
||||
temp[index++] = "0123456789ABCDEF"[digit];
|
||||
value /= base;
|
||||
}
|
||||
}
|
||||
int out_index = 0;
|
||||
for (int i = index - 1; i >= 0; i--) {
|
||||
buffer[out_index++] = temp[i];
|
||||
}
|
||||
buffer[out_index] = '\0';
|
||||
}
|
||||
|
||||
/* --- Helper Functions --- */
|
||||
unsigned int toa_buf_size(unsigned int bits, unsigned int base) {
|
||||
unsigned int sz;
|
||||
if (base == 2) {
|
||||
sz = bits; // Binary: 1 symbol per bit
|
||||
} else if (base == 8) {
|
||||
sz = (bits + 2) / 3; // Octal: 3 bits per digit
|
||||
} else if (base == 16) {
|
||||
sz = (bits + 3) / 4; // Hex: 4 bits per digit
|
||||
} else if (base == 10) {
|
||||
sz = (bits * 30103) / 100000 + 1; // Approximate log10(2) ≈ 0.30103
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
return sz + 1; // null byte inclusive
|
||||
}
|
||||
|
||||
/* --- Custom printf Implementation --- */
|
||||
#define IS_PRINTABLE(c) ((c) >= ' ' && (c) <= '~')
|
||||
|
||||
void printf(const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
while (*format) {
|
||||
if (*format == '%') {
|
||||
format++;
|
||||
bool do_number = false;
|
||||
int number_size_bits = 32;
|
||||
char number_buffer[TOA_MAX_BUF_SIZE + 1];
|
||||
char base;
|
||||
bool sign;
|
||||
// Check for length modifiers:
|
||||
switch (*format) {
|
||||
case 'h':
|
||||
do_number = true;
|
||||
number_size_bits = 16; // 16-bit (promoted to int in varargs)
|
||||
format++;
|
||||
break;
|
||||
case 'l':
|
||||
do_number = true;
|
||||
number_size_bits = 64; // 64-bit
|
||||
format++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (do_number && !strcontains("duxob", *format)) {
|
||||
PANIC("printf: expected number format specifier after %h or %l");
|
||||
}
|
||||
|
||||
switch (*format) {
|
||||
case 'd':
|
||||
do_number = true;
|
||||
base = 10;
|
||||
sign = true;
|
||||
break;
|
||||
case 'u':
|
||||
do_number = true;
|
||||
base = 10;
|
||||
sign = false;
|
||||
break;
|
||||
case 'x':
|
||||
do_number = true;
|
||||
base = 16;
|
||||
sign = false;
|
||||
break;
|
||||
case 'o':
|
||||
do_number = true;
|
||||
base = 8;
|
||||
sign = false;
|
||||
case 'b':
|
||||
do_number = true;
|
||||
base = 2;
|
||||
sign = false;
|
||||
break;
|
||||
case 'c': {
|
||||
char ch = (char)va_arg(args, int);
|
||||
putc(ch);
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
char *str = va_arg(args, char *);
|
||||
puts(str);
|
||||
break;
|
||||
}
|
||||
case 'p': {
|
||||
void *ptr = va_arg(args, void *);
|
||||
putu64x((uint64_t)(intptr_t)ptr);
|
||||
break;
|
||||
}
|
||||
case '%': {
|
||||
putc('%');
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
PANIC("printf: unsupported format specifier");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (do_number) {
|
||||
if (number_size_bits == 64) {
|
||||
long long value = va_arg(args, long long);
|
||||
if (sign) {
|
||||
itoa_ll(value, base, number_buffer);
|
||||
} else {
|
||||
utoa_ll((unsigned long long)value, base, number_buffer);
|
||||
}
|
||||
} else {
|
||||
int value = va_arg(args, int);
|
||||
if (sign) {
|
||||
itoa(value, base, number_buffer);
|
||||
} else {
|
||||
utoa((unsigned int)value, base, number_buffer);
|
||||
}
|
||||
}
|
||||
puts(number_buffer);
|
||||
}
|
||||
format++;
|
||||
} else if (IS_PRINTABLE(*format) || *format == '\n') {
|
||||
putc(*format);
|
||||
format++;
|
||||
} else {
|
||||
// we disallow everything else for now (including \r, \t)
|
||||
putc('[');
|
||||
putu8x(*format);
|
||||
putc(']');
|
||||
format++;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* --- Debug helpers --- */
|
||||
__attribute__((noreturn)) void panic(const char *file, unsigned int line, const char *msg) {
|
||||
printf("PANIC@%s:%d: %s\n", file, line, msg);
|
||||
while (1) {
|
||||
// loop forever
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
#include "std.h"
|
||||
#include "tar.h"
|
||||
#include "bootboot.h"
|
||||
#include "output.h"
|
||||
|
||||
extern BOOTBOOT bootboot; // see bootboot.h
|
||||
|
||||
|
|
@ -36,11 +35,8 @@ int tar_get_file(const char *name, struct tar_header *hd_out) {
|
|||
struct tar_header hd;
|
||||
|
||||
find_begin:
|
||||
if (hard_follow_count > 1) {
|
||||
panic("tar error: hardlink points to hardlink?");
|
||||
} else if (sym_follow_count == SYM_FOLLOW_CAP) {
|
||||
panic("tar error: symlink chain too long");
|
||||
}
|
||||
ASSERT(hard_follow_count <= 1);
|
||||
ASSERT(sym_follow_count < SYM_FOLLOW_CAP);
|
||||
|
||||
uint64_t p = bootboot.initrd_ptr;
|
||||
while (p < end) {
|
||||
|
|
|
|||
|
|
@ -1,31 +1,31 @@
|
|||
#include "x86_64/asm.h"
|
||||
|
||||
uint8_t in8(int port) {
|
||||
unsigned char value;
|
||||
__asm__ ("inb %%dx" : "=a"(value) : "d"(port));
|
||||
return value;
|
||||
unsigned char value;
|
||||
__asm__("inb %%dx" : "=a"(value) : "d"(port));
|
||||
return value;
|
||||
}
|
||||
|
||||
uint16_t in16(int port) {
|
||||
uint16_t value;
|
||||
__asm__ ("inw %%dx" : "=a"(value) : "d"(port));
|
||||
return value;
|
||||
uint16_t value;
|
||||
__asm__("inw %%dx" : "=a"(value) : "d"(port));
|
||||
return value;
|
||||
}
|
||||
|
||||
uint32_t in32(int port) {
|
||||
uint32_t value;
|
||||
__asm__ ("inl %%dx" : "=a"(value) : "d"(port));
|
||||
__asm__("inl %%dx" : "=a"(value) : "d"(port));
|
||||
return value;
|
||||
}
|
||||
|
||||
void out8(int port, uint8_t value) {
|
||||
__asm__ ("outb %%dx" :: "d"(port), "a"(value));
|
||||
__asm__("outb %%dx" ::"d"(port), "a"(value));
|
||||
}
|
||||
|
||||
void out16(int port, uint16_t value) {
|
||||
__asm__ ("outw %%dx" :: "d"(port), "a"(value));
|
||||
__asm__("outw %%dx" ::"d"(port), "a"(value));
|
||||
}
|
||||
|
||||
void out32(int port, uint32_t value) {
|
||||
__asm__ ("outl %%dx" :: "d"(port), "a"(value));
|
||||
__asm__("outl %%dx" ::"d"(port), "a"(value));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,35 +1,30 @@
|
|||
#include <stdint.h>
|
||||
#include "output.h" // remove later, this is only for interrupt handler
|
||||
#include "std.h" // remove later, this is only for interrupt handler
|
||||
|
||||
uint64_t gdt[3];
|
||||
|
||||
void write_segment_descriptor(uint64_t *entry, uint8_t dpl, uint8_t executable) {
|
||||
uint8_t access_byte =
|
||||
(1 << 7) // present bit
|
||||
| (dpl << 5)
|
||||
| (1 << 4) // S
|
||||
| (executable << 3)
|
||||
| (0 << 2) // DC
|
||||
uint8_t access_byte = (1 << 7) // present bit
|
||||
| (dpl << 5) | (1 << 4) // S
|
||||
| (executable << 3) | (0 << 2) // DC
|
||||
| (1 << 1) // RW
|
||||
| (0 << 0) // A
|
||||
;
|
||||
;
|
||||
|
||||
uint8_t flags =
|
||||
(1 << 3) // G
|
||||
uint8_t flags = (1 << 3) // G
|
||||
| (0 << 2) // DB
|
||||
| (1 << 1) // L
|
||||
| (0 << 0) // reserved
|
||||
;
|
||||
|
||||
*entry =
|
||||
0xffff // limit
|
||||
;
|
||||
|
||||
*entry = 0xffff // limit
|
||||
| ((uint64_t)0x0000 << 16) // base
|
||||
| ((uint64_t)0x00 << 32) // base
|
||||
| ((uint64_t)access_byte << 40) // access byte
|
||||
| ((uint64_t)0xf << 48) // limit
|
||||
| ((uint64_t)flags << 52) // flags
|
||||
| ((uint64_t)0x00 << 56) // base
|
||||
;
|
||||
;
|
||||
}
|
||||
|
||||
#define CODE_SEGMENT 1
|
||||
|
|
@ -42,13 +37,13 @@ void init_gdt() {
|
|||
|
||||
uint8_t gdtr[10];
|
||||
|
||||
*(uint16_t*)gdtr = sizeof(gdt) - 1;
|
||||
*(uint64_t**)(gdtr + 2) = (uint64_t*)gdt;
|
||||
*(uint16_t *)gdtr = sizeof(gdt) - 1;
|
||||
*(uint64_t **)(gdtr + 2) = (uint64_t *)gdt;
|
||||
|
||||
__asm__ ("lgdt (%0)" :: "r"(gdtr));
|
||||
__asm__("lgdt (%0)" ::"r"(gdtr));
|
||||
|
||||
__asm__ ("mov %0, %%ds" :: "r"(DATA_SEGMENT << 3));
|
||||
// TODO set code segment -> iret?
|
||||
__asm__("mov %0, %%ds" ::"r"(DATA_SEGMENT << 3));
|
||||
// TODO set code segment -> iret?
|
||||
}
|
||||
|
||||
__attribute__ ((packed))
|
||||
|
|
@ -88,7 +83,7 @@ void write_int_desc_entry(struct int_desc_entry *e, uint64_t offset) {
|
|||
}
|
||||
|
||||
void basic_interrupt_handler(void) {
|
||||
panic("Hello Interrupt!\n");
|
||||
PANIC("Hello Interrupt!");
|
||||
}
|
||||
|
||||
#define NUM_INTERRUPTS 256
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
#define COM1_BASE_PORT 0x3F8
|
||||
|
||||
void
|
||||
uart_write_char(char c)
|
||||
{
|
||||
while (1) {
|
||||
int line_status = in8(COM1_BASE_PORT + 5);
|
||||
if (line_status & 0x20) break;
|
||||
}
|
||||
void uart_write_char(char c) {
|
||||
while (1) {
|
||||
int line_status = in8(COM1_BASE_PORT + 5);
|
||||
if (line_status & 0x20) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out8(COM1_BASE_PORT, c);
|
||||
out8(COM1_BASE_PORT, c);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue