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, see <http://www.gnu.org/licenses/>.
28 #if !defined (CONFIG_USER_ONLY)
30 static void pal_reset (CPUState
*env
);
31 /* Console handlers */
32 static void pal_console_call (CPUState
*env
, uint32_t palcode
);
33 /* OpenVMS handlers */
34 static void pal_openvms_call (CPUState
*env
, uint32_t palcode
);
35 /* UNIX / Linux handlers */
36 static void pal_unix_call (CPUState
*env
, uint32_t palcode
);
38 pal_handler_t pal_handlers
[] = {
42 .call_pal
= &pal_console_call
,
47 .call_pal
= &pal_openvms_call
,
49 /* UNIX / Linux handler */
52 .call_pal
= &pal_unix_call
,
57 /* One must explicitly check that the TB is valid and the FOE bit is reset */
58 static void update_itb (void)
60 /* This writes into a temp register, not the actual one */
63 /* This commits the TB update */
67 static void update_dtb (void);
70 /* This write into a temp register, not the actual one */
72 /* This commits the TB update */
77 static void pal_reset (CPUState
*env
)
81 static void do_swappal (CPUState
*env
, uint64_t palid
)
83 pal_handler_t
*pal_handler
;
89 pal_handler
= &pal_handlers
[palid
];
90 env
->pal_handler
= pal_handler
;
91 env
->ipr
[IPR_PAL_BASE
] = -1ULL;
92 (*pal_handler
->reset
)(env
);
95 /* Unknown identifier */
99 /* We were given the entry point address */
100 env
->pal_handler
= NULL
;
101 env
->ipr
[IPR_PAL_BASE
] = palid
;
102 env
->pc
= env
->ipr
[IPR_PAL_BASE
];
107 static void pal_console_call (CPUState
*env
, uint32_t palcode
)
111 if (palcode
< 0x00000080) {
112 /* Privileged palcodes */
113 if (!(env
->ps
>> 3)) {
114 /* TODO: generate privilege exception */
128 /* Implemented as no-op */
138 do_swappal(env
, palid
);
151 /* Implemented as no-op */
170 static void pal_openvms_call (CPUState
*env
, uint32_t palcode
)
172 uint64_t palid
, val
, oldval
;
174 if (palcode
< 0x00000080) {
175 /* Privileged palcodes */
176 if (!(env
->ps
>> 3)) {
177 /* TODO: generate privilege exception */
191 /* Implemented as no-op */
204 if (cpu_alpha_mfpr(env
, IPR_ASN
, &val
) == 0)
210 if (cpu_alpha_mtpr(env
, IPR_ASTEN
, val
, &oldval
) == 1)
216 if (cpu_alpha_mtpr(env
, IPR_ASTSR
, val
, &oldval
) == 1)
227 do_swappal(env
, palid
);
231 if (cpu_alpha_mfpr(env
, IPR_FEN
, &val
) == 0)
237 if (cpu_alpha_mtpr(env
, IPR_FEN
, val
, &oldval
) == 1)
243 if (cpu_alpha_mtpr(env
, IPR_IPIR
, val
, &oldval
) == 1)
248 if (cpu_alpha_mfpr(env
, IPR_IPL
, &val
) == 0)
254 if (cpu_alpha_mtpr(env
, IPR_IPL
, val
, &oldval
) == 1)
259 if (cpu_alpha_mfpr(env
, IPR_MCES
, &val
) == 0)
265 if (cpu_alpha_mtpr(env
, IPR_MCES
, val
, &oldval
) == 1)
270 if (cpu_alpha_mfpr(env
, IPR_PCBB
, &val
) == 0)
275 if (cpu_alpha_mfpr(env
, IPR_PRBR
, &val
) == 0)
281 if (cpu_alpha_mtpr(env
, IPR_PRBR
, val
, &oldval
) == 1)
286 if (cpu_alpha_mfpr(env
, IPR_PTBR
, &val
) == 0)
291 if (cpu_alpha_mfpr(env
, IPR_SCBB
, &val
) == 0)
297 if (cpu_alpha_mtpr(env
, IPR_SCBB
, val
, &oldval
) == 1)
303 if (cpu_alpha_mtpr(env
, IPR_SIRR
, val
, &oldval
) == 1)
308 if (cpu_alpha_mfpr(env
, IPR_SISR
, &val
) == 0)
313 if (cpu_alpha_mfpr(env
, IPR_TBCHK
, &val
) == 0)
319 if (cpu_alpha_mtpr(env
, IPR_TBIA
, val
, &oldval
) == 1)
325 if (cpu_alpha_mtpr(env
, IPR_TBIAP
, val
, &oldval
) == 1)
331 if (cpu_alpha_mtpr(env
, IPR_TBIS
, val
, &oldval
) == 1)
336 if (cpu_alpha_mfpr(env
, IPR_ESP
, &val
) == 0)
342 if (cpu_alpha_mtpr(env
, IPR_ESP
, val
, &oldval
) == 1)
347 if (cpu_alpha_mfpr(env
, IPR_SSP
, &val
) == 0)
353 if (cpu_alpha_mtpr(env
, IPR_SSP
, val
, &oldval
) == 1)
358 if (cpu_alpha_mfpr(env
, IPR_USP
, &val
) == 0)
364 if (cpu_alpha_mtpr(env
, IPR_USP
, val
, &oldval
) == 1)
370 if (cpu_alpha_mtpr(env
, IPR_TBISD
, val
, &oldval
) == 1)
376 if (cpu_alpha_mtpr(env
, IPR_TBISI
, val
, &oldval
) == 1)
381 if (cpu_alpha_mfpr(env
, IPR_ASTEN
, &val
) == 0)
386 if (cpu_alpha_mfpr(env
, IPR_ASTSR
, &val
) == 0)
391 if (cpu_alpha_mfpr(env
, IPR_VPTB
, &val
) == 0)
397 if (cpu_alpha_mtpr(env
, IPR_VPTB
, val
, &oldval
) == 1)
403 if (cpu_alpha_mtpr(env
, IPR_PERFMON
, val
, &oldval
) == 1)
409 if (cpu_alpha_mtpr(env
, IPR_DATFX
, val
, &oldval
) == 1)
417 if (cpu_alpha_mfpr(env
, IPR_WHAMI
, &val
) == 0)
443 /* Implemented as no-op */
564 static void pal_unix_call (CPUState
*env
, uint32_t palcode
)
566 uint64_t palid
, val
, oldval
;
568 if (palcode
< 0x00000080) {
569 /* Privileged palcodes */
570 if (!(env
->ps
>> 3)) {
571 /* TODO: generate privilege exception */
585 /* Implemented as no-op */
595 do_swappal(env
, palid
);
600 if (cpu_alpha_mtpr(env
, IPR_IPIR
, val
, &oldval
) == 1)
605 if (cpu_alpha_mfpr(env
, IPR_MCES
, &val
) == 0)
611 if (cpu_alpha_mtpr(env
, IPR_MCES
, val
, &oldval
) == 1)
617 if (cpu_alpha_mtpr(env
, IPR_PERFMON
, val
, &oldval
) == 1)
635 if (cpu_alpha_mtpr(env
, IPR_TBIS
, val
, &oldval
) == 1)
653 if (cpu_alpha_mtpr(env
, IPR_USP
, val
, &oldval
) == 1)
659 if (cpu_alpha_mtpr(env
, IPR_PERFMON
, val
, &oldval
) == 1)
664 if (cpu_alpha_mfpr(env
, IPR_USP
, &val
) == 0)
669 if (cpu_alpha_mfpr(env
, IPR_WHAMI
, &val
) == 0)
680 if (cpu_alpha_mfpr(env
, IPR_WHAMI
, &val
) == 0)
697 /* Implemented as no-op */
722 void call_pal (CPUState
*env
)
724 pal_handler_t
*pal_handler
= env
->pal_handler
;
726 switch (env
->exception_index
) {
728 (*pal_handler
->reset
)(env
);
731 (*pal_handler
->machine_check
)(env
);
734 (*pal_handler
->arithmetic
)(env
);
737 (*pal_handler
->interrupt
)(env
);
740 (*pal_handler
->dfault
)(env
);
742 case EXCP_DTB_MISS_PAL
:
743 (*pal_handler
->dtb_miss_pal
)(env
);
745 case EXCP_DTB_MISS_NATIVE
:
746 (*pal_handler
->dtb_miss_native
)(env
);
749 (*pal_handler
->unalign
)(env
);
752 (*pal_handler
->itb_miss
)(env
);
755 (*pal_handler
->itb_acv
)(env
);
758 (*pal_handler
->opcdec
)(env
);
761 (*pal_handler
->fen
)(env
);
764 if (env
->exception_index
>= EXCP_CALL_PAL
&&
765 env
->exception_index
< EXCP_CALL_PALP
) {
766 /* Unprivileged PAL call */
767 (*pal_handler
->call_pal
)
768 (env
, (env
->exception_index
- EXCP_CALL_PAL
) >> 6);
769 } else if (env
->exception_index
>= EXCP_CALL_PALP
&&
770 env
->exception_index
< EXCP_CALL_PALE
) {
771 /* Privileged PAL call */
772 (*pal_handler
->call_pal
)
773 (env
, ((env
->exception_index
- EXCP_CALL_PALP
) >> 6) + 0x80);
775 /* Should never happen */
779 env
->ipr
[IPR_EXC_ADDR
] &= ~1;
782 void pal_init (CPUState
*env
)
788 static uint64_t get_ptebase (CPUState
*env
, uint64_t vaddr
)
790 uint64_t virbnd
, ptbr
;
792 if ((env
->features
& FEATURE_VIRBND
)) {
793 cpu_alpha_mfpr(env
, IPR_VIRBND
, &virbnd
);
795 cpu_alpha_mfpr(env
, IPR_SYSPTBR
, &ptbr
);
797 cpu_alpha_mfpr(env
, IPR_PTBR
, &ptbr
);
799 cpu_alpha_mfpr(env
, IPR_PTBR
, &ptbr
);
805 static int get_page_bits (CPUState
*env
)
811 static int get_pte (uint64_t *pfnp
, int *zbitsp
, int *protp
,
812 uint64_t ptebase
, int page_bits
, uint64_t level
,
815 uint64_t pteaddr
, pte
, pfn
;
817 int ure
, uwe
, kre
, kwe
, foE
, foR
, foW
, v
, ret
, ar
, is_user
;
820 is_user
= mmu_idx
== MMU_USER_IDX
;
821 pteaddr
= (ptebase
<< page_bits
) + (8 * level
);
822 pte
= ldq_raw(pteaddr
);
823 /* Decode all interresting PTE fields */
825 uwe
= (pte
>> 13) & 1;
826 kwe
= (pte
>> 12) & 1;
827 ure
= (pte
>> 9) & 1;
828 kre
= (pte
>> 8) & 1;
830 foE
= (pte
>> 3) & 1;
831 foW
= (pte
>> 2) & 1;
832 foR
= (pte
>> 1) & 1;
837 /* Check access rights */
866 *zbitsp
= page_bits
+ (3 * gh
);
873 static int paddr_from_pte (uint64_t *paddr
, int *zbitsp
, int *prot
,
874 uint64_t ptebase
, int page_bits
,
875 uint64_t vaddr
, int mmu_idx
, int rw
)
877 uint64_t pfn
, page_mask
, lvl_mask
, level1
, level2
, level3
;
880 page_mask
= (1ULL << page_bits
) - 1ULL;
881 lvl_bits
= page_bits
- 3;
882 lvl_mask
= (1ULL << lvl_bits
) - 1ULL;
883 level3
= (vaddr
>> page_bits
) & lvl_mask
;
884 level2
= (vaddr
>> (page_bits
+ lvl_bits
)) & lvl_mask
;
885 level1
= (vaddr
>> (page_bits
+ (2 * lvl_bits
))) & lvl_mask
;
887 ret
= get_pte(&pfn
, NULL
, NULL
, ptebase
, page_bits
, level1
, 0, 0);
890 /* Access violation */
893 /* translation not valid */
900 ret
= get_pte(&pfn
, NULL
, NULL
, pfn
, page_bits
, level2
, 0, 0);
903 /* Access violation */
906 /* translation not valid */
913 ret
= get_pte(&pfn
, zbitsp
, prot
, pfn
, page_bits
, level3
, mmu_idx
, rw
);
915 /* Translation not valid */
917 } else if (ret
& 2) {
918 /* Access violation */
931 /* Fault on execute */
940 *paddr
= (pfn
<< page_bits
) | (vaddr
& page_mask
);
945 static int virtual_to_physical (CPUState
*env
, uint64_t *physp
,
946 int *zbitsp
, int *protp
,
947 uint64_t virtual, int mmu_idx
, int rw
)
949 uint64_t sva
, ptebase
;
950 int seg
, page_bits
, ret
;
952 sva
= ((int64_t)(virtual << (64 - VA_BITS
))) >> (64 - VA_BITS
);
956 seg
= sva
>> (VA_BITS
- 2);
957 virtual &= ~(0xFFFFFC0000000000ULL
<< (VA_BITS
- 43));
958 ptebase
= get_ptebase(env
, virtual);
959 page_bits
= get_page_bits(env
);
963 /* seg1: 3 levels of PTE */
964 ret
= paddr_from_pte(physp
, zbitsp
, protp
, ptebase
, page_bits
,
965 virtual, mmu_idx
, rw
);
968 /* seg1: 2 levels of PTE */
969 ret
= paddr_from_pte(physp
, zbitsp
, protp
, ptebase
, page_bits
,
970 virtual, mmu_idx
, rw
);
981 /* seg1: TB mapped */
982 ret
= paddr_from_pte(physp
, zbitsp
, protp
, ptebase
, page_bits
,
983 virtual, mmu_idx
, rw
);
993 /* XXX: code provision */
994 int cpu_ppc_handle_mmu_fault (CPUState
*env
, uint32_t address
, int rw
,
995 int mmu_idx
, int is_softmmu
)
997 uint64_t physical
, page_size
, end
;
998 int prot
, zbits
, ret
;
1000 #if defined(CONFIG_USER_ONLY)
1003 ret
= virtual_to_physical(env
, &physical
, &zbits
, &prot
,
1004 address
, mmu_idx
, rw
);
1009 page_size
= 1ULL << zbits
;
1010 address
&= ~(page_size
- 1);
1011 for (end
= physical
+ page_size
; physical
< end
; physical
+= 0x1000) {
1012 ret
= tlb_set_page(env
, address
, physical
, prot
,
1013 mmu_idx
, is_softmmu
);
1019 env
->exception_index
= EXCP_DFAULT
;
1020 env
->ipr
[IPR_EXC_ADDR
] = address
;
1024 env
->exception_index
= EXCP_ACCESS_VIOLATION
;
1025 env
->ipr
[IPR_EXC_ADDR
] = address
;
1029 env
->exception_index
= EXCP_FAULT_ON_READ
;
1030 env
->ipr
[IPR_EXC_ADDR
] = address
;
1034 env
->exception_index
= EXCP_FAULT_ON_EXECUTE
;
1035 env
->ipr
[IPR_EXC_ADDR
] = address
;
1038 env
->exception_index
= EXCP_FAULT_ON_WRITE
;
1039 env
->ipr
[IPR_EXC_ADDR
] = address
;
1043 /* Should never happen */
1044 env
->exception_index
= EXCP_MCHK
;
1045 env
->ipr
[IPR_EXC_ADDR
] = address
;
1054 #else /* !defined (CONFIG_USER_ONLY) */
1055 void pal_init (CPUState
*env
)
1059 void call_pal (CPUState
*env
, int palcode
)
1067 /* FIXME: Sends SIGTRAP, si_code=TRAP_BRKPT. */
1071 qemu_log("BUGCHK\n");
1072 /* FIXME: Sends SIGTRAP, si_code=SI_FAULT. */
1076 qemu_log("CALLSYS n " TARGET_FMT_ld
"\n", env
->ir
[0]);
1077 ret
= do_syscall(env
, env
->ir
[IR_V0
], env
->ir
[IR_A0
], env
->ir
[IR_A1
],
1078 env
->ir
[IR_A2
], env
->ir
[IR_A3
], env
->ir
[IR_A4
],
1082 env
->ir
[IR_V0
] = ret
;
1085 env
->ir
[IR_V0
] = -ret
;
1091 /* ??? We can probably elide the code using page_unprotect that is
1092 checking for self-modifying code. Instead we could simply call
1093 tb_flush here. Until we work out the changes required to turn
1094 off the extra write protection, this can be a no-op. */
1098 qemu_log("RDUNIQUE: " TARGET_FMT_lx
"\n", env
->unique
);
1099 /* Handled in the translator for usermode. */
1103 qemu_log("WRUNIQUE: " TARGET_FMT_lx
"\n", env
->ir
[IR_A0
]);
1104 /* Handled in the translator for usermode. */
1108 qemu_log("GENTRAP: " TARGET_FMT_lx
"\n", env
->ir
[IR_A0
]);
1109 /* FIXME: This is supposed to send a signal:
1111 GEN_INTOVF, GEN_INTDIV, GEN_FLTOVF, GEN_FLTDIV,
1112 GEN_FLTUND, GEN_FLTINV, GEN_FLTINE, GEN_ROPRAND
1115 with various settings of si_code. */
1118 qemu_log("%s: unhandled palcode %02x\n", __func__
, palcode
);