Commit 92e873b996adb4cdc8ec9ab7e49d1c88d8749127
1 parent
9fddaa0c
support for non continuous RAM or ROM
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@842 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
46 additions
and
11 deletions
exec.c
| ... | ... | @@ -64,9 +64,7 @@ uint8_t *phys_ram_base; |
| 64 | 64 | uint8_t *phys_ram_dirty; |
| 65 | 65 | |
| 66 | 66 | typedef struct PageDesc { |
| 67 | - /* offset in host memory of the page + io_index in the low 12 bits */ | |
| 68 | - unsigned long phys_offset; | |
| 69 | - /* list of TBs intersecting this physical page */ | |
| 67 | + /* list of TBs intersecting this ram page */ | |
| 70 | 68 | TranslationBlock *first_tb; |
| 71 | 69 | /* in order to optimize self modifying code, we count the number |
| 72 | 70 | of lookups we do to a given page to use a bitmap */ |
| ... | ... | @@ -77,6 +75,11 @@ typedef struct PageDesc { |
| 77 | 75 | #endif |
| 78 | 76 | } PageDesc; |
| 79 | 77 | |
| 78 | +typedef struct PhysPageDesc { | |
| 79 | + /* offset in host memory of the page + io_index in the low 12 bits */ | |
| 80 | + unsigned long phys_offset; | |
| 81 | +} PhysPageDesc; | |
| 82 | + | |
| 80 | 83 | typedef struct VirtPageDesc { |
| 81 | 84 | /* physical address of code page. It is valid only if 'valid_tag' |
| 82 | 85 | matches 'virt_valid_tag' */ |
| ... | ... | @@ -102,7 +105,9 @@ unsigned long host_page_bits; |
| 102 | 105 | unsigned long host_page_size; |
| 103 | 106 | unsigned long host_page_mask; |
| 104 | 107 | |
| 108 | +/* XXX: for system emulation, it could just be an array */ | |
| 105 | 109 | static PageDesc *l1_map[L1_SIZE]; |
| 110 | +static PhysPageDesc *l1_phys_map[L1_SIZE]; | |
| 106 | 111 | |
| 107 | 112 | #if !defined(CONFIG_USER_ONLY) |
| 108 | 113 | static VirtPageDesc *l1_virt_map[L1_SIZE]; |
| ... | ... | @@ -166,6 +171,31 @@ static inline PageDesc *page_find(unsigned int index) |
| 166 | 171 | return p + (index & (L2_SIZE - 1)); |
| 167 | 172 | } |
| 168 | 173 | |
| 174 | +static inline PhysPageDesc *phys_page_find_alloc(unsigned int index) | |
| 175 | +{ | |
| 176 | + PhysPageDesc **lp, *p; | |
| 177 | + | |
| 178 | + lp = &l1_phys_map[index >> L2_BITS]; | |
| 179 | + p = *lp; | |
| 180 | + if (!p) { | |
| 181 | + /* allocate if not found */ | |
| 182 | + p = qemu_malloc(sizeof(PhysPageDesc) * L2_SIZE); | |
| 183 | + memset(p, 0, sizeof(PhysPageDesc) * L2_SIZE); | |
| 184 | + *lp = p; | |
| 185 | + } | |
| 186 | + return p + (index & (L2_SIZE - 1)); | |
| 187 | +} | |
| 188 | + | |
| 189 | +static inline PhysPageDesc *phys_page_find(unsigned int index) | |
| 190 | +{ | |
| 191 | + PhysPageDesc *p; | |
| 192 | + | |
| 193 | + p = l1_phys_map[index >> L2_BITS]; | |
| 194 | + if (!p) | |
| 195 | + return 0; | |
| 196 | + return p + (index & (L2_SIZE - 1)); | |
| 197 | +} | |
| 198 | + | |
| 169 | 199 | #if !defined(CONFIG_USER_ONLY) |
| 170 | 200 | static void tlb_protect_code(CPUState *env, target_ulong addr); |
| 171 | 201 | static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr); |
| ... | ... | @@ -1428,7 +1458,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr, |
| 1428 | 1458 | target_phys_addr_t paddr, int prot, |
| 1429 | 1459 | int is_user, int is_softmmu) |
| 1430 | 1460 | { |
| 1431 | - PageDesc *p; | |
| 1461 | + PhysPageDesc *p; | |
| 1432 | 1462 | unsigned long pd; |
| 1433 | 1463 | TranslationBlock *first_tb; |
| 1434 | 1464 | unsigned int index; |
| ... | ... | @@ -1436,13 +1466,18 @@ int tlb_set_page(CPUState *env, target_ulong vaddr, |
| 1436 | 1466 | unsigned long addend; |
| 1437 | 1467 | int ret; |
| 1438 | 1468 | |
| 1439 | - p = page_find(paddr >> TARGET_PAGE_BITS); | |
| 1469 | + p = phys_page_find(paddr >> TARGET_PAGE_BITS); | |
| 1470 | + first_tb = NULL; | |
| 1440 | 1471 | if (!p) { |
| 1441 | 1472 | pd = IO_MEM_UNASSIGNED; |
| 1442 | - first_tb = NULL; | |
| 1443 | 1473 | } else { |
| 1474 | + PageDesc *p1; | |
| 1444 | 1475 | pd = p->phys_offset; |
| 1445 | - first_tb = p->first_tb; | |
| 1476 | + if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) { | |
| 1477 | + /* NOTE: we also allocate the page at this stage */ | |
| 1478 | + p1 = page_find_alloc(pd >> TARGET_PAGE_BITS); | |
| 1479 | + first_tb = p1->first_tb; | |
| 1480 | + } | |
| 1446 | 1481 | } |
| 1447 | 1482 | #if defined(DEBUG_TLB) |
| 1448 | 1483 | printf("tlb_set_page: vaddr=0x%08x paddr=0x%08x prot=%x u=%d c=%d smmu=%d pd=0x%08x\n", |
| ... | ... | @@ -1752,11 +1787,11 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr, |
| 1752 | 1787 | unsigned long phys_offset) |
| 1753 | 1788 | { |
| 1754 | 1789 | unsigned long addr, end_addr; |
| 1755 | - PageDesc *p; | |
| 1790 | + PhysPageDesc *p; | |
| 1756 | 1791 | |
| 1757 | 1792 | end_addr = start_addr + size; |
| 1758 | 1793 | for(addr = start_addr; addr < end_addr; addr += TARGET_PAGE_SIZE) { |
| 1759 | - p = page_find_alloc(addr >> TARGET_PAGE_BITS); | |
| 1794 | + p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS); | |
| 1760 | 1795 | p->phys_offset = phys_offset; |
| 1761 | 1796 | if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) |
| 1762 | 1797 | phys_offset += TARGET_PAGE_SIZE; |
| ... | ... | @@ -1938,14 +1973,14 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, |
| 1938 | 1973 | uint32_t val; |
| 1939 | 1974 | target_phys_addr_t page; |
| 1940 | 1975 | unsigned long pd; |
| 1941 | - PageDesc *p; | |
| 1976 | + PhysPageDesc *p; | |
| 1942 | 1977 | |
| 1943 | 1978 | while (len > 0) { |
| 1944 | 1979 | page = addr & TARGET_PAGE_MASK; |
| 1945 | 1980 | l = (page + TARGET_PAGE_SIZE) - addr; |
| 1946 | 1981 | if (l > len) |
| 1947 | 1982 | l = len; |
| 1948 | - p = page_find(page >> TARGET_PAGE_BITS); | |
| 1983 | + p = phys_page_find(page >> TARGET_PAGE_BITS); | |
| 1949 | 1984 | if (!p) { |
| 1950 | 1985 | pd = IO_MEM_UNASSIGNED; |
| 1951 | 1986 | } else { | ... | ... |