Beispiel #1
0
status_t
register_boot_file_system(BootVolume& bootVolume)
{
	Directory* rootDirectory = bootVolume.RootDirectory();
	gRoot->AddLink("boot", rootDirectory);

	Partition *partition;
	status_t status = gRoot->GetPartitionFor(rootDirectory, &partition);
	if (status != B_OK) {
		dprintf("register_boot_file_system(): could not locate boot volume in "
			"root!\n");
		return status;
	}

	gBootVolume.SetInt64(BOOT_VOLUME_PARTITION_OFFSET,
		partition->offset);

	if (bootVolume.IsPackaged()) {
		gBootVolume.SetBool(BOOT_VOLUME_PACKAGED, true);
		PackageVolumeState* state = bootVolume.GetPackageVolumeState();
		if (state->Name() != NULL)
			gBootVolume.AddString(BOOT_VOLUME_PACKAGES_STATE, state->Name());
	}

	Node *device = get_node_from(partition->FD());
	if (device == NULL) {
		dprintf("register_boot_file_system(): could not get boot device!\n");
		return B_ERROR;
	}

	return platform_register_boot_device(device);
}
Beispiel #2
0
static int
open_maybe_packaged(BootVolume& volume, const char* path, int openMode)
{
	if (strncmp(path, kSystemDirectoryPrefix, strlen(kSystemDirectoryPrefix))
			== 0) {
		path += strlen(kSystemDirectoryPrefix);
		return open_from(volume.SystemDirectory(), path, openMode);
	}

	return open_from(volume.RootDirectory(), path, openMode);
}
Beispiel #3
0
bool
is_bootable(Directory *volume)
{
	if (volume->IsEmpty())
		return false;

	BootVolume bootVolume;
	if (bootVolume.SetTo(volume) != B_OK)
		return false;

	// check for the existance of a kernel (for our platform)
	int fd = find_kernel(bootVolume);
	if (fd < 0)
		return false;

	close(fd);

	return true;
}
Beispiel #4
0
status_t
load_modules(stage2_args* args, BootVolume& volume)
{
	int32 failed = 0;

	// ToDo: this should be mostly replaced by a hardware oriented detection mechanism

	int32 i = 0;
	for (; sAddonPaths[i]; i++) {
		char path[B_FILE_NAME_LENGTH];
		snprintf(path, sizeof(path), "%s/boot", sAddonPaths[i]);

		if (load_modules_from(volume, path) != B_OK)
			failed++;
	}

	if (failed == i) {
		// couldn't load any boot modules
		// fall back to load all modules (currently needed by the boot floppy)
		const char *paths[] = { "bus_managers", "busses/ide", "busses/scsi",
			"generic", "partitioning_systems", "drivers/bin", NULL};

		for (int32 i = 0; paths[i]; i++) {
			char path[B_FILE_NAME_LENGTH];
			snprintf(path, sizeof(path), "%s/%s", sAddonPaths[0], paths[i]);
			load_modules_from(volume, path);
		}
	}

	// and now load all partitioning and file system modules
	// needed to identify the boot volume

	if (!gBootVolume.GetBool(BOOT_VOLUME_BOOTED_FROM_IMAGE, false)) {
		// iterate over the mounted volumes and load their file system
		Partition *partition;
		if (gRoot->GetPartitionFor(volume.RootDirectory(), &partition)
				== B_OK) {
			while (partition != NULL) {
				load_module(volume, partition->ModuleName());
				partition = partition->Parent();
			}
		}
	} else {
		// The boot image should only contain the file system
		// needed to boot the system, so we just load it.
		// ToDo: this is separate from the fall back from above
		//	as this piece will survive a more intelligent module
		//	loading approach...
		char path[B_FILE_NAME_LENGTH];
		snprintf(path, sizeof(path), "%s/%s", sAddonPaths[0], "file_systems");
		load_modules_from(volume, path);
	}

	return B_OK;
}
Beispiel #5
0
/*! Gets the boot device, scans all of its partitions, gets the
	boot partition, and mounts its file system.

	\param args The stage 2 arguments.
	\param _bootVolume On success set to the boot volume.
	\return \c B_OK on success, another error code otherwise.
*/
status_t
get_boot_file_system(stage2_args* args, BootVolume& _bootVolume)
{
	status_t error = platform_add_boot_device(args, &gBootDevices);
	if (error != B_OK)
		return error;

	NodeIterator iterator = gBootDevices.GetIterator();
	while (iterator.HasNext()) {
		Node *device = iterator.Next();

		error = add_partitions_for(device, false, true);
		if (error != B_OK)
			continue;

		NodeList bootPartitions;
		error = platform_get_boot_partitions(args, device, &gPartitions, &bootPartitions);
		if (error != B_OK)
			continue;

		NodeIterator partitionIterator = bootPartitions.GetIterator();
		while (partitionIterator.HasNext()) {
			Partition *partition = (Partition*)partitionIterator.Next();

			Directory *fileSystem;
			error = partition->Mount(&fileSystem, true);
			if (error != B_OK) {
				// this partition doesn't contain any known file system; we
				// don't need it anymore
				gPartitions.Remove(partition);
				delete partition;
				continue;
			}

			// init the BootVolume
			error = _bootVolume.SetTo(fileSystem);
			if (error != B_OK)
				continue;

			sBootDevice = device;
			return B_OK;
		}
	}

	return B_ERROR;
}
Beispiel #6
0
/*! Gets the boot device, scans all of its partitions, gets the
	boot partition, and mounts its file system.

	\param args The stage 2 arguments.
	\param _bootVolume On success set to the boot volume.
	\return \c B_OK on success, another error code otherwise.
*/
status_t
get_boot_file_system(stage2_args* args, BootVolume& _bootVolume)
{
	Node *device;
	status_t error = platform_add_boot_device(args, &gBootDevices);
	if (error != B_OK)
		return error;

	// the boot device must be the first device in the list
	device = gBootDevices.First();

	error = add_partitions_for(device, false, true);
	if (error != B_OK)
		return error;

	Partition *partition;
	error = platform_get_boot_partition(args, device, &gPartitions, &partition);
	if (error != B_OK)
		return error;

	Directory *fileSystem;
	error = partition->Mount(&fileSystem, true);
	if (error != B_OK) {
		// this partition doesn't contain any known file system; we
		// don't need it anymore
		gPartitions.Remove(partition);
		delete partition;
		return error;
	}

	// init the BootVolume
	error = _bootVolume.SetTo(fileSystem);
	if (error != B_OK)
		return error;

	sBootDevice = device;
	return B_OK;
}
Beispiel #7
0
extern "C" int
main(stage2_args *args)
{
	TRACE(("boot(): enter\n"));

	if (heap_init(args) < B_OK)
		panic("Could not initialize heap!\n");

	TRACE(("boot(): heap initialized...\n"));

	// set debug syslog default
#if KDEBUG_ENABLE_DEBUG_SYSLOG
	gKernelArgs.keep_debug_output_buffer = true;
#endif

	add_stage2_driver_settings(args);

	platform_init_video();

	// the main platform dependent initialisation
	// has already taken place at this point.

	if (vfs_init(args) < B_OK)
		panic("Could not initialize VFS!\n");

	dprintf("Welcome to the Haiku boot loader!\n");

	bool mountedAllVolumes = false;

	BootVolume bootVolume;
	PathBlacklist pathBlacklist;

	if (get_boot_file_system(args, bootVolume) != B_OK
		|| (platform_boot_options() & BOOT_OPTION_MENU) != 0) {
		if (!bootVolume.IsValid())
			puts("\tno boot path found, scan for all partitions...\n");

		if (mount_file_systems(args) < B_OK) {
			// That's unfortunate, but we still give the user the possibility
			// to insert a CD-ROM or just rescan the available devices
			puts("Could not locate any supported boot devices!\n");
		}

		// ToDo: check if there is only one bootable volume!

		mountedAllVolumes = true;

		if (user_menu(bootVolume, pathBlacklist) < B_OK) {
			// user requested to quit the loader
			goto out;
		}
	}

	if (bootVolume.IsValid()) {
		// we got a volume to boot from!
		status_t status;
		while ((status = load_kernel(args, bootVolume)) < B_OK) {
			// loading the kernel failed, so let the user choose another
			// volume to boot from until it works
			bootVolume.Unset();

			if (!mountedAllVolumes) {
				// mount all other file systems, if not already happened
				if (mount_file_systems(args) < B_OK)
					panic("Could not locate any supported boot devices!\n");

				mountedAllVolumes = true;
			}

			if (user_menu(bootVolume, pathBlacklist) != B_OK
				|| !bootVolume.IsValid()) {
				// user requested to quit the loader
				goto out;
			}
		}

		// if everything is okay, continue booting; the kernel
		// is already loaded at this point and we definitely
		// know our boot volume, too
		if (status == B_OK) {
			if (bootVolume.IsPackaged()) {
				packagefs_apply_path_blacklist(bootVolume.SystemDirectory(),
					pathBlacklist);
			}

			register_boot_file_system(bootVolume);

			if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) == 0)
				platform_switch_to_logo();

			load_modules(args, bootVolume);
			load_driver_settings(args, bootVolume.RootDirectory());

			// apply boot settings
			apply_boot_settings();

			// set up kernel args version info
			gKernelArgs.kernel_args_size = sizeof(kernel_args);
			gKernelArgs.version = CURRENT_KERNEL_ARGS_VERSION;

			// clone the boot_volume KMessage into kernel accessible memory
			// note, that we need to 4 byte align the buffer and thus allocate
			// 3 more bytes
			void* buffer = kernel_args_malloc(gBootVolume.ContentSize() + 3);
			if (!buffer) {
				panic("Could not allocate memory for the boot volume kernel "
					"arguments");
			}

			buffer = (void*)(((addr_t)buffer + 3) & ~(addr_t)0x3);
			memcpy(buffer, gBootVolume.Buffer(), gBootVolume.ContentSize());
			gKernelArgs.boot_volume = buffer;
			gKernelArgs.boot_volume_size = gBootVolume.ContentSize();

			// ToDo: cleanup, heap_release() etc.
			heap_print_statistics();
			platform_start_kernel();
		}
	}

