Commit 6f27aba62e90b382d3d8e35e6d72046470c270a8
1 parent
952a328f
Sparc64 hypervisor mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3398 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
4 changed files
with
121 additions
and
48 deletions
target-sparc/cpu.h
| ... | ... | @@ -98,6 +98,8 @@ |
| 98 | 98 | #define PS_AG (1<<0) |
| 99 | 99 | |
| 100 | 100 | #define FPRS_FEF (1<<2) |
| 101 | + | |
| 102 | +#define HS_PRIV (1<<2) | |
| 101 | 103 | #endif |
| 102 | 104 | |
| 103 | 105 | /* Fcc */ |
| ... | ... | @@ -166,7 +168,11 @@ |
| 166 | 168 | |
| 167 | 169 | typedef struct sparc_def_t sparc_def_t; |
| 168 | 170 | |
| 171 | +#if !defined(TARGET_SPARC64) | |
| 169 | 172 | #define NB_MMU_MODES 2 |
| 173 | +#else | |
| 174 | +#define NB_MMU_MODES 3 | |
| 175 | +#endif | |
| 170 | 176 | |
| 171 | 177 | typedef struct CPUSPARCState { |
| 172 | 178 | target_ulong gregs[8]; /* general registers */ |
| ... | ... | @@ -323,12 +329,37 @@ void cpu_check_irqs(CPUSPARCState *env); |
| 323 | 329 | #define cpu_list sparc_cpu_list |
| 324 | 330 | |
| 325 | 331 | /* MMU modes definitions */ |
| 326 | -#define MMU_MODE0_SUFFIX _kernel | |
| 327 | -#define MMU_MODE1_SUFFIX _user | |
| 328 | -#define MMU_USER_IDX 1 | |
| 332 | +#define MMU_MODE0_SUFFIX _user | |
| 333 | +#define MMU_MODE1_SUFFIX _kernel | |
| 334 | +#ifdef TARGET_SPARC64 | |
| 335 | +#define MMU_MODE2_SUFFIX _hypv | |
| 336 | +#endif | |
| 337 | +#define MMU_USER_IDX 0 | |
| 329 | 338 | static inline int cpu_mmu_index (CPUState *env) |
| 330 | 339 | { |
| 331 | - return env->psrs == 0 ? 1 : 0; | |
| 340 | +#if defined(CONFIG_USER_ONLY) | |
| 341 | + return 0; | |
| 342 | +#elif !defined(TARGET_SPARC64) | |
| 343 | + return env->psrs; | |
| 344 | +#else | |
| 345 | + if (!env->psrs) | |
| 346 | + return 0; | |
| 347 | + else if ((env->hpstate & HS_PRIV) == 0) | |
| 348 | + return 1; | |
| 349 | + else | |
| 350 | + return 2; | |
| 351 | +#endif | |
| 352 | +} | |
| 353 | + | |
| 354 | +static inline int cpu_fpu_enabled(CPUState *env) | |
| 355 | +{ | |
| 356 | +#if defined(CONFIG_USER_ONLY) | |
| 357 | + return 1; | |
| 358 | +#elif !defined(TARGET_SPARC64) | |
| 359 | + return env->psref; | |
| 360 | +#else | |
| 361 | + return ((env->pstate & PS_PEF) != 0) && ((env->fprs & FPRS_FEF) != 0); | |
| 362 | +#endif | |
| 332 | 363 | } |
| 333 | 364 | |
| 334 | 365 | #include "cpu-all.h" | ... | ... |
target-sparc/op.c
| ... | ... | @@ -1023,6 +1023,11 @@ void OPPROTO op_sra(void) |
| 1023 | 1023 | |
| 1024 | 1024 | #define MEMSUFFIX _kernel |
| 1025 | 1025 | #include "op_mem.h" |
| 1026 | + | |
| 1027 | +#ifdef TARGET_SPARC64 | |
| 1028 | +#define MEMSUFFIX _hypv | |
| 1029 | +#include "op_mem.h" | |
| 1030 | +#endif | |
| 1026 | 1031 | #endif |
| 1027 | 1032 | |
| 1028 | 1033 | void OPPROTO op_ldfsr(void) | ... | ... |
target-sparc/op_helper.c
| ... | ... | @@ -789,7 +789,8 @@ void helper_ld_asi(int asi, int size, int sign) |
| 789 | 789 | { |
| 790 | 790 | uint64_t ret = 0; |
| 791 | 791 | |
| 792 | - if (asi < 0x80 && (env->pstate & PS_PRIV) == 0) | |
| 792 | + if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) | |
| 793 | + || (asi >= 0x30 && asi < 0x80) && !(env->hpstate & HS_PRIV)) | |
| 793 | 794 | raise_exception(TT_PRIV_ACT); |
| 794 | 795 | |
| 795 | 796 | switch (asi) { |
| ... | ... | @@ -800,20 +801,38 @@ void helper_ld_asi(int asi, int size, int sign) |
| 800 | 801 | case 0x88: // Primary LE |
| 801 | 802 | case 0x8a: // Primary no-fault LE |
| 802 | 803 | if ((asi & 0x80) && (env->pstate & PS_PRIV)) { |
| 803 | - switch(size) { | |
| 804 | - case 1: | |
| 805 | - ret = ldub_kernel(T0); | |
| 806 | - break; | |
| 807 | - case 2: | |
| 808 | - ret = lduw_kernel(T0 & ~1); | |
| 809 | - break; | |
| 810 | - case 4: | |
| 811 | - ret = ldl_kernel(T0 & ~3); | |
| 812 | - break; | |
| 813 | - default: | |
| 814 | - case 8: | |
| 815 | - ret = ldq_kernel(T0 & ~7); | |
| 816 | - break; | |
| 804 | + if (env->hpstate & HS_PRIV) { | |
| 805 | + switch(size) { | |
| 806 | + case 1: | |
| 807 | + ret = ldub_hypv(T0); | |
| 808 | + break; | |
| 809 | + case 2: | |
| 810 | + ret = lduw_hypv(T0 & ~1); | |
| 811 | + break; | |
| 812 | + case 4: | |
| 813 | + ret = ldl_hypv(T0 & ~3); | |
| 814 | + break; | |
| 815 | + default: | |
| 816 | + case 8: | |
| 817 | + ret = ldq_hypv(T0 & ~7); | |
| 818 | + break; | |
| 819 | + } | |
| 820 | + } else { | |
| 821 | + switch(size) { | |
| 822 | + case 1: | |
| 823 | + ret = ldub_kernel(T0); | |
| 824 | + break; | |
| 825 | + case 2: | |
| 826 | + ret = lduw_kernel(T0 & ~1); | |
| 827 | + break; | |
| 828 | + case 4: | |
| 829 | + ret = ldl_kernel(T0 & ~3); | |
| 830 | + break; | |
| 831 | + default: | |
| 832 | + case 8: | |
| 833 | + ret = ldq_kernel(T0 & ~7); | |
| 834 | + break; | |
| 835 | + } | |
| 817 | 836 | } |
| 818 | 837 | } else { |
| 819 | 838 | switch(size) { |
| ... | ... | @@ -987,7 +1006,8 @@ void helper_ld_asi(int asi, int size, int sign) |
| 987 | 1006 | |
| 988 | 1007 | void helper_st_asi(int asi, int size) |
| 989 | 1008 | { |
| 990 | - if (asi < 0x80 && (env->pstate & PS_PRIV) == 0) | |
| 1009 | + if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) | |
| 1010 | + || (asi >= 0x30 && asi < 0x80) && !(env->hpstate & HS_PRIV)) | |
| 991 | 1011 | raise_exception(TT_PRIV_ACT); |
| 992 | 1012 | |
| 993 | 1013 | /* Convert to little endian */ |
| ... | ... | @@ -1022,20 +1042,38 @@ void helper_st_asi(int asi, int size) |
| 1022 | 1042 | case 0x80: // Primary |
| 1023 | 1043 | case 0x88: // Primary LE |
| 1024 | 1044 | if ((asi & 0x80) && (env->pstate & PS_PRIV)) { |
| 1025 | - switch(size) { | |
| 1026 | - case 1: | |
| 1027 | - stb_kernel(T0, T1); | |
| 1028 | - break; | |
| 1029 | - case 2: | |
| 1030 | - stw_kernel(T0 & ~1, T1); | |
| 1031 | - break; | |
| 1032 | - case 4: | |
| 1033 | - stl_kernel(T0 & ~3, T1); | |
| 1034 | - break; | |
| 1035 | - case 8: | |
| 1036 | - default: | |
| 1037 | - stq_kernel(T0 & ~7, T1); | |
| 1038 | - break; | |
| 1045 | + if (env->hpstate & HS_PRIV) { | |
| 1046 | + switch(size) { | |
| 1047 | + case 1: | |
| 1048 | + stb_hypv(T0, T1); | |
| 1049 | + break; | |
| 1050 | + case 2: | |
| 1051 | + stw_hypv(T0 & ~1, T1); | |
| 1052 | + break; | |
| 1053 | + case 4: | |
| 1054 | + stl_hypv(T0 & ~3, T1); | |
| 1055 | + break; | |
| 1056 | + case 8: | |
| 1057 | + default: | |
| 1058 | + stq_hypv(T0 & ~7, T1); | |
| 1059 | + break; | |
| 1060 | + } | |
| 1061 | + } else { | |
| 1062 | + switch(size) { | |
| 1063 | + case 1: | |
| 1064 | + stb_kernel(T0, T1); | |
| 1065 | + break; | |
| 1066 | + case 2: | |
| 1067 | + stw_kernel(T0 & ~1, T1); | |
| 1068 | + break; | |
| 1069 | + case 4: | |
| 1070 | + stl_kernel(T0 & ~3, T1); | |
| 1071 | + break; | |
| 1072 | + case 8: | |
| 1073 | + default: | |
| 1074 | + stq_kernel(T0 & ~7, T1); | |
| 1075 | + break; | |
| 1076 | + } | |
| 1039 | 1077 | } |
| 1040 | 1078 | } else { |
| 1041 | 1079 | switch(size) { | ... | ... |
target-sparc/translate.c
| ... | ... | @@ -361,17 +361,24 @@ GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf); |
| 361 | 361 | #endif |
| 362 | 362 | #define gen_op_ldst(name) gen_op_##name##_raw() |
| 363 | 363 | #else |
| 364 | -#define supervisor(dc) (dc->mem_idx == 1) | |
| 364 | +#define supervisor(dc) (dc->mem_idx >= 1) | |
| 365 | 365 | #ifdef TARGET_SPARC64 |
| 366 | 366 | #define hypervisor(dc) (dc->mem_idx == 2) |
| 367 | -#endif | |
| 368 | -#define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])() | |
| 367 | +#define OP_LD_TABLE(width) \ | |
| 368 | + static GenOpFunc * const gen_op_##width[] = { \ | |
| 369 | + &gen_op_##width##_user, \ | |
| 370 | + &gen_op_##width##_kernel, \ | |
| 371 | + &gen_op_##width##_hypv, \ | |
| 372 | + }; | |
| 373 | +#else | |
| 369 | 374 | #define OP_LD_TABLE(width) \ |
| 370 | 375 | static GenOpFunc * const gen_op_##width[] = { \ |
| 371 | 376 | &gen_op_##width##_user, \ |
| 372 | 377 | &gen_op_##width##_kernel, \ |
| 373 | 378 | }; |
| 374 | 379 | #endif |
| 380 | +#define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])() | |
| 381 | +#endif | |
| 375 | 382 | |
| 376 | 383 | #ifndef CONFIG_USER_ONLY |
| 377 | 384 | OP_LD_TABLE(ld); |
| ... | ... | @@ -3378,17 +3385,8 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, |
| 3378 | 3385 | dc->pc = pc_start; |
| 3379 | 3386 | last_pc = dc->pc; |
| 3380 | 3387 | dc->npc = (target_ulong) tb->cs_base; |
| 3381 | -#if defined(CONFIG_USER_ONLY) | |
| 3382 | - dc->mem_idx = 0; | |
| 3383 | - dc->fpu_enabled = 1; | |
| 3384 | -#else | |
| 3385 | - dc->mem_idx = ((env->psrs) != 0); | |
| 3386 | -#ifdef TARGET_SPARC64 | |
| 3387 | - dc->fpu_enabled = (((env->pstate & PS_PEF) != 0) && ((env->fprs & FPRS_FEF) != 0)); | |
| 3388 | -#else | |
| 3389 | - dc->fpu_enabled = ((env->psref) != 0); | |
| 3390 | -#endif | |
| 3391 | -#endif | |
| 3388 | + dc->mem_idx = cpu_mmu_index(env); | |
| 3389 | + dc->fpu_enabled = cpu_fpu_enabled(env); | |
| 3392 | 3390 | gen_opc_ptr = gen_opc_buf; |
| 3393 | 3391 | gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; |
| 3394 | 3392 | gen_opparam_ptr = gen_opparam_buf; |
| ... | ... | @@ -3522,6 +3520,7 @@ void cpu_reset(CPUSPARCState *env) |
| 3522 | 3520 | env->psrps = 1; |
| 3523 | 3521 | #ifdef TARGET_SPARC64 |
| 3524 | 3522 | env->pstate = PS_PRIV; |
| 3523 | + env->hpstate = HS_PRIV; | |
| 3525 | 3524 | env->pc = 0x1fff0000000ULL; |
| 3526 | 3525 | #else |
| 3527 | 3526 | env->pc = 0; | ... | ... |