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 static void pal_reset (CPUState
*env
);
29 /* Console handlers */
30 static void pal_console_call (CPUState
*env
, uint32_t palcode
);
31 /* OpenVMS handlers */
32 static void pal_openvms_call (CPUState
*env
, uint32_t palcode
);
33 /* UNIX / Linux handlers */
34 static void pal_unix_call (CPUState
*env
, uint32_t palcode
);
36 pal_handler_t pal_handlers
[] = {
40 .call_pal
= &pal_console_call
,
45 .call_pal
= &pal_openvms_call
,
47 /* UNIX / Linux handler */
50 .call_pal
= &pal_unix_call
,
55 /* One must explicitly check that the TB is valid and the FOE bit is reset */
56 static void update_itb (void)
58 /* This writes into a temp register, not the actual one */
61 /* This commits the TB update */
65 static void update_dtb (void);
68 /* This write into a temp register, not the actual one */
70 /* This commits the TB update */
75 static void pal_reset (CPUState
*env
)
79 static void do_swappal (CPUState
*env
, uint64_t palid
)
81 pal_handler_t
*pal_handler
;
87 pal_handler
= &pal_handlers
[palid
];
88 env
->pal_handler
= pal_handler
;
89 env
->ipr
[IPR_PAL_BASE
] = -1ULL;
90 (*pal_handler
->reset
)(env
);
93 /* Unknown identifier */
97 /* We were given the entry point address */
98 env
->pal_handler
= NULL
;
99 env
->ipr
[IPR_PAL_BASE
] = palid
;
100 env
->pc
= env
->ipr
[IPR_PAL_BASE
];
105 static void pal_console_call (CPUState
*env
, uint32_t palcode
)
109 if (palcode
< 0x00000080) {
110 /* Privileged palcodes */
111 if (!(env
->ps
>> 3)) {
112 /* TODO: generate privilege exception */
126 /* Implemented as no-op */
136 do_swappal(env
, palid
);
149 /* Implemented as no-op */
168 static void pal_openvms_call (CPUState
*env
, uint32_t palcode
)
170 uint64_t palid
, val
, oldval
;
172 if (palcode
< 0x00000080) {
173 /* Privileged palcodes */
174 if (!(env
->ps
>> 3)) {
175 /* TODO: generate privilege exception */
189 /* Implemented as no-op */
202 if (cpu_alpha_mfpr(env
, IPR_ASN
, &val
) == 0)
208 if (cpu_alpha_mtpr(env
, IPR_ASTEN
, val
, &oldval
) == 1)
214 if (cpu_alpha_mtpr(env
, IPR_ASTSR
, val
, &oldval
) == 1)
225 do_swappal(env
, palid
);
229 if (cpu_alpha_mfpr(env
, IPR_FEN
, &val
) == 0)
235 if (cpu_alpha_mtpr(env
, IPR_FEN
, val
, &oldval
) == 1)
241 if (cpu_alpha_mtpr(env
, IPR_IPIR
, val
, &oldval
) == 1)
246 if (cpu_alpha_mfpr(env
, IPR_IPL
, &val
) == 0)
252 if (cpu_alpha_mtpr(env
, IPR_IPL
, val
, &oldval
) == 1)
257 if (cpu_alpha_mfpr(env
, IPR_MCES
, &val
) == 0)
263 if (cpu_alpha_mtpr(env
, IPR_MCES
, val
, &oldval
) == 1)
268 if (cpu_alpha_mfpr(env
, IPR_PCBB
, &val
) == 0)
273 if (cpu_alpha_mfpr(env
, IPR_PRBR
, &val
) == 0)
279 if (cpu_alpha_mtpr(env
, IPR_PRBR
, val
, &oldval
) == 1)
284 if (cpu_alpha_mfpr(env
, IPR_PTBR
, &val
) == 0)
289 if (cpu_alpha_mfpr(env
, IPR_SCBB
, &val
) == 0)
295 if (cpu_alpha_mtpr(env
, IPR_SCBB
, val
, &oldval
) == 1)
301 if (cpu_alpha_mtpr(env
, IPR_SIRR
, val
, &oldval
) == 1)
306 if (cpu_alpha_mfpr(env
, IPR_SISR
, &val
) == 0)
311 if (cpu_alpha_mfpr(env
, IPR_TBCHK
, &val
) == 0)
317 if (cpu_alpha_mtpr(env
, IPR_TBIA
, val
, &oldval
) == 1)
323 if (cpu_alpha_mtpr(env
, IPR_TBIAP
, val
, &oldval
) == 1)
329 if (cpu_alpha_mtpr(env
, IPR_TBIS
, val
, &oldval
) == 1)
334 if (cpu_alpha_mfpr(env
, IPR_ESP
, &val
) == 0)
340 if (cpu_alpha_mtpr(env
, IPR_ESP
, val
, &oldval
) == 1)
345 if (cpu_alpha_mfpr(env
, IPR_SSP
, &val
) == 0)
351 if (cpu_alpha_mtpr(env
, IPR_SSP
, val
, &oldval
) == 1)
356 if (cpu_alpha_mfpr(env
, IPR_USP
, &val
) == 0)
362 if (cpu_alpha_mtpr(env
, IPR_USP
, val
, &oldval
) == 1)
368 if (cpu_alpha_mtpr(env
, IPR_TBISD
, val
, &oldval
) == 1)
374 if (cpu_alpha_mtpr(env
, IPR_TBISI
, val
, &oldval
) == 1)
379 if (cpu_alpha_mfpr(env
, IPR_ASTEN
, &val
) == 0)
384 if (cpu_alpha_mfpr(env
, IPR_ASTSR
, &val
) == 0)
389 if (cpu_alpha_mfpr(env
, IPR_VPTB
, &val
) == 0)
395 if (cpu_alpha_mtpr(env
, IPR_VPTB
, val
, &oldval
) == 1)
401 if (cpu_alpha_mtpr(env
, IPR_PERFMON
, val
, &oldval
) == 1)
407 if (cpu_alpha_mtpr(env
, IPR_DATFX
, val
, &oldval
) == 1)
415 if (cpu_alpha_mfpr(env
, IPR_WHAMI
, &val
) == 0)
441 /* Implemented as no-op */
562 static void pal_unix_call (CPUState
*env
, uint32_t palcode
)
564 uint64_t palid
, val
, oldval
;
566 if (palcode
< 0x00000080) {
567 /* Privileged palcodes */
568 if (!(env
->ps
>> 3)) {
569 /* TODO: generate privilege exception */
583 /* Implemented as no-op */
593 do_swappal(env
, palid
);
598 if (cpu_alpha_mtpr(env
, IPR_IPIR
, val
, &oldval
) == 1)
603 if (cpu_alpha_mfpr(env
, IPR_MCES
, &val
) == 0)
609 if (cpu_alpha_mtpr(env
, IPR_MCES
, val
, &oldval
) == 1)
615 if (cpu_alpha_mtpr(env
, IPR_PERFMON
, val
, &oldval
) == 1)
633 if (cpu_alpha_mtpr(env
, IPR_TBIS
, val
, &oldval
) == 1)
651 if (cpu_alpha_mtpr(env
, IPR_USP
, val
, &oldval
) == 1)
657 if (cpu_alpha_mtpr(env
, IPR_PERFMON
, val
, &oldval
) == 1)
662 if (cpu_alpha_mfpr(env
, IPR_USP
, &val
) == 0)
667 if (cpu_alpha_mfpr(env
, IPR_WHAMI
, &val
) == 0)
678 if (cpu_alpha_mfpr(env
, IPR_WHAMI
, &val
) == 0)
695 /* Implemented as no-op */
720 void call_pal (CPUState
*env
)
722 pal_handler_t
*pal_handler
= env
->pal_handler
;
724 switch (env
->exception_index
) {
726 (*pal_handler
->reset
)(env
);
729 (*pal_handler
->machine_check
)(env
);
732 (*pal_handler
->arithmetic
)(env
);
735 (*pal_handler
->interrupt
)(env
);
738 (*pal_handler
->dfault
)(env
);
740 case EXCP_DTB_MISS_PAL
:
741 (*pal_handler
->dtb_miss_pal
)(env
);
743 case EXCP_DTB_MISS_NATIVE
:
744 (*pal_handler
->dtb_miss_native
)(env
);
747 (*pal_handler
->unalign
)(env
);
750 (*pal_handler
->itb_miss
)(env
);
753 (*pal_handler
->itb_acv
)(env
);
756 (*pal_handler
->opcdec
)(env
);
759 (*pal_handler
->fen
)(env
);
762 if (env
->exception_index
>= EXCP_CALL_PAL
&&
763 env
->exception_index
< EXCP_CALL_PALP
) {
764 /* Unprivileged PAL call */
765 (*pal_handler
->call_pal
)
766 (env
, (env
->exception_index
- EXCP_CALL_PAL
) >> 6);
767 } else if (env
->exception_index
>= EXCP_CALL_PALP
&&
768 env
->exception_index
< EXCP_CALL_PALE
) {
769 /* Privileged PAL call */
770 (*pal_handler
->call_pal
)
771 (env
, ((env
->exception_index
- EXCP_CALL_PALP
) >> 6) + 0x80);
773 /* Should never happen */
777 env
->ipr
[IPR_EXC_ADDR
] &= ~1;
780 void pal_init (CPUState
*env
)
786 static uint64_t get_ptebase (CPUState
*env
, uint64_t vaddr
)
788 uint64_t virbnd
, ptbr
;
790 if ((env
->features
& FEATURE_VIRBND
)) {
791 cpu_alpha_mfpr(env
, IPR_VIRBND
, &virbnd
);
793 cpu_alpha_mfpr(env
, IPR_SYSPTBR
, &ptbr
);
795 cpu_alpha_mfpr(env
, IPR_PTBR
, &ptbr
);
797 cpu_alpha_mfpr(env
, IPR_PTBR
, &ptbr
);
803 static int get_page_bits (CPUState
*env
)
809 static int get_pte (uint64_t *pfnp
, int *zbitsp
, int *protp
,
810 uint64_t ptebase
, int page_bits
, uint64_t level
,
813 uint64_t pteaddr
, pte
, pfn
;
815 int ure
, uwe
, kre
, kwe
, foE
, foR
, foW
, v
, ret
, ar
, is_user
;
818 is_user
= mmu_idx
== MMU_USER_IDX
;
819 pteaddr
= (ptebase
<< page_bits
) + (8 * level
);
820 pte
= ldq_raw(pteaddr
);
821 /* Decode all interresting PTE fields */
823 uwe
= (pte
>> 13) & 1;
824 kwe
= (pte
>> 12) & 1;
825 ure
= (pte
>> 9) & 1;
826 kre
= (pte
>> 8) & 1;
828 foE
= (pte
>> 3) & 1;
829 foW
= (pte
>> 2) & 1;
830 foR
= (pte
>> 1) & 1;
835 /* Check access rights */
864 *zbitsp
= page_bits
+ (3 * gh
);
871 static int paddr_from_pte (uint64_t *paddr
, int *zbitsp
, int *prot
,
872 uint64_t ptebase
, int page_bits
,
873 uint64_t vaddr
, int mmu_idx
, int rw
)
875 uint64_t pfn
, page_mask
, lvl_mask
, level1
, level2
, level3
;
878 page_mask
= (1ULL << page_bits
) - 1ULL;
879 lvl_bits
= page_bits
- 3;
880 lvl_mask
= (1ULL << lvl_bits
) - 1ULL;
881 level3
= (vaddr
>> page_bits
) & lvl_mask
;
882 level2
= (vaddr
>> (page_bits
+ lvl_bits
)) & lvl_mask
;
883 level1
= (vaddr
>> (page_bits
+ (2 * lvl_bits
))) & lvl_mask
;
885 ret
= get_pte(&pfn
, NULL
, NULL
, ptebase
, page_bits
, level1
, 0, 0);
888 /* Access violation */
891 /* translation not valid */
898 ret
= get_pte(&pfn
, NULL
, NULL
, pfn
, page_bits
, level2
, 0, 0);
901 /* Access violation */
904 /* translation not valid */
911 ret
= get_pte(&pfn
, zbitsp
, prot
, pfn
, page_bits
, level3
, mmu_idx
, rw
);
913 /* Translation not valid */
915 } else if (ret
& 2) {
916 /* Access violation */
929 /* Fault on execute */
938 *paddr
= (pfn
<< page_bits
) | (vaddr
& page_mask
);
943 static int virtual_to_physical (CPUState
*env
, uint64_t *physp
,
944 int *zbitsp
, int *protp
,
945 uint64_t virtual, int mmu_idx
, int rw
)
947 uint64_t sva
, ptebase
;
948 int seg
, page_bits
, ret
;
950 sva
= ((int64_t)(virtual << (64 - VA_BITS
))) >> (64 - VA_BITS
);
954 seg
= sva
>> (VA_BITS
- 2);
955 virtual &= ~(0xFFFFFC0000000000ULL
<< (VA_BITS
- 43));
956 ptebase
= get_ptebase(env
, virtual);
957 page_bits
= get_page_bits(env
);
961 /* seg1: 3 levels of PTE */
962 ret
= paddr_from_pte(physp
, zbitsp
, protp
, ptebase
, page_bits
,
963 virtual, mmu_idx
, rw
);
966 /* seg1: 2 levels of PTE */
967 ret
= paddr_from_pte(physp
, zbitsp
, protp
, ptebase
, page_bits
,
968 virtual, mmu_idx
, rw
);
979 /* seg1: TB mapped */
980 ret
= paddr_from_pte(physp
, zbitsp
, protp
, ptebase
, page_bits
,
981 virtual, mmu_idx
, rw
);
991 /* XXX: code provision */
992 int cpu_ppc_handle_mmu_fault (CPUState
*env
, uint32_t address
, int rw
,
993 int mmu_idx
, int is_softmmu
)
995 uint64_t physical
, page_size
, end
;
996 int prot
, zbits
, ret
;
998 ret
= virtual_to_physical(env
, &physical
, &zbits
, &prot
,
999 address
, mmu_idx
, rw
);
1004 page_size
= 1ULL << zbits
;
1005 address
&= ~(page_size
- 1);
1006 /* FIXME: page_size should probably be passed to tlb_set_page,
1007 and this loop removed. */
1008 for (end
= physical
+ page_size
; physical
< end
; physical
+= 0x1000) {
1009 tlb_set_page(env
, address
, physical
, prot
, mmu_idx
,
1017 env
->exception_index
= EXCP_DFAULT
;
1018 env
->ipr
[IPR_EXC_ADDR
] = address
;
1022 env
->exception_index
= EXCP_ACCESS_VIOLATION
;
1023 env
->ipr
[IPR_EXC_ADDR
] = address
;
1027 env
->exception_index
= EXCP_FAULT_ON_READ
;
1028 env
->ipr
[IPR_EXC_ADDR
] = address
;
1032 env
->exception_index
= EXCP_FAULT_ON_EXECUTE
;
1033 env
->ipr
[IPR_EXC_ADDR
] = address
;
1036 env
->exception_index
= EXCP_FAULT_ON_WRITE
;
1037 env
->ipr
[IPR_EXC_ADDR
] = address
;
1041 /* Should never happen */
1042 env
->exception_index
= EXCP_MCHK
;
1043 env
->ipr
[IPR_EXC_ADDR
] = address
;