qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] (PAM stuff) reset doesn't work on OVMF + SeaBIOS CSM


From: Laszlo Ersek
Subject: [Qemu-devel] (PAM stuff) reset doesn't work on OVMF + SeaBIOS CSM
Date: Thu, 14 Feb 2013 21:41:03 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:10.0.12) Gecko/20130108 Thunderbird/10.0.12

Hi,

I noticed that under OVMF + SeaBIOS CSM + your related patches for both,
reset requested by the guest doesn't work as expected. The behavior is
an infinite loop, with the following debug fragment repeated by the
CSM-ized SeaBIOS:

  In resume (status=0)
  In 32bit resume
  Attempting a hard reboot
  i8042_wait_write

The corresponding call chain seems to be:

  reset_vector() [src/romlayout.S]
    entry_post()
      entry_resume()
        handle_resume() [src/resume.c]
          prints "In resume"
          handle_resume32()
            prints "In 32bit resume"
            tryReboot()
              prints "Attempting a hard reboot"
              i8042_reboot() [src/ps2port.c]
                i8042_wait_write()
                  prints "i8042_wait_write"
                outb(0xfe, PORT_PS2_STATUS)

(The entry_post -> entry_resume jump occurs because HaveRunPost has been
set to 1 by csm_maininit() --> interface_init() --> ivt_init().)

At this point kbd_write_command() in qemu-kvm's "hw/pckbd.c", case
KBD_CCMD_RESET, requests a system reset. Soon the reset handlers run,
among them cpu_reset() (which was registered by

  pc_init1() [hw/pc.c]
    pc_new_cpu()

). cpu_reset() [target-i386/helper.c] sets CS:IP to f000:fff0, which is
the exact address of... reset_vector() in SeaBIOS.

Of course OVMF should be re-run instead of SeaBIOS. When qemu-kvm
starts, "OVMF.fd" is installed as ROM, such that the last address it
occupies is "all-bits-one", independently of its size (below a limit of
course):

  pc_init1() [hw/pc.c]
    rom_add_file_fixed() []
      open() / read() /close()
      rom_insert()
    some calls to inform KVM


I think when OVMF runs SeaBIOS as CSM, OVMF shadows the original ROM
(containing the OVMF binary itself) with the SeaBIOS code + static data
(I'm peeking at
<http://en.wikipedia.org/wiki/Shadow_RAM#Shadow_RAM>...). This should
render SeaBIOS visible / executable / writeable in the top 16-bit
segment, and leave OVMF in a permanently unusable state (in RAM at least).

My guess at the relevant edk2 function is ShadowAndStartLegacy16()
[IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c]. The
LegacyRegion->UnLock() call should be instrumental (implemented in
"OvmfPkg/Csm/CsmSupportLib/LegacyRegion.c" with PAM (Programmable
Attribute Map) registers?)

Hence I *presume* qemu-kvm should un-shadow the ROM at reset time (ie.
make OVMF visible again as ROM) not later than allowing the VCPU to
continue at f000:fff0 again. Normally that address should be occupied by
OVMF code from (I guess) "UefiCpuPkg/ResetVector/Vtf0".

Does this make any sense? Is qemu-kvm forgetting to reset the PAMs? Or
would that be the responsibility of tryReboot() in SeaBIOS?

... Aah! qemu_prep_reset() in SeaBIOS [src/shadow.c] goes like:

void
qemu_prep_reset(void)
{
    if (!CONFIG_QEMU)
        return;
    // QEMU doesn't map 0xc0000-0xfffff back to the original rom on a
    // reset, so do that manually before invoking a hard reset.
    make_bios_writable();
    extern u8 code32flat_start[], code32flat_end[];
    memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET
           , code32flat_end - code32flat_start);

    if (HaveRunPost)
        // Memory copy failed to work - try to halt the machine.
        apm_shutdown();
}

and this function is actually called inside the infinite loop (I ignored
it before):

            tryReboot()
              prints "Attempting a hard reboot"
              qemu_prep_reset() [src/shadow.c] <-------------- here
              i8042_reboot() [src/ps2port.c]
                i8042_wait_write()
                  prints "i8042_wait_write"
                outb(0xfe, PORT_PS2_STATUS)

but of course it doesn't do anything with CONFIG_CSM (since that implies
!CONFIG_QEMU). What's more, qemu_prep_reset() and
make_bios_writable_intel() seem to exploit SeaBIOS characteristics
(code32flat_*, HaveRunPost etc.) that probably make no sense when the
data being restored is a different (= OVMF) image.

Can we dumb down ^W^W generalize this code? :) Or maybe should qemu
introduce a reset handler for PAMs?

(I realize I've been reading all the time about PAMs, in the "Writeable
files in fw_cfg" thread, in the discussion about unlocking the 0xE0000
segment for stack purposes... Didn't understand a single word before,
sorry. Downloaded my copy of the i440FX spec just today; I finally have
a remote idea how shadowing / write-protecting works.)

Thanks!
Laszlo



reply via email to

[Prev in Thread] Current Thread [Next in Thread]