Skip to content

Commit

Permalink
memory: store MemoryRegionSection pointers in phys_map
Browse files Browse the repository at this point in the history
Instead of storing PhysPageDesc, store pointers to MemoryRegionSections.
The various offsets (phys_offset & ~TARGET_PAGE_MASK,
PHYS_OFFSET & TARGET_PAGE_MASK, region_offset) can all be synthesized
from the information in a MemoryRegionSection.  Adjust phys_page_find()
to synthesize a PhysPageDesc.

The upshot is that phys_map now contains uniform values, so it's easier
to generate and compress.

The end result is somewhat clumsy but this will be improved as we we
propagate MemoryRegionSections throughout the code instead of transforming
them to PhysPageDesc.

The MemoryRegionSection pointers are stored as uint16_t offsets in an
array.  This saves space (when we also compress node pointers) and is
more cache friendly.

Signed-off-by: Avi Kivity <avi@redhat.com>
  • Loading branch information
avikivity committed Feb 29, 2012
1 parent 4346ae3 commit 5312bd8
Showing 1 changed file with 107 additions and 80 deletions.
187 changes: 107 additions & 80 deletions exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,13 @@ typedef struct PhysPageDesc {

typedef struct PhysPageEntry PhysPageEntry;

static MemoryRegionSection *phys_sections;
static unsigned phys_sections_nb, phys_sections_nb_alloc;
static uint16_t phys_section_unassigned;

struct PhysPageEntry {
union {
PhysPageDesc leaf;
uint16_t leaf; /* index into phys_sections */
PhysPageEntry *node;
} u;
};
Expand Down Expand Up @@ -399,7 +403,7 @@ static inline PageDesc *page_find(tb_page_addr_t index)
}

#if !defined(CONFIG_USER_ONLY)
static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
static uint16_t *phys_page_find_alloc(target_phys_addr_t index, int alloc)
{
PhysPageEntry *lp, *p;
int i, j;
Expand All @@ -414,11 +418,8 @@ static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
}
lp->u.node = p = g_malloc0(sizeof(PhysPageEntry) * L2_SIZE);
if (i == 0) {
int first_index = index & ~(L2_SIZE - 1);
for (j = 0; j < L2_SIZE; j++) {
p[j].u.leaf.phys_offset = io_mem_unassigned.ram_addr;
p[j].u.leaf.region_offset
= (first_index + j) << TARGET_PAGE_BITS;
p[j].u.leaf = phys_section_unassigned;
}
}
}
Expand All @@ -430,16 +431,31 @@ static PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)

static inline PhysPageDesc phys_page_find(target_phys_addr_t index)
{
PhysPageDesc *p = phys_page_find_alloc(index, 0);
uint16_t *p = phys_page_find_alloc(index, 0);
uint16_t s_index = phys_section_unassigned;
MemoryRegionSection *section;
PhysPageDesc pd;

if (p) {
return *p;
} else {
return (PhysPageDesc) {
.phys_offset = io_mem_unassigned.ram_addr,
.region_offset = index << TARGET_PAGE_BITS,
};
s_index = *p;
}
section = &phys_sections[s_index];
index <<= TARGET_PAGE_BITS;
assert(section->offset_within_address_space <= index
&& index <= section->offset_within_address_space + section->size-1);
pd.phys_offset = section->mr->ram_addr;
pd.region_offset = (index - section->offset_within_address_space)
+ section->offset_within_region;
if (memory_region_is_ram(section->mr)) {
pd.phys_offset += pd.region_offset;
pd.region_offset = 0;
} else if (section->mr->rom_device) {
pd.phys_offset += pd.region_offset;
}
if (section->readonly) {
pd.phys_offset |= io_mem_rom.ram_addr;
}
return pd;
}

static void tlb_protect_code(ram_addr_t ram_addr);
Expand Down Expand Up @@ -2480,15 +2496,13 @@ static inline void tlb_set_dirty(CPUState *env,
typedef struct subpage_t {
MemoryRegion iomem;
target_phys_addr_t base;
ram_addr_t sub_io_index[TARGET_PAGE_SIZE];
ram_addr_t region_offset[TARGET_PAGE_SIZE];
uint16_t sub_section[TARGET_PAGE_SIZE];
} subpage_t;

static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
ram_addr_t memory, ram_addr_t region_offset);
static subpage_t *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
ram_addr_t orig_memory,
ram_addr_t region_offset);
uint16_t section);
static subpage_t *subpage_init (target_phys_addr_t base, uint16_t *section,
uint16_t orig_section);
#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
need_subpage) \
do { \
Expand All @@ -2509,10 +2523,10 @@ static subpage_t *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
} \
} while (0)

