[driver,bus] Move WvBus* subjects into new bus.c
[people/sha0/winvblock.git] / src / winvblock / ramdisk / grub4dos.c
1 /**
2  * Copyright (C) 2009-2011, Shao Miller <shao.miller@yrdsb.edu.on.ca>.
3  *
4  * This file is part of WinVBlock, derived from WinAoE.
5  *
6  * WinVBlock is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * WinVBlock is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with WinVBlock.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 /**
21  * @file
22  *
23  * GRUB4DOS RAM disk specifics.
24  */
25
26 #include <stdio.h>
27 #include <ntddk.h>
28
29 #include "portable.h"
30 #include "winvblock.h"
31 #include "wv_string.h"
32 #include "driver.h"
33 #include "bus.h"
34 #include "device.h"
35 #include "disk.h"
36 #include "ramdisk.h"
37 #include "debug.h"
38 #include "probe.h"
39 #include "grub4dos.h"
40
41 VOID ramdisk_grub4dos__find(void) {
42   PHYSICAL_ADDRESS PhysicalAddress;
43   PUCHAR PhysicalMemory;
44   WV_SP_PROBE_INT_VECTOR InterruptVector;
45   UINT32 Int13Hook;
46   WV_SP_PROBE_SAFE_MBR_HOOK SafeMbrHookPtr;
47   WV_SP_GRUB4DOS_DRIVE_MAPPING Grub4DosDriveMapSlotPtr;
48   UINT32 i = 8;
49   BOOLEAN FoundGrub4DosMapping = FALSE;
50   WV_SP_RAMDISK_T ramdisk_ptr;
51
52   /*
53    * Find a GRUB4DOS memory-mapped disk.  Start by looking at the
54    * real-mode IDT and following the "SafeMBRHook" INT 0x13 hook
55    */
56   PhysicalAddress.QuadPart = 0LL;
57   PhysicalMemory = MmMapIoSpace ( PhysicalAddress, 0x100000, MmNonCached );
58   if ( !PhysicalMemory )
59     {
60       DBG ( "Could not map low memory\n" );
61       return;
62     }
63   InterruptVector =
64     (WV_SP_PROBE_INT_VECTOR) (PhysicalMemory + 0x13 * sizeof *InterruptVector);
65   /* Walk the "safe hook" chain of INT 13h hooks as far as possible. */
66   while (SafeMbrHookPtr = WvProbeGetSafeHook(PhysicalMemory, InterruptVector)) {
67       if (!wv_memcmpeq(
68           SafeMbrHookPtr->VendorId,
69           "GRUB4DOS",
70           sizeof "GRUB4DOS" - 1
71         )) {
72           DBG ( "Non-GRUB4DOS INT 0x13 Safe Hook\n" );
73           InterruptVector = &SafeMbrHookPtr->PrevHook;
74           continue;
75         }
76       Grub4DosDriveMapSlotPtr = (WV_SP_GRUB4DOS_DRIVE_MAPPING) (
77           PhysicalMemory +
78           (((UINT32) InterruptVector->Segment) << 4) +
79           0x20
80         );
81       while ( i-- )
82         {
83           DBG ( "GRUB4DOS SourceDrive: 0x%02x\n",
84                 Grub4DosDriveMapSlotPtr[i].SourceDrive );
85           DBG ( "GRUB4DOS DestDrive: 0x%02x\n",
86                 Grub4DosDriveMapSlotPtr[i].DestDrive );
87           DBG ( "GRUB4DOS MaxHead: %d\n", Grub4DosDriveMapSlotPtr[i].MaxHead );
88           DBG ( "GRUB4DOS MaxSector: %d\n",
89                 Grub4DosDriveMapSlotPtr[i].MaxSector );
90           DBG ( "GRUB4DOS DestMaxCylinder: %d\n",
91                 Grub4DosDriveMapSlotPtr[i].DestMaxCylinder );
92           DBG ( "GRUB4DOS DestMaxHead: %d\n",
93                 Grub4DosDriveMapSlotPtr[i].DestMaxHead );
94           DBG ( "GRUB4DOS DestMaxSector: %d\n",
95                 Grub4DosDriveMapSlotPtr[i].DestMaxSector );
96           DBG ( "GRUB4DOS SectorStart: 0x%08x\n",
97                 Grub4DosDriveMapSlotPtr[i].SectorStart );
98           DBG ( "GRUB4DOS SectorCount: %d\n",
99                 Grub4DosDriveMapSlotPtr[i].SectorCount );
100           if ( !( Grub4DosDriveMapSlotPtr[i].DestDrive == 0xff ) )
101             {
102               DBG ( "Skipping non-RAM disk GRUB4DOS mapping\n" );
103               continue;
104             }
105           ramdisk_ptr = ramdisk__create (  );
106           if ( ramdisk_ptr == NULL )
107             {
108               DBG ( "Could not create GRUB4DOS disk!\n" );
109               return;
110             }
111           /*
112            * Possible precision loss
113            */
114           if ( Grub4DosDriveMapSlotPtr[i].SourceODD )
115             {
116               ramdisk_ptr->disk->Media = WvDiskMediaTypeOptical;
117               ramdisk_ptr->disk->SectorSize = 2048;
118             }
119           else
120             {
121               ramdisk_ptr->disk->Media =
122                 Grub4DosDriveMapSlotPtr[i].SourceDrive & 0x80 ?
123                 WvDiskMediaTypeHard : WvDiskMediaTypeFloppy;
124               ramdisk_ptr->disk->SectorSize = 512;
125             }
126           DBG ( "RAM Drive is type: %d\n", ramdisk_ptr->disk->Media );
127           ramdisk_ptr->DiskBuf =
128             ( UINT32 ) ( Grub4DosDriveMapSlotPtr[i].SectorStart *
129                                     512 );
130           ramdisk_ptr->disk->LBADiskSize = ramdisk_ptr->DiskSize =
131             ( UINT32 ) Grub4DosDriveMapSlotPtr[i].SectorCount;
132           ramdisk_ptr->disk->Heads = Grub4DosDriveMapSlotPtr[i].MaxHead + 1;
133           ramdisk_ptr->disk->Sectors =
134             Grub4DosDriveMapSlotPtr[i].DestMaxSector;
135           ramdisk_ptr->disk->Cylinders =
136             ramdisk_ptr->disk->LBADiskSize / ( ramdisk_ptr->disk->Heads *
137                                                ramdisk_ptr->disk->Sectors );
138           ramdisk_ptr->disk->Dev->Boot = TRUE;
139           FoundGrub4DosMapping = TRUE;
140           /* Add the ramdisk to the bus. */
141           if (!WvBusAddDev(ramdisk_ptr->disk->Dev))
142       WvDevFree(ramdisk_ptr->disk->Dev);
143         }
144       InterruptVector = &SafeMbrHookPtr->PrevHook;
145     }
146
147   MmUnmapIoSpace ( PhysicalMemory, 0x100000 );
148   if ( !FoundGrub4DosMapping )
149     {
150       DBG ( "No GRUB4DOS drive mappings found\n" );
151     }
152 }