part.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. /*++
  2. Copyright (c) 2014 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. part.c
  5. Abstract:
  6. This module implements partition support for the setup app on Minoca OS.
  7. Author:
  8. Evan Green 10-Apr-2014
  9. Environment:
  10. User
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <assert.h>
  16. #include <errno.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include "../setup.h"
  20. #include <minoca/lib/mlibc.h>
  21. //
  22. // ---------------------------------------------------------------- Definitions
  23. //
  24. //
  25. // ------------------------------------------------------ Data Type Definitions
  26. //
  27. //
  28. // ----------------------------------------------- Internal Function Prototypes
  29. //
  30. //
  31. // -------------------------------------------------------------------- Globals
  32. //
  33. UUID SetupPartitionDeviceInformationUuid = PARTITION_DEVICE_INFORMATION_UUID;
  34. //
  35. // ------------------------------------------------------------------ Functions
  36. //
  37. INT
  38. SetupOsEnumerateDevices (
  39. PSETUP_PARTITION_DESCRIPTION *DeviceArray,
  40. PULONG DeviceCount
  41. )
  42. /*++
  43. Routine Description:
  44. This routine enumerates all the disks and partitions on the system.
  45. Arguments:
  46. DeviceArray - Supplies a pointer where an array of partition structures
  47. will be returned on success.
  48. DeviceCount - Supplies a pointer where the number of elements in the
  49. partition array will be returned on success.
  50. Return Value:
  51. 0 on success.
  52. Returns an error code on failure.
  53. --*/
  54. {
  55. UINTN AllocationSize;
  56. UINTN ArrayIndex;
  57. IO_BOOT_INFORMATION BootInformation;
  58. UINTN BootInformationSize;
  59. INT CompareResult;
  60. UINTN DataSize;
  61. SETUP_DESTINATION_TYPE DestinationType;
  62. PSETUP_PARTITION_DESCRIPTION Device;
  63. PSETUP_PARTITION_DESCRIPTION Devices;
  64. ULONG ResultCount;
  65. UINTN ResultIndex;
  66. PDEVICE_INFORMATION_RESULT Results;
  67. KSTATUS Status;
  68. ArrayIndex = 0;
  69. Devices = NULL;
  70. ResultCount = 0;
  71. Results = NULL;
  72. //
  73. // Get the boot information.
  74. //
  75. BootInformationSize = sizeof(IO_BOOT_INFORMATION);
  76. Status = OsGetSetSystemInformation(SystemInformationIo,
  77. IoInformationBoot,
  78. &BootInformation,
  79. &BootInformationSize,
  80. FALSE);
  81. if (!KSUCCESS(Status)) {
  82. goto OsEnumerateDevicesEnd;
  83. }
  84. //
  85. // Enumerate all the devices that support getting partition device
  86. // information.
  87. //
  88. Status = OsLocateDeviceInformation(&SetupPartitionDeviceInformationUuid,
  89. NULL,
  90. NULL,
  91. &ResultCount);
  92. if (Status != STATUS_BUFFER_TOO_SMALL) {
  93. goto OsEnumerateDevicesEnd;
  94. }
  95. if (ResultCount == 0) {
  96. Status = STATUS_SUCCESS;
  97. goto OsEnumerateDevicesEnd;
  98. }
  99. AllocationSize = sizeof(DEVICE_INFORMATION_RESULT) * ResultCount;
  100. Results = malloc(AllocationSize);
  101. if (Results == NULL) {
  102. Status = STATUS_INSUFFICIENT_RESOURCES;
  103. goto OsEnumerateDevicesEnd;
  104. }
  105. memset(Results, 0, AllocationSize);
  106. Status = OsLocateDeviceInformation(&SetupPartitionDeviceInformationUuid,
  107. NULL,
  108. Results,
  109. &ResultCount);
  110. if (!KSUCCESS(Status)) {
  111. goto OsEnumerateDevicesEnd;
  112. }
  113. if (ResultCount == 0) {
  114. Status = STATUS_SUCCESS;
  115. goto OsEnumerateDevicesEnd;
  116. }
  117. //
  118. // Allocate the real array.
  119. //
  120. AllocationSize = sizeof(SETUP_PARTITION_DESCRIPTION) * ResultCount;
  121. Devices = malloc(AllocationSize);
  122. if (Devices == NULL) {
  123. Status = STATUS_INSUFFICIENT_RESOURCES;
  124. goto OsEnumerateDevicesEnd;
  125. }
  126. memset(Devices, 0, AllocationSize);
  127. //
  128. // Loop through the results setting up the structure elements.
  129. //
  130. for (ResultIndex = 0; ResultIndex < ResultCount; ResultIndex += 1) {
  131. Device = &(Devices[ArrayIndex]);
  132. //
  133. // Get the partition information.
  134. //
  135. DataSize = sizeof(PARTITION_DEVICE_INFORMATION);
  136. Status = OsGetSetDeviceInformation(Results[ResultIndex].DeviceId,
  137. &SetupPartitionDeviceInformationUuid,
  138. &(Device->Partition),
  139. &DataSize,
  140. FALSE);
  141. //
  142. // If that worked, create the destination structure.
  143. //
  144. if (KSUCCESS(Status)) {
  145. if ((Device->Partition.Flags & PARTITION_FLAG_RAW_DISK) != 0) {
  146. DestinationType = SetupDestinationDisk;
  147. CompareResult = memcmp(
  148. &(Device->Partition.DiskId),
  149. &(BootInformation.SystemDiskIdentifier),
  150. sizeof(BootInformation.SystemDiskIdentifier));
  151. if (CompareResult == 0) {
  152. Device->Flags |= SETUP_DEVICE_FLAG_SYSTEM;
  153. }
  154. } else {
  155. DestinationType = SetupDestinationPartition;
  156. CompareResult = memcmp(
  157. &(Device->Partition.PartitionId),
  158. &(BootInformation.SystemPartitionIdentifier),
  159. sizeof(BootInformation.SystemPartitionIdentifier));
  160. if (CompareResult == 0) {
  161. Device->Flags |= SETUP_DEVICE_FLAG_SYSTEM;
  162. }
  163. }
  164. Device->Destination = SetupCreateDestination(
  165. DestinationType,
  166. NULL,
  167. Results[ResultIndex].DeviceId);
  168. //
  169. // If that worked, advance the array index.
  170. //
  171. if (Device->Destination != NULL) {
  172. ArrayIndex += 1;
  173. }
  174. }
  175. }
  176. Status = STATUS_SUCCESS;
  177. OsEnumerateDevicesEnd:
  178. if (Results != NULL) {
  179. free(Results);
  180. }
  181. if (!KSUCCESS(Status)) {
  182. if (Devices != NULL) {
  183. SetupDestroyDeviceDescriptions(Devices, ArrayIndex);
  184. Devices = NULL;
  185. }
  186. return ClConvertKstatusToErrorNumber(Status);
  187. }
  188. *DeviceArray = Devices;
  189. *DeviceCount = ArrayIndex;
  190. return 0;
  191. }
  192. INT
  193. SetupOsGetPartitionInformation (
  194. PSETUP_DESTINATION Destination,
  195. PPARTITION_DEVICE_INFORMATION Information
  196. )
  197. /*++
  198. Routine Description:
  199. This routine returns the partition information for the given destination.
  200. Arguments:
  201. Destination - Supplies a pointer to the partition to query.
  202. Information - Supplies a pointer where the information will be returned
  203. on success.
  204. Return Value:
  205. 0 on success.
  206. Returns an error code on failure.
  207. --*/
  208. {
  209. UINTN Size;
  210. KSTATUS Status;
  211. if (Destination->Path != NULL) {
  212. return EINVAL;
  213. }
  214. Size = sizeof(PARTITION_DEVICE_INFORMATION);
  215. Status = OsGetSetDeviceInformation(Destination->DeviceId,
  216. &SetupPartitionDeviceInformationUuid,
  217. Information,
  218. &Size,
  219. FALSE);
  220. if (!KSUCCESS(Status)) {
  221. fprintf(stderr, "Failed to get partition information: %d\n", Status);
  222. return ClConvertKstatusToErrorNumber(Status);
  223. }
  224. return 0;
  225. }
  226. PVOID
  227. SetupOsOpenBootVolume (
  228. PSETUP_CONTEXT Context
  229. )
  230. /*++
  231. Routine Description:
  232. This routine opens the boot volume on the current machine.
  233. Arguments:
  234. Context - Supplies a pointer to the application context.
  235. Return Value:
  236. Returns the open handle to the boot volume on success.
  237. NULL on failure.
  238. --*/
  239. {
  240. PSETUP_PARTITION_DESCRIPTION BootPartition;
  241. PVOID BootVolume;
  242. INT Compare;
  243. ULONG Index;
  244. BOOL MultipleNonSystem;
  245. PSETUP_PARTITION_DESCRIPTION Partition;
  246. ULONG PartitionCount;
  247. PARTITION_DEVICE_INFORMATION PartitionInformation;
  248. PSETUP_PARTITION_DESCRIPTION Partitions;
  249. INT Result;
  250. PSETUP_PARTITION_DESCRIPTION SecondBest;
  251. PSETUP_PARTITION_DESCRIPTION SystemDisk;
  252. BootVolume = NULL;
  253. Partitions = NULL;
  254. Result = SetupOsEnumerateDevices(&Partitions, &PartitionCount);
  255. if (Result != 0) {
  256. fprintf(stderr, "Failed to enumerate partitions.\n");
  257. goto OsOpenBootVolumeEnd;
  258. }
  259. //
  260. // First find the system disk, or at least try to.
  261. //
  262. SystemDisk = NULL;
  263. for (Index = 0; Index < PartitionCount; Index += 1) {
  264. Partition = &(Partitions[Index]);
  265. if ((Partition->Destination->Type == SetupDestinationDisk) &&
  266. ((Partition->Flags & SETUP_DEVICE_FLAG_SYSTEM) != 0)) {
  267. SystemDisk = Partition;
  268. break;
  269. }
  270. }
  271. //
  272. // Loop across all partitions and disks looking for the EFI system
  273. // partition.
  274. //
  275. MultipleNonSystem = FALSE;
  276. BootPartition = NULL;
  277. SecondBest = NULL;
  278. for (Index = 0; Index < PartitionCount; Index += 1) {
  279. Partition = &(Partitions[Index]);
  280. if ((Partition->Destination->Type == SetupDestinationPartition) &&
  281. (((Partition->Partition.Flags & PARTITION_FLAG_BOOT) != 0) ||
  282. (Partition->Partition.PartitionType == PartitionTypeEfiSystem))) {
  283. Compare = -1;
  284. if (SystemDisk != NULL) {
  285. Compare = memcmp(Partition->Partition.DiskId,
  286. SystemDisk->Partition.DiskId,
  287. DISK_IDENTIFIER_SIZE);
  288. }
  289. //
  290. // If it is on the system disk, try to assign it directly to
  291. // the winner, and fail if it's already set.
  292. //
  293. if (Compare == 0) {
  294. if (BootPartition == NULL) {
  295. BootPartition = Partition;
  296. } else {
  297. Result = ENODEV;
  298. printf("Error: Setup found multiple boot "
  299. "partitions.\n");
  300. goto OsOpenBootVolumeEnd;
  301. }
  302. //
  303. // If it's not on the boot device, track it as the second best
  304. // and remember if there are multiple of these.
  305. //
  306. } else {
  307. if (SecondBest == NULL) {
  308. SecondBest = Partition;
  309. } else {
  310. MultipleNonSystem = TRUE;
  311. }
  312. }
  313. }
  314. }
  315. if ((BootPartition == NULL) && (SecondBest != NULL)) {
  316. if (MultipleNonSystem != FALSE) {
  317. fprintf(stderr,
  318. "Error: Found more than one boot partition on the system "
  319. "disk.\n");
  320. Result = ENODEV;
  321. goto OsOpenBootVolumeEnd;
  322. }
  323. BootPartition = SecondBest;
  324. }
  325. if (BootPartition == NULL) {
  326. fprintf(stderr, "Failed to find boot partition.\n");
  327. goto OsOpenBootVolumeEnd;
  328. }
  329. assert(Context->Disk == NULL);
  330. memset(&PartitionInformation, 0, sizeof(PartitionInformation));
  331. Context->Disk = SetupPartitionOpen(Context,
  332. BootPartition->Destination,
  333. &PartitionInformation);
  334. if (Context->Disk == NULL) {
  335. fprintf(stderr, "Failed to open boot partition.\n");
  336. goto OsOpenBootVolumeEnd;
  337. }
  338. //
  339. // If the disk identifier has not yet been set, set it now. This assumes
  340. // that if installing to a directory, the directory resides on the same
  341. // disk as the boot partition.
  342. //
  343. Compare = memcmp(PartitionInformation.DiskId,
  344. &SetupZeroDiskIdentifier,
  345. DISK_IDENTIFIER_SIZE);
  346. if (Compare == 0) {
  347. memcpy(&(Context->PartitionContext.DiskIdentifier),
  348. PartitionInformation.DiskId,
  349. DISK_IDENTIFIER_SIZE);
  350. }
  351. Context->CurrentPartitionOffset = 0;
  352. Context->CurrentPartitionSize = BootPartition->Partition.LastBlock + 1 -
  353. BootPartition->Partition.FirstBlock;
  354. //
  355. // Always open the boot volume in compatibility mode, since firmware and
  356. // others may be looking into it.
  357. //
  358. BootVolume = SetupVolumeOpen(Context,
  359. BootPartition->Destination,
  360. SetupVolumeFormatNever,
  361. TRUE);
  362. OsOpenBootVolumeEnd:
  363. if (Partitions != NULL) {
  364. SetupDestroyDeviceDescriptions(Partitions, PartitionCount);
  365. }
  366. return BootVolume;
  367. }
  368. //
  369. // --------------------------------------------------------- Internal Functions
  370. //