Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

694 lines
15 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. mbr.c
  5. Abstract:
  6. This module implements the FIXMBR command.
  7. Author:
  8. Wesley Witt (wesw) 21-Oct-1998
  9. Revision History:
  10. --*/
  11. #include "cmdcons.h"
  12. #pragma hdrstop
  13. #include <bootmbr.h>
  14. //
  15. // For NEC98 boot memu code.
  16. //
  17. #include <x86mboot.h>
  18. VOID
  19. RcDetermineDisk0(
  20. VOID
  21. );
  22. BOOL
  23. RcDetermineDisk0Enum(
  24. IN PPARTITIONED_DISK Disk,
  25. IN PDISK_REGION Region,
  26. IN ULONG_PTR Context
  27. );
  28. NTSTATUS
  29. RcOpenPartition(
  30. IN PWSTR DiskDevicePath,
  31. IN ULONG PartitionNumber,
  32. OUT HANDLE *Handle,
  33. IN BOOLEAN NeedWriteAccess
  34. );
  35. NTSTATUS
  36. RcReadDiskSectors(
  37. IN HANDLE Handle,
  38. IN ULONG SectorNumber,
  39. IN ULONG SectorCount,
  40. IN ULONG BytesPerSector,
  41. IN OUT PVOID AlignedBuffer
  42. );
  43. NTSTATUS
  44. RcWriteDiskSectors(
  45. IN HANDLE Handle,
  46. IN ULONG SectorNumber,
  47. IN ULONG SectorCount,
  48. IN ULONG BytesPerSector,
  49. IN OUT PVOID AlignedBuffer
  50. );
  51. #define MBRSIZE_NEC98 0x2000
  52. #define IPL_SIGNATURE_NEC98 "IPL1"
  53. ULONG
  54. RcCmdFixMBR(
  55. IN PTOKENIZED_LINE TokenizedLine
  56. )
  57. /*++
  58. Routine Description:
  59. Top-level routine supporting the FIXMBR command in the setup diagnostic
  60. command interpreter.
  61. FIXMBR writes a new master boot record. It will ask before writing the boot
  62. record if it cannot detect a valid mbr signature.
  63. Arguments:
  64. TokenizedLine - supplies structure built by the line parser describing
  65. each string on the line as typed by the user.
  66. Return Value:
  67. None.
  68. --*/
  69. {
  70. WCHAR DeviceName[256];
  71. ULONG i;
  72. ULONG SectorCount;
  73. ULONG BytesPerSector;
  74. PUCHAR Buffer = NULL;
  75. UCHAR InfoBuffer[2048];
  76. ULONG SectorId = 0;
  77. HANDLE handle = 0;
  78. NTSTATUS rc;
  79. PON_DISK_MBR mbr;
  80. IO_STATUS_BLOCK StatusBlock;
  81. Int13HookerType Int13Hooker = NoHooker;
  82. ULONG NextSector;
  83. WCHAR Text[2];
  84. PWSTR YesNo = NULL;
  85. BOOL Confirm = TRUE;
  86. BOOL SignatureInvalid = FALSE;
  87. BOOL Int13Detected = FALSE;
  88. PREAL_DISK_MBR_NEC98 MbrNec98;
  89. //
  90. // command is only supported on X86 platforms.
  91. // Alpha or other RISC platforms don't use
  92. // mbr code
  93. //
  94. #ifndef _X86_
  95. RcMessageOut( MSG_ONLY_ON_X86 );
  96. return 1;
  97. #else
  98. if (RcCmdParseHelp( TokenizedLine, MSG_FIXMBR_HELP )) {
  99. return 1;
  100. }
  101. if (TokenizedLine->TokenCount == 2) {
  102. wcscpy( DeviceName, TokenizedLine->Tokens->Next->String );
  103. } else {
  104. RtlZeroMemory(DeviceName,sizeof(DeviceName));
  105. SpEnumerateDiskRegions( (PSPENUMERATEDISKREGIONS)RcDetermineDisk0Enum, (ULONG_PTR)DeviceName );
  106. }
  107. rc = RcOpenPartition( DeviceName, 0, &handle, TRUE );
  108. if (!NT_SUCCESS(rc)) {
  109. DEBUG_PRINTF(( "failed to open partition zero!!!!!!" ));
  110. return 1;
  111. }
  112. //
  113. // get disk geometry
  114. //
  115. rc = ZwDeviceIoControlFile(
  116. handle,
  117. NULL,
  118. NULL,
  119. NULL,
  120. &StatusBlock,
  121. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  122. NULL,
  123. 0,
  124. InfoBuffer,
  125. sizeof( InfoBuffer )
  126. );
  127. if( !NT_SUCCESS( rc ) ) {
  128. RcMessageOut( MSG_FIXMBR_READ_ERROR );
  129. goto cleanup;
  130. }
  131. //
  132. // retrieve the sector size!
  133. //
  134. BytesPerSector = ((DISK_GEOMETRY*)InfoBuffer)->BytesPerSector;
  135. //
  136. // compute the sector count
  137. //
  138. SectorCount = max( 1, (!IsNEC_98
  139. ? (sizeof( ON_DISK_MBR )/BytesPerSector)
  140. : (MBRSIZE_NEC98/BytesPerSector) ));
  141. //
  142. // allocate a buffer twice as big as necessary
  143. //
  144. Buffer = SpMemAlloc( 2 * SectorCount * BytesPerSector );
  145. //
  146. // align the buffer
  147. //
  148. if(!IsNEC_98) {
  149. mbr = ALIGN( Buffer, BytesPerSector );
  150. } else {
  151. MbrNec98 = ALIGN( Buffer, BytesPerSector );
  152. }
  153. //
  154. // take in the sectors
  155. //
  156. rc = RcReadDiskSectors(
  157. handle,
  158. SectorId,
  159. SectorCount,
  160. BytesPerSector,
  161. (!IsNEC_98 ? (PVOID)mbr : (PVOID)MbrNec98)
  162. );
  163. if (!NT_SUCCESS(rc)) {
  164. RcMessageOut( MSG_FIXMBR_READ_ERROR );
  165. goto cleanup;
  166. }
  167. if ((!IsNEC_98 && U_USHORT(mbr->AA55Signature) != MBR_SIGNATURE) ||
  168. (IsNEC_98 &&
  169. ((U_USHORT(MbrNec98->AA55Signature) != MBR_SIGNATURE) ||
  170. _strnicmp(MbrNec98->IPLSignature,IPL_SIGNATURE_NEC98,sizeof(IPL_SIGNATURE_NEC98)-1)))
  171. ) {
  172. SignatureInvalid = TRUE;
  173. RcMessageOut( MSG_FIXMBR_NO_VALID_SIGNATURE );
  174. }
  175. //
  176. // check for weird int13 hookers
  177. //
  178. // No NEC98 supports EZ Drive.
  179. //
  180. //
  181. if (!IsNEC_98) {
  182. //
  183. //
  184. // EZDrive support: if the first entry in the partition table is
  185. // type 0x55, then the actual partition table is on sector 1.
  186. //
  187. // Only for x86 because on non-x86, the firmware can't see EZDrive
  188. // partitions.
  189. //
  190. //
  191. if (mbr->PartitionTable[0].SystemId == 0x55) {
  192. Int13Hooker = HookerEZDrive;
  193. SectorId = 1;
  194. }
  195. //
  196. // Also check for on-track.
  197. //
  198. if( mbr->PartitionTable[0].SystemId == 0x54 ) {
  199. Int13Hooker = HookerOnTrackDiskManager;
  200. SectorId = 1;
  201. }
  202. //
  203. // there's a define for HookerMax but we don't appear
  204. // to check for it in setup so I don't check for it here
  205. //
  206. //
  207. // If we have an int13 hooker
  208. //
  209. if (Int13Hooker != NoHooker) {
  210. Int13Detected = TRUE;
  211. RcMessageOut( MSG_FIXMBR_INT13_HOOKER );
  212. }
  213. //
  214. // we have a valid signature AND int 13 hooker is detected
  215. //
  216. if (Int13Detected) {
  217. //
  218. // take sector 1 in, since sector 0 is the int hooker boot code
  219. //
  220. rc = RcReadDiskSectors(
  221. handle,
  222. SectorId,
  223. SectorCount,
  224. BytesPerSector,
  225. mbr
  226. );
  227. //
  228. // sector 1 should look like a valid MBR too
  229. //
  230. if (U_USHORT(mbr->AA55Signature) != MBR_SIGNATURE) {
  231. SignatureInvalid = TRUE;
  232. RcMessageOut( MSG_FIXMBR_NO_VALID_SIGNATURE );
  233. }
  234. }
  235. }
  236. RcMessageOut( MSG_FIXMBR_WARNING_BEFORE_PROCEED );
  237. if (!InBatchMode) {
  238. YesNo = SpRetreiveMessageText(ImageBase,MSG_YESNO,NULL,0);
  239. if(!YesNo) {
  240. Confirm = FALSE;
  241. }
  242. while(Confirm) {
  243. RcMessageOut( MSG_FIXMBR_ARE_YOU_SURE );
  244. if(RcLineIn(Text,2)) {
  245. if((Text[0] == YesNo[0]) || (Text[0] == YesNo[1])) {
  246. //
  247. // Wants to do it.
  248. //
  249. Confirm = FALSE;
  250. } else {
  251. if((Text[0] == YesNo[2]) || (Text[0] == YesNo[3])) {
  252. //
  253. // Doesn't want to do it.
  254. //
  255. goto cleanup;
  256. }
  257. }
  258. }
  259. }
  260. }
  261. //
  262. // now we need to slap in new boot code!
  263. // make sure the boot code starts at the start of the sector.
  264. //
  265. if(!IsNEC_98) {
  266. ASSERT(&((PON_DISK_MBR)0)->BootCode == 0);
  267. } else {
  268. ASSERT(&((PREAL_DISK_MBR_NEC98)0)->BootCode == 0);
  269. }
  270. RcMessageOut( MSG_FIXMBR_DOING_IT, DeviceName );
  271. //
  272. // clobber the existing boot code
  273. //
  274. if(!IsNEC_98) {
  275. RtlMoveMemory(mbr,x86BootCode,sizeof(mbr->BootCode));
  276. //
  277. // put a new signature in
  278. //
  279. U_USHORT(mbr->AA55Signature) = MBR_SIGNATURE;
  280. } else {
  281. //
  282. // Write MBR in 1st sector.
  283. //
  284. RtlMoveMemory(MbrNec98,x86PC98BootCode,0x200);
  285. //
  286. // Write continous MBR after 3rd sector.
  287. //
  288. RtlMoveMemory((PUCHAR)MbrNec98+0x400,x86PC98BootMenu,MBRSIZE_NEC98-0x400);
  289. }
  290. //
  291. // write out the sector
  292. //
  293. rc = RcWriteDiskSectors(
  294. handle,
  295. SectorId,
  296. SectorCount,
  297. BytesPerSector,
  298. (!IsNEC_98 ? (PVOID)mbr : (PVOID)MbrNec98)
  299. );
  300. if (!NT_SUCCESS( rc )) {
  301. DEBUG_PRINTF(( "failed writing out new MBR." ));
  302. RcMessageOut( MSG_FIXMBR_FAILED );
  303. goto cleanup;
  304. }
  305. RcMessageOut( MSG_FIXMBR_DONE );
  306. cleanup:
  307. if (handle) {
  308. NtClose(handle);
  309. }
  310. if (Buffer) {
  311. SpMemFree(Buffer);
  312. }
  313. if (YesNo) {
  314. SpMemFree(YesNo);
  315. }
  316. return 1;
  317. #endif
  318. }
  319. BOOL
  320. RcDetermineDisk0Enum(
  321. IN PPARTITIONED_DISK Disk,
  322. IN PDISK_REGION Region,
  323. IN ULONG_PTR Context
  324. )
  325. /*++
  326. Routine Description:
  327. Callback routine passed to SpEnumDiskRegions.
  328. Arguments:
  329. Region - a pointer to a disk region returned by SpEnumDiskRegions
  330. Ignore - ignored parameter
  331. Return Value:
  332. TRUE - to continue enumeration
  333. FALSE - to end enumeration
  334. --*/
  335. {
  336. WCHAR ArcName[256];
  337. PWSTR DeviceName = (PWSTR)Context;
  338. SpArcNameFromRegion(
  339. Region,
  340. ArcName,
  341. sizeof(ArcName),
  342. PartitionOrdinalCurrent,
  343. PrimaryArcPath
  344. );
  345. //
  346. // look for the one with arc path L"multi(0)disk(0)rdisk(0)"
  347. //
  348. if( wcsstr( ArcName, L"multi(0)disk(0)rdisk(0)" ) ) {
  349. *DeviceName = UNICODE_NULL;
  350. SpNtNameFromRegion(
  351. Region,
  352. DeviceName,
  353. MAX_PATH * sizeof(WCHAR),
  354. PartitionOrdinalCurrent
  355. );
  356. if (*DeviceName != UNICODE_NULL) {
  357. PWSTR PartitionKey = wcsstr(DeviceName, L"Partition");
  358. if (!PartitionKey) {
  359. PartitionKey = wcsstr(DeviceName, L"partition");
  360. }
  361. //
  362. // partition 0 represents the start of disk
  363. //
  364. if (PartitionKey) {
  365. *PartitionKey = UNICODE_NULL;
  366. wcscat(DeviceName, L"Partition0");
  367. } else {
  368. DeviceName[wcslen(DeviceName) - 1] = L'0';
  369. }
  370. }
  371. return FALSE;
  372. }
  373. return TRUE;
  374. }
  375. NTSTATUS
  376. RcReadDiskSectors(
  377. IN HANDLE Handle,
  378. IN ULONG SectorNumber,
  379. IN ULONG SectorCount,
  380. IN ULONG BytesPerSector,
  381. IN OUT PVOID AlignedBuffer
  382. )
  383. /*++
  384. Routine Description:
  385. Reads one or more disk sectors.
  386. Arguments:
  387. Handle - supplies handle to open partition object from which
  388. sectors are to be read or written. The handle must be
  389. opened for synchronous I/O.
  390. Return Value:
  391. NTSTATUS value indicating outcome of I/O operation.
  392. --*/
  393. {
  394. LARGE_INTEGER IoOffset;
  395. ULONG IoSize;
  396. IO_STATUS_BLOCK IoStatusBlock;
  397. NTSTATUS Status;
  398. //
  399. // Calculate the large integer byte offset of the first sector
  400. // and the size of the I/O.
  401. //
  402. IoOffset.QuadPart = SectorNumber * BytesPerSector;
  403. IoSize = SectorCount * BytesPerSector;
  404. //
  405. // Perform the I/O.
  406. //
  407. Status = (NTSTATUS) ZwReadFile(
  408. Handle,
  409. NULL,
  410. NULL,
  411. NULL,
  412. &IoStatusBlock,
  413. AlignedBuffer,
  414. IoSize,
  415. &IoOffset,
  416. NULL
  417. );
  418. if (!NT_SUCCESS(Status)) {
  419. KdPrint(("SETUP: Unable to read %u sectors starting at sector %u\n",SectorCount,SectorNumber));
  420. }
  421. return(Status);
  422. }
  423. NTSTATUS
  424. RcWriteDiskSectors(
  425. IN HANDLE Handle,
  426. IN ULONG SectorNumber,
  427. IN ULONG SectorCount,
  428. IN ULONG BytesPerSector,
  429. IN OUT PVOID AlignedBuffer
  430. )
  431. /*++
  432. Routine Description:
  433. Writes one or more disk sectors.
  434. Arguments:
  435. Handle - supplies handle to open partition object from which
  436. sectors are to be read or written. The handle must be
  437. opened for synchronous I/O.
  438. Return Value:
  439. NTSTATUS value indicating outcome of I/O operation.
  440. --*/
  441. {
  442. LARGE_INTEGER IoOffset;
  443. ULONG IoSize;
  444. IO_STATUS_BLOCK IoStatusBlock;
  445. NTSTATUS Status;
  446. //
  447. // Calculate the large integer byte offset of the first sector
  448. // and the size of the I/O.
  449. //
  450. IoOffset.QuadPart = SectorNumber * BytesPerSector;
  451. IoSize = SectorCount * BytesPerSector;
  452. //
  453. // Perform the I/O.
  454. //
  455. Status = (NTSTATUS) ZwWriteFile(
  456. Handle,
  457. NULL,
  458. NULL,
  459. NULL,
  460. &IoStatusBlock,
  461. AlignedBuffer,
  462. IoSize,
  463. &IoOffset,
  464. NULL
  465. );
  466. if (!NT_SUCCESS(Status)) {
  467. KdPrint(("SETUP: Unable to write %u sectors starting at sector %u\n",SectorCount,SectorNumber));
  468. }
  469. return(Status);
  470. }
  471. NTSTATUS
  472. RcOpenPartition(
  473. IN PWSTR DiskDevicePath,
  474. IN ULONG PartitionNumber,
  475. OUT HANDLE *Handle,
  476. IN BOOLEAN NeedWriteAccess
  477. )
  478. /*++
  479. Routine Description:
  480. Opens and returns a handle to the specified partition.
  481. Arguments:
  482. DiskDevicePath - the path to the device.
  483. PartitionNumber - if the path doesn't already specify the Partition then
  484. the function will open the partition specified by this number
  485. Handle - where the open handle will be returned.
  486. The handle is opened for synchronous I/O.
  487. NeedWriteAccess - true to open in R/W
  488. Return Value:
  489. NTSTATUS value indicating outcome of I/O operation.
  490. --*/
  491. {
  492. PWSTR PartitionPath;
  493. UNICODE_STRING UnicodeString;
  494. OBJECT_ATTRIBUTES Obja;
  495. NTSTATUS Status;
  496. IO_STATUS_BLOCK IoStatusBlock;
  497. //
  498. // Form the pathname of partition.
  499. //
  500. PartitionPath = SpMemAlloc((wcslen(DiskDevicePath) * sizeof(WCHAR)) + sizeof(L"\\partition000"));
  501. if(PartitionPath == NULL) {
  502. return STATUS_NO_MEMORY;
  503. }
  504. //
  505. // if partition is already specified in the string, then don't bother appending
  506. // it
  507. //
  508. if (wcsstr( DiskDevicePath, L"Partition" ) == 0) {
  509. swprintf(PartitionPath,L"%ws\\partition%u",DiskDevicePath,PartitionNumber);
  510. } else {
  511. swprintf(PartitionPath,L"%ws",DiskDevicePath);
  512. }
  513. //
  514. // Attempt to open partition0.
  515. //
  516. INIT_OBJA(&Obja,&UnicodeString,PartitionPath);
  517. Status = ZwCreateFile(
  518. Handle,
  519. FILE_GENERIC_READ | (NeedWriteAccess ? FILE_GENERIC_WRITE : 0),
  520. &Obja,
  521. &IoStatusBlock,
  522. NULL,
  523. FILE_ATTRIBUTE_NORMAL,
  524. FILE_SHARE_READ | (NeedWriteAccess ? FILE_SHARE_WRITE : 0),
  525. FILE_OPEN,
  526. FILE_SYNCHRONOUS_IO_NONALERT,
  527. NULL,
  528. 0
  529. );
  530. if (!NT_SUCCESS(Status)) {
  531. KdPrint(("CMDCONS: Unable to open %ws (%lx)\n",PartitionPath,Status));
  532. }
  533. SpMemFree(PartitionPath);
  534. return Status;
  535. }