diff mbox

ARM: Virt: Don't generate RTC ACPI node when using UEFI

Message ID 1452612274-30218-1-git-send-email-shannon.zhao@linaro.org
State New
Headers show

Commit Message

Shannon Zhao Jan. 12, 2016, 3:24 p.m. UTC
When booting VM through UEFI, UEFI takes ownership of the RTC hardware.
To DTB UEFI could call libfdt api to disable the RTC device node, but to
ACPI it couldn't do that. Therefore, we don't generate the RTC ACPI
device in QEMU when using UEFI.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>

---
 hw/arm/virt-acpi-build.c         | 13 +++++++++++--
 hw/arm/virt.c                    |  5 ++++-
 include/hw/arm/virt-acpi-build.h |  1 +
 3 files changed, 16 insertions(+), 3 deletions(-)

-- 
2.1.0

Comments

Peter Maydell Jan. 12, 2016, 3:30 p.m. UTC | #1
On 12 January 2016 at 15:24, Shannon Zhao <shannon.zhao@linaro.org> wrote:
> When booting VM through UEFI, UEFI takes ownership of the RTC hardware.

> To DTB UEFI could call libfdt api to disable the RTC device node, but to

> ACPI it couldn't do that. Therefore, we don't generate the RTC ACPI

> device in QEMU when using UEFI.


I don't really understand this. I thought that if we were
using ACPI then we would always be doing it via UEFI?

Also I think if UEFI wants to take command of some of the
hardware it ought to be UEFI's job to adjust the tables
accordingly before it passes them on to the guest OS.

thanks
-- PMM
Laszlo Ersek Jan. 13, 2016, 10:09 a.m. UTC | #2
On 01/12/16 16:30, Peter Maydell wrote:
> On 12 January 2016 at 15:24, Shannon Zhao <shannon.zhao@linaro.org> wrote:

>> When booting VM through UEFI, UEFI takes ownership of the RTC hardware.

>> To DTB UEFI could call libfdt api to disable the RTC device node, but to

>> ACPI it couldn't do that. Therefore, we don't generate the RTC ACPI

>> device in QEMU when using UEFI.

> 

> I don't really understand this. I thought that if we were

> using ACPI then we would always be doing it via UEFI?


Yes.

Let my try to summarize here too:

- kernel booted without UEFI: consumes DTB, accesses RTC directly

- kernel booted with UEFI, consumes DTB: UEFI owns RTC, kernel uses UEFI
services, UEFI keeps kernel from directly accessing the RTC by disabling
the RTC node in the DTB, using libfdt

- kernel booted with UEFI, consumes ACPI: UEFI owns RTC, kernel uses
UEFI services, UEFI keeps kernel from directly accessing the RTC by...,
well, it can't, because we don't *parse* AML in UEFI.

> Also I think if UEFI wants to take command of some of the

> hardware it ought to be UEFI's job to adjust the tables

> accordingly before it passes them on to the guest OS.


In theory, maybe.

In practice, no; we have the ACPI linker/loader for that. Either the
generated AML must not contain the RTC node, or else some linker/loader
script command(s) have to be added that cause the guest firmware's
linker/loader client to patch the device out. Generally speaking
however, the linker/loader can only patch data tables, not definition
blocks (AML).

You might ask why the DTB is different then. Why aren't I suggesting, in
paralle, that the DTB generator behave similarly in QEMU? The answer is
that the firmware needs the RTC node in the DTB for its *own* purposes
as well, so the RTC node must be in the DTB in any case.

ACPI is different. The firmware downloads it, patches it blindly (=
processes the linker/loader script), then passes it to the OS. That's all.

Formatting AML is doable in the firmware; parsing / modifying AML that
was originally generated by QEMU is practically impossible. If you
recall the *original* introducion of the ACPI interpreter into the
kernel -- there was a huge uproar. Today Linux has a customized version
of the ACPI CA framework. edk2 doesn't, and shouldn't.

