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 explicitely check that the TB is valid and the FOE bit is reset */
59 static void update_itb ()
61 /* This writes into a temp register, not the actual one */
64 /* This commits the TB update */
68 static void update_dtb ();
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
;
820 pteaddr
= (ptebase
<< page_bits
) + (8 * level
);
821 pte
= ldq_raw(pteaddr
);
822 /* Decode all interresting PTE fields */
824 uwe
= (pte
>> 13) & 1;
825 kwe
= (pte
>> 12) & 1;
826 ure
= (pte
>> 9) & 1;
827 kre
= (pte
>> 8) & 1;
829 foE
= (pte
>> 3) & 1;
830 foW
= (pte
>> 2) & 1;
831 foR
= (pte
>> 1) & 1;
836 /* Check access rights */
865 *zbitsp
= page_bits
+ (3 * gh
);
872 static int paddr_from_pte (uint64_t *paddr
, int *zbitsp
, int *prot
,
873 uint64_t ptebase
, int page_bits
,
874 uint64_t vaddr
, int is_user
, int rw
)
876 uint64_t pfn
, page_mask
, lvl_mask
, level1
, level2
, level3
;
879 page_mask
= (1ULL << page_bits
) - 1ULL;
880 lvl_bits
= page_bits
- 3;
881 lvl_mask
= (1ULL << lvl_bits
) - 1ULL;
882 level3
= (vaddr
>> page_bits
) & lvl_mask
;
883 level2
= (vaddr
>> (page_bits
+ lvl_bits
)) & lvl_mask
;
884 level1
= (vaddr
>> (page_bits
+ (2 * lvl_bits
))) & lvl_mask
;
886 ret
= get_pte(&pfn
, NULL
, NULL
, ptebase
, page_bits
, level1
, 0, 0);
889 /* Access violation */
892 /* translation not valid */
899 ret
= get_pte(&pfn
, NULL
, NULL
, pfn
, page_bits
, level2
, 0, 0);
902 /* Access violation */
905 /* translation not valid */
912 ret
= get_pte(&pfn
, zbitsp
, prot
, pfn
, page_bits
, level3
, is_user
, rw
);
914 /* Translation not valid */
916 } else if (ret
& 2) {
917 /* Access violation */
930 /* Fault on execute */
939 *paddr
= (pfn
<< page_bits
) | (vaddr
& page_mask
);
944 static int virtual_to_physical (CPUState
*env
, uint64_t *physp
,
945 int *zbitsp
, int *protp
,
946 uint64_t virtual, int is_user
, int rw
)
948 uint64_t sva
, ptebase
;
949 int seg
, page_bits
, ret
;
951 sva
= ((int64_t)(virtual << (64 - VA_BITS
))) >> (64 - VA_BITS
);
955 seg
= sva
>> (VA_BITS
- 2);
956 virtual &= ~(0xFFFFFC0000000000ULL
<< (VA_BITS
- 43));
957 ptebase
= get_ptebase(env
, virtual);
958 page_bits
= get_page_bits(env
);
962 /* seg1: 3 levels of PTE */
963 ret
= paddr_from_pte(physp
, zbitsp
, protp
, ptebase
, page_bits
,
964 virtual, is_user
, rw
);
967 /* seg1: 2 levels of PTE */
968 ret
= paddr_from_pte(physp
, zbitsp
, protp
, ptebase
, page_bits
,
969 virtual, is_user
, rw
);
980 /* seg1: TB mapped */
981 ret
= paddr_from_pte(physp
, zbitsp
, protp
, ptebase
, page_bits
,
982 virtual, is_user
, rw
);
992 /* XXX: code provision */
993 int cpu_ppc_handle_mmu_fault (CPUState
*env
, uint32_t address
, int rw
,
994 int is_user
, int is_softmmu
)
996 uint64_t physical
, page_size
, end
;
997 int prot
, zbits
, ret
;
999 if (env
->user_mode_only
) {
1002 ret
= virtual_to_physical(env
, &physical
, &zbits
, &prot
,
1003 address
, is_user
, rw
);
1008 page_size
= 1ULL << zbits
;
1009 address
&= ~(page_size
- 1);
1010 for (end
= physical
+ page_size
; physical
< end
; physical
+= 0x1000) {
1011 ret
= tlb_set_page(env
, address
, physical
, prot
,
1012 is_user
, is_softmmu
);
1018 env
->exception_index
= EXCP_DFAULT
;
1019 env
->ipr
[IPR_EXC_ADDR
] = address
;
1023 env
->exception_index
= EXCP_ACCESS_VIOLATION
;
1024 env
->ipr
[IPR_EXC_ADDR
] = address
;
1028 env
->exception_index
= EXCP_FAULT_ON_READ
;
1029 env
->ipr
[IPR_EXC_ADDR
] = address
;
1033 env
->exception_index
= EXCP_FAULT_ON_EXECUTE
;
1034 env
->ipr
[IPR_EXC_ADDR
] = address
;
1037 env
->exception_index
= EXCP_FAULT_ON_WRITE
;
1038 env
->ipr
[IPR_EXC_ADDR
] = address
;
1042 /* Should never happen */
1043 env
->exception_index
= EXCP_MCHK
;
1044 env
->ipr
[IPR_EXC_ADDR
] = address
;
1053 #else /* !defined (CONFIG_USER_ONLY) */
1054 void pal_init (CPUState
*env
)
1058 void call_pal (CPUState
*env
, int palcode
)
1062 printf("%s: palcode %02x\n", __func__
, palcode
);
1063 if (logfile
!= NULL
)
1064 fprintf(logfile
, "%s: palcode %02x\n", __func__
, palcode
);
1068 printf("CALLSYS n " TARGET_FMT_ld
"\n", env
->ir
[0]);
1069 if (logfile
!= NULL
)
1070 fprintf(logfile
, "CALLSYS n " TARGET_FMT_ld
"\n", env
->ir
[0]);
1071 ret
= do_syscall(env
, env
->ir
[IR_V0
], env
->ir
[IR_A0
], env
->ir
[IR_A1
],
1072 env
->ir
[IR_A2
], env
->ir
[IR_A3
], env
->ir
[IR_A4
],
1074 env
->ir
[IR_A3
] = ret
;
1075 if (ret
> (target_ulong
)(-515)) {
1083 env
->ir
[IR_V0
] = env
->unique
;
1084 printf("RDUNIQUE: " TARGET_FMT_lx
"\n", env
->unique
);
1088 env
->unique
= env
->ir
[IR_A0
];
1089 printf("WRUNIQUE: " TARGET_FMT_lx
"\n", env
->unique
);
1092 printf("%s: unhandled palcode %02x\n", __func__
, palcode
);
1093 if (logfile
!= NULL
)
1094 fprintf(logfile
, "%s: unhandled palcode %02x\n",