Source code of Windows XP (NT5)
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.

2084 lines
56 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. hiber.c
  5. Abstract:
  6. Author:
  7. Revision History:
  8. 8/7/1998 Elliot Shmukler (t-ellios) Added Hiber file compression
  9. --*/
  10. #include "bldr.h"
  11. #include "msg.h"
  12. #include "stdio.h"
  13. #include "stdlib.h"
  14. #include "xpress.h"
  15. extern UCHAR WakeDispatcherStart;
  16. extern UCHAR WakeDispatcherEnd;
  17. //
  18. //
  19. // Hiber globals
  20. //
  21. // HiberFile - File handle
  22. // HiberBuffer - PAGE of ram
  23. // HiberIoError - Set to true to indicate an IO read error occured during restore
  24. //
  25. ULONG HiberFile;
  26. PUCHAR HiberBuffer;
  27. ULONG HiberBufferPage;
  28. BOOLEAN HiberIoError;
  29. BOOLEAN HiberOutOfRemap;
  30. BOOLEAN HiberAbort;
  31. LARGE_INTEGER HiberStartTime;
  32. LARGE_INTEGER HiberEndTime;
  33. //
  34. // HiberImageFeatureFlags - Feature flags from hiber image header
  35. // HiberBreakOnWake - BreakOnWake flag from hiber image header
  36. //
  37. BOOLEAN HiberBreakOnWake;
  38. ULONG HiberImageFeatureFlags;
  39. #if defined(_ALPHA_) || defined(_IA64_)
  40. //
  41. // On Alpha, the address of the KPROCESSOR_STATE read from the hiber file
  42. // must be saved where WakeDispatch can find it (it's at a fixed offset
  43. // relative to HiberVa on x86).
  44. //
  45. PKPROCESSOR_STATE HiberWakeState;
  46. #else // x86
  47. //
  48. // HiberPtes - Virtual address of ptes to use for restoriation. There
  49. // are at least HIBER_PTES consecutive ptes for use, and are for the
  50. // address of HiberVa
  51. //
  52. // HiberVa - The virtual address the HiberPtes map
  53. //
  54. // HiberIdentityVa - The restoration images HiberVa
  55. //
  56. // HiberPageFrames - Page frames of the hiber ptes (does not include dest pte)
  57. //
  58. PVOID HiberPtes;
  59. PUCHAR HiberVa;
  60. PVOID HiberIdentityVa;
  61. ULONG HiberPageFrames[HIBER_PTES];
  62. #endif // Alpha/x86
  63. PFN_NUMBER HiberImagePageSelf;
  64. ULONG HiberNoMappings;
  65. ULONG HiberFirstRemap;
  66. ULONG HiberLastRemap;
  67. VOID
  68. BlUpdateProgressBar(
  69. ULONG fPercentage
  70. );
  71. VOID
  72. BlOutputStartupMsg(
  73. ULONG uMsgID
  74. );
  75. VOID
  76. BlOutputTrailerMsg(
  77. ULONG uMsgID
  78. );
  79. //
  80. // Defines for Hiber restore UI
  81. //
  82. ULONG HbCurrentScreen;
  83. #define BAR_X 7
  84. #define BAR_Y 10
  85. #define PERCENT_BAR_WIDTH 66
  86. #define PAUSE_X 7
  87. #define PAUSE_Y 7
  88. #define FAULT_X 7
  89. #define FAULT_Y 7
  90. UCHAR szHiberDebug[] = "debug";
  91. UCHAR szHiberFileName[] = "\\hiberfil.sys";
  92. //
  93. // HiberFile Compression Related definnes
  94. //
  95. #define PAGE_MASK (PAGE_SIZE - 1)
  96. #define PAGE_PAGES(n) (((n) + PAGE_MASK) >> PAGE_SHIFT)
  97. //
  98. // The size of the buffer for compressed data
  99. #define COMPRESSION_BUFFER_SIZE 64 << PAGE_SHIFT
  100. //
  101. #define MAX_COMPRESSION_BUFFER_EXTRA_PAGES \
  102. PAGE_PAGES (PAGE_MASK + 2*XPRESS_HEADER_SIZE)
  103. #define MAX_COMPRESSION_BUFFER_EXTRA_SIZE \
  104. (MAX_COMPRESSION_BUFFER_EXTRA_PAGES << PAGE_SHIFT)
  105. #define LZNT1_COMPRESSION_BUFFER_PAGES 16
  106. #define LZNT1_COMPRESSION_BUFFER_SIZE \
  107. (LZNT1_COMPRESSION_BUFFER_PAGES << PAGE_SHIFT)
  108. #define XPRESS_COMPRESSION_BUFFER_PAGES \
  109. PAGE_PAGES (XPRESS_MAX_SIZE + MAX_COMPRESSION_BUFFER_EXTRA_SIZE)
  110. #define XPRESS_COMPRESSION_BUFFER_SIZE \
  111. (XPRESS_COMPRESSION_BUFFER_PAGES << PAGE_SHIFT)
  112. #define MAX_COMPRESSION_BUFFER_PAGES \
  113. max (LZNT1_COMPRESSION_BUFFER_PAGES, XPRESS_COMPRESSION_BUFFER_PAGES)
  114. #define MAX_COMPRESSION_BUFFER_SIZE \
  115. (MAX_COMPRESSION_BUFFER_PAGES << PAGE_SHIFT)
  116. // Buffer to store decoded data
  117. typedef struct {
  118. PUCHAR DataPtr, PreallocatedDataBuffer;
  119. LONG DataSize;
  120. struct {
  121. struct {
  122. LONG Size;
  123. ULONG Checksum;
  124. } Compressed, Uncompressed;
  125. LONG XpressEncoded;
  126. } Header;
  127. LONG DelayedCnt; // # of delayed pages
  128. ULONG DelayedChecksum; // last checksum value
  129. ULONG DelayedBadChecksum;
  130. struct {
  131. PUCHAR DestVa; // delayed DestVa
  132. PFN_NUMBER DestPage;// delayed page number
  133. ULONG RangeCheck; // last range checksum
  134. LONG Flags; // 1 = clear checksum, 2 = compare checksum
  135. } Delayed[XPRESS_MAX_PAGES];
  136. } DECOMPRESSED_BLOCK, *PDECOMPRESSED_BLOCK;
  137. typedef struct {
  138. struct {
  139. PUCHAR Beg;
  140. PUCHAR End;
  141. } Current, Buffer, Aligned;
  142. PFN_NUMBER FilePage;
  143. BOOLEAN NeedSeek;
  144. } COMPRESSED_BUFFER, *PCOMPRESSED_BUFFER;
  145. #define HIBER_PERF_STATS 0
  146. //
  147. // Internal prototypes
  148. //
  149. #if !defined (HIBER_DEBUG)
  150. #define CHECK_ERROR(a,b) if(a) { *Information = __LINE__; return b; }
  151. #define DBGOUT(_x_)
  152. #else
  153. #define CHECK_ERROR(a,b) if(a) {HbPrintMsg(b);HbPrint(TEXT("\r\n")); *Information = __LINE__; HbPause(); return b; }
  154. #define DBGOUT(_x_) BlPrint _x_
  155. #endif
  156. ULONG
  157. HbRestoreFile (
  158. IN PULONG Information,
  159. OUT OPTIONAL PCHAR *BadLinkName
  160. );
  161. VOID
  162. HbPrint (
  163. IN _PTUCHAR str
  164. );
  165. BOOLEAN
  166. HbReadNextCompressedPageLZNT1 (
  167. PUCHAR DestVa,
  168. PCOMPRESSED_BUFFER CompressedBuffer
  169. );
  170. BOOLEAN
  171. HbReadNextCompressedChunkLZNT1 (
  172. PUCHAR DestVa,
  173. PCOMPRESSED_BUFFER CompressedBuffer
  174. );
  175. BOOLEAN
  176. HbReadNextCompressedPages (
  177. LONG BytesNeeded,
  178. PCOMPRESSED_BUFFER CompressedBuffer
  179. );
  180. BOOLEAN
  181. HbReadNextCompressedBlock (
  182. PDECOMPRESSED_BLOCK Block,
  183. PCOMPRESSED_BUFFER CompressedBuffer
  184. );
  185. BOOLEAN
  186. HbReadDelayedBlock (
  187. BOOLEAN ForceDecoding,
  188. PFN_NUMBER DestPage,
  189. ULONG RangeCheck,
  190. PDECOMPRESSED_BLOCK Block,
  191. PCOMPRESSED_BUFFER CompressedBuffer
  192. );
  193. BOOLEAN
  194. HbReadNextCompressedBlockHeader (
  195. PDECOMPRESSED_BLOCK Block,
  196. PCOMPRESSED_BUFFER CompressedBuffer
  197. );
  198. ULONG
  199. BlHiberRestore (
  200. IN ULONG DriveId,
  201. OUT PCHAR *BadLinkName
  202. );
  203. BOOLEAN
  204. HbReadNextCompressedChunk (
  205. PUCHAR DestVa,
  206. PPFN_NUMBER FilePage,
  207. PUCHAR CompressBuffer,
  208. PULONG DataOffset,
  209. PULONG BufferOffset,
  210. ULONG MaxOffset
  211. );
  212. #if defined (HIBER_DEBUG) || HIBER_PERF_STATS
  213. // HIBER_DEBUG bit mask:
  214. // 2 - general bogosity
  215. // 4 - remap trace
  216. VOID HbFlowControl(VOID)
  217. {
  218. UCHAR c;
  219. ULONG count;
  220. if (ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
  221. ArcRead(ARC_CONSOLE_INPUT, &c, 1, &count);
  222. if (c == 'S' - 0x40) {
  223. ArcRead(ARC_CONSOLE_INPUT, &c, 1, &count);
  224. }
  225. }
  226. }
  227. VOID HbPause(VOID)
  228. {
  229. UCHAR c;
  230. ULONG count;
  231. #if defined(ENABLE_LOADER_DEBUG)
  232. DbgBreakPoint();
  233. #else
  234. HbPrint(TEXT("Press any key to continue . . ."));
  235. ArcRead(ARC_CONSOLE_INPUT, &c, 1, &count);
  236. HbPrint(TEXT("\r\n"));
  237. #endif
  238. }
  239. VOID HbPrintNum(ULONG n)
  240. {
  241. TCHAR buf[9];
  242. _stprintf(buf, TEXT("%ld"), n);
  243. HbPrint(buf);
  244. HbFlowControl();
  245. }
  246. VOID HbPrintHex(ULONG n)
  247. {
  248. TCHAR buf[11];
  249. _stprintf(buf, TEXT("0x%08lX"), n);
  250. HbPrint(buf);
  251. HbFlowControl();
  252. }
  253. #define SHOWNUM(x) ((void) (HbPrint(#x TEXT(" = ")), HbPrintNum((ULONG) (x)), HbPrint(TEXT("\r\n"))))
  254. #define SHOWHEX(x) ((void) (HbPrint(#x TEXT(" = ")), HbPrintHex((ULONG) (x)), HbPrint(TEXT("\r\n"))))
  255. #endif // HIBER_DEBUG
  256. #if !defined(i386) && !defined(_ALPHA_)
  257. ULONG
  258. HbSimpleCheck (
  259. IN ULONG PartialSum,
  260. IN PVOID SourceVa,
  261. IN ULONG Length
  262. );
  263. #else
  264. // Use the TCP/IP Check Sum routine if available
  265. ULONG
  266. tcpxsum(
  267. IN ULONG cksum,
  268. IN PUCHAR buf,
  269. IN ULONG len
  270. );
  271. #define HbSimpleCheck(a,b,c) tcpxsum(a,(PUCHAR)b,c)
  272. #endif
  273. VOID
  274. HbReadPage (
  275. IN PFN_NUMBER PageNo,
  276. IN PUCHAR Buffer
  277. );
  278. VOID
  279. HbSetImageSignature (
  280. IN ULONG NewSignature
  281. );
  282. VOID
  283. HbPrint (
  284. IN _PTUCHAR str
  285. )
  286. {
  287. ULONG Junk;
  288. ArcWrite (
  289. BlConsoleOutDeviceId,
  290. str,
  291. _tcslen(str)*sizeof(TCHAR),
  292. &Junk
  293. );
  294. }
  295. VOID HbPrintChar (_TUCHAR chr)
  296. {
  297. ULONG Junk;
  298. ArcWrite(
  299. BlConsoleOutDeviceId,
  300. &chr,
  301. sizeof(_TUCHAR),
  302. &Junk
  303. );
  304. }
  305. VOID
  306. HbPrintMsg (
  307. IN ULONG MsgNo
  308. )
  309. {
  310. PTCHAR Str;
  311. Str = BlFindMessage(MsgNo);
  312. if (Str) {
  313. HbPrint (Str);
  314. }
  315. }
  316. VOID
  317. HbScreen (
  318. IN ULONG Screen
  319. )
  320. {
  321. UCHAR Buffer[100];
  322. int i, ii;
  323. #if defined(HIBER_DEBUG)
  324. HbPrint(TEXT("\r\n"));
  325. HbPause();
  326. #endif
  327. HbCurrentScreen = Screen;
  328. BlSetInverseMode (FALSE);
  329. BlPositionCursor (1, 1);
  330. BlClearToEndOfScreen();
  331. BlPositionCursor (1, 3);
  332. HbPrintMsg(Screen);
  333. }
  334. ULONG
  335. HbSelection (
  336. ULONG x,
  337. ULONG y,
  338. PULONG Sel,
  339. ULONG Debug
  340. )
  341. {
  342. ULONG CurSel, MaxSel;
  343. ULONG i;
  344. UCHAR Key;
  345. PUCHAR pDebug;
  346. for (MaxSel=0; Sel[MaxSel]; MaxSel++) ;
  347. MaxSel -= Debug;
  348. pDebug = szHiberDebug;
  349. #if DBG
  350. MaxSel += Debug;
  351. Debug = 0;
  352. #endif
  353. CurSel = 0;
  354. for (; ;) {
  355. //
  356. // Draw selections
  357. //
  358. for (i=0; i < MaxSel; i++) {
  359. BlPositionCursor (x, y+i);
  360. BlSetInverseMode ((BOOLEAN) (CurSel == i) );
  361. HbPrintMsg(Sel[i]);
  362. }
  363. //
  364. // Get a key
  365. //
  366. ArcRead(ARC_CONSOLE_INPUT, &Key, sizeof(Key), &i);
  367. if (Key == ASCI_CSI_IN) {
  368. ArcRead(ARC_CONSOLE_INPUT, &Key, sizeof(Key), &i);
  369. switch (Key) {
  370. case 'A':
  371. //
  372. // Cursor up
  373. //
  374. CurSel -= 1;
  375. if (CurSel >= MaxSel) {
  376. CurSel = MaxSel-1;
  377. }
  378. break;
  379. case 'B':
  380. //
  381. // Cursor down
  382. //
  383. CurSel += 1;
  384. if (CurSel >= MaxSel) {
  385. CurSel = 0;
  386. }
  387. break;
  388. }
  389. } else {
  390. if (Key == *pDebug) {
  391. pDebug++;
  392. if (!*pDebug) {
  393. MaxSel += Debug;
  394. Debug = 0;
  395. }
  396. } else {
  397. pDebug = szHiberDebug;
  398. }
  399. switch (Key) {
  400. case ASCII_LF:
  401. case ASCII_CR:
  402. BlSetInverseMode (FALSE);
  403. BlPositionCursor (1, 2);
  404. BlClearToEndOfScreen ();
  405. if (Sel[CurSel] == HIBER_DEBUG_BREAK_ON_WAKE) {
  406. HiberBreakOnWake = TRUE;
  407. }
  408. return CurSel;
  409. }
  410. }
  411. }
  412. }
  413. VOID
  414. HbCheckForPause (
  415. VOID
  416. )
  417. {
  418. ULONG uSel = 0;
  419. UCHAR Key;
  420. ULONG Sel[4];
  421. BOOLEAN bPaused = FALSE;
  422. //
  423. // Check for space bar
  424. //
  425. if (ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
  426. ArcRead(ARC_CONSOLE_INPUT, &Key, sizeof(Key), &uSel);
  427. switch (Key) {
  428. // space bar pressed
  429. case ' ':
  430. bPaused = TRUE;
  431. break;
  432. // user pressed F5/F8 key
  433. case ASCI_CSI_IN:
  434. ArcRead(ARC_CONSOLE_INPUT, &Key, sizeof(Key), &uSel);
  435. if(Key == 'O') {
  436. ArcRead(ARC_CONSOLE_INPUT, &Key, sizeof(Key), &uSel);
  437. bPaused = (Key == 'r' || Key == 't');
  438. }
  439. break;
  440. default:
  441. bPaused = FALSE;
  442. break;
  443. }
  444. if (bPaused) {
  445. Sel[0] = HIBER_CONTINUE;
  446. Sel[1] = HIBER_CANCEL;
  447. Sel[2] = HIBER_DEBUG_BREAK_ON_WAKE;
  448. Sel[3] = 0;
  449. HbScreen(HIBER_PAUSE);
  450. uSel = HbSelection (PAUSE_X, PAUSE_Y, Sel, 1);
  451. if (uSel == 1) {
  452. HiberIoError = TRUE;
  453. HiberAbort = TRUE;
  454. return ;
  455. } else {
  456. BlSetInverseMode(FALSE);
  457. //
  458. // restore hiber progress screen
  459. //
  460. BlOutputStartupMsg(BL_MSG_RESUMING_WINDOWS);
  461. BlOutputTrailerMsg(BL_ADVANCED_BOOT_MESSAGE);
  462. }
  463. }
  464. }
  465. }
  466. ULONG
  467. BlHiberRestore (
  468. IN ULONG DriveId,
  469. OUT PCHAR *BadLinkName
  470. )
  471. /*++
  472. Routine Description:
  473. Checks DriveId for a valid hiberfile.sys and if found start the
  474. restoration procedure
  475. --*/
  476. {
  477. extern BOOLEAN BlOutputDots;
  478. NTSTATUS Status;
  479. ULONG Msg;
  480. ULONG Information;
  481. ULONG Sel[2];
  482. BOOLEAN bDots = BlOutputDots;
  483. //
  484. // If restore was aborted once, don't bother
  485. //
  486. #if defined (HIBER_DEBUG)
  487. HbPrint(TEXT("BlHiberRestore\r\n"));
  488. #endif
  489. if (HiberAbort) {
  490. return ESUCCESS;
  491. }
  492. //
  493. // Get the hiber image. If not present, done.
  494. //
  495. Status = BlOpen (DriveId, szHiberFileName, ArcOpenReadWrite, &HiberFile);
  496. if (Status != ESUCCESS) {
  497. #if defined (HIBER_DEBUG)
  498. HbPrint(TEXT("No hiber image file.\r\n"));
  499. #endif
  500. return ESUCCESS;
  501. }
  502. //
  503. // Restore the hiber image
  504. //
  505. BlOutputDots = TRUE;
  506. //
  507. // Set the global flag to allow blmemory.c to grab from the right
  508. // part of the buffer
  509. //
  510. BlRestoring=TRUE;
  511. Msg = HbRestoreFile (&Information, BadLinkName);
  512. BlOutputDots = bDots;
  513. if (Msg) {
  514. BlSetInverseMode (FALSE);
  515. if (!HiberAbort) {
  516. HbScreen(HIBER_ERROR);
  517. HbPrintMsg(Msg);
  518. Sel[0] = HIBER_CANCEL;
  519. Sel[1] = 0;
  520. HbSelection (FAULT_X, FAULT_Y, Sel, 0);
  521. }
  522. HbSetImageSignature (0);
  523. }
  524. BlClose (HiberFile);
  525. BlRestoring=FALSE;
  526. return Msg ? EAGAIN : ESUCCESS;
  527. }
  528. #if !defined(i386) && !defined(_ALPHA_)
  529. ULONG
  530. HbSimpleCheck (
  531. IN ULONG PartialSum,
  532. IN PVOID SourceVa,
  533. IN ULONG Length
  534. )
  535. /*++
  536. Routine Description:
  537. Computes a checksum for the supplied virtual address and length
  538. This function comes from Dr. Dobbs Journal, May 1992
  539. --*/
  540. {
  541. PUSHORT Source;
  542. Source = (PUSHORT) SourceVa;
  543. Length = Length / 2;
  544. while (Length--) {
  545. PartialSum += *Source++;
  546. PartialSum = (PartialSum >> 16) + (PartialSum & 0xFFFF);
  547. }
  548. return PartialSum;
  549. }
  550. #endif // i386
  551. VOID
  552. HbReadPage (
  553. IN PFN_NUMBER PageNo,
  554. IN PUCHAR Buffer
  555. )
  556. /*++
  557. Routine Description:
  558. This function reads the specified page from the hibernation file
  559. Arguments:
  560. PageNo - Page number to read
  561. Buffer - Buffer to read the data
  562. Return Value:
  563. On success Buffer, else HbIoError set to TRUE
  564. --*/
  565. {
  566. ULONG Status;
  567. ULONG Count;
  568. LARGE_INTEGER li;
  569. li.QuadPart = PageNo << PAGE_SHIFT;
  570. Status = BlSeek (HiberFile, &li, SeekAbsolute);
  571. if (Status != ESUCCESS) {
  572. HiberIoError = TRUE;
  573. }
  574. Status = BlRead (HiberFile, Buffer, PAGE_SIZE, &Count);
  575. if (Status != ESUCCESS) {
  576. HiberIoError = TRUE;
  577. }
  578. }
  579. BOOLEAN
  580. HbReadNextCompressedPages (
  581. LONG BytesNeeded,
  582. PCOMPRESSED_BUFFER CompressedBuffer
  583. )
  584. /*++
  585. Routine Description:
  586. This routine makes sure that BytesNeeded bytes are available
  587. in CompressedBuffer and brings in more pages from Hiber file
  588. if necessary.
  589. All reads from the Hiber file occurr at the file's
  590. current offset forcing compressed pages to be read
  591. in a continuous fashion without extraneous file seeks.
  592. Arguments:
  593. BytesNeeded - Number of bytes that must be present in CompressedBuffer
  594. CompressedBuffer - Descriptor of data already brought in
  595. Return Value:
  596. TRUE if the operation is successful, FALSE otherwise.
  597. --*/
  598. {
  599. LONG BytesLeft;
  600. LONG BytesRequested;
  601. ULONG Status;
  602. LONG MaxBytes;
  603. // Obtain number of bytes left in buffer
  604. BytesLeft = (LONG) (CompressedBuffer->Current.End - CompressedBuffer->Current.Beg);
  605. // Obtain number of bytes that are needed but not available
  606. BytesNeeded -= BytesLeft;
  607. // Preserve amount of bytes caller needs (BytesNeeded may be changed later)
  608. BytesRequested = BytesNeeded;
  609. // Do we need to read more?
  610. if (BytesNeeded <= 0) {
  611. // No, do nothing
  612. return(TRUE);
  613. }
  614. // Align BytesNeeded on page boundary
  615. BytesNeeded = (BytesNeeded + PAGE_MASK) & ~PAGE_MASK;
  616. // Copy left bytes to the beginning of aligned buffer retaining page alignment
  617. if (BytesLeft == 0) {
  618. CompressedBuffer->Current.Beg = CompressedBuffer->Current.End = CompressedBuffer->Aligned.Beg;
  619. } else {
  620. LONG BytesBeforeBuffer = (LONG)(CompressedBuffer->Aligned.Beg - CompressedBuffer->Buffer.Beg) & ~PAGE_MASK;
  621. LONG BytesLeftAligned = (BytesLeft + PAGE_MASK) & ~PAGE_MASK;
  622. LONG BytesToCopy;
  623. PUCHAR Dst, Src;
  624. // Find out how many pages we may keep before aligned buffer
  625. if (BytesBeforeBuffer >= BytesLeftAligned) {
  626. BytesBeforeBuffer = BytesLeftAligned;
  627. }
  628. // Avoid misaligned data accesses during copy
  629. BytesToCopy = (BytesLeft + 63) & ~63;
  630. Dst = CompressedBuffer->Aligned.Beg + BytesLeftAligned - BytesBeforeBuffer - BytesToCopy;
  631. Src = CompressedBuffer->Current.End - BytesToCopy;
  632. if (Dst != Src) {
  633. RtlMoveMemory (Dst, Src, BytesToCopy);
  634. BytesLeftAligned = (LONG) (Dst - Src);
  635. CompressedBuffer->Current.Beg += BytesLeftAligned;
  636. CompressedBuffer->Current.End += BytesLeftAligned;
  637. }
  638. }
  639. //
  640. // Increase the number of bytes read to fill our buffer up to the next
  641. // 64K boundary.
  642. //
  643. MaxBytes = (LONG)((((ULONG_PTR)CompressedBuffer->Current.End + 0x10000) & 0xffff) - (ULONG_PTR)CompressedBuffer->Current.End);
  644. if (MaxBytes > CompressedBuffer->Buffer.End - CompressedBuffer->Current.End) {
  645. MaxBytes = (LONG)(CompressedBuffer->Buffer.End - CompressedBuffer->Current.End);
  646. }
  647. if (MaxBytes > BytesNeeded) {
  648. BytesNeeded = MaxBytes;
  649. }
  650. #if 0
  651. // for debugging only
  652. if (0x10000 - (((LONG) CompressedBuffer->Current.End) & 0xffff) < BytesNeeded) {
  653. BlPrint (("Current.Beg = %p, Current.End = %p, Current.End2 = %p\n",
  654. CompressedBuffer->Current.Beg,
  655. CompressedBuffer->Current.End,
  656. CompressedBuffer->Current.End + BytesNeeded
  657. ));
  658. }
  659. #endif
  660. // Make sure we have enough space
  661. if (BytesNeeded > CompressedBuffer->Buffer.End - CompressedBuffer->Current.End) {
  662. // Too many bytes to read -- should never happen, but just in case...
  663. DBGOUT (("Too many bytes to read -- corrupted data?\n"));
  664. return(FALSE);
  665. }
  666. // Issue seek if necessary
  667. if (CompressedBuffer->NeedSeek) {
  668. LARGE_INTEGER li;
  669. li.QuadPart = CompressedBuffer->FilePage << PAGE_SHIFT;
  670. Status = BlSeek (HiberFile, &li, SeekAbsolute);
  671. if (Status != ESUCCESS) {
  672. DBGOUT (("Seek to 0x%x error 0x%x\n", CompressedBuffer->FilePage, Status));
  673. HiberIoError = TRUE;
  674. return(FALSE);
  675. }
  676. CompressedBuffer->NeedSeek = FALSE;
  677. }
  678. // Read in stuff from the Hiber file into the available buffer space
  679. Status = BlRead (HiberFile, CompressedBuffer->Current.End, BytesNeeded, &BytesNeeded);
  680. // Check for I/O errors...
  681. if (Status != ESUCCESS || (BytesNeeded & PAGE_MASK) != 0 || BytesNeeded < BytesRequested) {
  682. // I/O Error - FAIL.
  683. DBGOUT (("Read error: Status = 0x%x, ReadBytes = 0x%x, Requested = 0x%x\n", Status, BytesNeeded, BytesRequested));
  684. HiberIoError = TRUE;
  685. return(FALSE);
  686. }
  687. // I/O was good - recalculate buffer offsets based on how much
  688. // stuff was actually read in
  689. CompressedBuffer->Current.End += BytesNeeded;
  690. CompressedBuffer->FilePage += (BytesNeeded >> PAGE_SHIFT);
  691. return(TRUE);
  692. }
  693. BOOLEAN
  694. HbReadNextCompressedBlockHeader (
  695. PDECOMPRESSED_BLOCK Block,
  696. PCOMPRESSED_BUFFER CompressedBuffer
  697. )
  698. /*++
  699. Routine Description:
  700. Read next compressed block header if it's Xpress compression.
  701. Arguments:
  702. Block - Descriptor of compressed data block
  703. CompressedBuffer - Descriptor of data already brought in
  704. Return Value:
  705. TRUE if block is not Xpress block at all or valid Xpress block, FALSE otherwise
  706. --*/
  707. {
  708. PUCHAR Buffer;
  709. LONG CompressedSize; // they all must be signed -- do not change to ULONG
  710. LONG UncompressedSize;
  711. ULONG PackedSizes;
  712. // First make sure next compressed data block header is available
  713. if (!HbReadNextCompressedPages (XPRESS_HEADER_SIZE, CompressedBuffer)) {
  714. // I/O error or bad header -- FAIL
  715. return(FALSE);
  716. }
  717. // Set pointer to the beginning of buffer
  718. Buffer = CompressedBuffer->Current.Beg;
  719. // Check header magic
  720. Block->Header.XpressEncoded = (RtlCompareMemory (Buffer, XPRESS_HEADER_STRING, XPRESS_HEADER_STRING_SIZE) == XPRESS_HEADER_STRING_SIZE);
  721. if (!Block->Header.XpressEncoded) {
  722. // Not Xpress -- return OK
  723. return(TRUE);
  724. }
  725. // Skip magic string -- we will not need it anymore
  726. Buffer += XPRESS_HEADER_STRING_SIZE;
  727. // Read sizes of compressed and uncompressed data
  728. PackedSizes = Buffer[0] + (Buffer[1] << 8) + (Buffer[2] << 16) + (Buffer[3] << 24);
  729. CompressedSize = (LONG) (PackedSizes >> 10) + 1;
  730. UncompressedSize = ((LONG) (PackedSizes & 1023) + 1) << PAGE_SHIFT;
  731. Block->Header.Compressed.Size = CompressedSize;
  732. Block->Header.Uncompressed.Size = UncompressedSize;
  733. // Read checksums
  734. Block->Header.Uncompressed.Checksum = Buffer[4] + (Buffer[5] << 8);
  735. Block->Header.Compressed.Checksum = Buffer[6] + (Buffer[7] << 8);
  736. // Clear space occupied by compressed checksum
  737. Buffer[6] = Buffer[7] = 0;
  738. // Make sure sizes are in correct range
  739. if (UncompressedSize > XPRESS_MAX_SIZE ||
  740. CompressedSize > UncompressedSize ||
  741. CompressedSize == 0 ||
  742. UncompressedSize == 0) {
  743. // broken input data -- do not even try to decompress
  744. DBGOUT (("Corrupted header: %02x %02x %02x %02x %02x %02x %02x %02x\n",
  745. Buffer[0], Buffer[1], Buffer[2], Buffer[3], Buffer[4], Buffer[5], Buffer[6], Buffer[7]));
  746. DBGOUT (("CompressedSize = %d, UncompressedSize = %d\n", CompressedSize, UncompressedSize));
  747. return(FALSE);
  748. }
  749. // Xpress header and it looks OK so far
  750. return(TRUE);
  751. }
  752. BOOLEAN
  753. HbReadNextCompressedBlock (
  754. PDECOMPRESSED_BLOCK Block,
  755. PCOMPRESSED_BUFFER CompressedBuffer
  756. )
  757. /*++
  758. Routine Description:
  759. Reads and decompresses the next compressed chunk from the Hiber file
  760. and stores it in a designated region of virtual memory.
  761. Since no master data structure exists within the Hiber file to identify
  762. the location of all of the compression chunks, this routine operates
  763. by reading sections of the Hiber file into a compression buffer
  764. and extracting chunks from that buffer.
  765. Chunks are extracted by determining if a chunk is completely present in the buffer
  766. using the RtlDescribeChunk API. If the chunk is not completely present,
  767. more of the Hiber file is read into the buffer until the chunk can
  768. be extracted.
  769. All reads from the Hiber file occurr at its current offset, forcing
  770. compressed chunks to be read in a continous fashion with no extraneous
  771. seeks.
  772. Arguments:
  773. Block - Descriptor of compressed data block
  774. CompressedBuffer - Descriptor of data already brought in
  775. Return Value:
  776. TRUE if a chunk has been succesfully extracted and decompressed, FALSE otherwise.
  777. --*/
  778. {
  779. PUCHAR Buffer;
  780. LONG CompressedSize; // they all must be signed -- do not change to ULONG
  781. LONG AlignedCompressedSize;
  782. LONG UncompressedSize;
  783. // First make sure next compressed data block header is available
  784. if (!HbReadNextCompressedBlockHeader (Block, CompressedBuffer)) {
  785. // I/O error -- FAIL
  786. return(FALSE);
  787. }
  788. // It must be Xpress
  789. if (!Block->Header.XpressEncoded) {
  790. #ifdef HIBER_DEBUG
  791. // Set pointer to the beginning of buffer
  792. Buffer = CompressedBuffer->Current.Beg;
  793. // wrong magic -- corrupted data
  794. DBGOUT (("Corrupted header: %02x %02x %02x %02x %02x %02x %02x %02x\n",
  795. Buffer[0], Buffer[1], Buffer[2], Buffer[3], Buffer[4], Buffer[5], Buffer[6], Buffer[7]));
  796. #endif /* HIBER_DEBUG */
  797. return(FALSE);
  798. }
  799. // Read sizes
  800. UncompressedSize = Block->Header.Uncompressed.Size;
  801. CompressedSize = Block->Header.Compressed.Size;
  802. // If not enough space supplied use preallocated buffer
  803. if (UncompressedSize != Block->DataSize) {
  804. Block->DataSize = UncompressedSize;
  805. Block->DataPtr = Block->PreallocatedDataBuffer;
  806. }
  807. // Evaluate aligned size of compressed data
  808. AlignedCompressedSize = (CompressedSize + (XPRESS_ALIGNMENT - 1)) & ~(XPRESS_ALIGNMENT - 1);
  809. // Make sure we have all compressed data and the header in buffer
  810. if (!HbReadNextCompressedPages (AlignedCompressedSize + XPRESS_HEADER_SIZE, CompressedBuffer)) {
  811. // I/O error -- FAIL
  812. return(FALSE);
  813. }
  814. // Set pointer to the beginning of buffer
  815. Buffer = CompressedBuffer->Current.Beg;
  816. // We will use some bytes out of buffer now -- reflect this fact
  817. CompressedBuffer->Current.Beg += AlignedCompressedSize + XPRESS_HEADER_SIZE;
  818. // evaluate and compare checksum of compressed data and header with written value
  819. if (Block->Header.Compressed.Checksum != 0) {
  820. ULONG Checksum;
  821. Checksum = HbSimpleCheck (0, Buffer, AlignedCompressedSize + XPRESS_HEADER_SIZE);
  822. if (((Checksum ^ Block->Header.Compressed.Checksum) & 0xffff) != 0) {
  823. DBGOUT (("Compressed data checksum mismatch (got %08lx, written %08lx)\n", Checksum, Block->Header.Compressed.Checksum));
  824. return(FALSE);
  825. }
  826. }
  827. // Was this buffer compressed at all?
  828. if (CompressedSize == UncompressedSize) {
  829. // Nope, do not decompress it -- set bounds and return OK
  830. Block->DataPtr = Buffer + XPRESS_HEADER_SIZE;
  831. } else {
  832. LONG DecodedSize;
  833. // Decompress the buffer
  834. DecodedSize = XpressDecode (NULL,
  835. Block->DataPtr,
  836. UncompressedSize,
  837. UncompressedSize,
  838. Buffer + XPRESS_HEADER_SIZE,
  839. CompressedSize);
  840. if (DecodedSize != UncompressedSize) {
  841. DBGOUT (("Decode error: DecodedSize = %d, UncompressedSize = %d\n", DecodedSize, UncompressedSize));
  842. return(FALSE);
  843. }
  844. }
  845. #ifdef HIBER_DEBUG
  846. // evaluate and compare uncompressed data checksums (just to be sure)
  847. if (Block->Header.Uncompressed.Checksum != 0) {
  848. ULONG Checksum;
  849. Checksum = HbSimpleCheck (0, Block->DataPtr, UncompressedSize);
  850. if (((Checksum ^ Block->Header.Uncompressed.Checksum) & 0xffff) != 0) {
  851. DBGOUT (("Decoded data checksum mismatch (got %08lx, written %08lx)\n", Checksum, Block->Header.Uncompressed.Checksum));
  852. return(FALSE);
  853. }
  854. }
  855. #endif /* HIBER_DEBUG */
  856. return(TRUE);
  857. }
  858. BOOLEAN
  859. HbReadNextCompressedPageLZNT1 (
  860. PUCHAR DestVa,
  861. PCOMPRESSED_BUFFER CompressedBuffer
  862. )
  863. /*++
  864. Routine Description:
  865. This routine reads in the next compressed page from the
  866. Hiber file and decompresses it into a designated region
  867. of virtual memory.
  868. The page is recreated by assembling it from a series
  869. a compressed chunks that are assumed to be contiguously
  870. stored in the Hiber file.
  871. All reads from the Hiber file occurr at the file's
  872. current offset forcing compressed pages to be read
  873. in a continuous fashion without extraneous file seeks.
  874. Arguments:
  875. DestVa - The Virtual Address where the decompressed page should
  876. be written.
  877. CompressedBuffer - Descriptor of data already brought in
  878. Return Value:
  879. TRUE if the operation is successful, FALSE otherwise.
  880. --*/
  881. {
  882. ULONG ReadTotal;
  883. // Loop while page is incomplete
  884. for (ReadTotal = 0; ReadTotal < PAGE_SIZE; ReadTotal += PO_COMPRESS_CHUNK_SIZE) {
  885. // Get a chunk
  886. if (!HbReadNextCompressedChunkLZNT1(DestVa, CompressedBuffer)) {
  887. return FALSE;
  888. }
  889. // Move on to the next chunk of the page
  890. DestVa += PO_COMPRESS_CHUNK_SIZE;
  891. }
  892. return TRUE;
  893. }
  894. BOOLEAN
  895. HbReadNextCompressedChunkLZNT1 (
  896. PUCHAR DestVa,
  897. PCOMPRESSED_BUFFER CompressedBuffer
  898. )
  899. /*++
  900. Routine Description:
  901. Reads and decompresses the next compressed chunk from the Hiber file
  902. and stores it in a designated region of virtual memory.
  903. Since no master data structure exists within the Hiber file to identify
  904. the location of all of the compression chunks, this routine operates
  905. by reading sections of the Hiber file into a compression buffer
  906. and extracting chunks from that buffer.
  907. Chunks are extracted by determining if a chunk is completely present in the buffer
  908. using the RtlDescribeChunk API. If the chunk is not completely present,
  909. more of the Hiber file is read into the buffer until the chunk can
  910. be extracted.
  911. All reads from the Hiber file occurr at its current offset, forcing
  912. compressed chunks to be read in a continous fashion with no extraneous
  913. seeks.
  914. Arguments:
  915. DestVa - The virtual address where the decompressed chunk
  916. should be written.
  917. CompressedBuffer - Descriptor of data already brought in
  918. Return Value:
  919. TRUE if a chunk has been succesfully extracted and decompressed, FALSE otherwise.
  920. --*/
  921. {
  922. PUCHAR Buffer;
  923. NTSTATUS Status;
  924. ULONG ChunkSize;
  925. PUCHAR ChunkBuffer;
  926. ULONG SpaceLeft;
  927. // Loop until we have accomplished our goal since we may need
  928. // several operations before a chunk is extracted
  929. while (1) {
  930. Buffer = CompressedBuffer->Current.Beg;
  931. // Check the first unextracted chunk in the buffer
  932. Status = RtlDescribeChunk(COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_STANDARD,
  933. &Buffer,
  934. CompressedBuffer->Current.End,
  935. &ChunkBuffer,
  936. &ChunkSize);
  937. switch (Status) {
  938. case STATUS_SUCCESS:
  939. // A complete and valid chunk is present in the buffer
  940. // Decompress the chunk into the proper region of virtual memory
  941. Status = RtlDecompressBuffer (COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_STANDARD,
  942. DestVa,
  943. PO_COMPRESS_CHUNK_SIZE,
  944. CompressedBuffer->Current.Beg,
  945. (LONG) (CompressedBuffer->Current.End - CompressedBuffer->Current.Beg),
  946. &ChunkSize);
  947. if ((!NT_SUCCESS(Status)) || (ChunkSize != PO_COMPRESS_CHUNK_SIZE)) {
  948. // Decompression failed
  949. return(FALSE);
  950. } else {
  951. // Decompression succeeded, indicate that the chunk following
  952. // this one is the next unextracted chunk in the buffer
  953. CompressedBuffer->Current.Beg = Buffer;
  954. return(TRUE);
  955. }
  956. case STATUS_BAD_COMPRESSION_BUFFER:
  957. case STATUS_NO_MORE_ENTRIES:
  958. //
  959. // Buffer does not contain a complete and valid chunk
  960. //
  961. //
  962. // Check how much space remains in the buffer since
  963. // we will need to read some stuff from the Hiber file
  964. //
  965. SpaceLeft = (LONG) (CompressedBuffer->Aligned.End - CompressedBuffer->Aligned.Beg);
  966. if (SpaceLeft > LZNT1_COMPRESSION_BUFFER_SIZE) {
  967. SpaceLeft = LZNT1_COMPRESSION_BUFFER_SIZE;
  968. }
  969. SpaceLeft -= (((LONG) (CompressedBuffer->Current.End - CompressedBuffer->Current.Beg)) + PAGE_MASK) & ~PAGE_MASK;
  970. if (SpaceLeft <= 0) {
  971. // Should never happen
  972. DBGOUT (("SpaceLeft = %d\n", SpaceLeft));
  973. return(FALSE);
  974. }
  975. if (!HbReadNextCompressedPages (SpaceLeft, CompressedBuffer)) {
  976. // IO error
  977. return(FALSE);
  978. }
  979. break;
  980. default:
  981. //
  982. // Unhandled RtlDescribeChunk return code - have they changed the function on us?
  983. //
  984. return(FALSE);
  985. }
  986. //
  987. // try again with the bigger buffer
  988. //
  989. }
  990. return FALSE;
  991. }
  992. VOID
  993. HexDump (
  994. IN ULONG indent,
  995. IN ULONG va,
  996. IN ULONG len,
  997. IN ULONG width,
  998. IN PUCHAR buf
  999. )
  1000. {
  1001. UCHAR s[80], t[80], lstr[200];
  1002. PUCHAR ps, pt;
  1003. ULONG i;
  1004. UCHAR Key;
  1005. static UCHAR rgHexDigit[] = "0123456789abcdef";
  1006. if (HiberIoError) {
  1007. HbPrint (TEXT("*** HiberIoError\n"));
  1008. return ;
  1009. }
  1010. if (HiberOutOfRemap) {
  1011. HbPrint (TEXT("*** HiberOutOfRemap\n"));
  1012. return ;
  1013. }
  1014. i = 0;
  1015. while (len) {
  1016. ps = s;
  1017. pt = t;
  1018. ps[0] = '\0';
  1019. pt[0] = '*';
  1020. pt++;
  1021. for (i=0; i < 16; i++) {
  1022. ps[0] = ' ';
  1023. ps[1] = ' ';
  1024. ps[2] = ' ';
  1025. if (len) {
  1026. ps[0] = rgHexDigit[buf[0] >> 4];
  1027. ps[1] = rgHexDigit[buf[0] & 0xf];
  1028. pt[0] = buf[0] < ' ' || buf[0] > 'z' ? '.' : buf[0];
  1029. len -= 1;
  1030. buf += 1;
  1031. pt += 1;
  1032. }
  1033. ps += 3;
  1034. }
  1035. ps[0] = 0;
  1036. pt[0] = '*';
  1037. pt[1] = 0;
  1038. s[23] = '-';
  1039. if (s[0]) {
  1040. sprintf (lstr, "%*s%08lx: %s %s\r\n", indent, "", va, s, t);
  1041. #ifdef UNICODE
  1042. {
  1043. WCHAR lstrW[200];
  1044. ANSI_STRING aString;
  1045. UNICODE_STRING uString;
  1046. RtlInitString( &aString, lstr );
  1047. uString.Buffer = lstrW;
  1048. uString.MaximumLength = sizeof(lstrW);
  1049. RtlAnsiStringToUnicodeString( &uString, &aString, FALSE );
  1050. HbPrint(lstrW);
  1051. }
  1052. #else
  1053. HbPrint (lstr);
  1054. #endif
  1055. va += 16;
  1056. }
  1057. }
  1058. ArcRead(ARC_CONSOLE_INPUT, &Key, sizeof(Key), &i);
  1059. }
  1060. BOOLEAN
  1061. HbReadDelayedBlock (
  1062. BOOLEAN ForceDecoding,
  1063. PFN_NUMBER DestPage,
  1064. ULONG RangeCheck,
  1065. PDECOMPRESSED_BLOCK Block,
  1066. PCOMPRESSED_BUFFER CompressedBuffer
  1067. )
  1068. {
  1069. LONG i, j;
  1070. BOOLEAN Contig;
  1071. BOOLEAN Ret;
  1072. if (ForceDecoding) {
  1073. if (Block->DelayedCnt == 0) {
  1074. return TRUE;
  1075. }
  1076. } else {
  1077. // If first page to delay read next block info
  1078. if (Block->DelayedCnt <= 0) {
  1079. Ret = HbReadNextCompressedBlockHeader (Block, CompressedBuffer);
  1080. if (HiberIoError || !Ret || !Block->Header.XpressEncoded) {
  1081. // Something is wrong
  1082. return FALSE;
  1083. }
  1084. }
  1085. // remember page info
  1086. Block->Delayed[Block->DelayedCnt].DestPage = DestPage;
  1087. Block->Delayed[Block->DelayedCnt].RangeCheck = RangeCheck;
  1088. // Update counter
  1089. Block->DelayedCnt += 1;
  1090. // Last page that may be delayed?
  1091. if (Block->DelayedCnt != sizeof (Block->Delayed) / sizeof (Block->Delayed[0]) &&
  1092. (Block->DelayedCnt << PAGE_SHIFT) < Block->Header.Uncompressed.Size) {
  1093. // Nope, nothing to do
  1094. return TRUE;
  1095. }
  1096. }
  1097. // Make sure that size of encoded block and # of delayed pages are the same
  1098. if ((Block->DelayedCnt << PAGE_SHIFT) != Block->Header.Uncompressed.Size) {
  1099. DBGOUT (("DelayedCnt = %d, UncompressedSize = %d\n", Block->DelayedCnt, Block->Header.Uncompressed.Size));
  1100. return FALSE;
  1101. }
  1102. // Prepare for mapping. Hopefully mapping will be contiguous
  1103. Contig = TRUE;
  1104. // Map new pages
  1105. for (j = 0; j < Block->DelayedCnt; ++j) {
  1106. i = HbPageDisposition (Block->Delayed[j].DestPage);
  1107. if (i == HbPageInvalid) {
  1108. // Should never happen
  1109. return(FALSE);
  1110. }
  1111. if (i == HbPageNotInUse) {
  1112. Block->Delayed[j].DestVa = HbMapPte(PTE_XPRESS_DEST_FIRST + j, Block->Delayed[j].DestPage);
  1113. } else {
  1114. Block->Delayed[j].DestVa = HbNextSharedPage(PTE_XPRESS_DEST_FIRST + j, Block->Delayed[j].DestPage);
  1115. }
  1116. if (j > 0 && Block->Delayed[j].DestVa != Block->Delayed[j-1].DestVa + PAGE_SIZE) {
  1117. Contig = FALSE;
  1118. }
  1119. }
  1120. // Set pointer to data. Try mapped pages if possible
  1121. if (Contig) {
  1122. Block->DataSize = Block->DelayedCnt << PAGE_SHIFT;
  1123. Block->DataPtr = Block->Delayed[0].DestVa;
  1124. } else {
  1125. // Will have to used preallocated data buffer
  1126. Block->DataSize = Block->Header.Uncompressed.Size;
  1127. Block->DataPtr = Block->PreallocatedDataBuffer;
  1128. }
  1129. // Decode next block
  1130. Ret = HbReadNextCompressedBlock (Block, CompressedBuffer);
  1131. // Check for errors
  1132. if (HiberIoError || !Ret) {
  1133. // Something's seriousely wrong
  1134. return FALSE;
  1135. }
  1136. for (j = 0; j < Block->DelayedCnt; ++j) {
  1137. // Copy block to target address if necessary
  1138. if (Block->Delayed[j].DestVa != Block->DataPtr) {
  1139. RtlCopyMemory (Block->Delayed[j].DestVa, Block->DataPtr, PAGE_SIZE);
  1140. }
  1141. Block->DataPtr += PAGE_SIZE;
  1142. Block->DataSize -= PAGE_SIZE;
  1143. }
  1144. // No more delayed blocks
  1145. Block->DelayedCnt = 0;
  1146. return TRUE;
  1147. }
  1148. // Allocate data aligned on page boundary
  1149. PVOID
  1150. HbAllocateAlignedHeap (
  1151. ULONG Size
  1152. )
  1153. {
  1154. PCHAR Va;
  1155. Va = BlAllocateHeap (Size + PAGE_MASK);
  1156. if (Va != NULL) {
  1157. Va += ((PAGE_SIZE - (((ULONG_PTR) Va) & PAGE_MASK)) & PAGE_MASK);
  1158. }
  1159. return (Va);
  1160. }
  1161. ULONG
  1162. HbRestoreFile (
  1163. IN PULONG Information,
  1164. OUT PCHAR *BadLinkName
  1165. )
  1166. {
  1167. PPO_MEMORY_IMAGE MemImage;
  1168. PPO_IMAGE_LINK ImageLink;
  1169. PPO_MEMORY_RANGE_ARRAY Table;
  1170. PHIBER_WAKE_DISPATCH WakeDispatch;
  1171. ULONG Length;
  1172. ULONG Check;
  1173. ULONG Count;
  1174. PUCHAR p1;
  1175. PUCHAR DestVa;
  1176. ULONG Index, i;
  1177. PFN_NUMBER TablePage;
  1178. PFN_NUMBER DestPage;
  1179. PFN_NUMBER Scale;
  1180. ULONG TotalPages;
  1181. ULONG LastBar;
  1182. ULONG Sel[4];
  1183. ULONG LinkedDrive;
  1184. COMPRESSED_BUFFER CompressedBufferData;
  1185. PCOMPRESSED_BUFFER CompressedBuffer = &CompressedBufferData;
  1186. BOOLEAN Ret;
  1187. LONG XpressEncoded;
  1188. PDECOMPRESSED_BLOCK Block;
  1189. PUCHAR msg;
  1190. ULONG fPercentage = 0;
  1191. ULONG LastPercentage = (ULONG)-1;
  1192. PUCHAR Ptr;
  1193. ARC_STATUS Status;
  1194. ULONG ActualBase;
  1195. #if HIBER_PERF_STATS
  1196. ULONG StartTime, EndTime;
  1197. StartTime = ArcGetRelativeTime();
  1198. #endif
  1199. #if defined (HIBER_DEBUG)
  1200. HbPrint(TEXT("HbRestoreFile\r\n"));
  1201. #endif
  1202. *Information = 0;
  1203. HiberBufferPage = 0;
  1204. BlAllocateAlignedDescriptor (LoaderFirmwareTemporary,
  1205. 0,
  1206. 1,
  1207. 1,
  1208. &HiberBufferPage);
  1209. CHECK_ERROR (!HiberBufferPage, HIBER_ERROR_NO_MEMORY);
  1210. HiberBuffer = (PUCHAR) (KSEG0_BASE | (((ULONG)HiberBufferPage) << PAGE_SHIFT));
  1211. //
  1212. // Read image header
  1213. //
  1214. HbReadPage (PO_IMAGE_HEADER_PAGE, HiberBuffer);
  1215. MemImage = (PPO_MEMORY_IMAGE) HiberBuffer;
  1216. //
  1217. // If the signature is a link, then follow it
  1218. //
  1219. if (MemImage->Signature == PO_IMAGE_SIGNATURE_LINK) {
  1220. ImageLink = (PPO_IMAGE_LINK) HiberBuffer;
  1221. //
  1222. // Open target partition, and then the hiberfile image on that
  1223. // partition. If not found, then we're done
  1224. //
  1225. Status = ArcOpen ((char*)ImageLink->Name, ArcOpenReadOnly, &LinkedDrive);
  1226. if (Status != ESUCCESS) {
  1227. if (ARGUMENT_PRESENT(BadLinkName)) {
  1228. *BadLinkName = (char *)(&ImageLink->Name);
  1229. //
  1230. // At this point we want to blast the link signature. The caller
  1231. // may need to load NTBOOTDD to access the real hiberfile. Once
  1232. // this happens there is no turning back as we cannot go back to
  1233. // the BIOS to reread BOOT.INI. By zeroing the signature we ensure
  1234. // that if the restore fails, the next boot will not try to restore
  1235. // it again.
  1236. //
  1237. HbSetImageSignature(0);
  1238. }
  1239. return 0;
  1240. }
  1241. Status = BlOpen (LinkedDrive, szHiberFileName, ArcOpenReadWrite, &i);
  1242. if (Status != ESUCCESS) {
  1243. ArcClose(LinkedDrive);
  1244. return 0;
  1245. }
  1246. //
  1247. // Switch to linked HiberFile image and continue
  1248. //
  1249. BlClose (HiberFile);
  1250. HiberFile = i;
  1251. HbReadPage (PO_IMAGE_HEADER_PAGE, HiberBuffer);
  1252. }
  1253. //
  1254. // If the image has the wake signature, then we've already attempted
  1255. // to restart this image once. Check if it should be attempted again
  1256. //
  1257. if (MemImage->Signature == PO_IMAGE_SIGNATURE_WAKE) {
  1258. Sel[0] = HIBER_CANCEL;
  1259. Sel[1] = HIBER_CONTINUE;
  1260. Sel[2] = HIBER_DEBUG_BREAK_ON_WAKE;
  1261. Sel[3] = 0;
  1262. HbScreen(HIBER_RESTART_AGAIN);
  1263. i = HbSelection(PAUSE_X, PAUSE_Y, Sel, 1);
  1264. if (i == 0) {
  1265. HiberAbort = TRUE;
  1266. HbSetImageSignature (0);
  1267. return 0;
  1268. }
  1269. MemImage->Signature = PO_IMAGE_SIGNATURE;
  1270. }
  1271. //
  1272. // If the signature is not valid, then behave as if there's no
  1273. // hibernated context
  1274. //
  1275. if (MemImage->Signature != PO_IMAGE_SIGNATURE) {
  1276. return 0;
  1277. }
  1278. CHECK_ERROR (MemImage->LengthSelf > PAGE_SIZE, HIBER_ERROR_BAD_IMAGE);
  1279. //
  1280. // Copy the image out of the HiberBuffer
  1281. //
  1282. Length = MemImage->LengthSelf;
  1283. MemImage = BlAllocateHeap(Length);
  1284. CHECK_ERROR (!MemImage, HIBER_ERROR_NO_MEMORY);
  1285. memcpy (MemImage, HiberBuffer, Length);
  1286. HiberImageFeatureFlags = MemImage->FeatureFlags;
  1287. //
  1288. // Verify the checksum on the image header
  1289. //
  1290. Check = MemImage->CheckSum;
  1291. MemImage->CheckSum = 0;
  1292. Check = Check - HbSimpleCheck(0, MemImage, Length);
  1293. CHECK_ERROR (Check, HIBER_ERROR_BAD_IMAGE);
  1294. CHECK_ERROR (MemImage->Version != 0, HIBER_IMAGE_INCOMPATIBLE);
  1295. CHECK_ERROR (MemImage->PageSize != PAGE_SIZE, HIBER_IMAGE_INCOMPATIBLE);
  1296. //
  1297. // Setup mapping information for restore
  1298. //
  1299. #if !defined (_ALPHA_) || defined(_IA64_)
  1300. CHECK_ERROR (MemImage->NoHiberPtes > HIBER_PTES, HIBER_IMAGE_INCOMPATIBLE);
  1301. #endif
  1302. HiberNoMappings = MemImage->NoFreePages;
  1303. #if defined (_ALPHA_) || defined(_IA64_)
  1304. HiberImagePageSelf = MemImage->PageSelf; // used in WakeDispatch to enable break-on-wake
  1305. #else
  1306. HiberIdentityVa = (PVOID) MemImage->HiberVa;
  1307. HiberImagePageSelf = MemImage->PageSelf;
  1308. //
  1309. // Allocate a block of PTEs for restoration work which
  1310. // do not overlap the same addresses needed for the
  1311. // restoration
  1312. //
  1313. while (!HiberVa || (MemImage->HiberVa >= (ULONG_PTR) HiberVa && MemImage->HiberVa <= (ULONG_PTR) p1)) {
  1314. HbAllocatePtes (HIBER_PTES, &HiberPtes, &HiberVa);
  1315. p1 = HiberVa + (HIBER_PTES << PAGE_SHIFT);
  1316. }
  1317. #endif
  1318. //
  1319. // Read in the free page map
  1320. //
  1321. HbReadPage (PO_FREE_MAP_PAGE, HiberBuffer);
  1322. Check = HbSimpleCheck(0, HiberBuffer, PAGE_SIZE);
  1323. CHECK_ERROR (MemImage->FreeMapCheck != Check, HIBER_ERROR_BAD_IMAGE);
  1324. // Set us up to decompress the contents of the hiber file
  1325. // Allocate a buffer for compression work
  1326. //
  1327. // N.B. The compression buffer size must be at least the maximum
  1328. // compressed size of a single compression chunk.
  1329. //
  1330. // Initialize decompressed data buffer
  1331. Ptr = HbAllocateAlignedHeap (sizeof (*Block) + XPRESS_MAX_SIZE);
  1332. CHECK_ERROR(!Ptr, HIBER_ERROR_NO_MEMORY);
  1333. Block = (PVOID) (Ptr + XPRESS_MAX_SIZE);
  1334. Block->DataSize = 0;
  1335. Block->PreallocatedDataBuffer = Ptr;
  1336. //
  1337. // Allocate compressed data buffer. Change the allocation policy
  1338. // to lowest first in order to get a buffer under 1MB. This saves
  1339. // us from double-buffering all the BIOS transfers.
  1340. //
  1341. Status = BlAllocateAlignedDescriptor(LoaderFirmwareTemporary,
  1342. 0,
  1343. MAX_COMPRESSION_BUFFER_PAGES + MAX_COMPRESSION_BUFFER_EXTRA_PAGES,
  1344. 0x10000 >> PAGE_SHIFT,
  1345. &ActualBase);
  1346. if (Status == ESUCCESS) {
  1347. Ptr = (PVOID)(KSEG0_BASE | (ActualBase << PAGE_SHIFT));
  1348. } else {
  1349. Ptr = HbAllocateAlignedHeap (MAX_COMPRESSION_BUFFER_SIZE + MAX_COMPRESSION_BUFFER_EXTRA_SIZE);
  1350. }
  1351. CHECK_ERROR(!Ptr, HIBER_ERROR_NO_MEMORY);
  1352. // Initialize compressed data buffer
  1353. CompressedBuffer->Buffer.Beg = Ptr;
  1354. CompressedBuffer->Buffer.End = Ptr + MAX_COMPRESSION_BUFFER_SIZE + MAX_COMPRESSION_BUFFER_EXTRA_SIZE;
  1355. CompressedBuffer->Aligned.Beg = CompressedBuffer->Buffer.Beg;
  1356. CompressedBuffer->Aligned.End = CompressedBuffer->Buffer.End;
  1357. CompressedBuffer->FilePage = 0;
  1358. CompressedBuffer->NeedSeek = TRUE;
  1359. CompressedBuffer->Current.Beg = CompressedBuffer->Current.End = CompressedBuffer->Aligned.Beg;
  1360. // ***************************************************************
  1361. //
  1362. // From here on, there's no memory allocation from the loaders
  1363. // heap. This is to simplify the booking of whom owns which
  1364. // page. If the hibernation process is aborted, then the
  1365. // pages used here are simply forgoten and the loader continues.
  1366. // If the hiberation processor completes, we forget about
  1367. // the pages in use by the loader
  1368. //
  1369. // ***************************************************************
  1370. #if defined(_ALPHA_) || defined(_IA64_)
  1371. //
  1372. // Initialize the hibernation memory allocation and remap table,
  1373. // using the free page map just read from the hibernation file.
  1374. //
  1375. HbInitRemap((PPFN_NUMBER) HiberBuffer); // why can't HiberBuffer be a PVOID?
  1376. #else // original (x86) code
  1377. //
  1378. // Set the loader map pointer to the tempory buffer, and get
  1379. // a physical shared page to copy the map to.
  1380. //
  1381. HbMapPte(PTE_MAP_PAGE, HiberBufferPage);
  1382. HbMapPte(PTE_REMAP_PAGE, HiberBufferPage);
  1383. DestVa = HbNextSharedPage(PTE_MAP_PAGE, 0);
  1384. memcpy (DestVa, HiberBuffer, PAGE_SIZE);
  1385. DestVa = HbNextSharedPage(PTE_REMAP_PAGE, 0);
  1386. #endif // Alpha/x86
  1387. //
  1388. // Map in and copy relocatable hiber wake dispatcher
  1389. //
  1390. Length = (ULONG) (&WakeDispatcherEnd - &WakeDispatcherStart);
  1391. p1 = (PUCHAR) &WakeDispatcherStart;
  1392. Index = 0;
  1393. while (Length) {
  1394. CHECK_ERROR(PTE_DISPATCHER_START+Index > PTE_DISPATCHER_END, HIBER_INTERNAL_ERROR);
  1395. DestVa = HbNextSharedPage(PTE_DISPATCHER_START+Index, 0);
  1396. if (Index == 0) {
  1397. WakeDispatch = (PHIBER_WAKE_DISPATCH) DestVa;
  1398. }
  1399. i = Length > PAGE_SIZE ? PAGE_SIZE : Length;
  1400. memcpy (DestVa, p1, i);
  1401. Length -= i;
  1402. p1 += i;
  1403. Index += 1;
  1404. }
  1405. //
  1406. // Read the hibernated processors context
  1407. //
  1408. // Note we read into the hiber buffer and then copy in order to
  1409. // ensure that the destination of the I/O is legal to transfer into.
  1410. // Busmaster ISA SCSI cards can only access the low 16MB of RAM.
  1411. //
  1412. DestVa = HbNextSharedPage(PTE_HIBER_CONTEXT, 0);
  1413. HbReadPage (PO_PROCESSOR_CONTEXT_PAGE, HiberBuffer);
  1414. memcpy(DestVa, HiberBuffer, PAGE_SIZE);
  1415. Check = HbSimpleCheck(0, DestVa, PAGE_SIZE);
  1416. CHECK_ERROR(MemImage->WakeCheck != Check, HIBER_ERROR_BAD_IMAGE);
  1417. #if defined(_ALPHA_)
  1418. HiberWakeState = (PKPROCESSOR_STATE)DestVa;
  1419. #endif
  1420. //
  1421. // Perform architecture specific setup for dispatcher, then set
  1422. // the location of first remap past the pages mapped so far
  1423. //
  1424. HiberSetupForWakeDispatch ();
  1425. HiberFirstRemap = HiberLastRemap;
  1426. //
  1427. // Restore memory from hibernation image
  1428. //
  1429. TablePage = MemImage->FirstTablePage;
  1430. Table = (PPO_MEMORY_RANGE_ARRAY) HiberBuffer;
  1431. Scale = MemImage->TotalPages / PERCENT_BAR_WIDTH;
  1432. LastBar = 0;
  1433. TotalPages = 3;
  1434. //
  1435. // Popup "Resuming Windows 2000..." message
  1436. //
  1437. BlSetProgBarCharacteristics(HIBER_UI_BAR_ELEMENT, BLDR_UI_BAR_BACKGROUND);
  1438. BlOutputStartupMsg(BL_MSG_RESUMING_WINDOWS);
  1439. BlOutputTrailerMsg(BL_ADVANCED_BOOT_MESSAGE);
  1440. XpressEncoded = -1; // unknown encoding (either Xpress or LZNT1)
  1441. Block->DataSize = 0; // no data left in buffer
  1442. Block->DelayedCnt = 0; // no delayed blocks
  1443. Block->DelayedChecksum = 0; // delayed checksum = 0;
  1444. Block->DelayedBadChecksum = FALSE;
  1445. while (TablePage) {
  1446. #if defined (HIBER_DEBUG) && (HIBER_DEBUG & 2)
  1447. SHOWNUM(TablePage);
  1448. #endif
  1449. //
  1450. // Do not use HbReadPage if possible -- it issues extra seek
  1451. // (usually 5-6 ms penalty) -- use sequential read if possible
  1452. //
  1453. if (CompressedBuffer->FilePage == 0 ||
  1454. TablePage > CompressedBuffer->FilePage ||
  1455. TablePage < CompressedBuffer->FilePage - (PFN_NUMBER) ((CompressedBuffer->Current.End - CompressedBuffer->Current.Beg) >> PAGE_SHIFT)) {
  1456. //
  1457. // Cannot read table page from current buffer -- need to seek
  1458. // and reset the buffer (should happen on very first entry only)
  1459. //
  1460. CompressedBuffer->FilePage = TablePage;
  1461. CompressedBuffer->Current.Beg = CompressedBuffer->Current.End = CompressedBuffer->Aligned.Beg;
  1462. CompressedBuffer->NeedSeek = TRUE;
  1463. }
  1464. //
  1465. // Shift current pointer to the page we need
  1466. //
  1467. CompressedBuffer->Current.Beg = CompressedBuffer->Current.End - ((CompressedBuffer->FilePage - TablePage) << PAGE_SHIFT);
  1468. //
  1469. // Make sure the page is in
  1470. //
  1471. Ret = HbReadNextCompressedPages (PAGE_SIZE, CompressedBuffer);
  1472. CHECK_ERROR(HiberIoError, HIBER_READ_ERROR);
  1473. CHECK_ERROR(!Ret, HIBER_ERROR_BAD_IMAGE);
  1474. //
  1475. // Copy table page to target location and adjust input pointer
  1476. //
  1477. RtlCopyMemory (Table, CompressedBuffer->Current.Beg, PAGE_SIZE);
  1478. CompressedBuffer->Current.Beg += PAGE_SIZE;
  1479. Check = Table[0].Link.CheckSum;
  1480. if (Check) {
  1481. Table[0].Link.CheckSum = 0;
  1482. Check = Check - HbSimpleCheck(0, Table, PAGE_SIZE);
  1483. CHECK_ERROR(Check, HIBER_ERROR_BAD_IMAGE);
  1484. }
  1485. // Check the first block magic to see whether it LZNT1 or Xpress
  1486. if (XpressEncoded < 0) {
  1487. Ret = HbReadNextCompressedBlockHeader (Block, CompressedBuffer);
  1488. CHECK_ERROR(HiberIoError, HIBER_READ_ERROR);
  1489. CHECK_ERROR(!Ret, HIBER_ERROR_BAD_IMAGE);
  1490. // Remember the mode
  1491. XpressEncoded = (BOOLEAN) (Block->Header.XpressEncoded);
  1492. }
  1493. for (Index=1; Index <= Table[0].Link.EntryCount; Index++) {
  1494. Check = 0;
  1495. DestPage = Table[Index].Range.StartPage;
  1496. while (DestPage < Table[Index].Range.EndPage) {
  1497. if (!XpressEncoded) {
  1498. // LZNT1 encoding -- do one page at a time
  1499. //
  1500. // If this page conflicts with something in the
  1501. // loader, then use the next mapping
  1502. //
  1503. i = HbPageDisposition (DestPage);
  1504. CHECK_ERROR(i == HbPageInvalid, HIBER_ERROR_BAD_IMAGE);
  1505. if (i == HbPageNotInUse) {
  1506. DestVa = HbMapPte(PTE_DEST, DestPage);
  1507. } else {
  1508. DestVa = HbNextSharedPage(PTE_DEST, DestPage);
  1509. }
  1510. Ret = HbReadNextCompressedPageLZNT1 (DestVa, CompressedBuffer);
  1511. CHECK_ERROR(HiberIoError, HIBER_READ_ERROR);
  1512. CHECK_ERROR(!Ret, HIBER_ERROR_BAD_IMAGE);
  1513. Check = HbSimpleCheck(Check, DestVa, PAGE_SIZE);
  1514. } else {
  1515. Ret = HbReadDelayedBlock (FALSE,
  1516. DestPage,
  1517. Table[Index].Range.CheckSum,
  1518. Block,
  1519. CompressedBuffer);
  1520. CHECK_ERROR(HiberIoError, HIBER_READ_ERROR);
  1521. CHECK_ERROR(!Ret, HIBER_ERROR_BAD_IMAGE);
  1522. }
  1523. // Update counters
  1524. DestPage += 1;
  1525. TotalPages += 1;
  1526. fPercentage = (ULONG)((TotalPages * 100) / MemImage->TotalPages);
  1527. if (fPercentage != LastPercentage) {
  1528. BlUpdateProgressBar(fPercentage);
  1529. HbCheckForPause();
  1530. LastPercentage = fPercentage;
  1531. }
  1532. }
  1533. CHECK_ERROR(HiberOutOfRemap, HIBER_ERROR_OUT_OF_REMAP);
  1534. //
  1535. // Verify checksum on range, but allow continuation with debug flag
  1536. //
  1537. if (!XpressEncoded && Check != Table[Index].Range.CheckSum) {
  1538. Block->DelayedBadChecksum = TRUE;
  1539. }
  1540. if (Block->DelayedBadChecksum && !HiberBreakOnWake) {
  1541. ChecksumError:
  1542. Block->DelayedBadChecksum = FALSE;
  1543. #if defined (HIBER_DEBUG) && (HIBER_DEBUG & 2)
  1544. {
  1545. TCHAR lstr[80];
  1546. HbPrint (TEXT("\r\n"));
  1547. _stprintf (lstr,
  1548. TEXT("TP:%x IDX:%x FP:%x SP:%x EP:%x CHK:%x-%x\r\n"),
  1549. TablePage,
  1550. Index,
  1551. Table[Index].Range.PageNo,
  1552. Table[Index].Range.StartPage,
  1553. Table[Index].Range.EndPage,
  1554. Table[Index].Range.CheckSum,
  1555. Check );
  1556. HbPrint(lstr);
  1557. HexDump (2, (DestPage-1) << PAGE_SHIFT, 0x100, 4, DestVa);
  1558. }
  1559. #endif
  1560. #ifdef HIBER_DEBUG
  1561. DBGOUT ((TEXT("Checksum error\n")));
  1562. HbPause ();
  1563. #endif
  1564. HbScreen(HIBER_ERROR);
  1565. HbPrintMsg(HIBER_ERROR_BAD_IMAGE);
  1566. Sel[0] = HIBER_CANCEL;
  1567. Sel[1] = HIBER_DEBUG_BREAK_ON_WAKE;
  1568. Sel[2] = 0;
  1569. i = HbSelection (FAULT_X, FAULT_Y, Sel, 1);
  1570. if (i == 0) {
  1571. HiberAbort = TRUE;
  1572. HbSetImageSignature (0);
  1573. return 0;
  1574. }
  1575. }
  1576. }
  1577. TablePage = Table[0].Link.NextTable;
  1578. }
  1579. // Process the rest of delayed pages if necessary
  1580. if (XpressEncoded > 0) {
  1581. Ret = HbReadDelayedBlock (TRUE,
  1582. 0,
  1583. 0,
  1584. Block,
  1585. CompressedBuffer);
  1586. CHECK_ERROR(HiberIoError, HIBER_READ_ERROR);
  1587. CHECK_ERROR(!Ret, HIBER_ERROR_BAD_IMAGE);
  1588. if (Block->DelayedBadChecksum) {
  1589. goto ChecksumError;
  1590. }
  1591. }
  1592. //
  1593. // Set the image signature to wake
  1594. //
  1595. HbSetImageSignature (PO_IMAGE_SIGNATURE_WAKE);
  1596. #if HIBER_PERF_STATS
  1597. EndTime = ArcGetRelativeTime();
  1598. BlPositionCursor(BAR_X, BAR_Y + 5);
  1599. HbPrint(TEXT("HIBER: Restore File took "));
  1600. HbPrintNum(EndTime - StartTime);
  1601. HbPrint(TEXT("\r\n"));
  1602. HbPause();
  1603. #endif
  1604. //
  1605. // Check hiber flags to see if it is necessary to reconnect APM
  1606. //
  1607. if (MemImage->HiberFlags & PO_HIBER_APM_RECONNECT) {
  1608. //
  1609. // attempt apm restart
  1610. //
  1611. DoApmAttemptReconnect();
  1612. }
  1613. //
  1614. // Use architecture specific relocatable code to perform the final wake dispatcher
  1615. //
  1616. WakeDispatch();
  1617. CHECK_ERROR (TRUE, HIBER_INTERNAL_ERROR);
  1618. }
  1619. VOID
  1620. HbSetImageSignature (
  1621. IN ULONG NewSignature
  1622. )
  1623. {
  1624. LARGE_INTEGER li;
  1625. ULONG Count, Status;
  1626. li.QuadPart = 0;
  1627. Status = BlSeek (HiberFile, &li, SeekAbsolute);
  1628. if (Status == ESUCCESS) {
  1629. BlWrite (HiberFile, &NewSignature, sizeof(ULONG), &Count);
  1630. }
  1631. }