Plus, *intelligently* modifying AML in the firmware defeats the purpose
of the ACPI linker/loader -- which is to allow the firmware to remain
ignorant about ACPI.

Thanks
Laszlo
Laszlo Ersek Jan. 13, 2016, 10:18 a.m. UTC | #3
On 01/12/16 16:24, Shannon Zhao wrote:
> When booting VM through UEFI, UEFI takes ownership of the RTC hardware.

> To DTB UEFI could call libfdt api to disable the RTC device node, but to

> ACPI it couldn't do that. Therefore, we don't generate the RTC ACPI

> device in QEMU when using UEFI.

> 

> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>

> ---

>  hw/arm/virt-acpi-build.c         | 13 +++++++++++--

>  hw/arm/virt.c                    |  5 ++++-

>  include/hw/arm/virt-acpi-build.h |  1 +

>  3 files changed, 16 insertions(+), 3 deletions(-)

> 

> diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c

> index 0caf5ce..cccec79 100644

> --- a/hw/arm/virt-acpi-build.c

> +++ b/hw/arm/virt-acpi-build.c

> @@ -575,8 +575,17 @@ build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)

>      acpi_dsdt_add_cpus(scope, guest_info->smp_cpus);

>      acpi_dsdt_add_uart(scope, &memmap[VIRT_UART],

>                         (irqmap[VIRT_UART] + ARM_SPI_BASE));

> -    acpi_dsdt_add_rtc(scope, &memmap[VIRT_RTC],

> -                      (irqmap[VIRT_RTC] + ARM_SPI_BASE));

> +

> +    /* When booting VM through UEFI, UEFI takes ownership of the RTC hardware.

> +     * To DTB UEFI could call libfdt api to disable the RTC device node, but to

> +     * ACPI it couldn't do that. Therefore, we don't generate the RTC ACPI

> +     * device here when using UEFI.

> +     */

> +    if (guest_info->acpi_rtc) {

> +        acpi_dsdt_add_rtc(scope, &memmap[VIRT_RTC],

> +                          (irqmap[VIRT_RTC] + ARM_SPI_BASE));

> +    }

> +

>      acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]);

>      acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO],

>                      (irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS);

> diff --git a/hw/arm/virt.c b/hw/arm/virt.c

> index fd52b76..de12037 100644

> --- a/hw/arm/virt.c

> +++ b/hw/arm/virt.c

> @@ -1002,6 +1002,7 @@ static void machvirt_init(MachineState *machine)

>      VirtGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state);

>      VirtGuestInfo *guest_info = &guest_info_state->info;

>      char **cpustr;

> +    bool firmware_loaded;

>  

>      if (!cpu_model) {

>          cpu_model = "cortex-a15";

> @@ -1124,12 +1125,14 @@ static void machvirt_init(MachineState *machine)

>      create_fw_cfg(vbi, &address_space_memory);

>      rom_set_fw(fw_cfg_find());

>  

> +    firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);

>      guest_info->smp_cpus = smp_cpus;

>      guest_info->fw_cfg = fw_cfg_find();

>      guest_info->memmap = vbi->memmap;

>      guest_info->irqmap = vbi->irqmap;

>      guest_info->use_highmem = vms->highmem;

>      guest_info->gic_version = gic_version;

> +    guest_info->acpi_rtc = !firmware_loaded;

>      guest_info_state->machine_done.notify = virt_guest_info_machine_done;

>      qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);

>  

> @@ -1141,7 +1144,7 @@ static void machvirt_init(MachineState *machine)

>      vbi->bootinfo.board_id = -1;

>      vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base;

>      vbi->bootinfo.get_dtb = machvirt_dtb;

> -    vbi->bootinfo.firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);

> +    vbi->bootinfo.firmware_loaded = firmware_loaded;

>      arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo);

>  

