MIPS patches 2017-08-03

Changes:
 KVM T&E segment support for TCG
 malta: leave space for the bootmap after the initrd
 Apply CP0.PageMask before writing into TLB entry
 Fix fallout from indirect branch optimisation
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.5 (GNU/Linux)
 
 iQIVAwUAWYM0GyI464bV95fCAQLhcw/9EBGDoCKgDGtriMOs6XhJjiGyQi0WZ2js
 kVjcS0jbyyIXgjLAfH33Gbn5/23pJy1rTk9I+ERqqtMgwdnX2zLWax6cm2NM4+hI
 IGuP3rIK0W2ETHRpn8UPA4G89PVh6Q46QW3Cu4jEd699fDZHAQx+YMhEr1RT3m6V
 zWpzH2Myt2DrbglBRAbt20CFZl0z6+OUcYi1Cw7aZ7t7+3hV+ZxLqAa9Vo64VslS
 4bdTrFhpL1+AoxMilGWjNgeoeentsX8OZSl61pAq/vEgaoPT1S+ipmvdH5mAUwPp
 NOXM9A5OwLdWM1pTTLhcPPmdd9zeJbCtCoA1c6CXtULe1oX3MtT/TFvqAV8ALpar
 XffbDk90PyB3cMvFIBjSKmQGVEl580rS7db9G0LMfw9ZnxWKE0txf/qD40MMfG8O
 HQbuazVT8A40VjbF6hPS0rJliI+q+sKChp7ug27PSf22fnEYsPlctgiSYMA44uF8
 HzbgS0jqMNDaKCw+rehxVMQiR1J6sGOt/XLbSkG32l5Qjo6NoYoffC95AGp9R3nH
 DyW8nKrCZsrYXf/nsvAqgWo4ceEGu9xL5hKUfCLFGkgnBzGxyrAYlO0m043/YHbU
 LXJKeq5oN0mqRpZkDZan8P2irL2SaX+kDJeA07Z6xxuQDn+qC4fp2G8HXkNU3n/7
 iQ+XqMDECSE=
 =R2lj
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/yongbok/tags/mips-20170803' into staging

MIPS patches 2017-08-03

Changes:
KVM T&E segment support for TCG
malta: leave space for the bootmap after the initrd
Apply CP0.PageMask before writing into TLB entry
Fix fallout from indirect branch optimisation

# gpg: Signature made Thu 03 Aug 2017 15:32:59 BST
# gpg:                using RSA key 0x2238EB86D5F797C2
# gpg: Good signature from "Yongbok Kim <yongbok.kim@imgtec.com>"
# gpg: WARNING: This key is not certified with sufficiently trusted signatures!
# gpg:          It is not certain that the signature belongs to the owner.
# Primary key fingerprint: 8600 4CF5 3415 A5D9 4CFA  2B5C 2238 EB86 D5F7 97C2

* remotes/yongbok/tags/mips-20170803:
  target/mips: Fix RDHWR CC with icount
  target/mips: Drop redundant gen_io_start/stop()
  target/mips: Use BS_EXCP where interrupts are expected
  target-mips: apply CP0.PageMask before writing into TLB entry
  mips: Add KVM T&E segment support for TCG
  mips: Improve segment defs for KVM T&E guests
  mips/malta: leave space for the bootmap after the initrd
  target-mips: Don't stop on [d]mtc0 DESAVE/KScratch

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2017-08-04 13:03:58 +01:00
commit c233a35d3d
6 changed files with 90 additions and 57 deletions

View File

