aecc4e5255e1d2bb39539a82d2134cf9b11fbb7b
[people/sha0/winvblock.git] / src / winvblock / ramdisk / memdisk.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  * MEMDISK specifics.
24  */
25
26 #include <stdio.h>
27 #include <ntddk.h>
28
29 #include "winvblock.h"
30 #include "wv_string.h"
31 #include "portable.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 "mdi.h"
39 #include "probe.h"
40
41 static winvblock__bool STDCALL WvMemdiskCheckMbft_(
42     winvblock__uint8_ptr phys_mem,
43     winvblock__uint32 offset
44   ) {
45     WV_SP_MDI_MBFT mbft = (WV_SP_MDI_MBFT) (phys_mem + offset);
46     winvblock__uint32 i;
47     winvblock__uint8 chksum = 0;
48     WV_SP_PROBE_SAFE_MBR_HOOK assoc_hook;
49     ramdisk__type_ptr ramdisk;
50
51     if (offset >= 0x100000) {
52         DBG("mBFT physical pointer too high!\n");
53         return FALSE;
54       }
55     if (!wv_memcmpeq(mbft->Signature, "mBFT", sizeof "mBFT" - 1)) return FALSE;
56     if (offset + mbft->Length >= 0x100000) {
57         DBG("mBFT length out-of-bounds\n");
58         return FALSE;
59       }
60     for (i = 0; i < mbft->Length; i++)
61       chksum += ((winvblock__uint8 *) mbft)[i];
62     if (chksum) {
63         DBG("Invalid mBFT checksum\n");
64         return FALSE;
65       }
66     DBG("Found mBFT: 0x%08x\n", mbft);
67     if (mbft->SafeHook >= 0x100000) {
68         DBG("mBFT safe hook physical pointer too high!\n");
69         return FALSE;
70       }
71     assoc_hook =
72       (WV_SP_PROBE_SAFE_MBR_HOOK) (phys_mem + mbft->SafeHook);
73     if (assoc_hook->Flags) {
74         DBG("This MEMDISK already processed\n");
75         return TRUE;
76       }
77     DBG("MEMDISK DiskBuf: 0x%08x\n", mbft->mdi.diskbuf);
78     DBG("MEMDISK DiskSize: %d sectors\n", mbft->mdi.disksize);
79     ramdisk = ramdisk__create();
80     if (ramdisk == NULL) {
81         DBG("Could not create MEMDISK disk!\n");
82         return FALSE;
83       }
84     ramdisk->DiskBuf = mbft->mdi.diskbuf;
85     ramdisk->disk->LBADiskSize = ramdisk->DiskSize = mbft->mdi.disksize;
86     if (mbft->mdi.driveno == 0xE0) {
87         ramdisk->disk->Media = WvDiskMediaTypeOptical;
88         ramdisk->disk->SectorSize = 2048;
89       } else {
90         if (mbft->mdi.driveno & 0x80)
91                 ramdisk->disk->Media = WvDiskMediaTypeHard;
92           else
93                 ramdisk->disk->Media = WvDiskMediaTypeFloppy;
94         ramdisk->disk->SectorSize = 512;
95       }
96     DBG("RAM Drive is type: %d\n", ramdisk->disk->Media);
97     ramdisk->disk->Cylinders = mbft->mdi.cylinders;
98     ramdisk->disk->Heads = mbft->mdi.heads;
99     ramdisk->disk->Sectors = mbft->mdi.sectors;
100     ramdisk->disk->Dev->Boot = TRUE;
101
102     /* Add the ramdisk to the bus. */
103     if (!WvDriverBusAddDev(ramdisk->disk->Dev)) {
104         WvDevFree(ramdisk->disk->Dev);
105         return FALSE;
106       }
107     assoc_hook->Flags = 1;
108     return TRUE;
109   }
110
111 void WvMemdiskFind(void) {
112     PHYSICAL_ADDRESS phys_addr;
113     winvblock__uint8_ptr phys_mem;
114     WV_SP_PROBE_INT_VECTOR int_vector;
115     WV_SP_PROBE_SAFE_MBR_HOOK safe_mbr_hook;
116     winvblock__uint32 offset;
117     winvblock__bool found = FALSE;
118
119     /* Find a MEMDISK.  We check the "safe hook" chain, then scan for mBFTs. */
120     phys_addr.QuadPart = 0LL;
121     phys_mem = MmMapIoSpace(phys_addr, 0x100000, MmNonCached);
122     if (!phys_mem) {
123         DBG("Could not map low memory\n");
124         return;
125       }
126     int_vector =
127       (WV_SP_PROBE_INT_VECTOR) (phys_mem + 0x13 * sizeof *int_vector);
128     /* Walk the "safe hook" chain of INT 13h hooks as far as possible. */
129     while (safe_mbr_hook = WvProbeGetSafeHook(phys_mem, int_vector)) {
130         if (!wv_memcmpeq(safe_mbr_hook->VendorId, "MEMDISK ", 8)) {
131                   DBG("Non-MEMDISK INT 0x13 Safe Hook\n");
132                 } else {
133                   found |= WvMemdiskCheckMbft_(phys_mem, safe_mbr_hook->Mbft);
134                 }
135         int_vector = &safe_mbr_hook->PrevHook;
136       }
137     /* Now search for "floating" mBFTs. */
138     for (offset = 0; offset < 0xFFFF0; offset += 0x10) {
139         found |= WvMemdiskCheckMbft_(phys_mem, offset);
140       }
141     MmUnmapIoSpace(phys_mem, 0x100000);
142     if (!found) {
143         DBG("No MEMDISKs found\n");
144       }
145   }