[68162] | 1 | /* $Id: UnattendedOs2Installer.cpp 104535 2024-05-07 15:46:29Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
[93094] | 3 | * UnattendedOs2Installer implementation.
|
---|
[68162] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2006-2023 Oracle and/or its affiliates.
|
---|
[68162] | 8 | *
|
---|
[96407] | 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 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
[68162] | 26 | */
|
---|
| 27 |
|
---|
[69238] | 28 |
|
---|
[68162] | 29 | /*********************************************************************************************************************************
|
---|
| 30 | * Header Files *
|
---|
| 31 | *********************************************************************************************************************************/
|
---|
| 32 | #define LOG_GROUP LOG_GROUP_MAIN_UNATTENDED
|
---|
| 33 | #include "LoggingNew.h"
|
---|
| 34 | #include "VirtualBoxBase.h"
|
---|
| 35 | #include "VirtualBoxErrorInfoImpl.h"
|
---|
| 36 | #include "AutoCaller.h"
|
---|
| 37 | #include <VBox/com/ErrorInfo.h>
|
---|
| 38 |
|
---|
| 39 | #include "UnattendedImpl.h"
|
---|
| 40 | #include "UnattendedInstaller.h"
|
---|
| 41 | #include "UnattendedScript.h"
|
---|
| 42 |
|
---|
| 43 | #include <VBox/err.h>
|
---|
| 44 | #include <iprt/ctype.h>
|
---|
| 45 | #include <iprt/fsisomaker.h>
|
---|
| 46 | #include <iprt/fsvfs.h>
|
---|
[91476] | 47 | #include <iprt/file.h>
|
---|
[68162] | 48 | #include <iprt/path.h>
|
---|
| 49 | #include <iprt/stream.h>
|
---|
| 50 | #include <iprt/vfs.h>
|
---|
| 51 | #ifdef RT_OS_SOLARIS
|
---|
| 52 | # undef ES /* Workaround for someone dragging the namespace pollutor sys/regset.h. Sigh. */
|
---|
| 53 | #endif
|
---|
[93085] | 54 | #include <iprt/formats/fat.h>
|
---|
[68162] | 55 | #include <iprt/cpp/path.h>
|
---|
| 56 |
|
---|
| 57 |
|
---|
| 58 | using namespace std;
|
---|
| 59 |
|
---|
| 60 |
|
---|
| 61 |
|
---|
[93085] | 62 | UnattendedOs2Installer::UnattendedOs2Installer(Unattended *pParent, Utf8Str const &rStrHints)
|
---|
| 63 | : UnattendedInstaller(pParent,
|
---|
[93094] | 64 | "os2_response_files.rsp", "os2_cid_install.cmd",
|
---|
[93109] | 65 | "os2_response_files.rsp", "VBOXCID.CMD",
|
---|
[93085] | 66 | DeviceType_Floppy)
|
---|
| 67 | {
|
---|
| 68 | Assert(!isOriginalIsoNeeded());
|
---|
| 69 | Assert(isAuxiliaryFloppyNeeded());
|
---|
| 70 | Assert(isAuxiliaryIsoIsVISO());
|
---|
| 71 | Assert(bootFromAuxiliaryIso());
|
---|
| 72 | mStrAuxiliaryInstallDir = "S:\\";
|
---|
| 73 |
|
---|
| 74 | /* Extract the info from the hints variable: */
|
---|
| 75 | RTCList<RTCString, RTCString *> Pairs = rStrHints.split(" ");
|
---|
| 76 | size_t i = Pairs.size();
|
---|
| 77 | Assert(i > 0);
|
---|
| 78 | while (i -- > 0)
|
---|
| 79 | {
|
---|
| 80 | RTCString const rStr = Pairs[i];
|
---|
| 81 | if (rStr.startsWith("OS2SE20.SRC="))
|
---|
| 82 | mStrOs2Images = rStr.substr(sizeof("OS2SE20.SRC=") - 1);
|
---|
| 83 | else
|
---|
| 84 | AssertMsgFailed(("Unknown hint: %s\n", rStr.c_str()));
|
---|
| 85 | }
|
---|
| 86 | }
|
---|
| 87 |
|
---|
| 88 |
|
---|
| 89 | HRESULT UnattendedOs2Installer::replaceAuxFloppyImageBootSector(RTVFSFILE hVfsFile) RT_NOEXCEPT
|
---|
| 90 | {
|
---|
| 91 | /*
|
---|
| 92 | * Find the bootsector. Because the ArcaOS ISOs doesn't contain any floppy
|
---|
| 93 | * images, we cannot just lift it off one of those. Instead we'll locate it
|
---|
| 94 | * in the SYSINSTX.COM utility, i.e. the tool which installs it onto floppies
|
---|
| 95 | * and harddisks. The SYSINSTX.COM utility is a NE executable and we don't
|
---|
| 96 | * have issues with compressed pages like with LX images.
|
---|
| 97 | *
|
---|
| 98 | * The utility seems always to be located on disk 0.
|
---|
| 99 | */
|
---|
| 100 | RTVFS hVfsOrgIso;
|
---|
| 101 | HRESULT hrc = openInstallIsoImage(&hVfsOrgIso);
|
---|
| 102 | if (SUCCEEDED(hrc))
|
---|
| 103 | {
|
---|
| 104 | char szPath[256];
|
---|
| 105 | int vrc = RTPathJoin(szPath, sizeof(szPath), mStrOs2Images.c_str(), "DISK_0/SYSINSTX.COM");
|
---|
| 106 | if (RT_SUCCESS(vrc))
|
---|
| 107 | {
|
---|
| 108 | RTVFSFILE hVfsSysInstX;
|
---|
| 109 | vrc = RTVfsFileOpen(hVfsOrgIso, szPath, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE, &hVfsSysInstX);
|
---|
| 110 | if (RT_SUCCESS(vrc))
|
---|
| 111 | {
|
---|
| 112 | /*
|
---|
| 113 | * Scan the image looking for a 512 block ending with a DOS signature
|
---|
| 114 | * and starting with a three byte jump followed by an OEM name string.
|
---|
| 115 | */
|
---|
| 116 | uint8_t *pbBootSector = NULL;
|
---|
[93089] | 117 | RTFOFF off = 0;
|
---|
[93085] | 118 | bool fEof = false;
|
---|
| 119 | uint8_t abBuf[_8K] = {0};
|
---|
| 120 | do
|
---|
| 121 | {
|
---|
| 122 | /* Read the next chunk. */
|
---|
| 123 | memmove(abBuf, &abBuf[sizeof(abBuf) - 512], 512); /* Move up the last 512 (all zero the first time around). */
|
---|
| 124 | size_t cbRead = 0;
|
---|
| 125 | vrc = RTVfsFileReadAt(hVfsSysInstX, off, &abBuf[512], sizeof(abBuf) - 512, &cbRead);
|
---|
| 126 | if (RT_FAILURE(vrc))
|
---|
| 127 | break;
|
---|
| 128 | fEof = cbRead != sizeof(abBuf) - 512;
|
---|
| 129 | off += cbRead;
|
---|
| 130 |
|
---|
| 131 | /* Scan it. */
|
---|
| 132 | size_t cbLeft = sizeof(abBuf);
|
---|
| 133 | uint8_t *pbCur = abBuf;
|
---|
| 134 | while (cbLeft >= 512)
|
---|
| 135 | {
|
---|
| 136 | /* Look for the DOS signature (0x55 0xaa) at the end of the sector: */
|
---|
| 137 | uint8_t *pbHit = (uint8_t *)memchr(pbCur + 510, 0x55, cbLeft - 510 - 1);
|
---|
| 138 | if (!pbHit)
|
---|
| 139 | break;
|
---|
| 140 | if (pbHit[1] == 0xaa)
|
---|
| 141 | {
|
---|
| 142 | uint8_t *pbStart = pbHit - 510;
|
---|
| 143 | if ( pbStart[0] == 0xeb /* JMP imm8 */
|
---|
| 144 | && pbStart[1] >= 3 + 8 + sizeof(FATEBPB) - 2 /* must jump after the FATEBPB */
|
---|
| 145 | && RT_C_IS_ALNUM(pbStart[3]) /* ASSUME OEM string starts with two letters (typically 'IBM x.y')*/
|
---|
| 146 | && RT_C_IS_ALNUM(pbStart[4]))
|
---|
| 147 | {
|
---|
| 148 | FATEBPB *pBpb = (FATEBPB *)&pbStart[3 + 8];
|
---|
| 149 | if ( pBpb->bExtSignature == FATEBPB_SIGNATURE
|
---|
| 150 | && ( memcmp(pBpb->achType, "FAT ", sizeof(pBpb->achType)) == 0
|
---|
| 151 | || memcmp(pBpb->achType, FATEBPB_TYPE_FAT12, sizeof(pBpb->achType)) == 0))
|
---|
| 152 | {
|
---|
| 153 | pbBootSector = pbStart;
|
---|
| 154 | break;
|
---|
| 155 | }
|
---|
| 156 | }
|
---|
| 157 | }
|
---|
| 158 |
|
---|
| 159 | /* skip */
|
---|
| 160 | pbCur = pbHit - 510 + 1;
|
---|
[93089] | 161 | cbLeft = (uintptr_t)&abBuf[sizeof(abBuf)] - (uintptr_t)pbCur;
|
---|
[93085] | 162 | }
|
---|
| 163 | } while (!fEof);
|
---|
| 164 |
|
---|
| 165 | if (pbBootSector)
|
---|
| 166 | {
|
---|
| 167 | if (pbBootSector != abBuf)
|
---|
| 168 | pbBootSector = (uint8_t *)memmove(abBuf, pbBootSector, 512);
|
---|
| 169 |
|
---|
| 170 | /*
|
---|
| 171 | * We've now got a bootsector. So, we need to copy the EBPB
|
---|
| 172 | * from the destination image before replacing it.
|
---|
| 173 | */
|
---|
| 174 | vrc = RTVfsFileReadAt(hVfsFile, 0, &abBuf[512], 512, NULL);
|
---|
| 175 | if (RT_SUCCESS(vrc))
|
---|
| 176 | {
|
---|
| 177 | memcpy(&pbBootSector[3 + 8], &abBuf[512 + 3 + 8], sizeof(FATEBPB));
|
---|
| 178 |
|
---|
| 179 | /*
|
---|
| 180 | * Write it.
|
---|
| 181 | */
|
---|
| 182 | vrc = RTVfsFileWriteAt(hVfsFile, 0, pbBootSector, 512, NULL);
|
---|
| 183 | if (RT_SUCCESS(vrc))
|
---|
| 184 | {
|
---|
| 185 | LogFlowFunc(("Successfully installed new bootsector\n"));
|
---|
| 186 | hrc = S_OK;
|
---|
| 187 | }
|
---|
| 188 | else
|
---|
| 189 | hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to write bootsector: %Rrc"), vrc);
|
---|
| 190 | }
|
---|
| 191 | else
|
---|
| 192 | hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to read bootsector: %Rrc"), vrc);
|
---|
| 193 | }
|
---|
| 194 | else if (RT_FAILURE(vrc))
|
---|
| 195 | hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Error reading SYSINSTX.COM: %Rrc"), vrc);
|
---|
| 196 | else
|
---|
| 197 | hrc = mpParent->setErrorBoth(E_FAIL, VERR_NOT_FOUND,
|
---|
| 198 | tr("Unable to locate bootsector template in SYSINSTX.COM"));
|
---|
| 199 | RTVfsFileRelease(hVfsSysInstX);
|
---|
| 200 | }
|
---|
| 201 | else
|
---|
| 202 | hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to open SYSINSTX.COM: %Rrc"), vrc);
|
---|
| 203 | }
|
---|
| 204 | else
|
---|
| 205 | hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to construct SYSINSTX.COM path"));
|
---|
| 206 | RTVfsRelease(hVfsOrgIso);
|
---|
| 207 | }
|
---|
| 208 | return hrc;
|
---|
| 209 |
|
---|
| 210 | }
|
---|
| 211 |
|
---|
| 212 | HRESULT UnattendedOs2Installer::newAuxFloppyImage(const char *pszFilename, bool fOverwrite, PRTVFSFILE phVfsFile)
|
---|
| 213 | {
|
---|
| 214 | /*
|
---|
| 215 | * Open the image file.
|
---|
| 216 | */
|
---|
| 217 | HRESULT hrc;
|
---|
| 218 | RTVFSFILE hVfsFile;
|
---|
| 219 | uint64_t fOpen = RTFILE_O_READWRITE | RTFILE_O_DENY_ALL | (0660 << RTFILE_O_CREATE_MODE_SHIFT);
|
---|
| 220 | if (fOverwrite)
|
---|
| 221 | fOpen |= RTFILE_O_CREATE_REPLACE;
|
---|
| 222 | else
|
---|
| 223 | fOpen |= RTFILE_O_OPEN;
|
---|
| 224 | int vrc = RTVfsFileOpenNormal(pszFilename, fOpen, &hVfsFile);
|
---|
| 225 | if (RT_SUCCESS(vrc))
|
---|
| 226 | {
|
---|
| 227 | /*
|
---|
| 228 | * Format it.
|
---|
| 229 | */
|
---|
| 230 | vrc = RTFsFatVolFormat288(hVfsFile, false /*fQuick*/);
|
---|
| 231 | if (RT_SUCCESS(vrc))
|
---|
| 232 | {
|
---|
| 233 | /*
|
---|
| 234 | * Now we install the OS/2 boot sector on it.
|
---|
| 235 | */
|
---|
| 236 | hrc = replaceAuxFloppyImageBootSector(hVfsFile);
|
---|
| 237 | if (SUCCEEDED(hrc))
|
---|
| 238 | {
|
---|
| 239 | *phVfsFile = hVfsFile;
|
---|
| 240 | LogRelFlow(("UnattendedInstaller::newAuxFloppyImage: created and formatted '%s'\n", pszFilename));
|
---|
| 241 | return S_OK;
|
---|
| 242 | }
|
---|
| 243 | }
|
---|
| 244 | else
|
---|
| 245 | hrc = mpParent->setErrorBoth(E_FAIL, vrc, tr("Failed to format floppy image '%s': %Rrc"), pszFilename, vrc);
|
---|
| 246 | RTVfsFileRelease(hVfsFile);
|
---|
| 247 | RTFileDelete(pszFilename);
|
---|
| 248 | }
|
---|
| 249 | else
|
---|
| 250 | hrc = mpParent->setErrorBoth(E_FAIL, vrc, tr("Failed to create floppy image '%s': %Rrc"), pszFilename, vrc);
|
---|
| 251 | return hrc;
|
---|
| 252 | }
|
---|
| 253 |
|
---|
| 254 |
|
---|
| 255 | HRESULT UnattendedOs2Installer::splitResponseFile() RT_NOEXCEPT
|
---|
| 256 | {
|
---|
| 257 | if (mVecSplitFiles.size() == 0)
|
---|
| 258 | {
|
---|
| 259 | #if 0
|
---|
| 260 | Utf8Str strResponseFile;
|
---|
| 261 | int vrc = strResponseFile.assignNoThrow(mpParent->i_getAuxiliaryBasePath());
|
---|
| 262 | if (RT_SUCCESS(vrc))
|
---|
| 263 | vrc = strResponseFile.appendNoThrow(mMainScript.getDefaultFilename());
|
---|
| 264 | if (RT_SUCCESS(vrc))
|
---|
| 265 | return splitFile(strResponseFile.c_str(), mVecSplitFiles);
|
---|
| 266 | return mpParent->setErrorVrc(vrc);
|
---|
| 267 | #else
|
---|
| 268 | return splitFile(&mMainScript, mVecSplitFiles);
|
---|
| 269 | #endif
|
---|
| 270 | }
|
---|
| 271 | return S_OK;
|
---|
| 272 | }
|
---|
| 273 |
|
---|
[93094] | 274 | /**
|
---|
| 275 | * OS/2 code pattern.
|
---|
| 276 | */
|
---|
| 277 | typedef struct OS2CODEPATTERN
|
---|
| 278 | {
|
---|
| 279 | /** The code pattern. */
|
---|
| 280 | uint8_t const *pbPattern;
|
---|
| 281 | /** The mask to apply when using the pattern (ignore 0x00 bytes, compare 0xff
|
---|
| 282 | * bytes). */
|
---|
| 283 | uint8_t const *pbMask;
|
---|
| 284 | /** The pattern size. */
|
---|
| 285 | size_t cb;
|
---|
| 286 | /** User info \#1. */
|
---|
| 287 | uintptr_t uUser1;
|
---|
| 288 | /** User info \#2. */
|
---|
| 289 | uint32_t uUser2;
|
---|
| 290 | /** User info \#3. */
|
---|
| 291 | uint32_t uUser3;
|
---|
| 292 | /** User info \#4. */
|
---|
| 293 | uint32_t uUser4;
|
---|
| 294 | /** User info \#5. */
|
---|
| 295 | uint32_t uUser5;
|
---|
| 296 | } OS2CODEPATTERN;
|
---|
| 297 | /** Pointer to an OS/2 code pattern. */
|
---|
| 298 | typedef OS2CODEPATTERN const *PCOS2CODEPATTERN;
|
---|
| 299 |
|
---|
| 300 |
|
---|
| 301 | /**
|
---|
| 302 | * Search @a pbCode for the code patterns in @a paPatterns.
|
---|
| 303 | *
|
---|
| 304 | * @returns pointer within @a pbCode to matching code, NULL if no match.
|
---|
| 305 | */
|
---|
| 306 | static uint8_t *findCodePattern(PCOS2CODEPATTERN paPatterns, size_t cPatterns, uint8_t *pbCode, size_t cbCode,
|
---|
| 307 | PCOS2CODEPATTERN *ppMatch)
|
---|
| 308 | {
|
---|
| 309 | for (size_t i = 0; i < cPatterns; i++)
|
---|
| 310 | {
|
---|
| 311 | size_t const cbPattern = paPatterns[i].cb;
|
---|
| 312 | uint8_t const *pbPattern = paPatterns[i].pbPattern;
|
---|
| 313 | uint8_t const *pbMask = paPatterns[i].pbMask;
|
---|
| 314 | Assert(pbMask[0] == 0xff); /* ASSUME the we can use the first byte with memchr. */
|
---|
| 315 | uint8_t const bFirst = *pbPattern;
|
---|
| 316 | size_t off = 0;
|
---|
| 317 | while (off + cbPattern <= cbCode)
|
---|
| 318 | {
|
---|
| 319 | uint8_t *pbHit = (uint8_t *)memchr(&pbCode[off], bFirst, cbCode - off - cbPattern + 1);
|
---|
| 320 | if (!pbHit)
|
---|
| 321 | break;
|
---|
| 322 |
|
---|
| 323 | size_t offPattern = 1;
|
---|
| 324 | while ( offPattern < cbPattern
|
---|
| 325 | && (pbPattern[offPattern] & pbMask[offPattern]) == (pbHit[offPattern] & pbMask[offPattern]))
|
---|
| 326 | offPattern++;
|
---|
| 327 | if (offPattern == cbPattern)
|
---|
| 328 | {
|
---|
| 329 | *ppMatch = &paPatterns[i];
|
---|
| 330 | return pbHit;
|
---|
| 331 | }
|
---|
| 332 |
|
---|
| 333 | /* next */
|
---|
| 334 | off++;
|
---|
| 335 | }
|
---|
| 336 | }
|
---|
| 337 | return NULL;
|
---|
| 338 | }
|
---|
| 339 |
|
---|
[93109] | 340 | #if 0
|
---|
| 341 | /**
|
---|
| 342 | * Patcher callback for TESTCFG.SYS.
|
---|
| 343 | *
|
---|
| 344 | * This is for debugging a mysterious DS corruption issue happening on an AMD
|
---|
| 345 | * 3990x host.
|
---|
| 346 | *
|
---|
| 347 | * @verbatim
|
---|
| 348 | dbgf event/0: xcpt_gp - #GP (general protection fault)! arg=0x1d8
|
---|
| 349 | VBoxDbg> r
|
---|
| 350 | eax=00000001 ebx=00dc0000 ecx=56d80000 edx=178b0000 esi=ffde0100 edi=feff44e4
|
---|
| 351 | eip=00000124 esp=00000f76 ebp=0000dbf3 iopl=3 nv up ei pl nz na po nc
|
---|
| 352 | cs=0763 ds=01db es=0130 fs=0000 gs=0000 ss=001f eflags=00003206
|
---|
| 353 | 0763:00000124 cb retf
|
---|
| 354 | VBoxDbg> dw ss:sp
|
---|
| 355 | 001f:00000f76: 0549 075b 03e4 0000-0fb8 04b9 44e4 0130
|
---|
| 356 | VBoxDbg> u cs:fc
|
---|
| 357 | 0763:000000fc 55 push bp
|
---|
| 358 | 0763:000000fd 8b ec mov bp, sp
|
---|
| 359 | 0763:000000ff 53 push bx
|
---|
| 360 | 0763:00000100 51 push cx
|
---|
| 361 | 0763:00000101 52 push dx
|
---|
| 362 | 0763:00000102 1e push DS
|
---|
| 363 | 0763:00000103 33 c9 xor cx, cx
|
---|
| 364 | 0763:00000105 b0 10 mov AL, 010h
|
---|
| 365 | 0763:00000107 b2 24 mov DL, 024h
|
---|
| 366 | 0763:00000109 ff 1e 22 00 call far [00022h]
|
---|
| 367 | 0763:0000010d 72 0e jc +00eh (0011dh)
|
---|
| 368 | 0763:0000010f 50 push ax
|
---|
| 369 | 0763:00000110 1f pop DS
|
---|
| 370 | 0763:00000111 f7 47 06 03 00 test word [bx+006h], 00003h
|
---|
| 371 | 0763:00000116 74 05 je +005h (0011dh)
|
---|
| 372 | 0763:00000118 b8 01 00 mov ax, 00001h
|
---|
| 373 | 0763:0000011b eb 02 jmp +002h (0011fh)
|
---|
| 374 | 0763:0000011d 33 c0 xor ax, ax
|
---|
| 375 | 0763:0000011f 1f pop DS
|
---|
| 376 | 0763:00000120 5a pop dx
|
---|
| 377 | 0763:00000121 59 pop cx
|
---|
| 378 | 0763:00000122 5b pop bx
|
---|
| 379 | 0763:00000123 5d pop bp
|
---|
| 380 | 0763:00000124 cb retf
|
---|
| 381 | VBoxDbg> dw ss:sp - 5*2 L8
|
---|
| 382 | 001f:00000f6c: 0750 082a 220e 44e4-0f7e 0549 075b 03e4
|
---|
| 383 | * @endverbatim
|
---|
| 384 | *
|
---|
| 385 | * We end up with a \#GP on the RETF, but the stack frame is a valid 075b:0549
|
---|
| 386 | * return address (in TESTCFG's first code segment). The error code is 0x1d8,
|
---|
| 387 | * which makes no sense. DS contains 0x1db, which could be related, however it
|
---|
| 388 | * is the *wrong* value as seen by the stack restore frame above, it was just
|
---|
| 389 | * restored as 0750 (TESTCFG data segment).
|
---|
| 390 | *
|
---|
| 391 | * The patching here aim at modifying to code to try figure out what might
|
---|
| 392 | * trigger the bogus DS and \#GP(0x1d8).
|
---|
| 393 | *
|
---|
| 394 | * P.S. There are no exits or event injections taking place when DS gets
|
---|
| 395 | * corrupt, the last exit was a CR0 read in OS2KRNL's DOSSEG (0120:1798)
|
---|
| 396 | * probably related to we comming back to protected mode from real mode as we
|
---|
| 397 | * just made an APM BIOS call.
|
---|
| 398 | *
|
---|
| 399 | * Update: The values loaded off the stack aren't the ones ending up the
|
---|
| 400 | * registers, so that might explain why this goes south.
|
---|
[93114] | 401 | *
|
---|
[93109] | 402 | * @sa ticketref:20625
|
---|
| 403 | */
|
---|
| 404 | /*static*/
|
---|
| 405 | int UnattendedOs2Installer::patchTestCfg(uint8_t *pbFile, size_t cbFile, const char *pszFilename, UnattendedOs2Installer *pThis)
|
---|
| 406 | {
|
---|
| 407 | RT_NOREF(pThis, pszFilename);
|
---|
[93094] | 408 |
|
---|
[93109] | 409 | static uint8_t const s_abVariant1[] =
|
---|
| 410 | {
|
---|
| 411 | /*0763:00fc*/ 0x55, /* push bp */
|
---|
| 412 | /*0763:00fd*/ 0x8b, 0xec, /* mov bp, sp */
|
---|
| 413 | /*0763:00ff*/ 0x53, /* push bx */
|
---|
| 414 | /*0763:0100*/ 0x51, /* push cx */
|
---|
| 415 | /*0763:0101*/ 0x52, /* push dx */
|
---|
| 416 | /*0763:0102*/ 0x1e, /* push DS */
|
---|
| 417 | /*0763:0103*/ 0x33, 0xc9, /* xor cx, cx */
|
---|
| 418 | /*0763:0105*/ 0xb0, 0x10, /* mov AL, 010h */
|
---|
| 419 | /*0763:0107*/ 0xb2, 0x24, /* mov DL, 024h */
|
---|
| 420 | /*0763:0109*/ 0xff, 0x1e, 0x22, 0x00, /* call far [00022h] */
|
---|
| 421 | /*0763:010d*/ 0x72, 0x0e, /* jc +00eh (0011dh) */
|
---|
| 422 | /*0763:010f*/ 0x50, /* push ax */
|
---|
| 423 | /*0763:0110*/ 0x1f, /* pop DS */
|
---|
| 424 | /*0763:0111*/ 0xf7, 0x47, 0x06, 0x03, 0x00, /* test word [bx+006h], 00003h */
|
---|
| 425 | /*0763:0116*/ 0x74, 0x05, /* je +005h (0011dh) */
|
---|
| 426 | /*0763:0118*/ 0xb8, 0x01, 0x00, /* mov ax, 00001h */
|
---|
| 427 | /*0763:011b*/ 0xeb, 0x02, /* jmp +002h (0011fh) */
|
---|
| 428 | /*0763:011d*/ 0x33, 0xc0, /* xor ax, ax */
|
---|
| 429 | /*0763:011f*/ 0x1f, /* pop DS */
|
---|
| 430 | /*0763:0120*/ 0x5a, /* pop dx */
|
---|
| 431 | /*0763:0121*/ 0x59, /* pop cx */
|
---|
| 432 | /*0763:0122*/ 0x5b, /* pop bx */
|
---|
| 433 | /*0763:0123*/ 0x5d, /* pop bp */
|
---|
| 434 | /*0763:0124*/ 0xcb, /* retf */
|
---|
| 435 | };
|
---|
| 436 | static uint8_t const s_abVariant1Mask[] =
|
---|
| 437 | {
|
---|
| 438 | /*0763:00fc*/ 0xff, /* push bp */
|
---|
| 439 | /*0763:00fd*/ 0xff, 0xec, /* mov bp, sp */
|
---|
| 440 | /*0763:00ff*/ 0xff, /* push bx */
|
---|
| 441 | /*0763:0100*/ 0xff, /* push cx */
|
---|
| 442 | /*0763:0101*/ 0xff, /* push dx */
|
---|
| 443 | /*0763:0102*/ 0xff, /* push DS */
|
---|
| 444 | /*0763:0103*/ 0xff, 0xff, /* xor cx, cx */
|
---|
| 445 | /*0763:0105*/ 0xff, 0xff, /* mov AL, 010h */
|
---|
| 446 | /*0763:0107*/ 0xff, 0xff, /* mov DL, 024h */
|
---|
| 447 | /*0763:0109*/ 0xff, 0xff, 0x00, 0x00, /* call far [00022h] */
|
---|
| 448 | /*0763:010d*/ 0xff, 0xff, /* jc +00eh (0011dh) */
|
---|
| 449 | /*0763:010f*/ 0xff, /* push ax */
|
---|
| 450 | /*0763:0110*/ 0xff, /* pop DS */
|
---|
| 451 | /*0763:0111*/ 0xff, 0xff, 0xff, 0xff, 0xff, /* test word [bx+006h], 00003h */
|
---|
| 452 | /*0763:0116*/ 0xff, 0xff, /* je +005h (0011dh) */
|
---|
| 453 | /*0763:0118*/ 0xff, 0xff, 0xff, /* mov ax, 00001h */
|
---|
| 454 | /*0763:011b*/ 0xff, 0xff, /* jmp +002h (0011fh) */
|
---|
| 455 | /*0763:011d*/ 0xff, 0xff, /* xor ax, ax */
|
---|
| 456 | /*0763:011f*/ 0xff, /* pop DS */
|
---|
| 457 | /*0763:0120*/ 0xff, /* pop dx */
|
---|
| 458 | /*0763:0121*/ 0xff, /* pop cx */
|
---|
| 459 | /*0763:0122*/ 0xff, /* pop bx */
|
---|
| 460 | /*0763:0123*/ 0xff, /* pop bp */
|
---|
| 461 | /*0763:0124*/ 0xff, /* retf */
|
---|
| 462 | };
|
---|
| 463 | AssertCompile(sizeof(s_abVariant1Mask) == sizeof(s_abVariant1));
|
---|
| 464 |
|
---|
| 465 | /* uUser1 = off to start modifying the code; */
|
---|
| 466 | static const OS2CODEPATTERN s_aPatterns[] =
|
---|
| 467 | {
|
---|
| 468 | { s_abVariant1, s_abVariant1Mask, sizeof(s_abVariant1Mask), 0x010d - 0x00fc, 0, 0, 0, 0 },
|
---|
| 469 | };
|
---|
| 470 |
|
---|
| 471 | PCOS2CODEPATTERN pPattern;
|
---|
| 472 | uint8_t *pbHit = findCodePattern(&s_aPatterns[0], RT_ELEMENTS(s_aPatterns), pbFile, cbFile, &pPattern);
|
---|
| 473 | if (pPattern)
|
---|
| 474 | {
|
---|
| 475 | /* We've got */
|
---|
| 476 | uint8_t *pbPatch = &pbHit[pPattern->uUser1];
|
---|
| 477 | #if 0 /* this seems to fix the issue */
|
---|
| 478 | *pbPatch++ = 0xe6; /* out 78h, al - triggers an exit */
|
---|
| 479 | *pbPatch++ = 0x78;
|
---|
| 480 | #elif 0 /* this seems to fix it too */
|
---|
| 481 | *pbPatch++ = 0xf3; /* pause */
|
---|
| 482 | *pbPatch++ = 0x90;
|
---|
| 483 | #elif 0 /* still reproducible with normal nops. */
|
---|
| 484 | *pbPatch++ = 0x90;
|
---|
| 485 | *pbPatch++ = 0x90;
|
---|
| 486 | #else
|
---|
| 487 | # if 0
|
---|
| 488 | /*0763:010d*/ 0x72, 0x0e, /* jc +00eh (0011dh) */
|
---|
| 489 | /*0763:010f*/ 0x50, /* push ax */
|
---|
| 490 | /*0763:0110*/ 0x1f, /* pop DS */
|
---|
| 491 | /*0763:0111*/ 0xf7, 0x47, 0x06, 0x03, 0x00, /* test word [bx+006h], 00003h */
|
---|
| 492 | /*0763:0116*/ 0x74, 0x05, /* je +005h (0011dh) */
|
---|
| 493 | /*0763:0118*/ 0xb8, 0x01, 0x00, /* mov ax, 00001h */
|
---|
| 494 | /*0763:011b*/ 0xeb, 0x02, /* jmp +002h (0011fh) */
|
---|
| 495 | /*0763:011d*/ 0x33, 0xc0, /* xor ax, ax */
|
---|
| 496 | /*0763:011f*/ 0x1f, /* pop DS */
|
---|
| 497 | /*0763:0120*/ 0x5a, /* pop dx */
|
---|
| 498 | /*0763:0121*/ 0x59, /* pop cx */
|
---|
| 499 | /*0763:0122*/ 0x5b, /* pop bx */
|
---|
| 500 | /*0763:0123*/ 0x5d, /* pop bp */
|
---|
| 501 | /*0763:0124*/ 0xcb, /* retf */
|
---|
| 502 | # endif
|
---|
| 503 | /* Try straigthen out the code and mabye load DS into AX (we don't care about the return value) */
|
---|
| 504 | *pbPatch++ = 0x50; /* push ax */
|
---|
| 505 | *pbPatch++ = 0x1f; /* pop DS */
|
---|
| 506 |
|
---|
| 507 | *pbPatch++ = 0xf7; /* test word [bx+006h], 00003h */
|
---|
| 508 | *pbPatch++ = 0x47;
|
---|
| 509 | *pbPatch++ = 0x06;
|
---|
| 510 | *pbPatch++ = 0x03;
|
---|
| 511 | *pbPatch++ = 0x00;
|
---|
| 512 | /* not je */
|
---|
| 513 | *pbPatch++ = 0xb8; /* mov ax, 00001h */
|
---|
| 514 | *pbPatch++ = 0x01;
|
---|
| 515 | *pbPatch++ = 0x00;
|
---|
| 516 |
|
---|
| 517 | # if 0 /* try reload SS */
|
---|
| 518 | *pbPatch++ = 0x8c; /* mov ax, ss */
|
---|
| 519 | *pbPatch++ = 0xd0;
|
---|
| 520 | *pbPatch++ = 0x8e; /* mov ss, ax */
|
---|
| 521 | *pbPatch++ = 0xd0;
|
---|
| 522 | # endif
|
---|
| 523 | # if 0 /* try reload CR3 to flush everything - not possible, we're in ring-3 */
|
---|
| 524 | *pbPatch++ = 0x0f; /* mov eax, cr3 */
|
---|
| 525 | *pbPatch++ = 0x20;
|
---|
| 526 | *pbPatch++ = 0xd8;
|
---|
| 527 | *pbPatch++ = 0x0f; /* mov cr3, eax */
|
---|
| 528 | *pbPatch++ = 0x22;
|
---|
| 529 | *pbPatch++ = 0xd8;
|
---|
| 530 | # endif
|
---|
| 531 |
|
---|
| 532 | *pbPatch++ = 0x1f; /* pop DS */
|
---|
| 533 | # if 0
|
---|
| 534 | *pbPatch++ = 0x8c; /* mov ax, ds */
|
---|
| 535 | *pbPatch++ = 0xd8;
|
---|
| 536 | # endif
|
---|
| 537 | *pbPatch++ = 0x5a; /* pop dx */
|
---|
| 538 | *pbPatch++ = 0x59; /* pop cx */
|
---|
| 539 | *pbPatch++ = 0x5b; /* pop bx */
|
---|
| 540 | *pbPatch++ = 0x5d; /* pop bp */
|
---|
| 541 | *pbPatch++ = 0xcb; /* retf */
|
---|
| 542 |
|
---|
| 543 | #endif
|
---|
| 544 | }
|
---|
| 545 | else
|
---|
| 546 | {
|
---|
| 547 | LogRelFunc(("No patch pattern match!\n"));
|
---|
| 548 | return VERR_NOT_FOUND;
|
---|
| 549 | }
|
---|
| 550 |
|
---|
| 551 | return VINF_SUCCESS;
|
---|
| 552 | }
|
---|
| 553 | #endif
|
---|
| 554 |
|
---|
| 555 |
|
---|
[93094] | 556 | /**
|
---|
| 557 | * Patcher callback for OS2LDR.
|
---|
| 558 | *
|
---|
| 559 | * There are one or two delay calibration loops here that doesn't work well on
|
---|
| 560 | * fast CPUs. Typically ends up with division by chainsaw, which in a BIOS
|
---|
| 561 | * context means an unending loop as the BIOS \#DE handler doesn't do much.
|
---|
| 562 | *
|
---|
| 563 | * The patching is simplictic, in that it just returns a constant value. We
|
---|
| 564 | * could rewrite this to use RDTSC and some secret MSR/whatever for converting
|
---|
| 565 | * that to a decent loop count.
|
---|
| 566 | */
|
---|
| 567 | /*static*/
|
---|
| 568 | int UnattendedOs2Installer::patchOs2Ldr(uint8_t *pbFile, size_t cbFile, const char *pszFilename, UnattendedOs2Installer *pThis)
|
---|
| 569 | {
|
---|
| 570 | RT_NOREF(pThis, pszFilename);
|
---|
| 571 |
|
---|
| 572 | /*
|
---|
| 573 | * This first variant is from ACP2:
|
---|
| 574 | *
|
---|
| 575 | * VBoxDbg> r
|
---|
| 576 | * eax=00001000 ebx=00010000 ecx=56d8ffd5 edx=178b0000 esi=00000000 edi=0000b750
|
---|
| 577 | * eip=0000847a esp=0000cfe8 ebp=00000000 iopl=0 nv up ei pl zr na po nc
|
---|
| 578 | * cs=2000 ds=2000 es=2000 fs=0000 gs=0000 ss=2000 eflags=00000246
|
---|
| 579 | * 2000:0000847a f7 fb idiv bx
|
---|
| 580 | * VBoxDbg> ucfg 2000:840a
|
---|
| 581 | *
|
---|
| 582 | * This is a little annoying because it stores the result in a global variable,
|
---|
| 583 | * so we cannot just do an early return, instead we have to have to jump to the
|
---|
| 584 | * end of the function so it can be stored correctly.
|
---|
| 585 | */
|
---|
| 586 | static uint8_t const s_abVariant1[] =
|
---|
| 587 | {
|
---|
| 588 | /*2000:840a*/ 0x60, /* pushaw */
|
---|
| 589 | /*2000:840b*/ 0x1e, /* push DS */
|
---|
| 590 | /*2000:840c*/ 0x0e, /* push CS */
|
---|
| 591 | /*2000:840d*/ 0x1f, /* pop DS */
|
---|
| 592 | /*2000:840e*/ 0x9c, /* pushfw */
|
---|
| 593 | /*2000:840f*/ 0xfa, /* cli */
|
---|
| 594 | /*2000:8410*/ 0xb0, 0x34, /* mov AL, 034h */
|
---|
| 595 | /*2000:8412*/ 0xe6, 0x43, /* out 043h, AL */
|
---|
| 596 | /*2000:8414*/ 0xe8, 0x75, 0xfc, /* call 0808ch */
|
---|
| 597 | /*2000:8417*/ 0x32, 0xc0, /* xor al, al */
|
---|
| 598 | /*2000:8419*/ 0xe6, 0x40, /* out 040h, AL */
|
---|
| 599 | /*2000:841b*/ 0xe8, 0x6e, 0xfc, /* call 0808ch */
|
---|
| 600 | /*2000:841e*/ 0xe6, 0x40, /* out 040h, AL */
|
---|
| 601 | /*2000:8420*/ 0xe8, 0x69, 0xfc, /* call 0808ch */
|
---|
| 602 | /*2000:8423*/ 0xb0, 0x00, /* mov AL, 000h */
|
---|
| 603 | /*2000:8425*/ 0xe6, 0x43, /* out 043h, AL */
|
---|
| 604 | /*2000:8427*/ 0xe8, 0x62, 0xfc, /* call 0808ch */
|
---|
| 605 | /*2000:842a*/ 0xe4, 0x40, /* in AL, 040h */
|
---|
| 606 | /*2000:842c*/ 0xe8, 0x5d, 0xfc, /* call 0808ch */
|
---|
| 607 | /*2000:842f*/ 0x8a, 0xd8, /* mov bl, al */
|
---|
| 608 | /*2000:8431*/ 0xe4, 0x40, /* in AL, 040h */
|
---|
| 609 | /*2000:8433*/ 0x8a, 0xf8, /* mov bh, al */
|
---|
| 610 | /*2000:8435*/ 0xb0, 0x00, /* mov AL, 000h */
|
---|
| 611 | /*2000:8437*/ 0xe6, 0x43, /* out 043h, AL */
|
---|
| 612 | /*2000:8439*/ 0xe8, 0x50, 0xfc, /* call 0808ch */
|
---|
| 613 | /*2000:843c*/ 0xe4, 0x40, /* in AL, 040h */
|
---|
| 614 | /*2000:843e*/ 0xe8, 0x4b, 0xfc, /* call 0808ch */
|
---|
| 615 | /*2000:8441*/ 0x8a, 0xc8, /* mov cl, al */
|
---|
| 616 | /*2000:8443*/ 0xe4, 0x40, /* in AL, 040h */
|
---|
| 617 | /*2000:8445*/ 0x8a, 0xe8, /* mov ch, al */
|
---|
| 618 | /*2000:8447*/ 0xbe, 0x00, 0x10, /* mov si, 01000h */
|
---|
| 619 | /*2000:844a*/ 0x87, 0xdb, /* xchg bx, bx */
|
---|
| 620 | /*2000:844c*/ 0x4e, /* dec si */
|
---|
| 621 | /*2000:844d*/ 0x75, 0xfd, /* jne -003h (0844ch) */
|
---|
| 622 | /*2000:844f*/ 0xb0, 0x00, /* mov AL, 000h */
|
---|
| 623 | /*2000:8451*/ 0xe6, 0x43, /* out 043h, AL */
|
---|
| 624 | /*2000:8453*/ 0xe8, 0x36, 0xfc, /* call 0808ch */
|
---|
| 625 | /*2000:8456*/ 0xe4, 0x40, /* in AL, 040h */
|
---|
| 626 | /*2000:8458*/ 0xe8, 0x31, 0xfc, /* call 0808ch */
|
---|
| 627 | /*2000:845b*/ 0x8a, 0xd0, /* mov dl, al */
|
---|
| 628 | /*2000:845d*/ 0xe4, 0x40, /* in AL, 040h */
|
---|
| 629 | /*2000:845f*/ 0x8a, 0xf0, /* mov dh, al */
|
---|
| 630 | /*2000:8461*/ 0x9d, /* popfw */
|
---|
| 631 | /*2000:8462*/ 0x2b, 0xd9, /* sub bx, cx */
|
---|
| 632 | /*2000:8464*/ 0x2b, 0xca, /* sub cx, dx */
|
---|
| 633 | /*2000:8466*/ 0x2b, 0xcb, /* sub cx, bx */
|
---|
| 634 | /*2000:8468*/ 0x87, 0xca, /* xchg dx, cx */
|
---|
| 635 | /*2000:846a*/ 0xb8, 0x28, 0x00, /* mov ax, 00028h */
|
---|
| 636 | /*2000:846d*/ 0xf7, 0xea, /* imul dx */
|
---|
| 637 | /*2000:846f*/ 0xbb, 0x18, 0x00, /* mov bx, 00018h */
|
---|
| 638 | /*2000:8472*/ 0xf7, 0xfb, /* idiv bx */
|
---|
| 639 | /*2000:8474*/ 0x33, 0xd2, /* xor dx, dx */
|
---|
| 640 | /*2000:8476*/ 0xbb, 0x00, 0x10, /* mov bx, 01000h */
|
---|
| 641 | /*2000:8479*/ 0x93, /* xchg bx, ax */
|
---|
| 642 | /*2000:847a*/ 0xf7, 0xfb, /* idiv bx */
|
---|
| 643 | /*2000:847c*/ 0x0b, 0xd2, /* or dx, dx */
|
---|
| 644 | /*2000:847e*/ 0x74, 0x01, /* je +001h (08481h) */
|
---|
| 645 | /*2000:8480*/ 0x40, /* inc ax */
|
---|
| 646 | /*2000:8481*/ 0x40, /* inc ax */
|
---|
| 647 | /*2000:8482*/ 0xa3, 0x4d, 0xac, /* mov word [0ac4dh], ax */
|
---|
| 648 | /*2000:8485*/ 0x1f, /* pop DS */
|
---|
| 649 | /*2000:8486*/ 0x61, /* popaw */
|
---|
| 650 | /*2000:8487*/ 0xc3, /* retn */
|
---|
| 651 | };
|
---|
| 652 | static uint8_t const s_abVariant1Mask[] =
|
---|
| 653 | {
|
---|
| 654 | /*2000:840a*/ 0xff, /* pushaw */
|
---|
| 655 | /*2000:840b*/ 0xff, /* push DS */
|
---|
| 656 | /*2000:840c*/ 0xff, /* push CS */
|
---|
| 657 | /*2000:840d*/ 0xff, /* pop DS */
|
---|
| 658 | /*2000:840e*/ 0xff, /* pushfw */
|
---|
| 659 | /*2000:840f*/ 0xff, /* cli */
|
---|
| 660 | /*2000:8410*/ 0xff, 0xff, /* mov AL, 034h */
|
---|
| 661 | /*2000:8412*/ 0xff, 0xff, /* out 043h, AL */
|
---|
| 662 | /*2000:8414*/ 0xff, 0x00, 0x00, /* call 0808ch - ignore offset */
|
---|
| 663 | /*2000:8417*/ 0xff, 0xff, /* xor al, al */
|
---|
| 664 | /*2000:8419*/ 0xff, 0xff, /* out 040h, AL */
|
---|
| 665 | /*2000:841b*/ 0xff, 0x00, 0x00, /* call 0808ch - ignore offset */
|
---|
| 666 | /*2000:841e*/ 0xff, 0xff, /* out 040h, AL */
|
---|
| 667 | /*2000:8420*/ 0xff, 0x00, 0x00, /* call 0808ch - ignore offset */
|
---|
| 668 | /*2000:8423*/ 0xff, 0xff, /* mov AL, 000h */
|
---|
| 669 | /*2000:8425*/ 0xff, 0xff, /* out 043h, AL */
|
---|
| 670 | /*2000:8427*/ 0xff, 0x00, 0x00, /* call 0808ch - ignore offset */
|
---|
| 671 | /*2000:842a*/ 0xff, 0xff, /* in AL, 040h */
|
---|
| 672 | /*2000:842c*/ 0xff, 0x00, 0x00, /* call 0808ch - ignore offset */
|
---|
| 673 | /*2000:842f*/ 0xff, 0xff, /* mov bl, al */
|
---|
| 674 | /*2000:8431*/ 0xff, 0xff, /* in AL, 040h */
|
---|
| 675 | /*2000:8433*/ 0xff, 0xff, /* mov bh, al */
|
---|
| 676 | /*2000:8435*/ 0xff, 0xff, /* mov AL, 000h */
|
---|
| 677 | /*2000:8437*/ 0xff, 0xff, /* out 043h, AL */
|
---|
| 678 | /*2000:8439*/ 0xff, 0x00, 0x00, /* call 0808ch - ignore offset */
|
---|
| 679 | /*2000:843c*/ 0xff, 0x40, /* in AL, 040h */
|
---|
| 680 | /*2000:843e*/ 0xff, 0x00, 0x00, /* call 0808ch - ignore offset */
|
---|
| 681 | /*2000:8441*/ 0xff, 0xff, /* mov cl, al */
|
---|
| 682 | /*2000:8443*/ 0xff, 0xff, /* in AL, 040h */
|
---|
| 683 | /*2000:8445*/ 0xff, 0xff, /* mov ch, al */
|
---|
| 684 | /*2000:8447*/ 0xff, 0x00, 0x00, /* mov si, 01000h - ignore loop count */
|
---|
| 685 | /*2000:844a*/ 0xff, 0xff, /* xchg bx, bx */
|
---|
| 686 | /*2000:844c*/ 0xff, /* dec si */
|
---|
| 687 | /*2000:844d*/ 0xff, 0xfd, /* jne -003h (0844ch) */
|
---|
| 688 | /*2000:844f*/ 0xff, 0xff, /* mov AL, 000h */
|
---|
| 689 | /*2000:8451*/ 0xff, 0xff, /* out 043h, AL */
|
---|
| 690 | /*2000:8453*/ 0xff, 0x00, 0x00, /* call 0808ch - ignore offset */
|
---|
| 691 | /*2000:8456*/ 0xff, 0xff, /* in AL, 040h */
|
---|
| 692 | /*2000:8458*/ 0xff, 0x00, 0x00, /* call 0808ch - ignore offset */
|
---|
| 693 | /*2000:845b*/ 0xff, 0xff, /* mov dl, al */
|
---|
| 694 | /*2000:845d*/ 0xff, 0xff, /* in AL, 040h */
|
---|
| 695 | /*2000:845f*/ 0xff, 0xff, /* mov dh, al */
|
---|
| 696 | /*2000:8461*/ 0xff, /* popfw */
|
---|
| 697 | /*2000:8462*/ 0xff, 0xff, /* sub bx, cx */
|
---|
| 698 | /*2000:8464*/ 0xff, 0xff, /* sub cx, dx */
|
---|
| 699 | /*2000:8466*/ 0xff, 0xff, /* sub cx, bx */
|
---|
| 700 | /*2000:8468*/ 0xff, 0xff, /* xchg dx, cx */
|
---|
| 701 | /*2000:846a*/ 0xff, 0xff, 0xff, /* mov ax, 00028h */
|
---|
| 702 | /*2000:846d*/ 0xff, 0xff, /* imul dx */
|
---|
| 703 | /*2000:846f*/ 0xff, 0xff, 0xff, /* mov bx, 00018h */
|
---|
| 704 | /*2000:8472*/ 0xff, 0xff, /* idiv bx */
|
---|
| 705 | /*2000:8474*/ 0xff, 0xff, /* xor dx, dx */
|
---|
| 706 | /*2000:8476*/ 0xff, 0x00, 0x00, /* mov bx, 01000h - ignore loop count */
|
---|
| 707 | /*2000:8479*/ 0xff, /* xchg bx, ax */
|
---|
| 708 | /*2000:847a*/ 0xff, 0xff, /* idiv bx */
|
---|
| 709 | /*2000:847c*/ 0xff, 0xff, /* or dx, dx */
|
---|
| 710 | /*2000:847e*/ 0xff, 0xff, /* je +001h (08481h) */
|
---|
| 711 | /*2000:8480*/ 0xff, /* inc ax */
|
---|
| 712 | /*2000:8481*/ 0xff, /* inc ax */
|
---|
| 713 | /*2000:8482*/ 0xff, 0x00, 0x00, /* mov word [0ac4dh], ax */
|
---|
| 714 | /*2000:8485*/ 0xff, /* pop DS */
|
---|
| 715 | /*2000:8486*/ 0xff, /* popaw */
|
---|
| 716 | /*2000:8487*/ 0xff, /* retn */
|
---|
| 717 | };
|
---|
| 718 | AssertCompile(sizeof(s_abVariant1Mask) == sizeof(s_abVariant1));
|
---|
| 719 |
|
---|
| 720 | /* uUser1 = off to start injecting code; uUser2 = jump target offset from start of pattern */
|
---|
| 721 | static const OS2CODEPATTERN s_aPatterns[] =
|
---|
| 722 | {
|
---|
| 723 | { s_abVariant1, s_abVariant1Mask, sizeof(s_abVariant1Mask), 0x840e - 0x840a, 0x8482 - 0x840a, 0, 0, 0 },
|
---|
| 724 | };
|
---|
| 725 |
|
---|
[104535] | 726 | PCOS2CODEPATTERN pPattern = NULL;
|
---|
[93094] | 727 | uint8_t *pbHit = findCodePattern(&s_aPatterns[0], RT_ELEMENTS(s_aPatterns), pbFile, cbFile, &pPattern);
|
---|
[104535] | 728 | if (pbHit)
|
---|
[93094] | 729 | {
|
---|
| 730 | uint8_t *pbJmpTarget = &pbHit[pPattern->uUser2];
|
---|
| 731 | uint8_t *pbPatch = &pbHit[pPattern->uUser1];
|
---|
| 732 | *pbPatch++ = 0xb8; /* mov ax, 01000h */
|
---|
| 733 | *pbPatch++ = 0x00;
|
---|
| 734 | *pbPatch++ = 0x10;
|
---|
| 735 | #if 0
|
---|
| 736 | *pbPatch++ = 0xfa; /* cli */
|
---|
| 737 | *pbPatch++ = 0xf4; /* hlt */
|
---|
| 738 | #endif
|
---|
| 739 | uint16_t offRel16 = (uint16_t)(pbJmpTarget - &pbPatch[3]);
|
---|
| 740 | *pbPatch++ = 0xe9; /* jmp rel16 */
|
---|
| 741 | *pbPatch++ = (uint8_t)offRel16;
|
---|
| 742 | *pbPatch++ = (uint8_t)(offRel16 >> 8);
|
---|
| 743 | *pbPatch++ = 0xcc;
|
---|
| 744 | *pbPatch++ = 0xcc;
|
---|
| 745 | }
|
---|
| 746 | else
|
---|
| 747 | LogRelFunc(("No patch pattern match!\n"));
|
---|
| 748 |
|
---|
| 749 | return VINF_SUCCESS;
|
---|
| 750 | }
|
---|
| 751 |
|
---|
[93085] | 752 | HRESULT UnattendedOs2Installer::copyFilesToAuxFloppyImage(RTVFS hVfs)
|
---|
| 753 | {
|
---|
| 754 | /*
|
---|
| 755 | * Make sure we've split the files already.
|
---|
| 756 | */
|
---|
| 757 | HRESULT hrc = splitResponseFile();
|
---|
| 758 | if (FAILED(hrc))
|
---|
| 759 | return hrc;
|
---|
| 760 |
|
---|
| 761 | /*
|
---|
| 762 | * We need to copy over the files needed to boot OS/2.
|
---|
| 763 | */
|
---|
| 764 | static struct
|
---|
| 765 | {
|
---|
| 766 | bool fMandatory;
|
---|
[93094] | 767 | const char *apszNames[2]; /**< Will always copy it over using the first name. */
|
---|
[93085] | 768 | const char *apszDisks[3];
|
---|
| 769 | const char *pszMinVer;
|
---|
| 770 | const char *pszMaxVer;
|
---|
[93094] | 771 | int (*pfnPatcher)(uint8_t *pbFile, size_t cbFile, const char *pszFilename, UnattendedOs2Installer *pThis);
|
---|
[93085] | 772 | } const s_aFiles[] =
|
---|
| 773 | {
|
---|
[93094] | 774 | { true, { "OS2BOOT", NULL }, { "DISK_0", NULL, NULL }, "2.1", NULL, NULL }, /* 2.0 did not have OS2BOOT */
|
---|
| 775 | { true, { "OS2LDR", NULL }, { "DISK_0", NULL, NULL }, NULL, NULL, patchOs2Ldr },
|
---|
| 776 | { true, { "OS2LDR.MSG", NULL }, { "DISK_0", NULL, NULL }, NULL, NULL, NULL },
|
---|
| 777 | { true, { "OS2KRNL", "OS2KRNLI" }, { "DISK_0", NULL, NULL }, NULL, NULL, NULL }, /* OS2KRNLI seems to trigger question for 2nd floppy */
|
---|
| 778 | { true, { "OS2DUMP", NULL }, { "DISK_0", NULL, NULL }, NULL, NULL, NULL },
|
---|
| 779 |
|
---|
| 780 | { true, { "ANSICALL.DLL", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 781 | { true, { "BKSCALLS.DLL", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 782 | { true, { "BMSCALLS.DLL", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 783 | { true, { "BVHINIT.DLL", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 784 | { true, { "BVSCALLS.DLL", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 785 | { true, { "CDFS.IFS", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 786 | { true, { "CLOCK01.SYS", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 787 | { true, { "COUNT437.SYS", "COUNTRY.SYS" }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 788 | { true, { "DOS.SYS", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 789 | { true, { "DOSCALL1.DLL", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 790 | { true, { "IBM1FLPY.ADD", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 791 | { true, { "IBM1S506.ADD", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 792 | { true, { "IBMIDECD.FLT", NULL }, { "DISK_1", "DISK_2", NULL }, "4.0", NULL, NULL }, /* not in 2.1 & Warp3 */
|
---|
| 793 | { true, { "IBMKBD.SYS", "KBD01.SYS"/*?*/}, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 794 | #if 1 /* Sometimes takes forever. (Bad IODelay count? Fixed by OS2LDR patching?) Removing seems to cause testcfg.sys to crash. */
|
---|
| 795 | { true, { "ISAPNP.SNP", NULL }, { "DISK_1", "DISK_2", NULL }, "4.0", NULL, NULL }, /* not in 2.1 */
|
---|
| 796 | #endif
|
---|
| 797 | { true, { "KBDBASE.SYS", NULL }, { "DISK_1", "DISK_2", NULL }, "3.0", NULL, NULL }, /* not in 2.1 */
|
---|
| 798 | { true, { "KBDCALLS.DLL", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 799 | { true, { "KEYBOARD.DCP", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 800 | { true, { "MOUCALLS.DLL", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 801 | { true, { "MSG.DLL", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 802 | { true, { "NAMPIPES.DLL", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 803 | { true, { "NLS.DLL", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 804 | { true, { "OS2CDROM.DMD", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 805 | { true, { "OS2CHAR.DLL", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 806 | { true, { "OS2DASD.DMD", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 807 | { true, { "OS2LVM.DMD", NULL }, { "DISK_1", "DISK_2", NULL }, "4.5", NULL, NULL },
|
---|
| 808 | { true, { "OS2VER", NULL }, { "DISK_0", NULL, NULL }, NULL, NULL, NULL },
|
---|
| 809 | { true, { "PNP.SYS", NULL }, { "DISK_1", "DISK_2", NULL }, "4.0", NULL, NULL },
|
---|
| 810 | { true, { "QUECALLS.DLL", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 811 | { true, { "RESOURCE.SYS", NULL }, { "DISK_1", "DISK_2", NULL }, "3.0", NULL, NULL }, /* not in 2.1*/
|
---|
| 812 | { true, { "SCREEN01.SYS", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 813 | { true, { "SESMGR.DLL", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
[93109] | 814 | { true, { "TESTCFG.SYS", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL, /*patchTestCfg*/ },
|
---|
[93094] | 815 | { true, { "VIO437.DCP", "VTBL850.DCP" }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
| 816 | { true, { "VIOCALLS.DLL", NULL }, { "DISK_1", "DISK_2", NULL }, NULL, NULL, NULL },
|
---|
[93085] | 817 | };
|
---|
| 818 |
|
---|
| 819 |
|
---|
| 820 | RTVFS hVfsOrgIso;
|
---|
| 821 | hrc = openInstallIsoImage(&hVfsOrgIso);
|
---|
| 822 | if (SUCCEEDED(hrc))
|
---|
| 823 | {
|
---|
| 824 | for (size_t i = 0; i < RT_ELEMENTS(s_aFiles); i++)
|
---|
| 825 | {
|
---|
| 826 | bool fCopied = false;
|
---|
| 827 | for (size_t iDisk = 0; iDisk < RT_ELEMENTS(s_aFiles[i].apszDisks) && s_aFiles[i].apszDisks[iDisk] && !fCopied; iDisk++)
|
---|
| 828 | {
|
---|
| 829 | for (size_t iName = 0; iName < RT_ELEMENTS(s_aFiles[i].apszNames) && s_aFiles[i].apszNames[iName]; iName++)
|
---|
| 830 | {
|
---|
| 831 | char szPath[256];
|
---|
| 832 | int vrc = RTPathJoin(szPath, sizeof(szPath), mStrOs2Images.c_str(), s_aFiles[i].apszDisks[iDisk]);
|
---|
| 833 | if (RT_SUCCESS(vrc))
|
---|
| 834 | vrc = RTPathAppend(szPath, sizeof(szPath), s_aFiles[i].apszNames[iName]);
|
---|
| 835 | AssertRCBreakStmt(vrc, hrc = mpParent->setErrorBoth(E_FAIL, vrc, tr("RTPathJoin/Append failed for %s: %Rrc"),
|
---|
| 836 | s_aFiles[i].apszNames[iName], vrc));
|
---|
| 837 | RTVFSFILE hVfsSrc;
|
---|
| 838 | vrc = RTVfsFileOpen(hVfsOrgIso, szPath, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE, &hVfsSrc);
|
---|
| 839 | if (RT_SUCCESS(vrc))
|
---|
| 840 | {
|
---|
| 841 | RTVFSFILE hVfsDst;
|
---|
| 842 | vrc = RTVfsFileOpen(hVfs, s_aFiles[i].apszNames[0],
|
---|
| 843 | RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE
|
---|
| 844 | | (0755 << RTFILE_O_CREATE_MODE_SHIFT), &hVfsDst);
|
---|
| 845 | if (RT_SUCCESS(vrc))
|
---|
| 846 | {
|
---|
[93094] | 847 | if (!s_aFiles[i].pfnPatcher)
|
---|
| 848 | {
|
---|
| 849 | /*
|
---|
| 850 | * Not patching this file, so just pump it thru and close it.
|
---|
| 851 | */
|
---|
| 852 | RTVFSIOSTREAM hVfsIosSrc = RTVfsFileToIoStream(hVfsSrc);
|
---|
| 853 | RTVFSIOSTREAM hVfsIosDst = RTVfsFileToIoStream(hVfsDst);
|
---|
| 854 | vrc = RTVfsUtilPumpIoStreams(hVfsIosSrc, hVfsIosDst, 0);
|
---|
| 855 | RTVfsIoStrmRelease(hVfsIosDst);
|
---|
| 856 | RTVfsIoStrmRelease(hVfsIosSrc);
|
---|
| 857 | if (RT_FAILURE(vrc))
|
---|
| 858 | hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc,
|
---|
| 859 | tr("Failed to write %s to the floppy: %Rrc"),
|
---|
| 860 | s_aFiles[i].apszNames, vrc);
|
---|
| 861 | }
|
---|
| 862 | else
|
---|
| 863 | {
|
---|
| 864 | /*
|
---|
| 865 | * Read the file into memory, do the patching and writed
|
---|
| 866 | * the patched content to the floppy.
|
---|
| 867 | */
|
---|
| 868 | uint64_t cbFile = 0;
|
---|
| 869 | vrc = RTVfsFileQuerySize(hVfsSrc, &cbFile);
|
---|
| 870 | if (RT_SUCCESS(vrc) && cbFile < _32M)
|
---|
| 871 | {
|
---|
| 872 | uint8_t *pbFile = (uint8_t *)RTMemTmpAllocZ((size_t)cbFile);
|
---|
| 873 | if (pbFile)
|
---|
| 874 | {
|
---|
| 875 | vrc = RTVfsFileRead(hVfsSrc, pbFile, (size_t)cbFile, NULL);
|
---|
| 876 | if (RT_SUCCESS(vrc))
|
---|
| 877 | {
|
---|
| 878 | vrc = s_aFiles[i].pfnPatcher(pbFile, (size_t)cbFile, s_aFiles[i].apszNames[0], this);
|
---|
| 879 | if (RT_SUCCESS(vrc))
|
---|
| 880 | {
|
---|
| 881 | vrc = RTVfsFileWrite(hVfsDst, pbFile, (size_t)cbFile, NULL);
|
---|
| 882 | if (RT_FAILURE(vrc))
|
---|
| 883 | hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc,
|
---|
| 884 | tr("Failed to write %s to the floppy: %Rrc"),
|
---|
| 885 | s_aFiles[i].apszNames, vrc);
|
---|
| 886 | }
|
---|
| 887 | else
|
---|
| 888 | hrc = mpParent->setErrorBoth(E_FAIL, vrc, tr("Patcher failed for '%s': %Rrc"),
|
---|
| 889 | s_aFiles[i].apszNames, vrc);
|
---|
| 890 | }
|
---|
| 891 | else
|
---|
| 892 | hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc,
|
---|
| 893 | tr("Error reading '%s' into memory for patching: %Rrc"),
|
---|
| 894 | s_aFiles[i].apszNames, vrc);
|
---|
| 895 | RTMemTmpFree(pbFile);
|
---|
| 896 | }
|
---|
| 897 | else
|
---|
| 898 | hrc = mpParent->setError(E_OUTOFMEMORY, tr("Failed to allocate %zu bytes for '%s'"),
|
---|
| 899 | (size_t)cbFile, s_aFiles[i].apszNames);
|
---|
| 900 | }
|
---|
| 901 | else if (RT_FAILURE(vrc))
|
---|
| 902 | hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc,
|
---|
| 903 | tr("Failed to query the size of '%s': %Rrc"),
|
---|
| 904 | s_aFiles[i].apszNames, vrc);
|
---|
| 905 | else
|
---|
| 906 | hrc = mpParent->setErrorBoth(E_FAIL, VERR_OUT_OF_RANGE, tr("File too big to patch: '%s'"),
|
---|
| 907 | s_aFiles[i].apszNames);
|
---|
| 908 | }
|
---|
[93085] | 909 | RTVfsFileRelease(hVfsDst);
|
---|
| 910 | }
|
---|
| 911 | else
|
---|
| 912 | hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to open %s on floppy: %Rrc"),
|
---|
| 913 | s_aFiles[i].apszNames, vrc);
|
---|
| 914 |
|
---|
| 915 | RTVfsFileRelease(hVfsSrc);
|
---|
| 916 | fCopied = true;
|
---|
| 917 | break;
|
---|
| 918 | }
|
---|
| 919 | }
|
---|
| 920 | }
|
---|
| 921 | if (FAILED(hrc))
|
---|
| 922 | break;
|
---|
| 923 | if (!fCopied)
|
---|
| 924 | {
|
---|
| 925 | /** @todo do version filtering. */
|
---|
| 926 | hrc = mpParent->setErrorBoth(E_FAIL, VERR_FILE_NOT_FOUND,
|
---|
| 927 | tr("Failed to locate '%s' needed for the install floppy"), s_aFiles[i].apszNames[0]);
|
---|
| 928 | break;
|
---|
| 929 | }
|
---|
| 930 | }
|
---|
| 931 | RTVfsRelease(hVfsOrgIso);
|
---|
| 932 | }
|
---|
| 933 |
|
---|
| 934 | /*
|
---|
| 935 | * In addition, we need to add a CONFIG.SYS and the startup script.
|
---|
| 936 | */
|
---|
| 937 | if (SUCCEEDED(hrc))
|
---|
| 938 | {
|
---|
| 939 | Utf8Str strSrc;
|
---|
| 940 | try
|
---|
| 941 | {
|
---|
| 942 | strSrc = mpParent->i_getAuxiliaryBasePath();
|
---|
| 943 | strSrc.append("CONFIG.SYS");
|
---|
| 944 | }
|
---|
| 945 | catch (std::bad_alloc &)
|
---|
| 946 | {
|
---|
| 947 | return E_OUTOFMEMORY;
|
---|
| 948 | }
|
---|
| 949 | hrc = addFileToFloppyImage(hVfs, strSrc.c_str(), "CONFIG.SYS");
|
---|
| 950 | }
|
---|
| 951 |
|
---|
| 952 | /*
|
---|
| 953 | * We also want a ALTF2ON.$$$ file so we can see which drivers are loaded
|
---|
| 954 | * and where it might get stuck.
|
---|
| 955 | */
|
---|
| 956 | if (SUCCEEDED(hrc))
|
---|
| 957 | {
|
---|
| 958 | RTVFSFILE hVfsFile;
|
---|
| 959 | int vrc = RTVfsFileOpen(hVfs, "ALTF2ON.$$$",
|
---|
| 960 | RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE
|
---|
| 961 | | (0755 << RTFILE_O_CREATE_MODE_SHIFT), &hVfsFile);
|
---|
| 962 | if (RT_SUCCESS(vrc))
|
---|
| 963 | {
|
---|
| 964 | /** @todo buggy fat vfs: cannot write empty files */
|
---|
| 965 | RTVfsFileWrite(hVfsFile, RT_STR_TUPLE("\r\n"), NULL);
|
---|
| 966 | RTVfsFileRelease(hVfsFile);
|
---|
| 967 | }
|
---|
| 968 | else
|
---|
| 969 | hrc = mpParent->setErrorBoth(E_FAIL, VERR_FILE_NOT_FOUND, tr("Failed to create 'ALTF2ON.$$$' on the install floppy"));
|
---|
| 970 | }
|
---|
| 971 |
|
---|
| 972 | return hrc;
|
---|
| 973 | }
|
---|
| 974 |
|
---|
| 975 | HRESULT UnattendedOs2Installer::addFilesToAuxVisoVectors(RTCList<RTCString> &rVecArgs, RTCList<RTCString> &rVecFiles,
|
---|
| 976 | RTVFS hVfsOrgIso, bool fOverwrite)
|
---|
| 977 | {
|
---|
| 978 | /*
|
---|
| 979 | * Make sure we've split the files already.
|
---|
| 980 | */
|
---|
| 981 | HRESULT hrc = splitResponseFile();
|
---|
| 982 | if (FAILED(hrc))
|
---|
| 983 | return hrc;
|
---|
| 984 |
|
---|
| 985 | /*
|
---|
| 986 | * Add our stuff to the vectors.
|
---|
[93122] | 987 | *
|
---|
| 988 | * Note! Typcially OS/2 ISOs are without joliet or UDF namespaces, given
|
---|
| 989 | * their age and tools used to produce them, but more recent ones
|
---|
| 990 | * like ArcaOS have joliet present. So, to avoid ending up with an
|
---|
| 991 | * almost empty CDROM in Phase2 because UDF.IFS is loaded and
|
---|
| 992 | * presenting the joliet namespace, the --name-setup-from-import
|
---|
| 993 | * option was added to the ISO maker. It will look at the files that
|
---|
| 994 | * were imported and adjust the --name-setup accordingly (logged).
|
---|
[93085] | 995 | */
|
---|
| 996 | try
|
---|
| 997 | {
|
---|
| 998 | /* Remaster ISO. */
|
---|
| 999 | rVecArgs.append() = "--no-file-mode";
|
---|
| 1000 | rVecArgs.append() = "--no-dir-mode";
|
---|
| 1001 |
|
---|
| 1002 | rVecArgs.append() = "--import-iso";
|
---|
| 1003 | rVecArgs.append(mpParent->i_getIsoPath());
|
---|
[93122] | 1004 | rVecArgs.append() = "--name-setup-from-import"; /* */
|
---|
[93085] | 1005 |
|
---|
[93122] | 1006 | /** @todo these enables rock-ridge... */
|
---|
[93085] | 1007 | rVecArgs.append() = "--file-mode=0444";
|
---|
| 1008 | rVecArgs.append() = "--dir-mode=0555";
|
---|
| 1009 |
|
---|
| 1010 | /* Add the boot floppy to the ISO: */
|
---|
| 1011 | rVecArgs.append() = "--eltorito-new-entry";
|
---|
| 1012 | rVecArgs.append() = "--eltorito-add-image";
|
---|
[93122] | 1013 | rVecArgs.append().assign("VBoxBootFloppy.img=").append(mStrAuxiliaryFloppyFilePath);
|
---|
[93085] | 1014 | rVecArgs.append() = "--eltorito-floppy-288";
|
---|
| 1015 |
|
---|
| 1016 | /* Add the response files and postinstall files to the ISO: */
|
---|
| 1017 | Utf8Str const &rStrAuxPrefix = mpParent->i_getAuxiliaryBasePath();
|
---|
| 1018 | size_t i = mVecSplitFiles.size();
|
---|
| 1019 | while (i-- > 0)
|
---|
| 1020 | {
|
---|
| 1021 | RTCString const &rStrFile = mVecSplitFiles[i];
|
---|
| 1022 | rVecArgs.append().assign("VBoxCID/").append(rStrFile).append('=').append(rStrAuxPrefix).append(rStrFile);
|
---|
| 1023 | }
|
---|
[93122] | 1024 |
|
---|
| 1025 | /* Add the os2_util.exe to the ISO: */
|
---|
| 1026 | Utf8Str strUnattendedTemplates;
|
---|
| 1027 | int vrc = RTPathAppPrivateNoArchCxx(strUnattendedTemplates);
|
---|
| 1028 | AssertRCReturn(vrc, mpParent->setErrorVrc(vrc));
|
---|
| 1029 | vrc = RTPathAppendCxx(strUnattendedTemplates, "UnattendedTemplates");
|
---|
| 1030 | AssertRCReturn(vrc, mpParent->setErrorVrc(vrc));
|
---|
| 1031 | rVecArgs.append().assign("VBoxCID/os2_util.exe=").append(strUnattendedTemplates).append("/os2_util.exe");
|
---|
[93085] | 1032 | }
|
---|
| 1033 | catch (std::bad_alloc &)
|
---|
| 1034 | {
|
---|
| 1035 | return E_OUTOFMEMORY;
|
---|
| 1036 | }
|
---|
| 1037 |
|
---|
| 1038 | /*
|
---|
| 1039 | * Call parent.
|
---|
| 1040 | */
|
---|
| 1041 | return UnattendedInstaller::addFilesToAuxVisoVectors(rVecArgs, rVecFiles, hVfsOrgIso, fOverwrite);
|
---|
| 1042 | }
|
---|
| 1043 |
|
---|
| 1044 | /**
|
---|
| 1045 | * Helper for splitFile.
|
---|
| 1046 | */
|
---|
[99775] | 1047 | static const char *splitFileLocateSubstring(const char *pszSrc, size_t cchSrc, const char *pszSubstring, size_t cchSubstring)
|
---|
[93085] | 1048 | {
|
---|
| 1049 | char const ch0 = *pszSubstring;
|
---|
| 1050 | while (cchSrc >= cchSubstring)
|
---|
| 1051 | {
|
---|
| 1052 | const char *pszHit0 = (const char *)memchr(pszSrc, ch0, cchSrc - cchSubstring + 1);
|
---|
| 1053 | if (pszHit0)
|
---|
| 1054 | {
|
---|
| 1055 | if (memcmp(pszHit0, pszSubstring, cchSubstring) == 0)
|
---|
| 1056 | return pszHit0;
|
---|
| 1057 | }
|
---|
| 1058 | else
|
---|
| 1059 | break;
|
---|
[93089] | 1060 | cchSrc -= (size_t)(pszHit0 - pszSrc) + 1;
|
---|
[93085] | 1061 | pszSrc = pszHit0 + 1;
|
---|
| 1062 | }
|
---|
| 1063 | return NULL;
|
---|
| 1064 | }
|
---|
| 1065 |
|
---|
| 1066 | /**
|
---|
| 1067 | * Worker for splitFile().
|
---|
| 1068 | */
|
---|
| 1069 | HRESULT UnattendedOs2Installer::splitFileInner(const char *pszFileToSplit, RTCList<RTCString> &rVecSplitFiles,
|
---|
| 1070 | const char *pszSrc, size_t cbLeft) RT_NOEXCEPT
|
---|
| 1071 | {
|
---|
| 1072 | static const char s_szPrefix[] = "@@VBOX_SPLITTER_";
|
---|
| 1073 | const char * const pszStart = pszSrc;
|
---|
| 1074 | const char * const pszEnd = &pszSrc[cbLeft];
|
---|
| 1075 | while (cbLeft > 0)
|
---|
| 1076 | {
|
---|
| 1077 | /*
|
---|
| 1078 | * Locate the next split start marker (everything before it is ignored).
|
---|
| 1079 | */
|
---|
| 1080 | const char *pszMarker = splitFileLocateSubstring(pszSrc, cbLeft, s_szPrefix, sizeof(s_szPrefix) - 1);
|
---|
| 1081 | if (pszMarker)
|
---|
| 1082 | pszMarker += sizeof(s_szPrefix) - 1;
|
---|
| 1083 | else
|
---|
| 1084 | break;
|
---|
| 1085 | if (strncmp(pszMarker, RT_STR_TUPLE("START[")) != 0)
|
---|
| 1086 | return mpParent->setErrorBoth(E_FAIL, VERR_PARSE_ERROR,
|
---|
| 1087 | tr("Unexpected splitter tag in '%s' at offset %p: @@VBOX_SPLITTER_%.64s"),
|
---|
| 1088 | pszFileToSplit, pszMarker - pszStart, pszMarker);
|
---|
| 1089 | pszMarker += sizeof("START[") - 1;
|
---|
[93089] | 1090 | const char *pszTail = splitFileLocateSubstring(pszMarker, (size_t)(pszEnd - pszMarker), RT_STR_TUPLE("]@@"));
|
---|
[93098] | 1091 | size_t const cchFilename = (size_t)(pszTail - pszMarker);
|
---|
[93085] | 1092 | if ( !pszTail
|
---|
[93098] | 1093 | || cchFilename > 64
|
---|
| 1094 | || memchr(pszMarker, '\\', cchFilename)
|
---|
| 1095 | || memchr(pszMarker, '/', cchFilename)
|
---|
| 1096 | || memchr(pszMarker, ':', cchFilename)
|
---|
| 1097 | || memchr(pszMarker, '\0', cchFilename) )
|
---|
[93085] | 1098 | return mpParent->setErrorBoth(E_FAIL, VERR_PARSE_ERROR,
|
---|
| 1099 | tr("Malformed splitter tag in '%s' at offset %p: @@VBOX_SPLITTER_START[%.64s"),
|
---|
[93098] | 1100 | pszFileToSplit, cchFilename, pszMarker);
|
---|
| 1101 | int vrc = RTStrValidateEncodingEx(pszMarker, cchFilename, RTSTR_VALIDATE_ENCODING_EXACT_LENGTH);
|
---|
[93085] | 1102 | if (RT_FAILURE(vrc))
|
---|
| 1103 | return mpParent->setErrorBoth(E_FAIL, vrc,
|
---|
| 1104 | tr("Malformed splitter tag in '%s' at offset %p: @@VBOX_SPLITTER_START[%.*Rhxs"),
|
---|
[93098] | 1105 | pszFileToSplit, cchFilename, pszTail - pszMarker, pszMarker);
|
---|
[93085] | 1106 | const char *pszFilename;
|
---|
| 1107 | try
|
---|
| 1108 | {
|
---|
[93098] | 1109 | pszFilename = rVecSplitFiles.append().assign(pszMarker, cchFilename).c_str();
|
---|
[93085] | 1110 | }
|
---|
| 1111 | catch (std::bad_alloc &)
|
---|
| 1112 | {
|
---|
| 1113 | return E_OUTOFMEMORY;
|
---|
| 1114 | }
|
---|
| 1115 | const char *pszDocStart = pszTail + sizeof("]@@") - 1;
|
---|
| 1116 | while (RT_C_IS_SPACE(*pszDocStart))
|
---|
| 1117 | if (*pszDocStart++ == '\n')
|
---|
| 1118 | break;
|
---|
| 1119 |
|
---|
| 1120 | /* Advance. */
|
---|
| 1121 | pszSrc = pszDocStart;
|
---|
[93096] | 1122 | cbLeft = (size_t)(pszEnd - pszDocStart);
|
---|
[93085] | 1123 |
|
---|
| 1124 | /*
|
---|
| 1125 | * Locate the matching end marker (there cannot be any other markers inbetween).
|
---|
| 1126 | */
|
---|
| 1127 | const char * const pszDocEnd = pszMarker = splitFileLocateSubstring(pszSrc, cbLeft, s_szPrefix, sizeof(s_szPrefix) - 1);
|
---|
| 1128 | if (pszMarker)
|
---|
| 1129 | pszMarker += sizeof(s_szPrefix) - 1;
|
---|
| 1130 | else
|
---|
| 1131 | return mpParent->setErrorBoth(E_FAIL, VERR_PARSE_ERROR,
|
---|
| 1132 | tr("No END splitter tag for '%s' in '%s'"), pszFilename, pszFileToSplit);
|
---|
| 1133 | if (strncmp(pszMarker, RT_STR_TUPLE("END[")) != 0)
|
---|
| 1134 | return mpParent->setErrorBoth(E_FAIL, VERR_PARSE_ERROR,
|
---|
| 1135 | tr("Unexpected splitter tag in '%s' at offset %p: @@VBOX_SPLITTER_%.64s"),
|
---|
[93089] | 1136 | pszFileToSplit, (size_t)(pszEnd - pszMarker), pszMarker);
|
---|
[93085] | 1137 | pszMarker += sizeof("END[") - 1;
|
---|
| 1138 | if ( strncmp(pszMarker, pszFilename, cchFilename) != 0
|
---|
| 1139 | || pszMarker[cchFilename] != ']'
|
---|
| 1140 | || pszMarker[cchFilename + 1] != '@'
|
---|
| 1141 | || pszMarker[cchFilename + 2] != '@')
|
---|
| 1142 | return mpParent->setErrorBoth(E_FAIL, VERR_PARSE_ERROR,
|
---|
| 1143 | tr("Mismatching splitter tag for '%s' in '%s' at offset %p: @@VBOX_SPLITTER_END[%.64Rhxs"),
|
---|
[93089] | 1144 | pszFilename, pszFileToSplit, (size_t)(pszEnd - pszMarker), pszMarker);
|
---|
[93085] | 1145 |
|
---|
| 1146 | /* Advance. */
|
---|
| 1147 | pszSrc = pszMarker + cchFilename + sizeof("]@@") - 1;
|
---|
[93089] | 1148 | cbLeft = (size_t)(pszEnd - pszSrc);
|
---|
[93085] | 1149 |
|
---|
| 1150 | /*
|
---|
| 1151 | * Write out the file.
|
---|
| 1152 | */
|
---|
| 1153 | Utf8Str strDstFilename;
|
---|
| 1154 | vrc = strDstFilename.assignNoThrow(mpParent->i_getAuxiliaryBasePath());
|
---|
| 1155 | if (RT_SUCCESS(vrc))
|
---|
| 1156 | vrc = strDstFilename.appendNoThrow(pszFilename);
|
---|
| 1157 | if (RT_SUCCESS(vrc))
|
---|
| 1158 | {
|
---|
| 1159 | RTFILE hFile;
|
---|
| 1160 | vrc = RTFileOpen(&hFile, strDstFilename.c_str(), RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);
|
---|
| 1161 | if (RT_SUCCESS(vrc))
|
---|
| 1162 | {
|
---|
[93089] | 1163 | vrc = RTFileWrite(hFile, pszDocStart, (size_t)(pszDocEnd - pszDocStart), NULL);
|
---|
[93085] | 1164 | if (RT_SUCCESS(vrc))
|
---|
| 1165 | vrc = RTFileClose(hFile);
|
---|
| 1166 | else
|
---|
| 1167 | RTFileClose(hFile);
|
---|
| 1168 | if (RT_FAILURE(vrc))
|
---|
| 1169 | return mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Error writing '%s' (split out from '%s'): %Rrc"),
|
---|
| 1170 | strDstFilename.c_str(), pszFileToSplit, vrc);
|
---|
| 1171 | }
|
---|
| 1172 | else
|
---|
| 1173 | return mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc,
|
---|
| 1174 | tr("File splitter failed to open output file '%s' in '%s': %Rrc (%s)"),
|
---|
| 1175 | pszFilename, pszFileToSplit, vrc, strDstFilename.c_str());
|
---|
| 1176 | }
|
---|
| 1177 | else
|
---|
| 1178 | return mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc,
|
---|
| 1179 | tr("File splitter failed to construct path for '%s' in '%s': %Rrc"),
|
---|
| 1180 | pszFilename, pszFileToSplit, vrc);
|
---|
| 1181 | }
|
---|
| 1182 |
|
---|
| 1183 | return S_OK;
|
---|
| 1184 | }
|
---|
| 1185 |
|
---|
| 1186 | HRESULT UnattendedOs2Installer::splitFile(const char *pszFileToSplit, RTCList<RTCString> &rVecSplitFiles) RT_NOEXCEPT
|
---|
| 1187 | {
|
---|
| 1188 | /*
|
---|
| 1189 | * Read the whole source file into memory, making sure it's zero terminated.
|
---|
| 1190 | */
|
---|
| 1191 | HRESULT hrc;
|
---|
| 1192 | void *pvSrc;
|
---|
| 1193 | size_t cbSrc;
|
---|
| 1194 | int vrc = RTFileReadAllEx(pszFileToSplit, 0 /*off*/, _16M /*cbMax*/,
|
---|
| 1195 | RTFILE_RDALL_F_TRAILING_ZERO_BYTE | RTFILE_RDALL_F_FAIL_ON_MAX_SIZE | RTFILE_RDALL_O_DENY_WRITE,
|
---|
| 1196 | &pvSrc, &cbSrc);
|
---|
| 1197 | if (RT_SUCCESS(vrc))
|
---|
| 1198 | {
|
---|
| 1199 | /*
|
---|
| 1200 | * Do the actual splitting in a worker function to avoid needing to
|
---|
| 1201 | * thing about calling RTFileReadAllFree in error paths.
|
---|
| 1202 | */
|
---|
| 1203 | hrc = splitFileInner(pszFileToSplit, rVecSplitFiles, (const char *)pvSrc, cbSrc);
|
---|
| 1204 | RTFileReadAllFree(pvSrc, cbSrc);
|
---|
| 1205 | }
|
---|
| 1206 | else
|
---|
| 1207 | hrc = mpParent->setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to read '%s' for splitting up: %Rrc"),
|
---|
| 1208 | pszFileToSplit, vrc);
|
---|
| 1209 | return hrc;
|
---|
| 1210 | }
|
---|
| 1211 |
|
---|
| 1212 | HRESULT UnattendedOs2Installer::splitFile(BaseTextScript *pEditor, RTCList<RTCString> &rVecSplitFiles) RT_NOEXCEPT
|
---|
| 1213 | {
|
---|
| 1214 | /*
|
---|
| 1215 | * Get the output from the editor.
|
---|
| 1216 | */
|
---|
| 1217 | Utf8Str strSrc;
|
---|
| 1218 | HRESULT hrc = pEditor->saveToString(strSrc);
|
---|
| 1219 | if (SUCCEEDED(hrc))
|
---|
| 1220 | {
|
---|
| 1221 | /*
|
---|
| 1222 | * Do the actual splitting.
|
---|
| 1223 | */
|
---|
| 1224 | hrc = splitFileInner(pEditor->getDefaultFilename(), rVecSplitFiles, strSrc.c_str(), strSrc.length());
|
---|
| 1225 | }
|
---|
| 1226 | return hrc;
|
---|
| 1227 | }
|
---|
| 1228 |
|
---|