195 lines
6 KiB
C
195 lines
6 KiB
C
/* Calcite, kernel/src/entry.c
|
|
* Copyright 2025 Benji Dial
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or (at
|
|
* your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <framebuffer.h>
|
|
#include <interrupts.h>
|
|
#include <utility.h>
|
|
#include <initfs.h>
|
|
#include <limine.h>
|
|
#include <paging.h>
|
|
#include <panic.h>
|
|
#include <ps2.h>
|
|
|
|
LIMINE_BASE_REVISION(3)
|
|
|
|
static volatile struct limine_framebuffer_request fb_request = {
|
|
.id = LIMINE_FRAMEBUFFER_REQUEST,
|
|
.revision = 0,
|
|
.response = 0
|
|
};
|
|
|
|
static volatile struct limine_hhdm_request hhdm_request = {
|
|
.id = LIMINE_HHDM_REQUEST,
|
|
.revision = 0,
|
|
.response = 0
|
|
};
|
|
|
|
static volatile struct limine_kernel_address_request ka_request = {
|
|
.id = LIMINE_KERNEL_ADDRESS_REQUEST,
|
|
.revision = 0,
|
|
.response = 0
|
|
};
|
|
|
|
static volatile struct limine_memmap_request memmap_request = {
|
|
.id = LIMINE_MEMMAP_REQUEST,
|
|
.revision = 0,
|
|
.response = 0
|
|
};
|
|
|
|
static volatile struct limine_module_request module_request = {
|
|
.id = LIMINE_MODULE_REQUEST,
|
|
.revision = 0,
|
|
.response = 0
|
|
};
|
|
|
|
[[noreturn]] static void die() {
|
|
while (1)
|
|
__asm__ ("hlt");
|
|
}
|
|
|
|
//these are defined in the linker script. they are page-aligned.
|
|
extern uint8_t __kernel_rx_start;
|
|
extern uint8_t __kernel_rx_end;
|
|
extern uint8_t __kernel_ro_start;
|
|
extern uint8_t __kernel_ro_end;
|
|
extern uint8_t __kernel_rw_start;
|
|
extern uint8_t __kernel_rw_end;
|
|
|
|
static void map_kernel_region(
|
|
uint64_t physical_start, void *virtual_start,
|
|
uint64_t length, int writable, int executable) {
|
|
for (uint64_t i = 0; i < length; i += 4096)
|
|
map_in_kernel_page_table(
|
|
physical_start + i, (uint8_t *)virtual_start + i, writable, executable);
|
|
}
|
|
|
|
static uint8_t *initfs_start;
|
|
static uint64_t initfs_length;
|
|
|
|
[[noreturn]] static void with_kernel_page_tables();
|
|
|
|
[[noreturn]] void kernel_entry() {
|
|
|
|
//die if the bootloader hasn't given us something that we need.
|
|
|
|
if (fb_request.response == 0 || hhdm_request.response == 0 ||
|
|
ka_request.response == 0 || memmap_request.response == 0 ||
|
|
module_request.response == 0 ||
|
|
fb_request.response->framebuffer_count == 0 ||
|
|
module_request.response->module_count == 0)
|
|
die();
|
|
|
|
struct limine_framebuffer *fb = fb_request.response->framebuffers[0];
|
|
if (fb->memory_model != LIMINE_FRAMEBUFFER_RGB || fb->bpp != 32 ||
|
|
fb->red_mask_shift != 16 || fb->red_mask_size != 8 ||
|
|
fb->green_mask_shift != 8 || fb->green_mask_size != 8 ||
|
|
fb->blue_mask_shift != 0 || fb->blue_mask_size != 8)
|
|
die();
|
|
|
|
//find the initfs, and die if we don't have one.
|
|
|
|
struct limine_file *initfs = 0;
|
|
struct limine_module_response *response = module_request.response;
|
|
for (uint64_t i = 0; i < response->module_count; ++i)
|
|
if (strequ(response->modules[i]->cmdline, "initfs")) {
|
|
initfs = response->modules[i];
|
|
break;
|
|
}
|
|
|
|
if (!initfs)
|
|
die();
|
|
|
|
//set up page tables. we will mark the regions with bootloader structures as
|
|
//usable, so we need to be careful not to allocate any physical pages until
|
|
//after we are done using bootloader structures. we map the kernel into our
|
|
//page tables, and we remap the framebuffer to somewhere in kernel memory.
|
|
//we do not map the bootloader structures, so we also need to not switch
|
|
//to the new tables until we are done using them.
|
|
|
|
uint64_t kernel_physical_base = ka_request.response->physical_base;
|
|
uint8_t *kernel_virtual_base = (uint8_t *)ka_request.response->virtual_base;
|
|
init_paging(kernel_physical_base, kernel_virtual_base);
|
|
|
|
struct limine_memmap_response *mm_response = memmap_request.response;
|
|
for (uint64_t i = 0; i < mm_response->entry_count; ++i) {
|
|
struct limine_memmap_entry *entry = mm_response->entries[i];
|
|
if (entry->type == LIMINE_MEMMAP_USABLE ||
|
|
entry->type == LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE)
|
|
//limine guarantees these two types are page-aligned already.
|
|
mark_physical_memory_free(entry->base, entry->length);
|
|
}
|
|
|
|
map_kernel_region(
|
|
&__kernel_rx_start - kernel_virtual_base + kernel_physical_base,
|
|
&__kernel_rx_start, &__kernel_rx_end - &__kernel_rx_start, 0, 1);
|
|
map_kernel_region(
|
|
&__kernel_ro_start - kernel_virtual_base + kernel_physical_base,
|
|
&__kernel_ro_start, &__kernel_ro_end - &__kernel_ro_start, 0, 0);
|
|
map_kernel_region(
|
|
&__kernel_rw_start - kernel_virtual_base + kernel_physical_base,
|
|
&__kernel_rw_start, &__kernel_rw_end - &__kernel_rw_start, 1, 0);
|
|
|
|
//we round up to a multiple of a page.
|
|
uint64_t fb_length = ((fb->height * fb->pitch - 1) / 4096 + 1) * 4096;
|
|
fb_base = find_free_kernel_region(fb_length);
|
|
map_kernel_region(
|
|
(uint64_t)fb->address - hhdm_request.response->offset,
|
|
fb_base, fb_length, 1, 0);
|
|
|
|
//store rest of framebuffer information
|
|
|
|
fb_width = fb->width;
|
|
fb_height = fb->height;
|
|
fb_pitch = fb->pitch;
|
|
|
|
//remap initfs module and store information.
|
|
|
|
uint64_t initfs_physical_start =
|
|
(uint64_t)initfs->address - hhdm_request.response->offset;
|
|
|
|
initfs_length = initfs->size;
|
|
uint64_t initfs_length_rounded = ((initfs_length - 1) / 4096 + 1) * 4096;
|
|
|
|
initfs_start = find_free_kernel_region(initfs_length_rounded);
|
|
map_kernel_region(
|
|
initfs_physical_start, initfs_start, initfs_length_rounded, 0, 0);
|
|
|
|
//switch to kernel page tables!
|
|
|
|
switch_to_kernel_page_tables(&with_kernel_page_tables);
|
|
|
|
}
|
|
|
|
[[noreturn]] static void with_kernel_page_tables() {
|
|
|
|
//set initfs
|
|
|
|
set_initfs(initfs_start, initfs_length);
|
|
|
|
//set up interrupts
|
|
|
|
init_ps2();
|
|
set_irq_handler(0x01, &on_keyboard_irq);
|
|
set_irq_handler(0x0c, &on_mouse_irq);
|
|
enable_interrupts();
|
|
|
|
//halt repeatedly
|
|
|
|
while (1)
|
|
__asm__ ("hlt");
|
|
|
|
}
|