You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
325 lines
7.5 KiB
C
325 lines
7.5 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/port.h>
|
|
#include <arch/vmparam.h>
|
|
|
|
#include <gay/cdefs.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)
|
|
{
|
|
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(" [0x%016llx-0x%016llx] %s\n",
|
|
entry->addr,
|
|
entry->addr + entry->len - 1,
|
|
mmap_type_name(entry->type));
|
|
|
|
usize safe_len;
|
|
# ifdef __x86_64__
|
|
safe_len = entry->safe_len;
|
|
# else
|
|
if (entry->addr >= (1llu << 32))
|
|
safe_len = 0; /* we can't handle 64-bit pointers */
|
|
else if (entry->len > (1llu << 32) - entry->addr)
|
|
safe_len = (1llu << 32) - entry->addr; /* clip to 32-bit */
|
|
else
|
|
safe_len = entry->len;
|
|
# endif
|
|
|
|
if (entry->type == MB2_MEMORY_AVAILABLE && safe_len > region_len) {
|
|
region = entry->addr;
|
|
region_len = safe_len;
|
|
}
|
|
|
|
entry = (void *)entry + tag->entry_size;
|
|
}
|
|
|
|
if (region == 0 || region_len == 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) {
|
|
void *first_row = (void *)cell_at(0, 0);
|
|
void *second_row = (void *)cell_at(1, 0);
|
|
void *last_row_end = (void *)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 = ' ';
|
|
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;
|
|
|
|
/* disable cursor */
|
|
x86_outb(0x3D4, 0x0A);
|
|
x86_outb(0x3D5, 0x20);
|
|
|
|
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,
|
|
};
|
|
static char line[FB_COLS];
|
|
memset(line, ' ', FB_COLS);
|
|
|
|
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];
|
|
fb_write(NULL, line, FB_COLS);
|
|
}
|
|
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.
|
|
*/
|