VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-rm-InitHighDlls.c@ 106560

Last change on this file since 106560 was 106061, checked in by vboxsync, 5 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.6 KB
Line 
1/* $Id: bs3-rm-InitHighDlls.c 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * BS3Kit - Initialize any high DLLs, real mode.
4 */
5
6/*
7 * Copyright (C) 2007-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41//#define BS3_USE_RM_TEXT_SEG 1
42#include "bs3kit-template-header.h"
43#include "bs3kit-linker.h"
44#include "bs3-cmn-memory.h"
45
46
47extern BS3HIGHDLLENTRY BS3_FAR_DATA BS3_DATA_NM(g_aBs3HighDllTable)[];
48extern BS3HIGHDLLENTRY BS3_FAR_DATA BS3_DATA_NM(g_Bs3HighDllTable_End);
49
50
51
52/**
53 * Load the DLL. This is where we ASSUME real-mode, pre-PIC setup,
54 * and interrupts enabled as we need to use int13 for the actual
55 * reading. We switch to 32-bit protected mode and copies the
56 * chunk from pbBuf and to the actual load address.
57 *
58 * Note! When reading we must make sure to not switch head as the
59 * BIOS code messes up the result if it does the wraparound.
60 */
61static void bs3InitHighDllLoadImage(BS3HIGHDLLENTRY RT_FAR * const pHighDllEntry, const char RT_FAR * const pszFilename,
62 uint8_t BS3_FAR * const pbBuf, uint8_t const cBufSectors, uint32_t const uFlatBuf,
63 uint8_t const bDrive, uint8_t const uMaxHead, uint8_t const uMaxSector,
64 uint16_t const cSectorsPerCylinder)
65{
66 int rc;
67#ifdef BS3_WITH_LOAD_CHECKSUMS
68# if 0 /* for debugging */
69 uint32_t iCurSector = 0;
70# endif
71 uint32_t uChecksum = BS3_CALC_CHECKSUM_INITIAL_VALUE;
72#endif
73 uint32_t cSectorsLeftToLoad = pHighDllEntry->cbInImage / 512U;
74 uint32_t uCurFlatLoadAddr = pHighDllEntry->uLoadAddr;
75 /* Calculate the current CHS position: */
76 uint32_t const uCurSectorInImage = pHighDllEntry->offInImage / 512U;
77 uint16_t uCylinder = uCurSectorInImage / cSectorsPerCylinder;
78 uint16_t const uRemainder = uCurSectorInImage % cSectorsPerCylinder;
79 uint8_t uHead = uRemainder / uMaxSector;
80 uint8_t uSector = (uRemainder % uMaxSector) + 1;
81 while (cSectorsLeftToLoad > 0)
82 {
83 /* Figure out how much we dare read. Only up to the end of the track. */
84 uint8_t cSectors = uMaxSector + 1 - uSector;
85 if (cSectors > cBufSectors)
86 cSectors = cBufSectors;
87 if (cSectorsLeftToLoad < cSectors)
88 cSectors = (uint8_t)(cSectorsLeftToLoad);
89
90 //Bs3TestPrintf("Calling Bs3DiskRead(%#x,%#x,%#x,%#x,%#x,%p) [uCurFlatLoadAddr=%RX32]\n",
91 // bDrive, uCylinder, uHead, uSector, cSectors, pbBuf, uCurFlatLoadAddr);
92 rc = Bs3DiskRead_rm(bDrive, uCylinder, uHead, uSector, cSectors, pbBuf);
93 if (rc != 0)
94 {
95 Bs3TestPrintf("Bs3DiskRead(%#x,%#x,%#x,%#x,%#x,) failed: %#x\n",
96 bDrive, uCylinder, uHead, uSector, cBufSectors, rc);
97 Bs3Shutdown();
98 }
99
100#ifdef BS3_WITH_LOAD_CHECKSUMS
101 /* Checksum what we just loaded. */
102# if 0 /* For debugging. */
103 {
104 uint16_t j;
105 uint32_t uChecksumTmp = uChecksum;
106 for (j = 0; j < cSectors; j++, iCurSector++)
107 Bs3TestPrintf("sector #%RU32: %#RX32 %#010RX32\n", iCurSector,
108 uChecksumTmp = Bs3CalcChecksum(uChecksumTmp, &pbBuf[j * 512U], 512U),
109 Bs3CalcChecksum(BS3_CALC_CHECKSUM_INITIAL_VALUE, &pbBuf[j * 512U], 512U));
110 uChecksum = Bs3CalcChecksum(uChecksum, pbBuf, 512U * cSectors);
111 if (uChecksum != uChecksumTmp)
112 Bs3TestPrintf("Checksum error: %#RX32, expected %#RX32!\n", uChecksum, uChecksumTmp);
113 }
114# else
115 uChecksum = Bs3CalcChecksum(uChecksum, pbBuf, 512U * cSectors);
116# endif
117#endif
118
119 /* Copy the page to where the DLL is being loaded. */
120 Bs3MemCopyFlat_rm_far(uCurFlatLoadAddr, uFlatBuf, 512U * cSectors);
121 Bs3PrintChr('.');
122
123 /* Advance */
124 uCurFlatLoadAddr += cSectors * 512U;
125 cSectorsLeftToLoad -= cSectors;
126 uSector += cSectors;
127 if (!uSector || uSector > uMaxSector)
128 {
129 uSector = 1;
130 uHead++;
131 if (uHead > uMaxHead)
132 {
133 uHead = 0;
134 uCylinder++;
135 }
136 }
137 }
138
139#ifdef BS3_WITH_LOAD_CHECKSUMS
140 /* Verify the checksum. */
141 if (uChecksum != pHighDllEntry->uChecksum)
142 {
143 Bs3TestPrintf("Checksum mismatch for '%s': %#RX32 vs %#RX32\n", pszFilename, uChecksum, pHighDllEntry->uChecksum);
144 Bs3Shutdown();
145 }
146#endif
147}
148
149
150/**
151 * Initializes any special (16-bit) segments for the given high DLL.
152 */
153static void bs3InitHighDllSetUpSegments(BS3HIGHDLLENTRY RT_FAR *pHighDllEntry, const char RT_FAR *pszFilename)
154{
155 PBS3HIGHDLLSEGMENT const paSegments = (PBS3HIGHDLLSEGMENT)((char RT_FAR *)pHighDllEntry + pHighDllEntry->offSegments);
156 unsigned const cSegments = pHighDllEntry->cSegments;
157 unsigned iSeg;
158
159 for (iSeg = 0; iSeg < cSegments; iSeg++)
160 {
161 Bs3Printf("Segment #%u: %#010RX32 LB %#010RX32 idxSel=%#06x fFlags=%#x\n",
162 iSeg, paSegments[iSeg].uAddr, paSegments[iSeg].cb, paSegments[iSeg].idxSel, paSegments[iSeg].fFlags);
163 if (paSegments[iSeg].fFlags & BS3HIGHDLLSEGMENT_F_16BIT)
164 {
165 X86DESC BS3_FAR *pDesc = &Bs3Gdt[paSegments[iSeg].idxSel >> X86_SEL_SHIFT];
166
167 if (paSegments[iSeg].fFlags & BS3HIGHDLLSEGMENT_F_EXEC)
168 {
169 BS3_ASSERT((unsigned)(paSegments[iSeg].idxSel - BS3_SEL_HIGH16_CS_FIRST) < (unsigned)BS3_SEL_HIGH16_CS_COUNT);
170 Bs3SelSetup16BitCode(pDesc, paSegments[iSeg].uAddr, 0);
171 if (paSegments[iSeg].fFlags & BS3HIGHDLLSEGMENT_F_CONFORMING)
172 pDesc->Gen.u4Type = X86_SEL_TYPE_ER_CONF_ACC;
173 //Bs3TestPrintf("Segment #%u: 16-bit code %p %#x\n", iSeg, pDesc, paSegments[iSeg].idxSel);
174 }
175 else
176 {
177 BS3_ASSERT((unsigned)(paSegments[iSeg].idxSel - BS3_SEL_HIGH16_DS_FIRST) < (unsigned)BS3_SEL_HIGH16_DS_COUNT);
178 Bs3SelSetup16BitData(pDesc, paSegments[iSeg].uAddr);
179 //Bs3TestPrintf("Segment #%u: 16-bit data %p %#x\n", iSeg, pDesc, paSegments[iSeg].idxSel);
180 }
181 if (paSegments[iSeg].cb < _64K)
182 pDesc->Gen.u16LimitLow = paSegments[iSeg].cb - 1;
183 }
184 //else
185 // Bs3TestPrintf("Segment #%u: Not 16-bit\n", iSeg);
186 }
187
188}
189
190
191/**
192 * Allocates/reserves the memory backing for the given DLL.
193 */
194static void bs3InitHighDllAllocateMemory(BS3HIGHDLLENTRY RT_FAR *pHighDllEntry, const char RT_FAR *pszFilename)
195{
196 uint16_t const cPagesToLoad = (uint16_t)(pHighDllEntry->cbLoaded / _4K);
197 uint16_t iPage = Bs3SlabAllocFixed(&g_Bs3Mem4KUpperTiled.Core, pHighDllEntry->uLoadAddr, cPagesToLoad);
198 if (iPage == 0 || iPage == UINT16_MAX)
199 {
200 Bs3TestPrintf("Bs3SlabAllocFixed(,%#RX32, %#RX16) failed: %#RX16 (%s)\n",
201 pHighDllEntry->uLoadAddr, cPagesToLoad, iPage, pszFilename);
202 Bs3Shutdown();
203 }
204 /** @todo We don't have any memory management above 16MB... at the moment. */
205}
206
207
208BS3_DECL_FAR(void) Bs3InitHighDlls_rm_far(void)
209{
210 unsigned const cHighDlls = (unsigned)(&g_Bs3HighDllTable_End - &g_aBs3HighDllTable[0]);
211 //Bs3TestPrintf("cHighDlls=%d g_uBs3CpuDetected=%#x Bs3InitHighDlls_rm_far=%p\n", cHighDlls, g_uBs3CpuDetected, &Bs3InitHighDlls_rm_far);
212
213 if ( cHighDlls > 0
214 && (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386)
215 {
216 /*
217 * Get the drive geometry. ASSUMES the bootsector hasn't been trashed yet!
218 */
219 uint8_t const bDrive = ((BS3BOOTSECTOR RT_FAR *)BS3_FP_MAKE(0,0x7c00))->bBootDrv;
220 uint16_t uMaxCylinder = 0;
221 uint8_t uMaxHead = 0;
222 uint8_t uMaxSector = 0;
223 int rc = Bs3DiskQueryGeometry_rm(bDrive, &uMaxCylinder, &uMaxHead, &uMaxSector);
224 //Bs3TestPrintf("Bs3DiskQueryGeometry(%#x)-> C=%#x H=%#x S=%#x\n", bDrive, uMaxCylinder, uMaxHead, uMaxSector);
225 if (rc == 0)
226 {
227 uint16_t const cSectorsPerCylinder = uMaxSector * ((uint16_t)uMaxHead + 1);
228 unsigned i;
229
230 /*
231 * We need a buffer first of all. Try for one able to contain a
232 * full track, as that'll give us the best reading speed.
233 */
234 uint32_t uFlatBuf;
235 uint8_t cBufSectors;
236 uint8_t BS3_FAR *pbBuf;
237 uint16_t cbBuf = uMaxSector >= 72U ? 72U * 512U : uMaxSector * 512U;
238 void BS3_FAR *pvBufAllocated = Bs3MemAlloc(BS3MEMKIND_REAL, cbBuf);
239 if (!pvBufAllocated)
240 {
241 cbBuf = cbBuf >= _32K ? _32K : 1 << ASMBitLastSetU16(cbBuf) /* no - 1!*/; /* converts to a power of two. */
242 for (;;)
243 {
244 pvBufAllocated = Bs3MemAlloc(BS3MEMKIND_REAL, cbBuf);
245 if (pvBufAllocated)
246 break;
247 if (cbBuf <= _4K)
248 {
249 Bs3TestPrintf("Failed to allocate 4 KiB memory buffer for loading high DLL(s)!\n");
250 Bs3Shutdown();
251 }
252 cbBuf >>= 1;
253 }
254 }
255 cBufSectors = (uint8_t)(cbBuf / 512U);
256 uFlatBuf = BS3_FP_REAL_TO_FLAT(pvBufAllocated);
257 pbBuf = (uint8_t BS3_FAR *)BS3_FP_MAKE(uFlatBuf >> 4, 0); /* make sure the whole buffer is within a segment. */
258 /** @todo Is the above pbBuf hack necessary? */
259 //Bs3TestPrintf("pvBufAllocated=%p pbBuf=%p uFlatBuf=%RX32 cbBuf=%#x\n", pvBufAllocated, pbBuf, uFlatBuf, cbBuf);
260
261 /*
262 * Iterate the high DLL table and load it all into memory.
263 */
264 for (i = 0; i < cHighDlls; i++)
265 {
266 const char RT_FAR * const pszzStrings = (char RT_FAR *)&g_aBs3HighDllTable[i] + g_aBs3HighDllTable[i].offStrings;
267 const char RT_FAR * const pszFilename = &pszzStrings[g_aBs3HighDllTable[i].offFilename];
268 Bs3Printf("Loading dll '%s' at %#RX32..%#RX32\n", pszFilename, g_aBs3HighDllTable[i].uLoadAddr,
269 g_aBs3HighDllTable[i].uLoadAddr + g_aBs3HighDllTable[i].cbLoaded - 1);
270
271 /*
272 * Allocate the memory taken by the DLL.
273 */
274 bs3InitHighDllAllocateMemory(&g_aBs3HighDllTable[i], pszFilename);
275
276 /*
277 * Process the segment table.
278 */
279 bs3InitHighDllSetUpSegments(&g_aBs3HighDllTable[i], pszFilename);
280
281 /*
282 * Load it.
283 */
284 bs3InitHighDllLoadImage(&g_aBs3HighDllTable[i], pszFilename, pbBuf, cBufSectors, uFlatBuf,
285 bDrive, uMaxHead, uMaxSector, cSectorsPerCylinder);
286 }
287
288 Bs3Printf("\n");
289 Bs3MemFree(pvBufAllocated, cbBuf);
290 }
291 else
292 {
293 Bs3TestPrintf("Bs3DiskQueryGeometry(%#x) failed: %#x\n", bDrive, rc);
294 Bs3Shutdown();
295 }
296 }
297}
298
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette