Revision d4c430a8 target-arm/helper.c
b/target-arm/helper.c | ||
---|---|---|
894 | 894 |
} |
895 | 895 |
|
896 | 896 |
static int get_phys_addr_v5(CPUState *env, uint32_t address, int access_type, |
897 |
int is_user, uint32_t *phys_ptr, int *prot) |
|
897 |
int is_user, uint32_t *phys_ptr, int *prot, |
|
898 |
target_ulong *page_size) |
|
898 | 899 |
{ |
899 | 900 |
int code; |
900 | 901 |
uint32_t table; |
... | ... | |
927 | 928 |
phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); |
928 | 929 |
ap = (desc >> 10) & 3; |
929 | 930 |
code = 13; |
931 |
*page_size = 1024 * 1024; |
|
930 | 932 |
} else { |
931 | 933 |
/* Lookup l2 entry. */ |
932 | 934 |
if (type == 1) { |
... | ... | |
944 | 946 |
case 1: /* 64k page. */ |
945 | 947 |
phys_addr = (desc & 0xffff0000) | (address & 0xffff); |
946 | 948 |
ap = (desc >> (4 + ((address >> 13) & 6))) & 3; |
949 |
*page_size = 0x10000; |
|
947 | 950 |
break; |
948 | 951 |
case 2: /* 4k page. */ |
949 | 952 |
phys_addr = (desc & 0xfffff000) | (address & 0xfff); |
950 | 953 |
ap = (desc >> (4 + ((address >> 13) & 6))) & 3; |
954 |
*page_size = 0x1000; |
|
951 | 955 |
break; |
952 | 956 |
case 3: /* 1k page. */ |
953 | 957 |
if (type == 1) { |
... | ... | |
962 | 966 |
phys_addr = (desc & 0xfffffc00) | (address & 0x3ff); |
963 | 967 |
} |
964 | 968 |
ap = (desc >> 4) & 3; |
969 |
*page_size = 0x400; |
|
965 | 970 |
break; |
966 | 971 |
default: |
967 | 972 |
/* Never happens, but compiler isn't smart enough to tell. */ |
... | ... | |
981 | 986 |
} |
982 | 987 |
|
983 | 988 |
static int get_phys_addr_v6(CPUState *env, uint32_t address, int access_type, |
984 |
int is_user, uint32_t *phys_ptr, int *prot) |
|
989 |
int is_user, uint32_t *phys_ptr, int *prot, |
|
990 |
target_ulong *page_size) |
|
985 | 991 |
{ |
986 | 992 |
int code; |
987 | 993 |
uint32_t table; |
... | ... | |
1021 | 1027 |
if (desc & (1 << 18)) { |
1022 | 1028 |
/* Supersection. */ |
1023 | 1029 |
phys_addr = (desc & 0xff000000) | (address & 0x00ffffff); |
1030 |
*page_size = 0x1000000; |
|
1024 | 1031 |
} else { |
1025 | 1032 |
/* Section. */ |
1026 | 1033 |
phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); |
1034 |
*page_size = 0x100000; |
|
1027 | 1035 |
} |
1028 | 1036 |
ap = ((desc >> 10) & 3) | ((desc >> 13) & 4); |
1029 | 1037 |
xn = desc & (1 << 4); |
... | ... | |
1040 | 1048 |
case 1: /* 64k page. */ |
1041 | 1049 |
phys_addr = (desc & 0xffff0000) | (address & 0xffff); |
1042 | 1050 |
xn = desc & (1 << 15); |
1051 |
*page_size = 0x10000; |
|
1043 | 1052 |
break; |
1044 | 1053 |
case 2: case 3: /* 4k page. */ |
1045 | 1054 |
phys_addr = (desc & 0xfffff000) | (address & 0xfff); |
1046 | 1055 |
xn = desc & 1; |
1056 |
*page_size = 0x1000; |
|
1047 | 1057 |
break; |
1048 | 1058 |
default: |
1049 | 1059 |
/* Never happens, but compiler isn't smart enough to tell. */ |
... | ... | |
1132 | 1142 |
|
1133 | 1143 |
static inline int get_phys_addr(CPUState *env, uint32_t address, |
1134 | 1144 |
int access_type, int is_user, |
1135 |
uint32_t *phys_ptr, int *prot) |
|
1145 |
uint32_t *phys_ptr, int *prot, |
|
1146 |
target_ulong *page_size) |
|
1136 | 1147 |
{ |
1137 | 1148 |
/* Fast Context Switch Extension. */ |
1138 | 1149 |
if (address < 0x02000000) |
... | ... | |
1142 | 1153 |
/* MMU/MPU disabled. */ |
1143 | 1154 |
*phys_ptr = address; |
1144 | 1155 |
*prot = PAGE_READ | PAGE_WRITE; |
1156 |
*page_size = TARGET_PAGE_SIZE; |
|
1145 | 1157 |
return 0; |
1146 | 1158 |
} else if (arm_feature(env, ARM_FEATURE_MPU)) { |
1159 |
*page_size = TARGET_PAGE_SIZE; |
|
1147 | 1160 |
return get_phys_addr_mpu(env, address, access_type, is_user, phys_ptr, |
1148 | 1161 |
prot); |
1149 | 1162 |
} else if (env->cp15.c1_sys & (1 << 23)) { |
1150 | 1163 |
return get_phys_addr_v6(env, address, access_type, is_user, phys_ptr, |
1151 |
prot); |
|
1164 |
prot, page_size);
|
|
1152 | 1165 |
} else { |
1153 | 1166 |
return get_phys_addr_v5(env, address, access_type, is_user, phys_ptr, |
1154 |
prot); |
|
1167 |
prot, page_size);
|
|
1155 | 1168 |
} |
1156 | 1169 |
} |
1157 | 1170 |
|
... | ... | |
1159 | 1172 |
int access_type, int mmu_idx, int is_softmmu) |
1160 | 1173 |
{ |
1161 | 1174 |
uint32_t phys_addr; |
1175 |
target_ulong page_size; |
|
1162 | 1176 |
int prot; |
1163 | 1177 |
int ret, is_user; |
1164 | 1178 |
|
1165 | 1179 |
is_user = mmu_idx == MMU_USER_IDX; |
1166 |
ret = get_phys_addr(env, address, access_type, is_user, &phys_addr, &prot); |
|
1180 |
ret = get_phys_addr(env, address, access_type, is_user, &phys_addr, &prot, |
|
1181 |
&page_size); |
|
1167 | 1182 |
if (ret == 0) { |
1168 | 1183 |
/* Map a single [sub]page. */ |
1169 | 1184 |
phys_addr &= ~(uint32_t)0x3ff; |
1170 | 1185 |
address &= ~(uint32_t)0x3ff; |
1171 |
return tlb_set_page (env, address, phys_addr, prot, mmu_idx, |
|
1172 |
is_softmmu); |
|
1186 |
tlb_set_page (env, address, phys_addr, prot | PAGE_EXEC, mmu_idx, |
|
1187 |
page_size); |
|
1188 |
return 0; |
|
1173 | 1189 |
} |
1174 | 1190 |
|
1175 | 1191 |
if (access_type == 2) { |
... | ... | |
1189 | 1205 |
target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) |
1190 | 1206 |
{ |
1191 | 1207 |
uint32_t phys_addr; |
1208 |
target_ulong page_size; |
|
1192 | 1209 |
int prot; |
1193 | 1210 |
int ret; |
1194 | 1211 |
|
1195 |
ret = get_phys_addr(env, addr, 0, 0, &phys_addr, &prot); |
|
1212 |
ret = get_phys_addr(env, addr, 0, 0, &phys_addr, &prot, &page_size);
|
|
1196 | 1213 |
|
1197 | 1214 |
if (ret != 0) |
1198 | 1215 |
return -1; |
... | ... | |
1406 | 1423 |
tlb_flush(env, 0); |
1407 | 1424 |
break; |
1408 | 1425 |
case 1: /* Invalidate single TLB entry. */ |
1409 |
#if 0 |
|
1410 |
/* ??? This is wrong for large pages and sections. */ |
|
1411 |
/* As an ugly hack to make linux work we always flush a 4K |
|
1412 |
pages. */ |
|
1413 |
val &= 0xfffff000; |
|
1414 |
tlb_flush_page(env, val); |
|
1415 |
tlb_flush_page(env, val + 0x400); |
|
1416 |
tlb_flush_page(env, val + 0x800); |
|
1417 |
tlb_flush_page(env, val + 0xc00); |
|
1418 |
#else |
|
1419 |
tlb_flush(env, 1); |
|
1420 |
#endif |
|
1426 |
tlb_flush_page(env, val & TARGET_PAGE_MASK); |
|
1421 | 1427 |
break; |
1422 | 1428 |
case 2: /* Invalidate on ASID. */ |
1423 | 1429 |
tlb_flush(env, val == 0); |
Also available in: Unified diff