summaryrefslogtreecommitdiff
path: root/kernel/entry.c
blob: 0b22ee7219e28b606e9b7b0897621c4edc662caa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include "kernel.h"
#include "paging.h"

extern void main();

asm(
	".globl entry\n"
	"entry:\n"
	"mov $entry_stack_top, %esp\n"
	"push %ebx\n"
	"push %eax\n"
	"call entry_main\n"
);

void entry_copy_multiboot(multiboot_info_t* mb_info);

void entry_main(uint32_t mb_magic, multiboot_info_t* mb_info) {
	if(mb_magic != 0x2badb002) {
		goto stop;
	}
	
	entry_copy_multiboot(mb_info);
	
	// Create initial page tables.
	for(unsigned int i = 0; i < 1024; i++) {
		// Clear page directory.
		entry_pagedir[i] = 0;
		
		// Identity mapping of the current code.
		entry_pagetable_low[i] = ((uint32_t)&addr_phys & 0xffc00000) | (i << 12) | P1_P | P1_W;
		
		// Map kernelspace.
		if((i << 12) < ((uint32_t)&addr_virt_end & 0x003fffff)) {
			entry_pagetable_high[i] = ((uint32_t)&addr_load_virt + (i << 12)) | P1_P | P1_W | P1_G;
		} else {
			entry_pagetable_high[i] = 0;
		}
	}
	
	entry_pagetable_high[((uint32_t)&multiboot_info & 0x003ff000) >> 12] = (uint32_t)&entry_multiboot | P1_P | P1_W | P1_G;
	
	entry_pagedir[(uint32_t)&addr_phys >> 22] = (uint32_t)&entry_pagetable_low | P2_P | P2_W;
	entry_pagedir[(uint32_t)&addr_virt >> 22] = (uint32_t)&entry_pagetable_high | P2_P | P2_W | P2_G;
	
	// Map map_p1.
	entry_pagedir[1022] = (uint32_t)&entry_pagedir | P2_P | P2_W | P2_G;
	
	// Mapping stack to top without creating another page directory.
	entry_pagetable_low[1023] = (uint32_t)&entry_stack | P1_P | P1_W | P1_G;
	entry_pagedir[1023] = (uint32_t)&entry_pagetable_low | P2_P | P2_W | P2_G;
	
	// Enable paging.
	asm volatile(
		"mov %0, %%cr3\n"
		"mov %%cr0, %0\n"
		"or $0x80000000, %0\n"
		"mov %0, %%cr0\n"
		:: "r" (&entry_pagedir) : "%0"
	);
	
	// TODO: Check that segments are loaded and mapped right.
	
	// Call main() in virtual memory.
	asm volatile("mov $stack_top, %esp");
	main();
	
	stop:
	asm volatile(
		"cli\n"
		"hlt\n"
	);
	while(1);
}

#define memcpy(source, target, size) asm volatile( \
	"cld\n" \
	"rep movsd\n" \
	:: "S" (source), "D" (target), "c" (size / 4) \
	: "flags", "memory")

unsigned int strcpy(char* source, char* target) {
	unsigned int i = 0;
		while(*source) {
			*target++ = *source++;
			i++;
		}
		*target = 0;
		return i + 1;
}

void entry_copy_multiboot(multiboot_info_t* mb_info) {
	// Copy multiboot structure.
	memcpy(mb_info, &entry_multiboot, sizeof(multiboot_info_t));
	uint32_t low_p = (uint32_t)&entry_multiboot + sizeof(multiboot_info_t);
	uint32_t high_p = (uint32_t)&multiboot_info + sizeof(multiboot_info_t);
	
	// Copy module structures.
	memcpy(mb_info->mods_addr, low_p, mb_info->mods_count * sizeof(multiboot_module_t));
	entry_multiboot.mods_addr = (multiboot_module_t*)high_p;
	multiboot_module_t* mods_addr = (multiboot_module_t*)low_p;
	low_p += mb_info->mods_count * sizeof(multiboot_module_t);
	high_p += mb_info->mods_count * sizeof(multiboot_module_t);
	
	// Copy strings.
	unsigned int s;
	s = strcpy(entry_multiboot.cmdline, (char*)low_p);
	entry_multiboot.cmdline = (char*)high_p;
	low_p += s;
	high_p += s;
	
	for(unsigned int i = 0; i < entry_multiboot.mods_count; i++) {
		s = strcpy(mods_addr[i].string, (char*)low_p);
		mods_addr[i].string = (char*)high_p;
		low_p += s;
		high_p += s;
	}
}