>      /*

> diff --git a/include/hw/arm/virt-acpi-build.h b/include/hw/arm/virt-acpi-build.h

> index 744b666..6f412a4 100644

> --- a/include/hw/arm/virt-acpi-build.h

> +++ b/include/hw/arm/virt-acpi-build.h

> @@ -33,6 +33,7 @@ typedef struct VirtGuestInfo {

>      const int *irqmap;

>      bool use_highmem;

>      int gic_version;

> +    bool acpi_rtc;

>  } VirtGuestInfo;

>  

>  

> 


I realize that Peter is not buying the argument just yet, but I'd like
to offer a review here nonetheless.

I think the patch is good, except the location and the wording of the
code comment.

(1) The code comment should be located right above the

    guest_info->acpi_rtc = !firmware_loaded;

assignment.

(2) I think the code comment should simply use indicative mood:

    When booting the VM with UEFI, UEFI takes ownership of the RTC
    hardware. While UEFI can use libfdt to disable the RTC device node
    in the DTB that it passes to the OS, it cannot modify AML.
    Therefore, we won't generate the RTC ACPI device at all when using
    UEFI.

With those changes, I'm willing to R-b.

Thanks
Laszlo
Ard Biesheuvel Jan. 13, 2016, 10:20 a.m. UTC | #4
On 13 January 2016 at 11:18, Laszlo Ersek <lersek@redhat.com> wrote:
> On 01/12/16 16:24, Shannon Zhao wrote:

>> When booting VM through UEFI, UEFI takes ownership of the RTC hardware.

>> To DTB UEFI could call libfdt api to disable the RTC device node, but to

>> ACPI it couldn't do that. Therefore, we don't generate the RTC ACPI

>> device in QEMU when using UEFI.

>>

>> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>

>> ---

>>  hw/arm/virt-acpi-build.c         | 13 +++++++++++--

>>  hw/arm/virt.c                    |  5 ++++-

>>  include/hw/arm/virt-acpi-build.h |  1 +

>>  3 files changed, 16 insertions(+), 3 deletions(-)

>>

>> diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c

>> index 0caf5ce..cccec79 100644

>> --- a/hw/arm/virt-acpi-build.c

>> +++ b/hw/arm/virt-acpi-build.c

>> @@ -575,8 +575,17 @@ build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)

>>      acpi_dsdt_add_cpus(scope, guest_info->smp_cpus);

>>      acpi_dsdt_add_uart(scope, &memmap[VIRT_UART],

>>                         (irqmap[VIRT_UART] + ARM_SPI_BASE));

>> -    acpi_dsdt_add_rtc(scope, &memmap[VIRT_RTC],

>> -                      (irqmap[VIRT_RTC] + ARM_SPI_BASE));

>> +

>> +    /* When booting VM through UEFI, UEFI takes ownership of the RTC hardware.

>> +     * To DTB UEFI could call libfdt api to disable the RTC device node, but to

>> +     * ACPI it couldn't do that. Therefore, we don't generate the RTC ACPI

>> +     * device here when using UEFI.

>> +     */

>> +    if (guest_info->acpi_rtc) {

>> +        acpi_dsdt_add_rtc(scope, &memmap[VIRT_RTC],

>> +                          (irqmap[VIRT_RTC] + ARM_SPI_BASE));

>> +    }

>> +

>>      acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]);

>>      acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO],

>>                      (irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS);

>> diff --git a/hw/arm/virt.c b/hw/arm/virt.c

>> index fd52b76..de12037 100644

>> --- a/hw/arm/virt.c

>> +++ b/hw/arm/virt.c

>> @@ -1002,6 +1002,7 @@ static void machvirt_init(MachineState *machine)

>>      VirtGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state);

>>      VirtGuestInfo *guest_info = &guest_info_state->info;

>>      char **cpustr;

>> +    bool firmware_loaded;

>>

>>      if (!cpu_model) {

>>          cpu_model = "cortex-a15";

>> @@ -1124,12 +1125,14 @@ static void machvirt_init(MachineState *machine)

>>      create_fw_cfg(vbi, &address_space_memory);

>>      rom_set_fw(fw_cfg_find());

>>

>> +    firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);

