Merge 25584, 25588.
[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
22 #define NDEBUG
23 #include <debug.h>
24
25 BOOLEAN DriveMapInstalled = FALSE; // Tells us if we have already installed our drive map int 13h handler code
26 ULONG OldInt13HandlerAddress = 0; // Address of BIOS int 13h handler
27 ULONG DriveMapHandlerAddress = 0; // Linear address of our drive map handler
28 ULONG DriveMapHandlerSegOff = 0; // Segment:offset style address of our drive map handler
29
30 VOID DriveMapMapDrivesInSection(PCSTR SectionName)
31 {
32 CHAR SettingName[80];
33 CHAR SettingValue[80];
34 CHAR ErrorText[260];
35 CHAR Drive1[80];
36 CHAR Drive2[80];
37 ULONG SectionId;
38 ULONG SectionItemCount;
39 ULONG Index;
40 ULONG Index2;
41 DRIVE_MAP_LIST DriveMapList;
42
43 RtlZeroMemory(&DriveMapList, sizeof(DRIVE_MAP_LIST));
44
45 if (!IniOpenSection(SectionName, &SectionId))
46 {
47 return;
48 }
49
50 // Get the number of items in this section
51 SectionItemCount = IniGetNumSectionItems(SectionId);
52
53 // Loop through each one and check if its a DriveMap= setting
54 for (Index=0; Index<SectionItemCount; Index++)
55 {
56 // Get the next setting from the .ini file section
57 if (IniReadSettingByNumber(SectionId, Index, SettingName, sizeof(SettingName), SettingValue, sizeof(SettingValue)))
58 {
59 if (_stricmp(SettingName, "DriveMap") == 0)
60 {
61 // Make sure we haven't exceeded the drive map max count
62 if (DriveMapList.DriveMapCount >= 4)
63 {
64 sprintf(ErrorText, "Max DriveMap count exceeded in section [%s]:\n\n%s=%s", SectionName, SettingName, SettingValue);
65 UiMessageBox(ErrorText);
66 continue;
67 }
68
69 RtlZeroMemory(Drive1, 80);
70 RtlZeroMemory(Drive2, 80);
71
72 strcpy(Drive1, SettingValue);
73
74 // Parse the setting value and separate a string "hd0,hd1"
75 // into two strings "hd0" and "hd1"
76 for (Index2=0; Index2<strlen(Drive1); Index2++)
77 {
78 // Check if this character is the separater character (comma - ',')
79 if (Drive1[Index2] == ',')
80 {
81 Drive1[Index2] = '\0';
82 strcpy(Drive2, &Drive1[Index2+1]);
83 break;
84 }
85 }
86
87 // Make sure we got good values before we add them to the map
88 if (!DriveMapIsValidDriveString(Drive1) || !DriveMapIsValidDriveString(Drive2))
89 {
90 sprintf(ErrorText, "Error in DriveMap setting in section [%s]:\n\n%s=%s", SectionName, SettingName, SettingValue);
91 UiMessageBox(ErrorText);
92 continue;
93 }
94
95 // Add them to the map
96 DriveMapList.DriveMap[(DriveMapList.DriveMapCount * 2)] = DriveMapGetBiosDriveNumber(Drive1);
97 DriveMapList.DriveMap[(DriveMapList.DriveMapCount * 2)+1] = DriveMapGetBiosDriveNumber(Drive2);
98 DriveMapList.DriveMapCount++;
99
100 DbgPrint((DPRINT_WARNING, "Mapping BIOS drive 0x%x to drive 0x%x\n", DriveMapGetBiosDriveNumber(Drive1), DriveMapGetBiosDriveNumber(Drive2)));
101 }
102 }
103 }
104
105 if (DriveMapList.DriveMapCount)
106 {
107 DbgPrint((DPRINT_WARNING, "Installing Int13 drive map for %d drives.\n", DriveMapList.DriveMapCount));
108 DriveMapInstallInt13Handler(&DriveMapList);
109 }
110 else
111 {
112 DbgPrint((DPRINT_WARNING, "Removing any previously installed Int13 drive map.\n"));
113 DriveMapRemoveInt13Handler();
114 }
115 }
116
117 BOOLEAN DriveMapIsValidDriveString(PCSTR DriveString)
118 {
119 ULONG Index;
120
121 // Now verify that the user has given us appropriate strings
122 if ((strlen(DriveString) < 3) ||
123 ((DriveString[0] != 'f') && (DriveString[0] != 'F') && (DriveString[0] != 'h') && (DriveString[0] != 'H')) ||
124 ((DriveString[1] != 'd') && (DriveString[1] != 'D')))
125 {
126 return FALSE;
127 }
128
129 // Now verify that the user has given us appropriate numbers
130 // Make sure that only numeric characters were given
131 for (Index=2; Index<strlen(DriveString); Index++)
132 {
133 if (DriveString[Index] < '0' || DriveString[Index] > '9')
134 {
135 return FALSE;
136 }
137 }
138 // Now make sure that they are not outrageous values (i.e. hd90874)
139 if ((atoi(&DriveString[2]) < 0) || (atoi(&DriveString[2]) > 0xff))
140 {
141 return FALSE;
142 }
143
144 return TRUE;
145 }
146
147 ULONG DriveMapGetBiosDriveNumber(PCSTR DeviceName)
148 {
149 ULONG BiosDriveNumber = 0;
150
151 // If they passed in a number string then just
152 // convert it to decimal and return it
153 if (DeviceName[0] >= '0' && DeviceName[0] <= '9')
154 {
155 return atoi(DeviceName);
156 }
157
158 // Convert the drive number string into a number
159 // 'hd1' = 1
160 BiosDriveNumber = atoi(&DeviceName[2]);
161
162 // If it's a hard disk then set the high bit
163 if ((DeviceName[0] == 'h' || DeviceName[0] == 'H') &&
164 (DeviceName[1] == 'd' || DeviceName[1] == 'D'))
165 {
166 BiosDriveNumber |= 0x80;
167 }
168
169 return BiosDriveNumber;
170 }
171
172 VOID DriveMapInstallInt13Handler(PDRIVE_MAP_LIST DriveMap)
173 {
174 ULONG* RealModeIVT = (ULONG*)0x00000000;
175 USHORT* BiosLowMemorySize = (USHORT*)0x00000413;
176
177 if (!DriveMapInstalled)
178 {
179 // Get the old INT 13h handler address from the vector table
180 OldInt13HandlerAddress = RealModeIVT[0x13];
181
182 // Decrease the size of low memory
183 (*BiosLowMemorySize)--;
184
185 // Get linear address for drive map handler
186 DriveMapHandlerAddress = (ULONG)(*BiosLowMemorySize) << 10;
187
188 // Convert to segment:offset style address
189 DriveMapHandlerSegOff = (DriveMapHandlerAddress << 12) & 0xffff0000;
190 }
191
192 // Copy the drive map structure to the proper place
193 RtlCopyMemory(&DriveMapInt13HandlerMapList, DriveMap, sizeof(DRIVE_MAP_LIST));
194
195 // Set the address of the BIOS INT 13h handler
196 DriveMapOldInt13HandlerAddress = OldInt13HandlerAddress;
197
198 // Copy the code to our reserved area
199 RtlCopyMemory((PVOID)DriveMapHandlerAddress, &DriveMapInt13HandlerStart, ((ULONG)&DriveMapInt13HandlerEnd - (ULONG)&DriveMapInt13HandlerStart));
200
201 // Update the IVT
202 RealModeIVT[0x13] = DriveMapHandlerSegOff;
203
204 CacheInvalidateCacheData();
205 DriveMapInstalled = TRUE;
206 }
207
208 VOID DriveMapRemoveInt13Handler(VOID)
209 {
210 ULONG* RealModeIVT = (ULONG*)0x00000000;
211 USHORT* BiosLowMemorySize = (USHORT*)0x00000413;
212
213 if (DriveMapInstalled)
214 {
215 // Get the old INT 13h handler address from the vector table
216 RealModeIVT[0x13] = OldInt13HandlerAddress;
217
218 // Increase the size of low memory
219 (*BiosLowMemorySize)++;
220
221 CacheInvalidateCacheData();
222 DriveMapInstalled = FALSE;
223 }
224 }