2
* Alpha emulation - PALcode emulation for qemu.
4
* Copyright (c) 2007 Jocelyn Mayer
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2 of the License, or (at your option) any later version.
11
* This library is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General Public License for more details.
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with this library; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29
#if !defined (CONFIG_USER_ONLY)
31
static void pal_reset (CPUState *env);
32
/* Console handlers */
33
static void pal_console_call (CPUState *env, uint32_t palcode);
34
/* OpenVMS handlers */
35
static void pal_openvms_call (CPUState *env, uint32_t palcode);
36
/* UNIX / Linux handlers */
37
static void pal_unix_call (CPUState *env, uint32_t palcode);
39
pal_handler_t pal_handlers[] = {
43
.call_pal = &pal_console_call,
48
.call_pal = &pal_openvms_call,
50
/* UNIX / Linux handler */
53
.call_pal = &pal_unix_call,
58
/* One must explicitly check that the TB is valid and the FOE bit is reset */
59
static void update_itb (void)
61
/* This writes into a temp register, not the actual one */
64
/* This commits the TB update */
68
static void update_dtb (void);
71
/* This write into a temp register, not the actual one */
73
/* This commits the TB update */
78
static void pal_reset (CPUState *env)
82
static void do_swappal (CPUState *env, uint64_t palid)
84
pal_handler_t *pal_handler;
90
pal_handler = &pal_handlers[palid];
91
env->pal_handler = pal_handler;
92
env->ipr[IPR_PAL_BASE] = -1ULL;
93
(*pal_handler->reset)(env);
96
/* Unknown identifier */
100
/* We were given the entry point address */
101
env->pal_handler = NULL;
102
env->ipr[IPR_PAL_BASE] = palid;
103
env->pc = env->ipr[IPR_PAL_BASE];
108
static void pal_console_call (CPUState *env, uint32_t palcode)
112
if (palcode < 0x00000080) {
113
/* Privileged palcodes */
114
if (!(env->ps >> 3)) {
115
/* TODO: generate privilege exception */
129
/* Implemented as no-op */
139
do_swappal(env, palid);
152
/* Implemented as no-op */
171
static void pal_openvms_call (CPUState *env, uint32_t palcode)
173
uint64_t palid, val, oldval;
175
if (palcode < 0x00000080) {
176
/* Privileged palcodes */
177
if (!(env->ps >> 3)) {
178
/* TODO: generate privilege exception */
192
/* Implemented as no-op */
205
if (cpu_alpha_mfpr(env, IPR_ASN, &val) == 0)
211
if (cpu_alpha_mtpr(env, IPR_ASTEN, val, &oldval) == 1)
217
if (cpu_alpha_mtpr(env, IPR_ASTSR, val, &oldval) == 1)
228
do_swappal(env, palid);
232
if (cpu_alpha_mfpr(env, IPR_FEN, &val) == 0)
238
if (cpu_alpha_mtpr(env, IPR_FEN, val, &oldval) == 1)
244
if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1)
249
if (cpu_alpha_mfpr(env, IPR_IPL, &val) == 0)
255
if (cpu_alpha_mtpr(env, IPR_IPL, val, &oldval) == 1)
260
if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0)
266
if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1)
271
if (cpu_alpha_mfpr(env, IPR_PCBB, &val) == 0)
276
if (cpu_alpha_mfpr(env, IPR_PRBR, &val) == 0)
282
if (cpu_alpha_mtpr(env, IPR_PRBR, val, &oldval) == 1)
287
if (cpu_alpha_mfpr(env, IPR_PTBR, &val) == 0)
292
if (cpu_alpha_mfpr(env, IPR_SCBB, &val) == 0)
298
if (cpu_alpha_mtpr(env, IPR_SCBB, val, &oldval) == 1)
304
if (cpu_alpha_mtpr(env, IPR_SIRR, val, &oldval) == 1)
309
if (cpu_alpha_mfpr(env, IPR_SISR, &val) == 0)
314
if (cpu_alpha_mfpr(env, IPR_TBCHK, &val) == 0)
320
if (cpu_alpha_mtpr(env, IPR_TBIA, val, &oldval) == 1)
326
if (cpu_alpha_mtpr(env, IPR_TBIAP, val, &oldval) == 1)
332
if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1)
337
if (cpu_alpha_mfpr(env, IPR_ESP, &val) == 0)
343
if (cpu_alpha_mtpr(env, IPR_ESP, val, &oldval) == 1)
348
if (cpu_alpha_mfpr(env, IPR_SSP, &val) == 0)
354
if (cpu_alpha_mtpr(env, IPR_SSP, val, &oldval) == 1)
359
if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0)
365
if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1)
371
if (cpu_alpha_mtpr(env, IPR_TBISD, val, &oldval) == 1)
377
if (cpu_alpha_mtpr(env, IPR_TBISI, val, &oldval) == 1)
382
if (cpu_alpha_mfpr(env, IPR_ASTEN, &val) == 0)
387
if (cpu_alpha_mfpr(env, IPR_ASTSR, &val) == 0)
392
if (cpu_alpha_mfpr(env, IPR_VPTB, &val) == 0)
398
if (cpu_alpha_mtpr(env, IPR_VPTB, val, &oldval) == 1)
404
if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
410
if (cpu_alpha_mtpr(env, IPR_DATFX, val, &oldval) == 1)
418
if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
444
/* Implemented as no-op */
565
static void pal_unix_call (CPUState *env, uint32_t palcode)
567
uint64_t palid, val, oldval;
569
if (palcode < 0x00000080) {
570
/* Privileged palcodes */
571
if (!(env->ps >> 3)) {
572
/* TODO: generate privilege exception */
586
/* Implemented as no-op */
596
do_swappal(env, palid);
601
if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1)
606
if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0)
612
if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1)
618
if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
636
if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1)
654
if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1)
660
if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
665
if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0)
670
if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
681
if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
698
/* Implemented as no-op */
723
void call_pal (CPUState *env)
725
pal_handler_t *pal_handler = env->pal_handler;
727
switch (env->exception_index) {
729
(*pal_handler->reset)(env);
732
(*pal_handler->machine_check)(env);
735
(*pal_handler->arithmetic)(env);
738
(*pal_handler->interrupt)(env);
741
(*pal_handler->dfault)(env);
743
case EXCP_DTB_MISS_PAL:
744
(*pal_handler->dtb_miss_pal)(env);
746
case EXCP_DTB_MISS_NATIVE:
747
(*pal_handler->dtb_miss_native)(env);
750
(*pal_handler->unalign)(env);
753
(*pal_handler->itb_miss)(env);
756
(*pal_handler->itb_acv)(env);
759
(*pal_handler->opcdec)(env);
762
(*pal_handler->fen)(env);
765
if (env->exception_index >= EXCP_CALL_PAL &&
766
env->exception_index < EXCP_CALL_PALP) {
767
/* Unprivileged PAL call */
768
(*pal_handler->call_pal)
769
(env, (env->exception_index - EXCP_CALL_PAL) >> 6);
770
} else if (env->exception_index >= EXCP_CALL_PALP &&
771
env->exception_index < EXCP_CALL_PALE) {
772
/* Privileged PAL call */
773
(*pal_handler->call_pal)
774
(env, ((env->exception_index - EXCP_CALL_PALP) >> 6) + 0x80);
776
/* Should never happen */
780
env->ipr[IPR_EXC_ADDR] &= ~1;
783
void pal_init (CPUState *env)
789
static uint64_t get_ptebase (CPUState *env, uint64_t vaddr)
791
uint64_t virbnd, ptbr;
793
if ((env->features & FEATURE_VIRBND)) {
794
cpu_alpha_mfpr(env, IPR_VIRBND, &virbnd);
796
cpu_alpha_mfpr(env, IPR_SYSPTBR, &ptbr);
798
cpu_alpha_mfpr(env, IPR_PTBR, &ptbr);
800
cpu_alpha_mfpr(env, IPR_PTBR, &ptbr);
806
static int get_page_bits (CPUState *env)
812
static int get_pte (uint64_t *pfnp, int *zbitsp, int *protp,
813
uint64_t ptebase, int page_bits, uint64_t level,
816
uint64_t pteaddr, pte, pfn;
818
int ure, uwe, kre, kwe, foE, foR, foW, v, ret, ar, is_user;
821
is_user = mmu_idx == MMU_USER_IDX;
822
pteaddr = (ptebase << page_bits) + (8 * level);
823
pte = ldq_raw(pteaddr);
824
/* Decode all interresting PTE fields */
826
uwe = (pte >> 13) & 1;
827
kwe = (pte >> 12) & 1;
828
ure = (pte >> 9) & 1;
829
kre = (pte >> 8) & 1;
831
foE = (pte >> 3) & 1;
832
foW = (pte >> 2) & 1;
833
foR = (pte >> 1) & 1;
838
/* Check access rights */
867
*zbitsp = page_bits + (3 * gh);
874
static int paddr_from_pte (uint64_t *paddr, int *zbitsp, int *prot,
875
uint64_t ptebase, int page_bits,
876
uint64_t vaddr, int mmu_idx, int rw)
878
uint64_t pfn, page_mask, lvl_mask, level1, level2, level3;
881
page_mask = (1ULL << page_bits) - 1ULL;
882
lvl_bits = page_bits - 3;
883
lvl_mask = (1ULL << lvl_bits) - 1ULL;
884
level3 = (vaddr >> page_bits) & lvl_mask;
885
level2 = (vaddr >> (page_bits + lvl_bits)) & lvl_mask;
886
level1 = (vaddr >> (page_bits + (2 * lvl_bits))) & lvl_mask;
888
ret = get_pte(&pfn, NULL, NULL, ptebase, page_bits, level1, 0, 0);
891
/* Access violation */
894
/* translation not valid */
901
ret = get_pte(&pfn, NULL, NULL, pfn, page_bits, level2, 0, 0);
904
/* Access violation */
907
/* translation not valid */
914
ret = get_pte(&pfn, zbitsp, prot, pfn, page_bits, level3, mmu_idx, rw);
916
/* Translation not valid */
918
} else if (ret & 2) {
919
/* Access violation */
932
/* Fault on execute */
941
*paddr = (pfn << page_bits) | (vaddr & page_mask);
946
static int virtual_to_physical (CPUState *env, uint64_t *physp,
947
int *zbitsp, int *protp,
948
uint64_t virtual, int mmu_idx, int rw)
950
uint64_t sva, ptebase;
951
int seg, page_bits, ret;
953
sva = ((int64_t)(virtual << (64 - VA_BITS))) >> (64 - VA_BITS);
957
seg = sva >> (VA_BITS - 2);
958
virtual &= ~(0xFFFFFC0000000000ULL << (VA_BITS - 43));
959
ptebase = get_ptebase(env, virtual);
960
page_bits = get_page_bits(env);
964
/* seg1: 3 levels of PTE */
965
ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
966
virtual, mmu_idx, rw);
969
/* seg1: 2 levels of PTE */
970
ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
971
virtual, mmu_idx, rw);
982
/* seg1: TB mapped */
983
ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
984
virtual, mmu_idx, rw);
994
/* XXX: code provision */
995
int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
996
int mmu_idx, int is_softmmu)
998
uint64_t physical, page_size, end;
999
int prot, zbits, ret;
1001
if (env->user_mode_only) {
1004
ret = virtual_to_physical(env, &physical, &zbits, &prot,
1005
address, mmu_idx, rw);
1010
page_size = 1ULL << zbits;
1011
address &= ~(page_size - 1);
1012
for (end = physical + page_size; physical < end; physical += 0x1000) {
1013
ret = tlb_set_page(env, address, physical, prot,
1014
mmu_idx, is_softmmu);
1020
env->exception_index = EXCP_DFAULT;
1021
env->ipr[IPR_EXC_ADDR] = address;
1025
env->exception_index = EXCP_ACCESS_VIOLATION;
1026
env->ipr[IPR_EXC_ADDR] = address;
1030
env->exception_index = EXCP_FAULT_ON_READ;
1031
env->ipr[IPR_EXC_ADDR] = address;
1035
env->exception_index = EXCP_FAULT_ON_EXECUTE;
1036
env->ipr[IPR_EXC_ADDR] = address;
1039
env->exception_index = EXCP_FAULT_ON_WRITE;
1040
env->ipr[IPR_EXC_ADDR] = address;
1044
/* Should never happen */
1045
env->exception_index = EXCP_MCHK;
1046
env->ipr[IPR_EXC_ADDR] = address;
1055
#else /* !defined (CONFIG_USER_ONLY) */
1056
void pal_init (CPUState *env)
1060
void call_pal (CPUState *env, int palcode)
1064
printf("%s: palcode %02x\n", __func__, palcode);
1065
if (logfile != NULL)
1066
fprintf(logfile, "%s: palcode %02x\n", __func__, palcode);
1070
printf("CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]);
1071
if (logfile != NULL)
1072
fprintf(logfile, "CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]);
1073
ret = do_syscall(env, env->ir[IR_V0], env->ir[IR_A0], env->ir[IR_A1],
1074
env->ir[IR_A2], env->ir[IR_A3], env->ir[IR_A4],
1076
env->ir[IR_A3] = ret;
1077
if (ret > (target_ulong)(-515)) {
1085
env->ir[IR_V0] = env->unique;
1086
printf("RDUNIQUE: " TARGET_FMT_lx "\n", env->unique);
1090
env->unique = env->ir[IR_A0];
1091
printf("WRUNIQUE: " TARGET_FMT_lx "\n", env->unique);
1094
printf("%s: unhandled palcode %02x\n", __func__, palcode);
1095
if (logfile != NULL)
1096
fprintf(logfile, "%s: unhandled palcode %02x\n",