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