提交 90f18422 编写于 作者: B bellard

64 bit virtual addressing fix


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1525 c046a42c-6fe2-441c-8c8c-71466251a162
上级 95293972
...@@ -83,6 +83,8 @@ typedef struct PhysPageDesc { ...@@ -83,6 +83,8 @@ typedef struct PhysPageDesc {
uint32_t phys_offset; uint32_t phys_offset;
} PhysPageDesc; } PhysPageDesc;
/* Note: the VirtPage handling is absolete and will be suppressed
ASAP */
typedef struct VirtPageDesc { typedef struct VirtPageDesc {
/* physical address of code page. It is valid only if 'valid_tag' /* physical address of code page. It is valid only if 'valid_tag'
matches 'virt_valid_tag' */ matches 'virt_valid_tag' */
...@@ -113,7 +115,13 @@ static PageDesc *l1_map[L1_SIZE]; ...@@ -113,7 +115,13 @@ static PageDesc *l1_map[L1_SIZE];
PhysPageDesc **l1_phys_map; PhysPageDesc **l1_phys_map;
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
#if TARGET_LONG_BITS > 32
#define VIRT_L_BITS 9
#define VIRT_L_SIZE (1 << VIRT_L_BITS)
static void *l1_virt_map[VIRT_L_SIZE];
#else
static VirtPageDesc *l1_virt_map[L1_SIZE]; static VirtPageDesc *l1_virt_map[L1_SIZE];
#endif
static unsigned int virt_valid_tag; static unsigned int virt_valid_tag;
#endif #endif
...@@ -234,51 +242,113 @@ static inline PhysPageDesc *phys_page_find(unsigned int index) ...@@ -234,51 +242,113 @@ static inline PhysPageDesc *phys_page_find(unsigned int index)
static void tlb_protect_code(CPUState *env, target_ulong addr); static void tlb_protect_code(CPUState *env, target_ulong addr);
static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr); static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr);
static inline VirtPageDesc *virt_page_find_alloc(unsigned int index) static VirtPageDesc *virt_page_find_alloc(target_ulong index, int alloc)
{ {
VirtPageDesc **lp, *p;
/* XXX: should not truncate for 64 bit addresses */
#if TARGET_LONG_BITS > 32 #if TARGET_LONG_BITS > 32
index &= (L1_SIZE - 1); void **p, **lp;
#endif
p = l1_virt_map;
lp = p + ((index >> (5 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
p = *lp;
if (!p) {
if (!alloc)
return NULL;
p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
*lp = p;
}
lp = p + ((index >> (4 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
p = *lp;
if (!p) {
if (!alloc)
return NULL;
p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
*lp = p;
}
lp = p + ((index >> (3 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
p = *lp;
if (!p) {
if (!alloc)
return NULL;
p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
*lp = p;
}
lp = p + ((index >> (2 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
p = *lp;
if (!p) {
if (!alloc)
return NULL;
p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
*lp = p;
}
lp = p + ((index >> (1 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
p = *lp;
if (!p) {
if (!alloc)
return NULL;
p = qemu_mallocz(sizeof(VirtPageDesc) * VIRT_L_SIZE);
*lp = p;
}
return ((VirtPageDesc *)p) + (index & (VIRT_L_SIZE - 1));
#else
VirtPageDesc *p, **lp;
lp = &l1_virt_map[index >> L2_BITS]; lp = &l1_virt_map[index >> L2_BITS];
p = *lp; p = *lp;
if (!p) { if (!p) {
/* allocate if not found */ /* allocate if not found */
p = qemu_malloc(sizeof(VirtPageDesc) * L2_SIZE); if (!alloc)
memset(p, 0, sizeof(VirtPageDesc) * L2_SIZE); return NULL;
p = qemu_mallocz(sizeof(VirtPageDesc) * L2_SIZE);
*lp = p; *lp = p;
} }
return p + (index & (L2_SIZE - 1)); return p + (index & (L2_SIZE - 1));
#endif
} }
static inline VirtPageDesc *virt_page_find(unsigned int index) static inline VirtPageDesc *virt_page_find(target_ulong index)
{ {
VirtPageDesc *p; return virt_page_find_alloc(index, 0);
}
p = l1_virt_map[index >> L2_BITS]; #if TARGET_LONG_BITS > 32
if (!p) static void virt_page_flush_internal(void **p, int level)
return 0; {
return p + (index & (L2_SIZE - 1)); int i;
if (level == 0) {
VirtPageDesc *q = (VirtPageDesc *)p;
for(i = 0; i < VIRT_L_SIZE; i++)
q[i].valid_tag = 0;
} else {
level--;
for(i = 0; i < VIRT_L_SIZE; i++) {
if (p[i])
virt_page_flush_internal(p[i], level);
}
}
} }
#endif
static void virt_page_flush(void) static void virt_page_flush(void)
{ {
int i, j;
VirtPageDesc *p;
virt_valid_tag++; virt_valid_tag++;
if (virt_valid_tag == 0) { if (virt_valid_tag == 0) {
virt_valid_tag = 1; virt_valid_tag = 1;
for(i = 0; i < L1_SIZE; i++) { #if TARGET_LONG_BITS > 32
p = l1_virt_map[i]; virt_page_flush_internal(l1_virt_map, 5);
if (p) { #else
for(j = 0; j < L2_SIZE; j++) {
p[j].valid_tag = 0; int i, j;
VirtPageDesc *p;
for(i = 0; i < L1_SIZE; i++) {
p = l1_virt_map[i];
if (p) {
for(j = 0; j < L2_SIZE; j++)
p[j].valid_tag = 0;
}
} }
} }
#endif
} }
} }
#else #else
...@@ -945,7 +1015,7 @@ void tb_link(TranslationBlock *tb) ...@@ -945,7 +1015,7 @@ void tb_link(TranslationBlock *tb)
/* save the code memory mappings (needed to invalidate the code) */ /* save the code memory mappings (needed to invalidate the code) */
addr = tb->pc & TARGET_PAGE_MASK; addr = tb->pc & TARGET_PAGE_MASK;
vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS); vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
#ifdef DEBUG_TLB_CHECK #ifdef DEBUG_TLB_CHECK
if (vp->valid_tag == virt_valid_tag && if (vp->valid_tag == virt_valid_tag &&
vp->phys_addr != tb->page_addr[0]) { vp->phys_addr != tb->page_addr[0]) {
...@@ -963,7 +1033,7 @@ void tb_link(TranslationBlock *tb) ...@@ -963,7 +1033,7 @@ void tb_link(TranslationBlock *tb)
if (tb->page_addr[1] != -1) { if (tb->page_addr[1] != -1) {
addr += TARGET_PAGE_SIZE; addr += TARGET_PAGE_SIZE;
vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS); vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
#ifdef DEBUG_TLB_CHECK #ifdef DEBUG_TLB_CHECK
if (vp->valid_tag == virt_valid_tag && if (vp->valid_tag == virt_valid_tag &&
vp->phys_addr != tb->page_addr[1]) { vp->phys_addr != tb->page_addr[1]) {
...@@ -1572,7 +1642,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr, ...@@ -1572,7 +1642,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr,
addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK); addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
} }
index = (vaddr >> 12) & (CPU_TLB_SIZE - 1); index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
addend -= vaddr; addend -= vaddr;
if (prot & PAGE_READ) { if (prot & PAGE_READ) {
env->tlb_read[is_user][index].address = address; env->tlb_read[is_user][index].address = address;
...@@ -1635,7 +1705,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr, ...@@ -1635,7 +1705,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr,
original mapping */ original mapping */
VirtPageDesc *vp; VirtPageDesc *vp;
vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS); vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);
vp->phys_addr = pd; vp->phys_addr = pd;
vp->prot = prot; vp->prot = prot;
vp->valid_tag = virt_valid_tag; vp->valid_tag = virt_valid_tag;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册