summaryrefslogtreecommitdiff
path: root/src/kernel/core/kmain.cpp
blob: 23b62e3f7043a2f826f070ab4474867eae930ec6 (plain) (blame)
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
#include <types.h>
#include <config.h>

#include "multiboot.h"
#include "sys.h"
#include <mem/gdt.h>
#include <mem/paging.h>
#include <mem/mem.h>

#include <vfs/node.h>
#include <vfs/initrd.h>

#include <task/idt.h>
#include <task/timer.h>
#include <task/task.h>
#include <linker/elf.h>

#include <ui/vt.h>
#include <dev/vgatxt.h>
#include <dev/ps2keyboard.h>

/*	The kernel's main procedure. This function is called in loader_.asm.
	This function calls the initializer functions for all system parts.
	It then loads the modules the kernel was given by the bootloader. 
	This function never returns : once multitasking is started for good,
	the execution flow of this function is never returned to. */
extern "C" void kmain(multiboot_info_t* mbd, int32_t magic) {
	ASSERT(magic == MULTIBOOT_BOOTLOADER_MAGIC);

	mem_placementAddr = ((size_t)&end & 0xFFFFF000) + 0x1000;
	mbd->cmdline += K_HIGHHALF_ADDR; mbd->mods_addr += K_HIGHHALF_ADDR;
	module_t *mods = (module_t*)mbd->mods_addr;
	for (unsigned i = 0; i < mbd->mods_count; i++) {
		mods[i].mod_start += K_HIGHHALF_ADDR;
		mods[i].mod_end += K_HIGHHALF_ADDR;
		mods[i].string += K_HIGHHALF_ADDR;
		if (mods[i].mod_end > mem_placementAddr)
			mem_placementAddr = (mods[i].mod_end & 0xFFFFF000) + 0x1000;
	}


	// Init memory managment functions
	idt_init();
	size_t totalRam = ((mbd->mem_upper + mbd->mem_lower) * 1024);
	paging_init(totalRam);
	gdt_init();
	paging_cleanup();
	_no_more_ksbrk = true;

	// Init higher level stuff
	timer_init(100);
	tasking_init();
	vfs_setup();

	// Init display devices
	text_display = new vgatxt(dot_dev);
	dot_dev->add_child("vgatxt", text_display);

	ke_vt = new vt(dot_ui, 80, 25);
	dot_ui->add_child("klog", ke_vt);
	ke_vt->outputTo(text_display);
	home_vt = new vt(dot_ui, 80, 25);
	dot_ui->add_child("home", home_vt);
	dot_ui->add_child("vt1", new vt(dot_ui, 80, 25));
	dot_ui->add_child("vt2", new vt(dot_ui, 80, 25));
	dot_ui->add_child("vt3", new vt(dot_ui, 80, 25));
	dot_ui->add_child("vt4", new vt(dot_ui, 80, 25));

	// Say hello
	ke_vt->fgcolor = TC_LIGHTGRAY;
	*ke_vt << "Hello. This is ";
	ke_vt->fgcolor = TC_WHITE; 		*ke_vt << K_OS_NAME;
	ke_vt->fgcolor = TC_LIGHTGRAY; 	*ke_vt << " version ";
	ke_vt->fgcolor = TC_WHITE; 		*ke_vt << K_OS_VER;
	ke_vt->fgcolor = TC_LIGHTGRAY;	*ke_vt << " codename '";
	ke_vt->fgcolor = TC_WHITE;		*ke_vt << K_OS_CODENAME;
	ke_vt->fgcolor = TC_LIGHTGRAY;	*ke_vt << "'. Enjoy!\n";

	// Init devices
	kbd = new ps2kbd(dot_dev);
	dot_dev->add_child("ps2kbd", kbd);
	kbd->outputTo(ke_vt);

	// Load modules
	*ke_vt << "Loading modules :\n";
	for (unsigned i = 0; i < mbd->mods_count; i++) {
		char* cmd = (char*)mods[i].string;
		*ke_vt << " * " << cmd << " \t";
		if (elf_check((uint8_t*)mods[i].mod_start) == 0) {

			char *args[16] = { cmd, 0 };
			int a = 1;
			for (char* c = cmd; c != 0; c++) {
				if (*c == ' ') {
					*c = 0;
					args[a] = c + 1;
					a++;
					if (a == 15) {
						args[a] = 0;
						break;
					}
				} else if (*c == 0) {
					args[a] = 0;
					break;
				}
			}

			process *pr = elf_exec((uint8_t*)mods[i].mod_start, PL_USER, args);	// todo add args
			if (pr == 0) {
				*ke_vt << "Error loading\n";
			} else {
				pr->fd.set(0, ke_vt);
				*ke_vt << "OK, pid=" << (int)pr->pid << "\n";
			}
		} else if (initrd_check((uint8_t*)mods[i].mod_start) == 0) {
			vdir* fs = new vdir(root);
			int e = initrd_load((uint8_t*)mods[i].mod_start, fs);
			if (e == 0) {
				char* name = cmd;
				for (char* i = name; *i != 0; i++) {
					if (*i == '/' || *i == ' ') name = i + 1;
				}
				root->add_child(name, fs);
				*ke_vt << "OK, initrd as /" << name << "/\n";
			} else {
				*ke_vt << "initrd but error " << e << "\n";
			}
		} else {
			*ke_vt << "Invalid file, neither ELF nor initrd.\n";
		}
	}

	*ke_vt << "Giving control to userland processes.\n\n";
	sti();
	schedule();
	PANIC("Should never happen. Something probably went wrong with multitasking.");
}