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.

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