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/mips/cpudevs.h"
static int mips_um_ksegs;
uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr)
{
return addr & 0x1fffffffll;
@ -38,3 +40,13 @@ uint64_t cpu_mips_kvm_um_phys_to_kseg0(void *opaque, uint64_t addr)
{
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);
}
/* Sanity check where the kernel has been linked */
if (kvm_enabled()) {
if (kernel_entry & 0x80000000ll) {
/* Check where the kernel has been linked */
if (kernel_entry & 0x80000000ll) {
if (kvm_enabled()) {
error_report("KVM guest kernels must be linked in useg. "
"Did you forget to enable CONFIG_KVM_GUEST?");
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;
} 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 */
@ -843,7 +840,10 @@ static int64_t load_kernel (void)
if (loaderparams.initrd_filename) {
initrd_size = get_image_size (loaderparams.initrd_filename);
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;
if (kernel_high >= initrd_offset) {
fprintf(stderr,

View file

@ -5,11 +5,12 @@
/* 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_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 */
void cpu_mips_irq_init_cpu(MIPSCPU *cpu);

View file

@ -19,10 +19,10 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "sysemu/kvm.h"
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
#include "exec/log.h"
#include "hw/mips/cpudevs.h"
enum {
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) */
target_ulong address = real_address;
#define USEG_LIMIT 0x7FFFFFFFUL
#define KSEG0_BASE 0x80000000UL
#define KSEG1_BASE 0xA0000000UL
#define KSEG2_BASE 0xC0000000UL
#define KSEG3_BASE 0xE0000000UL
#define USEG_LIMIT ((target_ulong)(int32_t)0x7FFFFFFFUL)
#define KSEG0_BASE ((target_ulong)(int32_t)0x80000000UL)
#define KSEG1_BASE ((target_ulong)(int32_t)0xA0000000UL)
#define KSEG2_BASE ((target_ulong)(int32_t)0xC0000000UL)
#define KSEG3_BASE ((target_ulong)(int32_t)0xE0000000UL)
#define KVM_KSEG0_BASE 0x40000000UL
#define KVM_KSEG2_BASE 0x60000000UL
#define KVM_KSEG0_BASE ((target_ulong)(int32_t)0x40000000UL)
#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 */
if (real_address >= KVM_KSEG0_BASE) {
if (real_address < KVM_KSEG2_BASE) {
@ -307,17 +307,17 @@ static int get_physical_address (CPUMIPSState *env, hwaddr *physical,
ret = TLBRET_BADADDR;
}
#endif
} else if (address < (int32_t)KSEG1_BASE) {
} else if (address < KSEG1_BASE) {
/* kseg0 */
ret = get_segctl_physical_address(env, physical, prot, real_address, rw,
access_type, mmu_idx,
env->CP0_SegCtl1 >> 16, 0x1FFFFFFF);
} else if (address < (int32_t)KSEG2_BASE) {
} else if (address < KSEG2_BASE) {
/* kseg1 */
ret = get_segctl_physical_address(env, physical, prot, real_address, rw,
access_type, mmu_idx,
env->CP0_SegCtl1, 0x1FFFFFFF);
} else if (address < (int32_t)KSEG3_BASE) {
} else if (address < KSEG3_BASE) {
/* sseg (kseg2) */
ret = get_segctl_physical_address(env, physical, prot, real_address, rw,
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) &&
env->CP0_Config5 & (1 << CP0C5_CV))) {
/* Force KSeg1 for cache errors */
env->active_tc.PC = (int32_t)KSEG1_BASE |
(env->CP0_EBase & 0x1FFFF000);
env->active_tc.PC = KSEG1_BASE | (env->CP0_EBase & 0x1FFFF000);
} else {
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)
{
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 */
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->XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) & 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->D1 = (env->CP0_EntryLo1 & 4) != 0;
tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
tlb->XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) & 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)

View file

@ -27,10 +27,10 @@
#include "exec/exec-all.h"
#include "tcg-op.h"
#include "exec/cpu_ldst.h"
#include "hw/mips/cpudevs.h"
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
#include "sysemu/kvm.h"
#include "exec/semihost.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();
}
/* Break the TB to be able to take timer interrupts immediately
after reading count. */
ctx->bstate = BS_STOP;
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;
rn = "Count";
break;
/* 6,7 are implementation dependent */
@ -6061,6 +6063,11 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
case 0:
save_cpu_state(ctx, 1);
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";
break;
default:
@ -6386,8 +6393,6 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
default:
goto cp0_unimplemented;
}
/* Stop translation as we may have switched the execution mode */
ctx->bstate = BS_STOP;
break;
default:
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. */
if (ctx->tb->cflags & CF_USE_ICOUNT) {
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;
@ -6678,8 +6686,10 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
gen_io_end();
}
/* Break the TB to be able to take timer interrupts immediately
after reading count. */
ctx->bstate = BS_STOP;
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;
rn = "Count";
break;
/* 6,7 are implementation dependent */
@ -7391,17 +7401,12 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
switch (sel) {
case 0:
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);
if (ctx->tb->cflags & CF_USE_ICOUNT) {
gen_io_end();
}
/* Stop translation as we may have triggered an intetrupt */
ctx->bstate = BS_STOP;
/* Stop translation as we may have triggered an intetrupt. 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";
break;
default:
@ -7714,8 +7719,6 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
default:
goto cp0_unimplemented;
}
/* Stop translation as we may have switched the execution mode */
ctx->bstate = BS_STOP;
break;
default:
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. */
if (ctx->tb->cflags & CF_USE_ICOUNT) {
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;
@ -10749,8 +10755,19 @@ static void gen_rdhwr(DisasContext *ctx, int rt, int rd, int sel)
gen_store_gpr(t0, rt);
break;
case 2:
if (ctx->tb->cflags & CF_USE_ICOUNT) {
gen_io_start();
}
gen_helper_rdhwr_cc(t0, cpu_env);
if (ctx->tb->cflags & CF_USE_ICOUNT) {
gen_io_end();
}
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;
case 3:
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);
gen_helper_ei(t0, cpu_env);
gen_store_gpr(t0, rs);
/* Stop translation as we may have switched the execution mode */
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;
tcg_temp_free(t0);
}
break;
@ -19692,9 +19711,10 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
save_cpu_state(ctx, 1);
gen_helper_ei(t0, cpu_env);
gen_store_gpr(t0, rt);
/* Stop translation as we may have switched
the execution mode. */
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;
break;
default: /* Invalid */
MIPS_INVAL("mfmc0");
@ -20639,7 +20659,7 @@ void cpu_state_reset(CPUMIPSState *env)
env->CP0_Wired = 0;
env->CP0_GlobalNumber = (cs->cpu_index & 0xFF) << CP0GN_VPId;
env->CP0_EBase = (cs->cpu_index & 0x3FF);
if (kvm_enabled()) {
if (mips_um_ksegs_enabled()) {
env->CP0_EBase |= 0x40000000;
} else {
env->CP0_EBase |= (int32_t)0x80000000;