forked from herd/herdtools7
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAArch64PteVal.ml
229 lines (193 loc) · 7.28 KB
/
AArch64PteVal.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
(****************************************************************************)
(* the diy toolsuite *)
(* *)
(* Jade Alglave, University College London, UK. *)
(* Luc Maranget, INRIA Paris, France. *)
(* *)
(* Copyright 2020-present Institut National de Recherche en Informatique et *)
(* en Automatique, ARM Ltd and the authors. All rights reserved. *)
(* *)
(* This software is governed by the CeCILL-B license under French law and *)
(* abiding by the rules of distribution of free software. You can use, *)
(* modify and/ or redistribute the software under the terms of the CeCILL-B *)
(* license as circulated by CEA, CNRS and INRIA at the following URL *)
(* "http://www.cecill.info". We also give a copy in LICENSE.txt. *)
(****************************************************************************)
open Printf
module Attrs = struct
type t = StringSet.t
(* By default we assume the attributes of the memory malloc would
return on Linux. This is architecture specific, however, for now,
translation is supported only for AArch64. *)
let default = StringSet.empty
let compare a1 a2 = StringSet.compare a1 a2
let eq a1 a2 = StringSet.equal a1 a2
let pp a = StringSet.pp_str ", " Misc.identity a
let as_list a = StringSet.elements a
let of_list l = StringSet.of_list l
end
type t = {
oa : OutputAddress.t;
valid : int;
af : int;
db : int;
dbm : int;
el0 : int;
attrs: Attrs.t;
}
let eq_props p1 p2 =
Misc.int_eq p1.af p2.af &&
Misc.int_eq p1.db p2.db &&
Misc.int_eq p1.dbm p2.dbm &&
Misc.int_eq p1.valid p2.valid &&
Misc.int_eq p1.el0 p2.el0 &&
Attrs.eq p1.attrs p2.attrs
(* Let us abstract... *)
let is_af {af; _} = af <> 0
and same_oa {oa=oa1; _} {oa=oa2; _} = OutputAddress.eq oa1 oa2
(* *)
let writable ha hd p =
(p.af <> 0 || ha) && (* access allowed *)
(p.db <> 0 || (p.dbm <> 0 && hd)) (* write allowed *)
let get_attrs {attrs;_ } = Attrs.as_list attrs
(* For ordinary tests not to fault, the dirty bit has to be set. *)
let prot_default =
{ oa=OutputAddress.PHY "";
valid=1; af=1; db=1; dbm=0; el0=1; attrs=Attrs.default; }
let default s = { prot_default with oa=OutputAddress.PHY s; }
(* Page table entries for pointers into the page table
have el0 flag unset. Namely, page table access from
EL0 is disallowed. This correspond to expected behaviour:
user code cannot access the page table. *)
let of_pte s = { prot_default with oa=OutputAddress.PTE s; el0=0; }
let pp_field ok pp eq ac p k =
let f = ac p in if not ok && eq f (ac prot_default) then k else pp f::k
(* hexa arg is ignored, as it would complicate normalisation *)
let pp_int_field _hexa ok name =
let pp_int = sprintf "%d" in
pp_field ok (fun v -> sprintf "%s:%s" name (pp_int v)) Misc.int_eq
let pp_valid hexa ok = pp_int_field hexa ok "valid" (fun p -> p.valid)
and pp_af hexa ok = pp_int_field hexa ok "af" (fun p -> p.af)
and pp_db hexa ok = pp_int_field hexa ok "db" (fun p -> p.db)
and pp_dbm hexa ok = pp_int_field hexa ok "dbm" (fun p -> p.dbm)
and pp_el0 hexa ok = pp_int_field hexa ok "el0" (fun p -> p.el0)
and pp_attrs ok = pp_field ok (fun a -> Attrs.pp a) Attrs.eq (fun p -> p.attrs)
let is_default t = eq_props prot_default t
(* If showall is true, field will always be printed.
Otherwise, field will be printed only if non-default.
While computing hashes, backward compatibility commands that:
(1) Fields older than el0 are always printed.
(2) Fields from el0 (included) are printed if non-default. *)
let pp_fields hexa showall p k =
let k = pp_el0 hexa false p k in
let k = pp_valid hexa showall p k in
let k = pp_dbm hexa showall p k in
let k = pp_db hexa showall p k in
let k = pp_af hexa showall p k in
k
let do_pp hexa showall old_oa p =
let k = pp_attrs false p [] in
let k = pp_fields hexa showall p k in
let k =
sprintf "oa:%s"
((if old_oa then OutputAddress.pp_old
else OutputAddress.pp) p.oa)::k in
let fs = String.concat ", " k in
sprintf "(%s)" fs
(* By default pp does not list fields whose value is default *)
let pp hexa = do_pp hexa false false
(* For initial values dumped for hashing, pp_hash is different,
for not altering hashes as much as possible *)
let pp_v = pp false
let pp_hash = do_pp false true true
let my_int_of_string s v =
let v = try int_of_string v with
_ -> Warn.user_error "PTE field %s should be an integer" s
in v
let add_field k v p =
match k with
| "af" -> { p with af = my_int_of_string k v }
| "db" -> { p with db = my_int_of_string k v }
| "dbm" -> { p with dbm = my_int_of_string k v }
| "valid" -> { p with valid = my_int_of_string k v }
| "el0" -> { p with el0 = my_int_of_string k v }
| _ ->
Warn.user_error "Illegal AArch64 page table entry property %s" k
let tr p =
let open ParsedPteVal in
let r = prot_default in
let r =
match p.p_oa with
| None -> r
| Some oa -> { r with oa; } in
let r = StringMap.fold add_field p.p_kv r in
let r =
let attrs = StringSet.union r.attrs p.p_attrs; in
{ r with attrs; } in
r
let pp_norm p =
let n = tr p in
pp_v n
let lex_compare c1 c2 x y = match c1 x y with
| 0 -> c2 x y
| r -> r
let compare =
let cmp = (fun p1 p2 -> Misc.int_compare p1.el0 p2.el0) in
let cmp =
lex_compare (fun p1 p2 -> Misc.int_compare p1.valid p2.valid) cmp in
let cmp =
lex_compare (fun p1 p2 -> Misc.int_compare p1.dbm p2.dbm) cmp in
let cmp =
lex_compare (fun p1 p2 -> Misc.int_compare p1.db p2.db) cmp in
let cmp =
lex_compare (fun p1 p2 -> Misc.int_compare p1.af p2.af) cmp in
let cmp =
lex_compare (fun p1 p2 -> OutputAddress.compare p1.oa p2.oa) cmp in
let cmp =
lex_compare (fun p1 p2 -> Attrs.compare p1.attrs p2.attrs) cmp in
cmp
let eq p1 p2 = OutputAddress.eq p1.oa p2.oa && eq_props p1 p2
(* For litmus *)
(* Those lists must of course match one with the other *)
let fields = ["af";"db";"dbm";"valid";"el0";]
and default_fields =
let p = prot_default in
let ds = [p.af; p.db; p.dbm; p.valid;p.el0;] in
List.map (Printf.sprintf "%i") ds
let norm =
let default =
try
List.fold_right2
(fun k v -> StringMap.add k v)
fields
default_fields
StringMap.empty
with Invalid_argument _ -> assert false in
fun kvs ->
StringMap.fold
(fun k v m ->
try
let v0 = StringMap.find k default in
if Misc.string_eq v v0 then m
else StringMap.add k v m
with
| Not_found -> StringMap.add k v m)
kvs StringMap.empty
let dump_pack pp_oa p =
sprintf
"pack_pack(%s,%d,%d,%d,%d,%d)"
(pp_oa (OutputAddress.pp_old p.oa))
p.af p.db p.dbm p.valid p.el0
let as_physical p = OutputAddress.as_physical p.oa
let as_flags p =
if is_default p then None
else
let add b s k = if b<>0 then s::k else k in
let msk =
add p.el0 "msk_el0"
(add p.valid "msk_valid"
(add p.af "msk_af"
(add p.dbm "msk_dbm"
(add p.db "msk_db" [])))) in
let msk = String.concat "|" msk in
Some msk