static void destroy_page_desc(PhysPageDesc pd)
static void destroy_page_desc(uint16_t section_index)
{
unsigned io_index = pd.phys_offset & ~TARGET_PAGE_MASK;
MemoryRegion *mr = io_mem_region[io_index];
MemoryRegionSection *section = &phys_sections[section_index];
MemoryRegion *mr = section->mr;

if (mr->subpage) {
subpage_t *subpage = container_of(mr, subpage_t, iomem);
Expand Down Expand Up @@ -2546,6 +2560,22 @@ static void destroy_all_mappings(void)
destroy_l2_mapping(&phys_map, P_L2_LEVELS - 1);
}

static uint16_t phys_section_add(MemoryRegionSection *section)
{
if (phys_sections_nb == phys_sections_nb_alloc) {
phys_sections_nb_alloc = MAX(phys_sections_nb_alloc * 2, 16);
phys_sections = g_renew(MemoryRegionSection, phys_sections,
phys_sections_nb_alloc);
}
phys_sections[phys_sections_nb] = *section;
return phys_sections_nb++;
}

static void phys_sections_clear(void)
{
phys_sections_nb = 0;
}

/* register physical memory.
For RAM, 'size' must be a multiple of the target page size.
If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
Expand All @@ -2559,67 +2589,46 @@ void cpu_register_physical_memory_log(MemoryRegionSection *section,
{
target_phys_addr_t start_addr = section->offset_within_address_space;
ram_addr_t size = section->size;
ram_addr_t phys_offset = section->mr->ram_addr;
ram_addr_t region_offset = section->offset_within_region;
target_phys_addr_t addr, end_addr;
PhysPageDesc *p;
uint16_t *p;
CPUState *env;
ram_addr_t orig_size = size;
subpage_t *subpage;

if (memory_region_is_ram(section->mr)) {
phys_offset += region_offset;
region_offset = 0;
}

if (readonly) {
phys_offset |= io_mem_rom.ram_addr;
}
uint16_t section_index = phys_section_add(section);

assert(size);

if (phys_offset == io_mem_unassigned.ram_addr) {
region_offset = start_addr;
}
region_offset &= TARGET_PAGE_MASK;
size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
end_addr = start_addr + (target_phys_addr_t)size;

addr = start_addr;
do {
p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 0);
if (p && p->phys_offset != io_mem_unassigned.ram_addr) {
ram_addr_t orig_memory = p->phys_offset;
if (p && *p != phys_section_unassigned) {
uint16_t orig_memory= *p;
target_phys_addr_t start_addr2, end_addr2;
int need_subpage = 0;
MemoryRegion *mr = io_mem_region[orig_memory & ~TARGET_PAGE_MASK];
MemoryRegion *mr = phys_sections[orig_memory].mr;

CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
need_subpage);
if (need_subpage) {
if (!(mr->subpage)) {
subpage = subpage_init((addr & TARGET_PAGE_MASK),
&p->phys_offset, orig_memory,
p->region_offset);
p, orig_memory);
} else {
subpage = container_of(mr, subpage_t, iomem);
}
subpage_register(subpage, start_addr2, end_addr2, phys_offset,
region_offset);
p->region_offset = 0;
subpage_register(subpage, start_addr2, end_addr2,
section_index);
} else {
p->phys_offset = phys_offset;
p->region_offset = region_offset;
if (is_ram_rom_romd(phys_offset))
phys_offset += TARGET_PAGE_SIZE;
*p = section_index;
}
} else {
MemoryRegion *mr = section->mr;
p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
p->phys_offset = phys_offset;
p->region_offset = region_offset;
if (is_ram_rom_romd(phys_offset)) {
phys_offset += TARGET_PAGE_SIZE;
} else {
*p = section_index;
if (!(memory_region_is_ram(mr) || mr->rom_device)) {
target_phys_addr_t start_addr2, end_addr2;
int need_subpage = 0;

Expand All @@ -2628,16 +2637,12 @@ void cpu_register_physical_memory_log(MemoryRegionSection *section,

if (need_subpage) {
subpage = subpage_init((addr & TARGET_PAGE_MASK),
&p->phys_offset,
io_mem_unassigned.ram_addr,
addr & TARGET_PAGE_MASK);
p, phys_section_unassigned);
subpage_register(subpage, start_addr2, end_addr2,
phys_offset, region_offset);
p->region_offset = 0;
section_index);
}
}
}
region_offset += TARGET_PAGE_SIZE;
addr += TARGET_PAGE_SIZE;
} while (addr != end_addr);

Expand Down Expand Up @@ -3333,30 +3338,36 @@ static uint64_t subpage_read(void *opaque, target_phys_addr_t addr,
{
subpage_t *mmio = opaque;
unsigned int idx = SUBPAGE_IDX(addr);
MemoryRegionSection *section;
#if defined(DEBUG_SUBPAGE)
printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
mmio, len, addr, idx);
#endif

addr += mmio->region_offset[idx];
idx = mmio->sub_io_index[idx];
return io_mem_read(idx, addr, len);
section = &phys_sections[mmio->sub_section[idx]];
addr += mmio->base;
addr -= section->offset_within_address_space;
addr += section->offset_within_region;
return io_mem_read(section->mr->ram_addr, addr, len);
}

static void subpage_write(void *opaque, target_phys_addr_t addr,
uint64_t value, unsigned len)
{
subpage_t *mmio = opaque;
unsigned int idx = SUBPAGE_IDX(addr);
MemoryRegionSection *section;
#if defined(DEBUG_SUBPAGE)
printf("%s: subpage %p len %d addr " TARGET_FMT_plx
" idx %d value %"PRIx64"\n",
__func__, mmio, len, addr, idx, value);
#endif

addr += mmio->region_offset[idx];
idx = mmio->sub_io_index[idx];
io_mem_write(idx, addr, value, len);
section = &phys_sections[mmio->sub_section[idx]];
addr += mmio->base;
addr -= section->offset_within_address_space;
addr += section->offset_within_region;
io_mem_write(section->mr->ram_addr, addr, value, len);
}

static const MemoryRegionOps subpage_ops = {
Expand Down Expand Up @@ -3398,7 +3409,7 @@ static const MemoryRegionOps subpage_ram_ops = {
};

static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
ram_addr_t memory, ram_addr_t region_offset)
uint16_t section)
{
int idx, eidx;

Expand All @@ -3410,38 +3421,40 @@ static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %ld\n", __func__,
mmio, start, end, idx, eidx, memory);
#endif
if ((memory & ~TARGET_PAGE_MASK) == io_mem_ram.ram_addr) {
memory = io_mem_subpage_ram.ram_addr;
if (memory_region_is_ram(phys_sections[section].mr)) {
MemoryRegionSection new_section = phys_sections[section];
new_section.mr = &io_mem_subpage_ram;
section = phys_section_add(&new_section);
}
memory &= IO_MEM_NB_ENTRIES - 1;
for (; idx <= eidx; idx++) {
mmio->sub_io_index[idx] = memory;
mmio->region_offset[idx] = region_offset;
mmio->sub_section[idx] = section;
}

return 0;
}

static subpage_t *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
ram_addr_t orig_memory,
ram_addr_t region_offset)
static subpage_t *subpage_init (target_phys_addr_t base, uint16_t *section_ind,
uint16_t orig_section)
{
subpage_t *mmio;
int subpage_memory;
MemoryRegionSection section = {
.offset_within_address_space = base,
.size = TARGET_PAGE_SIZE,
};

mmio = g_malloc0(sizeof(subpage_t));

mmio->base = base;
memory_region_init_io(&mmio->iomem, &subpage_ops, mmio,
"subpage", TARGET_PAGE_SIZE);
mmio->iomem.subpage = true;
subpage_memory = mmio->iomem.ram_addr;
section.mr = &mmio->iomem;
#if defined(DEBUG_SUBPAGE)
printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
mmio, base, TARGET_PAGE_SIZE, subpage_memory);
#endif
*phys = subpage_memory;
subpage_register(mmio, 0, TARGET_PAGE_SIZE-1, orig_memory, region_offset);
*section_ind = phys_section_add(&section);
subpage_register(mmio, 0, TARGET_PAGE_SIZE-1, orig_section);

return mmio;
}
Expand Down Expand Up @@ -3493,6 +3506,18 @@ void cpu_unregister_io_memory(int io_index)
io_mem_used[io_index] = 0;
}

static uint16_t dummy_section(MemoryRegion *mr)
{
MemoryRegionSection section = {
.mr = mr,
.offset_within_address_space = 0,
.offset_within_region = 0,
.size = UINT64_MAX,
};

return phys_section_add(&section);
}

static void io_mem_init(void)
{
int i;
Expand All @@ -3517,6 +3542,8 @@ static void io_mem_init(void)
static void core_begin(MemoryListener *listener)
{
destroy_all_mappings();
phys_sections_clear();
phys_section_unassigned = dummy_section(&io_mem_unassigned);
}

static void core_commit(MemoryListener *listener)
Expand Down

0 comments on commit 5312bd8

Please sign in to comment.