@ -24,6 +24,8 @@
#include "hw/hw.h" #include "hw/hw.h"
#include "hw/mips/cpudevs.h" #include "hw/mips/cpudevs.h"
static int mips_um_ksegs;
uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr) uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr)
{ {
return addr & 0x1fffffffll; return addr & 0x1fffffffll;
@ -38,3 +40,13 @@ uint64_t cpu_mips_kvm_um_phys_to_kseg0(void *opaque, uint64_t addr)
{ {
return addr | 0x40000000ll; return addr | 0x40000000ll;
} }
bool mips_um_ksegs_enabled(void)
{
return mips_um_ksegs;
}
void mips_um_ksegs_enable(void)
{
mips_um_ksegs = 1;
}

View File

@ -818,23 +818,20 @@ static int64_t load_kernel (void)
exit(1); exit(1);
} }
/* Sanity check where the kernel has been linked */ /* Check where the kernel has been linked */
if (kvm_enabled()) { if (kernel_entry & 0x80000000ll) {
if (kernel_entry & 0x80000000ll) { if (kvm_enabled()) {
error_report("KVM guest kernels must be linked in useg. " error_report("KVM guest kernels must be linked in useg. "
"Did you forget to enable CONFIG_KVM_GUEST?"); "Did you forget to enable CONFIG_KVM_GUEST?");
exit(1); exit(1);
} }
xlate_to_kseg0 = cpu_mips_kvm_um_phys_to_kseg0;
} else {
if (!(kernel_entry & 0x80000000ll)) {
error_report("KVM guest kernels aren't supported with TCG. "
"Did you unintentionally enable CONFIG_KVM_GUEST?");
exit(1);
}
xlate_to_kseg0 = cpu_mips_phys_to_kseg0; xlate_to_kseg0 = cpu_mips_phys_to_kseg0;
} else {
/* if kernel entry is in useg it is probably a KVM T&E kernel */
mips_um_ksegs_enable();
xlate_to_kseg0 = cpu_mips_kvm_um_phys_to_kseg0;
} }
/* load initrd */ /* load initrd */
@ -843,7 +840,10 @@ static int64_t load_kernel (void)
if (loaderparams.initrd_filename) { if (loaderparams.initrd_filename) {
initrd_size = get_image_size (loaderparams.initrd_filename); initrd_size = get_image_size (loaderparams.initrd_filename);
if (initrd_size > 0) { if (initrd_size > 0) {
initrd_offset = (loaderparams.ram_low_size - initrd_size /* The kernel allocates the bootmap memory in the low memory after
the initrd. It takes at most 128kiB for 2GB RAM and 4kiB
pages. */
initrd_offset = (loaderparams.ram_low_size - initrd_size - 131072
- ~INITRD_PAGE_MASK) & INITRD_PAGE_MASK; - ~INITRD_PAGE_MASK) & INITRD_PAGE_MASK;
if (kernel_high >= initrd_offset) { if (kernel_high >= initrd_offset) {
fprintf(stderr, fprintf(stderr,

View File

@ -5,11 +5,12 @@
/* Definitions for MIPS CPU internal devices. */ /* Definitions for MIPS CPU internal devices. */
/* mips_addr.c */ /* addr.c */
uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr); uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr);
uint64_t cpu_mips_phys_to_kseg0(void *opaque, uint64_t addr); uint64_t cpu_mips_phys_to_kseg0(void *opaque, uint64_t addr);
uint64_t cpu_mips_kvm_um_phys_to_kseg0(void *opaque, uint64_t addr); uint64_t cpu_mips_kvm_um_phys_to_kseg0(void *opaque, uint64_t addr);
bool mips_um_ksegs_enabled(void);
void mips_um_ksegs_enable(void);
/* mips_int.c */ /* mips_int.c */
void cpu_mips_irq_init_cpu(MIPSCPU *cpu); void cpu_mips_irq_init_cpu(MIPSCPU *cpu);

View File

@ -19,10 +19,10 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "cpu.h" #include "cpu.h"
#include "sysemu/kvm.h"
#include "exec/exec-all.h" #include "exec/exec-all.h"
#include "exec/cpu_ldst.h" #include "exec/cpu_ldst.h"
#include "exec/log.h" #include "exec/log.h"
#include "hw/mips/cpudevs.h"
enum { enum {
TLBRET_XI = -6, TLBRET_XI = -6,
@ -216,16 +216,16 @@ static int get_physical_address (CPUMIPSState *env, hwaddr *physical,
/* effective address (modified for KVM T&E kernel segments) */ /* effective address (modified for KVM T&E kernel segments) */
target_ulong address = real_address; target_ulong address = real_address;
#define USEG_LIMIT 0x7FFFFFFFUL #define USEG_LIMIT ((target_ulong)(int32_t)0x7FFFFFFFUL)
#define KSEG0_BASE 0x80000000UL #define KSEG0_BASE ((target_ulong)(int32_t)0x80000000UL)
#define KSEG1_BASE 0xA0000000UL #define KSEG1_BASE ((target_ulong)(int32_t)0xA0000000UL)
#define KSEG2_BASE 0xC0000000UL #define KSEG2_BASE ((target_ulong)(int32_t)0xC0000000UL)
#define KSEG3_BASE 0xE0000000UL #define KSEG3_BASE ((target_ulong)(int32_t)0xE0000000UL)
#define KVM_KSEG0_BASE 0x40000000UL #define KVM_KSEG0_BASE ((target_ulong)(int32_t)0x40000000UL)
#define KVM_KSEG2_BASE 0x60000000UL #define KVM_KSEG2_BASE ((target_ulong)(int32_t)0x60000000UL)
if (kvm_enabled()) { if (mips_um_ksegs_enabled()) {
/* KVM T&E adds guest kernel segments in useg */ /* KVM T&E adds guest kernel segments in useg */
if (real_address >= KVM_KSEG0_BASE) { if (real_address >= KVM_KSEG0_BASE) {
if (real_address < KVM_KSEG2_BASE) { if (real_address < KVM_KSEG2_BASE) {
@ -307,17 +307,17 @@ static int get_physical_address (CPUMIPSState *env, hwaddr *physical,
ret = TLBRET_BADADDR; ret = TLBRET_BADADDR;
} }
#endif #endif
} else if (address < (int32_t)KSEG1_BASE) { } else if (address < KSEG1_BASE) {
/* kseg0 */ /* kseg0 */
ret = get_segctl_physical_address(env, physical, prot, real_address, rw, ret = get_segctl_physical_address(env, physical, prot, real_address, rw,
access_type, mmu_idx, access_type, mmu_idx,
env->CP0_SegCtl1 >> 16, 0x1FFFFFFF); env->CP0_SegCtl1 >> 16, 0x1FFFFFFF);
} else if (address < (int32_t)KSEG2_BASE) { } else if (address < KSEG2_BASE) {
/* kseg1 */ /* kseg1 */
ret = get_segctl_physical_address(env, physical, prot, real_address, rw, ret = get_segctl_physical_address(env, physical, prot, real_address, rw,
access_type, mmu_idx, access_type, mmu_idx,
env->CP0_SegCtl1, 0x1FFFFFFF); env->CP0_SegCtl1, 0x1FFFFFFF);
} else if (address < (int32_t)KSEG3_BASE) { } else if (address < KSEG3_BASE) {
/* sseg (kseg2) */ /* sseg (kseg2) */
ret = get_segctl_physical_address(env, physical, prot, real_address, rw, ret = get_segctl_physical_address(env, physical, prot, real_address, rw,
access_type, mmu_idx, access_type, mmu_idx,
@ -974,8 +974,7 @@ void mips_cpu_do_interrupt(CPUState *cs)
} else if (cause == 30 && !(env->CP0_Config3 & (1 << CP0C3_SC) && } else if (cause == 30 && !(env->CP0_Config3 & (1 << CP0C3_SC) &&
env->CP0_Config5 & (1 << CP0C5_CV))) { env->CP0_Config5 & (1 << CP0C5_CV))) {
/* Force KSeg1 for cache errors */ /* Force KSeg1 for cache errors */
env->active_tc.PC = (int32_t)KSEG1_BASE | env->active_tc.PC = KSEG1_BASE | (env->CP0_EBase & 0x1FFFF000);
(env->CP0_EBase & 0x1FFFF000);
} else { } else {
env->active_tc.PC = env->CP0_EBase & ~0xfff; env->active_tc.PC = env->CP0_EBase & ~0xfff;
} }

View File

@ -2008,6 +2008,7 @@ static inline uint64_t get_tlb_pfn_from_entrylo(uint64_t entrylo)
static void r4k_fill_tlb(CPUMIPSState *env, int idx) static void r4k_fill_tlb(CPUMIPSState *env, int idx)
{ {
r4k_tlb_t *tlb; r4k_tlb_t *tlb;
uint64_t mask = env->CP0_PageMask >> (TARGET_PAGE_BITS + 1);
/* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
tlb = &env->tlb->mmu.r4k.tlb[idx]; tlb = &env->tlb->mmu.r4k.tlb[idx];
@ -2028,13 +2029,13 @@ static void r4k_fill_tlb(CPUMIPSState *env, int idx)
tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7; tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
tlb->XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) & 1; tlb->XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) & 1;
tlb->RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) & 1; tlb->RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) & 1;
tlb->PFN[0] = get_tlb_pfn_from_entrylo(env->CP0_EntryLo0) << 12; tlb->PFN[0] = (get_tlb_pfn_from_entrylo(env->CP0_EntryLo0) & ~mask) << 12;
tlb->V1 = (env->CP0_EntryLo1 & 2) != 0; tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
tlb->D1 = (env->CP0_EntryLo1 & 4) != 0; tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7; tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
tlb->XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) & 1; tlb->XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) & 1;
tlb->RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) & 1; tlb->RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) & 1;
tlb->PFN[1] = get_tlb_pfn_from_entrylo(env->CP0_EntryLo1) << 12; tlb->PFN[1] = (get_tlb_pfn_from_entrylo(env->CP0_EntryLo1) & ~mask) << 12;
} }
void r4k_helper_tlbinv(CPUMIPSState *env) void r4k_helper_tlbinv(CPUMIPSState *env)

View File

@ -27,10 +27,10 @@
#include "exec/exec-all.h" #include "exec/exec-all.h"
#include "tcg-op.h" #include "tcg-op.h"
#include "exec/cpu_ldst.h" #include "exec/cpu_ldst.h"
#include "hw/mips/cpudevs.h"
#include "exec/helper-proto.h" #include "exec/helper-proto.h"
#include "exec/helper-gen.h" #include "exec/helper-gen.h"
#include "sysemu/kvm.h"
#include "exec/semihost.h" #include "exec/semihost.h"
#include "target/mips/trace.h" #include "target/mips/trace.h"
@ -5334,8 +5334,10 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
gen_io_end(); gen_io_end();
} }
/* Break the TB to be able to take timer interrupts immediately /* Break the TB to be able to take timer interrupts immediately
after reading count. */ after reading count. BS_STOP isn't sufficient, we need to ensure
ctx->bstate = BS_STOP; we break completely out of translated code. */
gen_save_pc(ctx->pc + 4);
ctx->bstate = BS_EXCP;
rn = "Count"; rn = "Count";
break; break;
/* 6,7 are implementation dependent */ /* 6,7 are implementation dependent */
@ -6061,6 +6063,11 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
case 0: case 0:
save_cpu_state(ctx, 1); save_cpu_state(ctx, 1);
gen_helper_mtc0_cause(cpu_env, arg); gen_helper_mtc0_cause(cpu_env, arg);
/* Stop translation as we may have triggered an interrupt. BS_STOP
* isn't sufficient, we need to ensure we break out of translated
* code to check for pending interrupts. */
gen_save_pc(ctx->pc + 4);
ctx->bstate = BS_EXCP;
rn = "Cause"; rn = "Cause";
break; break;
default: default:
@ -6386,8 +6393,6 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
default: default:
goto cp0_unimplemented; goto cp0_unimplemented;
} }
/* Stop translation as we may have switched the execution mode */
ctx->bstate = BS_STOP;
break; break;
default: default:
goto cp0_unimplemented; goto cp0_unimplemented;
@ -6397,7 +6402,10 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
/* For simplicity assume that all writes can cause interrupts. */ /* For simplicity assume that all writes can cause interrupts. */
if (ctx->tb->cflags & CF_USE_ICOUNT) { if (ctx->tb->cflags & CF_USE_ICOUNT) {
gen_io_end(); gen_io_end();
ctx->bstate = BS_STOP; /* BS_STOP isn't sufficient, we need to ensure we break out of
* translated code to check for pending interrupts. */
gen_save_pc(ctx->pc + 4);
ctx->bstate = BS_EXCP;
} }
return; return;
@ -6678,8 +6686,10 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
gen_io_end(); gen_io_end();
} }
/* Break the TB to be able to take timer interrupts immediately /* Break the TB to be able to take timer interrupts immediately
after reading count. */ after reading count. BS_STOP isn't sufficient, we need to ensure
ctx->bstate = BS_STOP; we break completely out of translated code. */
gen_save_pc(ctx->pc + 4);
ctx->bstate = BS_EXCP;
rn = "Count"; rn = "Count";
break; break;
/* 6,7 are implementation dependent */ /* 6,7 are implementation dependent */
@ -7391,17 +7401,12 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
switch (sel) { switch (sel) {
case 0: case 0:
save_cpu_state(ctx, 1); save_cpu_state(ctx, 1);
/* Mark as an IO operation because we may trigger a software
interrupt. */
if (ctx->tb->cflags & CF_USE_ICOUNT) {
gen_io_start();
}
gen_helper_mtc0_cause(cpu_env, arg); gen_helper_mtc0_cause(cpu_env, arg);
if (ctx->tb->cflags & CF_USE_ICOUNT) { /* Stop translation as we may have triggered an intetrupt. BS_STOP
gen_io_end(); * isn't sufficient, we need to ensure we break out of translated
} * code to check for pending interrupts. */
/* Stop translation as we may have triggered an intetrupt */ gen_save_pc(ctx->pc + 4);
ctx->bstate = BS_STOP; ctx->bstate = BS_EXCP;
rn = "Cause"; rn = "Cause";
break; break;
default: default:
@ -7714,8 +7719,6 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
default: default:
goto cp0_unimplemented; goto cp0_unimplemented;
} }
/* Stop translation as we may have switched the execution mode */
ctx->bstate = BS_STOP;
break; break;
default: default:
goto cp0_unimplemented; goto cp0_unimplemented;
@ -7725,7 +7728,10 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
/* For simplicity assume that all writes can cause interrupts. */ /* For simplicity assume that all writes can cause interrupts. */
if (ctx->tb->cflags & CF_USE_ICOUNT) { if (ctx->tb->cflags & CF_USE_ICOUNT) {
gen_io_end(); gen_io_end();
ctx->bstate = BS_STOP; /* BS_STOP isn't sufficient, we need to ensure we break out of
* translated code to check for pending interrupts. */
gen_save_pc(ctx->pc + 4);
ctx->bstate = BS_EXCP;
} }
return; return;
@ -10749,8 +10755,19 @@ static void gen_rdhwr(DisasContext *ctx, int rt, int rd, int sel)
gen_store_gpr(t0, rt); gen_store_gpr(t0, rt);
break; break;
case 2: case 2:
if (ctx->tb->cflags & CF_USE_ICOUNT) {
gen_io_start();
}
gen_helper_rdhwr_cc(t0, cpu_env); gen_helper_rdhwr_cc(t0, cpu_env);
if (ctx->tb->cflags & CF_USE_ICOUNT) {
gen_io_end();
}
gen_store_gpr(t0, rt); gen_store_gpr(t0, rt);
/* Break the TB to be able to take timer interrupts immediately
after reading count. BS_STOP isn't sufficient, we need to ensure
we break completely out of translated code. */
gen_save_pc(ctx->pc + 4);
ctx->bstate = BS_EXCP;
break; break;
case 3: case 3:
gen_helper_rdhwr_ccres(t0, cpu_env); gen_helper_rdhwr_ccres(t0, cpu_env);
@ -13569,8 +13586,10 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs)
save_cpu_state(ctx, 1); save_cpu_state(ctx, 1);
gen_helper_ei(t0, cpu_env); gen_helper_ei(t0, cpu_env);
gen_store_gpr(t0, rs); gen_store_gpr(t0, rs);
/* Stop translation as we may have switched the execution mode */ /* BS_STOP isn't sufficient, we need to ensure we break out
ctx->bstate = BS_STOP; of translated code to check for pending interrupts. */
gen_save_pc(ctx->pc + 4);
ctx->bstate = BS_EXCP;
tcg_temp_free(t0); tcg_temp_free(t0);
} }
break; break;
@ -19692,9 +19711,10 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
save_cpu_state(ctx, 1); save_cpu_state(ctx, 1);
gen_helper_ei(t0, cpu_env); gen_helper_ei(t0, cpu_env);
gen_store_gpr(t0, rt); gen_store_gpr(t0, rt);
/* Stop translation as we may have switched /* BS_STOP isn't sufficient, we need to ensure we break out
the execution mode. */ of translated code to check for pending interrupts. */
ctx->bstate = BS_STOP; gen_save_pc(ctx->pc + 4);
ctx->bstate = BS_EXCP;
break; break;
default: /* Invalid */ default: /* Invalid */
MIPS_INVAL("mfmc0"); MIPS_INVAL("mfmc0");
@ -20639,7 +20659,7 @@ void cpu_state_reset(CPUMIPSState *env)
env->CP0_Wired = 0; env->CP0_Wired = 0;
env->CP0_GlobalNumber = (cs->cpu_index & 0xFF) << CP0GN_VPId; env->CP0_GlobalNumber = (cs->cpu_index & 0xFF) << CP0GN_VPId;
env->CP0_EBase = (cs->cpu_index & 0x3FF); env->CP0_EBase = (cs->cpu_index & 0x3FF);
if (kvm_enabled()) { if (mips_um_ksegs_enabled()) {
env->CP0_EBase |= 0x40000000; env->CP0_EBase |= 0x40000000;
} else { } else {
env->CP0_EBase |= (int32_t)0x80000000; env->CP0_EBase |= (int32_t)0x80000000;