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.

470 lines
11 KiB

  1. /*++
  2. Copyright (c) 1990-1998 Microsoft Corporation
  3. Module Name:
  4. xipdisp.c
  5. Abstract:
  6. This file implements functions for communicating with the XIP Disk Driver.
  7. Most importantly this routine is used by the kernel to communicate
  8. information about the location of the memory set aside for XIP.
  9. Author:
  10. Dave Probert (davepr) 2000/10/10
  11. Environment:
  12. kernel mode
  13. Revision History:
  14. --*/
  15. #include "exp.h"
  16. #pragma hdrstop
  17. #include "cpyuchr.h"
  18. #include "fat.h"
  19. #include "xip.h"
  20. #if defined(_X86_)
  21. typedef struct _XIP_CONFIGURATION {
  22. XIP_BOOT_PARAMETERS BootParameters;
  23. BIOS_PARAMETER_BLOCK BiosParameterBlock;
  24. ULONG ClusterZeroPage;
  25. } XIP_CONFIGURATION, *PXIP_CONFIGURATION;
  26. PXIP_CONFIGURATION XIPConfiguration;
  27. BOOLEAN XIPConfigured;
  28. VOID
  29. XIPInit(
  30. PLOADER_PARAMETER_BLOCK LoaderBlock
  31. );
  32. PMEMORY_ALLOCATION_DESCRIPTOR
  33. XIPpFindMemoryDescriptor(
  34. PLOADER_PARAMETER_BLOCK LoaderBlock
  35. );
  36. #if defined(ALLOC_PRAGMA)
  37. #pragma alloc_text(INIT, XIPInit)
  38. #pragma alloc_text(INIT, XIPpFindMemoryDescriptor)
  39. #pragma alloc_text(PAGE, XIPLocatePages)
  40. #endif
  41. VOID
  42. XIPInit(
  43. PLOADER_PARAMETER_BLOCK LoaderBlock
  44. )
  45. /*++
  46. Routine Description:
  47. This routine sets up the boot parameter information for XIP Rom.
  48. Arguments:
  49. Environment:
  50. Called only at INIT.
  51. --*/
  52. {
  53. PMEMORY_ALLOCATION_DESCRIPTOR XIPMemoryDescriptor;
  54. PPACKED_BOOT_SECTOR pboot;
  55. BIOS_PARAMETER_BLOCK bios;
  56. PHYSICAL_ADDRESS physicalAddress;
  57. PCHAR Options;
  58. PCHAR XIPBoot, XIPRom, XIPRam, XIPSize, XIPVerbose;
  59. PCHAR sizestr;
  60. ULONG nmegs = 0;
  61. //
  62. // Process the boot options. Really only need to know whether or not we are the boot device, and RAM or ROM.
  63. // But the other checking is done for diagnostic purposes (at least in checked builds).
  64. //
  65. Options = LoaderBlock->LoadOptions;
  66. if (!Options) {
  67. return;
  68. }
  69. XIPBoot = strstr(Options, "XIPBOOT");
  70. XIPRom = strstr(Options, "XIPROM=");
  71. XIPRam = strstr(Options, "XIPRAM=");
  72. XIPSize = strstr(Options, "XIPMEGS=");
  73. XIPVerbose = strstr(Options, "XIPVERBOSE");
  74. if (XIPVerbose) {
  75. DbgPrint("\n\nXIP: debug timestamp at line %d in %s: <<<%s %s>>>\n\n\n", __LINE__, __FILE__, __DATE__, __TIME__);
  76. }
  77. XIPMemoryDescriptor = XIPpFindMemoryDescriptor(LoaderBlock);
  78. if (!XIPMemoryDescriptor) {
  79. return;
  80. }
  81. if (XIPVerbose) {
  82. DbgPrint("XIP: Base %x Count %x\n", XIPMemoryDescriptor->BasePage, XIPMemoryDescriptor->PageCount);
  83. }
  84. if (XIPRom && XIPRam) {
  85. return;
  86. }
  87. if (!XIPRom && !XIPRam) {
  88. return;
  89. }
  90. sizestr = XIPSize? strchr(XIPSize, '=') : NULL;
  91. if (sizestr) {
  92. nmegs = (ULONG) atol(sizestr+1);
  93. }
  94. if (nmegs == 0) {
  95. return;
  96. }
  97. if (XIPVerbose && XIPMemoryDescriptor->PageCount != nmegs * 1024*1024 / PAGE_SIZE) {
  98. DbgPrint("XIPMEGS=%d in boot options is %d pages, but only %d pages were allocated by NTLDR\n",
  99. nmegs * 1024*1024 / PAGE_SIZE,
  100. XIPMemoryDescriptor->PageCount * PAGE_SIZE);
  101. return;
  102. }
  103. //
  104. // Get info from FAT16 boot sector.
  105. // We only need to map one page, so we've allocated an MDL on the stack.
  106. //
  107. //
  108. // Temporarily map the page with the boot sector so we can unpack it.
  109. //
  110. physicalAddress.QuadPart = XIPMemoryDescriptor->BasePage * PAGE_SIZE;
  111. pboot = (PPACKED_BOOT_SECTOR) MmMapIoSpace(physicalAddress, PAGE_SIZE, MmCached);
  112. if (!pboot) {
  113. return;
  114. }
  115. FatUnpackBios(&bios, &pboot->PackedBpb);
  116. MmUnmapIoSpace (pboot, PAGE_SIZE);
  117. //
  118. // Check Bios parameters
  119. //
  120. if (bios.BytesPerSector != 512
  121. || FatBytesPerCluster(&bios) != PAGE_SIZE
  122. || FatFileAreaLbo(&bios) & (PAGE_SIZE-1)) {
  123. if (XIPVerbose) {
  124. DbgPrint("XIP: Malformed FAT Filesystem: BytesPerSector=%x BytesPerCluster=%x ClusterZeroOffset=%x\n",
  125. bios.BytesPerSector, FatBytesPerCluster(&bios), FatFileAreaLbo(&bios));
  126. }
  127. return;
  128. }
  129. //
  130. // Boot.ini parameters and Bios parameters were ok, so initialize the XIP configuration.
  131. //
  132. XIPConfiguration = ExAllocatePoolWithTag (NonPagedPool, sizeof(*XIPConfiguration), XIP_POOLTAG);
  133. if (!XIPConfiguration) {
  134. return;
  135. }
  136. XIPConfigured = TRUE;
  137. XIPConfiguration->BiosParameterBlock = bios;
  138. XIPConfiguration->BootParameters.SystemDrive = XIPBoot? TRUE : FALSE;
  139. XIPConfiguration->BootParameters.ReadOnly = XIPRom? TRUE : FALSE;
  140. XIPConfiguration->BootParameters.BasePage = XIPMemoryDescriptor->BasePage;
  141. XIPConfiguration->BootParameters.PageCount = XIPMemoryDescriptor->PageCount;
  142. XIPConfiguration->ClusterZeroPage = FatFileAreaLbo(&bios) >> PAGE_SHIFT;
  143. return;
  144. }
  145. NTSTATUS
  146. XIPDispatch(
  147. IN XIPCMD Command,
  148. IN OUT PVOID ParameterBuffer OPTIONAL,
  149. IN ULONG BufferSize
  150. )
  151. /*++
  152. Routine Description:
  153. This routine sets up the boot parameter information for XIP Rom.
  154. Arguments:
  155. Environment:
  156. Only to be called at INIT time.
  157. --*/
  158. {
  159. ULONG sz;
  160. if (!XIPConfiguration) {
  161. return STATUS_NO_SUCH_DEVICE;
  162. }
  163. switch (Command) {
  164. case XIPCMD_GETBOOTPARAMETERS:
  165. sz = sizeof(XIPConfiguration->BootParameters);
  166. if (sz != BufferSize) {
  167. break;
  168. }
  169. RtlCopyMemory(ParameterBuffer, &XIPConfiguration->BootParameters, sz);
  170. return STATUS_SUCCESS;
  171. case XIPCMD_GETBIOSPARAMETERS:
  172. sz = sizeof(XIPConfiguration->BiosParameterBlock);
  173. if (sz != BufferSize) {
  174. break;
  175. }
  176. RtlCopyMemory(ParameterBuffer, &XIPConfiguration->BiosParameterBlock, sz);
  177. return STATUS_SUCCESS;
  178. case XIPCMD_NOOP:
  179. if (BufferSize) {
  180. break;
  181. }
  182. return STATUS_SUCCESS;
  183. }
  184. return STATUS_INVALID_PARAMETER;
  185. }
  186. ////////////////////////////
  187. // DEBUG
  188. int XIPlocate_noisy = 0;
  189. int XIPlocate_breakin = 0;
  190. int XIPlocate_disable = 0;
  191. struct {
  192. int attempted;
  193. int bounced;
  194. int succeeded;
  195. int no_irp;
  196. int no_devobj;
  197. int no_contig;
  198. int no_endofdisk;
  199. } XIPlocatecnt;
  200. ////////////////////////////
  201. NTSTATUS
  202. XIPLocatePages(
  203. IN PFILE_OBJECT FileObject,
  204. OUT PPHYSICAL_ADDRESS PhysicalAddress
  205. )
  206. /*++
  207. Routine Description:
  208. Return the requested XIP physical address. If the requested page range
  209. is not contiguous in the file, or there is any other problem, the routine fails.
  210. Arguments:
  211. FileObject - the file of interest
  212. PhysicalAddress - used to return the physical address of the start of the file in ROM.
  213. Environment:
  214. Kernel
  215. --*/
  216. {
  217. STARTING_VCN_INPUT_BUFFER startingvcn;
  218. RETRIEVAL_POINTERS_BUFFER retrbuf;
  219. IO_STATUS_BLOCK iostatus;
  220. PDEVICE_OBJECT deviceObject;
  221. PIO_STACK_LOCATION irpSp;
  222. NTSTATUS status;
  223. KEVENT event;
  224. PIRP irp;
  225. PFN_NUMBER firstPage, numberOfPages;
  226. PDEVICE_OBJECT xipDeviceObject;
  227. xipDeviceObject = FileObject->DeviceObject;
  228. if (!XIPConfiguration) {
  229. return STATUS_NO_SUCH_DEVICE;
  230. }
  231. if (!xipDeviceObject || !(xipDeviceObject->Flags & DO_XIP)) {
  232. return STATUS_INVALID_DEVICE_REQUEST;
  233. }
  234. ////////////////
  235. XIPlocatecnt.attempted++;
  236. ////////////////
  237. startingvcn.StartingVcn.QuadPart = 0;
  238. deviceObject = IoGetRelatedDeviceObject(FileObject);
  239. if (!deviceObject) {
  240. ////////////////
  241. XIPlocatecnt.no_devobj++;
  242. ////////////////
  243. return STATUS_INVALID_DEVICE_REQUEST;
  244. }
  245. //
  246. // Ask fat for the retrieval pointers (relative to cluster 0).
  247. //
  248. irp = IoBuildDeviceIoControlRequest(
  249. FSCTL_GET_RETRIEVAL_POINTERS,
  250. deviceObject,
  251. &startingvcn,
  252. sizeof(startingvcn),
  253. &retrbuf,
  254. sizeof(retrbuf),
  255. FALSE,
  256. &event,
  257. &iostatus);
  258. if (!irp) {
  259. ////////////////
  260. XIPlocatecnt.no_irp++;
  261. ////////////////
  262. return STATUS_INSUFFICIENT_RESOURCES;
  263. }
  264. irp->Flags |= IRP_SYNCHRONOUS_API;
  265. irp->Tail.Overlay.OriginalFileObject = FileObject;
  266. irpSp = IoGetNextIrpStackLocation( irp );
  267. irpSp->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
  268. irpSp->MinorFunction = IRP_MN_USER_FS_REQUEST;
  269. irpSp->FileObject = FileObject;
  270. //
  271. // Take out another reference to the file object to match I/O completion will deref.
  272. //
  273. ObReferenceObject( FileObject );
  274. //
  275. // Do the FSCTL
  276. //
  277. KeInitializeEvent( &event, NotificationEvent, FALSE );
  278. status = IoCallDriver( deviceObject, irp );
  279. if (status == STATUS_PENDING) {
  280. KeWaitForSingleObject( &event, Suspended, KernelMode, FALSE, NULL );
  281. status = iostatus.Status;
  282. }
  283. if (!NT_SUCCESS(iostatus.Status)
  284. || retrbuf.ExtentCount != 1
  285. || retrbuf.Extents[0].Lcn.HighPart
  286. || retrbuf.Extents[0].NextVcn.HighPart
  287. || retrbuf.StartingVcn.QuadPart != 0L) {
  288. ////////////////
  289. XIPlocatecnt.no_contig++;
  290. ////////////////
  291. return STATUS_UNSUCCESSFUL;
  292. }
  293. firstPage = XIPConfiguration->BootParameters.BasePage
  294. + XIPConfiguration->ClusterZeroPage
  295. + retrbuf.Extents[0].Lcn.LowPart;
  296. numberOfPages = retrbuf.Extents[0].NextVcn.LowPart;
  297. if (firstPage + numberOfPages > XIPConfiguration->BootParameters.BasePage
  298. + XIPConfiguration->BootParameters.PageCount) {
  299. XIPlocatecnt.no_endofdisk++;
  300. return STATUS_DISK_CORRUPT_ERROR;
  301. }
  302. ////////////////
  303. ////////////////
  304. if (XIPlocate_noisy || XIPlocate_breakin) {
  305. DbgPrint("Break top of XIPLocatePages. bounced=%x attempted=%x succeeded=%x\n"
  306. " %x nt!XIPlocate_disable %s\n"
  307. " %x nt!XIPlocate_breakin %s\n"
  308. " %x nt!XIPConfiguration\n"
  309. " Would have returned address %x (npages was %x)\n",
  310. XIPlocatecnt.bounced, XIPlocatecnt.attempted, XIPlocatecnt.succeeded,
  311. &XIPlocate_disable, XIPlocate_disable? "DISABLED" : "enabled",
  312. &XIPlocate_breakin, XIPlocate_breakin? "WILL BREAK" : "no break",
  313. XIPConfiguration, firstPage, numberOfPages);
  314. if (XIPlocate_breakin) {
  315. DbgBreakPoint();
  316. }
  317. }
  318. if (XIPlocate_disable) {
  319. XIPlocatecnt.bounced++;
  320. return STATUS_DEVICE_OFF_LINE;
  321. }
  322. XIPlocatecnt.succeeded++;
  323. ////////////////
  324. ////////////////
  325. PhysicalAddress->QuadPart = firstPage << PAGE_SHIFT;
  326. return STATUS_SUCCESS;
  327. }
  328. //
  329. // Local support routine
  330. //
  331. //
  332. // Find the XIP memory descriptor
  333. // Called only at INIT.
  334. //
  335. PMEMORY_ALLOCATION_DESCRIPTOR
  336. XIPpFindMemoryDescriptor(
  337. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  338. )
  339. {
  340. PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
  341. PLIST_ENTRY NextMd;
  342. for (NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
  343. NextMd != &LoaderBlock->MemoryDescriptorListHead;
  344. NextMd = MemoryDescriptor->ListEntry.Flink
  345. )
  346. {
  347. MemoryDescriptor = CONTAINING_RECORD(NextMd,
  348. MEMORY_ALLOCATION_DESCRIPTOR,
  349. ListEntry);
  350. if (MemoryDescriptor->MemoryType == LoaderXIPRom) {
  351. return MemoryDescriptor;
  352. }
  353. }
  354. return NULL;
  355. }
  356. #endif //__X86__