Commit 2e2aa845 by malcolm

Merge branch 'memtest' into 'master'

Memtest



See merge request !13
parents 155b2238 b135dd23
......@@ -4,7 +4,7 @@ MEMINFO equ 1<<1 ; provide memory map
FLAGS equ MBALIGN | MEMINFO ; this is the Multiboot 'flag' field
MAGIC equ 0x1BADB002 ; 'magic number' lets bootloader find the header
CHECKSUM equ -(MAGIC + FLAGS) ; checksum of above, to prove we are multiboot
; Declare a header as in the Multiboot Standard. We put this into a special
; section so we can force the header to be in the start of the final program.
; You don't need to understand all these details as it is just magic values that
......@@ -15,7 +15,7 @@ align 4
dd MAGIC
dd FLAGS
dd CHECKSUM
; Currently the stack pointer register (esp) points at anything and using it may
; cause massive harm. Instead, we'll provide our own stack. We will allocate
; room for a small temporary stack by creating a symbol at the bottom of it,
......@@ -25,7 +25,7 @@ align 4
stack_bottom:
resb 16384
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.
......@@ -42,7 +42,7 @@ _start:
; you get to make the entire system yourself. You have absolute and complete
; power over the machine, there are no security restrictions, no safe
; guards, no debugging mechanisms, there is nothing but what you build.
; By now, you are perhaps tired of assembly language. You realize some
; things simply cannot be done in C, such as making the multiboot header in
; the right section and setting up the stack. However, you would like to
......@@ -51,17 +51,20 @@ _start:
; such code. C doesn't expect much at this point and we only need to set up
; a stack. Note that the processor is not fully initialized yet and stuff
; such as floating point instructions are not available yet.
; To set up a stack, we simply set the esp register to point to the top of
; our stack (as it grows downwards).
mov esp, stack_top
push eax ; Multiboot magic number
push ebx ; Multiboot info struct
; We are now ready to actually execute C code. We cannot embed that in an
; assembly file, so we'll create a kernel.c file in a moment. In that file,
; we'll create a C entry point called kernel_main and call it here.
extern kernel_main
call kernel_main
; In case the function returns, we'll want to put the computer into an
; infinite loop. To do that, we use the clear interrupt ('cli') instruction
; to disable interrupts, the halt instruction ('hlt') to stop the CPU until
......
#include <stdbool.h> /* C doesn't have booleans by default. */
/*
kern.c is where the c code starts, as invoked by our heading
assembly. It should only contain high level code
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
......@@ -8,11 +13,11 @@
#include "mem.h"
#include "gdt.h"
#include "idt.h"
#include "test.h"
#include "multiboot.h"
#if defined(__cplusplus)
extern "C" /* Use C linkage for kernel_main. */
#endif
void kernel_main()
// The parameters passed here ultimately come through the bootloader
void kernel_main(multiboot_info* mbt, uint32_t magic)
{
/* Initialize terminal and serial interfaces */
terminal_initialize();
......@@ -26,21 +31,25 @@ void kernel_main()
*/
serial_writestring("IDT initialized\n");
terminal_writestring("Hello, kernel World!\n");
//serial_writestring("Second Serial Test\n");
// Abort if magic is not correct.
if (magic != 0x2badb002)
{
serial_writestring("Magic number not correct\n");
// wait how do we terminate
}
// Enable paging of memory. For now there is only one virtual
// memory space defined by page_dir
page_directory_entry* page_dir;
page_dir = initiate_directory();
initiate_page_table(page_dir);
loadPageDirectory(page_dir);
page_directory_entry* kern_page_dir;
kern_page_dir = mem_init_kern_tables(mbt->mmap_addr, mbt->mmap_addr + mbt->mmap_length);
loadPageDirectory(kern_page_dir);
enablePaging();
serial_writestring("Finished Initilizing memory\n");
asm ("int $0x80");
asm ("int $0x90");
int o=0;
int j=5/o;
serial_hexword(j);
asm ("hlt");
test_mem();
test_idt();
}
/* Linker code ripped directly from osdev wiki */
/* The bootloader will look at this image and start execution at the symbol
designated as the entry point. */
ENTRY(_start)
......
......@@ -13,7 +13,104 @@ page_directory_entry page_directory[1024] __attribute__((aligned(4096)));
// only page table in the page directory
page_table_entry page_table_one[1024] __attribute__((aligned(4096)));
page_directory_entry* initiate_directory()
// populate_page_table makes a page table at `table` mapping `num`
// pages to bytes after `start + offset*4KB`
// both table and start must be properly aligned
void populate_page_table(page_table_entry* table, void* start, int num, int offset)
{
// Check that there are the correct number of entries
if ((offset + num) > 1024)
{
serial_writestring("tred to populate past the end of the page table\n");
}
// Check that the table is properly aligned
if (((uint32_t)table & 0xfff) != 0)
{
serial_writestring("tried to populate a table that was not page aligned");
}
// Check that the table is properly aligned
if (((uint32_t)start & 0xfff) != 0)
{
serial_writestring("tried to start mapping on an unaligned address");
}
int i;
int stop = num + offset;
for (i = offset; i < stop; i++)
{
table[i] = 0;
table[i] |= (uint32_t)start + (i<<12);
table[i] |= PAGE_WRITABLE | PAGE_PRESENT;
}
}
// TODO: put this as a label at the end of the code, so we can take
// its address
#define KERN_END 0x104000
page_directory_entry* mem_init_kern_tables(multiboot_memory_map* mmap, multiboot_memory_map* mmap_end)
{
// Make a page directory structure easily
page_directory_entry* kern_page_dir = initiate_directory();
// This line will change with the above TODO
page_table_entry* next_table = (page_table_entry*) KERN_END;
int current_dir_entry = 0;
// For each entry in the memory map
while (mmap < mmap_end)
{
// Special case for the first memory segment - it gets its own directory entry
if (mmap->base_addr == 0)
{
// Lower memory should be first in the page directory and
// mapped one to one
populate_page_table(next_table, 0, 1024, 0);
page_directory[0] = (uint32_t) next_table;
page_directory[0] |= PAGE_WRITABLE | PAGE_PRESENT;
current_dir_entry = 1;
next_table += 0x1000;
}
else if (mmap->type == 1)
{
uint32_t i;
for (i = 0; i+0x1000000 < mmap->length; i += 0x1000000)
{
populate_page_table(next_table, (void*) mmap->base_addr + i, 1024 ,0);
page_directory[current_dir_entry] = (uint32_t) next_table;
page_directory[current_dir_entry] |= PAGE_WRITABLE | PAGE_PRESENT;
current_dir_entry += 1;
next_table += 0x1000;
}
// There will be an edge case where there is less than a
// full page table to be mapped. This handlis this case.
if (i != mmap->length)
{
populate_page_table(next_table, (void*) mmap->base_addr + i, (mmap->length - i) / 0x1000 ,0);
page_directory[current_dir_entry] = (uint32_t) next_table;
page_directory[current_dir_entry] |= PAGE_WRITABLE | PAGE_PRESENT;
current_dir_entry += 1;
next_table += 0x1000;
}
}
mmap = (multiboot_memory_map*)((uint32_t)mmap + mmap->size + sizeof(uint32_t));
}
// let the memory allocator work freely with all remaining memory
memory_mark = next_table;
return kern_page_dir;
}
page_directory_entry* initiate_directory()
{
// set each entry to not present
int i;
......@@ -28,28 +125,16 @@ page_directory_entry* initiate_directory()
page_directory[i] |= PAGE_WRITABLE;
}
// Set last directory entry to point back
page_directory[1023] = (uint32_t) page_directory;
page_directory[1023] |= PAGE_WRITABLE | PAGE_PRESENT;
return page_directory;
}
void initiate_page_table(page_directory_entry* page_dir)
void* malloc(uint32_t bytes)
{
// 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.
unsigned int i;
//we will fill all 1024 entries in the table, mapping 4 megabytes
for(i = 0; i < 1024; i++)
{
// As the address is page aligned, it will always leave 12 bits zeroed.
// Those bits are used by the attributes:
// -> supervisor level, read/write, present.
page_table_one[i] = 0;
page_table_one[i] |= i << 12;
page_table_one[i] |= PAGE_WRITABLE | PAGE_PRESENT;
}
// attributes: supervisor level, read/write, present
page_dir[0] = (uint32_t) page_table_one;
page_dir[0] |= PAGE_WRITABLE | PAGE_PRESENT;
void* old_mark = memory_mark;
memory_mark = (void*)((uint32_t)memory_mark + bytes);
return old_mark;
}
......@@ -8,6 +8,8 @@
#include <stdbool.h>
#include <stdint.h>
#include "multiboot.h"
// Flags for pages directory entries and table entries
#define PAGE_PRESENT 0x1
#define PAGE_WRITABLE 0x2
......@@ -27,6 +29,13 @@ extern void enablePaging();
// Defined in the file mem.c
page_directory_entry* initiate_directory();
void initiate_page_table(page_directory_entry* page_dir);
page_directory_entry* mem_init_kern_tables(multiboot_memory_map* mmap, multiboot_memory_map* mmap_end);
// memory mark stores a counter of bytes for the most recently used
// memory. Everything before it is used and all valid memory after it
// is free
void* memory_mark;
void* malloc(uint32_t bytes);
#endif
/*
multiboot.h defines structures used in the multiboot standard
much of this file was closely inspired by the gnu version
*/
#ifndef _MULTIBOOT_INC
#define _MULTIBOOT_INC
#include <stdint.h>
typedef struct
{
uint32_t size;
uint64_t base_addr;
uint64_t length;
uint32_t type;
} multiboot_memory_map;
typedef struct
{
uint32_t tabsize;
uint32_t strsize;
uint32_t addr;
uint32_t reserved;
} aout_symbol_table;
typedef struct
{
uint32_t flags;
uint32_t mem_lower;
uint32_t mem_upper;
uint32_t boot_device;
uint32_t cmdline;
uint32_t mods_count;
uint32_t mods_addr;
union
{
aout_symbol_table aout_sym;
} u;
uint32_t mmap_length;
multiboot_memory_map* mmap_addr;
} multiboot_info;
#endif
......@@ -6,7 +6,7 @@
#define SERIAL_IO_PORT 0x3f8 // COM1
void serial_init()
void serial_init()
{
outb(SERIAL_IO_PORT + 1, 0x00); // Disable all interrupts
outb(SERIAL_IO_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
......@@ -17,21 +17,21 @@ void serial_init()
outb(SERIAL_IO_PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
}
int is_transmit_empty()
int is_transmit_empty()
{
return inb(SERIAL_IO_PORT + 5) & 0x20;
}
void serial_writechar(char a)
void serial_writechar(char a)
{
while (is_transmit_empty() == 0);
outb(SERIAL_IO_PORT,a);
}
void serial_writestring(char* s)
void serial_writestring(char* s)
{
while (*s)
while (*s)
{
serial_writechar(*s);
s++;
......@@ -39,9 +39,17 @@ void serial_writestring(char* s)
}
const char* hexchars = "0123456789abcdef";
void serial_hexword(uint32_t x)
void serial_hexword(uint32_t x)
{
for (int i = 8; i != 0; i--)
for (int i = 7; i >= 0; i--)
{
serial_writechar(hexchars[x>>i*4&0xf]);
}
}
void serial_hexqword(uint64_t x)
{
for (int i = 15; i >= 0; i--)
{
serial_writechar(hexchars[x>>i*4&0xf]);
}
......@@ -49,7 +57,7 @@ void serial_hexword(uint32_t x)
void serial_hexstring(void* s, uint32_t n) {
char* d = (char*)s;
for (uint32_t i = 0; i < n; i++)
for (uint32_t i = 0; i < n; i++)
{
serial_writechar(hexchars[(d[i]>>4)&0xf]);
serial_writechar(hexchars[d[i]&0xf]);
......
......@@ -22,6 +22,7 @@ void serial_writestring(char* s);
// Function to write a 4 byte word toserial in hex
void serial_hexword(uint32_t x);
void serial_hexqword(uint64_t x);
void serial_hexstring(void* s, uint32_t n);
#endif
/*
test.c implements functions used for testing
*/
#include "test.h"
void test_idt()
{
asm ("int $0x80");
asm ("int $0x90");
asm ("hlt");
}
void test_mem()
{
// try writing a bunch of bytes starting at 0
int i = 0x0;
for(i=0; i < 0x4000; i++)
{
*(int*)(i<<2) = i;
}
// read it back in and make sure its all stored
for (i=0; i < 0x4000; i++)
{
if (*(int*)(i<<2) != i)
{
serial_writestring("Memory error\n");
}
}
serial_writestring("Wrote a bunch of memory\n");
}
/*
test.h defines functions used for testing
*/
#ifndef INC_TEST
#define INC_TEST
#include "serial.h"
// test_idt calls a couple of interrupts. Should be done after kernel
// has been set up
void test_idt();
// test_mem writes some stuff to moem
void test_mem();
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment