kern/arch/x86/boot/boot.c
fef 3fee893f21
x86: begin preparations for amd64 support
This is a huge commit, but it mainly just moves
some files around and doesn't change their
contents much.
A lot of stuff works the same on amd64 as it does
on i386, so i'm moving the parts that are specific
to the latter into separate subdirectories while
the rest can be shared with the amd64 codebase.
2021-10-21 05:27:42 +02:00

307 lines
7.1 KiB
C

/* See the end of this file for copyright and license terms. */
#include <string.h>
#include <arch/interrupt.h>
#include <arch/multiboot.h>
#include <arch/vmparam.h>
#include <gay/cdefs.h>
#include <gay/config.h>
#include <gay/kprintf.h>
#include <gay/mm.h>
#include <gay/types.h>
#include <gay/util.h>
enum vga_color {
VGA_COLOR_BLACK = 0,
VGA_COLOR_BLUE = 1,
VGA_COLOR_GREEN = 2,
VGA_COLOR_CYAN = 3,
VGA_COLOR_RED = 4,
VGA_COLOR_MAGENTA = 5,
VGA_COLOR_BROWN = 6,
VGA_COLOR_LIGHT_GREY = 7,
VGA_COLOR_DARK_GREY = 8,
VGA_COLOR_LIGHT_BLUE = 9,
VGA_COLOR_LIGHT_GREEN = 10,
VGA_COLOR_LIGHT_CYAN = 11,
VGA_COLOR_LIGHT_RED = 12,
VGA_COLOR_LIGHT_MAGENTA = 13,
VGA_COLOR_LIGHT_BROWN = 14,
VGA_COLOR_WHITE = 15,
};
/*
* The character framebuffer sits at physical address 0x000b8000 and gets
* mapped in the last entry of the initial page table. With 1024 (0x400)
* entries per page table, each mapping 4096 (0x1000) bytes, this gives us an
* offset of 0x3ff * 0x1000 = 0x003ff000 for the virtual address.
*/
#define FB_ADDRESS (KERN_OFFSET + 0x003ff000)
#define FB_LINES 24
#define FB_COLS 80
struct fb_cell {
u8 c;
enum vga_color fg:4;
enum vga_color bg:4;
} __packed;
/** @brief BIOS provided character framebuffer */
static volatile struct fb_cell *const framebuffer = (volatile struct fb_cell *)FB_ADDRESS;
/** @brief current line in the framebuffer */
static unsigned int fb_line;
/** @brief current column in the framebuffer */
static unsigned int fb_col;
/** @brief current background color */
enum vga_color fb_background;
/** @brief current foreground color */
enum vga_color fb_foreground;
#define cell_at(line, col) ( &framebuffer[(line) * FB_COLS + (col)] )
#define current_cell (cell_at(fb_line, fb_col))
static isize fb_write(struct kprintf_printer *printer, const void *buf, usize size);
static isize fb_flush(struct kprintf_printer *printer);
static struct kprintf_printer fb_kprintf_printer = {
.write = fb_write,
.flush = fb_flush,
};
static void fb_newline(void);
static void fb_clear(void);
static void fb_init(enum vga_color fg, enum vga_color bg);
static void print_gay_propaganda(void);
static struct mb2_tag *next_tag(struct mb2_tag *tag);
static int handle_tag(struct mb2_tag *tag);
static int handle_mmap_tag(struct mb2_tag_mmap *tag);
static const char *mmap_type_name(u32 type);
extern int main(int argc, char *argv[]);
__asmlink void _boot(u32 magic, uintptr_t phys_address) /* NOLINT */
{
kprintf_set_printer(&fb_kprintf_printer);
fb_init(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
x86_setup_interrupts();
if (magic != MB2_BOOTLOADER_MAGIC) {
kprintf("Error: invalid bootloader magic, aborting\n");
return;
}
print_gay_propaganda();
/*
* all data structures passed from grub are physical addresses,
* so we need to be careful to translate all pointers to virtual
* addresses before accessing them.
*/
void *address = (void *)phys_address + KERN_OFFSET;
int err = 0;
for (struct mb2_tag *tag = address + 8; tag != NULL; tag = next_tag(tag)) {
err = handle_tag(tag);
if (err)
break;
}
if (!err)
main(0, NULL);
}
static inline int handle_tag(struct mb2_tag *tag)
{
int ret = 0;
switch (tag->type) {
case MB2_TAG_TYPE_END:
break;
case MB2_TAG_TYPE_CMDLINE:
kprintf("Kernel command line: %s\n", ((struct mb2_tag_string *)tag)->string);
break;
case MB2_TAG_TYPE_MMAP:
ret = handle_mmap_tag((struct mb2_tag_mmap *)tag);
break;
default:
//kprintf("Unknown tag %u\n", tag->type);
break;
}
return ret;
}
static inline int handle_mmap_tag(struct mb2_tag_mmap *tag)
{
kprintf("Memory map:\n");
uintptr_t region = 0;
usize region_len = 0;
struct mb2_mmap_entry *entry = &tag->entries[0];
while ((void *)entry < (void *)tag + tag->tag.size) {
kprintf(" [%p-%p] %s\n",
(void *)entry->addr,
(void *)entry->addr + entry->len - 1,
mmap_type_name(entry->type));
if (entry->type == 1 && entry->len > region_len) {
region = entry->addr;
region_len = entry->len;
}
entry = (void *)entry + tag->entry_size;
}
if (region == 0) {
kprintf("No memory available! Aborting.\n");
return 1;
}
int err = kmalloc_init(region, region + region_len);
if (err) {
kprintf("kmalloc_init() failed! Aborting.\n");
return 1;
}
return 0;
}
static inline struct mb2_tag *next_tag(struct mb2_tag *tag)
{
if (tag->type == MB2_TAG_TYPE_END)
return NULL;
else
return (void *)tag + ( (tag->size + 7) & ~7 );
}
static void fb_newline(void)
{
fb_col = 0;
if (fb_line == FB_LINES - 1) {
u8 *first_row = (u8 *)cell_at(0, 0);
u8 *second_row = (u8 *)cell_at(1, 0);
u8 *last_row_end = (u8 *)cell_at(FB_LINES, FB_COLS);
memmove(first_row, second_row, last_row_end - second_row);
} else {
fb_line++;
}
}
static isize fb_write(struct kprintf_printer *printer, const void *buf, usize size)
{
isize ret = 0;
const u8 *s = buf;
while (size > s - (const u8 *)buf) {
u8 c = *s++;
ret++;
if (fb_col == FB_COLS)
fb_newline();
if (c == '\n') {
fb_newline();
continue;
}
current_cell->c = c;
current_cell->fg = fb_foreground;
current_cell->bg = fb_background;
fb_col++;
}
return ret;
}
static isize fb_flush(struct kprintf_printer *printer)
{
return 0;
}
static void fb_clear(void)
{
for (unsigned int l = 0; l < FB_LINES; l++) {
for (unsigned int c = 0; c < FB_COLS; c++) {
cell_at(l, c)->c = '\0';
cell_at(l, c)->fg = fb_foreground;
cell_at(l, c)->bg = fb_background;
}
}
}
static void fb_init(enum vga_color fg, enum vga_color bg)
{
fb_line = 0;
fb_col = 0;
fb_foreground = fg;
fb_background = bg;
fb_clear();
}
static void print_gay_propaganda(void)
{
static const enum vga_color rainbow[] = {
VGA_COLOR_RED,
VGA_COLOR_LIGHT_RED,
VGA_COLOR_LIGHT_BROWN,
VGA_COLOR_GREEN,
VGA_COLOR_BLUE,
VGA_COLOR_MAGENTA,
};
enum vga_color bg_before = fb_background;
enum vga_color fg_before = fb_foreground;
for (int i = 0; i < ARRAY_SIZE(rainbow); i++) {
fb_background = rainbow[i];
for (int j = 0; j < FB_COLS; j++)
fb_write(NULL, " ", 1);
}
fb_background = bg_before;
kprintf("\nWelcome to ");
const char *gaybsd = "GayBSD";
for (const char *tmp = gaybsd; *tmp != '\0'; tmp++) {
fb_foreground = rainbow[tmp - gaybsd];
kprintf("%c", *tmp);
}
fb_foreground = fg_before;
kprintf(", be gay do crime!\n\n");
}
static const char *mmap_type_name(u32 type)
{
switch (type) {
case MB2_MEMORY_AVAILABLE:
return "Available";
case MB2_MEMORY_RESERVED:
return "Reserved";
case MB2_MEMORY_ACPI_RECLAIMABLE:
return "ACPI";
case MB2_MEMORY_NVS: /* non-volatile storage */
return "NVS";
case MB2_MEMORY_BADRAM:
return "Bad RAM";
default:
return "Unknown";
}
}
/*
* This file is part of GayBSD.
* Copyright (c) 2021 fef <owo@fef.moe>.
*
* GayBSD is nonviolent software: you may only use, redistribute, and/or
* modify it under the terms of the Cooperative Nonviolent Public License
* (CNPL) as found in the LICENSE file in the source code root directory
* or at <https://git.pixie.town/thufie/npl-builder>; either version 7
* of the license, or (at your option) any later version.
*
* GayBSD comes with ABSOLUTELY NO WARRANTY, to the extent
* permitted by applicable law. See the CNPL for details.
*/