223 lines
7.3 KiB
C
223 lines
7.3 KiB
C
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include <stivale2.h>
|
|
#include <std/inline.h>
|
|
#include <std/util.h>
|
|
#include <stdbool.h>
|
|
#include <std/stdio.h>
|
|
#include <drivers/idt/isr.h>
|
|
#include <drivers/keyboard/keyboard.h>
|
|
#include <drivers/pic/pic.h>
|
|
#include <drivers/device/device.h>
|
|
#include <drivers/ide/ide.h>
|
|
#include <framebuffer.h>
|
|
#include <psf.h>
|
|
|
|
// We need to tell the stivale bootloader where we want our stack to be.
|
|
// We are going to allocate our stack as an uninitialised array in .bss.
|
|
static uint8_t stack[4096];
|
|
void kmain();
|
|
|
|
bool is_running = true;
|
|
int keyboard_descriptor = 0;
|
|
int terminal_descriptor = 0;
|
|
|
|
// stivale2 uses a linked list of tags for both communicating TO the
|
|
// bootloader, or receiving info FROM it. More information about these tags
|
|
// is found in the stivale2 specification.
|
|
|
|
// We are now going to define a framebuffer header tag, which is mandatory when
|
|
// using the stivale2 terminal.
|
|
// This tag tells the bootloader that we want a graphical framebuffer instead
|
|
// of a CGA-compatible text mode. Omitting this tag will make the bootloader
|
|
// default to text mode, if available.
|
|
static struct stivale2_header_tag_framebuffer framebuffer_hdr_tag = {
|
|
// Same as above.
|
|
.tag = {
|
|
.identifier = STIVALE2_HEADER_TAG_FRAMEBUFFER_ID,
|
|
.next = 0
|
|
},
|
|
// set all the framebuffer specifics to 0 for it to pick the best it can.
|
|
.framebuffer_width = 800,
|
|
.framebuffer_height = 600,
|
|
.framebuffer_bpp = 32
|
|
};
|
|
|
|
// The stivale2 specification says we need to define a "header structure".
|
|
// This structure needs to reside in the .stivale2hdr ELF section in order
|
|
// for the bootloader to find it. We use this __attribute__ directive to
|
|
// tell the compiler to put the following structure in said section.
|
|
__attribute__((section(".stivale2hdr"), used))
|
|
static struct stivale2_header stivale_hdr = {
|
|
// The entry_point member is used to specify an alternative entry
|
|
// point that the bootloader should jump to instead of the executable's
|
|
// ELF entry point. We do not care about that so we leave it zeroed.
|
|
.entry_point = 0,
|
|
// Let's tell the bootloader where our stack is.
|
|
// We need to add the sizeof(stack) since in x86(_64) the stack grows
|
|
// downwards.
|
|
.stack = (uintptr_t)stack + sizeof(stack),
|
|
// Bit 1, if set, causes the bootloader to return to us pointers in the
|
|
// higher half, which we likely want.
|
|
.flags = (1 << 1),
|
|
// This header structure is the root of the linked list of header tags and
|
|
// points to the first one in the linked list.
|
|
.tags = (uintptr_t)&framebuffer_hdr_tag
|
|
};
|
|
|
|
// We will now write a helper function which will allow us to scan for tags
|
|
// that we want FROM the bootloader (structure tags).
|
|
void *stivale2_get_tag(struct stivale2_struct *stivale2_struct, uint64_t id) {
|
|
struct stivale2_tag *current_tag = (void *)stivale2_struct->tags;
|
|
for (;;) {
|
|
// If the tag pointer is NULL (end of linked list), we did not find
|
|
// the tag. Return NULL to signal this.
|
|
if (current_tag == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
// Check whether the identifier matches. If it does, return a pointer
|
|
// to the matching tag.
|
|
if (current_tag->identifier == id) {
|
|
return current_tag;
|
|
}
|
|
|
|
// Get a pointer to the next tag in the linked list and repeat.
|
|
current_tag = (void *)current_tag->next;
|
|
}
|
|
}
|
|
|
|
framebuffer_t *framebuffer;
|
|
|
|
// The following will be our kernel's entry point.
|
|
void _start(struct stivale2_struct *stivale2_struct) {
|
|
struct stivale2_struct_tag_framebuffer *tagfb = stivale2_get_tag(stivale2_struct, STIVALE2_STRUCT_TAG_FRAMEBUFFER_ID);
|
|
|
|
if (tagfb == NULL) {
|
|
printf("Requested stivale2 tags were not found, hanging...");
|
|
for (;;) {
|
|
asm ("hlt");
|
|
}
|
|
}
|
|
framebuffer->address = (uint8_t*)tagfb->framebuffer_addr;
|
|
framebuffer->width = tagfb->framebuffer_width;
|
|
framebuffer->height = tagfb->framebuffer_height;
|
|
framebuffer->depth = tagfb->framebuffer_bpp;
|
|
framebuffer->pitch = tagfb->framebuffer_pitch;
|
|
framebuffer->pixelwidth = tagfb->framebuffer_bpp / 8;
|
|
|
|
terminal_descriptor = terminal_initialize(framebuffer);
|
|
printf("Terminal initialized, descriptor: %d\n", terminal_descriptor);
|
|
|
|
printf("Framebuffer | addr: %#X, width: %d, height: %d, depth: %d, pitch: %d\n", framebuffer->address, framebuffer->width, framebuffer->height, framebuffer->depth, framebuffer->pitch, framebuffer->pixelwidth);
|
|
|
|
kmain();
|
|
}
|
|
|
|
void shell() {
|
|
printf("hello yes");
|
|
|
|
while (is_running) {
|
|
printf("\n> ");
|
|
|
|
while (true) {
|
|
uint32_t scancode = (uint32_t)read(keyboard_descriptor, NULL);
|
|
if (!scancode) continue;
|
|
|
|
bool special = true;
|
|
bool finished = false;
|
|
|
|
switch (scancode) {
|
|
case 72:
|
|
terminal_row--;
|
|
break;
|
|
case 75:
|
|
terminal_column--;
|
|
break;
|
|
case 77:
|
|
terminal_column++;
|
|
break;
|
|
case 80:
|
|
terminal_row++;
|
|
break;
|
|
case 0x1C:
|
|
finished = true;
|
|
break;
|
|
default:
|
|
special = false;
|
|
}
|
|
|
|
if (finished) break;
|
|
if (!special) putchar(keyboard_get_key_from_scancode(scancode));
|
|
terminal_updatecursor();
|
|
}
|
|
}
|
|
}
|
|
|
|
extern void load_page_directory(uint32_t);
|
|
extern void enable_paging();
|
|
|
|
uint32_t page_directory[1024] __attribute__((aligned(4096)));
|
|
uint32_t first_page_table[1024] __attribute__((aligned(4096)));
|
|
uint32_t second_page_table[1024] __attribute__((aligned(4096)));
|
|
|
|
#define PAGE_PRESENT 1 << 0
|
|
#define PAGE_WRITABLE 1 << 1
|
|
#define PAGE_USER 1 << 2
|
|
#define PAGE_WRITE_THROUGH 1 << 3
|
|
#define PAGE_CACHE_DISABLE 1 << 4
|
|
#define PAGE_ACCESSED 1 << 5
|
|
#define PAGE_DIRTY 1 << 6
|
|
#define PAGE_LARGE 1 << 7
|
|
#define PAGE_GLOBAL 1 << 8
|
|
/*
|
|
void setup_paging() {
|
|
// set each entry to not present
|
|
for (uint32_t i = 0; i < 1024; i++) {
|
|
page_directory[i] = 0;
|
|
}
|
|
|
|
// i holds the physical address where we want to start mapping these pages to.
|
|
// in this case, we want to map these pages to the very beginning of memory.
|
|
// we will fill all 1024 entries in the table, mapping 4 megabytes
|
|
for (uint32_t i = 0; i < 1024; i++) {
|
|
first_page_table[i] = (i * 0x1000) | PAGE_PRESENT | PAGE_WRITABLE;
|
|
}
|
|
|
|
page_directory[0] = ((uint32_t)first_page_table) | PAGE_PRESENT | PAGE_WRITABLE;
|
|
|
|
load_page_directory((uint32_t)page_directory);
|
|
enable_paging();
|
|
}
|
|
*/
|
|
void kmain() {
|
|
//setup_paging();
|
|
|
|
printf("Preparing interrupts... ");
|
|
pic_init();
|
|
isr_install();
|
|
printf("done\n");
|
|
|
|
printf("Preparing IDE driver... \n");
|
|
printf("Searching for IDE devices... \n");
|
|
ide_init();
|
|
|
|
fillrect(framebuffer, 500, 200, 100, 100, 0x00FFD5FF);
|
|
fillrect(framebuffer, 600, 300, 100, 100, 0xFF00D5FF);
|
|
|
|
keyboard_descriptor = keyboard_init();
|
|
printf("Keyboard ready, descriptor: %d\n", keyboard_descriptor);
|
|
|
|
printf("Are interrupts enabled? ");
|
|
if (are_interrupts_enabled() == 1) {
|
|
printf("yes\n");
|
|
} else {
|
|
printf("no\n");
|
|
}
|
|
|
|
printf("kmain memory address: %#X\n", (unsigned int)kmain);
|
|
|
|
printf("----------\n");
|
|
shell();
|
|
}
|