VirtualBox

Changeset 100456 in vbox for trunk


Ignore:
Timestamp:
Jul 10, 2023 1:46:21 PM (22 months ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
158203
Message:

BIOS: Added a way for the APM BIOS to halt the virtual CPU through port I/O instead of HLT to solve problems with obstinate guests (see bugref:6549).

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/bios.h

    r98103 r100456  
    4242#endif
    4343
    44 /** The BIOS shutdown port.
    45  * You write "Shutdown" byte by byte to shutdown the VM.
     44/** The BIOS control port.
     45 * Write "Shutdown" byte by byte to shutdown the VM.
     46 * Write "Bootfail" to indicate no bootable device.
     47 * Write "Prochalt" to execute alternative CPU halt.
    4648 * @sa VBOX_BIOS_OLD_SHUTDOWN_PORT  */
    4749#define VBOX_BIOS_SHUTDOWN_PORT                 0x040f
    4850
     51/** Write this value to shut down VM. */
     52#define VBOX_BIOS_CTL_SHUTDOWN                  0x8001
     53/** Write this value to report boot failure. */
     54#define VBOX_BIOS_CTL_BOOTFAIL                  0x8002
     55/** Write this value to halt CPU. */
     56#define VBOX_BIOS_CTL_PROCHALT                  0x8003
     57
    4958/** The old shutdown port number.
    5059 * Older versions of VirtualBox uses this as does Bochs.
    51  * @sa VBOX_BIOS_SHUTDOWN_PORT  */
     60 * @sa VBOX_BIOS_CONTROL_PORT  */
    5261#define VBOX_BIOS_OLD_SHUTDOWN_PORT             0x8900
    5362
  • trunk/include/VBox/bios.mac

    r98103 r100456  
    4141%endif
    4242%define VBOX_BIOS_SHUTDOWN_PORT                 0x040f
     43%define VBOX_BIOS_CTL_SHUTDOWN                  0x8001
     44%define VBOX_BIOS_CTL_BOOTFAIL                  0x8002
     45%define VBOX_BIOS_CTL_PROCHALT                  0x8003
    4346%define VBOX_BIOS_OLD_SHUTDOWN_PORT             0x8900
    4447%endif
  • trunk/src/VBox/Devices/PC/BIOS/apm.c

    r98103 r100456  
    162162        /// @todo change connection state
    163163        break;
     164#if VBOX_BIOS_CPU >= 80286
    164165    case APM_PM_CONN:
    165166        /// @todo validate device ID
     
    172173        DI = APM_BIOS_SEG_LEN;          /* Data segment length. */
    173174        break;
     175#endif
    174176#if VBOX_BIOS_CPU >= 80386
    175177    case APM_32_CONN:
  • trunk/src/VBox/Devices/PC/BIOS/apm_pm.asm

    r98103 r100456  
    3838public          apm_pm16_entry
    3939
     40;
     41; This module is for protected mode only and therefore
     42; 286+ only
     43;
    4044SET_DEFAULT_CPU_286
    4145
     
    8286
    8387apmf_idle:                              ; function 05h
     88if 1
     89                ; Port I/O based HLT equivalent using a custom BIOS I/O port.
     90                ; Works in situations where HLT can't be used, such as Windows 3.1
     91                ; in Standard mode or DR-DOS 5.0/6.0 EMM386.SYS.
     92                push    si
     93                push    cx
     94                push    dx
     95
     96                mov     dx, 40Fh
     97                mov     si, offset hlt_string
     98                mov     cx,8
     99                rep outsb
     100
     101                pop     dx
     102                pop     cx
     103                pop     si
     104
     105                jmp     apmw_success
     106
     107hlt_string      db      'Prochalt'
     108
     109else
    84110                ;
    85111                ; Windows 3.1 POWER.DRV in Standard mode calls into APM
     
    95121                hlt
    96122                jmp     apmw_success
     123endif
    97124
    98125apmf_busy:                              ; function 06h
  • trunk/src/VBox/Devices/PC/DevPcBios.cpp

    r100444 r100456  
    227227    /** Whether to clear the shutdown status on hard reset. */
    228228    bool            fClearShutdownStatusOnHardReset;
    229     /** Current port number for Bochs shutdown (used by APM). */
    230     RTIOPORT        ShutdownPort;
    231     /** True=use new port number for Bochs shutdown (used by APM). */
    232     bool            fNewShutdownPort;
     229    /** Current port number for BIOS control (used by APM). */
     230    RTIOPORT        ControlPort;
     231    /** True=use new port number for BIOS control (used by APM). */
     232    bool            fNewControlPort;
    233233    bool            afPadding[3+4];
    234     /** The shudown I/O port, either at 0x040f or 0x8900 (old saved state). */
    235     IOMMMIOHANDLE   hIoPortShutdown;
     234    /** The BIOS I/O port, either at 0x040f or 0x8900
     235     *  (old saved state). */
     236    IOMMMIOHANDLE   hIoPortControl;
    236237} DEVPCBIOS;
    237238/** Pointer to the BIOS device state. */
     
    252253static SSMFIELD const g_aPcBiosFields[] =
    253254{
    254     SSMFIELD_ENTRY(         DEVPCBIOS, fNewShutdownPort),
     255    SSMFIELD_ENTRY(         DEVPCBIOS, fNewControlPort),
    255256    SSMFIELD_ENTRY_TERM()
    256257};
     
    325326
    326327/**
    327  * @callback_method_impl{FNIOMIOPORTNEWIN, Bochs Shutdown port.}
     328 * @callback_method_impl{FNIOMIOPORTNEWIN, BIOS control port.}
    328329 */
    329330static DECLCALLBACK(VBOXSTRICTRC)
    330 pcbiosIOPortShutdownRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
     331pcbiosIOPortControlRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
    331332{
    332333    RT_NOREF5(pDevIns, pvUser, offPort, pu32, cb);
     
    335336
    336337
    337 /**
    338  * @callback_method_impl{FNIOMIOPORTNEWOUT, Bochs Shutdown port.}
     338static VBOXSTRICTRC pcbiosApmShutdown(PPDMDEVINS pDevIns)
     339{
     340    LogRel(("PcBios: APM shutdown request\n"));
     341    return PDMDevHlpVMPowerOff(pDevIns);
     342}
     343
     344
     345static VBOXSTRICTRC pcbiosApmIdle(PPDMDEVINS pDevIns)
     346{
     347    Log3(("PcBios: APM idle request\n"));
     348
     349    /* This request is used to put the CPU into a halted state *without* using
     350     * a HLT instruction. This is especially useful for the APM BIOS
     351     * in situations where executing HLT causes problems. See BIOS APM source
     352     * code for comments.
     353     * NB: The CPU will be woken up by an interrupt regardless of the
     354     * state of rFLAGS.IF.
     355     */
     356    int rc = PDMDevHlpVMWaitForDeviceReady(pDevIns, PDMDevHlpGetCurrentCpuId(pDevIns));
     357    return rc;
     358}
     359
     360static void pcbiosReportBootFail(PPDMDEVINS pDevIns)
     361{
     362    LogRel(("PcBios: Boot failure\n"));
     363    int rc = PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "VMBootFail",
     364                                        N_("The VM failed to boot. This is possibly caused by not having an operating system installed or a misconfigured boot order. Maybe picking a guest OS install DVD will resolve the situation"));
     365    AssertRC(rc);
     366}
     367
     368
     369/**
     370 * @callback_method_impl{FNIOMIOPORTNEWOUT, BIOS control port.}
    339371 */
    340372static DECLCALLBACK(VBOXSTRICTRC)
    341 pcbiosIOPortShutdownWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
     373pcbiosIOPortControlWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
    342374{
    343375    PDEVPCBIOS pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPCBIOS);
     
    349381        static const unsigned char s_szShutdown[] = "Shutdown";
    350382        static const unsigned char s_szBootfail[] = "Bootfail";
     383        static const unsigned char s_szProchalt[] = "Prochalt";
    351384        AssertCompile(sizeof(s_szShutdown) == sizeof(s_szBootfail));
     385        AssertCompile(sizeof(s_szShutdown) == sizeof(s_szProchalt));
    352386
    353387        if (pThis->iControl < sizeof(s_szShutdown)) /* paranoia */
     
    360394                {
    361395                    pThis->iControl = 0;
    362                     LogRel(("PcBios: APM shutdown request\n"));
    363                     return PDMDevHlpVMPowerOff(pDevIns);
     396                    return pcbiosApmShutdown(pDevIns);
    364397                }
    365398            }
     
    370403                {
    371404                    pThis->iControl = 0;
    372                     LogRel(("PcBios: Boot failure\n"));
    373                     int rc = PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "VMBootFail",
    374                                                         N_("The VM failed to boot. This is possibly caused by not having an operating system installed or a misconfigured boot order. Maybe picking a guest OS install DVD will resolve the situation"));
    375                     AssertRC(rc);
     405                    pcbiosReportBootFail(pDevIns);
     406                }
     407            }
     408            else if (u32 == s_szProchalt[pThis->iControl])
     409            {
     410
     411                pThis->iControl++;
     412                if (pThis->iControl >= 8)
     413                {
     414                    pThis->iControl = 0;
     415                    return pcbiosApmIdle(pDevIns);
    376416                }
    377417            }
     
    382422            pThis->iControl = 0;
    383423    }
     424    else if (cb == 2)
     425    {
     426        pThis->iControl = 0;
     427        /* Shortcuts for BIOS control, allowing guest to use one simple 16-bit I/O port write. */
     428        switch (u32)
     429        {
     430        case VBOX_BIOS_CTL_SHUTDOWN:
     431            return pcbiosApmShutdown(pDevIns);
     432        case VBOX_BIOS_CTL_BOOTFAIL:
     433            pcbiosReportBootFail(pDevIns);
     434            break;
     435        case VBOX_BIOS_CTL_PROCHALT:
     436            return pcbiosApmIdle(pDevIns);
     437        default:
     438            /* Ignore and do nothing. */
     439            LogFunc(("unrecognized control value (u32=%X)\n", u32));
     440        }
     441    }
    384442    /* else: not in use. */
    385443
     
    389447
    390448/**
    391  * Register the Bochs shutdown port.
     449 * Register the BIOS control port.
    392450 * This is used by pcbiosConstruct, pcbiosReset and pcbiosLoadExec.
    393451 */
    394 static int pcbiosRegisterShutdown(PPDMDEVINS pDevIns, PDEVPCBIOS pThis, bool fNewShutdownPort)
    395 {
    396     if (pThis->ShutdownPort != 0)
    397     {
    398         int rc = PDMDevHlpIoPortUnmap(pDevIns, pThis->hIoPortShutdown);
     452static int pcbiosRegisterControl(PPDMDEVINS pDevIns, PDEVPCBIOS pThis, bool fNewControlPort)
     453{
     454    if (pThis->ControlPort != 0)
     455    {
     456        int rc = PDMDevHlpIoPortUnmap(pDevIns, pThis->hIoPortControl);
    399457        AssertRC(rc);
    400458    }
    401459
    402     pThis->fNewShutdownPort = fNewShutdownPort;
    403     if (fNewShutdownPort)
    404         pThis->ShutdownPort = VBOX_BIOS_SHUTDOWN_PORT;
     460    pThis->fNewControlPort = fNewControlPort;
     461    if (fNewControlPort)
     462        pThis->ControlPort = VBOX_BIOS_SHUTDOWN_PORT;
    405463    else
    406         pThis->ShutdownPort = VBOX_BIOS_OLD_SHUTDOWN_PORT;
    407     return PDMDevHlpIoPortMap(pDevIns, pThis->hIoPortShutdown, pThis->ShutdownPort);
     464        pThis->ControlPort = VBOX_BIOS_OLD_SHUTDOWN_PORT;
     465    return PDMDevHlpIoPortMap(pDevIns, pThis->hIoPortControl, pThis->ControlPort);
    408466}
    409467
     
    421479/**
    422480 * @callback_method_impl{FNSSMDEVLOADPREP,
    423  *      Clears the fNewShutdownPort flag prior to loading the state so that old
     481 *      Clears the fNewControlPort flag prior to loading the state so that old
    424482 *      saved VM states keeps using the old port address (no pcbios state)}
    425483 */
     
    431489    /* Since there are legacy saved state files without any SSM data for PCBIOS
    432490     * this is the only way to handle them correctly. */
    433     pThis->fNewShutdownPort = false;
     491    pThis->fNewControlPort = false;
    434492
    435493    return VINF_SUCCESS;
     
    460518    RT_NOREF(pSSM);
    461519    PDEVPCBIOS pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPCBIOS);
    462     return pcbiosRegisterShutdown(pDevIns, pThis, pThis->fNewShutdownPort);
     520    return pcbiosRegisterControl(pDevIns, pThis, pThis->fNewControlPort);
    463521}
    464522
     
    542600    }
    543601
    544     /* After reset the new BIOS code is active, use the new shutdown port. */
    545     pcbiosRegisterShutdown(pDevIns, pThis, true /* fNewShutdownPort */);
     602    /* After reset the new BIOS code is active, use the new control port. */
     603    pcbiosRegisterControl(pDevIns, pThis, true /* fNewControlPort */);
    546604}
    547605
     
    15061564    AssertRCReturn(rc, rc);
    15071565
    1508     rc = PDMDevHlpIoPortCreateIsa(pDevIns, 1 /*cPorts*/, pcbiosIOPortShutdownWrite, pcbiosIOPortShutdownRead, NULL /*pvUser*/,
    1509                                   "Bochs PC BIOS - Shutdown", NULL /*paExtDescs*/, &pThis->hIoPortShutdown);
     1566    rc = PDMDevHlpIoPortCreateIsa(pDevIns, 1 /*cPorts*/, pcbiosIOPortControlWrite, pcbiosIOPortControlRead, NULL /*pvUser*/,
     1567                                  "PC BIOS - Control", NULL /*paExtDescs*/, &pThis->hIoPortControl);
    15101568    AssertRCReturn(rc, rc);
    1511     rc = pcbiosRegisterShutdown(pDevIns, pThis, true /* fNewShutdownPort */);
     1569    rc = pcbiosRegisterControl(pDevIns, pThis, true /* fNewControlPort */);
    15121570    AssertRCReturn(rc, rc);
    15131571
Note: See TracChangeset for help on using the changeset viewer.

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