Merge remote-tracking branch 'qemu-kvm/memory/mutators' into staging
Conflicts: memory.h
This commit is contained in:
commit
cde7fc31de
@ -219,6 +219,18 @@ The functions to do that are inside a vmstate definition, and are called:
|
|||||||
Example: You can look at hpet.c, that uses the three function to
|
Example: You can look at hpet.c, that uses the three function to
|
||||||
massage the state that is transferred.
|
massage the state that is transferred.
|
||||||
|
|
||||||
|
If you use memory API functions that update memory layout outside
|
||||||
|
initialization (i.e., in response to a guest action), this is a strong
|
||||||
|
indication that you need to call these functions in a post_load callback.
|
||||||
|
Examples of such memory API functions are:
|
||||||
|
|
||||||
|
- memory_region_add_subregion()
|
||||||
|
- memory_region_del_subregion()
|
||||||
|
- memory_region_set_readonly()
|
||||||
|
- memory_region_set_enabled()
|
||||||
|
- memory_region_set_address()
|
||||||
|
- memory_region_set_alias_offset()
|
||||||
|
|
||||||
=== Subsections ===
|
=== Subsections ===
|
||||||
|
|
||||||
The use of version_id allows to be able to migrate from older versions
|
The use of version_id allows to be able to migrate from older versions
|
||||||
|
@ -205,7 +205,7 @@ typedef struct CirrusVGAState {
|
|||||||
bool linear_vram; /* vga.vram mapped over cirrus_linear_io */
|
bool linear_vram; /* vga.vram mapped over cirrus_linear_io */
|
||||||
MemoryRegion low_mem_container; /* container for 0xa0000-0xc0000 */
|
MemoryRegion low_mem_container; /* container for 0xa0000-0xc0000 */
|
||||||
MemoryRegion low_mem; /* always mapped, overridden by: */
|
MemoryRegion low_mem; /* always mapped, overridden by: */
|
||||||
MemoryRegion *cirrus_bank[2]; /* aliases at 0xa0000-0xb0000 */
|
MemoryRegion cirrus_bank[2]; /* aliases at 0xa0000-0xb0000 */
|
||||||
uint32_t cirrus_addr_mask;
|
uint32_t cirrus_addr_mask;
|
||||||
uint32_t linear_mmio_mask;
|
uint32_t linear_mmio_mask;
|
||||||
uint8_t cirrus_shadow_gr0;
|
uint8_t cirrus_shadow_gr0;
|
||||||
@ -2363,40 +2363,16 @@ static const MemoryRegionOps cirrus_linear_bitblt_io_ops = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static void unmap_bank(CirrusVGAState *s, unsigned bank)
|
|
||||||
{
|
|
||||||
if (s->cirrus_bank[bank]) {
|
|
||||||
memory_region_del_subregion(&s->low_mem_container,
|
|
||||||
s->cirrus_bank[bank]);
|
|
||||||
memory_region_destroy(s->cirrus_bank[bank]);
|
|
||||||
g_free(s->cirrus_bank[bank]);
|
|
||||||
s->cirrus_bank[bank] = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void map_linear_vram_bank(CirrusVGAState *s, unsigned bank)
|
static void map_linear_vram_bank(CirrusVGAState *s, unsigned bank)
|
||||||
{
|
{
|
||||||
MemoryRegion *mr;
|
MemoryRegion *mr = &s->cirrus_bank[bank];
|
||||||
static const char *names[] = { "vga.bank0", "vga.bank1" };
|
bool enabled = !(s->cirrus_srcptr != s->cirrus_srcptr_end)
|
||||||
|
|
||||||
if (!(s->cirrus_srcptr != s->cirrus_srcptr_end)
|
|
||||||
&& !((s->vga.sr[0x07] & 0x01) == 0)
|
&& !((s->vga.sr[0x07] & 0x01) == 0)
|
||||||
&& !((s->vga.gr[0x0B] & 0x14) == 0x14)
|
&& !((s->vga.gr[0x0B] & 0x14) == 0x14)
|
||||||
&& !(s->vga.gr[0x0B] & 0x02)) {
|
&& !(s->vga.gr[0x0B] & 0x02);
|
||||||
|
|
||||||
mr = g_malloc(sizeof(*mr));
|
memory_region_set_enabled(mr, enabled);
|
||||||
memory_region_init_alias(mr, names[bank], &s->vga.vram,
|
memory_region_set_alias_offset(mr, s->cirrus_bank_base[bank]);
|
||||||
s->cirrus_bank_base[bank], 0x8000);
|
|
||||||
memory_region_add_subregion_overlap(
|
|
||||||
&s->low_mem_container,
|
|
||||||
0x8000 * bank,
|
|
||||||
mr,
|
|
||||||
1);
|
|
||||||
unmap_bank(s, bank);
|
|
||||||
s->cirrus_bank[bank] = mr;
|
|
||||||
} else {
|
|
||||||
unmap_bank(s, bank);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void map_linear_vram(CirrusVGAState *s)
|
static void map_linear_vram(CirrusVGAState *s)
|
||||||
@ -2415,8 +2391,8 @@ static void unmap_linear_vram(CirrusVGAState *s)
|
|||||||
s->linear_vram = false;
|
s->linear_vram = false;
|
||||||
memory_region_del_subregion(&s->pci_bar, &s->vga.vram);
|
memory_region_del_subregion(&s->pci_bar, &s->vga.vram);
|
||||||
}
|
}
|
||||||
unmap_bank(s, 0);
|
memory_region_set_enabled(&s->cirrus_bank[0], false);
|
||||||
unmap_bank(s, 1);
|
memory_region_set_enabled(&s->cirrus_bank[1], false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute the memory access functions */
|
/* Compute the memory access functions */
|
||||||
@ -2856,6 +2832,14 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci,
|
|||||||
memory_region_init_io(&s->low_mem, &cirrus_vga_mem_ops, s,
|
memory_region_init_io(&s->low_mem, &cirrus_vga_mem_ops, s,
|
||||||
"cirrus-low-memory", 0x20000);
|
"cirrus-low-memory", 0x20000);
|
||||||
memory_region_add_subregion(&s->low_mem_container, 0, &s->low_mem);
|
memory_region_add_subregion(&s->low_mem_container, 0, &s->low_mem);
|
||||||
|
for (i = 0; i < 2; ++i) {
|
||||||
|
static const char *names[] = { "vga.bank0", "vga.bank1" };
|
||||||
|
MemoryRegion *bank = &s->cirrus_bank[i];
|
||||||
|
memory_region_init_alias(bank, names[i], &s->vga.vram, 0, 0x8000);
|
||||||
|
memory_region_set_enabled(bank, false);
|
||||||
|
memory_region_add_subregion_overlap(&s->low_mem_container, i * 0x8000,
|
||||||
|
bank, 1);
|
||||||
|
}
|
||||||
memory_region_add_subregion_overlap(system_memory,
|
memory_region_add_subregion_overlap(system_memory,
|
||||||
isa_mem_base + 0x000a0000,
|
isa_mem_base + 0x000a0000,
|
||||||
&s->low_mem_container,
|
&s->low_mem_container,
|
||||||
|
@ -81,7 +81,6 @@ struct PCII440FXState {
|
|||||||
PAMMemoryRegion pam_regions[13];
|
PAMMemoryRegion pam_regions[13];
|
||||||
MemoryRegion smram_region;
|
MemoryRegion smram_region;
|
||||||
uint8_t smm_enabled;
|
uint8_t smm_enabled;
|
||||||
bool smram_enabled;
|
|
||||||
PIIX3State *piix3;
|
PIIX3State *piix3;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -141,6 +140,7 @@ static void i440fx_update_memory_mappings(PCII440FXState *d)
|
|||||||
{
|
{
|
||||||
int i, r;
|
int i, r;
|
||||||
uint32_t smram;
|
uint32_t smram;
|
||||||
|
bool smram_enabled;
|
||||||
|
|
||||||
memory_region_transaction_begin();
|
memory_region_transaction_begin();
|
||||||
update_pam(d, 0xf0000, 0x100000, (d->dev.config[I440FX_PAM] >> 4) & 3,
|
update_pam(d, 0xf0000, 0x100000, (d->dev.config[I440FX_PAM] >> 4) & 3,
|
||||||
@ -151,18 +151,8 @@ static void i440fx_update_memory_mappings(PCII440FXState *d)
|
|||||||
&d->pam_regions[i+1]);
|
&d->pam_regions[i+1]);
|
||||||
}
|
}
|
||||||
smram = d->dev.config[I440FX_SMRAM];
|
smram = d->dev.config[I440FX_SMRAM];
|
||||||
if ((d->smm_enabled && (smram & 0x08)) || (smram & 0x40)) {
|
smram_enabled = (d->smm_enabled && (smram & 0x08)) || (smram & 0x40);
|
||||||
if (!d->smram_enabled) {
|
memory_region_set_enabled(&d->smram_region, !smram_enabled);
|
||||||
memory_region_del_subregion(d->system_memory, &d->smram_region);
|
|
||||||
d->smram_enabled = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (d->smram_enabled) {
|
|
||||||
memory_region_add_subregion_overlap(d->system_memory, 0xa0000,
|
|
||||||
&d->smram_region, 1);
|
|
||||||
d->smram_enabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
memory_region_transaction_commit();
|
memory_region_transaction_commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,7 +298,9 @@ static PCIBus *i440fx_common_init(const char *device_name,
|
|||||||
}
|
}
|
||||||
memory_region_init_alias(&f->smram_region, "smram-region",
|
memory_region_init_alias(&f->smram_region, "smram-region",
|
||||||
f->pci_address_space, 0xa0000, 0x20000);
|
f->pci_address_space, 0xa0000, 0x20000);
|
||||||
f->smram_enabled = true;
|
memory_region_add_subregion_overlap(f->system_memory, 0xa0000,
|
||||||
|
&f->smram_region, 1);
|
||||||
|
memory_region_set_enabled(&f->smram_region, false);
|
||||||
|
|
||||||
/* Xen supports additional interrupt routes from the PCI devices to
|
/* Xen supports additional interrupt routes from the PCI devices to
|
||||||
* the IOAPIC: the four pins of each PCI device on the bus are also
|
* the IOAPIC: the four pins of each PCI device on the bus are also
|
||||||
|
81
memory.c
81
memory.c
@ -19,6 +19,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
unsigned memory_region_transaction_depth = 0;
|
unsigned memory_region_transaction_depth = 0;
|
||||||
|
static bool memory_region_update_pending = false;
|
||||||
|
|
||||||
typedef struct AddrRange AddrRange;
|
typedef struct AddrRange AddrRange;
|
||||||
|
|
||||||
@ -528,6 +529,10 @@ static void render_memory_region(FlatView *view,
|
|||||||
FlatRange fr;
|
FlatRange fr;
|
||||||
AddrRange tmp;
|
AddrRange tmp;
|
||||||
|
|
||||||
|
if (!mr->enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int128_addto(&base, int128_make64(mr->addr));
|
int128_addto(&base, int128_make64(mr->addr));
|
||||||
readonly |= mr->readonly;
|
readonly |= mr->readonly;
|
||||||
|
|
||||||
@ -750,9 +755,14 @@ static void address_space_update_topology(AddressSpace *as)
|
|||||||
address_space_update_ioeventfds(as);
|
address_space_update_ioeventfds(as);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void memory_region_update_topology(void)
|
static void memory_region_update_topology(MemoryRegion *mr)
|
||||||
{
|
{
|
||||||
if (memory_region_transaction_depth) {
|
if (memory_region_transaction_depth) {
|
||||||
|
memory_region_update_pending |= !mr || mr->enabled;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mr && !mr->enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -762,6 +772,8 @@ static void memory_region_update_topology(void)
|
|||||||
if (address_space_io.root) {
|
if (address_space_io.root) {
|
||||||
address_space_update_topology(&address_space_io);
|
address_space_update_topology(&address_space_io);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memory_region_update_pending = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void memory_region_transaction_begin(void)
|
void memory_region_transaction_begin(void)
|
||||||
@ -773,7 +785,9 @@ void memory_region_transaction_commit(void)
|
|||||||
{
|
{
|
||||||
assert(memory_region_transaction_depth);
|
assert(memory_region_transaction_depth);
|
||||||
--memory_region_transaction_depth;
|
--memory_region_transaction_depth;
|
||||||
memory_region_update_topology();
|
if (!memory_region_transaction_depth && memory_region_update_pending) {
|
||||||
|
memory_region_update_topology(NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void memory_region_destructor_none(MemoryRegion *mr)
|
static void memory_region_destructor_none(MemoryRegion *mr)
|
||||||
@ -813,6 +827,7 @@ void memory_region_init(MemoryRegion *mr,
|
|||||||
}
|
}
|
||||||
mr->addr = 0;
|
mr->addr = 0;
|
||||||
mr->offset = 0;
|
mr->offset = 0;
|
||||||
|
mr->enabled = true;
|
||||||
mr->terminates = false;
|
mr->terminates = false;
|
||||||
mr->readable = true;
|
mr->readable = true;
|
||||||
mr->readonly = false;
|
mr->readonly = false;
|
||||||
@ -1058,7 +1073,7 @@ void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client)
|
|||||||
uint8_t mask = 1 << client;
|
uint8_t mask = 1 << client;
|
||||||
|
|
||||||
mr->dirty_log_mask = (mr->dirty_log_mask & ~mask) | (log * mask);
|
mr->dirty_log_mask = (mr->dirty_log_mask & ~mask) | (log * mask);
|
||||||
memory_region_update_topology();
|
memory_region_update_topology(mr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool memory_region_get_dirty(MemoryRegion *mr, target_phys_addr_t addr,
|
bool memory_region_get_dirty(MemoryRegion *mr, target_phys_addr_t addr,
|
||||||
@ -1090,7 +1105,7 @@ void memory_region_set_readonly(MemoryRegion *mr, bool readonly)
|
|||||||
{
|
{
|
||||||
if (mr->readonly != readonly) {
|
if (mr->readonly != readonly) {
|
||||||
mr->readonly = readonly;
|
mr->readonly = readonly;
|
||||||
memory_region_update_topology();
|
memory_region_update_topology(mr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1098,7 +1113,7 @@ void memory_region_rom_device_set_readable(MemoryRegion *mr, bool readable)
|
|||||||
{
|
{
|
||||||
if (mr->readable != readable) {
|
if (mr->readable != readable) {
|
||||||
mr->readable = readable;
|
mr->readable = readable;
|
||||||
memory_region_update_topology();
|
memory_region_update_topology(mr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1203,7 +1218,7 @@ void memory_region_add_eventfd(MemoryRegion *mr,
|
|||||||
memmove(&mr->ioeventfds[i+1], &mr->ioeventfds[i],
|
memmove(&mr->ioeventfds[i+1], &mr->ioeventfds[i],
|
||||||
sizeof(*mr->ioeventfds) * (mr->ioeventfd_nb-1 - i));
|
sizeof(*mr->ioeventfds) * (mr->ioeventfd_nb-1 - i));
|
||||||
mr->ioeventfds[i] = mrfd;
|
mr->ioeventfds[i] = mrfd;
|
||||||
memory_region_update_topology();
|
memory_region_update_topology(mr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void memory_region_del_eventfd(MemoryRegion *mr,
|
void memory_region_del_eventfd(MemoryRegion *mr,
|
||||||
@ -1233,7 +1248,7 @@ void memory_region_del_eventfd(MemoryRegion *mr,
|
|||||||
--mr->ioeventfd_nb;
|
--mr->ioeventfd_nb;
|
||||||
mr->ioeventfds = g_realloc(mr->ioeventfds,
|
mr->ioeventfds = g_realloc(mr->ioeventfds,
|
||||||
sizeof(*mr->ioeventfds)*mr->ioeventfd_nb + 1);
|
sizeof(*mr->ioeventfds)*mr->ioeventfd_nb + 1);
|
||||||
memory_region_update_topology();
|
memory_region_update_topology(mr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void memory_region_add_subregion_common(MemoryRegion *mr,
|
static void memory_region_add_subregion_common(MemoryRegion *mr,
|
||||||
@ -1274,7 +1289,7 @@ static void memory_region_add_subregion_common(MemoryRegion *mr,
|
|||||||
}
|
}
|
||||||
QTAILQ_INSERT_TAIL(&mr->subregions, subregion, subregions_link);
|
QTAILQ_INSERT_TAIL(&mr->subregions, subregion, subregions_link);
|
||||||
done:
|
done:
|
||||||
memory_region_update_topology();
|
memory_region_update_topology(mr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1303,19 +1318,63 @@ void memory_region_del_subregion(MemoryRegion *mr,
|
|||||||
assert(subregion->parent == mr);
|
assert(subregion->parent == mr);
|
||||||
subregion->parent = NULL;
|
subregion->parent = NULL;
|
||||||
QTAILQ_REMOVE(&mr->subregions, subregion, subregions_link);
|
QTAILQ_REMOVE(&mr->subregions, subregion, subregions_link);
|
||||||
memory_region_update_topology();
|
memory_region_update_topology(mr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void memory_region_set_enabled(MemoryRegion *mr, bool enabled)
|
||||||
|
{
|
||||||
|
if (enabled == mr->enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mr->enabled = enabled;
|
||||||
|
memory_region_update_topology(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void memory_region_set_address(MemoryRegion *mr, target_phys_addr_t addr)
|
||||||
|
{
|
||||||
|
MemoryRegion *parent = mr->parent;
|
||||||
|
unsigned priority = mr->priority;
|
||||||
|
bool may_overlap = mr->may_overlap;
|
||||||
|
|
||||||
|
if (addr == mr->addr || !parent) {
|
||||||
|
mr->addr = addr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memory_region_transaction_begin();
|
||||||
|
memory_region_del_subregion(parent, mr);
|
||||||
|
if (may_overlap) {
|
||||||
|
memory_region_add_subregion_overlap(parent, addr, mr, priority);
|
||||||
|
} else {
|
||||||
|
memory_region_add_subregion(parent, addr, mr);
|
||||||
|
}
|
||||||
|
memory_region_transaction_commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void memory_region_set_alias_offset(MemoryRegion *mr, target_phys_addr_t offset)
|
||||||
|
{
|
||||||
|
target_phys_addr_t old_offset = mr->alias_offset;
|
||||||
|
|
||||||
|
assert(mr->alias);
|
||||||
|
mr->alias_offset = offset;
|
||||||
|
|
||||||
|
if (offset == old_offset || !mr->parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memory_region_update_topology(mr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_system_memory_map(MemoryRegion *mr)
|
void set_system_memory_map(MemoryRegion *mr)
|
||||||
{
|
{
|
||||||
address_space_memory.root = mr;
|
address_space_memory.root = mr;
|
||||||
memory_region_update_topology();
|
memory_region_update_topology(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_system_io_map(MemoryRegion *mr)
|
void set_system_io_map(MemoryRegion *mr)
|
||||||
{
|
{
|
||||||
address_space_io.root = mr;
|
address_space_io.root = mr;
|
||||||
memory_region_update_topology();
|
memory_region_update_topology(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct MemoryRegionList MemoryRegionList;
|
typedef struct MemoryRegionList MemoryRegionList;
|
||||||
|
39
memory.h
39
memory.h
@ -123,6 +123,7 @@ struct MemoryRegion {
|
|||||||
bool terminates;
|
bool terminates;
|
||||||
bool readable;
|
bool readable;
|
||||||
bool readonly; /* For RAM regions */
|
bool readonly; /* For RAM regions */
|
||||||
|
bool enabled;
|
||||||
MemoryRegion *alias;
|
MemoryRegion *alias;
|
||||||
target_phys_addr_t alias_offset;
|
target_phys_addr_t alias_offset;
|
||||||
unsigned priority;
|
unsigned priority;
|
||||||
@ -501,6 +502,44 @@ void memory_region_add_subregion_overlap(MemoryRegion *mr,
|
|||||||
void memory_region_del_subregion(MemoryRegion *mr,
|
void memory_region_del_subregion(MemoryRegion *mr,
|
||||||
MemoryRegion *subregion);
|
MemoryRegion *subregion);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* memory_region_set_enabled: dynamically enable or disable a region
|
||||||
|
*
|
||||||
|
* Enables or disables a memory region. A disabled memory region
|
||||||
|
* ignores all accesses to itself and its subregions. It does not
|
||||||
|
* obscure sibling subregions with lower priority - it simply behaves as
|
||||||
|
* if it was removed from the hierarchy.
|
||||||
|
*
|
||||||
|
* Regions default to being enabled.
|
||||||
|
*
|
||||||
|
* @mr: the region to be updated
|
||||||
|
* @enabled: whether to enable or disable the region
|
||||||
|
*/
|
||||||
|
void memory_region_set_enabled(MemoryRegion *mr, bool enabled);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* memory_region_set_address: dynamically update the address of a region
|
||||||
|
*
|
||||||
|
* Dynamically updates the address of a region, relative to its parent.
|
||||||
|
* May be used on regions are currently part of a memory hierarchy.
|
||||||
|
*
|
||||||
|
* @mr: the region to be updated
|
||||||
|
* @addr: new address, relative to parent region
|
||||||
|
*/
|
||||||
|
void memory_region_set_address(MemoryRegion *mr, target_phys_addr_t addr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* memory_region_set_alias_offset: dynamically update a memory alias's offset
|
||||||
|
*
|
||||||
|
* Dynamically updates the offset into the target region that an alias points
|
||||||
|
* to, as if the fourth argument to memory_region_init_alias() has changed.
|
||||||
|
*
|
||||||
|
* @mr: the #MemoryRegion to be updated; should be an alias.
|
||||||
|
* @offset: the new offset into the target memory region
|
||||||
|
*/
|
||||||
|
void memory_region_set_alias_offset(MemoryRegion *mr,
|
||||||
|
target_phys_addr_t offset);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* memory_region_transaction_begin: Start a transaction.
|
* memory_region_transaction_begin: Start a transaction.
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user