>>      guest_info->smp_cpus = smp_cpus;

>>      guest_info->fw_cfg = fw_cfg_find();

>>      guest_info->memmap = vbi->memmap;

>>      guest_info->irqmap = vbi->irqmap;

>>      guest_info->use_highmem = vms->highmem;

>>      guest_info->gic_version = gic_version;

>> +    guest_info->acpi_rtc = !firmware_loaded;

>>      guest_info_state->machine_done.notify = virt_guest_info_machine_done;

>>      qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);

>>

>> @@ -1141,7 +1144,7 @@ static void machvirt_init(MachineState *machine)

>>      vbi->bootinfo.board_id = -1;

>>      vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base;

>>      vbi->bootinfo.get_dtb = machvirt_dtb;

>> -    vbi->bootinfo.firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);

>> +    vbi->bootinfo.firmware_loaded = firmware_loaded;

>>      arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo);

>>

>>      /*

>> diff --git a/include/hw/arm/virt-acpi-build.h b/include/hw/arm/virt-acpi-build.h

>> index 744b666..6f412a4 100644

>> --- a/include/hw/arm/virt-acpi-build.h

>> +++ b/include/hw/arm/virt-acpi-build.h

>> @@ -33,6 +33,7 @@ typedef struct VirtGuestInfo {

>>      const int *irqmap;

>>      bool use_highmem;

>>      int gic_version;

>> +    bool acpi_rtc;

>>  } VirtGuestInfo;

>>

>>

>>

>

> I realize that Peter is not buying the argument just yet, but I'd like

> to offer a review here nonetheless.

>


I am not buying it either, to be honest. In fact, I think it is
another reason why we should mandate UEFI when using ACPI (which is
already the case in practice). Then, we can simply omit the RTC ACPI
node entirely.


> I think the patch is good, except the location and the wording of the

> code comment.

>

> (1) The code comment should be located right above the

>

>     guest_info->acpi_rtc = !firmware_loaded;

>

> assignment.

>

> (2) I think the code comment should simply use indicative mood:

>

>     When booting the VM with UEFI, UEFI takes ownership of the RTC

>     hardware. While UEFI can use libfdt to disable the RTC device node

>     in the DTB that it passes to the OS, it cannot modify AML.

>     Therefore, we won't generate the RTC ACPI device at all when using

>     UEFI.

>

> With those changes, I'm willing to R-b.

>

> Thanks

> Laszlo
Laszlo Ersek Jan. 13, 2016, 10:48 a.m. UTC | #5
On 01/13/16 11:20, Ard Biesheuvel wrote:
> On 13 January 2016 at 11:18, Laszlo Ersek <lersek@redhat.com> wrote:

>> On 01/12/16 16:24, Shannon Zhao wrote:

>>> When booting VM through UEFI, UEFI takes ownership of the RTC hardware.

>>> To DTB UEFI could call libfdt api to disable the RTC device node, but to

>>> ACPI it couldn't do that. Therefore, we don't generate the RTC ACPI

>>> device in QEMU when using UEFI.

>>>

>>> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>

>>> ---

>>>  hw/arm/virt-acpi-build.c         | 13 +++++++++++--

>>>  hw/arm/virt.c                    |  5 ++++-

>>>  include/hw/arm/virt-acpi-build.h |  1 +

>>>  3 files changed, 16 insertions(+), 3 deletions(-)

>>>

>>> diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c

>>> index 0caf5ce..cccec79 100644

>>> --- a/hw/arm/virt-acpi-build.c

>>> +++ b/hw/arm/virt-acpi-build.c

>>> @@ -575,8 +575,17 @@ build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)

>>>      acpi_dsdt_add_cpus(scope, guest_info->smp_cpus);

>>>      acpi_dsdt_add_uart(scope, &memmap[VIRT_UART],

>>>                         (irqmap[VIRT_UART] + ARM_SPI_BASE));

>>> -    acpi_dsdt_add_rtc(scope, &memmap[VIRT_RTC],

>>> -                      (irqmap[VIRT_RTC] + ARM_SPI_BASE));

>>> +

>>> +    /* When booting VM through UEFI, UEFI takes ownership of the RTC hardware.

>>> +     * To DTB UEFI could call libfdt api to disable the RTC device node, but to

>>> +     * ACPI it couldn't do that. Therefore, we don't generate the RTC ACPI

>>> +     * device here when using UEFI.

>>> +     */

