Files
xen/tools/firmware/hvmloader/config.h
T
Roger Pau Monne 22650d6054 x86/hvmloader: select xen platform pci MMIO BAR UC or WB MTRR cache attribute
The Xen platform PCI device (vendor ID 0x5853) exposed to x86 HVM guests
doesn't have the functionality of a traditional PCI device.  The exposed
MMIO BAR is used by some guests (including Linux) as a safe place to map
foreign memory, including the grant table itself.

Traditionally BARs from devices have the uncacheable (UC) cache attribute
from the MTRR, to ensure correct functionality of such devices.  hvmloader
mimics this behavior and sets the MTRR attributes of both the low and high
PCI MMIO windows (where BARs of PCI devices reside) as UC in MTRR.

This however causes performance issues for users of the Xen platform PCI
device BAR, as for the purposes of mapping remote memory there's no need to
use the UC attribute.  On Intel systems this is worked around by using
iPAT, that allows the hypervisor to force the effective cache attribute of
a p2m entry regardless of the guest PAT value.  AMD however doesn't have an
equivalent of iPAT, and guest PAT values are always considered.

Linux commit:

41925b105e34 xen: replace xen_remap() with memremap()

Attempted to mitigate this by forcing mappings of the grant-table to use
the write-back (WB) cache attribute.  However Linux memremap() takes MTRRs
into account to calculate which PAT type to use, and seeing the MTRR cache
attribute for the region being UC the PAT also ends up as UC, regardless of
the caller having requested WB.

As a workaround to allow current Linux to map the grant-table as WB using
memremap() introduce an xl.cfg option (xen_platform_pci_bar_uc=0) that can
be used to select whether the Xen platform PCI device BAR will have the UC
attribute in MTRR.  Such workaround in hvmloader should also be paired with
a fix for Linux so it attempts to change the MTRR of the Xen platform PCI
device BAR to WB by itself.

Overall, the long term solution would be to provide the guest with a safe
range in the guest physical address space where mappings to foreign pages
can be created.

Some vif throughput performance figures provided by Anthoine from a 8
vCPUs, 4GB of RAM HVM guest(s) running on AMD hardware:

Without this patch:
vm -> dom0: 1.1Gb/s
vm -> vm:   5.0Gb/s

With the patch:
vm -> dom0: 4.5Gb/s
vm -> vm:   7.0Gb/s

Reported-by: Anthoine Bourgeois <anthoine.bourgeois@vates.tech>
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Oleksii Kurochko<oleksii.kurochko@gmail.com>
Acked-by: Jan Beulich <jbeulich@suse.com> # hvmloader
Reviewed-by: Anthony PERARD <anthony.perard@vates.tech>
2025-06-18 09:30:11 +02:00

101 lines
2.7 KiB
C

#ifndef __HVMLOADER_CONFIG_H__
#define __HVMLOADER_CONFIG_H__
#include <stdint.h>
#include <stdbool.h>
enum virtual_vga { VGA_none, VGA_std, VGA_cirrus, VGA_pt };
extern enum virtual_vga virtual_vga;
extern unsigned long igd_opregion_pgbase;
#define IGD_OPREGION_PAGES 3
struct bios_config {
const char *name;
/* BIOS ROM image bits */
void *image;
unsigned int image_size;
/* Physical address to load at */
unsigned int bios_address;
/* ROMS */
void (*load_roms)(void);
void (*bios_load)(const struct bios_config *config, void *addr,
uint32_t size, void *extra_addr);
void (*bios_info_setup)(void);
void (*bios_info_finish)(void);
void (*e820_setup)(void);
void (*acpi_build_tables)(void);
void (*create_mp_tables)(void);
void (*create_smbios_tables)(void);
void (*create_pir_tables)(void);
};
extern struct bios_config rombios_config;
extern struct bios_config seabios_config;
extern struct bios_config ovmf_config;
#define PAGE_SHIFT 12
#define PAGE_SIZE (1ul << PAGE_SHIFT)
extern uint8_t ioapic_version;
#define IOAPIC_ID 0x01
extern uint32_t *cpu_to_apicid;
#define LAPIC_BASE_ADDRESS 0xfee00000
#define PCI_ISA_DEVFN 0x08 /* dev 1, fn 0 */
#define PCI_ISA_IRQ_MASK 0x0c20U /* ISA IRQs 5,10,11 are PCI connected */
#define ACPI_TIS_HDR_ADDRESS 0xFED40F00UL
extern uint32_t pci_mem_start;
extern uint32_t pci_mem_end;
extern uint64_t pci_hi_mem_start, pci_hi_mem_end;
extern bool acpi_enabled;
/* Memory map. */
#define SCRATCH_PHYSICAL_ADDRESS 0x00010000
#define HYPERCALL_PHYSICAL_ADDRESS 0x00080000
#define VGABIOS_PHYSICAL_ADDRESS 0x000C0000
#define HVMLOADER_PHYSICAL_ADDRESS 0x00100000
/* Special BIOS mappings, etc. are allocated from here upwards... */
#define RESERVED_MEMBASE 0xFC000000
/* NB. ACPI_INFO_PHYSICAL_ADDRESS *MUST* match definition in acpi/dsdt.asl! */
#define ACPI_INFO_PHYSICAL_ADDRESS 0xFC000000
#define ACPI_MEMORY_DYNAMIC_START 0xFC001000
#define RESERVED_MEMORY_DYNAMIC_START 0xFC100000
#define RESERVED_MEMORY_DYNAMIC_END 0xFE000000
/*
* GUEST_RESERVED: Physical address space reserved for guest use.
* This is not dynamically advertised to guests, so this range must *never*
* be used for any purpose by us, in future. It must always be marked as
* reserved in the memory map (e.g., E820_RESERVED) so that mechanisms such
* as PCI BAR remapping do not allocate from this region.
*/
#define GUEST_RESERVED_START 0xFE700000
#define GUEST_RESERVED_END 0xFE800000
extern unsigned long scratch_start;
#endif /* __HVMLOADER_CONFIG_H__ */
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/