f7b4266a4634859101a673789f0ff35145793630
[reactos.git] / reactos / boot / freeldr / freeldr / drivemap.c
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <freeldr.h>
21 #include <drivemap.h>
22 #include <rtl.h>
23 #include <inifile.h>
24 #include <cache.h>
25 #include <ui.h>
26 #include <debug.h>
27
28 BOOL DriveMapInstalled = FALSE; // Tells us if we have already installed our drive map int 13h handler code
29 ULONG OldInt13HandlerAddress = 0; // Address of BIOS int 13h handler
30 ULONG DriveMapHandlerAddress = 0; // Linear address of our drive map handler
31 ULONG DriveMapHandlerSegOff = 0; // Segment:offset style address of our drive map handler
32
33 VOID DriveMapMapDrivesInSection(PCHAR SectionName)
34 {
35 CHAR SettingName[80];
36 CHAR SettingValue[80];
37 CHAR ErrorText[260];
38 CHAR Drive1[80];
39 CHAR Drive2[80];
40 ULONG SectionId;
41 ULONG SectionItemCount;
42 ULONG Index;
43 ULONG Index2;
44 DRIVE_MAP_LIST DriveMapList;
45
46 RtlZeroMemory(&DriveMapList, sizeof(DRIVE_MAP_LIST));
47
48 if (!IniOpenSection(SectionName, &SectionId))
49 {
50 return;
51 }
52
53 // Get the number of items in this section
54 SectionItemCount = IniGetNumSectionItems(SectionId);
55
56 // Loop through each one and check if its a DriveMap= setting
57 for (Index=0; Index<SectionItemCount; Index++)
58 {
59 // Get the next setting from the .ini file section
60 if (IniReadSettingByNumber(SectionId, Index, SettingName, 80, SettingValue, 80))
61 {
62 if (stricmp(SettingName, "DriveMap") == 0)
63 {
64 // Make sure we haven't exceeded the drive map max count
65 if (DriveMapList.DriveMapCount >= 4)
66 {
67 sprintf(ErrorText, "Max DriveMap count exceeded in section [%s]:\n\n%s=%s", SectionName, SettingName, SettingValue);
68 UiMessageBox(ErrorText);
69 continue;
70 }
71
72 RtlZeroMemory(Drive1, 80);
73 RtlZeroMemory(Drive2, 80);
74
75 strcpy(Drive1, SettingValue);
76
77 // Parse the setting value and separate a string "hd0,hd1"
78 // into two strings "hd0" and "hd1"
79 for (Index2=0; Index2<strlen(Drive1); Index2++)
80 {
81 // Check if this character is the separater character (comma - ',')
82 if (Drive1[Index2] == ',')
83 {
84 Drive1[Index2] = '\0';
85 strcpy(Drive2, &Drive1[Index2+1]);
86 break;
87 }
88 }
89
90 // Make sure we got good values before we add them to the map
91 if (!DriveMapIsValidDriveString(Drive1) || !DriveMapIsValidDriveString(Drive2))
92 {
93 sprintf(ErrorText, "Error in DriveMap setting in section [%s]:\n\n%s=%s", SectionName, SettingName, SettingValue);
94 UiMessageBox(ErrorText);
95 continue;
96 }
97
98 // Add them to the map
99 DriveMapList.DriveMap[(DriveMapList.DriveMapCount * 2)] = DriveMapGetBiosDriveNumber(Drive1);
100 DriveMapList.DriveMap[(DriveMapList.DriveMapCount * 2)+1] = DriveMapGetBiosDriveNumber(Drive2);
101 DriveMapList.DriveMapCount++;
102
103 DbgPrint((DPRINT_WARNING, "Mapping BIOS drive 0x%x to drive 0x%x\n", DriveMapGetBiosDriveNumber(Drive1), DriveMapGetBiosDriveNumber(Drive2)));
104 }
105 }
106 }
107
108 if (DriveMapList.DriveMapCount)
109 {
110 DbgPrint((DPRINT_WARNING, "Installing Int13 drive map for %d drives.\n", DriveMapList.DriveMapCount));
111 DriveMapInstallInt13Handler(&DriveMapList);
112 }
113 else
114 {
115 DbgPrint((DPRINT_WARNING, "Removing any previously installed Int13 drive map.\n"));
116 DriveMapRemoveInt13Handler();
117 }
118 }
119
120 BOOL DriveMapIsValidDriveString(PCHAR DriveString)
121 {
122 ULONG Index;
123
124 // Now verify that the user has given us appropriate strings
125 if ((strlen(DriveString) < 3) ||
126 ((DriveString[0] != 'f') && (DriveString[0] != 'F') && (DriveString[0] != 'h') && (DriveString[0] != 'H')) ||
127 ((DriveString[1] != 'd') && (DriveString[1] != 'D')))
128 {
129 return FALSE;
130 }
131
132 // Now verify that the user has given us appropriate numbers
133 // Make sure that only numeric characters were given
134 for (Index=2; Index<strlen(DriveString); Index++)
135 {
136 if (DriveString[Index] < '0' || DriveString[Index] > '9')
137 {
138 return FALSE;
139 }
140 }
141 // Now make sure that they are not outrageous values (i.e. hd90874)
142 if ((atoi(&DriveString[2]) < 0) || (atoi(&DriveString[2]) > 0xff))
143 {
144 return FALSE;
145 }
146
147 return TRUE;
148 }
149
150 ULONG DriveMapGetBiosDriveNumber(PCHAR DeviceName)
151 {
152 ULONG BiosDriveNumber = 0;
153
154 // If they passed in a number string then just
155 // convert it to decimal and return it
156 if (DeviceName[0] >= '0' && DeviceName[0] <= '9')
157 {
158 return atoi(DeviceName);
159 }
160
161 // Convert the drive number string into a number
162 // 'hd1' = 1
163 BiosDriveNumber = atoi(&DeviceName[2]);
164
165 // If it's a hard disk then set the high bit
166 if ((DeviceName[0] == 'h' || DeviceName[0] == 'H') &&
167 (DeviceName[1] == 'd' || DeviceName[1] == 'D'))
168 {
169 BiosDriveNumber |= 0x80;
170 }
171
172 return BiosDriveNumber;
173 }
174
175 VOID DriveMapInstallInt13Handler(PDRIVE_MAP_LIST DriveMap)
176 {
177 ULONG* RealModeIVT = (ULONG*)0x00000000;
178 USHORT* BiosLowMemorySize = (USHORT*)0x00000413;
179
180 if (!DriveMapInstalled)
181 {
182 // Get the old INT 13h handler address from the vector table
183 OldInt13HandlerAddress = RealModeIVT[0x13];
184
185 // Decrease the size of low memory
186 (*BiosLowMemorySize)--;
187
188 // Get linear address for drive map handler
189 DriveMapHandlerAddress = (ULONG)(*BiosLowMemorySize) << 10;
190
191 // Convert to segment:offset style address
192 DriveMapHandlerSegOff = (DriveMapHandlerAddress << 12) & 0xffff0000;
193 }
194
195 // Copy the drive map structure to the proper place
196 RtlCopyMemory(&DriveMapInt13HandlerMapList, DriveMap, sizeof(DRIVE_MAP_LIST));
197
198 // Set the address of the BIOS INT 13h handler
199 DriveMapOldInt13HandlerAddress = OldInt13HandlerAddress;
200
201 // Copy the code to our reserved area
202 RtlCopyMemory((PVOID)DriveMapHandlerAddress, &DriveMapInt13HandlerStart, ((ULONG)&DriveMapInt13HandlerEnd - (ULONG)&DriveMapInt13HandlerStart));
203
204 // Update the IVT
205 RealModeIVT[0x13] = DriveMapHandlerSegOff;
206
207 CacheInvalidateCacheData();
208 DriveMapInstalled = TRUE;
209 }
210
211 VOID DriveMapRemoveInt13Handler(VOID)
212 {
213 ULONG* RealModeIVT = (ULONG*)0x00000000;
214 USHORT* BiosLowMemorySize = (USHORT*)0x00000413;
215
216 if (DriveMapInstalled)
217 {
218 // Get the old INT 13h handler address from the vector table
219 RealModeIVT[0x13] = OldInt13HandlerAddress;
220
221 // Increase the size of low memory
222 (*BiosLowMemorySize)++;
223
224 CacheInvalidateCacheData();
225 DriveMapInstalled = FALSE;
226 }
227 }