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 ...@@ -4,7 +4,7 @@ MEMINFO equ 1<<1 ; provide memory map
FLAGS equ MBALIGN | MEMINFO ; this is the Multiboot 'flag' field FLAGS equ MBALIGN | MEMINFO ; this is the Multiboot 'flag' field
MAGIC equ 0x1BADB002 ; 'magic number' lets bootloader find the header MAGIC equ 0x1BADB002 ; 'magic number' lets bootloader find the header
CHECKSUM equ -(MAGIC + FLAGS) ; checksum of above, to prove we are multiboot 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 ; 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. ; 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 ; You don't need to understand all these details as it is just magic values that
...@@ -15,7 +15,7 @@ align 4 ...@@ -15,7 +15,7 @@ align 4
dd MAGIC dd MAGIC
dd FLAGS dd FLAGS
dd CHECKSUM dd CHECKSUM
; Currently the stack pointer register (esp) points at anything and using it may ; 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 ; 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, ; room for a small temporary stack by creating a symbol at the bottom of it,
...@@ -25,7 +25,7 @@ align 4 ...@@ -25,7 +25,7 @@ align 4
stack_bottom: stack_bottom:
resb 16384 resb 16384
stack_top: stack_top:
; The linker script specifies _start as the entry point to the kernel and the ; 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 ; 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. ; doesn't make sense to return from this function as the bootloader is gone.
...@@ -42,7 +42,7 @@ _start: ...@@ -42,7 +42,7 @@ _start:
; you get to make the entire system yourself. You have absolute and complete ; you get to make the entire system yourself. You have absolute and complete
; power over the machine, there are no security restrictions, no safe ; power over the machine, there are no security restrictions, no safe
; guards, no debugging mechanisms, there is nothing but what you build. ; guards, no debugging mechanisms, there is nothing but what you build.
; By now, you are perhaps tired of assembly language. You realize some ; 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 ; 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 ; the right section and setting up the stack. However, you would like to
...@@ -51,17 +51,20 @@ _start: ...@@ -51,17 +51,20 @@ _start:
; such code. C doesn't expect much at this point and we only need to set up ; 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 ; a stack. Note that the processor is not fully initialized yet and stuff
; such as floating point instructions are not available yet. ; 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 ; To set up a stack, we simply set the esp register to point to the top of
; our stack (as it grows downwards). ; our stack (as it grows downwards).
mov esp, stack_top 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 ; 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, ; 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. ; we'll create a C entry point called kernel_main and call it here.
extern kernel_main extern kernel_main
call kernel_main call kernel_main
; In case the function returns, we'll want to put the computer into an ; 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 ; infinite loop. To do that, we use the clear interrupt ('cli') instruction
; to disable interrupts, the halt instruction ('hlt') to stop the CPU until ; 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 <stddef.h>
#include <stdint.h> #include <stdint.h>
...@@ -8,11 +13,11 @@ ...@@ -8,11 +13,11 @@
#include "mem.h" #include "mem.h"
#include "gdt.h" #include "gdt.h"
#include "idt.h" #include "idt.h"
#include "test.h"
#include "multiboot.h"
#if defined(__cplusplus) // The parameters passed here ultimately come through the bootloader
extern "C" /* Use C linkage for kernel_main. */ void kernel_main(multiboot_info* mbt, uint32_t magic)
#endif
void kernel_main()
{ {
/* Initialize terminal and serial interfaces */ /* Initialize terminal and serial interfaces */
terminal_initialize(); terminal_initialize();
...@@ -26,21 +31,25 @@ void kernel_main() ...@@ -26,21 +31,25 @@ void kernel_main()
*/ */
serial_writestring("IDT initialized\n"); serial_writestring("IDT initialized\n");
terminal_writestring("Hello, kernel World!\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 // Enable paging of memory. For now there is only one virtual
// memory space defined by page_dir // memory space defined by page_dir
page_directory_entry* page_dir; page_directory_entry* kern_page_dir;
page_dir = initiate_directory(); kern_page_dir = mem_init_kern_tables(mbt->mmap_addr, mbt->mmap_addr + mbt->mmap_length);
initiate_page_table(page_dir); loadPageDirectory(kern_page_dir);
loadPageDirectory(page_dir);
enablePaging(); enablePaging();
serial_writestring("Finished Initilizing memory\n"); serial_writestring("Finished Initilizing memory\n");
asm ("int $0x80");
asm ("int $0x90");
int o=0; int o=0;
int j=5/o; int j=5/o;
serial_hexword(j); 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 /* The bootloader will look at this image and start execution at the symbol
designated as the entry point. */ designated as the entry point. */
ENTRY(_start) ENTRY(_start)
......
...@@ -13,7 +13,104 @@ page_directory_entry page_directory[1024] __attribute__((aligned(4096))); ...@@ -13,7 +13,104 @@ page_directory_entry page_directory[1024] __attribute__((aligned(4096)));
// only page table in the page directory // only page table in the page directory
page_table_entry page_table_one[1024] __attribute__((aligned(4096))); 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 // set each entry to not present
int i; int i;
...@@ -28,28 +125,16 @@ page_directory_entry* initiate_directory() ...@@ -28,28 +125,16 @@ page_directory_entry* initiate_directory()
page_directory[i] |= PAGE_WRITABLE; 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; 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. void* old_mark = memory_mark;
// in this case, we want to map these pages to the very beginning of memory. memory_mark = (void*)((uint32_t)memory_mark + bytes);
unsigned int i; return old_mark;
//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;
} }
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "multiboot.h"
// Flags for pages directory entries and table entries // Flags for pages directory entries and table entries
#define PAGE_PRESENT 0x1 #define PAGE_PRESENT 0x1
#define PAGE_WRITABLE 0x2 #define PAGE_WRITABLE 0x2
...@@ -27,6 +29,13 @@ extern void enablePaging(); ...@@ -27,6 +29,13 @@ extern void enablePaging();
// Defined in the file mem.c // Defined in the file mem.c
page_directory_entry* initiate_directory(); 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 #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 @@ ...@@ -6,7 +6,7 @@
#define SERIAL_IO_PORT 0x3f8 // COM1 #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 + 1, 0x00); // Disable all interrupts
outb(SERIAL_IO_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor) outb(SERIAL_IO_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
...@@ -17,21 +17,21 @@ void serial_init() ...@@ -17,21 +17,21 @@ void serial_init()
outb(SERIAL_IO_PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set 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; return inb(SERIAL_IO_PORT + 5) & 0x20;
} }
void serial_writechar(char a) void serial_writechar(char a)
{ {
while (is_transmit_empty() == 0); while (is_transmit_empty() == 0);
outb(SERIAL_IO_PORT,a); outb(SERIAL_IO_PORT,a);
} }
void serial_writestring(char* s) void serial_writestring(char* s)
{ {
while (*s) while (*s)
{ {
serial_writechar(*s); serial_writechar(*s);
s++; s++;
...@@ -39,9 +39,17 @@ void serial_writestring(char* s) ...@@ -39,9 +39,17 @@ void serial_writestring(char* s)
} }
const char* hexchars = "0123456789abcdef"; 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]); serial_writechar(hexchars[x>>i*4&0xf]);
} }
...@@ -49,7 +57,7 @@ void serial_hexword(uint32_t x) ...@@ -49,7 +57,7 @@ void serial_hexword(uint32_t x)
void serial_hexstring(void* s, uint32_t n) { void serial_hexstring(void* s, uint32_t n) {
char* d = (char*)s; 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]>>4)&0xf]);
serial_writechar(hexchars[d[i]&0xf]); serial_writechar(hexchars[d[i]&0xf]);
......
...@@ -22,6 +22,7 @@ void serial_writestring(char* s); ...@@ -22,6 +22,7 @@ void serial_writestring(char* s);
// Function to write a 4 byte word toserial in hex // Function to write a 4 byte word toserial in hex
void serial_hexword(uint32_t x); void serial_hexword(uint32_t x);
void serial_hexqword(uint64_t x);
void serial_hexstring(void* s, uint32_t n); void serial_hexstring(void* s, uint32_t n);
#endif #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