Page 1 of 1

paging - grub error [SOLVED]

Posted: Sun Jun 15, 2008 7:51 am
by jocke
Hi,

i following JamesM's paging tutorial.
but when i run the code grub says that the kernel isn't executeable and give error code 13

when i leaving out the pagingpart the kernel will be started.

so i tried to comment some code in the paging.c to locate the error, it looks like the error is in the 3 first functions of this code:

Code: Select all

#include <heap.h>
#include <string.h>
#include <paging.h>

extern unsigned int placement_address;

page_directory_t *kernel_directory = 0;
page_directory_t *current_directory = 0;

unsigned int *frames;
unsigned int nframes;

#define INDEX_FROM_BIT(a) (a/(8*4))
#define OFFSET_FROM_BIT(a) (a%(8*4))

static void set_frame(unsigned int frame_addr) {
	unsigned int frame = frame_addr/0x1000;
	unsigned int idx = INDEX_FROM_BIT(frame);
	unsigned int off = OFFSET_FROM_BIT(frame);
	frames[idx] |= (0x1 << off);
}

static void clear_frame(unsigned int frame_addr) {
	unsigned int frame = frame_addr/0x1000;
	unsigned int idx = INDEX_FROM_BIT(frame);
	unsigned int off = OFFSET_FROM_BIT(frame);

	frames[idx] &= ~(0x1 << off);
}

static unsigned int test_frame(unsigned int frame_addr) {
	unsigned int frame = frame_addr/0x1000;
	unsigned int idx = INDEX_FROM_BIT(frame);
	unsigned int off = OFFSET_FROM_BIT(frame);

	return (frames[idx] & (0x1 << off));
}

static unsigned int first_frame() {
	unsigned int i, j;

	for (i = 0; i < INDEX_FROM_BIT(nframes); i++) {
		if (frames[i] != 0xFFFFFFFF) {
			for (j = 0; j < 32; j++) {
				unsigned int toTest = 0x1 << j;

				if (!(frames[i] & toTest)) {
					return i * 4 * 8 + j;
				}
			}
		}
	}
}

void alloc_frame(page_t *page, int is_kernel, int is_writeable) {
	if (page->frame != 0) {
		return;
	} else {
		unsigned int idx = first_frame();

		if (idx == (unsigned int) -1) {}

		set_frame(idx * 0x1000);
		page->present = 1;
		page->rw = (is_writeable) ? 1 : 0;
		page->user = (is_kernel) ? 0 : 1;
		page->frame = idx;
	}
}

void free_frame(page_t *page) {
	unsigned int frame;

	if (!(frame = page->frame)) {
		return;
	} else {
		clear_frame(frame);
		page->frame = 0x0;
	}
}

void init_paging() {
	unsigned int mem_end_page = 0x1000000;

	nframes = mem_end_page / 0x1000;
	frames = (unsigned int *) malloc(INDEX_FROM_BIT(nframes));
	memset(frames, 0, INDEX_FROM_BIT(nframes));

	kernel_directory = (page_directory_t *) malloc_a(sizeof(page_directory_t));
	memset(kernel_directory, 0, sizeof(page_directory_t));
	current_directory = kernel_directory;

	int i = 0;

	while(i < placement_address) {
		alloc_frame(get_page(i, 1, kernel_directory), 0, 0);
		i += 0x1000;
	}

	switch_page_directory(kernel_directory);
}

void switch_page_directory(page_directory_t *dir) {
	current_directory = dir;
	asm volatile("mov %0, %%cr3" :: "r" (&dir->tablesPhysical));
	unsigned int cr0;
	asm volatile("mov %%cr0, %0" : "=r" (cr0));
	cr0 |= 0x80000000;
	asm volatile("mov %0, %%cr0" :: "r" (cr0));
}

page_t *get_page(unsigned int address, int make, page_directory_t *dir) {
	address /= 0x1000;

	unsigned int table_idx = address / 1024;

	if (dir->tables[table_idx]) {
		return &dir->tables[table_idx]->pages[address % 1024];
	} else if (make) {
		unsigned int tmp;

		dir->tables[table_idx] = (page_table_t *) malloc_ap(sizeof(page_table_t), &tmp);
		memset(dir->tables[table_idx], 0, 0x1000);
		dir->tablesPhysical[table_idx] = tmp | 0x7;
		return &dir->tables[table_idx]->pages[address % 1024];
	} else {
		return 0;
	}
}
anyone knows what the problem is?

Posted: Sun Jun 15, 2008 11:12 am
by JamesM
You're probably not linking your boot.s file first, so when you add the paging code the multiboot header gets pushed over the 4KB boundary and GRUB never finds it.

Make sure boot.s is first on your linker line.

Posted: Sun Jun 15, 2008 12:29 pm
by jocke
thanks, that works :P