From 49c044ab9fc4afb883931c0d0e5ba5083e60a563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Sat, 8 Jan 2011 13:47:22 +0000 Subject: [PATCH] * Changed bootman.S to use the BIOS provided drive to stage load itself, as well as when the boot menu entry has a 0 BIOS drive. This allows the boot loader to be installed on any drive. * Implemented BootDrive class, and changed LegacyBootMenu the way it should work now. Installing the boot menu should now work again, and the first time while installing Haiku. * Removed MakeArray.cpp - we already have such a tool in our repository. * Build BootLoader.h automatically during the build process - the only disadvantage is that you can only build it on x86 now (but other systems don't use this boot loader, anyway). * In general, the BootManager is prepared to handle different kinds of boot menus; one only needs to write a class BootMenu implementation for this to work - and have the possibility to choose between different menus, if there are more than one per platform/partitioning system. * Renamed quite a few methods. * Automatic whitespace cleanup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@40149 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/bootmanager/BootDrive.cpp | 98 ++++++++ src/apps/bootmanager/BootDrive.h | 21 +- src/apps/bootmanager/BootLoader.h | 71 ------ .../bootmanager/BootManagerController.cpp | 49 ++-- src/apps/bootmanager/BootManagerController.h | 7 +- src/apps/bootmanager/BootMenu.h | 19 +- src/apps/bootmanager/DrivesPage.cpp | 46 ++-- src/apps/bootmanager/DrivesPage.h | 4 +- src/apps/bootmanager/Jamfile | 37 +-- src/apps/bootmanager/LegacyBootMenu.cpp | 218 +++++++++++------- src/apps/bootmanager/LegacyBootMenu.h | 15 +- src/apps/bootmanager/MakeArray.cpp | 51 ---- src/apps/bootmanager/WizardView.cpp | 4 + src/apps/bootmanager/bootman.S | 154 +++++++------ 14 files changed, 449 insertions(+), 345 deletions(-) create mode 100644 src/apps/bootmanager/BootDrive.cpp delete mode 100644 src/apps/bootmanager/BootLoader.h delete mode 100644 src/apps/bootmanager/MakeArray.cpp diff --git a/src/apps/bootmanager/BootDrive.cpp b/src/apps/bootmanager/BootDrive.cpp new file mode 100644 index 0000000000..977a7bd233 --- /dev/null +++ b/src/apps/bootmanager/BootDrive.cpp @@ -0,0 +1,98 @@ +/* + * Copyright 2011, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include "BootDrive.h" + +#include +#include +#include +#include + + +BootDrive::BootDrive(const char* path) + : + fPath(path) +{ +} + + +BootDrive::~BootDrive() +{ +} + + +BootMenu* +BootDrive::InstalledMenu(const BootMenuList& menus) const +{ + for (int32 i = 0; i < menus.CountItems(); i++) { + BootMenu* menu = menus.ItemAt(i); + if (menu->IsInstalled(*this)) + return menu; + } + return NULL; +} + + +status_t +BootDrive::CanMenuBeInstalled(const BootMenuList& menus) const +{ + status_t status = B_ERROR; + + for (int32 i = 0; i < menus.CountItems(); i++) { + status = menus.ItemAt(i)->CanBeInstalled(*this); + if (status == B_OK) + return status; + } + return status; +} + + +/*! Adds all boot menus from the list \a from that support the drive to \a to. +*/ +void +BootDrive::AddSupportedMenus(const BootMenuList& from, BootMenuList& to) +{ + for (int32 i = 0; i < from.CountItems(); i++) { + BootMenu* menu = from.ItemAt(i); + if (menu->CanBeInstalled(*this)) + to.AddItem(menu); + } +} + + +const char* +BootDrive::Path() const +{ + return fPath.Path(); +} + + +bool +BootDrive::IsBootDrive() const +{ + BVolumeRoster volumeRoster; + BVolume volume; + if (volumeRoster.GetBootVolume(&volume) != B_OK) + return false; + + BDiskDeviceRoster roster; + BDiskDevice device; + if (roster.FindPartitionByVolume(volume, &device, NULL) == B_OK) { + BPath path; + if (device.GetPath(&path) == B_OK && path == fPath) + return true; + } + + return false; +} + + +status_t +BootDrive::GetDiskDevice(BDiskDevice& device) const +{ + BDiskDeviceRoster roster; + return roster.GetDeviceForPath(fPath.Path(), &device); +} diff --git a/src/apps/bootmanager/BootDrive.h b/src/apps/bootmanager/BootDrive.h index 0f72b778e0..238bb87d38 100644 --- a/src/apps/bootmanager/BootDrive.h +++ b/src/apps/bootmanager/BootDrive.h @@ -6,21 +6,30 @@ #define BOOT_DRIVE_H -#include +#include + +#include "BootMenu.h" + + +class BDiskDevice; class BootDrive { public: - BootDrive(); + BootDrive(const char* path); virtual ~BootDrive(); - bool IsBootMenuInstalled() const; - bool CanBootMenuBeInstalled() const; + BootMenu* InstalledMenu( + const BootMenuList& menus) const; + status_t CanMenuBeInstalled( + const BootMenuList& menus) const; + void AddSupportedMenus(const BootMenuList& from, + BootMenuList& to); + const char* Path() const; bool IsBootDrive() const; - status_t GetStream(BPositionIO* stream); - status_t GetBIOSDrive(uint8* drive); + status_t GetDiskDevice(BDiskDevice& device) const; private: BPath fPath; diff --git a/src/apps/bootmanager/BootLoader.h b/src/apps/bootmanager/BootLoader.h deleted file mode 100644 index d186687653..0000000000 --- a/src/apps/bootmanager/BootLoader.h +++ /dev/null @@ -1,71 +0,0 @@ -// THIS FILE WAS GENERATED WITH -// ./make_array kBootLoader bootman.bin - -static const uint8 kBootLoader[] = { - 0xb8, 0xc0, 0x07, 0x8e, 0xd8, 0x8e, 0xc0, 0x8e, 0xd0, 0xbc, 0xf3, 0xff, 0x89, 0xe5, 0xfc, 0xb4, - 0x06, 0x30, 0xc0, 0xb7, 0x0f, 0x31, 0xc9, 0xba, 0x4f, 0x18, 0xcd, 0x10, 0xe8, 0x63, 0x00, 0xb7, - 0x00, 0xba, 0x1f, 0x01, 0x89, 0x56, 0x08, 0xbe, 0xa9, 0x00, 0xb3, 0x0f, 0xe8, 0x2f, 0x00, 0xba, - 0x1b, 0x17, 0x89, 0x56, 0x08, 0xb3, 0x07, 0xbe, 0xbc, 0x00, 0xe8, 0x21, 0x00, 0xb4, 0x42, 0xb2, - 0x80, 0xbe, 0x99, 0x00, 0xcd, 0x13, 0x72, 0x03, 0xe9, 0xb5, 0x01, 0xe8, 0x43, 0x00, 0xbe, 0xd7, - 0x00, 0xb3, 0x04, 0xe8, 0x08, 0x00, 0xb4, 0x00, 0xcd, 0x16, 0xb2, 0x80, 0xcd, 0x19, 0x50, 0x53, - 0x51, 0x52, 0x30, 0xff, 0xe9, 0x11, 0x00, 0x8b, 0x56, 0x08, 0xb4, 0x02, 0xcd, 0x10, 0xfe, 0x46, - 0x08, 0xb9, 0x01, 0x00, 0xb4, 0x09, 0xcd, 0x10, 0xac, 0x3c, 0x00, 0x75, 0xea, 0x5a, 0x59, 0x5b, - 0x58, 0xc3, 0xb4, 0x03, 0xcd, 0x10, 0x89, 0x4e, 0x0a, 0xb4, 0x01, 0xb9, 0x00, 0x20, 0xcd, 0x10, - 0xc3, 0x8b, 0x4e, 0x0a, 0xb4, 0x01, 0xcd, 0x10, 0xc3, 0x10, 0x00, 0x03, 0x00, 0x00, 0x02, 0xc0, - 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x61, 0x69, 0x6b, 0x75, 0x20, 0x42, - 0x6f, 0x6f, 0x74, 0x20, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x00, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x20, 0x61, 0x6e, 0x20, 0x4f, 0x53, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x6d, 0x65, 0x6e, 0x75, 0x00, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x6c, 0x6f, 0x61, - 0x64, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x21, 0x00, 0x42, 0x42, - 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, - 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, - 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, - 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, - 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, - 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, - 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, - 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, - 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, - 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, - 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, - 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, - 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, - 0xa1, 0x17, 0x04, 0x89, 0x46, 0x00, 0xb8, 0x13, 0x00, 0xf7, 0x26, 0x19, 0x04, 0x89, 0xd3, 0x50, - 0xb4, 0x00, 0xcd, 0x1a, 0x58, 0x01, 0xd0, 0x11, 0xcb, 0x89, 0x46, 0x04, 0x89, 0x5e, 0x06, 0xa0, - 0x15, 0x04, 0xd0, 0xe8, 0xb3, 0x0c, 0x28, 0xc3, 0x88, 0x5e, 0x02, 0xb4, 0x02, 0xcd, 0x16, 0x24, - 0x08, 0x74, 0x06, 0xc7, 0x06, 0x19, 0x04, 0xff, 0xff, 0xe8, 0x64, 0x00, 0x81, 0x3e, 0x19, 0x04, - 0xff, 0xff, 0x74, 0x25, 0xb4, 0x01, 0xcd, 0x16, 0x75, 0x1f, 0xe8, 0x05, 0x00, 0x73, 0xf5, 0xe9, - 0xa6, 0x00, 0xb4, 0x00, 0xcd, 0x1a, 0x3b, 0x4e, 0x06, 0x72, 0x07, 0x77, 0x07, 0x3b, 0x56, 0x04, - 0x77, 0x02, 0xf8, 0xc3, 0xf9, 0xc3, 0xe8, 0x37, 0x00, 0xb4, 0x00, 0xcd, 0x16, 0x80, 0xfc, 0x50, - 0x74, 0x0d, 0x80, 0xfc, 0x48, 0x74, 0x19, 0x80, 0xfc, 0x1c, 0x75, 0xed, 0xe9, 0x79, 0x00, 0x8b, - 0x46, 0x00, 0x40, 0x3b, 0x06, 0x15, 0x04, 0x75, 0x02, 0x31, 0xc0, 0x89, 0x46, 0x00, 0xeb, 0xd6, - 0x8b, 0x46, 0x00, 0x09, 0xc0, 0x75, 0x03, 0xa1, 0x15, 0x04, 0x48, 0x89, 0x46, 0x00, 0xeb, 0xc6, - 0x8a, 0x46, 0x02, 0x88, 0x46, 0x09, 0xbe, 0x1b, 0x04, 0x31, 0xc9, 0xac, 0x04, 0x03, 0xd0, 0xe8, - 0xb2, 0x28, 0x28, 0xc2, 0x88, 0x56, 0x08, 0xb0, 0x10, 0xe8, 0x30, 0x00, 0xfe, 0x46, 0x08, 0x89, - 0xcf, 0x81, 0xe7, 0x03, 0x00, 0x8a, 0x9d, 0xda, 0x03, 0x3b, 0x4e, 0x00, 0x75, 0x03, 0x80, 0xf3, - 0x08, 0xe8, 0xb6, 0x00, 0x81, 0xc6, 0x09, 0x00, 0x80, 0x46, 0x08, 0x01, 0xb0, 0x11, 0xe8, 0x0b, - 0x00, 0xfe, 0x46, 0x09, 0x41, 0x3b, 0x0e, 0x15, 0x04, 0x75, 0xc0, 0xc3, 0x3b, 0x4e, 0x00, 0x74, - 0x02, 0xb0, 0x20, 0xb3, 0x0f, 0xe9, 0xb6, 0x00, 0xe8, 0x96, 0xfd, 0xe8, 0x83, 0x00, 0xac, 0x88, - 0xc2, 0xbf, 0xd2, 0x03, 0xb9, 0x04, 0x00, 0xad, 0xab, 0xe2, 0xfc, 0xb4, 0x42, 0xbe, 0xca, 0x03, - 0xcd, 0x13, 0xbe, 0xde, 0x03, 0x72, 0x40, 0xa1, 0xfe, 0x01, 0x3d, 0x55, 0xaa, 0xbe, 0xf4, 0x03, - 0x75, 0x35, 0xb4, 0x06, 0x30, 0xc0, 0xb7, 0x0f, 0x31, 0xc9, 0xba, 0x4f, 0x18, 0xcd, 0x10, 0xc7, - 0x46, 0x08, 0x00, 0x00, 0xbe, 0x0d, 0x04, 0xb3, 0x07, 0xe8, 0x4e, 0x00, 0xfe, 0x46, 0x08, 0xe8, - 0x29, 0x00, 0x46, 0xe8, 0x44, 0x00, 0xba, 0x00, 0x01, 0x30, 0xff, 0xb4, 0x02, 0xcd, 0x10, 0xe8, - 0x2f, 0x00, 0x8a, 0x14, 0xe9, 0xa9, 0xfc, 0xba, 0x1a, 0x15, 0x89, 0x56, 0x08, 0xbb, 0x0f, 0x00, - 0xe8, 0x27, 0x00, 0xb4, 0x00, 0xcd, 0x16, 0xb2, 0x80, 0xcd, 0x19, 0xbe, 0x1b, 0x04, 0x8b, 0x4e, - 0x00, 0x41, 0x30, 0xe4, 0xe9, 0x07, 0x00, 0xac, 0x01, 0xc6, 0x81, 0xc6, 0x09, 0x00, 0xe2, 0xf7, - 0xc3, 0xe8, 0xe7, 0xff, 0xac, 0x30, 0xe4, 0x01, 0xc6, 0xc3, 0x50, 0x53, 0x51, 0x52, 0x30, 0xff, - 0xe9, 0x11, 0x00, 0x8b, 0x56, 0x08, 0xb4, 0x02, 0xcd, 0x10, 0xfe, 0x46, 0x08, 0xb9, 0x01, 0x00, - 0xb4, 0x09, 0xcd, 0x10, 0xac, 0x3c, 0x00, 0x75, 0xea, 0x5a, 0x59, 0x5b, 0x58, 0xc3, 0x50, 0x53, - 0x51, 0x52, 0x30, 0xff, 0x8b, 0x56, 0x08, 0xb4, 0x02, 0xcd, 0x10, 0xfe, 0x46, 0x08, 0xb9, 0x01, - 0x00, 0xb4, 0x09, 0xcd, 0x10, 0x5a, 0x59, 0x5b, 0x58, 0xc3, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, - 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x02, 0x03, 0x45, 0x72, - 0x72, 0x6f, 0x72, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x65, 0x63, 0x74, - 0x6f, 0x72, 0x73, 0x00, 0x4e, 0x6f, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, - 0x6c, 0x65, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x4c, 0x6f, 0x61, - 0x64, 0x69, 0x6e, 0x67, 0x00 -}; diff --git a/src/apps/bootmanager/BootManagerController.cpp b/src/apps/bootmanager/BootManagerController.cpp index 412b0b834d..75375cdeff 100644 --- a/src/apps/bootmanager/BootManagerController.cpp +++ b/src/apps/bootmanager/BootManagerController.cpp @@ -3,6 +3,7 @@ * Distributed under the terms of the MIT License. * * Authors: + * Axel Dörfler, axeld@pinc-software.de * Michael Pfeiffer */ @@ -18,6 +19,7 @@ #include #include +#include "BootDrive.h" #include "DefaultPartitionPage.h" #include "DescriptionPage.h" #include "DrivesPage.h" @@ -39,11 +41,12 @@ BootManagerController::BootManagerController() + : + fBootDrive(NULL), + fBootMenu(NULL) { #if USE_TEST_BOOT_DRIVE fBootMenu = new TestBootDrive(); -#else - fBootMenu = new LegacyBootMenu(); #endif // set defaults @@ -65,7 +68,8 @@ BootManagerController::BootManagerController() fSettings.AddString("file", ""); } - fReadPartitionsStatus = fBootMenu->ReadPartitions(&fSettings); + // That's the only boot menu we support at the moment. + fBootMenus.AddItem(new LegacyBootMenu()); } @@ -80,8 +84,8 @@ BootManagerController::Previous(WizardView* wizard) if (CurrentState() != kStateEntry) WizardController::Previous(wizard); else { - WizardController::Next(wizard); fSettings.ReplaceBool("install", false); + WizardController::Next(wizard); } } @@ -89,9 +93,7 @@ BootManagerController::Previous(WizardView* wizard) int32 BootManagerController::InitialState() { - if (fReadPartitionsStatus == B_OK) - return kStateEntry; - return kStateErrorEntry; + return kStateEntry; } @@ -101,11 +103,29 @@ BootManagerController::NextState(int32 state) switch (state) { case kStateEntry: { - if (fSettings.FindBool("install")) { - if (fBootMenu->IsBootMenuInstalled(&fSettings)) - return kStatePartitions; + const char* path; + if (fSettings.FindString("disk", &path) != B_OK) + return kStateErrorEntry; - return kStateSaveMBR; + delete fBootDrive; + + fBootDrive = new BootDrive(path); + fBootMenu = fBootDrive->InstalledMenu(fBootMenus); + + if (fSettings.FindBool("install")) { + int32 nextState = fBootMenu != NULL + ? kStatePartitions : kStateSaveMBR; + + // TODO: call BootDrive::AddSupportedMenus() once we support + // more than one type of boot menu - we'll probably need a + // requester to choose from them then as well. + if (fBootMenu == NULL) + fBootMenu = fBootMenus.ItemAt(0); + + fCollectPartitionsStatus = fBootMenu->CollectPartitions( + *fBootDrive, fSettings); + + return nextState; } return kStateUninstall; @@ -186,7 +206,7 @@ BootManagerController::_WriteBootMenu() if (alert->Go() == 1) return false; - fWriteBootMenuStatus = fBootMenu->WriteBootMenu(&fSettings); + fWriteBootMenuStatus = fBootMenu->Install(*fBootDrive, fSettings); return true; } @@ -238,7 +258,8 @@ BootManagerController::CreatePage(int32 state, WizardView* wizard) switch (state) { case kStateEntry: - page = new DrivesPage(wizard, &fSettings, "drives"); + fSettings.ReplaceBool("install", true); + page = new DrivesPage(wizard, fBootMenus, &fSettings, "drives"); break; case kStateErrorEntry: page = _CreateErrorEntryPage(); @@ -286,7 +307,7 @@ BootManagerController::_CreateErrorEntryPage() { BString description; - if (fReadPartitionsStatus == B_PARTITION_TOO_SMALL) { + if (fCollectPartitionsStatus == B_PARTITION_TOO_SMALL) { description << B_TRANSLATE_COMMENT("Partition table not compatible", "Title") << "\n\n" << B_TRANSLATE("The partition table of the first hard disk is not " diff --git a/src/apps/bootmanager/BootManagerController.h b/src/apps/bootmanager/BootManagerController.h index a7fcb4f1a5..876b41bf96 100644 --- a/src/apps/bootmanager/BootManagerController.h +++ b/src/apps/bootmanager/BootManagerController.h @@ -13,9 +13,10 @@ #include +#include "BootMenu.h" + class BootDrive; -class BootMenu; class WizardView; class WizardPageView; @@ -72,9 +73,11 @@ private: WizardPageView* _CreateUninstalledPage(); BMessage fSettings; + BootMenuList fBootMenus; + BootDrive* fBootDrive; BootMenu* fBootMenu; - status_t fReadPartitionsStatus; + status_t fCollectPartitionsStatus; status_t fWriteBootMenuStatus; status_t fSaveMBRStatus; status_t fRestoreMBRStatus; diff --git a/src/apps/bootmanager/BootMenu.h b/src/apps/bootmanager/BootMenu.h index 23e32fd47d..89191c78d9 100644 --- a/src/apps/bootmanager/BootMenu.h +++ b/src/apps/bootmanager/BootMenu.h @@ -11,12 +11,14 @@ #include #include +#include + + +class BootDrive; /* Setting BMessage Format: - "disk" String (path to boot disk) - "partition" array of BMessage: "show" bool (flag if entry should be added to boot menu) "name" String (the name as shown in boot menu) @@ -31,9 +33,14 @@ public: BootMenu() {} virtual ~BootMenu() {} - virtual bool IsBootMenuInstalled(BMessage* settings) = 0; - virtual status_t ReadPartitions(BMessage* settings) = 0; - virtual status_t WriteBootMenu(BMessage* settings) = 0; + virtual bool IsInstalled(const BootDrive& drive) = 0; + virtual status_t CanBeInstalled(const BootDrive& drive) = 0; + + virtual status_t CollectPartitions(const BootDrive& drive, + BMessage& settings) = 0; + + virtual status_t Install(const BootDrive& drive, + BMessage& settings) = 0; virtual status_t SaveMasterBootRecord(BMessage* settings, BFile* file) = 0; virtual status_t RestoreMasterBootRecord(BMessage* settings, @@ -45,5 +52,7 @@ public: BString& displayText) = 0; }; +typedef BObjectList BootMenuList; + #endif // BOOT_MENU_H diff --git a/src/apps/bootmanager/DrivesPage.cpp b/src/apps/bootmanager/DrivesPage.cpp index 004161d7ca..00cd2f448d 100644 --- a/src/apps/bootmanager/DrivesPage.cpp +++ b/src/apps/bootmanager/DrivesPage.cpp @@ -31,7 +31,8 @@ const uint32 kMsgSelectionChanged = 'slch'; class DriveItem : public BListItem { public: - DriveItem(const BDiskDevice& device); + DriveItem(const BDiskDevice& device, + const BootMenuList& menus); virtual ~DriveItem(); bool IsInstalled() const; @@ -39,7 +40,6 @@ public: bool IsBootDrive() const; const char* Path() const { return fPath.Path(); } - BMessage& Settings() { return fSettings; } BootDrive* Drive() { return fDrive; } protected: @@ -48,7 +48,6 @@ protected: virtual void Update(BView* owner, const BFont* font); private: - BMessage fSettings; BootDrive* fDrive; BString fName; BPath fPath; @@ -56,21 +55,28 @@ private: float fBaselineOffset; float fSecondBaselineOffset; float fSizeWidth; + status_t fCanBeInstalled; + bool fIsInstalled; }; -DriveItem::DriveItem(const BDiskDevice& device) +DriveItem::DriveItem(const BDiskDevice& device, const BootMenuList& menus) : fBaselineOffset(0), fSizeWidth(0) { - // TODO: retrieve disk name! + device.GetPath(&fPath); if (device.Name() != NULL && device.Name()[0]) fName = device.Name(); + else if (strstr(fPath.Path(), "usb") != NULL) + fName = B_TRANSLATE_COMMENT("USB Drive", "Default disk name"); else fName = B_TRANSLATE_COMMENT("Hard Drive", "Default disk name"); - device.GetPath(&fPath); + fDrive = new BootDrive(fPath.Path()); + + fIsInstalled = fDrive->InstalledMenu(menus) != NULL; + fCanBeInstalled = fDrive->CanMenuBeInstalled(menus); char buffer[256]; fSize = string_for_size(device.Size(), buffer, sizeof(buffer)); @@ -85,21 +91,21 @@ DriveItem::~DriveItem() bool DriveItem::IsInstalled() const { - return true; + return fIsInstalled; } bool DriveItem::CanBeInstalled() const { - return true; + return fCanBeInstalled == B_OK; } bool DriveItem::IsBootDrive() const { - return true; + return fDrive->IsBootDrive(); } @@ -142,6 +148,14 @@ DriveItem::DrawItem(BView* owner, BRect frame, bool complete) owner->MovePenTo(frame.left + 4, frame.top + fBaselineOffset); owner->DrawString(fName.String()); + if (fCanBeInstalled != B_OK) { + owner->SetHighColor(140, 0, 0); + owner->MovePenBy(fBaselineOffset, 0); + owner->DrawString(fCanBeInstalled == B_PARTITION_TOO_SMALL + ? B_TRANSLATE_COMMENT("No space available!", "Cannot install") + : B_TRANSLATE_COMMENT("Cannot access!", "Cannot install")); + } + owner->PopState(); } @@ -177,8 +191,8 @@ DriveItem::Update(BView* owner, const BFont* font) // #pragma mark - -DrivesPage::DrivesPage(WizardView* wizardView, BMessage* settings, - const char* name) +DrivesPage::DrivesPage(WizardView* wizardView, const BootMenuList& menus, + BMessage* settings, const char* name) : WizardPageView(settings, name), fWizardView(wizardView) @@ -193,7 +207,7 @@ DrivesPage::DrivesPage(WizardView* wizardView, BMessage* settings, fDrivesView = new BListView("drives"); fDrivesView->SetSelectionMessage(new BMessage(kMsgSelectionChanged)); - bool any = _FillDrivesView(); + bool any = _FillDrivesView(menus); BScrollView* scrollView = new BScrollView("scrollView", fDrivesView, 0, false, true); @@ -208,6 +222,8 @@ DrivesPage::DrivesPage(WizardView* wizardView, BMessage* settings, fWizardView->SetPreviousButtonLabel( B_TRANSLATE_COMMENT("Uninstall", "Button")); fWizardView->SetPreviousButtonHidden(false); + fWizardView->SetPreviousButtonEnabled(false); + fWizardView->SetPreviousButtonEnabled(false); } else { fWizardView->SetPreviousButtonHidden(true); fWizardView->SetNextButtonLabel( @@ -228,8 +244,6 @@ DrivesPage::PageCompleted() if (fSettings->ReplaceString("disk", item->Path()) != B_OK) fSettings->AddString("disk", item->Path()); - - fSettings->ReplaceBool("install", true); } @@ -262,7 +276,7 @@ DrivesPage::MessageReceived(BMessage* message) selects the boot drive. */ bool -DrivesPage::_FillDrivesView() +DrivesPage::_FillDrivesView(const BootMenuList& menus) { bool any = false; @@ -270,7 +284,7 @@ DrivesPage::_FillDrivesView() BDiskDevice device; while (roster.GetNextDevice(&device) == B_OK) { if (device.HasMedia() && !device.IsReadOnly()) { - DriveItem* item = new DriveItem(device); + DriveItem* item = new DriveItem(device, menus); if (item->CanBeInstalled()) any = true; fDrivesView->AddItem(item); diff --git a/src/apps/bootmanager/DrivesPage.h b/src/apps/bootmanager/DrivesPage.h index 5681eac3ce..058536ef4d 100644 --- a/src/apps/bootmanager/DrivesPage.h +++ b/src/apps/bootmanager/DrivesPage.h @@ -6,6 +6,7 @@ #define DRIVES_PAGE_H +#include "BootMenu.h" #include "WizardPageView.h" @@ -19,6 +20,7 @@ class WizardView; class DrivesPage : public WizardPageView { public: DrivesPage(WizardView* wizardView, + const BootMenuList& menus, BMessage* settings, const char* name); virtual ~DrivesPage(); @@ -29,7 +31,7 @@ protected: void MessageReceived(BMessage* message); private: - bool _FillDrivesView(); + bool _FillDrivesView(const BootMenuList& menus); DriveItem* _SelectedDriveItem(); void _UpdateWizardButtons(DriveItem* item); diff --git a/src/apps/bootmanager/Jamfile b/src/apps/bootmanager/Jamfile index 1fc05465e1..320f7d091b 100644 --- a/src/apps/bootmanager/Jamfile +++ b/src/apps/bootmanager/Jamfile @@ -3,6 +3,7 @@ SubDir HAIKU_TOP src apps bootmanager ; UsePrivateHeaders shared storage tracker ; local cataloguedSources = + BootDrive.cpp BootManager.cpp BootManagerController.cpp BootManagerWindow.cpp @@ -18,21 +19,29 @@ local cataloguedSources = Application BootManager : $(cataloguedSources) DescriptionPage.cpp -# TestBootDrive.cpp WizardController.cpp WizardPageView.cpp - : - be - textencoding - tracker - $(HAIKU_LOCALE_LIBS) - $(TARGET_LIBSUPC++) - : - BootManager.rdef + + : be textencoding tracker $(HAIKU_LOCALE_LIBS) $(TARGET_LIBSUPC++) + : BootManager.rdef ; -DoCatalogs BootManager : - x-vnd.Haiku-BootManager - : - $(cataloguedSources) -; +DoCatalogs BootManager : x-vnd.Haiku-BootManager : $(cataloguedSources) ; + +# Assemble the boot loader, and convert it into a header file + +rule AssembleYasmBin object : source +{ + SEARCH on $(source) = $(SUBDIR) ; + Depends $(object) : $(source) ; +} + +actions AssembleYasmBin +{ + $(HAIKU_YASM) -f bin -o $(1) $(2) +} + +AssembleYasmBin [ FGristFiles bootman.bin ] : bootman.S ; + +DataFileToSourceFile [ FGristFiles BootLoader.h ] : [ FGristFiles bootman.bin ] + : kBootLoader : kBootLoaderSize ; diff --git a/src/apps/bootmanager/LegacyBootMenu.cpp b/src/apps/bootmanager/LegacyBootMenu.cpp index 981361da29..35754c2051 100644 --- a/src/apps/bootmanager/LegacyBootMenu.cpp +++ b/src/apps/bootmanager/LegacyBootMenu.cpp @@ -3,6 +3,7 @@ * Distributed under the terms of the MIT License. * * Authors: + * Axel Dörfler, axeld@pinc-software.de * Michael Pfeiffer */ @@ -10,6 +11,8 @@ #include "LegacyBootMenu.h" #include + +#include #include #include @@ -17,19 +20,19 @@ #include #include #include +#include #include #include #include #include #include +#include "BootDrive.h" #include "BootLoader.h" #undef B_TRANSLATE_CONTEXT #define B_TRANSLATE_CONTEXT "LegacyBootMenu" -#define USE_SECOND_DISK 0 -#define GET_FIRST_BIOS_DRIVE 1 struct MasterBootRecord { @@ -53,10 +56,9 @@ public: }; -class PartitionRecorder : public BDiskDeviceVisitor { +class PartitionVisitor : public BDiskDeviceVisitor { public: - PartitionRecorder(BMessage* settings, - int8 drive); + PartitionVisitor(); virtual bool Visit(BDiskDevice* device); virtual bool Visit(BPartition* partition, int32 level); @@ -65,13 +67,25 @@ public: off_t FirstOffset() const; private: - bool _Record(BPartition* partition); + off_t fFirstOffset; +}; + + +class PartitionRecorder : public BDiskDeviceVisitor { +public: + PartitionRecorder(BMessage& settings, + int8 biosDrive); + + virtual bool Visit(BDiskDevice* device); + virtual bool Visit(BPartition* partition, int32 level); + + bool FoundPartitions() const; private: - BMessage* fSettings; - int8 fDrive; - int32 fIndex; - off_t fFirstOffset; + BMessage& fSettings; + int32 fUnnamedIndex; + int8 fBIOSDrive; + bool fFound; }; @@ -149,12 +163,53 @@ LittleEndianMallocIO::Fill(int16 size, int8 fillByte) // #pragma mark - -PartitionRecorder::PartitionRecorder(BMessage* settings, int8 drive) +PartitionVisitor::PartitionVisitor() + : + fFirstOffset(LONGLONG_MAX) +{ +} + + +bool +PartitionVisitor::Visit(BDiskDevice* device) +{ + return false; +} + + +bool +PartitionVisitor::Visit(BPartition* partition, int32 level) +{ + if (partition->Offset() < fFirstOffset) + fFirstOffset = partition->Offset(); + + return false; +} + + +bool +PartitionVisitor::HasPartitions() const +{ + return fFirstOffset != LONGLONG_MAX; +} + + +off_t +PartitionVisitor::FirstOffset() const +{ + return fFirstOffset; +} + + +// #pragma mark - + + +PartitionRecorder::PartitionRecorder(BMessage& settings, int8 biosDrive) : fSettings(settings), - fDrive(drive), - fIndex(0), - fFirstOffset(LONGLONG_MAX) + fUnnamedIndex(0), + fBIOSDrive(biosDrive), + fFound(false) { } @@ -168,27 +223,6 @@ PartitionRecorder::Visit(BDiskDevice* device) bool PartitionRecorder::Visit(BPartition* partition, int32 level) -{ - return _Record(partition); -} - - -bool -PartitionRecorder::HasPartitions() const -{ - return fFirstOffset != LONGLONG_MAX; -} - - -off_t -PartitionRecorder::FirstOffset() const -{ - return fFirstOffset; -} - - -bool -PartitionRecorder::_Record(BPartition* partition) { if (partition->ContainsPartitioningSystem()) return false; @@ -199,9 +233,8 @@ PartitionRecorder::_Record(BPartition* partition) BString buffer; const char* name = partition->ContentName(); if (name == NULL) { - fIndex ++; BString number; - number << fIndex; + number << ++fUnnamedIndex; buffer << B_TRANSLATE_COMMENT("Unnamed %d", "Default name of a partition whose name could not be read from " "disk; characters in codepage 437 are allowed only"); @@ -220,21 +253,25 @@ PartitionRecorder::_Record(BPartition* partition) message.AddString("name", name); message.AddString("type", type); message.AddString("path", partitionPath.Path()); - message.AddInt8("drive", fDrive); + if (fBIOSDrive != 0) + message.AddInt8("drive", fBIOSDrive); message.AddInt64("size", partition->Size()); - // Specific data - off_t offset = partition->Offset(); - message.AddInt64("offset", offset); + message.AddInt64("offset", partition->Offset()); - fSettings->AddMessage("partition", &message); - - if (offset < fFirstOffset) - fFirstOffset = offset; + fSettings.AddMessage("partition", &message); + fFound = true; return false; } +bool +PartitionRecorder::FoundPartitions() const +{ + return fFound; +} + + // #pragma mark - @@ -249,67 +286,78 @@ LegacyBootMenu::~LegacyBootMenu() bool -LegacyBootMenu::IsBootMenuInstalled(BMessage* settings) +LegacyBootMenu::IsInstalled(const BootDrive& drive) { - // TODO detect bootman + // TODO: detect bootman return false; } status_t -LegacyBootMenu::ReadPartitions(BMessage *settings) +LegacyBootMenu::CanBeInstalled(const BootDrive& drive) +{ + BDiskDevice device; + status_t status = drive.GetDiskDevice(device); + if (status != B_OK) + return status; + + PartitionVisitor visitor; + device.VisitEachDescendant(&visitor); + + // Enough space to write boot menu to drive? + if (!visitor.HasPartitions() || visitor.FirstOffset() < sizeof(kBootLoader)) + return B_PARTITION_TOO_SMALL; + + return B_OK; +} + + +status_t +LegacyBootMenu::CollectPartitions(const BootDrive& drive, BMessage& settings) { status_t status = B_ERROR; + // Remove previous partitions, if any + settings.RemoveName("partition"); + BDiskDeviceRoster diskDeviceRoster; BDiskDevice device; - bool diskFound = false; + bool partitionsFound = false; + while (diskDeviceRoster.GetNextDevice(&device) == B_OK) { BPath path; status_t status = device.GetPath(&path); if (status != B_OK) continue; - // skip not from BIOS bootable drives - int8 drive; - if (!_GetBiosDrive(path.Path(), &drive)) + // Skip not from BIOS bootable drives that are not the target disk + int8 biosDrive = 0; + if (path != drive.Path() + && _GetBIOSDrive(path.Path(), biosDrive) != B_OK) continue; - PartitionRecorder recorder(settings, drive); + PartitionRecorder recorder(settings, biosDrive); device.VisitEachDescendant(&recorder); - if (!diskFound) { - settings->AddString("disk", path.Path()); - diskFound = true; - - // Enough space to write boot menu to drive? - // (ignored in test build) - off_t size = sizeof(kBootLoader); - if (!recorder.HasPartitions() || recorder.FirstOffset() < size) - status = B_PARTITION_TOO_SMALL; - } + partitionsFound |= recorder.FoundPartitions(); } - return diskFound ? B_OK : status; + return partitionsFound ? B_OK : status; } status_t -LegacyBootMenu::WriteBootMenu(BMessage *settings) +LegacyBootMenu::Install(const BootDrive& drive, BMessage& settings) { - BString path; - if (settings->FindString("disk", &path) != B_OK) - return B_BAD_VALUE; - int32 defaultPartitionIndex; - if (settings->FindInt32("defaultPartition", &defaultPartitionIndex) != B_OK) + if (settings.FindInt32("defaultPartition", &defaultPartitionIndex) != B_OK) return B_BAD_VALUE; int32 timeout; - if (settings->FindInt32("timeout", &timeout) != B_OK) + if (settings.FindInt32("timeout", &timeout) != B_OK) return B_BAD_VALUE; - int fd = open(path.String(), O_RDWR); + int fd = open(drive.Path(), O_RDWR); if (fd < 0) return B_IO_ERROR; @@ -338,7 +386,7 @@ LegacyBootMenu::WriteBootMenu(BMessage *settings) int defaultMenuEntry = 0; BMessage partition; int32 index; - for (index = 0; settings->FindMessage("partition", index, + for (index = 0; settings.FindMessage("partition", index, &partition) == B_OK; index ++) { bool show; partition.FindBool("show", &show); @@ -353,7 +401,7 @@ LegacyBootMenu::WriteBootMenu(BMessage *settings) newBootLoader.WriteInt16(defaultMenuEntry); newBootLoader.WriteInt16(timeout); - for (index = 0; settings->FindMessage("partition", index, + for (index = 0; settings.FindMessage("partition", index, &partition) == B_OK; index ++) { bool show; BString name; @@ -537,20 +585,16 @@ LegacyBootMenu::_ConvertToBIOSText(const char* text, BString& biosText) } -bool -LegacyBootMenu::_GetBiosDrive(const char* device, int8* drive) +status_t +LegacyBootMenu::_GetBIOSDrive(const char* device, int8& drive) { - #if !GET_FIRST_BIOS_DRIVE - int fd = open(device, O_RDONLY); - if (fd < 0) - return false; - bool isBootableDrive = ioctl(fd, B_GET_BIOS_DRIVE_ID, drive, 1) == B_OK; - close(fd); - return isBootableDrive; - #else - *drive = 0x80; - return true; - #endif + int fd = open(device, O_RDONLY); + if (fd < 0) + return errno; + + status_t status = ioctl(fd, B_GET_BIOS_DRIVE_ID, drive, 1); + close(fd); + return status; } diff --git a/src/apps/bootmanager/LegacyBootMenu.h b/src/apps/bootmanager/LegacyBootMenu.h index e6f9b6399a..9e7573c7ca 100644 --- a/src/apps/bootmanager/LegacyBootMenu.h +++ b/src/apps/bootmanager/LegacyBootMenu.h @@ -3,6 +3,7 @@ * Distributed under the terms of the MIT License. * * Authors: + * Axel Dörfler, axeld@pinc-software.de * Michael Pfeiffer */ #ifndef LEGACY_BOOT_MENU_H @@ -22,9 +23,14 @@ public: LegacyBootMenu(); virtual ~LegacyBootMenu(); - virtual bool IsBootMenuInstalled(BMessage* settings); - virtual status_t ReadPartitions(BMessage* settings); - virtual status_t WriteBootMenu(BMessage* settings); + virtual bool IsInstalled(const BootDrive& drive); + virtual status_t CanBeInstalled(const BootDrive& drive); + + virtual status_t CollectPartitions(const BootDrive& drive, + BMessage& settings); + + virtual status_t Install(const BootDrive& drive, + BMessage& settings); virtual status_t SaveMasterBootRecord(BMessage* settings, BFile* file); virtual status_t RestoreMasterBootRecord(BMessage* settings, @@ -35,7 +41,8 @@ public: private: bool _ConvertToBIOSText(const char* text, BString& biosText); - bool _GetBiosDrive(const char* device, int8* drive); + status_t _GetBIOSDrive(const char* device, + int8& drive); status_t _ReadBlocks(int fd, uint8* buffer, size_t size); status_t _WriteBlocks(int fd, const uint8* buffer, size_t size); diff --git a/src/apps/bootmanager/MakeArray.cpp b/src/apps/bootmanager/MakeArray.cpp deleted file mode 100644 index c7014dfd49..0000000000 --- a/src/apps/bootmanager/MakeArray.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include -#include - - -int -main(int argc, char* argv[]) -{ - const char* application = argv[0]; - if (argc != 3) { - fprintf(stderr, "Usage:\n%s ", application); - return 1; - } - const char* variableName = argv[1]; - const char* fileName = argv[2]; - - int fd = open(fileName, 0); - if (fd < 0) { - fprintf(stderr, "%s: Error opening file '%s'!\n", application, - fileName); - return 1; - } - - const int kSize = 1024; - unsigned char buffer[kSize]; - int size = read(fd, buffer, kSize); - const int COLUMNS = 16; - int column = COLUMNS - 1; - bool first = true; - printf("// THIS FILE WAS GENERATED WITH\n"); - printf("// %s %s %s\n\n", application, variableName, fileName); - printf("static const uint8 %s[] = {", variableName); - while (size > 0) { - for (int i = 0; i < size; i ++) { - if (first) - first = false; - else - printf(", "); - column ++; - if (column == COLUMNS) { - printf("\n\t"); - column = 0; - } - printf("0x%2.2x", (int)buffer[i]); - } - size = read(fd, buffer, kSize); - } - printf("\n};\n"); - - close(fd); -} diff --git a/src/apps/bootmanager/WizardView.cpp b/src/apps/bootmanager/WizardView.cpp index 2b126f9256..399a1c1498 100644 --- a/src/apps/bootmanager/WizardView.cpp +++ b/src/apps/bootmanager/WizardView.cpp @@ -64,8 +64,12 @@ WizardView::PageCompleted() if (fPage != NULL) fPage->PageCompleted(); + // Restore initial state SetNextButtonLabel(B_TRANSLATE_COMMENT("Next", "Button")); SetPreviousButtonLabel(B_TRANSLATE_COMMENT("Previous", "Button")); + SetNextButtonEnabled(true); + SetPreviousButtonEnabled(true); + SetPreviousButtonHidden(false); } diff --git a/src/apps/bootmanager/bootman.S b/src/apps/bootmanager/bootman.S index 596dcc5dc9..40594da20c 100644 --- a/src/apps/bootmanager/bootman.S +++ b/src/apps/bootmanager/bootman.S @@ -2,14 +2,9 @@ ; Copyright 2007, Dengg David, david-d@gmx.at. All rights reserved. ; Copyright 2008, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. ; Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. +; Copyright 2011, Axel Dörfler, axeld@pinc-software.de. ; Distributed under the terms of the MIT License. -; Steps to create BootLoader.h -; 1. nasm -f bin bootman.S -o bootman.bin -; 2. cc MakeArray.cpp -o make_array -lstdc++ -; 3. ./make_array kBootLoader bootman.bin > BootLoader.h -; or -; nasm -f bin bootman.S -o bootman.bin && ./make_array kBootLoader bootman.bin > BootLoader.h %assign USE_TEST_MENU 0 @@ -155,7 +150,7 @@ %define TITLE 'Haiku Boot Manager' %strlen TITLE_LENGTH TITLE %define SELECT_OS_MESSAGE 'Select an OS from the menu' -%strlen SELECT_OS_MESSAGE_LENGTH SELECT_OS_MESSAGE +%strlen SELECT_OS_MESSAGE_LENGTH SELECT_OS_MESSAGE ; 16 bit code SECTION @@ -212,13 +207,13 @@ cursorPosition equ cursorX mov dx, [bp + cursorPosition] mov ah, SET_CURSOR int BIOS_VIDEO_SERVICES - + inc byte [bp + cursorX] - + mov cx, 1 mov ah, WRITE_CHAR int BIOS_VIDEO_SERVICES -.loop_condition +.loop_condition lodsb cmp al, 0 jnz .loop @@ -254,22 +249,23 @@ endstruc %define printstr printStringStage1 stage1: - mov ax, 0x07C0 ; BOOT_BLOCK_START_ADDRESS / 16 - mov ds, ax ; Setup segment registers + mov ax, 0x07c0 ; BOOT_BLOCK_START_ADDRESS / 16 + mov ds, ax ; Setup segment registers mov es, ax mov ss, ax - - mov sp, 0xFFFF - sizeof(Locals) ; Make stack empty + + mov sp, 0xFFFF - sizeof(Locals) ; Make stack empty mov bp, sp - - cld ; String operations increment index registers - + + mov [bootDrive], dl ; Store boot drive + cld ; String operations increment index + ; registers CLEAR_SCREEN call hideCursor - mov bh, 0 ; Text output on page 0 - - ; Print title centered at row 2 + mov bh, 0 ; Text output on page 0 + + ; Print title centered at row 2 mov dx, 1 * 0x100 + (40 - TITLE_LENGTH / 2) mov [bp + cursorPosition], dx @@ -281,28 +277,28 @@ stage1: mov dx, (TEXT_ROWS-2) * 0x100 + (40 - SELECT_OS_MESSAGE_LENGTH / 2) mov [bp + cursorPosition], dx - mov bl, LIGHT_GRAY + mov bl, LIGHT_GRAY mov si, kSelectOSMessage call printstr - ; Chain load rest of boot loader - mov ah, EXTENDED_READ ; Load 3 more sectors - mov dl, 0x80 ; First HDD + ; Chain load rest of boot loader + mov ah, EXTENDED_READ ; Load 3 more sectors + mov dl, [bootDrive] mov si, nextStageDAP int BIOS_DISK_SERVICES - jc .error ; I/O error - jmp stage2 ; Continue in loaded stage 2 + jc .error ; I/O error + jmp stage2 ; Continue in loaded stage 2 -.error: +.error: call showCursor mov si, kError mov bl, RED call printstr mov ah, READ_CHAR - int BIOS_KEYBOARD_SERVICES + int BIOS_KEYBOARD_SERVICES - mov dl, 0x80 + mov dl, [bootDrive] int BIOS_REBOOT printStringStage1: @@ -312,10 +308,10 @@ hideCursor: mov ah, GET_CURSOR int BIOS_VIDEO_SERVICES mov [bp + cursorShape], cx - + mov ah, SET_CURSOR_SHAPE mov cx, 0x2000 - int BIOS_VIDEO_SERVICES + int BIOS_VIDEO_SERVICES ret showCursor: @@ -324,7 +320,7 @@ showCursor: int BIOS_VIDEO_SERVICES ret -nextStageDAP: +nextStageDAP: istruc AddressPacket at AddressPacket.packet_size, db 0x10 at AddressPacket.block_count, db 0x03 @@ -332,6 +328,9 @@ nextStageDAP: at AddressPacket.offset, dw 1 iend +bootDrive: + db 0 + kTitle: db TITLE, 0x00 kSelectOSMessage: @@ -367,21 +366,21 @@ kMBRSignature: stage2: mov ax, [defaultItem] ; Select default item mov [bp + selection], ax - + mov ax, TICKS_PER_SECOND ; Calculate timeout ticks mul word [timeout] mov bx, dx push ax - + mov ah, READ_CLOCK int BIOS_TIME_SERVICES - + pop ax ; Add current ticks add ax, dx adc bx, cx mov [bp + timeoutTicks], ax mov [bp + timeoutTicks + 2], bx - + mov al, [listItemCount] ; Calculate start row for menu shr al, 1 mov bl, TEXT_ROWS / 2 @@ -422,21 +421,21 @@ isTimeoutReached: .returnTrue: stc ret - + ; ================== Wait for a key and do something with it ================== mainLoop: call printMenu - + inputLoop: mov ah, READ_CHAR int BIOS_KEYBOARD_SERVICES ; AL = ASCII Code, AH = Scancode cmp ah, KEY_DOWN - je selectNextPartition - + je selectNextPartition + cmp ah, KEY_UP je selectPreviousPartition - + cmp ah, KEY_RETURN jne inputLoop jmp bootSelectedPartition @@ -450,26 +449,26 @@ selectNextPartition: .done: mov [bp + selection], ax jmp mainLoop - + selectPreviousPartition: mov ax, [bp + selection] or ax, ax jnz .done ; At top of list? - mov ax, [listItemCount] ; Then jump to last entry + mov ax, [listItemCount] ; Then jump to last entry .done: dec ax mov [bp + selection], ax - jmp mainLoop + jmp mainLoop ; ======================= Print the OS list ============================ printMenu: mov al, [bp + firstLine] mov [bp + cursorY], al - + mov si, list ; Start at top of list xor cx, cx ; The index of the current item - + .loop: lodsb ; String length incl. 0-terminator add al, 3 ; center menu item @@ -493,17 +492,17 @@ printMenu: .print: call printstr add si, sizeof(BootLoaderAddress) - + add byte [bp + cursorX], 1 mov al, TRIANGLE_TO_LEFT call updateMarker - + inc byte [bp + cursorY] inc cx cmp cx, [listItemCount] - jne .loop - ret + jne .loop + ret updateMarker: cmp cx, [bp + selection] @@ -520,10 +519,10 @@ bootSelectedPartition: call showCursor - call getSelectedBootLoaderAddress + call getSelectedBootLoaderAddress lodsb ; Set boot drive mov dl, al - + mov di, bootSectorDAP+AddressPacket.offset ; Copy start sector mov cx, 4 ; It is stored in a quad word .copy_start_sector @@ -541,39 +540,39 @@ bootSelectedPartition: cmp ax, MBR_SIGNATURE mov si, kNoBootablePartitionError jne printAndHalt ; Missing signature - + CLEAR_SCREEN - + ; Print "Loading " at top of screen mov word [bp + cursorPosition], 0 mov si, kLoadingMessage mov bl, LIGHT_GRAY call printstr - + inc byte [bp + cursorX] call getSelectedMenuItem inc si ; Skip string length byte call printstr - + mov dx, 0x100 xor bh, bh mov ah, SET_CURSOR int BIOS_VIDEO_SERVICES - + call getSelectedBootLoaderAddress - mov dl, [si] ; drive number in dl - + mov dl, [si] ; drive number in dl + jmp $$ ; Start loaded boot loader - + printAndHalt: mov dx, (TEXT_ROWS-4) * 0x100 + (TEXT_COLUMNS / 3) mov [bp + cursorPosition], dx - + mov bx, 0x0F ; Page number and foreground color call printstr mov ah, READ_CHAR - int BIOS_KEYBOARD_SERVICES + int BIOS_KEYBOARD_SERVICES mov dl, 0x80 int BIOS_REBOOT @@ -582,15 +581,15 @@ printAndHalt: ; Trashes: ; ax, cx getSelectedMenuItem: - mov si, list ; Search address of start sector + mov si, list ; Search address of start sector ; of the selected item. mov cx, [bp + selection] inc cx ; Number of required iterations - + xor ah, ah ; The high-byte of the string length ; see loop body jmp .entry - + .loop: lodsb ; Length of menu item name add si, ax ; Skip name to BootLoaderAddess @@ -598,13 +597,20 @@ getSelectedMenuItem: .entry: loop .loop - ret + ret getSelectedBootLoaderAddress: call getSelectedMenuItem lodsb xor ah, ah add si, ax ; Skip name + mov dl, [si] + test dl, 0 ; if drive is 0, use boot drive + jz .takeOverBootDrive + ret +.takeOverBootDrive: + mov dl, [bootDrive] + mov [si], dl ret printStringStage2: @@ -617,13 +623,13 @@ printChar: push bx push cx push dx - + xor bh, bh ; Write on page 0 mov dx, [bp + cursorPosition] mov ah, SET_CURSOR int BIOS_VIDEO_SERVICES - + inc byte [bp + cursorX] mov cx, 1 @@ -635,7 +641,7 @@ printChar: pop bx pop ax ret - + ; ================================ DATA =========================== bootSectorDAP: @@ -646,7 +652,7 @@ bootSectorDAP: iend kColorTable: - db BLUE, RED, GREEN, CYAN + db BLUE, RED, GREEN, CYAN kReadError: db 'Error loading sectors', 0x00 kNoBootablePartitionError: @@ -659,7 +665,7 @@ listItemCount: defaultItem equ listItemCount + 2 timeout equ defaultItem + 2 list equ timeout + 2 - + ; dw number of entries ; dw the default entry ; dw the timeout (-1 for none) @@ -671,9 +677,9 @@ list equ timeout + 2 %if USE_TEST_MENU dw 0x06 - + dw 2 - + dw 5 db 0x06 @@ -705,7 +711,7 @@ list equ timeout + 2 db 'OpenBSD', 0 db 0x80 dw 0xAAAA, 0, 0, 0 - + dw kStage1UnusedSpace %endif