From fe6567d5fddfb7501a352c5e080a9eecf7b89177 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 31 Mar 2015 14:10:22 +0200 Subject: hw/i386: add a separate region that tracks the SMRAME bit This region is exported at /machine/smram. It is "empty" if SMRAME=0 and points to SMRAM if SMRAME=1. The CPU will enable/disable it as it enters or exits SMRAM. While touching nearby code, the existing memory region setup was slightly inconsistent. The smram_region is *disabled* in order to open SMRAM (because the smram_region shows the low VRAM instead of the RAM at 0xa0000). Because SMRAM is closed at startup, the smram_region must be enabled when creating the i440fx or q35 devices. Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini --- include/hw/pci-host/q35.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/hw/pci-host/q35.h') diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h index 96d4cdc713..4c9eacc587 100644 --- a/include/hw/pci-host/q35.h +++ b/include/hw/pci-host/q35.h @@ -53,6 +53,7 @@ typedef struct MCHPCIState { MemoryRegion *address_space_io; PAMMemoryRegion pam_regions[13]; MemoryRegion smram_region; + MemoryRegion smram, low_smram; PcPciInfo pci_info; uint8_t smm_enabled; ram_addr_t below_4g_mem_size; -- cgit 1.4.1 From f809c605122df291bbb9004dc487bde0969134b5 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 31 Mar 2015 14:12:25 +0200 Subject: target-i386: use memory API to implement SMRAM Remove cpu_smm_register and cpu_smm_update. Instead, each CPU address space gets an extra region which is an alias of /machine/smram. This extra region is enabled or disabled as the CPU enters/exits SMM. Signed-off-by: Paolo Bonzini --- bsd-user/main.c | 4 ---- hw/i386/pc.c | 21 --------------------- hw/pci-host/pam.c | 18 ++---------------- hw/pci-host/piix.c | 28 ++++++++-------------------- hw/pci-host/q35.c | 22 ++++++---------------- include/hw/i386/pc.h | 1 - include/hw/pci-host/pam.h | 5 +---- include/hw/pci-host/q35.h | 1 - linux-user/main.c | 4 ---- target-i386/cpu-qom.h | 4 +++- target-i386/cpu.c | 33 +++++++++++++++++++++++++++++++-- target-i386/cpu.h | 3 ++- target-i386/machine.c | 3 +++ target-i386/smm_helper.c | 14 ++++++++++++-- 14 files changed, 68 insertions(+), 93 deletions(-) (limited to 'include/hw/pci-host/q35.h') diff --git a/bsd-user/main.c b/bsd-user/main.c index 5bfaf5c421..ba0b9981f5 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -108,10 +108,6 @@ void cpu_list_unlock(void) /***********************************************************/ /* CPUX86 core interface */ -void cpu_smm_update(CPUX86State *env) -{ -} - uint64_t cpu_get_tsc(CPUX86State *env) { return cpu_get_real_ticks(); diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 2baff4a660..3f0d435da9 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -164,27 +164,6 @@ uint64_t cpu_get_tsc(CPUX86State *env) return cpu_get_ticks(); } -/* SMM support */ - -static cpu_set_smm_t smm_set; -static void *smm_arg; - -void cpu_smm_register(cpu_set_smm_t callback, void *arg) -{ - assert(smm_set == NULL); - assert(smm_arg == NULL); - smm_set = callback; - smm_arg = arg; -} - -void cpu_smm_update(CPUX86State *env) -{ - if (smm_set && smm_arg && CPU(x86_env_get_cpu(env)) == first_cpu) { - smm_set(!!(env->hflags & HF_SMM_MASK), smm_arg); - } -} - - /* IRQ handling */ int cpu_get_pic_interrupt(CPUX86State *env) { diff --git a/hw/pci-host/pam.c b/hw/pci-host/pam.c index 8272de3f28..99d7af97e7 100644 --- a/hw/pci-host/pam.c +++ b/hw/pci-host/pam.c @@ -31,26 +31,12 @@ #include "sysemu/sysemu.h" #include "hw/pci-host/pam.h" -void smram_update(MemoryRegion *smram_region, uint8_t smram, - uint8_t smm_enabled) +void smram_update(MemoryRegion *smram_region, uint8_t smram) { - bool smram_enabled; - - smram_enabled = ((smm_enabled && (smram & SMRAM_G_SMRAME)) || - (smram & SMRAM_D_OPEN)); + bool smram_enabled = (smram & SMRAM_D_OPEN); memory_region_set_enabled(smram_region, !smram_enabled); } -void smram_set_smm(uint8_t *host_smm_enabled, int smm, uint8_t smram, - MemoryRegion *smram_region) -{ - uint8_t smm_enabled = (smm != 0); - if (*host_smm_enabled != smm_enabled) { - *host_smm_enabled = smm_enabled; - smram_update(smram_region, smram, *host_smm_enabled); - } -} - void init_pam(DeviceState *dev, MemoryRegion *ram_memory, MemoryRegion *system_memory, MemoryRegion *pci_address_space, PAMMemoryRegion *mem, uint32_t start, uint32_t size) diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c index 0e439c5d52..a91ad73705 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/piix.c @@ -106,7 +106,6 @@ struct PCII440FXState { PAMMemoryRegion pam_regions[13]; MemoryRegion smram_region; MemoryRegion smram, low_smram; - uint8_t smm_enabled; }; @@ -139,23 +138,12 @@ static void i440fx_update_memory_mappings(PCII440FXState *d) pam_update(&d->pam_regions[i], i, pd->config[I440FX_PAM + ((i + 1) / 2)]); } - smram_update(&d->smram_region, pd->config[I440FX_SMRAM], d->smm_enabled); + smram_update(&d->smram_region, pd->config[I440FX_SMRAM]); memory_region_set_enabled(&d->smram, pd->config[I440FX_SMRAM] & SMRAM_G_SMRAME); memory_region_transaction_commit(); } -static void i440fx_set_smm(int val, void *arg) -{ - PCII440FXState *d = arg; - PCIDevice *pd = PCI_DEVICE(d); - - memory_region_transaction_begin(); - smram_set_smm(&d->smm_enabled, val, pd->config[I440FX_SMRAM], - &d->smram_region); - memory_region_transaction_commit(); -} - static void i440fx_write_config(PCIDevice *dev, uint32_t address, uint32_t val, int len) @@ -175,12 +163,13 @@ static int i440fx_load_old(QEMUFile* f, void *opaque, int version_id) PCII440FXState *d = opaque; PCIDevice *pd = PCI_DEVICE(d); int ret, i; + uint8_t smm_enabled; ret = pci_device_load(pd, f); if (ret < 0) return ret; i440fx_update_memory_mappings(d); - qemu_get_8s(f, &d->smm_enabled); + qemu_get_8s(f, &smm_enabled); if (version_id == 2) { for (i = 0; i < PIIX_NUM_PIRQS; i++) { @@ -208,7 +197,10 @@ static const VMStateDescription vmstate_i440fx = { .post_load = i440fx_post_load, .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(parent_obj, PCII440FXState), - VMSTATE_UINT8(smm_enabled, PCII440FXState), + /* Used to be smm_enabled, which was basically always zero because + * SeaBIOS hardly uses SMM. SMRAM is now handled by CPU code. + */ + VMSTATE_UNUSED(1), VMSTATE_END_OF_LIST() } }; @@ -300,11 +292,7 @@ static void i440fx_pcihost_realize(DeviceState *dev, Error **errp) static void i440fx_realize(PCIDevice *dev, Error **errp) { - PCII440FXState *d = I440FX_PCI_DEVICE(dev); - dev->config[I440FX_SMRAM] = 0x02; - - cpu_smm_register(&i440fx_set_smm, d); } PCIBus *i440fx_init(PCII440FXState **pi440fx_state, @@ -360,7 +348,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, memory_region_init(&f->smram, OBJECT(d), "smram", 1ull << 32); memory_region_set_enabled(&f->smram, true); memory_region_init_alias(&f->low_smram, OBJECT(d), "smram-low", - f->system_memory, 0xa0000, 0x20000); + f->ram_memory, 0xa0000, 0x20000); memory_region_set_enabled(&f->low_smram, true); memory_region_add_subregion(&f->smram, 0xa0000, &f->low_smram); object_property_add_const_link(qdev_get_machine(), "smram", diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index db4d871908..eefa199335 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -268,24 +268,12 @@ static void mch_update_smram(MCHPCIState *mch) PCIDevice *pd = PCI_DEVICE(mch); memory_region_transaction_begin(); - smram_update(&mch->smram_region, pd->config[MCH_HOST_BRIDGE_SMRAM], - mch->smm_enabled); + smram_update(&mch->smram_region, pd->config[MCH_HOST_BRIDGE_SMRAM]); memory_region_set_enabled(&mch->smram, pd->config[MCH_HOST_BRIDGE_SMRAM] & SMRAM_G_SMRAME); memory_region_transaction_commit(); } -static void mch_set_smm(int smm, void *arg) -{ - MCHPCIState *mch = arg; - PCIDevice *pd = PCI_DEVICE(mch); - - memory_region_transaction_begin(); - smram_set_smm(&mch->smm_enabled, smm, pd->config[MCH_HOST_BRIDGE_SMRAM], - &mch->smram_region); - memory_region_transaction_commit(); -} - static void mch_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { @@ -331,7 +319,10 @@ static const VMStateDescription vmstate_mch = { .post_load = mch_post_load, .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(parent_obj, MCHPCIState), - VMSTATE_UINT8(smm_enabled, MCHPCIState), + /* Used to be smm_enabled, which was basically always zero because + * SeaBIOS hardly uses SMM. SMRAM is now handled by CPU code. + */ + VMSTATE_UNUSED(1), VMSTATE_END_OF_LIST() } }; @@ -402,7 +393,6 @@ static void mch_realize(PCIDevice *d, Error **errp) mch->pci_address_space); /* if *disabled* show SMRAM to all CPUs */ - cpu_smm_register(&mch_set_smm, mch); memory_region_init_alias(&mch->smram_region, OBJECT(mch), "smram-region", mch->pci_address_space, 0xa0000, 0x20000); memory_region_add_subregion_overlap(mch->system_memory, 0xa0000, @@ -413,7 +403,7 @@ static void mch_realize(PCIDevice *d, Error **errp) memory_region_init(&mch->smram, OBJECT(mch), "smram", 1ull << 32); memory_region_set_enabled(&mch->smram, true); memory_region_init_alias(&mch->low_smram, OBJECT(mch), "smram-low", - mch->system_memory, 0xa0000, 0x20000); + mch->ram_memory, 0xa0000, 0x20000); memory_region_set_enabled(&mch->low_smram, true); memory_region_add_subregion(&mch->smram, 0xa0000, &mch->low_smram); object_property_add_const_link(qdev_get_machine(), "smram", diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index bec6de1ddf..86c565147c 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -210,7 +210,6 @@ void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus); void pc_pci_device_init(PCIBus *pci_bus); typedef void (*cpu_set_smm_t)(int smm, void *arg); -void cpu_smm_register(cpu_set_smm_t callback, void *arg); void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name); diff --git a/include/hw/pci-host/pam.h b/include/hw/pci-host/pam.h index 4d03e4bf18..80dd605b58 100644 --- a/include/hw/pci-host/pam.h +++ b/include/hw/pci-host/pam.h @@ -86,10 +86,7 @@ typedef struct PAMMemoryRegion { unsigned current; } PAMMemoryRegion; -void smram_update(MemoryRegion *smram_region, uint8_t smram, - uint8_t smm_enabled); -void smram_set_smm(uint8_t *host_smm_enabled, int smm, uint8_t smram, - MemoryRegion *smram_region); +void smram_update(MemoryRegion *smram_region, uint8_t smram); void init_pam(DeviceState *dev, MemoryRegion *ram, MemoryRegion *system, MemoryRegion *pci, PAMMemoryRegion *mem, uint32_t start, uint32_t size); void pam_update(PAMMemoryRegion *mem, int idx, uint8_t val); diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h index 4c9eacc587..17adeaaafd 100644 --- a/include/hw/pci-host/q35.h +++ b/include/hw/pci-host/q35.h @@ -55,7 +55,6 @@ typedef struct MCHPCIState { MemoryRegion smram_region; MemoryRegion smram, low_smram; PcPciInfo pci_info; - uint8_t smm_enabled; ram_addr_t below_4g_mem_size; ram_addr_t above_4g_mem_size; uint64_t pci_hole64_size; diff --git a/linux-user/main.c b/linux-user/main.c index 3f32db0afd..6989b82455 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -215,10 +215,6 @@ void cpu_list_unlock(void) /***********************************************************/ /* CPUX86 core interface */ -void cpu_smm_update(CPUX86State *env) -{ -} - uint64_t cpu_get_tsc(CPUX86State *env) { return cpu_get_real_ticks(); diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h index 39cd878fad..7a4fddd85f 100644 --- a/target-i386/cpu-qom.h +++ b/target-i386/cpu-qom.h @@ -23,6 +23,7 @@ #include "qom/cpu.h" #include "cpu.h" #include "qapi/error.h" +#include "qemu/notify.h" #ifdef TARGET_X86_64 #define TYPE_X86_CPU "x86_64-cpu" @@ -111,7 +112,8 @@ typedef struct X86CPU { /* in order to simplify APIC support, we leave this pointer to the user */ struct DeviceState *apic_state; - struct MemoryRegion *cpu_as_root; + struct MemoryRegion *cpu_as_root, *cpu_as_mem, *smram; + Notifier machine_done; } X86CPU; static inline X86CPU *x86_env_get_cpu(CPUX86State *env) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 051abc92cb..4e7cdaaaa5 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2751,6 +2751,21 @@ static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp) object_property_set_bool(OBJECT(cpu->apic_state), true, "realized", errp); } + +static void x86_cpu_machine_done(Notifier *n, void *unused) +{ + X86CPU *cpu = container_of(n, X86CPU, machine_done); + MemoryRegion *smram = + (MemoryRegion *) object_resolve_path("/machine/smram", NULL); + + if (smram) { + cpu->smram = g_new(MemoryRegion, 1); + memory_region_init_alias(cpu->smram, OBJECT(cpu), "smram", + smram, 0, 1ull << 32); + memory_region_set_enabled(cpu->smram, false); + memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->smram, 1); + } +} #else static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp) { @@ -2815,12 +2830,26 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) #ifndef CONFIG_USER_ONLY if (tcg_enabled()) { + cpu->cpu_as_mem = g_new(MemoryRegion, 1); cpu->cpu_as_root = g_new(MemoryRegion, 1); cs->as = g_new(AddressSpace, 1); - memory_region_init_alias(cpu->cpu_as_root, OBJECT(cpu), "memory", - get_system_memory(), 0, ~0ull); + + /* Outer container... */ + memory_region_init(cpu->cpu_as_root, OBJECT(cpu), "memory", ~0ull); memory_region_set_enabled(cpu->cpu_as_root, true); + + /* ... with two regions inside: normal system memory with low + * priority, and... + */ + memory_region_init_alias(cpu->cpu_as_mem, OBJECT(cpu), "memory", + get_system_memory(), 0, ~0ull); + memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->cpu_as_mem, 0); + memory_region_set_enabled(cpu->cpu_as_mem, true); address_space_init(cs->as, cpu->cpu_as_root, "CPU"); + + /* ... SMRAM with higher priority, linked from /machine/smram. */ + cpu->machine_done.notify = x86_cpu_machine_done; + qemu_add_machine_init_done_notifier(&cpu->machine_done); } #endif diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 9dae9ab854..603aaf0924 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1157,7 +1157,6 @@ void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3); void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4); /* hw/pc.c */ -void cpu_smm_update(CPUX86State *env); uint64_t cpu_get_tsc(CPUX86State *env); #define TARGET_PAGE_BITS 12 @@ -1323,7 +1322,9 @@ void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1); /* seg_helper.c */ void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw); +/* smm_helper.c */ void do_smm_enter(X86CPU *cpu); +void cpu_smm_update(X86CPU *cpu); void cpu_report_tpr_access(CPUX86State *env, TPRAccess access); diff --git a/target-i386/machine.c b/target-i386/machine.c index cd1ddd29e9..69d86cb476 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -372,6 +372,9 @@ static int cpu_post_load(void *opaque, int version_id) } tlb_flush(cs, 1); + if (tcg_enabled()) { + cpu_smm_update(cpu); + } return 0; } diff --git a/target-i386/smm_helper.c b/target-i386/smm_helper.c index 5617a14854..02e24b9236 100644 --- a/target-i386/smm_helper.c +++ b/target-i386/smm_helper.c @@ -40,6 +40,16 @@ void helper_rsm(CPUX86State *env) #define SMM_REVISION_ID 0x00020000 #endif +void cpu_smm_update(X86CPU *cpu) +{ + CPUX86State *env = &cpu->env; + bool smm_enabled = (env->hflags & HF_SMM_MASK); + + if (cpu->smram) { + memory_region_set_enabled(cpu->smram, smm_enabled); + } +} + void do_smm_enter(X86CPU *cpu) { CPUX86State *env = &cpu->env; @@ -57,7 +67,7 @@ void do_smm_enter(X86CPU *cpu) } else { env->hflags2 |= HF2_NMI_MASK; } - cpu_smm_update(env); + cpu_smm_update(cpu); sm_state = env->smbase + 0x8000; @@ -317,7 +327,7 @@ void helper_rsm(CPUX86State *env) } env->hflags2 &= ~HF2_SMM_INSIDE_NMI_MASK; env->hflags &= ~HF_SMM_MASK; - cpu_smm_update(env); + cpu_smm_update(cpu); qemu_log_mask(CPU_LOG_INT, "SMM: after RSM\n"); log_cpu_state_mask(CPU_LOG_INT, CPU(cpu), CPU_DUMP_CCOP); -- cgit 1.4.1 From 64130fa4a1514ae7a580b8d46290a11784770600 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 31 Mar 2015 17:13:01 +0200 Subject: q35: implement high SMRAM When H_SMRAME is 1, low memory at 0xa0000 is left alone by SMM, and instead the chipset maps the 0xa0000-0xbffff window at 0xfeda0000-0xfedbffff. This affects both the "non-SMM" view controlled by D_OPEN and the SMM view controlled by G_SMRAME, so add two new MemoryRegions and toggle the enabled/disabled state of all four in mch_update_smram. Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini --- hw/pci-host/q35.c | 35 +++++++++++++++++++++++++++++++---- include/hw/pci-host/q35.h | 16 ++++++++-------- 2 files changed, 39 insertions(+), 12 deletions(-) (limited to 'include/hw/pci-host/q35.h') diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 24829e0d52..8f8d9e86e1 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -266,12 +266,29 @@ static void mch_update_pam(MCHPCIState *mch) static void mch_update_smram(MCHPCIState *mch) { PCIDevice *pd = PCI_DEVICE(mch); + bool h_smrame = (pd->config[MCH_HOST_BRIDGE_ESMRAMC] & MCH_HOST_BRIDGE_ESMRAMC_H_SMRAME); memory_region_transaction_begin(); - memory_region_set_enabled(&mch->smram_region, - !(pd->config[MCH_HOST_BRIDGE_SMRAM] & SMRAM_D_OPEN)); - memory_region_set_enabled(&mch->smram, - pd->config[MCH_HOST_BRIDGE_SMRAM] & SMRAM_G_SMRAME); + + if (pd->config[MCH_HOST_BRIDGE_SMRAM] & SMRAM_D_OPEN) { + /* Hide (!) low SMRAM if H_SMRAME = 1 */ + memory_region_set_enabled(&mch->smram_region, h_smrame); + /* Show high SMRAM if H_SMRAME = 1 */ + memory_region_set_enabled(&mch->open_high_smram, h_smrame); + } else { + /* Hide high SMRAM and low SMRAM */ + memory_region_set_enabled(&mch->smram_region, true); + memory_region_set_enabled(&mch->open_high_smram, false); + } + + if (pd->config[MCH_HOST_BRIDGE_SMRAM] & SMRAM_G_SMRAME) { + memory_region_set_enabled(&mch->low_smram, !h_smrame); + memory_region_set_enabled(&mch->high_smram, h_smrame); + } else { + memory_region_set_enabled(&mch->low_smram, false); + memory_region_set_enabled(&mch->high_smram, false); + } + memory_region_transaction_commit(); } @@ -400,6 +417,12 @@ static void mch_realize(PCIDevice *d, Error **errp) &mch->smram_region, 1); memory_region_set_enabled(&mch->smram_region, true); + memory_region_init_alias(&mch->open_high_smram, OBJECT(mch), "smram-open-high", + mch->ram_memory, 0xa0000, 0x20000); + memory_region_add_subregion_overlap(mch->system_memory, 0xfeda0000, + &mch->open_high_smram, 1); + memory_region_set_enabled(&mch->open_high_smram, false); + /* smram, as seen by SMM CPUs */ memory_region_init(&mch->smram, OBJECT(mch), "smram", 1ull << 32); memory_region_set_enabled(&mch->smram, true); @@ -407,6 +430,10 @@ static void mch_realize(PCIDevice *d, Error **errp) mch->ram_memory, 0xa0000, 0x20000); memory_region_set_enabled(&mch->low_smram, true); memory_region_add_subregion(&mch->smram, 0xa0000, &mch->low_smram); + memory_region_init_alias(&mch->high_smram, OBJECT(mch), "smram-high", + mch->ram_memory, 0xa0000, 0x20000); + memory_region_set_enabled(&mch->high_smram, true); + memory_region_add_subregion(&mch->smram, 0xfeda0000, &mch->high_smram); object_property_add_const_link(qdev_get_machine(), "smram", OBJECT(&mch->smram), &error_abort); diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h index 17adeaaafd..0fff6a2421 100644 --- a/include/hw/pci-host/q35.h +++ b/include/hw/pci-host/q35.h @@ -52,8 +52,8 @@ typedef struct MCHPCIState { MemoryRegion *system_memory; MemoryRegion *address_space_io; PAMMemoryRegion pam_regions[13]; - MemoryRegion smram_region; - MemoryRegion smram, low_smram; + MemoryRegion smram_region, open_high_smram; + MemoryRegion smram, low_smram, high_smram; PcPciInfo pci_info; ram_addr_t below_4g_mem_size; ram_addr_t above_4g_mem_size; @@ -127,7 +127,7 @@ typedef struct Q35PCIHost { #define MCH_HOST_BRIDGE_PAM_MASK ((uint8_t)0x3) #define MCH_HOST_BRIDGE_SMRAM 0x9d -#define MCH_HOST_BRIDGE_SMRAM_SIZE 1 +#define MCH_HOST_BRIDGE_SMRAM_SIZE 2 #define MCH_HOST_BRIDGE_SMRAM_DEFAULT ((uint8_t)0x2) #define MCH_HOST_BRIDGE_SMRAM_D_OPEN ((uint8_t)(1 << 6)) #define MCH_HOST_BRIDGE_SMRAM_D_CLS ((uint8_t)(1 << 5)) @@ -141,11 +141,11 @@ typedef struct Q35PCIHost { #define MCH_HOST_BRIDGE_UPPER_SYSTEM_BIOS_END 0x100000 #define MCH_HOST_BRIDGE_ESMRAMC 0x9e -#define MCH_HOST_BRIDGE_ESMRAMC_H_SMRAME ((uint8_t)(1 << 6)) -#define MCH_HOST_BRIDGE_ESMRAMC_E_SMERR ((uint8_t)(1 << 5)) -#define MCH_HOST_BRIDGE_ESMRAMC_SM_CACHE ((uint8_t)(1 << 4)) -#define MCH_HOST_BRIDGE_ESMRAMC_SM_L1 ((uint8_t)(1 << 3)) -#define MCH_HOST_BRIDGE_ESMRAMC_SM_L2 ((uint8_t)(1 << 2)) +#define MCH_HOST_BRIDGE_ESMRAMC_H_SMRAME ((uint8_t)(1 << 7)) +#define MCH_HOST_BRIDGE_ESMRAMC_E_SMERR ((uint8_t)(1 << 6)) +#define MCH_HOST_BRIDGE_ESMRAMC_SM_CACHE ((uint8_t)(1 << 5)) +#define MCH_HOST_BRIDGE_ESMRAMC_SM_L1 ((uint8_t)(1 << 4)) +#define MCH_HOST_BRIDGE_ESMRAMC_SM_L2 ((uint8_t)(1 << 3)) #define MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK ((uint8_t)(0x3 << 1)) #define MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_1MB ((uint8_t)(0x0 << 1)) #define MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_2MB ((uint8_t)(0x1 << 1)) -- cgit 1.4.1 From 7744752402d11cebe4c1d4079dcd40d3145eb37b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 15 Apr 2015 16:43:24 +0200 Subject: q35: fix ESMRAMC default The cache bits in ESMRAMC are hardcoded to 1 (=disabled) according to the q35 mch specs. Add and use a define with this default. While being at it also update the SMRAM default to use the name (no code change, just makes things a bit more readable). Signed-off-by: Gerd Hoffmann Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini --- hw/pci-host/q35.c | 1 + include/hw/pci-host/q35.h | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'include/hw/pci-host/q35.h') diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 8f8d9e86e1..4e65bdc559 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -354,6 +354,7 @@ static void mch_reset(DeviceState *qdev) MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT); d->config[MCH_HOST_BRIDGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_DEFAULT; + d->config[MCH_HOST_BRIDGE_ESMRAMC] = MCH_HOST_BRIDGE_ESMRAMC_DEFAULT; mch_update(mch); } diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h index 0fff6a2421..d3c7bbbdfe 100644 --- a/include/hw/pci-host/q35.h +++ b/include/hw/pci-host/q35.h @@ -128,7 +128,6 @@ typedef struct Q35PCIHost { #define MCH_HOST_BRIDGE_SMRAM 0x9d #define MCH_HOST_BRIDGE_SMRAM_SIZE 2 -#define MCH_HOST_BRIDGE_SMRAM_DEFAULT ((uint8_t)0x2) #define MCH_HOST_BRIDGE_SMRAM_D_OPEN ((uint8_t)(1 << 6)) #define MCH_HOST_BRIDGE_SMRAM_D_CLS ((uint8_t)(1 << 5)) #define MCH_HOST_BRIDGE_SMRAM_D_LCK ((uint8_t)(1 << 4)) @@ -139,6 +138,8 @@ typedef struct Q35PCIHost { #define MCH_HOST_BRIDGE_SMRAM_C_END 0xc0000 #define MCH_HOST_BRIDGE_SMRAM_C_SIZE 0x20000 #define MCH_HOST_BRIDGE_UPPER_SYSTEM_BIOS_END 0x100000 +#define MCH_HOST_BRIDGE_SMRAM_DEFAULT \ + MCH_HOST_BRIDGE_SMRAM_C_BASE_SEG #define MCH_HOST_BRIDGE_ESMRAMC 0x9e #define MCH_HOST_BRIDGE_ESMRAMC_H_SMRAME ((uint8_t)(1 << 7)) @@ -151,6 +152,10 @@ typedef struct Q35PCIHost { #define MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_2MB ((uint8_t)(0x1 << 1)) #define MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_8MB ((uint8_t)(0x2 << 1)) #define MCH_HOST_BRIDGE_ESMRAMC_T_EN ((uint8_t)1) +#define MCH_HOST_BRIDGE_ESMRAMC_DEFAULT \ + (MCH_HOST_BRIDGE_ESMRAMC_SM_CACHE | \ + MCH_HOST_BRIDGE_ESMRAMC_SM_L1 | \ + MCH_HOST_BRIDGE_ESMRAMC_SM_L2) /* D1:F0 PCIE* port*/ #define MCH_PCIE_DEV 1 -- cgit 1.4.1 From b66a67d7519cb7f980885af5391b1103c42e9b6d Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 15 Apr 2015 16:48:12 +0200 Subject: q35: add config space wmask for SMRAM and ESMRAMC Not all bits in SMRAM and ESMRAMC can be changed by the guest. Add wmask defines accordingly and set them in mch_reset(). Signed-off-by: Gerd Hoffmann Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini --- hw/pci-host/q35.c | 2 ++ include/hw/pci-host/q35.h | 9 +++++++++ 2 files changed, 11 insertions(+) (limited to 'include/hw/pci-host/q35.h') diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 4e65bdc559..14e5aebee6 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -355,6 +355,8 @@ static void mch_reset(DeviceState *qdev) d->config[MCH_HOST_BRIDGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_DEFAULT; d->config[MCH_HOST_BRIDGE_ESMRAMC] = MCH_HOST_BRIDGE_ESMRAMC_DEFAULT; + d->wmask[MCH_HOST_BRIDGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_WMASK; + d->wmask[MCH_HOST_BRIDGE_ESMRAMC] = MCH_HOST_BRIDGE_ESMRAMC_WMASK; mch_update(mch); } diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h index d3c7bbbdfe..01b8492551 100644 --- a/include/hw/pci-host/q35.h +++ b/include/hw/pci-host/q35.h @@ -140,6 +140,11 @@ typedef struct Q35PCIHost { #define MCH_HOST_BRIDGE_UPPER_SYSTEM_BIOS_END 0x100000 #define MCH_HOST_BRIDGE_SMRAM_DEFAULT \ MCH_HOST_BRIDGE_SMRAM_C_BASE_SEG +#define MCH_HOST_BRIDGE_SMRAM_WMASK \ + (MCH_HOST_BRIDGE_SMRAM_D_OPEN | \ + MCH_HOST_BRIDGE_SMRAM_D_CLS | \ + MCH_HOST_BRIDGE_SMRAM_D_LCK | \ + MCH_HOST_BRIDGE_SMRAM_G_SMRAME) #define MCH_HOST_BRIDGE_ESMRAMC 0x9e #define MCH_HOST_BRIDGE_ESMRAMC_H_SMRAME ((uint8_t)(1 << 7)) @@ -156,6 +161,10 @@ typedef struct Q35PCIHost { (MCH_HOST_BRIDGE_ESMRAMC_SM_CACHE | \ MCH_HOST_BRIDGE_ESMRAMC_SM_L1 | \ MCH_HOST_BRIDGE_ESMRAMC_SM_L2) +#define MCH_HOST_BRIDGE_ESMRAMC_WMASK \ + (MCH_HOST_BRIDGE_ESMRAMC_H_SMRAME | \ + MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK | \ + MCH_HOST_BRIDGE_ESMRAMC_T_EN) /* D1:F0 PCIE* port*/ #define MCH_PCIE_DEV 1 -- cgit 1.4.1 From 68c77acfb18d28933f17b1c2a842bd936ce7223b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 14 Apr 2015 14:03:22 +0200 Subject: q35: implement SMRAM.D_LCK Once the SMRAM.D_LCK bit has been set by the guest several bits in SMRAM and ESMRAMC become readonly until the next machine reset. Implement this by updating the wmask accordingly when the guest sets the lock bit. As the lock it itself is locked down too we don't need to worry about the guest clearing the lock bit. Signed-off-by: Gerd Hoffmann Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini --- hw/pci-host/q35.c | 8 +++++++- include/hw/pci-host/q35.h | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'include/hw/pci-host/q35.h') diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 14e5aebee6..305994bc38 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -268,6 +268,13 @@ static void mch_update_smram(MCHPCIState *mch) PCIDevice *pd = PCI_DEVICE(mch); bool h_smrame = (pd->config[MCH_HOST_BRIDGE_ESMRAMC] & MCH_HOST_BRIDGE_ESMRAMC_H_SMRAME); + /* implement SMRAM.D_LCK */ + if (pd->config[MCH_HOST_BRIDGE_SMRAM] & MCH_HOST_BRIDGE_SMRAM_D_LCK) { + pd->config[MCH_HOST_BRIDGE_SMRAM] &= ~MCH_HOST_BRIDGE_SMRAM_D_OPEN; + pd->wmask[MCH_HOST_BRIDGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_WMASK_LCK; + pd->wmask[MCH_HOST_BRIDGE_ESMRAMC] = MCH_HOST_BRIDGE_ESMRAMC_WMASK_LCK; + } + memory_region_transaction_begin(); if (pd->config[MCH_HOST_BRIDGE_SMRAM] & SMRAM_D_OPEN) { @@ -297,7 +304,6 @@ static void mch_write_config(PCIDevice *d, { MCHPCIState *mch = MCH_PCI_DEVICE(d); - /* XXX: implement SMRAM.D_LOCK */ pci_default_write_config(d, address, val, len); if (ranges_overlap(address, len, MCH_HOST_BRIDGE_PAM0, diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h index 01b8492551..113cbe8190 100644 --- a/include/hw/pci-host/q35.h +++ b/include/hw/pci-host/q35.h @@ -145,6 +145,8 @@ typedef struct Q35PCIHost { MCH_HOST_BRIDGE_SMRAM_D_CLS | \ MCH_HOST_BRIDGE_SMRAM_D_LCK | \ MCH_HOST_BRIDGE_SMRAM_G_SMRAME) +#define MCH_HOST_BRIDGE_SMRAM_WMASK_LCK \ + MCH_HOST_BRIDGE_SMRAM_D_CLS #define MCH_HOST_BRIDGE_ESMRAMC 0x9e #define MCH_HOST_BRIDGE_ESMRAMC_H_SMRAME ((uint8_t)(1 << 7)) @@ -165,6 +167,7 @@ typedef struct Q35PCIHost { (MCH_HOST_BRIDGE_ESMRAMC_H_SMRAME | \ MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK | \ MCH_HOST_BRIDGE_ESMRAMC_T_EN) +#define MCH_HOST_BRIDGE_ESMRAMC_WMASK_LCK 0 /* D1:F0 PCIE* port*/ #define MCH_PCIE_DEV 1 -- cgit 1.4.1 From bafc90bdc594a4d04db846bd8712bdcec59678a8 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 20 Apr 2015 10:55:09 +0200 Subject: q35: implement TSEG TSEG provides larger amounts of SMRAM than the 128 KB available with legacy SMRAM and high SMRAM. Route access to tseg into nowhere when enabled, for both cpus and busmaster dma, and add tseg window to smram region, so cpus can access it in smm mode. Signed-off-by: Gerd Hoffmann Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini --- hw/pci-host/q35.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++ include/hw/pci-host/q35.h | 1 + 2 files changed, 71 insertions(+) (limited to 'include/hw/pci-host/q35.h') diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 305994bc38..bd7409456f 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -198,6 +198,28 @@ static const TypeInfo q35_host_info = { * MCH D0:F0 */ +static uint64_t tseg_blackhole_read(void *ptr, hwaddr reg, unsigned size) +{ + return 0xffffffff; +} + +static void tseg_blackhole_write(void *opaque, hwaddr addr, uint64_t val, + unsigned width) +{ + /* nothing */ +} + +static const MemoryRegionOps tseg_blackhole_ops = { + .read = tseg_blackhole_read, + .write = tseg_blackhole_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 4, + .impl.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + /* PCIe MMCFG */ static void mch_update_pciexbar(MCHPCIState *mch) { @@ -267,6 +289,7 @@ static void mch_update_smram(MCHPCIState *mch) { PCIDevice *pd = PCI_DEVICE(mch); bool h_smrame = (pd->config[MCH_HOST_BRIDGE_ESMRAMC] & MCH_HOST_BRIDGE_ESMRAMC_H_SMRAME); + uint32_t tseg_size; /* implement SMRAM.D_LCK */ if (pd->config[MCH_HOST_BRIDGE_SMRAM] & MCH_HOST_BRIDGE_SMRAM_D_LCK) { @@ -296,6 +319,39 @@ static void mch_update_smram(MCHPCIState *mch) memory_region_set_enabled(&mch->high_smram, false); } + if (pd->config[MCH_HOST_BRIDGE_ESMRAMC] & MCH_HOST_BRIDGE_ESMRAMC_T_EN) { + switch (pd->config[MCH_HOST_BRIDGE_ESMRAMC] & + MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK) { + case MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_1MB: + tseg_size = 1024 * 1024; + break; + case MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_2MB: + tseg_size = 1024 * 1024 * 2; + break; + case MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_8MB: + tseg_size = 1024 * 1024 * 8; + break; + default: + tseg_size = 0; + break; + } + } else { + tseg_size = 0; + } + memory_region_del_subregion(mch->system_memory, &mch->tseg_blackhole); + memory_region_set_enabled(&mch->tseg_blackhole, tseg_size); + memory_region_set_size(&mch->tseg_blackhole, tseg_size); + memory_region_add_subregion_overlap(mch->system_memory, + mch->below_4g_mem_size - tseg_size, + &mch->tseg_blackhole, 1); + + memory_region_set_enabled(&mch->tseg_window, tseg_size); + memory_region_set_size(&mch->tseg_window, tseg_size); + memory_region_set_address(&mch->tseg_window, + mch->below_4g_mem_size - tseg_size); + memory_region_set_alias_offset(&mch->tseg_window, + mch->below_4g_mem_size - tseg_size); + memory_region_transaction_commit(); } @@ -443,6 +499,20 @@ static void mch_realize(PCIDevice *d, Error **errp) mch->ram_memory, 0xa0000, 0x20000); memory_region_set_enabled(&mch->high_smram, true); memory_region_add_subregion(&mch->smram, 0xfeda0000, &mch->high_smram); + + memory_region_init_io(&mch->tseg_blackhole, OBJECT(mch), + &tseg_blackhole_ops, NULL, + "tseg-blackhole", 0); + memory_region_set_enabled(&mch->tseg_blackhole, false); + memory_region_add_subregion_overlap(mch->system_memory, + mch->below_4g_mem_size, + &mch->tseg_blackhole, 1); + + memory_region_init_alias(&mch->tseg_window, OBJECT(mch), "tseg-window", + mch->ram_memory, mch->below_4g_mem_size, 0); + memory_region_set_enabled(&mch->tseg_window, false); + memory_region_add_subregion(&mch->smram, mch->below_4g_mem_size, + &mch->tseg_window); object_property_add_const_link(qdev_get_machine(), "smram", OBJECT(&mch->smram), &error_abort); diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h index 113cbe8190..dbe6dc05b5 100644 --- a/include/hw/pci-host/q35.h +++ b/include/hw/pci-host/q35.h @@ -54,6 +54,7 @@ typedef struct MCHPCIState { PAMMemoryRegion pam_regions[13]; MemoryRegion smram_region, open_high_smram; MemoryRegion smram, low_smram, high_smram; + MemoryRegion tseg_blackhole, tseg_window; PcPciInfo pci_info; ram_addr_t below_4g_mem_size; ram_addr_t above_4g_mem_size; -- cgit 1.4.1