The beginning of paging!
The kernel resides in the higher half, and as of now still identity maps the lower half for compatibility. Will not merge back to master until all the previous features work properly in virtual memory..
This commit is contained in:
parent
4ffc4692ae
commit
20357559c1
8 changed files with 106 additions and 19 deletions
|
|
@ -3,4 +3,3 @@
|
||||||
i686-elf-gdb build/ukern.elf \
|
i686-elf-gdb build/ukern.elf \
|
||||||
-ex "target remote localhost:1234" \
|
-ex "target remote localhost:1234" \
|
||||||
-ex "break start" \
|
-ex "break start" \
|
||||||
-ex "continue"
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,6 @@
|
||||||
#define ASM_H
|
#define ASM_H
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define COM1 0x3F8
|
|
||||||
#define COM2 0x2F8
|
|
||||||
|
|
||||||
void outb(uint16_t port, uint8_t data);
|
void outb(uint16_t port, uint8_t data);
|
||||||
uint8_t inb(uint16_t port);
|
uint8_t inb(uint16_t port);
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,11 @@
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define COM1 0x3F8
|
||||||
|
#define COM2 0x2F8
|
||||||
|
|
||||||
typedef struct serial_ctx_s {
|
typedef struct serial_ctx_s {
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
} serial_ctx_t;
|
} serial_ctx_t;
|
||||||
|
|
|
||||||
24
linker.ld
24
linker.ld
|
|
@ -6,19 +6,31 @@ SECTIONS
|
||||||
/*start me at 1Mb because below that is x86 essential stuff, which we dont want to be written on top of.*/
|
/*start me at 1Mb because below that is x86 essential stuff, which we dont want to be written on top of.*/
|
||||||
. = 1M;
|
. = 1M;
|
||||||
|
|
||||||
_kernel_start = .;
|
|
||||||
|
|
||||||
/* we're going to maintain 4K alignment - apparently useful for paging, and i'm not complaining about the lost space anyway. */
|
/* we're going to maintain 4K alignment - apparently useful for paging, and i'm not complaining about the lost space anyway. */
|
||||||
/*our multiboot header from start.s - has to go at the beginning of the executable so the bootloader knows we're loadable.*/
|
/*our multiboot header from start.s - has to go at the beginning of the executable so the bootloader knows we're loadable.*/
|
||||||
/*executable section*/
|
/*executable section*/
|
||||||
.text BLOCK(4K) : ALIGN(4K)
|
.mb_sect :
|
||||||
{
|
{
|
||||||
*(.multiboot)
|
*(.multiboot)
|
||||||
|
}
|
||||||
|
|
||||||
|
.lower_text :
|
||||||
|
{
|
||||||
|
*(.lower_text)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Higher half addressing! We'll have to also specify that we want to be physically placed at 1MB.*/
|
||||||
|
. += 0xC0000000;
|
||||||
|
|
||||||
|
_kernel_start = .;
|
||||||
|
.text ALIGN (4K) : AT (ADDR (.text) - 0xC0000000)
|
||||||
|
{
|
||||||
*(.text)
|
*(.text)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*general read only data*/
|
/*general read only data*/
|
||||||
.rodata BLOCK(4K) : ALIGN(4K)
|
.rodata ALIGN (4K) : AT(ADDR(.rodata) - 0xC0000000)
|
||||||
{
|
{
|
||||||
*(.rodata*)
|
*(.rodata*)
|
||||||
*(.gdt_sect)
|
*(.gdt_sect)
|
||||||
|
|
@ -26,16 +38,18 @@ SECTIONS
|
||||||
}
|
}
|
||||||
|
|
||||||
/*initialized rw data. */
|
/*initialized rw data. */
|
||||||
.data BLOCK(4K) : ALIGN(4K)
|
.data ALIGN (4K) : AT(ADDR(.data) - 0xC0000000)
|
||||||
{
|
{
|
||||||
*(.data)
|
*(.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*uninitialized data, and our stack as defined in start.s*/
|
/*uninitialized data, and our stack as defined in start.s*/
|
||||||
.bss BLOCK(4K) : ALIGN(4K)
|
.bss ALIGN(4K) : AT(ADDR(.bss) - 0xC0000000)
|
||||||
{
|
{
|
||||||
*(COMMON)
|
*(COMMON)
|
||||||
*(.bss)
|
*(.bss)
|
||||||
|
*(.bootstrap_tables)
|
||||||
|
*(.tss)
|
||||||
*(.idt)
|
*(.idt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,5 +55,5 @@ section .gdt_sect
|
||||||
;size of the gdt
|
;size of the gdt
|
||||||
dw gdt_end - gdt - 1
|
dw gdt_end - gdt - 1
|
||||||
;location of the gdt
|
;location of the gdt
|
||||||
dd gdt
|
dd gdt - 0xC0000000
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@
|
||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
#include "serial.h"
|
#include "serial.h"
|
||||||
#include "physmem.h"
|
#include "physmem.h"
|
||||||
|
|
||||||
|
|
||||||
void kern_main(uint32_t multiboot_magic, mb_info_t* multiboot_info)
|
void kern_main(uint32_t multiboot_magic, mb_info_t* multiboot_info)
|
||||||
{
|
{
|
||||||
//Hello C! Let's get to work in cleaning up our environment a bit and creating some safety.
|
//Hello C! Let's get to work in cleaning up our environment a bit and creating some safety.
|
||||||
|
|
@ -56,10 +58,10 @@ void kern_main(uint32_t multiboot_magic, mb_info_t* multiboot_info)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This is broken while i implement virtual memory/paging
|
||||||
unsigned int pages_allocated = build_bitmap((mb_mmap_entry_t*)multiboot_info->mmap_addr, multiboot_info->mmap_length);
|
unsigned int pages_allocated = build_bitmap((mb_mmap_entry_t*)multiboot_info->mmap_addr, multiboot_info->mmap_length);
|
||||||
printf(default_output, "Available mem:%d Pages | %dK", pages_allocated, pages_allocated * 4);
|
printf(default_output, "Available mem:%d Pages | %dK", pages_allocated, pages_allocated * 4);
|
||||||
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
79
src/start.s
79
src/start.s
|
|
@ -5,6 +5,8 @@ bits 32
|
||||||
;Some symbols we'll need from other files...
|
;Some symbols we'll need from other files...
|
||||||
extern kern_main
|
extern kern_main
|
||||||
extern gdtr
|
extern gdtr
|
||||||
|
extern _kernel_start
|
||||||
|
extern _kernel_end
|
||||||
;This will be our entrypoint function name - gotta initialize it now as global so the linker knows later.
|
;This will be our entrypoint function name - gotta initialize it now as global so the linker knows later.
|
||||||
global start
|
global start
|
||||||
|
|
||||||
|
|
@ -17,21 +19,28 @@ section .bss align=16
|
||||||
;Therefore, we put a label here to represent the top of our stack for later.
|
;Therefore, we put a label here to represent the top of our stack for later.
|
||||||
stack_top:
|
stack_top:
|
||||||
;We're gonna throw the TSS here too.
|
;We're gonna throw the TSS here too.
|
||||||
|
|
||||||
|
section .tss align=16 nobits
|
||||||
tss:
|
tss:
|
||||||
resb 104
|
resb 104
|
||||||
|
|
||||||
|
section .bootstrap_tables nobits align=4096
|
||||||
|
bootstrap_PD:
|
||||||
|
resb 4096
|
||||||
|
bootstrap_PT:
|
||||||
|
resb 4096
|
||||||
|
|
||||||
;Actual code. Entry point goes here!
|
;Actual code. Entry point goes here!
|
||||||
section .text
|
section .lower_text exec
|
||||||
;Here it is!
|
;Here it is!
|
||||||
start:
|
start:
|
||||||
;We made a GDT! Let's use it!
|
;We made a GDT! Let's use it!
|
||||||
lgdt [gdtr]
|
lgdt [gdtr - 0xC0000000]
|
||||||
;Now we start by setting the code segment (CS) with a far jump...
|
;Now we start by setting the code segment (CS) with a far jump...
|
||||||
jmp 0x08:segment_be_gone
|
jmp 0x08:gdt_load
|
||||||
|
|
||||||
|
|
||||||
segment_be_gone:
|
gdt_load:
|
||||||
;Now we go ahead and dump our kernel mode data segment (0x10) into the rest of our segments.
|
;Now we go ahead and dump our kernel mode data segment (0x10) into the rest of our segments.
|
||||||
;Also preserving eax because it has the bootloader's multiboot magic in it and I want to check it in main.
|
;Also preserving eax because it has the bootloader's multiboot magic in it and I want to check it in main.
|
||||||
mov cx, 0x10
|
mov cx, 0x10
|
||||||
|
|
@ -40,7 +49,67 @@ section .text
|
||||||
mov ss, cx
|
mov ss, cx
|
||||||
mov fs, cx
|
mov fs, cx
|
||||||
mov gs, cx
|
mov gs, cx
|
||||||
;Lets set up the stack. Stack grows downward on x86. We did the work earlier of defining where the top of the stack is, so just tell esp.
|
|
||||||
|
;So, we want to set up a page table and page directory. Let's take inventory.
|
||||||
|
;eax - preserve, mb_magic
|
||||||
|
;ebx - preserve, mb_info
|
||||||
|
;ecx,edx,esi - can use
|
||||||
|
;Can technically use esp as the stack is set to stack_top later.
|
||||||
|
|
||||||
|
;ecx = our current indexing for pages, this is a 4K-aligned address
|
||||||
|
mov ecx, 0x0
|
||||||
|
;edi = our pointer to the current page table entry. Array of 4byte entries. It's at, of course, where we put it earlier.
|
||||||
|
;Worth noting that it's actually physically at ~1M with the kernel. The pointer, however, is virtually inclined. So we need to adjust.
|
||||||
|
mov edi, bootstrap_PT - 0xC0000000
|
||||||
|
|
||||||
|
page_alloc_loop:
|
||||||
|
;If we're lower than our kernel, skip this page. If we've passed our kernel, we're done mapping.
|
||||||
|
cmp ecx, _kernel_start
|
||||||
|
jl next_page
|
||||||
|
cmp ecx, _kernel_end - 0xC0000000
|
||||||
|
jge page_alloc_done
|
||||||
|
|
||||||
|
;Okay, we're in kernel zone. Let's map this one.
|
||||||
|
;Let's make a page table entry in edx.
|
||||||
|
;The top bits for the page table entry are just the upper bits of the address, so we dont need to touch it.
|
||||||
|
mov edx, ecx
|
||||||
|
;Set last two bits, "present" and "writeable". Later on we'll make a proper page table with proper permissions, but we're bootstrapping here.
|
||||||
|
or edx, 0x003
|
||||||
|
;edi holds a pointer to the page table entry, so dereference it and throw our new entry (in edx) to it. Done!
|
||||||
|
mov [edi], edx
|
||||||
|
|
||||||
|
next_page:
|
||||||
|
;address page + 1
|
||||||
|
add ecx, 0x1000
|
||||||
|
;page table entry + 1
|
||||||
|
add edi, 4
|
||||||
|
jmp page_alloc_loop
|
||||||
|
|
||||||
|
page_alloc_done:
|
||||||
|
;By now we've mapped the kernel in a page table! Let's map VGA too, we'll need that address later.
|
||||||
|
mov dword [bootstrap_PT - 0xC0000000 + 1023 * 4], 0x000B8000 | 0x27
|
||||||
|
|
||||||
|
;We have our page tables mapped to the phys addr of kernel + VGA. Time to add them to our page directory!
|
||||||
|
;First identity maps, second maps to higher half.
|
||||||
|
mov dword [bootstrap_PD - 0xC0000000], bootstrap_PT - 0xC0000000 + 0x003
|
||||||
|
mov dword [bootstrap_PD - 0xC0000000 + 4 * (0xC0000000 >> 22)], bootstrap_PT - 0xC0000000 + 0x003
|
||||||
|
|
||||||
|
;Let's set it! You do this with cr3.
|
||||||
|
mov ecx, bootstrap_PD - 0xC0000000
|
||||||
|
mov cr3, ecx
|
||||||
|
|
||||||
|
;Enable paging in cr0
|
||||||
|
mov ecx, cr0
|
||||||
|
or ecx, 0x80010000
|
||||||
|
mov cr0, ecx
|
||||||
|
;Done! Leave to the higher half!
|
||||||
|
lea ecx, setup_c_env
|
||||||
|
jmp ecx
|
||||||
|
|
||||||
|
section .text
|
||||||
|
|
||||||
|
setup_c_env:
|
||||||
|
;set up the stack. Stack grows downward on x86. We did the work earlier of defining where the top of the stack is, so just tell esp.
|
||||||
mov esp, stack_top ;set the stack pointer
|
mov esp, stack_top ;set the stack pointer
|
||||||
push ebx
|
push ebx
|
||||||
push eax
|
push eax
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
* VARS
|
* VARS
|
||||||
*/
|
*/
|
||||||
|
|
||||||
volatile uint16_t* const vga_buffer = (uint16_t*)0xB8000;
|
volatile uint16_t* const vga_buffer = (uint16_t*)0xC03FF000;
|
||||||
char_writer_t* default_vga = 0;
|
char_writer_t* default_vga = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue