DM: gvt: Identical mapping for GPU DSM refine to support EHL/TGL

Windows graphic driver obtains DSM address from in-BAR mmio register
which has passthroughed. Not like the other platforms obtained from
pci configure space register which has virtualized. GPU GuC must use
WOPCM in DSM, besides, Windows OS wants to manage DSM also. These two
reason force acrn has to keep identical mapping to avoid trap mmio
BAR to do the emulation.

Tracked-On: #5880
Signed-off-by: Peng Sun <peng.p.sun@intel.com>
This commit is contained in:
ppsun 2021-03-29 08:53:29 +00:00 committed by wenlingz
parent b80c388b52
commit 2a96c567b8
7 changed files with 148 additions and 111 deletions

View File

@ -54,20 +54,14 @@ static char bootargs[BOOT_ARG_LEN];
* Begin Limit Type Length
* 0: 0 - 0xA0000 RAM 0xA0000
* 1: 0x100000 - lowmem part1 RAM 0x0
* 2: gpu_rsvd_bot - gpu_rsvd_top (reserved) 0x4004000
* 3: lowmem part2 - 0x7f800000 (reserved) 0x0
* 4: SW SRAM_bot - 0x80000000 (reserved) SOFTWARE_SRAM_MAX_SIZE
* 5: 0xDB000000 - 0xDF000000 (reserved) 64MB
* 6: 0xDF000000 - 0xE0000000 (reserved) 16MB
* 7: 0xE0000000 - 0x100000000 MCFG, MMIO 512MB
* 8: 0x140000000 - highmem RAM highmem - 5GB
* 2: SW SRAM_bot - SW SRAM_top (reserved) SOFTWARE_SRAM_MAX_SIZE
* 3: gpu_rsvd_bot - gpu_rsvd_top (reserved) 0x4004000
* 4: lowmem part2 - 0x80000000 (reserved) 0x0
* 5: 0xE0000000 - 0x100000000 MCFG, MMIO 512MB
* 6: 0x140000000 - highmem RAM highmem - 5GB
*
* FIXME: Do we need to reserve DSM and OPREGION for GVTD here.
*/
#define GPU_DSM_OPREGION_BASE_GPA 0x3B800000
#define GPU_DSM_OPREGION_SIZE 0x4004000
const struct e820_entry e820_default_entries[NUM_E820_ENTRIES] = {
{ /* 0 to video memory */
.baseaddr = 0x00000000,
@ -81,30 +75,30 @@ const struct e820_entry e820_default_entries[NUM_E820_ENTRIES] = {
.type = E820_TYPE_RAM
},
{ /* TGL GPU DSM & OpRegion area */
.baseaddr = GPU_DSM_OPREGION_BASE_GPA,
.length = GPU_DSM_OPREGION_SIZE,
.type = E820_TYPE_RESERVED
},
{ /* lowmem part2 to lowmem_limit */
.baseaddr = GPU_DSM_OPREGION_BASE_GPA + GPU_DSM_OPREGION_SIZE,
.length = 0x0,
.type = E820_TYPE_RESERVED
},
/*
* Software SRAM area: base: 0x7f800000, size: 0x800000
* Software SRAM area: size: 0x800000
* In native, the Software SRAM region should be part of DRAM memory.
* But one fixed Software SRAM gpa is friendly for virtualization due
* to decoupled with various guest memory size.
*/
{
.baseaddr = SOFTWARE_SRAM_BASE_GPA,
.length = SOFTWARE_SRAM_MAX_SIZE,
.baseaddr = 0x0,
.length = 0x0,
.type = E820_TYPE_RESERVED
},
{ /* GPU DSM & OpRegion reserved region */
.baseaddr = 0x0,
.length = 0x0,
.type = E820_TYPE_RESERVED
},
{ /* lowmem part2 to lowmem_limit */
.baseaddr = 0x0,
.length = 0x0,
.type = E820_TYPE_RESERVED
},
{ /* ECFG_BASE to 4GB */
.baseaddr = PCI_EMUL_ECFG_BASE,
.length = (4 * GB) - PCI_EMUL_ECFG_BASE,
@ -225,32 +219,65 @@ uint32_t
acrn_create_e820_table(struct vmctx *ctx, struct e820_entry *e820)
{
uint32_t removed = 0, k;
uint32_t gpu_rsvmem_base_gpa = 0;
uint64_t software_sram_base_gpa = 0;
memcpy(e820, e820_default_entries, sizeof(e820_default_entries));
if (ctx->lowmem <= e820[LOWRAM_E820_ENTRY + 2].baseaddr) {
e820[LOWRAM_E820_ENTRY].length =
(ctx->lowmem < e820[LOWRAM_E820_ENTRY+1].baseaddr ? ctx->lowmem :
e820[LOWRAM_E820_ENTRY+1].baseaddr) - e820[LOWRAM_E820_ENTRY].baseaddr;
memmove(&e820[LOWRAM_E820_ENTRY + 2], &e820[LOWRAM_E820_ENTRY + 3],
sizeof(struct e820_entry) *
(NUM_E820_ENTRIES - (LOWRAM_E820_ENTRY + 3)));
removed++;
/* FIXME: Here wastes 8MB memory if pSRAM is enabled, and 64MB+16KB if
* GPU reserved memory is exist.
*
* Determines the GPU region due to DSM identical mapping.
*/
gpu_rsvmem_base_gpa = get_gpu_rsvmem_base_gpa();
if (gpu_rsvmem_base_gpa) {
e820[LOWRAM_E820_ENTRY + 2].baseaddr = gpu_rsvmem_base_gpa;
e820[LOWRAM_E820_ENTRY + 2].length = get_gpu_rsvmem_size();
} else {
e820[LOWRAM_E820_ENTRY].length = e820[LOWRAM_E820_ENTRY+1].baseaddr -
e820[LOWRAM_E820_ENTRY].baseaddr;
e820[LOWRAM_E820_ENTRY + 2].length =
((ctx->lowmem < e820[LOWRAM_E820_ENTRY + 3].baseaddr) ? ctx->lowmem :
e820[LOWRAM_E820_ENTRY + 3].baseaddr) - e820[LOWRAM_E820_ENTRY + 2].baseaddr;
e820[LOWRAM_E820_ENTRY + 2].baseaddr = ctx->lowmem_limit;
}
/* remove [5GB, highmem) if it's empty */
if (ctx->highmem > 0) {
e820[HIGHRAM_E820_ENTRY - removed].type = E820_TYPE_RAM;
e820[HIGHRAM_E820_ENTRY - removed].length = ctx->highmem;
/* Always put SW SRAM before GPU region and keep 1MB boundary for protection. */
software_sram_base_gpa = get_software_sram_base_gpa();
if (software_sram_base_gpa) {
e820[LOWRAM_E820_ENTRY + 1].baseaddr = software_sram_base_gpa;
e820[LOWRAM_E820_ENTRY + 1].length = get_software_sram_size();
} else {
removed++;
e820[LOWRAM_E820_ENTRY + 1].baseaddr = e820[LOWRAM_E820_ENTRY + 2].baseaddr;
}
if (ctx->lowmem <= e820[LOWRAM_E820_ENTRY + 1].baseaddr) {
/* Caculation for lowmem part1 */
e820[LOWRAM_E820_ENTRY].length =
ctx->lowmem - e820[LOWRAM_E820_ENTRY].baseaddr;
} else {
/* Caculation for lowmem part1 */
e820[LOWRAM_E820_ENTRY].length =
e820[LOWRAM_E820_ENTRY + 1].baseaddr - e820[LOWRAM_E820_ENTRY].baseaddr;
/* Caculation for lowmem part2 */
e820[LOWRAM_E820_ENTRY + 3].baseaddr =
e820[LOWRAM_E820_ENTRY + 2].baseaddr + e820[LOWRAM_E820_ENTRY + 2].length;
if (ctx->lowmem > e820[LOWRAM_E820_ENTRY + 3].baseaddr) {
e820[LOWRAM_E820_ENTRY + 3].length =
ctx->lowmem - e820[LOWRAM_E820_ENTRY + 3].baseaddr;
e820[LOWRAM_E820_ENTRY + 3].type = E820_TYPE_RAM;
}
}
/* Caculation for highmem */
if (ctx->highmem > 0) {
e820[HIGHRAM_E820_ENTRY].type = E820_TYPE_RAM;
e820[HIGHRAM_E820_ENTRY].length = ctx->highmem;
}
/* Remove empty entries in e820 table */
for (k = 0; k < (NUM_E820_ENTRIES - 1 - removed); k++) {
if (e820[k].length == 0x0) {
memmove(&e820[k], &e820[k + 1], sizeof(struct e820_entry) *
(NUM_E820_ENTRIES - (k + 1)));
k--;
removed++;
}
}
pr_info("SW_LOAD: build e820 %d entries to addr: %p\r\n",

View File

@ -59,48 +59,13 @@
#define PCI_BDF_GPU 0x00000010 /* 00:02.0 */
/* Reserved region in e820 table for GVT
* for GVT-g use:
* [0xDF000000, 0xDF800000) 8M, GOP FB, used OvmfPkg/GvtGopDxe for 1080p@30
* [0xDFFFD000, 0xDFFFF000) 8K, OpRegion, used by GvtGopDxe and GVT-g
* [0xDFFFF000, 0XE0000000) 4K, Reserved, not used
* for TGL GVT-d use:
* [0x3B800000, 0x3F800000) 64M, Date Stolen Memory
* [0x3F800000, 0X3F804000] 16K, OpRegion and Extended OpRegion
* for EHL/WHL/KBL GVT-d use:
* [0xDB000000, 0xDF000000) 64M, DSM, used by native GOP and gfx driver
* [0xDFFFC000, 0xDFFFE000) 8K, OpRegion, used by native GOP and gfx driver
* [0xDFFFE000, 0XE0000000] 8K, Extended OpRegion, store raw VBT
* OpRegion: 8KB(0x2000)
* [ OpRegion Header ] Offset: 0x0
* [ Mailbox #1: ACPI ] Offset: 0x100
* [ Mailbox #2: SWSCI ] Offset: 0x200
* [ Mailbox #3: ASLE ] Offset: 0x300
* [ Mailbox #4: VBT ] Offset: 0x400
* [ Mailbox #5: ASLE EXT ] Offset: 0x1C00
* Extended OpRegion: 8KB(0x2000)
* [ Raw VBT ] Offset: 0x0
* If VBT <= 6KB, stores in Mailbox #4
* If VBT > 6KB, stores in Extended OpRegion
* ASLE.rvda stores the location of VBT.
* For OpRegion 2.1+: ASLE.rvda = offset to OpRegion base address
* For OpRegion 2.0: ASLE.rvda = physical address, not support currently
*/
#define GPU_DSM_GPA 0xDB000000
#define GPU_DSM_SIZE 0x4000000
#define GPU_OPREGION_GPA 0xDFFFC000
#define GPU_OPREGION_SIZE 0x4000
/*
* TODO: Forced DSM/OPREGION size requires native BIOS configuration.
* This limitation need remove in future
*/
extern uint64_t audio_nhlt_len;
uint32_t gpu_dsm_hpa = 0;
uint32_t gpu_dsm_gpa = 0;
uint32_t gpu_opregion_hpa = 0;
uint32_t gpu_opregion_gpa = 0;
extern uint64_t audio_nhlt_len;
/* reference count for libpciaccess init/deinit */
static int pciaccess_ref_cnt;
static pthread_mutex_t ref_cnt_mtx = PTHREAD_MUTEX_INITIALIZER;
@ -472,6 +437,18 @@ has_virt_pcicfg_regs_on_def_gpu(int offset)
return ((offset == PCIR_BDSM) || (offset == PCIR_ASLS_CTL));
}
uint32_t
get_gpu_rsvmem_base_gpa()
{
return gpu_opregion_gpa;
}
uint32_t
get_gpu_rsvmem_size()
{
return GPU_OPREGION_SIZE + GPU_DSM_SIZE;
}
/*
* passthrough GPU DSM(Data Stolen Memory) and Opregion to guest
*/
@ -487,24 +464,6 @@ passthru_gpu_dsm_opregion(struct vmctx *ctx, struct passthru_dev *ptdev,
switch (device) {
case INTEL_ELKHARTLAKE:
/* BDSM register has 64 bits.
* bits 63:20 contains the base address of stolen memory
*/
gpu_dsm_hpa = read_config(ptdev->phys_dev, PCIR_GEN11_BDSM_DW0, 4);
dsm_mask_val = gpu_dsm_hpa & ~PCIM_BDSM_MASK;
gpu_dsm_hpa &= PCIM_BDSM_MASK;
gpu_dsm_hpa |= (uint64_t)read_config(ptdev->phys_dev, PCIR_GEN11_BDSM_DW1, 4) << 32;
gpu_dsm_gpa = GPU_DSM_GPA;
pci_set_cfgdata32(ptdev->dev, PCIR_GEN11_BDSM_DW0, gpu_dsm_gpa | dsm_mask_val);
/* write 0 to high 32-bits of BDSM on EHL platform */
pci_set_cfgdata32(ptdev->dev, PCIR_GEN11_BDSM_DW1, 0);
gpu_opregion_gpa = GPU_OPREGION_GPA;
ptdev->has_virt_pcicfg_regs = &has_virt_pcicfg_regs_on_ehl_gpu;
break;
case INTEL_TIGERLAKE:
/* BDSM register has 64 bits.
* bits 63:20 contains the base address of stolen memory
@ -523,8 +482,6 @@ passthru_gpu_dsm_opregion(struct vmctx *ctx, struct passthru_dev *ptdev,
/* write 0 to high 32-bits of BDSM on EHL platform */
pci_set_cfgdata32(ptdev->dev, PCIR_GEN11_BDSM_DW1, 0);
gpu_opregion_gpa = gpu_dsm_gpa + GPU_DSM_SIZE;
ptdev->has_virt_pcicfg_regs = &has_virt_pcicfg_regs_on_ehl_gpu;
break;
/* If on default platforms, such as KBL,WHL */
@ -537,12 +494,11 @@ passthru_gpu_dsm_opregion(struct vmctx *ctx, struct passthru_dev *ptdev,
pci_set_cfgdata32(ptdev->dev, PCIR_BDSM, gpu_dsm_gpa | dsm_mask_val);
gpu_opregion_gpa = GPU_OPREGION_GPA;
ptdev->has_virt_pcicfg_regs = &has_virt_pcicfg_regs_on_def_gpu;
break;
}
gpu_opregion_gpa = gpu_dsm_gpa - GPU_OPREGION_SIZE;
pci_set_cfgdata32(ptdev->dev, PCIR_ASLS_CTL, gpu_opregion_gpa | (opregion_phys & ~PCIM_ASLS_OPREGION_MASK));
/* initialize the EPT mapping for passthrough GPU dsm region */

View File

@ -1095,13 +1095,13 @@ int create_and_inject_vrtct(struct vmctx *ctx)
uint8_t *vrtct;
struct vm_memmap memmap = {
.type = VM_MMIO,
.gpa = SOFTWARE_SRAM_BASE_GPA,
/* HPA base and size of Software SRAM shall be parsed from vRTCT. */
.hpa = 0,
.len = 0,
.prot = PROT_ALL
};
memmap.gpa = get_software_sram_base_gpa();
native_rtct_fd = open(RTCT_NATIVE_FILE_PATH_IN_SOS, O_RDONLY);
if (native_rtct_fd < 0) {
pr_err("failed to open /sys/firmware/acpi/tables/PTCT !!!!! errno:%d\n", errno);

View File

@ -35,6 +35,7 @@
static uint64_t software_sram_base_hpa;
static uint64_t software_sram_size;
static uint64_t software_sram_base_gpa;
static uint8_t vrtct_checksum(uint8_t *vrtct, uint32_t length)
{
@ -209,7 +210,7 @@ static void remap_software_sram_regions(struct acpi_table_hdr *vrtct)
foreach_rtct_entry(vrtct, entry) {
if (entry->type == RTCT_ENTRY_TYPE_PSRAM) {
sw_sram_region = (struct rtct_entry_data_psram *)entry->data;
sw_sram_region->base = SOFTWARE_SRAM_BASE_GPA + (sw_sram_region->base - hpa_bottom);
sw_sram_region->base = software_sram_base_gpa + (sw_sram_region->base - hpa_bottom);
}
}
}
@ -287,6 +288,11 @@ uint64_t get_software_sram_base_hpa(void)
return software_sram_base_hpa;
}
uint64_t get_software_sram_base_gpa(void)
{
return software_sram_base_gpa;
}
uint64_t get_software_sram_size(void)
{
return software_sram_size;
@ -306,6 +312,7 @@ uint8_t *build_vrtct(struct vmctx *ctx, void *cfg)
struct acrn_vm_config vm_cfg;
struct acpi_table_hdr *rtct_cfg, *vrtct = NULL;
uint64_t dm_cpu_bitmask, hv_cpu_bitmask, guest_pcpu_bitmask;
uint32_t gpu_rsvmem_base_gpa = 0;
if ((cfg == NULL) || (ctx == NULL))
return NULL;
@ -351,6 +358,14 @@ uint8_t *build_vrtct(struct vmctx *ctx, void *cfg)
pr_info("%s, dm_cpu_bitmask:0x%x, hv_cpu_bitmask:0x%x, guest_cpu_bitmask: 0x%x\n",
__func__, dm_cpu_bitmask, hv_cpu_bitmask, guest_pcpu_bitmask);
gpu_rsvmem_base_gpa = get_gpu_rsvmem_base_gpa();
software_sram_size = SOFTWARE_SRAM_MAX_SIZE;
/* TODO: It is better to put one boundary between GPU region and SW SRAM
* for protection.
*/
software_sram_base_gpa = ((gpu_rsvmem_base_gpa ? gpu_rsvmem_base_gpa : 0x80000000UL) -
software_sram_size) & ~software_sram_size;
if (passthru_rtct_to_guest(vrtct, rtct_cfg, guest_pcpu_bitmask)) {
pr_err("%s, initialize vRTCT fail.", __func__);
goto error;

View File

@ -263,6 +263,45 @@ int create_mmio_rsvd_rgn(uint64_t start,
uint64_t end, int idx, int bar_type, struct pci_vdev *vdev);
void destory_mmio_rsvd_rgns(struct pci_vdev *vdev);
/* Reserved region in e820 table for GVT
* for GVT-g use:
* [0xDF000000, 0xDF800000) 8M, GOP FB, used OvmfPkg/GvtGopDxe for 1080p@30
* [0xDFFFD000, 0xDFFFF000) 8K, OpRegion, used by GvtGopDxe and GVT-g
* [0xDFFFF000, 0XE0000000) 4K, Reserved, not used
* for TGL/EHL GVT-d use: identical mapping, same with host layout
* [gpu_opregion_hpa, gpu_opregion_hpa+size) 16K, OpRegion and Extended OpRegion
* [gpu_dsm_hpa, gpu_dsm_hpa+size] 64M, Date Stolen Memory
* for WHL/KBL GVT-d use:
* [0x7BFFC000, 0x7BFFE000) 8K, OpRegion, used by native GOP and gfx driver
* [0x7BFFE000, 0X7C000000] 8K, Extended OpRegion, store raw VBT
* [0x7C000000, 0x80000000] 64M, DSM, used by native GOP and gfx driver
* OpRegion: 8KB(0x2000)
* [ OpRegion Header ] Offset: 0x0
* [ Mailbox #1: ACPI ] Offset: 0x100
* [ Mailbox #2: SWSCI ] Offset: 0x200
* [ Mailbox #3: ASLE ] Offset: 0x300
* [ Mailbox #4: VBT ] Offset: 0x400
* [ Mailbox #5: ASLE EXT ] Offset: 0x1C00
* Extended OpRegion: 8KB(0x2000)
* [ Raw VBT ] Offset: 0x0
* If VBT <= 6KB, stores in Mailbox #4
* If VBT > 6KB, stores in Extended OpRegion
* ASLE.rvda stores the location of VBT.
* For OpRegion 2.1+: ASLE.rvda = offset to OpRegion base address
* For OpRegion 2.0: ASLE.rvda = physical address, not support currently
*/
#define GPU_DSM_GPA 0x7C000000
#define GPU_DSM_SIZE 0x4000000
#define GPU_OPREGION_SIZE 0x4000
/*
* TODO: Forced DSM/OPREGION size requires native BIOS configuration.
* This limitation need remove in future
*/
uint32_t get_gpu_rsvmem_base_gpa(void);
uint32_t get_gpu_rsvmem_size(void);
uint64_t get_software_sram_base_gpa(void);
uint64_t get_software_sram_size(void);
typedef void (*pci_lintr_cb)(int b, int s, int pin, int pirq_pin,
int ioapic_irq, void *arg);

View File

@ -1066,8 +1066,8 @@
#define PCIM_OSC_CTL_PCIE_CAP_STRUCT 0x10 /* Various Capability Structures */
/* Graphics definitions */
#define INTEL_ELKHARTLAKE 0x4551
#define INTEL_TIGERLAKE 0x9a49
#define INTEL_ELKHARTLAKE 0x4571
#define INTEL_TIGERLAKE 0x9a49
#define PCIR_BDSM 0x5C /* BDSM graphics base data of stolen memory register */
#define PCIR_GEN11_BDSM_DW0 0xC0
#define PCIR_GEN11_BDSM_DW1 0xC4

View File

@ -39,9 +39,9 @@
#define E820_TYPE_ACPI_NVS 4U /* EFI 10 */
#define E820_TYPE_UNUSABLE 5U /* EFI 8 */
#define NUM_E820_ENTRIES 9
#define LOWRAM_E820_ENTRY 1
#define HIGHRAM_E820_ENTRY 6
#define NUM_E820_ENTRIES 7
#define LOWRAM_E820_ENTRY 1
#define HIGHRAM_E820_ENTRY 6
/* Defines a single entry in an E820 memory map. */
struct e820_entry {