summaryrefslogtreecommitdiff
path: root/kernel/entry.c
blob: 2496d21a1581f8824c2bf4e9ec6e160f87f3cb6e (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
#include "types.h"
#include "multiboot.h"

extern void addr_phys;
extern void addr_virt;
extern void addr_virt_end;
extern void addr_load_virt;
extern void addr_load_virt_end;

extern void entry_stack;

extern uint32_t entry_pagedir[];
extern uint32_t entry_pagetable_low[];
extern uint32_t entry_pagetable_high[];

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_main(uint32_t mb_magic, multiboot_info* 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");
	
	// TODO: Copy multiboot information.
	
	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");
	}
	
	
	// 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) | 0x003;
		
		// Map kernelspace.
		if((i << 12) < ((uint32_t)&addr_virt_end & 0x003fffff)) {
			entry_pagetable_high[i] = ((uint32_t)&addr_load_virt + (i << 12)) | 0x003;
		} else {
			entry_pagetable_high[i] = 0;
		}
	}
	
	entry_pagedir[(uint32_t)&addr_phys >> 22] = (uint32_t)&entry_pagetable_low | 0x003;
	entry_pagedir[(uint32_t)&addr_virt >> 22] = (uint32_t)&entry_pagetable_high | 0x003;
	
	// Mapping stack to top without creating another page directory.
	entry_pagetable_high[1023] = (uint32_t)&entry_stack | 0x003;
	entry_pagedir[1023] = (uint32_t)&entry_pagetable_high | 0x003;
	
	// 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 $0, %esp");
	main();
	
	stop:
	entry_serial_out("Halting.\n");
	asm volatile(
		"cli\n"
		"hlt\n"
	);
	while(1);
}

#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);
}