>>> +    if (guest_info->acpi_rtc) {

>>> +        acpi_dsdt_add_rtc(scope, &memmap[VIRT_RTC],

>>> +                          (irqmap[VIRT_RTC] + ARM_SPI_BASE));

>>> +    }

>>> +

>>>      acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]);

>>>      acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO],

>>>                      (irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS);

>>> diff --git a/hw/arm/virt.c b/hw/arm/virt.c

>>> index fd52b76..de12037 100644

>>> --- a/hw/arm/virt.c

>>> +++ b/hw/arm/virt.c

>>> @@ -1002,6 +1002,7 @@ static void machvirt_init(MachineState *machine)

>>>      VirtGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state);

>>>      VirtGuestInfo *guest_info = &guest_info_state->info;

>>>      char **cpustr;

>>> +    bool firmware_loaded;

>>>

>>>      if (!cpu_model) {

>>>          cpu_model = "cortex-a15";

>>> @@ -1124,12 +1125,14 @@ static void machvirt_init(MachineState *machine)

>>>      create_fw_cfg(vbi, &address_space_memory);

>>>      rom_set_fw(fw_cfg_find());

>>>

>>> +    firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);

>>>      guest_info->smp_cpus = smp_cpus;

>>>      guest_info->fw_cfg = fw_cfg_find();

>>>      guest_info->memmap = vbi->memmap;

>>>      guest_info->irqmap = vbi->irqmap;

>>>      guest_info->use_highmem = vms->highmem;

>>>      guest_info->gic_version = gic_version;

>>> +    guest_info->acpi_rtc = !firmware_loaded;

>>>      guest_info_state->machine_done.notify = virt_guest_info_machine_done;

>>>      qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);

>>>

>>> @@ -1141,7 +1144,7 @@ static void machvirt_init(MachineState *machine)

>>>      vbi->bootinfo.board_id = -1;

>>>      vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base;

>>>      vbi->bootinfo.get_dtb = machvirt_dtb;

>>> -    vbi->bootinfo.firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);

>>> +    vbi->bootinfo.firmware_loaded = firmware_loaded;

>>>      arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo);

>>>

