11553Srgrimes/*
21553Srgrimes * Copyright 2007-2014, Ingo Weinhold, ingo_weinhold@gmx.de.
31553Srgrimes * Copyright 2002-2010, Axel D��rfler, axeld@pinc-software.de.
41553Srgrimes * Distributed under the terms of the MIT License.
51553Srgrimes *
61553Srgrimes * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
71553Srgrimes * Distributed under the terms of the NewOS License.
81553Srgrimes */
91553Srgrimes
101553Srgrimes
111553Srgrimes#include "vfs_boot.h"
121553Srgrimes
131553Srgrimes#include <stdio.h>
141553Srgrimes#include <strings.h>
151553Srgrimes
161553Srgrimes#include <fs_info.h>
171553Srgrimes#include <OS.h>
181553Srgrimes
191553Srgrimes#include <boot/kernel_args.h>
201553Srgrimes#include <directories.h>
211553Srgrimes#include <disk_device_manager/KDiskDevice.h>
221553Srgrimes#include <disk_device_manager/KDiskDeviceManager.h>
231553Srgrimes#include <disk_device_manager/KPartitionVisitor.h>
241553Srgrimes#include <DiskDeviceTypes.h>
251553Srgrimes#include <file_cache.h>
261553Srgrimes#include <fs/KPath.h>
271553Srgrimes#include <kmodule.h>
281553Srgrimes#include <syscalls.h>
291553Srgrimes#include <util/KMessage.h>
30114601Sobrien#include <util/Stack.h>
311553Srgrimes#include <vfs.h>
3230260Scharnier
331553Srgrimes#include "vfs_net_boot.h"
341553Srgrimes
351553Srgrimes
361553Srgrimes//#define TRACE_VFS
371553Srgrimes#ifdef TRACE_VFS
381553Srgrimes#	define TRACE(x) dprintf x
39114601Sobrien#else
4030260Scharnier#	define TRACE(x) ;
41146755Scharnier#endif
42114601Sobrien
43114601Sobrien
441553Srgrimestypedef Stack<KPartition *> PartitionStack;
451553Srgrimes
46142832Srustatic struct {
471553Srgrimes	const char *path;
48113596Snectar	const char *target;
491553Srgrimes} sPredefinedLinks[] = {
501553Srgrimes	{ kGlobalSystemDirectory,		kSystemDirectory },
511553Srgrimes	{ kGlobalBinDirectory,			kSystemBinDirectory },
521553Srgrimes	{ kGlobalEtcDirectory,			kSystemEtcDirectory },
531553Srgrimes	{ kGlobalTempDirectory,			kSystemTempDirectory },
54285205Sgarga	{ kGlobalVarDirectory,			kSystemVarDirectory },
551553Srgrimes	{ kGlobalPackageLinksDirectory,	kSystemPackageLinksDirectory },
561553Srgrimes	{NULL}
571553Srgrimes};
581553Srgrimes
591553Srgrimes// This can be used by other code to see if there is a boot file system already
601553Srgrimesdev_t gBootDevice = -1;
611553Srgrimesbool gReadOnlyBootDevice = false;
621553Srgrimes
631553Srgrimes
641553Srgrimes/*!	No image was chosen - prefer disks with names like "Haiku", or "System"
651553Srgrimes */
661553Srgrimesint
671553Srgrimescompare_image_boot(const void* _a, const void* _b)
681553Srgrimes{
69113666Snectar	KPartition* a = *(KPartition**)_a;
70113666Snectar	KPartition* b = *(KPartition**)_b;
711553Srgrimes
72227257Sed	if (a->ContentName() != NULL) {
731553Srgrimes		if (b->ContentName() == NULL)
741553Srgrimes			return 1;
751553Srgrimes	} else if (b->ContentName() != NULL) {
761553Srgrimes		return -1;
771553Srgrimes	} else
78142832Sru		return 0;
791553Srgrimes
801553Srgrimes	int compare = strcasecmp(a->ContentName(), b->ContentName());
811553Srgrimes	if (!compare)
821553Srgrimes		return 0;
831553Srgrimes
842551Sgpalmer	if (!strcasecmp(a->ContentName(), "Haiku"))
851553Srgrimes		return 1;
8639777Sdt	if (!strcasecmp(b->ContentName(), "Haiku"))
8723517Swosch		return -1;
8823517Swosch	if (!strncmp(a->ContentName(), "System", 6))
8999819Salfred		return 1;
9099819Salfred	if (!strncmp(b->ContentName(), "System", 6))
9199819Salfred		return -1;
9299819Salfred
9399819Salfred	return compare;
9499819Salfred}
951553Srgrimes
961553Srgrimes
9799819Salfred/*!	The system was booted from CD - prefer CDs over other entries. If there
981553Srgrimes	is no CD, fall back to the standard mechanism (as implemented by
99113596Snectar	compare_image_boot().
100113596Snectar*/
10116876Sguidostatic int
10216876Sguidocompare_cd_boot(const void* _a, const void* _b)
1031553Srgrimes{
1041553Srgrimes	KPartition* a = *(KPartition**)_a;
10599819Salfred	KPartition* b = *(KPartition**)_b;
10699819Salfred
107113596Snectar	bool aIsCD = a->Type() != NULL
10899819Salfred		&& !strcmp(a->Type(), kPartitionTypeDataSession);
10999819Salfred	bool bIsCD = b->Type() != NULL
1101553Srgrimes		&& !strcmp(b->Type(), kPartitionTypeDataSession);
11116876Sguido
1122551Sgpalmer	int compare = (int)aIsCD - (int)bIsCD;
11316876Sguido	if (compare != 0)
11416876Sguido		return compare;
11516876Sguido
116132509Simp	return compare_image_boot(_a, _b);
11741712Sdillon}
1181553Srgrimes
119132509Simp
1202551Sgpalmer/*!	Computes a check sum for the specified block.
1211553Srgrimes	The check sum is the sum of all data in that block interpreted as an
12216876Sguido	array of uint32 values.
123146755Scharnier	Note, this must use the same method as the one used in
124142832Sru	boot/platform/bios_ia32/devices.cpp (or similar solutions).
1251553Srgrimes*/
126142832Srustatic uint32
127142832Srucompute_check_sum(KDiskDevice* device, off_t offset)
128142832Sru{
12932397Swosch	char buffer[512];
13032397Swosch	ssize_t bytesRead = read_pos(device->FD(), offset, buffer, sizeof(buffer));
13117672Swosch	if (bytesRead < B_OK)
132142832Sru		return 0;
133142832Sru
134142832Sru	if (bytesRead < (ssize_t)sizeof(buffer))
135132507Simp		memset(buffer + bytesRead, 0, sizeof(buffer) - bytesRead);
136132507Simp
137132507Simp	uint32* array = (uint32*)buffer;
1382551Sgpalmer	uint32 sum = 0;
139132509Simp
140132507Simp	for (uint32 i = 0;
1412551Sgpalmer			i < (bytesRead + sizeof(uint32) - 1) / sizeof(uint32); i++) {
142132509Simp		sum += array[i];
143132509Simp	}
144132509Simp
1451553Srgrimes	return sum;
1461553Srgrimes}
1471553Srgrimes
14835286Sphk
14935286Sphk// #pragma mark - BootMethod
15035286Sphk
15116876Sguido
15216876SguidoBootMethod::BootMethod(const KMessage& bootVolume, int32 method)
15316876Sguido	:
1542551Sgpalmer	fBootVolume(bootVolume),
1551553Srgrimes	fMethod(method)
1561553Srgrimes{
1571553Srgrimes}
1581553Srgrimes
1591553Srgrimes
1601553SrgrimesBootMethod::~BootMethod()
1611553Srgrimes{
16216946Smartin}
1631553Srgrimes
1641553Srgrimes
1651553Srgrimesstatus_t
1661553SrgrimesBootMethod::Init()
1671553Srgrimes{
1681553Srgrimes	return B_OK;
1691553Srgrimes}
1701553Srgrimes
1711553Srgrimes
1721553Srgrimes// #pragma mark - DiskBootMethod
1731553Srgrimes
1741553Srgrimes
1751553Srgrimesclass DiskBootMethod : public BootMethod {
1761553Srgrimespublic:
1771553Srgrimes	DiskBootMethod(const KMessage& bootVolume, int32 method)
1781553Srgrimes		: BootMethod(bootVolume, method)
1791553Srgrimes	{
1801553Srgrimes	}
1811553Srgrimes
18241712Sdillon	virtual bool IsBootDevice(KDiskDevice* device, bool strict);
18341712Sdillon	virtual bool IsBootPartition(KPartition* partition, bool& foundForSure);
18441712Sdillon	virtual void SortPartitions(KPartition** partitions, int32 count);
18541712Sdillon};
18641712Sdillon
18741712Sdillon
18841712Sdillonbool
18941712SdillonDiskBootMethod::IsBootDevice(KDiskDevice* device, bool strict)
19041712Sdillon{
19141712Sdillon	disk_identifier* disk;
19241712Sdillon	int32 diskIdentifierSize;
19341712Sdillon	if (fBootVolume.FindData(BOOT_VOLUME_DISK_IDENTIFIER, B_RAW_TYPE,
19441712Sdillon			(const void**)&disk, &diskIdentifierSize) != B_OK) {
19541712Sdillon		dprintf("DiskBootMethod::IsBootDevice(): no disk identifier!\n");
196132509Simp		return false;
19741712Sdillon	}
19841712Sdillon
19941712Sdillon	TRACE(("boot device: bus %" B_PRId32 ", device %" B_PRId32 "\n",
20041712Sdillon		disk->bus_type, disk->device_type));
20141712Sdillon
20241712Sdillon	// Assume that CD boots only happen off removable media.
20341712Sdillon	if (fMethod == BOOT_METHOD_CD && !device->IsRemovable())
20441712Sdillon		return false;
20541712Sdillon
20617672Swosch	switch (disk->bus_type) {
20732397Swosch		case PCI_BUS:
208192432Sbrian		case LEGACY_BUS:
209192432Sbrian			// TODO: implement this! (and then enable this feature in the boot
210192432Sbrian			// loader)
211192432Sbrian			// (we need a way to get the device_node of a device, then)
212192432Sbrian			break;
21317672Swosch
21417672Swosch		case UNKNOWN_BUS:
21517672Swosch			// nothing to do here
2161553Srgrimes			break;
2172551Sgpalmer	}
21816876Sguido
21917125Sbde	switch (disk->device_type) {
220114159Snectar		case UNKNOWN_DEVICE:
221114159Snectar			// test if the size of the device matches
22216876Sguido			// (the BIOS might have given us the wrong value here, though)
22316876Sguido			if (strict && device->Size() != disk->device.unknown.size)
2241553Srgrimes				return false;
22516876Sguido
22616876Sguido			// Skip the check sum test for CDs, since we didn't read anything
22716876Sguido			// useful from the disk in the boot loader.
228296424Sdwmalone			if (fMethod == BOOT_METHOD_CD)
22916876Sguido				break;
23016876Sguido
23116876Sguido			// check if the check sums match, too
23216876Sguido			for (int32 i = 0; i < NUM_DISK_CHECK_SUMS; i++) {
23316876Sguido				if (disk->device.unknown.check_sums[i].offset == -1)
23416876Sguido					continue;
235296424Sdwmalone
23616876Sguido				if (compute_check_sum(device,
23716876Sguido						disk->device.unknown.check_sums[i].offset)
23816876Sguido							!= disk->device.unknown.check_sums[i].sum) {
23916876Sguido					return false;
24016876Sguido				}
24116876Sguido			}
24216876Sguido			break;
24316876Sguido
24416876Sguido		case ATA_DEVICE:
24516876Sguido		case ATAPI_DEVICE:
24616876Sguido		case SCSI_DEVICE:
247114159Snectar		case USB_DEVICE:
248114159Snectar		case FIREWIRE_DEVICE:
249114159Snectar		case FIBRE_DEVICE:
250114159Snectar			// TODO: implement me!
251114159Snectar			break;
252114159Snectar	}
253114159Snectar
254114159Snectar	return true;
25516876Sguido}
25616876Sguido
25716876Sguido
25816876Sguidobool
25916876SguidoDiskBootMethod::IsBootPartition(KPartition* partition, bool& foundForSure)
26016876Sguido{
26116876Sguido	off_t bootPartitionOffset = fBootVolume.GetInt64(
26216876Sguido		BOOT_VOLUME_PARTITION_OFFSET, 0);
26316876Sguido
26416876Sguido	if (!fBootVolume.GetBool(BOOT_VOLUME_BOOTED_FROM_IMAGE, false)) {
26517125Sbde		// the simple case: we can just boot from the selected boot
26617125Sbde		// device
26717125Sbde		if (partition->Offset() == bootPartitionOffset) {
26817125Sbde			dprintf("Identified boot partition by partition offset.\n");
26916876Sguido			foundForSure = true;
270114159Snectar			return true;
271114159Snectar		}
27216876Sguido	} else {
273114159Snectar		// For now, unless we can positively identify an anyboot CD, we will
27416876Sguido		// just collect all BFS/ISO9660 volumes.
27516876Sguido
27616876Sguido		if (fMethod == BOOT_METHOD_CD) {
27717125Sbde			// Check for the boot partition of an anyboot CD. We identify it as
27816876Sguido			// such if it is a partition on the CD, has type BFS, and the boot
27916876Sguido			// partition offset is 0
28016876Sguido			KDiskDevice* device = partition->Device();
28116876Sguido			if (IsBootDevice(device, false)
28216876Sguido				&& bootPartitionOffset == 0 && partition->Parent() == device
28316876Sguido				&& device->ContentType() != NULL
28416876Sguido				&& strcmp(device->ContentType(), kPartitionTypeIntel) == 0
28516876Sguido				&& partition->ContentType() != NULL
28616876Sguido				&& strcmp(partition->ContentType(), kPartitionTypeBFS) == 0) {
28733413Sguido				dprintf("Identified anyboot CD.\n");
28833413Sguido				foundForSure = true;
28916876Sguido				return true;
29016876Sguido			}
29116876Sguido
292296424Sdwmalone			// Ignore non-session partitions, if a boot partition was selected
29316876Sguido			// by the user.
29416876Sguido			if (fBootVolume.GetBool(BOOT_VOLUME_USER_SELECTED, false)
29516876Sguido				&& partition->Type() != NULL
29616876Sguido				&& strcmp(partition->Type(), kPartitionTypeDataSession) != 0) {
29716876Sguido				return false;
298296424Sdwmalone			}
29916876Sguido		}
30016876Sguido
30116876Sguido		if (partition->ContentType() != NULL
30216876Sguido			&& (strcmp(partition->ContentType(), kPartitionTypeBFS) == 0
30316876Sguido			|| strcmp(partition->ContentType(), kPartitionTypeISO9660) == 0)) {
30416876Sguido			return true;
30516876Sguido		}
30616876Sguido	}
3071553Srgrimes
3081553Srgrimes	return false;
3091553Srgrimes}
3101553Srgrimes
3111553Srgrimes
3121553Srgrimesvoid
3131553SrgrimesDiskBootMethod::SortPartitions(KPartition** partitions, int32 count)
3141553Srgrimes{
3151553Srgrimes	qsort(partitions, count, sizeof(KPartition*),
3161553Srgrimes		fMethod == BOOT_METHOD_CD ? compare_cd_boot : compare_image_boot);
3171553Srgrimes}
3181553Srgrimes
3191553Srgrimes
3201553Srgrimes// #pragma mark -
3211553Srgrimes
3221553Srgrimes
3231553Srgrimes/*!	Make the boot partition (and probably others) available.
3241553Srgrimes	The partitions that are a boot candidate a put into the /a partitions
3251553Srgrimes	stack. If the user selected a boot device, there is will only be one
3261553Srgrimes	entry in this stack; if not, the most likely is put up first.
3271553Srgrimes	The boot code should then just try them one by one.
3281553Srgrimes*/
3291553Srgrimesstatic status_t
3301553Srgrimesget_boot_partitions(KMessage& bootVolume, PartitionStack& partitions)
3311553Srgrimes{
3321553Srgrimes	dprintf("get_boot_partitions(): boot volume message:\n");
3331553Srgrimes	bootVolume.Dump(&dprintf);
3341553Srgrimes
335113596Snectar	// create boot method
336113596Snectar	int32 bootMethodType = bootVolume.GetInt32(BOOT_METHOD, BOOT_METHOD_DEFAULT);
337113596Snectar	dprintf("get_boot_partitions(): boot method type: %" B_PRId32 "\n",
338114159Snectar		bootMethodType);
339113596Snectar
340114159Snectar	BootMethod* bootMethod = NULL;
341114159Snectar	switch (bootMethodType) {
342114159Snectar		case BOOT_METHOD_NET:
343114159Snectar			bootMethod = new(nothrow) NetBootMethod(bootVolume, bootMethodType);
344114159Snectar			break;
345114159Snectar
346114159Snectar		case BOOT_METHOD_HARD_DISK:
347114159Snectar		case BOOT_METHOD_CD:
348114159Snectar		default:
349114159Snectar			bootMethod = new(nothrow) DiskBootMethod(bootVolume,
350114159Snectar				bootMethodType);
351114159Snectar			break;
352114159Snectar	}
353114159Snectar
354114159Snectar	status_t status = bootMethod != NULL ? bootMethod->Init() : B_NO_MEMORY;
355223818Sgordon	if (status != B_OK)
3561553Srgrimes		return status;
35716876Sguido
3581553Srgrimes	KDiskDeviceManager::CreateDefault();
3591553Srgrimes	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
36039777Sdt
361223818Sgordon	status = manager->InitialDeviceScan();
3627277Swpaul	if (status != B_OK) {
363223818Sgordon		dprintf("KDiskDeviceManager::InitialDeviceScan() returned error: %s\n",
364223818Sgordon			strerror(status));
36551025Speter		// InitialDeviceScan returns error if one (or more) partitions are
36651025Speter		// determined to be invalid. The partition we are trying to boot from
36730260Scharnier		// may be usuable anyway, so don't fail here.
368113596Snectar	}
369113596Snectar
370113596Snectar#if KDEBUG
371142832Sru	// dump devices and partitions
372142832Sru	KDiskDevice *device;
373142832Sru	int32 cookie = 0;
374142832Sru	while ((device = manager->NextDevice(&cookie)) != NULL) {
375142832Sru		device->Dump(true, 0);
376142832Sru	}
37739777Sdt#endif
37823517Swosch
37916876Sguido	struct BootPartitionVisitor : KPartitionVisitor {
38016876Sguido		BootPartitionVisitor(BootMethod* bootMethod, PartitionStack &stack)
38116876Sguido			: fPartitions(stack),
38216876Sguido			  fBootMethod(bootMethod)
383113596Snectar		{
384113596Snectar		}
385113596Snectar
386113596Snectar		virtual bool VisitPre(KPartition *partition)
387113596Snectar		{
388113596Snectar			if (!partition->ContainsFileSystem())
389113596Snectar				return false;
390113596Snectar
391113596Snectar			bool foundForSure = false;
392113596Snectar			if (fBootMethod->IsBootPartition(partition, foundForSure))
393113596Snectar				fPartitions.Push(partition);
394113596Snectar
395113596Snectar			// if found for sure, we can terminate the search
396113596Snectar			return foundForSure;
397113596Snectar		}
398113596Snectar
399113596Snectar		private:
400113596Snectar			PartitionStack	&fPartitions;
401113596Snectar			BootMethod*		fBootMethod;
402113596Snectar	} visitor(bootMethod, partitions);
403113596Snectar
404113596Snectar	bool strict = true;
405113596Snectar
406113596Snectar	while (true) {
407113596Snectar		KDiskDevice *device;
408113596Snectar		int32 cookie = 0;
409113596Snectar		while ((device = manager->NextDevice(&cookie)) != NULL) {
410113666Snectar			if (!bootMethod->IsBootDevice(device, strict))
411113596Snectar				continue;
412113596Snectar
413113596Snectar			if (device->VisitEachDescendant(&visitor) != NULL)
414113596Snectar				break;
415113596Snectar		}
416113596Snectar
417113596Snectar		if (!partitions.IsEmpty() || !strict)
418113666Snectar			break;
419113596Snectar
420113596Snectar		// we couldn't find any potential boot devices, try again less strict
421113596Snectar		strict = false;
422113596Snectar	}
423113596Snectar
424113596Snectar	// sort partition list (e.g.. when booting from CD, CDs should come first in
425113596Snectar	// the list)
426113666Snectar	if (!bootVolume.GetBool(BOOT_VOLUME_USER_SELECTED, false))
427113596Snectar		bootMethod->SortPartitions(partitions.Array(), partitions.CountItems());
428113596Snectar
429113596Snectar	return B_OK;
430113596Snectar}
431113596Snectar
432113596Snectar
433113596Snectar//	#pragma mark -
434113666Snectar
435113596Snectar
436113596Snectarstatus_t
437113596Snectarvfs_bootstrap_file_systems(void)
438113596Snectar{
439113596Snectar	status_t status;
440113596Snectar
441113596Snectar	// bootstrap the root filesystem
442113666Snectar	status = _kern_mount("/", NULL, "rootfs", 0, NULL, 0);
443113596Snectar	if (status < B_OK)
444113596Snectar		panic("error mounting rootfs!\n");
445113596Snectar
446113596Snectar	_kern_setcwd(-1, "/");
447113596Snectar
448113596Snectar	// bootstrap the devfs
449113596Snectar	_kern_create_dir(-1, "/dev", 0755);
450113666Snectar	status = _kern_mount("/dev", NULL, "devfs", 0, NULL, 0);
451113596Snectar	if (status < B_OK)
452113596Snectar		panic("error mounting devfs\n");
453113596Snectar
454113596Snectar	// create directory for the boot volume
455113596Snectar	_kern_create_dir(-1, "/boot", 0755);
456113596Snectar
457113596Snectar	// create some standard links on the rootfs
458113596Snectar
459113666Snectar	for (int32 i = 0; sPredefinedLinks[i].path != NULL; i++) {
460113596Snectar		_kern_create_symlink(-1, sPredefinedLinks[i].path,
461113596Snectar			sPredefinedLinks[i].target, 0777);
462113596Snectar			// we don't care if it will succeed or not
463113596Snectar	}
464113596Snectar
465113596Snectar	return B_OK;
466113596Snectar}
467113596Snectar
468113596Snectar
469113596Snectarvoid
470113596Snectarvfs_mount_boot_file_system(kernel_args* args)
471113596Snectar{
472113596Snectar	KMessage bootVolume;
473142832Sru	bootVolume.SetTo(args->boot_volume, args->boot_volume_size);
474142832Sru
475142832Sru	PartitionStack partitions;
47616876Sguido	status_t status = get_boot_partitions(bootVolume, partitions);
47716876Sguido	if (status < B_OK) {
47816876Sguido		panic("get_boot_partitions failed!");
47916876Sguido	}
480142832Sru	if (partitions.IsEmpty()) {
481142832Sru		panic("did not find any boot partitions! @! syslog | tail 15");
48216876Sguido	}
4831553Srgrimes
484113596Snectar	dev_t bootDevice = -1;
48516876Sguido
48616876Sguido	KPartition* bootPartition;
48716876Sguido	while (partitions.Pop(&bootPartition)) {
488142832Sru		KPath path;
489142832Sru		if (bootPartition->GetPath(&path) != B_OK)
490142832Sru			panic("could not get boot device!\n");
49116876Sguido
49216876Sguido		const char* fsName = NULL;
49316876Sguido		bool readOnly = false;
49416876Sguido		if (strcmp(bootPartition->ContentType(), kPartitionTypeISO9660) == 0) {
495142832Sru			fsName = "iso9660:write_overlay:attribute_overlay";
496142832Sru			readOnly = true;
49716876Sguido		} else if (bootPartition->IsReadOnly()
4981553Srgrimes			&& strcmp(bootPartition->ContentType(), kPartitionTypeBFS) == 0) {
49916876Sguido			fsName = "bfs:write_overlay";
500113666Snectar			readOnly = true;
50116876Sguido		}
50216876Sguido
50316876Sguido		TRACE(("trying to mount boot partition: %s\n", path.Path()));
50416876Sguido
50516876Sguido		bootDevice = _kern_mount("/boot", path.Path(), fsName, 0, NULL, 0);
5061553Srgrimes		if (bootDevice >= 0) {
50716876Sguido			dprintf("Mounted boot partition: %s\n", path.Path());
508113666Snectar			gReadOnlyBootDevice = readOnly;
509142832Sru			break;
510142832Sru		}
511142832Sru	}
51216876Sguido
51316876Sguido	if (bootDevice < B_OK)
5141553Srgrimes		panic("could not mount boot device!\n");
51516876Sguido
516113666Snectar	// create link for the name of the boot device
517142832Sru
518142832Sru	fs_info info;
519142832Sru	if (_kern_read_fs_info(bootDevice, &info) == B_OK) {
52016876Sguido		char path[B_FILE_NAME_LENGTH + 1];
52116876Sguido		snprintf(path, sizeof(path), "/%s", info.volume_name);
52216876Sguido
52316876Sguido		_kern_create_symlink(-1, path, "/boot", 0777);
524113666Snectar	}
52516876Sguido
52616876Sguido	// If we're booting off a packaged system, mount packagefs.
52716876Sguido	struct stat st;
52816876Sguido	if (bootVolume.GetBool(BOOT_VOLUME_PACKAGED, false)
52916876Sguido		|| (bootVolume.GetBool(BOOT_VOLUME_BOOTED_FROM_IMAGE, false)
53016876Sguido			&& lstat(kSystemPackagesDirectory, &st) == 0)) {
53116876Sguido		static const char* const kPackageFSName = "packagefs";
532113666Snectar
533142832Sru		char arguments[256];
534142832Sru		strlcpy(arguments, "packages /boot/system/packages; type system",
535142832Sru			sizeof(arguments));
53616876Sguido		if (const char* stateName
5377257Swpaul				= bootVolume.GetString(BOOT_VOLUME_PACKAGES_STATE, NULL)) {
53816876Sguido			strlcat(arguments, "; state ", sizeof(arguments));
53916876Sguido			strlcat(arguments, stateName, sizeof(arguments));
540113666Snectar		}
541142832Sru
542142832Sru		dev_t packageMount = _kern_mount("/boot/system", NULL, kPackageFSName,
543142832Sru			0, arguments, 0 /* unused argument length */);
54416876Sguido		if (packageMount < 0) {
54516876Sguido			panic("Failed to mount system packagefs: %s",
54616876Sguido				strerror(packageMount));
54716876Sguido		}
54816876Sguido
549113666Snectar		packageMount = _kern_mount("/boot/home/config", NULL, kPackageFSName, 0,
550142832Sru			"packages /boot/home/config/packages; type home",
551142832Sru			0 /* unused argument length */);
552142832Sru		if (packageMount < 0) {
55316876Sguido			dprintf("Failed to mount home packagefs: %s\n",
55416876Sguido				strerror(packageMount));
55516876Sguido		}
55616876Sguido	}
55716876Sguido
5587257Swpaul	status = _kern_mount("/boot/system/var/shared_memory", NULL, "ramfs", 0, NULL, 0);
5591553Srgrimes	if (status < B_OK)
56039777Sdt		dprintf("Failed to mount shared memory FS: %s\n", strerror(status));
56133434Sguido
56233413Sguido	// Now that packagefs is mounted, the boot volume is really ready.
56333614Sguido	gBootDevice = bootDevice;
56419085Swpaul
56519085Swpaul	// Do post-boot-volume module initialization. The module code wants to know
56619085Swpaul	// whether the module images the boot loader has pre-loaded are the same as
56757868Spaul	// on the boot volume. That is the case when booting from hard disk or CD,
56857868Spaul	// but not via network.
56919085Swpaul	int32 bootMethodType = bootVolume.GetInt32(BOOT_METHOD, BOOT_METHOD_DEFAULT);
57033413Sguido	bool bootingFromBootLoaderVolume = bootMethodType == BOOT_METHOD_HARD_DISK
57119085Swpaul		|| bootMethodType == BOOT_METHOD_CD;
57219085Swpaul	module_init_post_boot_device(bootingFromBootLoaderVolume);
57333434Sguido
57433413Sguido	file_cache_init_post_boot_device();
57519085Swpaul
5761553Srgrimes	// search for other disk systems
5772916Swollman	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
57817125Sbde	manager->RescanDiskSystems();
5792934Swollman	manager->StartMonitoring();
5802934Swollman}
5812916Swollman
582113666Snectar