1/*
2 * Copyright 2003-2005, Axel D��rfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "menu.h"
8#include "loader.h"
9#include "load_driver_settings.h"
10
11#include <boot/stage2.h>
12#include <boot/vfs.h>
13#include <boot/platform.h>
14#include <boot/heap.h>
15#include <boot/stdio.h>
16
17#include <util/kernel_cpp.h>
18
19
20//#define TRACE_MAIN
21#ifdef TRACE_MAIN
22#	define TRACE(x) dprintf x
23#else
24#	define TRACE(x) ;
25#endif
26
27
28extern "C" int
29main(stage2_args *args)
30{
31	TRACE(("boot(): enter\n"));
32
33	if (heap_init(args) < B_OK)
34		panic("Could not initialize heap!\n");
35
36	TRACE(("boot(): heap initialized...\n"));
37
38	// set debug syslog default
39#if KDEBUG_ENABLE_DEBUG_SYSLOG
40	gKernelArgs.keep_debug_output_buffer = true;
41#endif
42
43	add_stage2_driver_settings(args);
44
45	platform_init_video();
46
47	// the main platform dependent initialisation
48	// has already taken place at this point.
49
50	if (vfs_init(args) < B_OK)
51		panic("Could not initialize VFS!\n");
52
53	dprintf("Welcome to the Haiku boot loader!\n");
54
55	bool mountedAllVolumes = false;
56
57	Directory *volume = get_boot_file_system(args);
58
59	if (volume == NULL || (platform_boot_options() & BOOT_OPTION_MENU) != 0) {
60		if (volume == NULL)
61			puts("\tno boot path found, scan for all partitions...\n");
62
63		if (mount_file_systems(args) < B_OK) {
64			// That's unfortunate, but we still give the user the possibility
65			// to insert a CD-ROM or just rescan the available devices
66			puts("Could not locate any supported boot devices!\n");
67		}
68
69		// ToDo: check if there is only one bootable volume!
70
71		mountedAllVolumes = true;
72
73		if (user_menu(&volume) < B_OK) {
74			// user requested to quit the loader
75			goto out;
76		}
77	}
78
79	if (volume != NULL) {
80		// we got a volume to boot from!
81		status_t status;
82		while ((status = load_kernel(args, volume)) < B_OK) {
83			// loading the kernel failed, so let the user choose another
84			// volume to boot from until it works
85			volume = NULL;
86
87			if (!mountedAllVolumes) {
88				// mount all other file systems, if not already happened
89				if (mount_file_systems(args) < B_OK)
90					panic("Could not locate any supported boot devices!\n");
91
92				mountedAllVolumes = true;
93			}
94
95			if (user_menu(&volume) < B_OK || volume == NULL) {
96				// user requested to quit the loader
97				goto out;
98			}
99		}
100
101		// if everything is okay, continue booting; the kernel
102		// is already loaded at this point and we definitely
103		// know our boot volume, too
104		if (status == B_OK) {
105			register_boot_file_system(volume);
106
107			if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) == 0)
108				platform_switch_to_logo();
109
110			load_modules(args, volume);
111			load_driver_settings(args, volume);
112
113			// apply boot settings
114			apply_boot_settings();
115
116			// set up kernel args version info
117			gKernelArgs.kernel_args_size = sizeof(kernel_args);
118			gKernelArgs.version = CURRENT_KERNEL_ARGS_VERSION;
119
120			// clone the boot_volume KMessage into kernel accessible memory
121			// note, that we need to 4 byte align the buffer and thus allocate
122			// 3 more bytes
123			void* buffer = kernel_args_malloc(gBootVolume.ContentSize() + 3);
124			if (!buffer) {
125				panic("Could not allocate memory for the boot volume kernel "
126					"arguments");
127			}
128
129			buffer = (void*)(((addr_t)buffer + 3) & ~(addr_t)0x3);
130			memcpy(buffer, gBootVolume.Buffer(), gBootVolume.ContentSize());
131			gKernelArgs.boot_volume = buffer;
132			gKernelArgs.boot_volume_size = gBootVolume.ContentSize();
133
134			// ToDo: cleanup, heap_release() etc.
135			platform_start_kernel();
136		}
137	}
138
139out:
140	heap_release(args);
141	return 0;
142}
143