out:
	heap_release(args);
	return 0;
}
Beispiel #8
0
status_t
user_menu(BootVolume& _bootVolume, PathBlacklist& _pathBlacklist)
{

	Menu* menu = new(std::nothrow) Menu(MAIN_MENU);

	sMainMenu = menu;
	sBootVolume = &_bootVolume;
	sPathBlacklist = &_pathBlacklist;

	Menu* safeModeMenu = NULL;
	Menu* debugMenu = NULL;
	MenuItem* item;

	TRACE(("user_menu: enter\n"));

	// Add boot volume
	menu->AddItem(item = new(std::nothrow) MenuItem("Select boot volume",
		add_boot_volume_menu()));

	// Add safe mode
	menu->AddItem(item = new(std::nothrow) MenuItem("Select safe mode options",
		safeModeMenu = add_safe_mode_menu()));

	// add debug menu
	menu->AddItem(item = new(std::nothrow) MenuItem("Select debug options",
		debugMenu = add_debug_menu()));

	// Add platform dependent menus
	platform_add_menus(menu);

	menu->AddSeparatorItem();

	menu->AddItem(item = new(std::nothrow) MenuItem("Reboot"));
	item->SetTarget(user_menu_reboot);
	item->SetShortcut('r');

	menu->AddItem(item = new(std::nothrow) MenuItem("Continue booting"));
	if (!_bootVolume.IsValid()) {
		item->SetEnabled(false);
		menu->ItemAt(0)->Select(true);
	} else
		item->SetShortcut('b');

	menu->Run();

	apply_safe_mode_options(safeModeMenu);
	apply_safe_mode_options(debugMenu);
	apply_safe_mode_path_blacklist();
	add_safe_mode_settings(sSafeModeOptionsBuffer.String());
	delete menu;


	TRACE(("user_menu: leave\n"));

	sMainMenu = NULL;
	sBlacklistRootMenu = NULL;
	sBootVolume = NULL;
	sPathBlacklist = NULL;
	return B_OK;
}