summaryrefslogtreecommitdiff
path: root/kernel/entry.c
blob: 2ec50898b6625f4ab69790860dd6aec9b791761e (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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#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_serial_out(char* str);
void entry_serial_out_hex(uint32_t x);
void entry_copy_multiboot(multiboot_info_t* mb_info);

void entry_main(uint32_t mb_magic, multiboot_info_t* mb_info) {
	entry_serial_out("entry_main()\n");
	if(mb_magic != 0x2badb002) {
		entry_serial_out("Multiboot magic word is wrong!\n");
		goto stop;
	}
	entry_serial_out("Multiboot ok\n");
	
	entry_copy_multiboot(mb_info);
	
	/*
	entry_serial_out("Flags: ");
	entry_serial_out_hex(mb_info->flags);
	
	if(mb_info->flags & (1 << 2)) {
		entry_serial_out(mb_info->cmdline);
		entry_serial_out("\n");
	} else {
		entry_serial_out("No cmdline.\n");
	}
	
	entry_serial_out("Module addr: ");
	entry_serial_out_hex(mb_info->mods_addr->mod_start);
	*/
	
	// 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:
	entry_serial_out("Halting.\n");
	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;
	}
}

#define outb(port, value) asm volatile("out %b0,%w1" : : "a" (value), "d" (port))

void entry_serial_out(char* str) {
	while(*str) {
		if(*str == '\n') {
			outb(0x3f8, '\r');
		}
		outb(0x3f8, *str++);
	}
}

void entry_serial_out_hex(uint32_t x) {
	char str[] = "00000000\n";
	for(int i = 0; i < 8; i++) {
		int z = (x >> (28 - i * 4)) & 0xf;
		str[i] = z < 10 ? '0' + z : 'a' - 10 + z;
	}
	entry_serial_out(str);
}