1/*
2 * Copyright 2003-2013, 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/PathBlocklist.h>
16#include <boot/stdio.h>
17#include <boot/net/NetStack.h>
18#include <system_revision.h>
19
20#include "file_systems/packagefs/packagefs.h"
21
22
23//#define TRACE_MAIN
24#ifdef TRACE_MAIN
25#	define TRACE(x) dprintf x
26#else
27#	define TRACE(x) ;
28#endif
29
30
31void *__dso_handle;
32
33
34extern "C" int
35main(stage2_args *args)
36{
37	TRACE(("boot(): enter\n"));
38
39	if (heap_init(args) < B_OK)
40		panic("Could not initialize heap!\n");
41
42	TRACE(("boot(): heap initialized...\n"));
43
44	// set debug syslog default
45#if KDEBUG_ENABLE_DEBUG_SYSLOG
46	gKernelArgs.keep_debug_output_buffer = true;
47	gKernelArgs.previous_debug_size = true;
48		// used as a boolean indicator until initialized for the kernel
49#endif
50
51	add_stage2_driver_settings(args);
52
53	platform_init_video();
54
55	// the main platform dependent initialisation
56	// has already taken place at this point.
57
58	if (vfs_init(args) < B_OK)
59		panic("Could not initialize VFS!\n");
60
61	dprintf("Welcome to the Haiku boot loader!\n");
62	dprintf("Haiku revision: %s\n", get_haiku_revision());
63
64	bool mountedAllVolumes = false;
65
66	BootVolume bootVolume;
67	PathBlocklist pathBlocklist;
68
69	if (get_boot_file_system(args, bootVolume) != B_OK
70		|| (platform_boot_options() & BOOT_OPTION_MENU) != 0) {
71		if (!bootVolume.IsValid())
72			puts("\tno boot path found, scan for all partitions...\n");
73
74		if (mount_file_systems(args) < B_OK) {
75			// That's unfortunate, but we still give the user the possibility
76			// to insert a CD-ROM or just rescan the available devices
77			puts("Could not locate any supported boot devices!\n");
78		}
79
80		// ToDo: check if there is only one bootable volume!
81
82		mountedAllVolumes = true;
83
84		if (user_menu(bootVolume, pathBlocklist) < B_OK) {
85			// user requested to quit the loader
86			goto out;
87		}
88	}
89
90	if (bootVolume.IsValid()) {
91		// we got a volume to boot from!
92
93		// TODO: fix for riscv64
94#ifndef __riscv
95		load_driver_settings(args, bootVolume.RootDirectory());
96#endif
97		status_t status;
98		while ((status = load_kernel(args, bootVolume)) < B_OK) {
99			// loading the kernel failed, so let the user choose another
100			// volume to boot from until it works
101			bootVolume.Unset();
102
103			if (!mountedAllVolumes) {
104				// mount all other file systems, if not already happened
105				if (mount_file_systems(args) < B_OK)
106					panic("Could not locate any supported boot devices!\n");
107
108				mountedAllVolumes = true;
109			}
110
111			if (user_menu(bootVolume, pathBlocklist) != B_OK
112				|| !bootVolume.IsValid()) {
113				// user requested to quit the loader
114				goto out;
115			}
116		}
117
118		// if everything is okay, continue booting; the kernel
119		// is already loaded at this point and we definitely
120		// know our boot volume, too
121		if (status == B_OK) {
122			if (bootVolume.IsPackaged()) {
123				packagefs_apply_path_blocklist(bootVolume.SystemDirectory(),
124					pathBlocklist);
125			}
126
127			register_boot_file_system(bootVolume);
128
129			if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) == 0)
130				platform_switch_to_logo();
131
132			load_modules(args, bootVolume);
133
134			gKernelArgs.ucode_data = NULL;
135			gKernelArgs.ucode_data_size = 0;
136			platform_load_ucode(bootVolume);
137
138			// TODO: fix for riscv64
139#ifndef __riscv
140			// apply boot settings
141			apply_boot_settings();
142#endif
143
144			// set up kernel args version info
145			gKernelArgs.kernel_args_size = sizeof(kernel_args);
146			gKernelArgs.version = CURRENT_KERNEL_ARGS_VERSION;
147			if (gKernelArgs.ucode_data == NULL)
148				gKernelArgs.kernel_args_size = kernel_args_size_v1;
149
150			// clone the boot_volume KMessage into kernel accessible memory
151			// note, that we need to 8-byte align the buffer and thus allocate
152			// 7 more bytes
153			void* buffer = kernel_args_malloc(gBootVolume.ContentSize() + 7);
154			if (!buffer) {
155				panic("Could not allocate memory for the boot volume kernel "
156					"arguments");
157			}
158
159			buffer = (void*)(((addr_t)buffer + 7) & ~(addr_t)0x7);
160			memcpy(buffer, gBootVolume.Buffer(), gBootVolume.ContentSize());
161			gKernelArgs.boot_volume = buffer;
162			gKernelArgs.boot_volume_size = gBootVolume.ContentSize();
163
164			platform_cleanup_devices();
165			// TODO: cleanup, heap_release() etc.
166			heap_print_statistics();
167			platform_start_kernel();
168		}
169	}
170
171out:
172	heap_release(args);
173	return 0;
174}
175