Load simple ELF binary & execute; improved paging; start VGA RGB output

This commit is contained in:
Luke Street
2018-10-06 19:28:56 -04:00
parent 9939fc5455
commit de6ea34d21
17 changed files with 320 additions and 134 deletions
+4 -5
View File
@@ -12,12 +12,11 @@ set(CMAKE_C_FLAGS "-m32 -std=c11 -fPIC -ffreestanding -fshort-enums -Wall -Werro
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -nostdinc -fno-builtin -nostdlib -nodefaultlibs")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-stack-protector") # FIXME generates bad code using `mov eax, large gs:14h`?
set(CMAKE_C_FLAGS_DEBUG "-gdwarf-4 -DENABLE_DWARF")
if (NOT CMAKE_HOST_APPLE)
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fsanitize=undefined")
endif()
#if (NOT CMAKE_HOST_APPLE)
# set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fsanitize=undefined")
#endif()
set(CMAKE_C_FLAGS_RELEASE "-Os")
set(CMAKE_EXE_LINKER_FLAGS "")
include_directories(${CMAKE_SOURCE_DIR}/libc)
add_executable(test test)
target_link_libraries(test c)
add_executable(test test)
+4 -1
View File
@@ -1,3 +1,6 @@
#include <stdint.h>
#include <string.h>
int _start(int argc, char **argv) {
return 1234;
return 5; // ((uintptr_t) strlen) + 256;
}
+3 -1
View File
@@ -32,7 +32,9 @@ set(SOURCE_FILES
multiboot
div64
elf
dwarf
stdio_impl
arch/x86/mmu
drivers/ports
drivers/timer
drivers/keyboard
@@ -56,6 +58,6 @@ set(SOURCE_FILES
tests/stdio
tests/path)
if (${CMAKE_BUILD_TYPE} MATCHES "Debug")
set(SOURCE_FILES ${SOURCE_FILES} debug/ubsan debug/dwarf)
set(SOURCE_FILES ${SOURCE_FILES} debug/ubsan)
endif ()
add_library(kernel STATIC ${SOURCE_FILES})
+22
View File
@@ -0,0 +1,22 @@
#include <stdint.h>
#include <stdio.h>
#define KERNEL_PAGE_OFFSET 0xC0000000 // FIXME make dynamic?
void *load_page_table() {
void *raw_ptr;
__asm__ volatile("mov %%cr3, %0" : "=a"(raw_ptr));
return (uint32_t *) ((uintptr_t) raw_ptr + KERNEL_PAGE_OFFSET);
}
void page_table_set(uintptr_t address, uint32_t val) {
uint32_t *page_table = load_page_table();
uint16_t i = (uint16_t) (address >> 22);
page_table[i] = val;
__asm__ volatile("invlpg %0" : : "m"(i));
}
void *kernel_page_offset(void *ptr) {
if ((uintptr_t) ptr > KERNEL_PAGE_OFFSET) return ptr;
return (void *) ((uintptr_t) ptr + KERNEL_PAGE_OFFSET);
}
+27
View File
@@ -0,0 +1,27 @@
//
// Paging flags for Page-Tables and Page-Directories.
//
#define X86_PAGE_PRESENT (1<<0) // set if page or page-table is present
#define X86_PAGE_WRITE (1<<1) // set to allow writing to the page or page-table
#define X86_PAGE_USER (1<<2) // set to make the page or page-table a user page or page-table
// if this flag is cleared the page or page-table can only be accessed in supervisor mode
#define X86_PAGE_PWT (1<<3) // when the PWT flag is set, write-through caching is enabled for the
// page or page-table; when the flag is clear, write-back caching is
// enabled for the page or page-table.
// This type of caching is useful for VGA framebuffers.
#define X86_PAGE_PCD (1<<4) // Page Cache Disable, set this flag to disable caching of the page or page-table
#define X86_PAGE_ACCESSED (1<<5) // the processor sets this flag the first time the page or page table is accessed
#define X86_PAGE_DIRTY (1<<6) // the processor sets this flag the first time a page is accessed for a write operation
// this flag is only used in page-table entries and should not be set for page-directory entries
#define X86_PAGE_PAGESIZE (1<<7) // page size extension flag. (Set for enable)
#define X86_PAGE_GLOBAL (1<<8) // this flag is only used in page-table entries
// when a page is marked global and the page global enable (PGE) flag in register
// CR4 is set, the page-table or page-directory entry for the page is not invalidated
// in the TLB when register CR3 is loaded
#define X86_PAGE_AVAIL1 (1<<9) // Available for usage by the Kernel
#define X86_PAGE_AVAIL2 (1<<10) // Available for usage by the Kernel
#define X86_PAGE_AVAIL3 (1<<11) // Available for usage by the Kernel
void *kernel_page_offset(void *ptr);
void page_table_set(uintptr_t address, uint32_t val);
+41 -19
View File
@@ -1,17 +1,45 @@
#include "vga.h"
#include "ports.h"
#include "../arch/x86/mmu.h"
#include <stdio.h>
#include <string.h>
#define VIDEO_ADDRESS ((uint16_t *) 0xC00B8000)
uint16_t *console_fb_addr = NULL;
void *rgb_fb_addr = NULL;
framebuffer_info_t rgb_fb_info = {};
void vga_init(void *fb_addr, uint8_t type, framebuffer_info_t *fb_info) {
if (type == VGA_FB_TYPE_EGA_TEXT) {
console_fb_addr = fb_addr;
} else if (type == VGA_FB_TYPE_RGB) {
rgb_fb_addr = fb_addr;
rgb_fb_info = *fb_info;
}
}
void vga_fill_color(uint8_t r, uint8_t g, uint8_t b) {
if (rgb_fb_addr == NULL || rgb_fb_info.bpp != 32) return;
uint32_t color = ((uint32_t) r << rgb_fb_info.red_field_position)
| ((uint32_t) g << rgb_fb_info.green_field_position)
| ((uint32_t) b << rgb_fb_info.blue_field_position);
for (int i = 0; i < rgb_fb_info.width / 2 && i < rgb_fb_info.height / 2; i++) {
uint32_t *pixel = rgb_fb_addr + rgb_fb_info.pitch * i;
printf("Setting pixel %Xh to %Xh\n", (uintptr_t) pixel, color);
*pixel = color;
}
}
int vga_print_char(char c, int col, int row, char attr) {
if (console_fb_addr == NULL) return 0;
if (!attr) attr = WHITE_ON_BLACK;
/* Error control: print a red 'E' if the coords aren't right */
if (col >= MAX_COLS || row >= MAX_ROWS) {
VIDEO_ADDRESS[MAX_COLS * MAX_ROWS - 1] = vga_entry('E', RED_ON_WHITE);
console_fb_addr[MAX_COLS * MAX_ROWS - 1] = vga_entry('E', RED_ON_WHITE);
return vga_get_offset(col, row);
}
@@ -25,18 +53,14 @@ int vga_print_char(char c, int col, int row, char attr) {
row = vga_get_offset_row(offset);
offset = vga_get_offset(0, row + 1);
} else {
VIDEO_ADDRESS[offset++] = ((uint16_t) attr << 8 | c);
console_fb_addr[offset++] = ((uint16_t) attr << 8 | c);
}
vga_set_cursor_offset(offset = vga_handle_scrolling(offset));
return offset;
}
int vga_get_cursor_offset() {
/*
* Use the VGA ports to get the current cursor position
* 1. Ask for high byte of the cursor offset (data 14)
* 2. Ask for low byte (data 15)
*/
if (console_fb_addr == NULL) return 0;
port_byte_out(REG_SCREEN_CTRL, 14);
int offset = port_byte_in(REG_SCREEN_DATA) << 8; /* High byte: << 8 */
port_byte_out(REG_SCREEN_CTRL, 15);
@@ -45,7 +69,7 @@ int vga_get_cursor_offset() {
}
void vga_set_cursor_offset(int offset) {
/* Similar to get_cursor_offset, but instead of reading we write data */
if (console_fb_addr == NULL) return;
port_byte_out(REG_SCREEN_CTRL, 14);
port_byte_out(REG_SCREEN_DATA, (unsigned char) (offset >> 8));
port_byte_out(REG_SCREEN_CTRL, 15);
@@ -53,30 +77,28 @@ void vga_set_cursor_offset(int offset) {
}
void vga_clear_screen() {
memset((void *) VIDEO_ADDRESS, 0, MAX_COLS * MAX_ROWS * sizeof(*VIDEO_ADDRESS));
if (console_fb_addr == NULL) return;
memset((void *) console_fb_addr, 0, MAX_COLS * MAX_ROWS * sizeof(*console_fb_addr));
vga_set_cursor_offset(vga_get_offset(0, 0));
}
/* Advance the text cursor, scrolling the video buffer if necessary. */
int vga_handle_scrolling(int cursor_offset) {
// If the cursor is within the screen, return it unmodified.
if (console_fb_addr == NULL) return 0;
if (cursor_offset < MAX_ROWS * MAX_COLS)
return cursor_offset;
/* Shuffle the rows back one. */
for (int i = 1; i < MAX_ROWS; i++) {
memcpy((void *) (VIDEO_ADDRESS + vga_get_offset(0, i - 1)),
(void *) (VIDEO_ADDRESS + vga_get_offset(0, i)),
MAX_COLS * sizeof(*VIDEO_ADDRESS));
memcpy((void *) (console_fb_addr + vga_get_offset(0, i - 1)),
(void *) (console_fb_addr + vga_get_offset(0, i)),
MAX_COLS * sizeof(*console_fb_addr));
}
/* Blank the last line by setting all bytes to 0 */
memset((void *) (VIDEO_ADDRESS + vga_get_offset(0, MAX_ROWS - 1)),
0, MAX_COLS * sizeof(*VIDEO_ADDRESS));
memset((void *) (console_fb_addr + vga_get_offset(0, MAX_ROWS - 1)),
0, MAX_COLS * sizeof(*console_fb_addr));
// Move the offset back one row, such that it is now on the last
// row, rather than off the edge of the screen.
cursor_offset -= MAX_COLS;
// Return the updated cursor position.
return cursor_offset;
}
+24
View File
@@ -9,6 +9,30 @@
#define REG_SCREEN_CTRL 0x3D4
#define REG_SCREEN_DATA 0x3D5
#define VGA_FB_TYPE_INDEXED 0
#define VGA_FB_TYPE_RGB 1
#define VGA_FB_TYPE_EGA_TEXT 2
struct framebuffer_info {
uint32_t pitch;
uint32_t width;
uint32_t height;
uint8_t bpp;
uint32_t palette_addr;
uint16_t palette_num_colors;
uint8_t red_field_position;
uint8_t red_mask_size;
uint8_t green_field_position;
uint8_t green_mask_size;
uint8_t blue_field_position;
uint8_t blue_mask_size;
};
typedef struct framebuffer_info framebuffer_info_t;
void vga_init(void *fb_addr, uint8_t type, framebuffer_info_t *fb_info);
void vga_fill_color(uint8_t r, uint8_t g, uint8_t b);
int vga_print_char(char c, int col, int row, char attr);
int vga_handle_scrolling(int cursor_offset);
+4 -6
View File
@@ -4,18 +4,16 @@
#include <stdio.h>
#include <errno.h>
#include "dwarf.h"
#include "../elf.h"
#include "../console.h"
#define KERNEL_BASE 0xC0100000
#include "elf.h"
#include "console.h"
void dwarf_find_file(uintptr_t address) {
FILE *file;
// FILE *file;
}
void *dwarf_find_debug_info() {
void *debug_line_ptr = NULL;
uint32_t read = 0;
// uint32_t read = 0;
elf_file_t *elf_file;
if ((elf_file = elf_open("kernel.bin")) == NULL) goto fail;
+16 -1
View File
@@ -172,6 +172,17 @@ static const char *elf_section_type(elf_section_header_type_t type) {
}
}
static const char *elf_obj_type(elf_obj_type_t type) {
switch (type) {
case ELF_ET_NONE: return "None";
case ELF_ET_REL: return "Relocatable";
case ELF_ET_EXEC: return "Executable";
case ELF_ET_DYN: return "Dynamic";
case ELF_ET_CORE: return "Core";
default: return "UNKNOWN";
}
}
void elf_print_sections(elf_file_t *file) {
if (!_elf_read_header(file)
|| !_elf_read_section_header_table(file)
@@ -179,13 +190,17 @@ void elf_print_sections(elf_file_t *file) {
return;
elf_header_t *header = file->header;
printf("ELF type: %s\n", elf_obj_type(header->obj_type));
printf("ELF entry offset: %Xh\n", header->program_entry_offset);
uint16_t num_entries = header->section_header_num_entries;
for (uint16_t i = 0; i < num_entries; ++i) {
elf_section_header_t *section_header = (void *) file->sht_start + header->section_header_entry_size * i;
if (section_header->type == ELF_SHT_NULL) continue; // Skip null header
printf("Section %03d %s: offset "PRIx32", size "PRIx32", type %s\n",
printf("Section %03d %s: offset "PRIx32", size "PRIx32", VMA "PRIXUPTR", type %s\n",
i, file->sht_str_section + section_header->name,
section_header->offset, section_header->size,
section_header->address,
elf_section_type(section_header->type));
}
}
+43 -18
View File
@@ -44,11 +44,11 @@ static_assert(sizeof(elf_machine_type_t) == sizeof(uint16_t),
"elf_machine_type incorrect size");
enum elf_obj_type {
ELF_ET_NONE = 0,
ELF_ET_REL = 1,
ELF_ET_EXEC = 2,
ELF_ET_DYN = 3,
ELF_ET_CORE = 4,
ELF_ET_NONE = 0, // No file type
ELF_ET_REL = 1, // Relocatable file
ELF_ET_EXEC = 2, // Executable file
ELF_ET_DYN = 3, // Shared object file (& PIE executables)
ELF_ET_CORE = 4, // Core file
ELF_ET_LOPROC = 0xFF00,
ELF_ET_HIPROC = 0xFFFF
};
@@ -83,22 +83,22 @@ static_assert(sizeof(elf_header_t) == 52,
"elf_header incorrect size");
enum elf_section_header_type {
ELF_SHT_NULL = 0,
ELF_SHT_PROGBITS = 1,
ELF_SHT_SYMTAB = 2,
ELF_SHT_STRTAB = 3,
ELF_SHT_RELA = 4,
ELF_SHT_HASH = 5,
ELF_SHT_DYNAMIC = 6,
ELF_SHT_NOTE = 7,
ELF_SHT_NOBITS = 8,
ELF_SHT_REL = 9,
ELF_SHT_SHLIB = 10,
ELF_SHT_DYNSYM = 11,
ELF_SHT_NULL = 0, // Unused
ELF_SHT_PROGBITS = 1, // Program bits
ELF_SHT_SYMTAB = 2, // Symbol table
ELF_SHT_STRTAB = 3, // String table
ELF_SHT_RELA = 4, // Relocation entries w/ explicit addends
ELF_SHT_HASH = 5, // Symbol hash table
ELF_SHT_DYNAMIC = 6, // Dynamic linking information
ELF_SHT_NOTE = 7, // Auxiliary information
ELF_SHT_NOBITS = 8, // Program bits with zero size in file
ELF_SHT_REL = 9, // Relocation entries w/o explicit addends
ELF_SHT_SHLIB = 10, // Reserved
ELF_SHT_DYNSYM = 11, // Dynamic symbol table
ELF_SHT_LOPROC = 0x70000000,
ELF_SHT_HIPROC = 0x7FFFFFFF,
ELF_SHT_LOUSER = 0x80000000,
ELF_SHT_HIUSER = 0xFFFFFFFF
ELF_SHT_HIUSER = 0xFFFFFFFF,
};
typedef enum elf_section_header_type elf_section_header_type_t;
@@ -122,6 +122,31 @@ typedef struct elf_section_header elf_section_header_t;
//static_assert(sizeof(elf_section_header_t) == 32,
// "elf_section_header incorrect size");
enum elf_program_header_type {
ELF_PT_NULL = 0, // Unused
ELF_PT_LOAD = 1, // Loadable segment
ELF_PT_DYNAMIC = 2, // Dynamic linking information
ELF_PT_INTERP = 3, // Interpreter
ELF_PT_NOTE = 4, // Auxiliary information
ELF_PT_SHLIB = 5, // Reserved
ELF_PT_PHDR = 6, // Program header table
ELF_PT_LOPROC = 0x70000000,
ELF_PT_HIPROC = 0x7FFFFFFF
};
typedef enum elf_program_header_type elf_program_header_type_t;
struct _packed elf_program_header {
elf_program_header_type_t type;
uint32_t offset; // Offset from start of file
uint32_t vaddr; // Virtual address
uint32_t paddr; // Physical address (ignored?)
uint32_t file_size; // Size in file
uint32_t memory_size; // Size in memory
uint32_t flags; // ?
uint32_t align; // Memory alignment
};
typedef struct elf_program_header elf_program_header_t;
struct elf_file {
FILE *fd;
elf_header_t *header;
+18 -18
View File
@@ -93,19 +93,19 @@ isr_common_stub:
mov ax, ds ; Lower 16-bits of eax = ds.
push eax ; save the data segment descriptor
mov ax, 0x10 ; load the kernel data segment descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
;mov ax, 0x10 ; load the kernel data segment descriptor
;mov ds, ax
;mov es, ax
;mov fs, ax
;mov gs, ax
call isr_handler
pop eax ; reload the original data segment descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
;mov ds, ax
;mov es, ax
;mov fs, ax
;mov gs, ax
; Restore the MXCSR register.
ldmxcsr [esp]
@@ -129,19 +129,19 @@ irq_common_stub:
mov ax, ds ; Lower 16-bits of eax = ds.
push eax ; save the data segment descriptor
mov ax, 0x10 ; load the kernel data segment descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
;mov ax, 0x10 ; load the kernel data segment descriptor
;mov ds, ax
;mov es, ax
;mov fs, ax
;mov gs, ax
call irq_handler
pop ebx ; reload the original data segment descriptor
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
;mov ds, bx
;mov es, bx
;mov fs, bx
;mov gs, bx
; Restore the MXCSR register.
ldmxcsr [esp]
+2 -2
View File
@@ -10,7 +10,7 @@
#include "fatfs/ff.h"
#ifdef ENABLE_DWARF
#include "debug/dwarf.h"
#include "dwarf.h"
#endif
#include <common.h>
@@ -18,7 +18,7 @@
// #define KDEBUG
extern bool vc_vector_run_tests();
extern void *load_page_table();
_noreturn _unused
void kernel_main(uint32_t multiboot_magic, void *multiboot_info) {
+59 -21
View File
@@ -1,9 +1,14 @@
#include <stdio.h>
#include <string.h>
#include "multiboot.h"
#include "console.h"
#include "arch/x86/mmu.h"
#include "drivers/vga.h"
#define PAGE_OFFSET 0xC0000000
#define KERNEL_OFFSET 0x200000 // FIXME
#define BASE_VIDEO_ADDRESS ((void *) 0xB8000)
#define MULTIBOOT_CHECK_FLAG(flags, flag) (((flags) & (flag)) == (flag))
extern void *malloc_memory_start;
extern void *malloc_memory_end;
@@ -13,12 +18,12 @@ void multiboot_init(uint32_t magic, void *info_ptr) {
panic("multiboot_magic: Invalid magic "PRIX32"\n", magic);
}
// XXX: uintptr_t hack b/c of compiler optimization which then triggers ubsan ¯\_(ツ)_/¯
struct multiboot_info *info = (struct multiboot_info *) ((uintptr_t) info_ptr + PAGE_OFFSET);
struct multiboot_info *info = (struct multiboot_info *) kernel_page_offset(info_ptr);
printf("multiboot_info = "PRIXPTR", flags = "PRIx32"\n", info, info->flags);
if (CHECK_FLAG(info->flags, MULTIBOOT_INFO_MEMORY)) {
malloc_memory_start = (void *) 0x100000 + PAGE_OFFSET + KERNEL_OFFSET;
// Check for base memory information.
if (MULTIBOOT_CHECK_FLAG(info->flags, MULTIBOOT_INFO_MEMORY)) {
malloc_memory_start = kernel_page_offset((void *) 0x100000 + KERNEL_OFFSET);
// 1 MiB + (info->mem_upper * 1 KiB)
malloc_memory_end = malloc_memory_start + (info->mem_upper * 0x400) - KERNEL_OFFSET;
printf("upper_memory_end = "PRIXPTR"\n", malloc_memory_end);
@@ -26,44 +31,48 @@ void multiboot_init(uint32_t magic, void *info_ptr) {
panic("multiboot: Memory information required");
}
if (CHECK_FLAG(info->flags, MULTIBOOT_INFO_BOOTDEV)) {
// Check for boot device.
if (MULTIBOOT_CHECK_FLAG(info->flags, MULTIBOOT_INFO_BOOTDEV)) {
printf("boot_device = "PRIx32"h\n", info->boot_device);
}
if (CHECK_FLAG(info->flags, MULTIBOOT_INFO_CMDLINE)) {
printf("cmdline = %s\n", (char *) (info->cmdline + PAGE_OFFSET));
// Check for command line.
if (MULTIBOOT_CHECK_FLAG(info->flags, MULTIBOOT_INFO_CMDLINE)) {
char *cmdline = (char *) kernel_page_offset((void *) info->cmdline);
printf("cmdline size %d = %s\n", strlen(cmdline), cmdline);
}
if (CHECK_FLAG(info->flags, MULTIBOOT_INFO_MODS)) {
// Check for modules.
if (MULTIBOOT_CHECK_FLAG(info->flags, MULTIBOOT_INFO_MODS)) {
struct multiboot_mod_list *mod;
int i;
printf("mods_count = "PRIu32", mods_addr = "PRIXUPTR"\n", info->mods_count, info->mods_addr);
for (i = 0, mod = (struct multiboot_mod_list *) (info->mods_addr + PAGE_OFFSET);
for (i = 0, mod = (struct multiboot_mod_list *) kernel_page_offset((void *) info->mods_addr);
i < info->mods_count;
i++, mod++) {
printf(" mod_start = "PRIXUPTR", mod_end = "PRIXUPTR", cmdline = %s\n",
mod->mod_start, mod->mod_end, (char *) (mod->cmdline + PAGE_OFFSET));
mod->mod_start, mod->mod_end, (char *) kernel_page_offset((void *) mod->cmdline));
}
}
/* Is the section header table of ELF valid? */
if (CHECK_FLAG(info->flags, MULTIBOOT_INFO_ELF_SHDR)) {
// Check for ELF section header table information.
if (MULTIBOOT_CHECK_FLAG(info->flags, MULTIBOOT_INFO_ELF_SHDR)) {
struct multiboot_elf_section_header_table *elf_sec = &info->u.elf_sec;
printf("multiboot_elf_sec: num = "PRIu32", size = "PRIu32", addr = "PRIXUPTR", shndx = "PRIu32"\n",
elf_sec->num, elf_sec->size, elf_sec->addr, elf_sec->shndx);
}
/* Are mmap_* valid? */
if (CHECK_FLAG(info->flags, MULTIBOOT_INFO_MEM_MAP)) {
// Check for memory map information
if (MULTIBOOT_CHECK_FLAG(info->flags, MULTIBOOT_INFO_MEM_MAP)) {
printf("mmap_addr = "PRIXUPTR", mmap_length = "PRIx32"\n", info->mmap_addr, info->mmap_length);
struct multiboot_mmap_entry *mmap;
struct multiboot_mmap_entry *largest_available_entry = NULL;
for (mmap = (struct multiboot_mmap_entry *) (info->mmap_addr + PAGE_OFFSET);
(unsigned long) mmap < info->mmap_addr + PAGE_OFFSET + info->mmap_length;
for (mmap = (struct multiboot_mmap_entry *) kernel_page_offset((void *) info->mmap_addr);
(uintptr_t) mmap < (uintptr_t) kernel_page_offset((void *) info->mmap_addr + info->mmap_length);
mmap = (struct multiboot_mmap_entry *)
((unsigned long) mmap + mmap->size + sizeof(mmap->size))) {
((uintptr_t) mmap + mmap->size + sizeof(mmap->size))) {
if (mmap->type == MULTIBOOT_MEMORY_AVAILABLE &&
(largest_available_entry == NULL || mmap->len > largest_available_entry->len)) {
largest_available_entry = mmap;
@@ -74,26 +83,55 @@ void multiboot_init(uint32_t magic, void *info_ptr) {
}
if (largest_available_entry != NULL) {
malloc_memory_start = (void *) (uint32_t) largest_available_entry->addr + PAGE_OFFSET + KERNEL_OFFSET;
malloc_memory_start = kernel_page_offset((void *) (uintptr_t) largest_available_entry->addr + KERNEL_OFFSET);
malloc_memory_end = malloc_memory_start + largest_available_entry->len - KERNEL_OFFSET;
printf("malloc_memory_start = "PRIXPTR", end = "PRIXPTR"\n", malloc_memory_start, malloc_memory_end);
}
}
/* Check VGA framebuffer. */
if (CHECK_FLAG (info->flags, MULTIBOOT_INFO_FRAMEBUFFER_INFO)) {
// Check for VBE info.
if (MULTIBOOT_CHECK_FLAG(info->flags, MULTIBOOT_INFO_VBE_INFO)) {
printf("vbe_control_info = "PRIXUPTR", vbe_mode_info = "PRIXUPTR", vbe_mode = %d\n",
info->vbe_control_info, info->vbe_mode_info, info->vbe_mode);
}
// Check for VGA framebuffer information.
if (MULTIBOOT_CHECK_FLAG(info->flags, MULTIBOOT_INFO_FRAMEBUFFER_INFO)) {
printf("framebuffer_addr = "PRIXUPTR64", type = %d, bpp = %d\n",
info->framebuffer_addr, info->framebuffer_type, info->framebuffer_bpp);
uintptr_t fbaddr = (uintptr_t) info->framebuffer_addr;
page_table_set(fbaddr, 0x83); // Add framebuffer to page table
vga_init((void *) fbaddr, info->framebuffer_type, &(framebuffer_info_t) {
.pitch = info->framebuffer_pitch,
.width = info->framebuffer_width,
.height = info->framebuffer_height,
.bpp = info->framebuffer_bpp,
.palette_addr = info->framebuffer_palette_addr,
.palette_num_colors = info->framebuffer_palette_num_colors,
.red_field_position = info->framebuffer_red_field_position,
.red_mask_size = info->framebuffer_red_mask_size,
.green_field_position = info->framebuffer_green_field_position,
.green_mask_size = info->framebuffer_green_mask_size,
.blue_field_position = info->framebuffer_blue_field_position,
.blue_mask_size = info->framebuffer_blue_mask_size,
});
switch (info->framebuffer_type) {
case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT:
console_set_vga_enabled(true);
break;
case MULTIBOOT_FRAMEBUFFER_TYPE_RGB:
vga_fill_color(255, 255, 255);
break;
default:
break;
}
} else {
// Assume text console & hardcoded FB address for now
vga_init(kernel_page_offset(BASE_VIDEO_ADDRESS), 2, 0);
console_set_vga_enabled(true); // FIXME
}
}
-2
View File
@@ -50,8 +50,6 @@
#define MULTIBOOT_MEMORY_NVS 4
#define MULTIBOOT_MEMORY_BADRAM 5
#define CHECK_FLAG(flags, flag) (((flags) & (flag)) == (flag))
struct multiboot_aout_symbol_table {
uint32_t tabsize;
uint32_t strsize;
+40 -2
View File
@@ -186,7 +186,41 @@ static uint8_t command_cat(const char *path) {
return 0;
}
static void print_prompt(unsigned char ret) {
static int command_exec(const char *path) {
if (!_fs_mounted) return 255;
elf_file_t *file;
char path_buf[512];
void *text_ptr;
path_append(path_buf, curr_path, path, sizeof(path_buf));
if ((file = elf_open(path_buf)) == NULL) {
fprintf(stderr, "Error opening %s: %d\n", path_buf, errno);
return 1;
}
elf_section_header_t *text_header = elf_find_section(file, ".text");
if ((text_ptr = malloc(text_header->size)) == NULL) {
fprintf(stderr, "Failed to allocate memory for %s\n", path_buf);
elf_close(file);
return ENOMEM;
}
fseek(file->fd, text_header->offset, SEEK_SET);
fread(text_ptr, text_header->size, 1, file->fd);
if (ferror(file->fd)) {
fprintf(stderr, "Failed reading %s: %d\n", path_buf, errno);
elf_close(file);
return 2;
}
int ret = ((int (*)(void)) text_ptr)();
free(text_ptr);
elf_close(file);
return ret;
}
static void print_prompt(int ret) {
if (_fs_mounted) {
printf("%d %s # ", ret, curr_path);
} else {
@@ -198,7 +232,7 @@ static void print_prompt(unsigned char ret) {
static void shell_callback(char *input) {
printf("\n");
unsigned char ret = 1;
int ret = 1;
bool save = true;
if (strcmp(input, "exit") == 0 ||
strcmp(input, "poweroff") == 0) {
@@ -261,6 +295,10 @@ static void shell_callback(char *input) {
ret = command_objdump(input + 8);
} else if (strncmp(input, "cat ", 4) == 0) {
ret = command_cat(input + 4);
} else if (strncmp(input, "./", 2) == 0) {
ret = command_exec(input + 2);
} else {
fprintf(stderr, "Command not found: %s\n", input);
}
print_prompt(ret);
+13 -38
View File
@@ -1,4 +1,3 @@
; Declare constants for the multiboot header.
FMBALIGN equ 1 << 0 ; align loaded modules on page boundaries
FMEMINFO equ 1 << 1 ; provide memory map
FVIDMODE equ 1 << 2 ; try to set graphics mode
@@ -6,34 +5,20 @@ FLAGS equ FMBALIGN | FMEMINFO | FVIDMODE
MAGIC equ 0x1BADB002
CHECKSUM equ -(MAGIC + FLAGS)
; This is the virtual base address of kernel space. It must be used to convert virtual
; addresses into physical addresses until paging is enabled.
KERNEL_VIRTUAL_BASE equ 0xC0000000 ; 3GB
KERNEL_PAGE_NUMBER equ (KERNEL_VIRTUAL_BASE >> 22) ; 768 -- Page directory index of kernel's 4MB PTE.
KERNEL_PAGE_NUMBER equ (KERNEL_VIRTUAL_BASE >> 22) ; 768
section .data
align 0x1000
boot_page_directory:
; This page directory entry identity-maps the first 4MB of the 32-bit physical address space.
; All bits are clear except the following:
; bit 7: PS The kernel page is 4MB.
; bit 1: RW The kernel page is read/write.
; bit 0: P The kernel page is present.
; 4MiB lower-half kernel page
dd 0x83
times (KERNEL_PAGE_NUMBER - 1) dd 0
; This entry must be here -- otherwise the kernel will crash immediately after paging is
; enabled because it can't fetch the next instruction! It's ok to unmap this page later.
dd 0x00000083
times (KERNEL_PAGE_NUMBER - 1) dd 0 ; Pages before kernel space.
; 4MiB higher-half kernel page
dd 0x83
times (1024 - KERNEL_PAGE_NUMBER - 1) dd 0
; This page directory entry defines a 4MB page containing the kernel.
dd 0x00000083
times (1024 - KERNEL_PAGE_NUMBER - 1) dd 0 ; Pages after the kernel image.
; Declare a multiboot header that marks the program as a kernel. These are magic
; values that are documented in the multiboot standard. The bootloader will
; search for this signature in the first 8 KiB of the kernel file, aligned at a
; 32-bit boundary. The signature is in its own section so the header can be
; forced to be within the first 8 KiB of the kernel file.
section .multiboot
align 4
; header
@@ -49,7 +34,7 @@ align 4
dd 0 ; entry_addr
; graphics tag
dd 1 ; mode_type
dd 0 ; mode_type
dd 800 ; width
dd 600 ; height
dd 32 ; depth
@@ -61,15 +46,11 @@ stack_bottom:
resb 0x4000 ; 16 KiB
stack_top:
; The linker script specifies _start as the entry point to the kernel and the
; bootloader will jump to this position once the kernel has been loaded. It
; doesn't make sense to return from this function as the bootloader is gone.
; Declare _start as a function symbol with the given symbol size.
section .text
global _start:function (_start.end - _start)
_start:
mov ecx, (boot_page_directory - KERNEL_VIRTUAL_BASE)
mov cr3, ecx ; Load Page Directory Base Register.
mov cr3, ecx ; Load boot_page_directory into CR3
mov ecx, cr4
or ecx, (1 << 4) ; Set PSE bit in CR4 to enable 4MB pages.
@@ -79,12 +60,11 @@ _start:
or ecx, (1 << 31) ; Set PG bit in CR0 to enable paging.
mov cr0, ecx
lea ecx, [.start_higher_half] ; far jump
lea ecx, [.start_higher_half] ; Far jump
jmp ecx
.start_higher_half:
; Unmap the identity-mapped first 4MB of physical address space.
; It should not be needed anymore.
; Unmap lower-half kernel page
mov dword [boot_page_directory], 0
invlpg [0]
@@ -107,13 +87,8 @@ _start:
; Initialize GDT & IDT
extern init_descriptor_tables
call init_descriptor_tables
; Enter the high-level kernel. The ABI requires the stack is 16-byte
; aligned at the time of the call instruction (which afterwards pushes
; the return pointer of size 4 bytes). The stack was originally 16-byte
; aligned above and we've since pushed a multiple of 16 bytes to the
; stack since (pushed 0 bytes so far) and the alignment is thus
; preserved and the call is well defined.
; Enter kernel
extern kernel_main
call kernel_main