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,6 +98,8 @@ | ||
| 98 | #define PS_AG (1<<0) | 98 | #define PS_AG (1<<0) |
| 99 | 99 | ||
| 100 | #define FPRS_FEF (1<<2) | 100 | #define FPRS_FEF (1<<2) |
| 101 | + | ||
| 102 | +#define HS_PRIV (1<<2) | ||
| 101 | #endif | 103 | #endif |
| 102 | 104 | ||
| 103 | /* Fcc */ | 105 | /* Fcc */ |
| @@ -166,7 +168,11 @@ | @@ -166,7 +168,11 @@ | ||
| 166 | 168 | ||
| 167 | typedef struct sparc_def_t sparc_def_t; | 169 | typedef struct sparc_def_t sparc_def_t; |
| 168 | 170 | ||
| 171 | +#if !defined(TARGET_SPARC64) | ||
| 169 | #define NB_MMU_MODES 2 | 172 | #define NB_MMU_MODES 2 |
| 173 | +#else | ||
| 174 | +#define NB_MMU_MODES 3 | ||
| 175 | +#endif | ||
| 170 | 176 | ||
| 171 | typedef struct CPUSPARCState { | 177 | typedef struct CPUSPARCState { |
| 172 | target_ulong gregs[8]; /* general registers */ | 178 | target_ulong gregs[8]; /* general registers */ |
| @@ -323,12 +329,37 @@ void cpu_check_irqs(CPUSPARCState *env); | @@ -323,12 +329,37 @@ void cpu_check_irqs(CPUSPARCState *env); | ||
| 323 | #define cpu_list sparc_cpu_list | 329 | #define cpu_list sparc_cpu_list |
| 324 | 330 | ||
| 325 | /* MMU modes definitions */ | 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 | static inline int cpu_mmu_index (CPUState *env) | 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 | #include "cpu-all.h" | 365 | #include "cpu-all.h" |
target-sparc/op.c
| @@ -1023,6 +1023,11 @@ void OPPROTO op_sra(void) | @@ -1023,6 +1023,11 @@ void OPPROTO op_sra(void) | ||
| 1023 | 1023 | ||
| 1024 | #define MEMSUFFIX _kernel | 1024 | #define MEMSUFFIX _kernel |
| 1025 | #include "op_mem.h" | 1025 | #include "op_mem.h" |
| 1026 | + | ||
| 1027 | +#ifdef TARGET_SPARC64 | ||
| 1028 | +#define MEMSUFFIX _hypv | ||
| 1029 | +#include "op_mem.h" | ||
| 1030 | +#endif | ||
| 1026 | #endif | 1031 | #endif |
| 1027 | 1032 | ||
| 1028 | void OPPROTO op_ldfsr(void) | 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,7 +789,8 @@ void helper_ld_asi(int asi, int size, int sign) | ||
| 789 | { | 789 | { |
| 790 | uint64_t ret = 0; | 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 | raise_exception(TT_PRIV_ACT); | 794 | raise_exception(TT_PRIV_ACT); |
| 794 | 795 | ||
| 795 | switch (asi) { | 796 | switch (asi) { |
| @@ -800,20 +801,38 @@ void helper_ld_asi(int asi, int size, int sign) | @@ -800,20 +801,38 @@ void helper_ld_asi(int asi, int size, int sign) | ||
| 800 | case 0x88: // Primary LE | 801 | case 0x88: // Primary LE |
| 801 | case 0x8a: // Primary no-fault LE | 802 | case 0x8a: // Primary no-fault LE |
| 802 | if ((asi & 0x80) && (env->pstate & PS_PRIV)) { | 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 | } else { | 837 | } else { |
| 819 | switch(size) { | 838 | switch(size) { |
| @@ -987,7 +1006,8 @@ void helper_ld_asi(int asi, int size, int sign) | @@ -987,7 +1006,8 @@ void helper_ld_asi(int asi, int size, int sign) | ||
| 987 | 1006 | ||
| 988 | void helper_st_asi(int asi, int size) | 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 | raise_exception(TT_PRIV_ACT); | 1011 | raise_exception(TT_PRIV_ACT); |
| 992 | 1012 | ||
| 993 | /* Convert to little endian */ | 1013 | /* Convert to little endian */ |
| @@ -1022,20 +1042,38 @@ void helper_st_asi(int asi, int size) | @@ -1022,20 +1042,38 @@ void helper_st_asi(int asi, int size) | ||
| 1022 | case 0x80: // Primary | 1042 | case 0x80: // Primary |
| 1023 | case 0x88: // Primary LE | 1043 | case 0x88: // Primary LE |
| 1024 | if ((asi & 0x80) && (env->pstate & PS_PRIV)) { | 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 | } else { | 1078 | } else { |
| 1041 | switch(size) { | 1079 | switch(size) { |
target-sparc/translate.c
| @@ -361,17 +361,24 @@ GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf); | @@ -361,17 +361,24 @@ GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf); | ||
| 361 | #endif | 361 | #endif |
| 362 | #define gen_op_ldst(name) gen_op_##name##_raw() | 362 | #define gen_op_ldst(name) gen_op_##name##_raw() |
| 363 | #else | 363 | #else |
| 364 | -#define supervisor(dc) (dc->mem_idx == 1) | 364 | +#define supervisor(dc) (dc->mem_idx >= 1) |
| 365 | #ifdef TARGET_SPARC64 | 365 | #ifdef TARGET_SPARC64 |
| 366 | #define hypervisor(dc) (dc->mem_idx == 2) | 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 | #define OP_LD_TABLE(width) \ | 374 | #define OP_LD_TABLE(width) \ |
| 370 | static GenOpFunc * const gen_op_##width[] = { \ | 375 | static GenOpFunc * const gen_op_##width[] = { \ |
| 371 | &gen_op_##width##_user, \ | 376 | &gen_op_##width##_user, \ |
| 372 | &gen_op_##width##_kernel, \ | 377 | &gen_op_##width##_kernel, \ |
| 373 | }; | 378 | }; |
| 374 | #endif | 379 | #endif |
| 380 | +#define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])() | ||
| 381 | +#endif | ||
| 375 | 382 | ||
| 376 | #ifndef CONFIG_USER_ONLY | 383 | #ifndef CONFIG_USER_ONLY |
| 377 | OP_LD_TABLE(ld); | 384 | OP_LD_TABLE(ld); |
| @@ -3378,17 +3385,8 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | @@ -3378,17 +3385,8 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, | ||
| 3378 | dc->pc = pc_start; | 3385 | dc->pc = pc_start; |
| 3379 | last_pc = dc->pc; | 3386 | last_pc = dc->pc; |
| 3380 | dc->npc = (target_ulong) tb->cs_base; | 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 | gen_opc_ptr = gen_opc_buf; | 3390 | gen_opc_ptr = gen_opc_buf; |
| 3393 | gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; | 3391 | gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; |
| 3394 | gen_opparam_ptr = gen_opparam_buf; | 3392 | gen_opparam_ptr = gen_opparam_buf; |
| @@ -3522,6 +3520,7 @@ void cpu_reset(CPUSPARCState *env) | @@ -3522,6 +3520,7 @@ void cpu_reset(CPUSPARCState *env) | ||
| 3522 | env->psrps = 1; | 3520 | env->psrps = 1; |
| 3523 | #ifdef TARGET_SPARC64 | 3521 | #ifdef TARGET_SPARC64 |
| 3524 | env->pstate = PS_PRIV; | 3522 | env->pstate = PS_PRIV; |
| 3523 | + env->hpstate = HS_PRIV; | ||
| 3525 | env->pc = 0x1fff0000000ULL; | 3524 | env->pc = 0x1fff0000000ULL; |
| 3526 | #else | 3525 | #else |
| 3527 | env->pc = 0; | 3526 | env->pc = 0; |