Commit 38e27c54 by malcolm

Merge branch 'elf_load' into 'master'

Elf load

Does some stuff but not yet.

See merge request !18
parents 4e2be3d0 ba7971ff
/*
elf.c
Mainly, contains the elf loading code
*/
#include "elf.h"
void load_elf(elf_header* elf_start)
{
// The elf will get its own memory space.
page_directory_entry* pgdir = page_new_directory();
// loop through and copy memory segments
for (int i = 0; i < elf_start->ph_entry_count; i++)
{
// get this section header
elf_program_header* ph;
ph = (elf_program_header*) elf_start + (elf_start->ph_table_offset + (i * elf_start->ph_entry_size));
// map and copy
for (void* pg = (void*)((uint32_t)ph->p_vaddr & 0xfffff000); (uint32_t)(pg - ph->p_vaddr) < ph->memory_segment_size; pg+=0x1000)
{
void* real_page = page_map(pgdir, pg);
void* start = (pg > ph->p_vaddr) ? pg : ph->p_vaddr;
void* end = (pg + 0x1000 < ph->p_vaddr + ph->file_segment_size) ? pg + 0x1000 : ph->p_vaddr + ph->file_segment_size;
size_t size = end - start;
size_t offset = (pg > ph->p_vaddr) ? 0 : ph->p_vaddr - pg;
// do some memcpy stuff
memcpy(real_page + offset, start, size);
}
}
}
/*
elf.h
Structures and symbols used for loading elf files
*/
#ifndef _ELF_INC
#define _ELF_INT
#include <stdint.h>
#include <stddef.h>
#include "mem.h"
#include "string.h"
extern uint8_t elf_hello[] asm("_binary_hello_elf_start");
typedef struct
{
uint32_t magic; // \x7FELF
uint8_t word_size; // 32/64 bit
uint8_t endianness;
uint8_t elf_version;
uint8_t os_abi;
uint64_t unused;
uint16_t relocatable;
uint16_t instruction_set;
uint32_t elf_version_b;
void* program_entry_position;
uint32_t ph_table_offset;
uint32_t sh_table_offset;
uint32_t flags; // undefined in x86
uint16_t header_size;
uint16_t ph_entry_size;
uint16_t ph_entry_count;
uint16_t sh_entry_size;
uint16_t sh_entry_count;
uint16_t sh_name_index;
} __attribute__((packed)) elf_header;
typedef struct
{
uint32_t segment_type;
uint32_t p_offset; // Offset in the elf file for this segment's data
void* p_vaddr; // Where this segment should be located in virtual memory
uint32_t unused;
uint32_t file_segment_size; // Size of the segment in this file and in memory
uint32_t memory_segment_size;
uint32_t flags;
uint32_t alignment;
} elf_program_header;
// Will probably return a pointer to the PCB block eventually. Dunno though.
void load_elf(elf_header* elf_start);
#endif
No preview for this file type
......@@ -19,13 +19,19 @@
#include "pic.h"
#include "pit.h"
#include "io.h"
#include "elf.h"
// 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();
serial_init();
// For some reason 'myos.bin ' is here. remove it.
memset(&_kernel_end, 0, 20);
gdt_init();
idt_init(0x8);
serial_writestring("IDT initialized\n");
......@@ -68,6 +74,12 @@ void kernel_main(multiboot_info* mbt, uint32_t magic)
// PCI
checkAllBuses();
// Elf testing
// This is defined in elf.h
serial_writestring("Elf address: 0x");
serial_hexstring(elf_hello, 4);
serial_writestring("\n");
test_idt();
while(true)
{
......
......@@ -43,4 +43,8 @@ SECTIONS
/* The compiler may produce other sections, by default it will put them in
a segment with the same name. Simply add stuff here as needed. */
.end BLOCK(4K) : ALIGN(4K)
{
_kernel_end = . ;
}
}
......@@ -5,7 +5,7 @@ all:
/usr/bin/nasm -felf32 paging.asm
/usr/bin/nasm -felf32 idta.asm
$C *.c -std=gnu99 -ffreestanding -O2 -Wall -Wextra -c
$C -T linker.ld -o myos.bin -ffreestanding -O2 -nostdlib *.o -lgcc
$C -Wl,--format=binary -Wl,hello.elf -Wl,--format=default -T linker.ld -o myos.bin -ffreestanding -O2 -nostdlib *.o -lgcc
clean:
rm *.o *.bin
......
......@@ -46,24 +46,58 @@ void populate_page_table(page_table_entry* table, void* start, int num, int offs
}
}
// TODO: put this as a label at the end of the code, so we can take
// its address
#define KERN_END 0x204000
// page_allocate returns the address of a new page in real memory
void* page_allocate()
{
// The starting address of the map should always be the same: &_kernel_end
// Find the correct bit to flip and page number
uint8_t* index = (uint8_t*) &_kernel_end;
while (*index == 0xff) index++;
uint8_t i = 7;
while ((*index & (1<<i)) != 0) i--;
// bitfilp
*index = *index | (1<<i);
uint32_t page_number = ((uint32_t)(index - (uint8_t*)_kernel_end) * 8) + (8-i);
return (void*)&_kernel_end + 0x1000 * page_number;
}
// page_free just flips the bit to say that the page has been freed
void page_free(void* page_start)
{
if (((uint32_t)page_start & 0xfff) != 0)
{
serial_writestring("tried to free a non-page as a page");
}
uint32_t page_number = (uint32_t)(page_start - (void*)&_kernel_end) / 0x1000;
uint8_t* index = (uint8_t*) &_kernel_end + page_number / 8;
*index = ~(~*index | (1<<(8-(page_number%8))));
}
// This goes through all available memory, and maps 1 to 1 virtual memory to it.
page_directory_entry* mem_init_kern_tables(multiboot_memory_map* mmap, multiboot_memory_map* mmap_end)
{
// Allocate enough space for the biggest possible allocation bitmap. Assigning 1 bit to each
for (int i = 0; i < 32; i++)
{
page_allocate();
}
// 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;
// _kern_end is defined in the linker script
/* page_table_entry* next_table = (page_table_entry*) &_kernel_end; */
int current_dir_entry = 0;
// For each entry in the memory map
while (mmap < mmap_end)
{
void* next_table = page_allocate();
// Special case for the first memory segment - it gets its own directory entry
if (mmap->base_addr == 0)
{
......@@ -74,7 +108,7 @@ page_directory_entry* mem_init_kern_tables(multiboot_memory_map* mmap, multiboot
page_directory[0] |= PAGE_WRITABLE | PAGE_PRESENT;
current_dir_entry = 1;
next_table += 0x1000;
/* next_table += 0x1000; */
}
else if (mmap->type == 1)
{
......@@ -86,7 +120,7 @@ page_directory_entry* mem_init_kern_tables(multiboot_memory_map* mmap, multiboot
page_directory[current_dir_entry] |= PAGE_WRITABLE | PAGE_PRESENT;
current_dir_entry += 1;
next_table += 0x1000;
/* 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.
......@@ -97,7 +131,7 @@ page_directory_entry* mem_init_kern_tables(multiboot_memory_map* mmap, multiboot
page_directory[current_dir_entry] |= PAGE_WRITABLE | PAGE_PRESENT;
current_dir_entry += 1;
next_table += 0x1000;
/* next_table += 0x1000; */
}
}
......@@ -105,11 +139,65 @@ page_directory_entry* mem_init_kern_tables(multiboot_memory_map* mmap, multiboot
}
// let the memory allocator work freely with all remaining memory
memory_mark = next_table;
memory_mark = page_allocate();
return kern_page_dir;
}
// page_map takes in a virtual address and a directory, and ensures
// that that address points to valid memory
void* page_map(page_directory_entry pgdir[], void* page_start)
{
void* page = 0;
if ((pgdir[(uint32_t)page_start>>22] & 0xfffff) == 0)
{
pgdir[(uint32_t)page_start>>22] |= (page_directory_entry)page_new_table();
}
page_table_entry* page_table = (page_table_entry*) ((uint32_t) pgdir[(uint32_t)page_start>>22] & 0xfffff000);
if ((page_table[((uint32_t)page_start >> 12) % 1024] & 0xfffff) == 0)
{
page = page_allocate();
page_table[((uint32_t)page_start>>12)%1024] |= (page_table_entry)page;
}
return page;
}
page_directory_entry* page_new_directory()
{
page_directory_entry* pgdir = (page_directory_entry*) page_allocate();
int i;
for(i = 0; i < 1024; i++)
{
// This sets the following flags to the pages:
// Supervisor: Only kernel-mode can access them
// Write Enabled: It can be both read from and written to
// (this is the 2 bit)
// Not Present: The page table is not present
pgdir[i] = 0;
pgdir[i] |= PAGE_WRITABLE;
}
return pgdir;
}
// Returns a blank table
page_table_entry* page_new_table()
{
page_table_entry* pgtab = (page_table_entry*) page_allocate();
int i;
for(i = 0; i < 1024; i++)
{
// This sets the following flags to the pages:
// Supervisor: Only kernel-mode can access them
// Write Enabled: It can be both read from and written to
// (this is the 2 bit)
// Not Present: The page table is not present
pgtab[i] = 0;
pgtab[i] |= PAGE_WRITABLE;
}
return pgtab;
}
page_directory_entry* initiate_directory()
{
// set each entry to not present
......@@ -138,3 +226,9 @@ void* malloc(uint32_t bytes)
memory_mark = (void*)((uint32_t)memory_mark + bytes);
return old_mark;
}
void* kmalloc(uint32_t size __attribute__((unused)))
{
return page_allocate();
}
......@@ -27,15 +27,54 @@ typedef uint32_t page_table_entry;
extern void loadPageDirectory(page_directory_entry*);
extern void enablePaging();
// Defined in the file mem.c
page_directory_entry* initiate_directory();
// Defined in linker.ld
extern char _kernel_end[];
// Allocation of pages
void* page_allocate();
void page_free(void* page_start);
void* page_map(page_directory_entry pgdir[], void* page_start);
// Initilization
page_directory_entry* mem_init_kern_tables(multiboot_memory_map* mmap, multiboot_memory_map* mmap_end);
// Directory and table handling
page_directory_entry* page_new_directory();
page_table_entry* page_new_table();
page_directory_entry* initiate_directory(); // DEPRECATED
// 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* kmalloc(uint32_t);
void* malloc(uint32_t bytes);
// Required for elf loading - virtual memory and stuff
// TODO:
/*
Two stage memory thing.
Ensure kernel is paged.
Ensure that a space equal to <remaining_memory> / (4096 * 8) is paged. This is for the following struct
Create binary array specifying which pages are used (abstract ownership a bit maybe to pid, or just use bit array)
Place in allocated space
Write allocor for pages. This should be the only way to get ownership of pages.
- takes a page directory and a new address as an argument.
- Sholud be called by the other malloc function, or by construction of page tables
- flips a bit in a binary array
- Also write corresponding free, flip bit and remove entry in page dir/table
Write more versatile malloc/free
- Use struct{void* next, size_t size} before every hunk. Walk list to find total size, use this to determine if more pages are needed. Or something
Problems - how to determine when new pages are needed
- how to load in elf stuff at arbitrary locations
*/
#endif
#include "string.h"
#include <stdbool.h>
void *memset(void *s, int c, size_t n){
void *memset(void *s, int c, size_t n)
{
unsigned char* p=s;
while(n--)
*p++=(unsigned char) c;
return s;
}
void memcpy(void* dest, void* src, size_t n)
{
size_t i;
char* d = (char*) dest;
char* s = (char*) src;
for (i = 0; i < n; ++i)
{
d[i] = s[i];
}
}
void reverse ( char s[] )
{
int c, i, j;
for (i=0, j= strlen(s)-1;i<j;i++,j--)
{
c = s[i];
......@@ -23,7 +35,7 @@ void reverse ( char s[] )
void itoa(int n, char s[])
{
int i, sign;
if ((sign = n) < 0) /* record sign */
{
n = -n; /* make n positive */
......@@ -42,7 +54,7 @@ void itoa(int n, char s[])
}
size_t strlen(const char* str)
size_t strlen(const char* str)
{
size_t ret = 0;
while ( str[ret] != 0 )
......@@ -69,7 +81,7 @@ int strncmp(const char *s1, const char *s2, size_t n)
return 0;
}
int atoi(const char *p)
int atoi(const char *p)
{
int k = 0;
while (*p) {
......@@ -88,36 +100,36 @@ int stoi(const char *str)
{
if ((*str) == 0)
return 0;
int res = 0;
int sign = 1;
int i = 0;
int i = 0;
if (str[0] == '-')
{
sign = -1;
i++;
}
for (; str[i] != '\0'; ++i)
{
if (isNumericChar(str[i]) == false)
return 0;
res = res*10 + str[i] - '0';
}
return sign*res;
}
double atof(const char* num)
{
if (!num || !*num)
return 0;
return 0;
double integerPart = 0;
double fractionPart = 0;
int divisorForFraction = 1;
int sign = 1;
bool inFraction = false;
if (*num == '-')
{
++num;
......
......@@ -2,7 +2,8 @@
#define _STRING_ING
#include<stddef.h>
void* memset(void *s, int c, size_t n);
void* memset(void* s, int c, size_t n);
void memcpy(void* dest, void* src, size_t n);
void itoa(int n, char s[]);
size_t strlen(const char* str);
int strcmp(const char* s1, const char* s2);
......
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