mirror of
https://github.com/qemu/qemu.git
synced 2024-11-25 11:53:39 +08:00
target-alpha: Fix translation of PALmode memory insns.
All of the "raw" memory accesses should be "phys" instead. Fix some confusion about argument ordering of the store routines. Fix the implementation of store-conditional. Delete the "alt-mode" helpers. Because we only implement two mmu modes, let /a imply user-mode unconditionally. Leave some combinations of virt access without permission checks as unimplemented. There are too many hoops through which to jump, and these insns will not be needed in the emulation palcode. Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
parent
352e48b0f4
commit
2374e73eda
@ -104,23 +104,15 @@ DEF_HELPER_0(hw_rei, void)
|
||||
DEF_HELPER_1(hw_ret, void, i64)
|
||||
DEF_HELPER_2(mfpr, i64, int, i64)
|
||||
DEF_HELPER_2(mtpr, void, int, i64)
|
||||
DEF_HELPER_0(set_alt_mode, void)
|
||||
DEF_HELPER_0(restore_mode, void)
|
||||
|
||||
DEF_HELPER_1(ld_virt_to_phys, i64, i64)
|
||||
DEF_HELPER_1(st_virt_to_phys, i64, i64)
|
||||
DEF_HELPER_2(ldl_raw, void, i64, i64)
|
||||
DEF_HELPER_2(ldq_raw, void, i64, i64)
|
||||
DEF_HELPER_2(ldl_l_raw, void, i64, i64)
|
||||
DEF_HELPER_2(ldq_l_raw, void, i64, i64)
|
||||
DEF_HELPER_2(ldl_kernel, void, i64, i64)
|
||||
DEF_HELPER_2(ldq_kernel, void, i64, i64)
|
||||
DEF_HELPER_2(ldl_data, void, i64, i64)
|
||||
DEF_HELPER_2(ldq_data, void, i64, i64)
|
||||
DEF_HELPER_2(stl_raw, void, i64, i64)
|
||||
DEF_HELPER_2(stq_raw, void, i64, i64)
|
||||
DEF_HELPER_2(stl_c_raw, i64, i64, i64)
|
||||
DEF_HELPER_2(stq_c_raw, i64, i64, i64)
|
||||
DEF_HELPER_1(ldl_phys, i64, i64)
|
||||
DEF_HELPER_1(ldq_phys, i64, i64)
|
||||
DEF_HELPER_1(ldl_l_phys, i64, i64)
|
||||
DEF_HELPER_1(ldq_l_phys, i64, i64)
|
||||
DEF_HELPER_2(stl_phys, void, i64, i64)
|
||||
DEF_HELPER_2(stq_phys, void, i64, i64)
|
||||
DEF_HELPER_2(stl_c_phys, i64, i64, i64)
|
||||
DEF_HELPER_2(stq_c_phys, i64, i64, i64)
|
||||
#endif
|
||||
|
||||
#include "def-helper.h"
|
||||
|
@ -1188,150 +1188,71 @@ void helper_mtpr (int iprn, uint64_t val)
|
||||
{
|
||||
cpu_alpha_mtpr(env, iprn, val, NULL);
|
||||
}
|
||||
|
||||
void helper_set_alt_mode (void)
|
||||
{
|
||||
env->saved_mode = env->ps & 0xC;
|
||||
env->ps = (env->ps & ~0xC) | (env->ipr[IPR_ALT_MODE] & 0xC);
|
||||
}
|
||||
|
||||
void helper_restore_mode (void)
|
||||
{
|
||||
env->ps = (env->ps & ~0xC) | env->saved_mode;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Softmmu support */
|
||||
#if !defined (CONFIG_USER_ONLY)
|
||||
|
||||
/* XXX: the two following helpers are pure hacks.
|
||||
* Hopefully, we emulate the PALcode, then we should never see
|
||||
* HW_LD / HW_ST instructions.
|
||||
*/
|
||||
uint64_t helper_ld_virt_to_phys (uint64_t virtaddr)
|
||||
uint64_t helper_ldl_phys(uint64_t p)
|
||||
{
|
||||
uint64_t tlb_addr, physaddr;
|
||||
int index, mmu_idx;
|
||||
void *retaddr;
|
||||
return (int32_t)ldl_phys(p);
|
||||
}
|
||||
|
||||
mmu_idx = cpu_mmu_index(env);
|
||||
index = (virtaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
redo:
|
||||
tlb_addr = env->tlb_table[mmu_idx][index].addr_read;
|
||||
if ((virtaddr & TARGET_PAGE_MASK) ==
|
||||
(tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
|
||||
physaddr = virtaddr + env->tlb_table[mmu_idx][index].addend;
|
||||
} else {
|
||||
/* the page is not in the TLB : fill it */
|
||||
retaddr = GETPC();
|
||||
tlb_fill(virtaddr, 0, mmu_idx, retaddr);
|
||||
goto redo;
|
||||
uint64_t helper_ldq_phys(uint64_t p)
|
||||
{
|
||||
return ldq_phys(p);
|
||||
}
|
||||
|
||||
uint64_t helper_ldl_l_phys(uint64_t p)
|
||||
{
|
||||
env->lock_addr = p;
|
||||
return env->lock_value = (int32_t)ldl_phys(p);
|
||||
}
|
||||
|
||||
uint64_t helper_ldq_l_phys(uint64_t p)
|
||||
{
|
||||
env->lock_addr = p;
|
||||
return env->lock_value = ldl_phys(p);
|
||||
}
|
||||
|
||||
void helper_stl_phys(uint64_t p, uint64_t v)
|
||||
{
|
||||
stl_phys(p, v);
|
||||
}
|
||||
|
||||
void helper_stq_phys(uint64_t p, uint64_t v)
|
||||
{
|
||||
stq_phys(p, v);
|
||||
}
|
||||
|
||||
uint64_t helper_stl_c_phys(uint64_t p, uint64_t v)
|
||||
{
|
||||
uint64_t ret = 0;
|
||||
|
||||
if (p == env->lock_addr) {
|
||||
int32_t old = ldl_phys(p);
|
||||
if (old == (int32_t)env->lock_value) {
|
||||
stl_phys(p, v);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
return physaddr;
|
||||
}
|
||||
|
||||
uint64_t helper_st_virt_to_phys (uint64_t virtaddr)
|
||||
{
|
||||
uint64_t tlb_addr, physaddr;
|
||||
int index, mmu_idx;
|
||||
void *retaddr;
|
||||
|
||||
mmu_idx = cpu_mmu_index(env);
|
||||
index = (virtaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
redo:
|
||||
tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
|
||||
if ((virtaddr & TARGET_PAGE_MASK) ==
|
||||
(tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
|
||||
physaddr = virtaddr + env->tlb_table[mmu_idx][index].addend;
|
||||
} else {
|
||||
/* the page is not in the TLB : fill it */
|
||||
retaddr = GETPC();
|
||||
tlb_fill(virtaddr, 1, mmu_idx, retaddr);
|
||||
goto redo;
|
||||
}
|
||||
return physaddr;
|
||||
}
|
||||
|
||||
void helper_ldl_raw(uint64_t t0, uint64_t t1)
|
||||
{
|
||||
ldl_raw(t1, t0);
|
||||
}
|
||||
|
||||
void helper_ldq_raw(uint64_t t0, uint64_t t1)
|
||||
{
|
||||
ldq_raw(t1, t0);
|
||||
}
|
||||
|
||||
void helper_ldl_l_raw(uint64_t t0, uint64_t t1)
|
||||
{
|
||||
env->lock = t1;
|
||||
ldl_raw(t1, t0);
|
||||
}
|
||||
|
||||
void helper_ldq_l_raw(uint64_t t0, uint64_t t1)
|
||||
{
|
||||
env->lock = t1;
|
||||
ldl_raw(t1, t0);
|
||||
}
|
||||
|
||||
void helper_ldl_kernel(uint64_t t0, uint64_t t1)
|
||||
{
|
||||
ldl_kernel(t1, t0);
|
||||
}
|
||||
|
||||
void helper_ldq_kernel(uint64_t t0, uint64_t t1)
|
||||
{
|
||||
ldq_kernel(t1, t0);
|
||||
}
|
||||
|
||||
void helper_ldl_data(uint64_t t0, uint64_t t1)
|
||||
{
|
||||
ldl_data(t1, t0);
|
||||
}
|
||||
|
||||
void helper_ldq_data(uint64_t t0, uint64_t t1)
|
||||
{
|
||||
ldq_data(t1, t0);
|
||||
}
|
||||
|
||||
void helper_stl_raw(uint64_t t0, uint64_t t1)
|
||||
{
|
||||
stl_raw(t1, t0);
|
||||
}
|
||||
|
||||
void helper_stq_raw(uint64_t t0, uint64_t t1)
|
||||
{
|
||||
stq_raw(t1, t0);
|
||||
}
|
||||
|
||||
uint64_t helper_stl_c_raw(uint64_t t0, uint64_t t1)
|
||||
{
|
||||
uint64_t ret;
|
||||
|
||||
if (t1 == env->lock) {
|
||||
stl_raw(t1, t0);
|
||||
ret = 0;
|
||||
} else
|
||||
ret = 1;
|
||||
|
||||
env->lock = 1;
|
||||
env->lock_addr = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t helper_stq_c_raw(uint64_t t0, uint64_t t1)
|
||||
uint64_t helper_stq_c_phys(uint64_t p, uint64_t v)
|
||||
{
|
||||
uint64_t ret;
|
||||
uint64_t ret = 0;
|
||||
|
||||
if (t1 == env->lock) {
|
||||
stq_raw(t1, t0);
|
||||
ret = 0;
|
||||
} else
|
||||
ret = 1;
|
||||
|
||||
env->lock = 1;
|
||||
if (p == env->lock_addr) {
|
||||
uint64_t old = ldq_phys(p);
|
||||
if (old == env->lock_value) {
|
||||
stq_phys(p, v);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
env->lock_addr = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -2616,27 +2616,26 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
|
||||
switch ((insn >> 12) & 0xF) {
|
||||
case 0x0:
|
||||
/* Longword physical access (hw_ldl/p) */
|
||||
gen_helper_ldl_raw(cpu_ir[ra], addr);
|
||||
gen_helper_ldl_phys(cpu_ir[ra], addr);
|
||||
break;
|
||||
case 0x1:
|
||||
/* Quadword physical access (hw_ldq/p) */
|
||||
gen_helper_ldq_raw(cpu_ir[ra], addr);
|
||||
gen_helper_ldq_phys(cpu_ir[ra], addr);
|
||||
break;
|
||||
case 0x2:
|
||||
/* Longword physical access with lock (hw_ldl_l/p) */
|
||||
gen_helper_ldl_l_raw(cpu_ir[ra], addr);
|
||||
gen_helper_ldl_l_phys(cpu_ir[ra], addr);
|
||||
break;
|
||||
case 0x3:
|
||||
/* Quadword physical access with lock (hw_ldq_l/p) */
|
||||
gen_helper_ldq_l_raw(cpu_ir[ra], addr);
|
||||
gen_helper_ldq_l_phys(cpu_ir[ra], addr);
|
||||
break;
|
||||
case 0x4:
|
||||
/* Longword virtual PTE fetch (hw_ldl/v) */
|
||||
tcg_gen_qemu_ld32s(cpu_ir[ra], addr, 0);
|
||||
break;
|
||||
goto invalid_opc;
|
||||
case 0x5:
|
||||
/* Quadword virtual PTE fetch (hw_ldq/v) */
|
||||
tcg_gen_qemu_ld64(cpu_ir[ra], addr, 0);
|
||||
goto invalid_opc;
|
||||
break;
|
||||
case 0x6:
|
||||
/* Incpu_ir[ra]id */
|
||||
@ -2646,14 +2645,10 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
|
||||
goto invalid_opc;
|
||||
case 0x8:
|
||||
/* Longword virtual access (hw_ldl) */
|
||||
gen_helper_st_virt_to_phys(addr, addr);
|
||||
gen_helper_ldl_raw(cpu_ir[ra], addr);
|
||||
break;
|
||||
goto invalid_opc;
|
||||
case 0x9:
|
||||
/* Quadword virtual access (hw_ldq) */
|
||||
gen_helper_st_virt_to_phys(addr, addr);
|
||||
gen_helper_ldq_raw(cpu_ir[ra], addr);
|
||||
break;
|
||||
goto invalid_opc;
|
||||
case 0xA:
|
||||
/* Longword virtual access with protection check (hw_ldl/w) */
|
||||
tcg_gen_qemu_ld32s(cpu_ir[ra], addr, 0);
|
||||
@ -2664,33 +2659,19 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
|
||||
break;
|
||||
case 0xC:
|
||||
/* Longword virtual access with alt access mode (hw_ldl/a)*/
|
||||
gen_helper_set_alt_mode();
|
||||
gen_helper_st_virt_to_phys(addr, addr);
|
||||
gen_helper_ldl_raw(cpu_ir[ra], addr);
|
||||
gen_helper_restore_mode();
|
||||
break;
|
||||
goto invalid_opc;
|
||||
case 0xD:
|
||||
/* Quadword virtual access with alt access mode (hw_ldq/a) */
|
||||
gen_helper_set_alt_mode();
|
||||
gen_helper_st_virt_to_phys(addr, addr);
|
||||
gen_helper_ldq_raw(cpu_ir[ra], addr);
|
||||
gen_helper_restore_mode();
|
||||
break;
|
||||
goto invalid_opc;
|
||||
case 0xE:
|
||||
/* Longword virtual access with alternate access mode and
|
||||
* protection checks (hw_ldl/wa)
|
||||
*/
|
||||
gen_helper_set_alt_mode();
|
||||
gen_helper_ldl_data(cpu_ir[ra], addr);
|
||||
gen_helper_restore_mode();
|
||||
protection checks (hw_ldl/wa) */
|
||||
tcg_gen_qemu_ld32s(cpu_ir[ra], addr, MMU_USER_IDX);
|
||||
break;
|
||||
case 0xF:
|
||||
/* Quadword virtual access with alternate access mode and
|
||||
* protection checks (hw_ldq/wa)
|
||||
*/
|
||||
gen_helper_set_alt_mode();
|
||||
gen_helper_ldq_data(cpu_ir[ra], addr);
|
||||
gen_helper_restore_mode();
|
||||
protection checks (hw_ldq/wa) */
|
||||
tcg_gen_qemu_ld64(cpu_ir[ra], addr, MMU_USER_IDX);
|
||||
break;
|
||||
}
|
||||
tcg_temp_free(addr);
|
||||
@ -2940,30 +2921,26 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
|
||||
switch ((insn >> 12) & 0xF) {
|
||||
case 0x0:
|
||||
/* Longword physical access */
|
||||
gen_helper_stl_raw(val, addr);
|
||||
gen_helper_stl_phys(addr, val);
|
||||
break;
|
||||
case 0x1:
|
||||
/* Quadword physical access */
|
||||
gen_helper_stq_raw(val, addr);
|
||||
gen_helper_stq_phys(addr, val);
|
||||
break;
|
||||
case 0x2:
|
||||
/* Longword physical access with lock */
|
||||
gen_helper_stl_c_raw(val, val, addr);
|
||||
gen_helper_stl_c_phys(val, addr, val);
|
||||
break;
|
||||
case 0x3:
|
||||
/* Quadword physical access with lock */
|
||||
gen_helper_stq_c_raw(val, val, addr);
|
||||
gen_helper_stq_c_phys(val, addr, val);
|
||||
break;
|
||||
case 0x4:
|
||||
/* Longword virtual access */
|
||||
gen_helper_st_virt_to_phys(addr, addr);
|
||||
gen_helper_stl_raw(val, addr);
|
||||
break;
|
||||
goto invalid_opc;
|
||||
case 0x5:
|
||||
/* Quadword virtual access */
|
||||
gen_helper_st_virt_to_phys(addr, addr);
|
||||
gen_helper_stq_raw(val, addr);
|
||||
break;
|
||||
goto invalid_opc;
|
||||
case 0x6:
|
||||
/* Invalid */
|
||||
goto invalid_opc;
|
||||
@ -2984,18 +2961,10 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
|
||||
goto invalid_opc;
|
||||
case 0xC:
|
||||
/* Longword virtual access with alternate access mode */
|
||||
gen_helper_set_alt_mode();
|
||||
gen_helper_st_virt_to_phys(addr, addr);
|
||||
gen_helper_stl_raw(val, addr);
|
||||
gen_helper_restore_mode();
|
||||
break;
|
||||
goto invalid_opc;
|
||||
case 0xD:
|
||||
/* Quadword virtual access with alternate access mode */
|
||||
gen_helper_set_alt_mode();
|
||||
gen_helper_st_virt_to_phys(addr, addr);
|
||||
gen_helper_stl_raw(val, addr);
|
||||
gen_helper_restore_mode();
|
||||
break;
|
||||
goto invalid_opc;
|
||||
case 0xE:
|
||||
/* Invalid */
|
||||
goto invalid_opc;
|
||||
|
Loading…
Reference in New Issue
Block a user