structure project
This commit is contained in:
137
src/arch/x86_64/interrupts.c
Normal file
137
src/arch/x86_64/interrupts.c
Normal file
@@ -0,0 +1,137 @@
|
||||
#include "interrupts.h"
|
||||
#include "../../util.h"
|
||||
|
||||
#define PIC1_COMMAND 0x20
|
||||
#define PIC1_DATA 0x21
|
||||
#define PIC2_COMMAND 0xA0
|
||||
#define PIC2_DATA 0xA1
|
||||
|
||||
static const char* exception_messages[32] = {
|
||||
"divide by zero",
|
||||
"debug",
|
||||
"non maskable interrupt",
|
||||
"breakpoint",
|
||||
"overflow",
|
||||
"bound range exceeded",
|
||||
"invalid opcode",
|
||||
"device not available",
|
||||
"double fault",
|
||||
"coprocessor segment overrun",
|
||||
"invalid tss",
|
||||
"segment not present",
|
||||
"stack-segment fault",
|
||||
"general protection fault",
|
||||
"page fault",
|
||||
"reserved",
|
||||
"x87 floating point exception",
|
||||
"alignment check",
|
||||
"machine check",
|
||||
"simd floating point exception",
|
||||
"virtualization exception",
|
||||
"control protection exception",
|
||||
"reserved",
|
||||
"reserved",
|
||||
"reserved",
|
||||
"reserved",
|
||||
"reserved",
|
||||
"reserved",
|
||||
"hypervisor injection exception",
|
||||
"vmm communication exception",
|
||||
"security exception",
|
||||
"reserved",
|
||||
};
|
||||
|
||||
static irq_handler_t irq_handlers[16] = {0};
|
||||
|
||||
bool cpu_has_apic()
|
||||
{
|
||||
uint32_t eax, edx;
|
||||
cpuid(1, &eax, &edx);
|
||||
return (edx & CPUID_FEAT_EDX_APIC) != 0;
|
||||
}
|
||||
|
||||
void enable_apic()
|
||||
{
|
||||
uint64_t apic_base = rdmsr(0x1B);
|
||||
apic_base |= (1 << 11);
|
||||
wrmsr(0x1B, apic_base);
|
||||
printf("APIC enabled\n");
|
||||
}
|
||||
|
||||
void remap_pic()
|
||||
{
|
||||
outb(PIC1_COMMAND, 0x11);
|
||||
outb(PIC2_COMMAND, 0x11);
|
||||
|
||||
outb(PIC1_DATA, 32);
|
||||
outb(PIC2_DATA, 40);
|
||||
|
||||
outb(PIC1_DATA, 4);
|
||||
outb(PIC2_DATA, 2);
|
||||
|
||||
outb(PIC1_DATA, 1);
|
||||
outb(PIC2_DATA, 1);
|
||||
|
||||
outb(PIC1_DATA, 0);
|
||||
outb(PIC2_DATA, 0);
|
||||
printf("PIC remapped\n");
|
||||
}
|
||||
|
||||
void disable_pic()
|
||||
{
|
||||
outb(PIC1_DATA, 0xFF);
|
||||
outb(PIC2_DATA, 0xFF);
|
||||
printf("PIC disabled\n");
|
||||
}
|
||||
|
||||
void handle_exception(const isr_frame_t* frame)
|
||||
{
|
||||
printf("exception[%d]: %s, error code: %d\n", frame->int_no, exception_messages[frame->int_no], frame->err_code);
|
||||
panic();
|
||||
}
|
||||
|
||||
void register_irq_handler(uint8_t irq, irq_handler_t handler)
|
||||
{
|
||||
if (irq >= 16)
|
||||
{
|
||||
printf("Cannot register irq %d is out of bounds\n", irq);
|
||||
}
|
||||
else
|
||||
{
|
||||
irq_handlers[irq] = handler;
|
||||
printf("Registered irq handler at vector %d\n", irq);
|
||||
}
|
||||
}
|
||||
|
||||
void handle_irq(const isr_frame_t* frame)
|
||||
{
|
||||
uint8_t irq = frame->int_no - 32;
|
||||
|
||||
if (irq_handlers[irq])
|
||||
{
|
||||
irq_handlers[irq](frame);
|
||||
}
|
||||
|
||||
if (irq >= 8)
|
||||
{
|
||||
outb(PIC2_COMMAND, 0x20);
|
||||
}
|
||||
|
||||
outb(PIC1_COMMAND, 0x20);
|
||||
}
|
||||
|
||||
void handle_isr(const isr_frame_t* frame)
|
||||
{
|
||||
if (frame->int_no < 32)
|
||||
{
|
||||
handle_exception(frame);
|
||||
}
|
||||
else if (frame->int_no < 48)
|
||||
{
|
||||
handle_irq(frame);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("interrupt[%d]: not implemented\n", frame->int_no);
|
||||
}
|
||||
}
|
||||
36
src/arch/x86_64/interrupts.h
Normal file
36
src/arch/x86_64/interrupts.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../kernel.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
|
||||
uint64_t rbp, rdi, rsi, rdx, rcx, rbx, rax;
|
||||
uint64_t int_no;
|
||||
uint64_t err_code;
|
||||
uint64_t rip, cs, rflags, rsp, ss;
|
||||
} __attribute__((packed)) isr_frame_t;
|
||||
|
||||
typedef void (*irq_handler_t)(const isr_frame_t*);
|
||||
|
||||
void remap_pic();
|
||||
void disable_pic();
|
||||
|
||||
bool cpu_has_apic();
|
||||
void enable_apic();
|
||||
|
||||
void register_irq_handler(uint8_t irq, irq_handler_t handler);
|
||||
|
||||
static inline void enable_interrupts()
|
||||
{
|
||||
__asm__ volatile("sti");
|
||||
printf("Interrupts enabled\n");
|
||||
}
|
||||
|
||||
static inline void disable_interrupts()
|
||||
{
|
||||
__asm__ volatile("cli");
|
||||
printf("Interrupts disabled\n");
|
||||
}
|
||||
110
src/arch/x86_64/keyboard.c
Normal file
110
src/arch/x86_64/keyboard.c
Normal file
@@ -0,0 +1,110 @@
|
||||
#include "keyboard.h"
|
||||
#include "../../kernel.h"
|
||||
#include "../../util.h"
|
||||
#include "interrupts.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#define SCANCODE_LEFT_SHIFT 42
|
||||
#define SCANCODE_RIGHT_SHIFT 54
|
||||
#define SCANCODE_CAPS_LOCK 58
|
||||
|
||||
#define KEYBOARD_HANDLERS_LENGTH 32
|
||||
|
||||
unsigned const char us_keymap[128] = {
|
||||
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', '\t', 'q', 'w',
|
||||
'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0, 'a', 's', 'd', 'f', 'g', 'h',
|
||||
'j', 'k', 'l', ';', '\'', '`', 0, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/',
|
||||
0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, '-', 0, 0, 0, '+', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
unsigned const char us_keymap_shift[128] = {
|
||||
0, 27, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b', '\t', 'Q', 'W',
|
||||
'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', 0, 'A', 'S', 'D', 'F', 'G', 'H',
|
||||
'J', 'K', 'L', ':', '"', '~', 0, '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?',
|
||||
0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, '-', 0, 0, 0, '+', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
bool shift = false;
|
||||
bool caps_lock = false;
|
||||
|
||||
// todo(nub): make dynamic when a memory allocator is implemented
|
||||
static keyboard_handler_t keyboard_handlers[KEYBOARD_HANDLERS_LENGTH];
|
||||
static size_t handler_index = 0;
|
||||
|
||||
char scan_code_to_ascii(uint8_t scan_code)
|
||||
{
|
||||
if (scan_code >= 128)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((!caps_lock && shift) || (caps_lock && !shift))
|
||||
{
|
||||
return us_keymap_shift[scan_code];
|
||||
}
|
||||
else
|
||||
{
|
||||
return us_keymap[scan_code];
|
||||
}
|
||||
}
|
||||
|
||||
void handle_keyboard(const isr_frame_t* frame)
|
||||
{
|
||||
uint8_t code = inb(0x60);
|
||||
uint8_t scan_code = code & 0x7F;
|
||||
bool pressed = (code & 0x80) == 0;
|
||||
|
||||
switch (scan_code)
|
||||
{
|
||||
case SCANCODE_LEFT_SHIFT:
|
||||
case SCANCODE_RIGHT_SHIFT:
|
||||
{
|
||||
shift = pressed;
|
||||
break;
|
||||
}
|
||||
case SCANCODE_CAPS_LOCK:
|
||||
{
|
||||
if (pressed)
|
||||
{
|
||||
caps_lock = !caps_lock;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
keyboard_event_t event = {
|
||||
.scan_code = scan_code,
|
||||
.pressed = pressed,
|
||||
.caps_lock = caps_lock,
|
||||
.shift = shift,
|
||||
.ascii = scan_code_to_ascii(scan_code),
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < handler_index; i++)
|
||||
{
|
||||
keyboard_handlers[i](&event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void register_keypress_handler(const keyboard_handler_t handler)
|
||||
{
|
||||
// todo(nub31): remove when a memory allocator is implemented and
|
||||
// keyboard_handlers is a dynamic list
|
||||
if (handler_index >= KEYBOARD_HANDLERS_LENGTH)
|
||||
{
|
||||
printf("Maximum keyboard handlers reached\n");
|
||||
panic();
|
||||
}
|
||||
|
||||
keyboard_handlers[handler_index] = handler;
|
||||
handler_index += 1;
|
||||
}
|
||||
|
||||
void init_keyboard()
|
||||
{
|
||||
register_irq_handler(1, handle_keyboard);
|
||||
}
|
||||
19
src/arch/x86_64/keyboard.h
Normal file
19
src/arch/x86_64/keyboard.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t scan_code;
|
||||
bool pressed;
|
||||
bool shift;
|
||||
bool caps_lock;
|
||||
char ascii;
|
||||
} keyboard_event_t;
|
||||
|
||||
typedef void (*keyboard_handler_t)(const keyboard_event_t*);
|
||||
|
||||
void init_keyboard();
|
||||
void register_keypress_handler(keyboard_handler_t handler);
|
||||
char scan_code_to_ascii(uint8_t scan_code);
|
||||
276
src/arch/x86_64/multiboot.h
Normal file
276
src/arch/x86_64/multiboot.h
Normal file
@@ -0,0 +1,276 @@
|
||||
/* multiboot.h - Multiboot header file. */
|
||||
/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY
|
||||
* DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MULTIBOOT_HEADER
|
||||
#define MULTIBOOT_HEADER 1
|
||||
|
||||
/* How many bytes from the start of the file we search for the header. */
|
||||
#define MULTIBOOT_SEARCH 8192
|
||||
#define MULTIBOOT_HEADER_ALIGN 4
|
||||
|
||||
/* The magic field should contain this. */
|
||||
#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
|
||||
|
||||
/* This should be in %eax. */
|
||||
#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
|
||||
|
||||
/* Alignment of multiboot modules. */
|
||||
#define MULTIBOOT_MOD_ALIGN 0x00001000
|
||||
|
||||
/* Alignment of the multiboot info structure. */
|
||||
#define MULTIBOOT_INFO_ALIGN 0x00000004
|
||||
|
||||
/* Flags set in the ’flags’ member of the multiboot header. */
|
||||
|
||||
/* Align all boot modules on i386 page (4KB) boundaries. */
|
||||
#define MULTIBOOT_PAGE_ALIGN 0x00000001
|
||||
|
||||
/* Must pass memory information to OS. */
|
||||
#define MULTIBOOT_MEMORY_INFO 0x00000002
|
||||
|
||||
/* Must pass video information to OS. */
|
||||
#define MULTIBOOT_VIDEO_MODE 0x00000004
|
||||
|
||||
/* This flag indicates the use of the address fields in the header. */
|
||||
#define MULTIBOOT_AOUT_KLUDGE 0x00010000
|
||||
|
||||
/* Flags to be set in the ’flags’ member of the multiboot info structure. */
|
||||
|
||||
/* is there basic lower/upper memory information? */
|
||||
#define MULTIBOOT_INFO_MEMORY 0x00000001
|
||||
/* is there a boot device set? */
|
||||
#define MULTIBOOT_INFO_BOOTDEV 0x00000002
|
||||
/* is the command-line defined? */
|
||||
#define MULTIBOOT_INFO_CMDLINE 0x00000004
|
||||
/* are there modules to do something with? */
|
||||
#define MULTIBOOT_INFO_MODS 0x00000008
|
||||
|
||||
/* These next two are mutually exclusive */
|
||||
|
||||
/* is there a symbol table loaded? */
|
||||
#define MULTIBOOT_INFO_AOUT_SYMS 0x00000010
|
||||
/* is there an ELF section header table? */
|
||||
#define MULTIBOOT_INFO_ELF_SHDR 0X00000020
|
||||
|
||||
/* is there a full memory map? */
|
||||
#define MULTIBOOT_INFO_MEM_MAP 0x00000040
|
||||
|
||||
/* Is there drive info? */
|
||||
#define MULTIBOOT_INFO_DRIVE_INFO 0x00000080
|
||||
|
||||
/* Is there a config table? */
|
||||
#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100
|
||||
|
||||
/* Is there a boot loader name? */
|
||||
#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200
|
||||
|
||||
/* Is there a APM table? */
|
||||
#define MULTIBOOT_INFO_APM_TABLE 0x00000400
|
||||
|
||||
/* Is there video information? */
|
||||
#define MULTIBOOT_INFO_VBE_INFO 0x00000800
|
||||
#define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000
|
||||
|
||||
#ifndef ASM_FILE
|
||||
|
||||
typedef unsigned char multiboot_uint8_t;
|
||||
typedef unsigned short multiboot_uint16_t;
|
||||
typedef unsigned int multiboot_uint32_t;
|
||||
typedef unsigned long long multiboot_uint64_t;
|
||||
|
||||
struct multiboot_header
|
||||
{
|
||||
/* Must be MULTIBOOT_MAGIC - see above. */
|
||||
multiboot_uint32_t magic;
|
||||
|
||||
/* Feature flags. */
|
||||
multiboot_uint32_t flags;
|
||||
|
||||
/* The above fields plus this one must equal 0 mod 2^32. */
|
||||
multiboot_uint32_t checksum;
|
||||
|
||||
/* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */
|
||||
multiboot_uint32_t header_addr;
|
||||
multiboot_uint32_t load_addr;
|
||||
multiboot_uint32_t load_end_addr;
|
||||
multiboot_uint32_t bss_end_addr;
|
||||
multiboot_uint32_t entry_addr;
|
||||
|
||||
/* These are only valid if MULTIBOOT_VIDEO_MODE is set. */
|
||||
multiboot_uint32_t mode_type;
|
||||
multiboot_uint32_t width;
|
||||
multiboot_uint32_t height;
|
||||
multiboot_uint32_t depth;
|
||||
};
|
||||
|
||||
/* The symbol table for a.out. */
|
||||
struct multiboot_aout_symbol_table
|
||||
{
|
||||
multiboot_uint32_t tabsize;
|
||||
multiboot_uint32_t strsize;
|
||||
multiboot_uint32_t addr;
|
||||
multiboot_uint32_t reserved;
|
||||
};
|
||||
typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t;
|
||||
|
||||
/* The section header table for ELF. */
|
||||
struct multiboot_elf_section_header_table
|
||||
{
|
||||
multiboot_uint32_t num;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint32_t addr;
|
||||
multiboot_uint32_t shndx;
|
||||
};
|
||||
typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t;
|
||||
|
||||
struct multiboot_info
|
||||
{
|
||||
/* Multiboot info version number */
|
||||
multiboot_uint32_t flags;
|
||||
|
||||
/* Available memory from BIOS */
|
||||
multiboot_uint32_t mem_lower;
|
||||
multiboot_uint32_t mem_upper;
|
||||
|
||||
/* "root" partition */
|
||||
multiboot_uint32_t boot_device;
|
||||
|
||||
/* Kernel command line */
|
||||
multiboot_uint32_t cmdline;
|
||||
|
||||
/* Boot-Module list */
|
||||
multiboot_uint32_t mods_count;
|
||||
multiboot_uint32_t mods_addr;
|
||||
|
||||
union
|
||||
{
|
||||
multiboot_aout_symbol_table_t aout_sym;
|
||||
multiboot_elf_section_header_table_t elf_sec;
|
||||
} u;
|
||||
|
||||
/* Memory Mapping buffer */
|
||||
multiboot_uint32_t mmap_length;
|
||||
multiboot_uint32_t mmap_addr;
|
||||
|
||||
/* Drive Info buffer */
|
||||
multiboot_uint32_t drives_length;
|
||||
multiboot_uint32_t drives_addr;
|
||||
|
||||
/* ROM configuration table */
|
||||
multiboot_uint32_t config_table;
|
||||
|
||||
/* Boot Loader Name */
|
||||
multiboot_uint32_t boot_loader_name;
|
||||
|
||||
/* APM table */
|
||||
multiboot_uint32_t apm_table;
|
||||
|
||||
/* Video */
|
||||
multiboot_uint32_t vbe_control_info;
|
||||
multiboot_uint32_t vbe_mode_info;
|
||||
multiboot_uint16_t vbe_mode;
|
||||
multiboot_uint16_t vbe_interface_seg;
|
||||
multiboot_uint16_t vbe_interface_off;
|
||||
multiboot_uint16_t vbe_interface_len;
|
||||
|
||||
multiboot_uint64_t framebuffer_addr;
|
||||
multiboot_uint32_t framebuffer_pitch;
|
||||
multiboot_uint32_t framebuffer_width;
|
||||
multiboot_uint32_t framebuffer_height;
|
||||
multiboot_uint8_t framebuffer_bpp;
|
||||
#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
|
||||
#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
|
||||
#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2
|
||||
multiboot_uint8_t framebuffer_type;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
multiboot_uint32_t framebuffer_palette_addr;
|
||||
multiboot_uint16_t framebuffer_palette_num_colors;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
multiboot_uint8_t framebuffer_red_field_position;
|
||||
multiboot_uint8_t framebuffer_red_mask_size;
|
||||
multiboot_uint8_t framebuffer_green_field_position;
|
||||
multiboot_uint8_t framebuffer_green_mask_size;
|
||||
multiboot_uint8_t framebuffer_blue_field_position;
|
||||
multiboot_uint8_t framebuffer_blue_mask_size;
|
||||
};
|
||||
};
|
||||
};
|
||||
typedef struct multiboot_info multiboot_info_t;
|
||||
|
||||
struct multiboot_color
|
||||
{
|
||||
multiboot_uint8_t red;
|
||||
multiboot_uint8_t green;
|
||||
multiboot_uint8_t blue;
|
||||
};
|
||||
|
||||
struct multiboot_mmap_entry
|
||||
{
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint64_t addr;
|
||||
multiboot_uint64_t len;
|
||||
#define MULTIBOOT_MEMORY_AVAILABLE 1
|
||||
#define MULTIBOOT_MEMORY_RESERVED 2
|
||||
#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3
|
||||
#define MULTIBOOT_MEMORY_NVS 4
|
||||
#define MULTIBOOT_MEMORY_BADRAM 5
|
||||
multiboot_uint32_t type;
|
||||
} __attribute__((packed));
|
||||
typedef struct multiboot_mmap_entry multiboot_memory_map_t;
|
||||
|
||||
struct multiboot_mod_list
|
||||
{
|
||||
/* the memory used goes from bytes ’mod_start’ to ’mod_end-1’ inclusive */
|
||||
multiboot_uint32_t mod_start;
|
||||
multiboot_uint32_t mod_end;
|
||||
|
||||
/* Module command line */
|
||||
multiboot_uint32_t cmdline;
|
||||
|
||||
/* padding to take it to 16 bytes (must be zero) */
|
||||
multiboot_uint32_t pad;
|
||||
};
|
||||
typedef struct multiboot_mod_list multiboot_module_t;
|
||||
|
||||
/* APM BIOS info. */
|
||||
struct multiboot_apm_info
|
||||
{
|
||||
multiboot_uint16_t version;
|
||||
multiboot_uint16_t cseg;
|
||||
multiboot_uint32_t offset;
|
||||
multiboot_uint16_t cseg_16;
|
||||
multiboot_uint16_t dseg;
|
||||
multiboot_uint16_t flags;
|
||||
multiboot_uint16_t cseg_len;
|
||||
multiboot_uint16_t cseg_16_len;
|
||||
multiboot_uint16_t dseg_len;
|
||||
};
|
||||
|
||||
#endif /* ! ASM_FILE */
|
||||
|
||||
#endif /* ! MULTIBOOT_HEADER */
|
||||
124
src/arch/x86_64/pmm.c
Normal file
124
src/arch/x86_64/pmm.c
Normal file
@@ -0,0 +1,124 @@
|
||||
#include "pmm.h"
|
||||
#include "../../kernel.h"
|
||||
#include "../../mem.h"
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define BITMAP_SIZE 32768 // Supports up to 1GB of RAM
|
||||
#define USABLE_REGION_SIZE 32
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint64_t base_address;
|
||||
uint64_t length;
|
||||
} memory_region_t;
|
||||
|
||||
static uint8_t page_bitmap[BITMAP_SIZE];
|
||||
static uint64_t total_pages = 0;
|
||||
static uint64_t free_pages = 0;
|
||||
|
||||
void init_pmm(multiboot_info_t* mbd)
|
||||
{
|
||||
memory_region_t usable_regions[USABLE_REGION_SIZE];
|
||||
size_t num_regions = 0;
|
||||
|
||||
if (!(mbd->flags & (1 << 6)))
|
||||
{
|
||||
printf("Invalid memory map given by bootloader\n");
|
||||
panic();
|
||||
}
|
||||
|
||||
uint64_t offset = 0;
|
||||
while (offset < mbd->mmap_length)
|
||||
{
|
||||
multiboot_memory_map_t* mmmt = (multiboot_memory_map_t*)(mbd->mmap_addr + offset);
|
||||
|
||||
if (mmmt->type == MULTIBOOT_MEMORY_AVAILABLE && num_regions < USABLE_REGION_SIZE)
|
||||
{
|
||||
usable_regions[num_regions] = (memory_region_t){
|
||||
.base_address = mmmt->addr,
|
||||
.length = mmmt->len,
|
||||
};
|
||||
|
||||
num_regions++;
|
||||
|
||||
printf("Available memory: 0x%x - 0x%x (%u KB)\n", mmmt->addr, mmmt->addr + mmmt->len, mmmt->len / 1024);
|
||||
}
|
||||
|
||||
offset += mmmt->size + sizeof(mmmt->size);
|
||||
}
|
||||
|
||||
memset(page_bitmap, 0xFF, BITMAP_SIZE);
|
||||
|
||||
for (size_t i = 0; i < num_regions; i++)
|
||||
{
|
||||
memory_region_t region = usable_regions[i];
|
||||
|
||||
uint64_t start_page = region.base_address / PAGE_SIZE;
|
||||
uint64_t num_pages = region.length / PAGE_SIZE;
|
||||
|
||||
for (uint64_t page = start_page; page < start_page + num_pages; page++)
|
||||
{
|
||||
if (page < BITMAP_SIZE * 8)
|
||||
{
|
||||
page_bitmap[page / 8] &= ~(1 << (page % 8));
|
||||
free_pages++;
|
||||
total_pages++;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("System has more ram than the bitmap allows!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reserve first 64MB which is reserved by boot code
|
||||
for (uint64_t page = 0; page < (64 * 1024 * 1024) / PAGE_SIZE; page++)
|
||||
{
|
||||
if (page < BITMAP_SIZE * 8)
|
||||
{
|
||||
if (!(page_bitmap[page / 8] & (1 << (page % 8))))
|
||||
{
|
||||
page_bitmap[page / 8] |= (1 << (page % 8));
|
||||
free_pages--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("PMM initialized\n");
|
||||
}
|
||||
|
||||
uint64_t pmm_alloc_page()
|
||||
{
|
||||
for (size_t i = 0; i < BITMAP_SIZE; i++)
|
||||
{
|
||||
if (page_bitmap[i] != 0xFF)
|
||||
{
|
||||
for (int bit = 0; bit < 8; bit++)
|
||||
{
|
||||
if (!(page_bitmap[i] & (1 << bit)))
|
||||
{
|
||||
page_bitmap[i] |= (1 << bit);
|
||||
free_pages--;
|
||||
return ((i * 8 + bit) * PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pmm_free_page(uint64_t addr)
|
||||
{
|
||||
uint64_t page = addr / PAGE_SIZE;
|
||||
if (page < BITMAP_SIZE * 8)
|
||||
{
|
||||
if (page_bitmap[page / 8] & (1 << (page % 8)))
|
||||
{
|
||||
page_bitmap[page / 8] &= ~(1 << (page % 8));
|
||||
free_pages++;
|
||||
}
|
||||
}
|
||||
}
|
||||
10
src/arch/x86_64/pmm.h
Normal file
10
src/arch/x86_64/pmm.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "multiboot.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#define PAGE_SIZE 4096
|
||||
|
||||
void init_pmm(multiboot_info_t* mbd);
|
||||
uint64_t pmm_alloc_page();
|
||||
void pmm_free_page(uint64_t addr);
|
||||
291
src/arch/x86_64/start.asm
Normal file
291
src/arch/x86_64/start.asm
Normal file
@@ -0,0 +1,291 @@
|
||||
global _start
|
||||
extern kmain
|
||||
extern handle_isr
|
||||
extern pml4
|
||||
|
||||
%define FLAGS 0b10
|
||||
%define MAGIC 0x1BADB002
|
||||
%define CHECKSUM -(MAGIC + FLAGS)
|
||||
|
||||
section .multiboot
|
||||
align 4
|
||||
dd MAGIC
|
||||
dd FLAGS
|
||||
dd CHECKSUM
|
||||
|
||||
section .bss
|
||||
align 16
|
||||
resb 32768
|
||||
stack_top:
|
||||
|
||||
section .bss
|
||||
align 4096
|
||||
pml4:
|
||||
resb 4096
|
||||
pdpt:
|
||||
resb 4096
|
||||
pd:
|
||||
resb 4096
|
||||
|
||||
section .data
|
||||
align 8
|
||||
gdt64:
|
||||
dq 0x0000000000000000
|
||||
.code:
|
||||
dq 0x00AF9A000000FFFF
|
||||
.descriptor:
|
||||
dw .end - gdt64 - 1
|
||||
dq gdt64
|
||||
.end:
|
||||
|
||||
section .data
|
||||
align 8
|
||||
multiboot_info:
|
||||
dq 0
|
||||
|
||||
section .text
|
||||
bits 32
|
||||
_start:
|
||||
mov esp, stack_top
|
||||
|
||||
; Multiboot will place a magic value in eax
|
||||
; If this magic value is not present, then we might not have multiboot info in ebx,
|
||||
; therefore we throw an error
|
||||
cmp eax, 0x2BADB002
|
||||
jne error
|
||||
|
||||
; Save multiboot info pointer for later
|
||||
mov [multiboot_info], ebx
|
||||
|
||||
; Check if cpuid is available by flipping bit 21
|
||||
; in the eflags register and checking if the cpu flipped it back
|
||||
pushfd
|
||||
pop eax
|
||||
mov ecx, eax
|
||||
xor eax, 1 << 21
|
||||
push eax
|
||||
popfd
|
||||
pushfd
|
||||
pop eax
|
||||
; If cpuid is available, eax should be different than ecx
|
||||
xor eax, ecx
|
||||
jz error
|
||||
; Finally restore eflags register to the original value
|
||||
push ecx
|
||||
popfd
|
||||
|
||||
; Check if extended cpuid is available by calling cpuid with 0x80000000,
|
||||
; If cpuid is available, eax will be greater than 0x80000000 after the call
|
||||
mov eax, 0x80000000
|
||||
cpuid
|
||||
cmp eax, 0x80000001
|
||||
jb error
|
||||
|
||||
; Check if long mode is available by calling cpuid with 0x80000001
|
||||
; this will place the extended features of the cpu in edx
|
||||
; Bit 29 tells us if long mode is supported or not
|
||||
mov eax, 0x80000001
|
||||
cpuid
|
||||
test edx, 1 << 29
|
||||
jz error
|
||||
|
||||
; Enable PAE by setting bit 5 in cr4 to 1
|
||||
mov eax, cr4
|
||||
or eax, 1 << 5
|
||||
mov cr4, eax
|
||||
|
||||
; pml4[0] -> pdpt
|
||||
mov eax, pdpt
|
||||
or eax, 0x03
|
||||
mov [pml4], eax
|
||||
; pdpt[0] -> pd
|
||||
mov eax, pd
|
||||
or eax, 0x03
|
||||
mov [pdpt], eax
|
||||
; Map first 32 2mb pages for the kernel for a total of 64mb
|
||||
mov edi, pd
|
||||
mov eax, 0x83
|
||||
mov ecx, 32
|
||||
.setup_pd:
|
||||
mov [edi], eax
|
||||
add eax, 0x200000
|
||||
add edi, 8
|
||||
loop .setup_pd
|
||||
|
||||
; Load cr3 with the address of pml4
|
||||
mov eax, pml4
|
||||
mov cr3, eax
|
||||
|
||||
lgdt [gdt64.descriptor]
|
||||
|
||||
; Enable long mode by setting bit 8 to 1 in EFER (Extended Feature Enable Register)
|
||||
mov ecx, 0xc0000080
|
||||
rdmsr
|
||||
or eax, 1 << 8
|
||||
wrmsr
|
||||
|
||||
; Enable paging by setting bit 31 in cr0 to 1
|
||||
mov eax, cr0
|
||||
or eax, 1 << 31
|
||||
mov cr0, eax
|
||||
|
||||
jmp 0x8:long_mode
|
||||
|
||||
error:
|
||||
cli
|
||||
mov byte [0xb8000], 'E'
|
||||
mov byte [0xb8002], 'R'
|
||||
mov byte [0xb8004], 'R'
|
||||
.hang:
|
||||
hlt
|
||||
jmp .hang
|
||||
|
||||
section .bss
|
||||
align 4096
|
||||
idt64:
|
||||
resb 4096
|
||||
|
||||
section .data
|
||||
align 8
|
||||
idt64_descriptor:
|
||||
dw 4095
|
||||
dq idt64
|
||||
|
||||
section .data
|
||||
align 8
|
||||
isr_stub_table:
|
||||
%assign i 0
|
||||
%rep 256
|
||||
dq isr_stub_%[i]
|
||||
%assign i i+1
|
||||
%endrep
|
||||
|
||||
%macro ISR_NOERR 1
|
||||
isr_stub_%1:
|
||||
push qword 0
|
||||
push qword %1
|
||||
jmp isr_common
|
||||
%endmacro
|
||||
|
||||
%macro ISR_ERR 1
|
||||
isr_stub_%1:
|
||||
push qword %1
|
||||
jmp isr_common
|
||||
%endmacro
|
||||
|
||||
section .text
|
||||
bits 64
|
||||
long_mode:
|
||||
; Clear segment registers in long mode
|
||||
xor ax, ax
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
mov ss, ax
|
||||
|
||||
; Fill in the idt table with the stub functions
|
||||
mov rdi, idt64
|
||||
mov rsi, isr_stub_table
|
||||
mov rcx, 256
|
||||
.loop:
|
||||
mov rax, [rsi]
|
||||
mov [rdi], ax
|
||||
mov word [rdi + 2], 0x08
|
||||
mov word [rdi + 4], 0x8E00
|
||||
shr rax, 16
|
||||
mov [rdi + 6], ax
|
||||
shr rax, 16
|
||||
mov [rdi + 8], eax
|
||||
mov dword [rdi + 12], 0
|
||||
add rdi, 16
|
||||
add rsi, 8
|
||||
loop .loop
|
||||
lidt [idt64_descriptor]
|
||||
|
||||
; Finally, we call in to c
|
||||
mov rdi, [multiboot_info]
|
||||
call kmain
|
||||
.hang:
|
||||
hlt
|
||||
jmp .hang
|
||||
|
||||
isr_common:
|
||||
push rax
|
||||
push rbx
|
||||
push rcx
|
||||
push rdx
|
||||
push rsi
|
||||
push rdi
|
||||
push rbp
|
||||
push r8
|
||||
push r9
|
||||
push r10
|
||||
push r11
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
|
||||
mov rdi, rsp
|
||||
call handle_isr
|
||||
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop r11
|
||||
pop r10
|
||||
pop r9
|
||||
pop r8
|
||||
pop rbp
|
||||
pop rdi
|
||||
pop rsi
|
||||
pop rdx
|
||||
pop rcx
|
||||
pop rbx
|
||||
pop rax
|
||||
|
||||
add rsp, 16
|
||||
iretq
|
||||
|
||||
; CPU exceptions 0-31. Some of these contain error codes, so we define them manually
|
||||
ISR_NOERR 0
|
||||
ISR_NOERR 1
|
||||
ISR_NOERR 2
|
||||
ISR_NOERR 3
|
||||
ISR_NOERR 4
|
||||
ISR_NOERR 5
|
||||
ISR_NOERR 6
|
||||
ISR_NOERR 7
|
||||
ISR_ERR 8
|
||||
ISR_NOERR 9
|
||||
ISR_ERR 10
|
||||
ISR_ERR 11
|
||||
ISR_ERR 12
|
||||
ISR_ERR 13
|
||||
ISR_ERR 14
|
||||
ISR_NOERR 15
|
||||
ISR_NOERR 16
|
||||
ISR_ERR 17
|
||||
ISR_NOERR 18
|
||||
ISR_NOERR 19
|
||||
ISR_NOERR 20
|
||||
ISR_NOERR 21
|
||||
ISR_NOERR 22
|
||||
ISR_NOERR 23
|
||||
ISR_NOERR 24
|
||||
ISR_NOERR 25
|
||||
ISR_NOERR 26
|
||||
ISR_NOERR 27
|
||||
ISR_NOERR 28
|
||||
ISR_NOERR 29
|
||||
ISR_ERR 30
|
||||
ISR_NOERR 31
|
||||
|
||||
; Hardware interrupts and user-defined interrupts (32-255). These don't have error codes
|
||||
%assign i 32
|
||||
%rep 224
|
||||
ISR_NOERR i
|
||||
%assign i i+1
|
||||
%endrep
|
||||
Reference in New Issue
Block a user