>>>      /*

>>> diff --git a/include/hw/arm/virt-acpi-build.h b/include/hw/arm/virt-acpi-build.h

>>> index 744b666..6f412a4 100644

>>> --- a/include/hw/arm/virt-acpi-build.h

>>> +++ b/include/hw/arm/virt-acpi-build.h

>>> @@ -33,6 +33,7 @@ typedef struct VirtGuestInfo {

>>>      const int *irqmap;

>>>      bool use_highmem;

>>>      int gic_version;

>>> +    bool acpi_rtc;

>>>  } VirtGuestInfo;

>>>

>>>

>>>

>>

>> I realize that Peter is not buying the argument just yet, but I'd like

>> to offer a review here nonetheless.

>>

> 

> I am not buying it either, to be honest. In fact, I think it is

> another reason why we should mandate UEFI when using ACPI (which is

> already the case in practice). Then, we can simply omit the RTC ACPI

> node entirely.


Good point.

Laszlo

> 

> 

>> I think the patch is good, except the location and the wording of the

>> code comment.

>>

>> (1) The code comment should be located right above the

>>

>>     guest_info->acpi_rtc = !firmware_loaded;

>>

>> assignment.

>>

>> (2) I think the code comment should simply use indicative mood:

>>

>>     When booting the VM with UEFI, UEFI takes ownership of the RTC

>>     hardware. While UEFI can use libfdt to disable the RTC device node

>>     in the DTB that it passes to the OS, it cannot modify AML.

>>     Therefore, we won't generate the RTC ACPI device at all when using

>>     UEFI.

>>

>> With those changes, I'm willing to R-b.

>>

>> Thanks

>> Laszlo
Peter Maydell Jan. 13, 2016, 11:52 a.m. UTC | #6
On 13 January 2016 at 10:48, Laszlo Ersek <lersek@redhat.com> wrote:
> On 01/13/16 11:20, Ard Biesheuvel wrote:

>> I am not buying it either, to be honest. In fact, I think it is

>> another reason why we should mandate UEFI when using ACPI (which is

>> already the case in practice). Then, we can simply omit the RTC ACPI

>> node entirely.

>

> Good point.


Yes, a patch that simply removed the RTC device from the
ACPI table altogether would I think be better. That then
continues with the current approach that the tables provided
by QEMU are intended for use only with a UEFI bios in
the picture.

thanks
-- PMM
diff mbox

Patch

diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 0caf5ce..cccec79 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -575,8 +575,17 @@  build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
     acpi_dsdt_add_cpus(scope, guest_info->smp_cpus);
     acpi_dsdt_add_uart(scope, &memmap[VIRT_UART],
                        (irqmap[VIRT_UART] + ARM_SPI_BASE));
-    acpi_dsdt_add_rtc(scope, &memmap[VIRT_RTC],
-                      (irqmap[VIRT_RTC] + ARM_SPI_BASE));
+
+    /* When booting VM through UEFI, UEFI takes ownership of the RTC hardware.
+     * To DTB UEFI could call libfdt api to disable the RTC device node, but to
+     * ACPI it couldn't do that. Therefore, we don't generate the RTC ACPI
+     * device here when using UEFI.
+     */
+    if (guest_info->acpi_rtc) {
+        acpi_dsdt_add_rtc(scope, &memmap[VIRT_RTC],
+                          (irqmap[VIRT_RTC] + ARM_SPI_BASE));
+    }
+
     acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]);
     acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO],
                     (irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS);
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index fd52b76..de12037 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -1002,6 +1002,7 @@  static void machvirt_init(MachineState *machine)
     VirtGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state);
     VirtGuestInfo *guest_info = &guest_info_state->info;
     char **cpustr;
+    bool firmware_loaded;
 
     if (!cpu_model) {
         cpu_model = "cortex-a15";
@@ -1124,12 +1125,14 @@  static void machvirt_init(MachineState *machine)
     create_fw_cfg(vbi, &address_space_memory);
     rom_set_fw(fw_cfg_find());
 
+    firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);
     guest_info->smp_cpus = smp_cpus;
     guest_info->fw_cfg = fw_cfg_find();
     guest_info->memmap = vbi->memmap;
     guest_info->irqmap = vbi->irqmap;
     guest_info->use_highmem = vms->highmem;
     guest_info->gic_version = gic_version;
+    guest_info->acpi_rtc = !firmware_loaded;
     guest_info_state->machine_done.notify = virt_guest_info_machine_done;
     qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
 
@@ -1141,7 +1144,7 @@  static void machvirt_init(MachineState *machine)
     vbi->bootinfo.board_id = -1;
     vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base;
     vbi->bootinfo.get_dtb = machvirt_dtb;
-    vbi->bootinfo.firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);
+    vbi->bootinfo.firmware_loaded = firmware_loaded;
     arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo);
 
     /*
diff --git a/include/hw/arm/virt-acpi-build.h b/include/hw/arm/virt-acpi-build.h
index 744b666..6f412a4 100644
--- a/include/hw/arm/virt-acpi-build.h
+++ b/include/hw/arm/virt-acpi-build.h
@@ -33,6 +33,7 @@  typedef struct VirtGuestInfo {
     const int *irqmap;
     bool use_highmem;
     int gic_version;
+    bool acpi_rtc;
 } VirtGuestInfo;