-
Notifications
You must be signed in to change notification settings - Fork 108
/
KernelInitSep_AI.thy
1955 lines (1661 loc) · 81.1 KB
/
KernelInitSep_AI.thy
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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
(*
* Copyright 2014, General Dynamics C4 Systems
*
* SPDX-License-Identifier: GPL-2.0-only
*)
theory KernelInitSep_AI
imports
"ASpec.KernelInit_A"
"Sep_Algebra.Sep_Algebra_L4v"
Invariants_AI
begin
(* UNFINISHED; paused project *)
text \<open>Migration candidates\<close>
lemma hoare_gen_asmE':
(* XXX: this should be the non-' version really, which is misnamed *)
"(P \<Longrightarrow> \<lbrace>P'\<rbrace> f \<lbrace>Q\<rbrace>,\<lbrace>E\<rbrace>) \<Longrightarrow> \<lbrace>P' and (K P)\<rbrace> f \<lbrace>Q\<rbrace>,\<lbrace>E\<rbrace>"
by (simp add: validE_R_def validE_def valid_def) blast
lemma unat_less_power_n:
"n = 2 ^ len_of TYPE('a) \<Longrightarrow> unat (x::'a::len word) < n"
by (simp add: unat_less_power)
lemma subset_union:
"S \<subset> T \<Longrightarrow> (S \<union> T) = T"
by blast
lemma singleton_subsetI:
"\<lbrakk> i \<in> S ; S - {i} \<noteq> {} \<rbrakk> \<Longrightarrow> {i} \<subset> S"
by blast
lemma bl_length_set_equal:
fixes i :: "bool list"
shows "{x. length x = length i} = {i} \<Longrightarrow> i = []"
apply (cases i, clarsimp)
apply (drule_tac x="(\<not>a) # list" in eqset_imp_iff)
apply simp
done
lemma bl_length_set_singleton_subset:
fixes i :: "bool list"
assumes notnil: "i \<noteq> []"
shows "{i} \<subset> {x. length x = length i}" (is "_ \<subset> ?s")
using notnil
proof -
from notnil obtain b bs where i: "i = b # bs" by (cases i, simp)
have b: "b # bs \<in> ?s" using i by simp
have notb: "(\<not>b) # bs \<in> ?s" using i by simp
from b notb have "?s - {b # bs} \<noteq> {}" by blast
thus ?thesis using i by (auto intro!: singleton_subsetI)
qed
lemma insert_same_length_id:
"insert i {x. length x = length i} = {x. length x = length i}"
by auto
text \<open>
Recursive sequence of length n along a ring, starting at p.
Wrapping permitted.\<close>
primrec
len_seq :: "'a::ring_1 \<Rightarrow> nat \<Rightarrow> 'a list"
where
"len_seq p 0 = []"
| "len_seq p (Suc n) = p # (len_seq (p + 1) n)"
lemma len_seq_length [simp]:
fixes p :: "'a::ring_1"
shows "length (len_seq p sz) = sz"
by (induct sz arbitrary: p, auto)
lemma len_seq_Cons:
"0 < sz \<Longrightarrow> len_seq p sz = p # len_seq (p+1) (sz - 1)"
by (induct sz arbitrary: p, auto)
lemma map_fun_Suc_upt_Cons:
assumes xn: "x \<le> n"
assumes gf: "\<And>n. g (Suc n) = f n"
shows "map g [x..<Suc n] = (g x) # map f [x..<n]"
proof -
have ss: "[Suc x..<Suc n] = map Suc [x..<n]"
by (subst map_Suc_upt[symmetric], rule refl)
show ?thesis using xn
by (simp add: upt_conv_Cons ss gf del: upt_Suc)
qed
lemma len_seq_map_upt_eq:
fixes p :: "'a::ring_1"
shows "len_seq p sz = map (\<lambda>n. p + of_nat n) [0..<sz]"
proof (induct sz arbitrary: p)
case 0 thus ?case by simp
next
case (Suc sz)
hence IH: "len_seq (p + 1) sz = map (\<lambda>n. p + 1 + of_nat n) [0..<sz]" by simp
show ?case
by (simp only: len_seq.simps IH map_fun_Suc_upt_Cons) fastforce
qed
lemma len_seq_no_wrap:
fixes p :: "'a :: len word"
assumes sz: "n < 2 ^ len_of TYPE('a)"
shows "p \<notin> set (len_seq (p + 1) n)"
proof (rule ccontr, simp)
assume pin: "p \<in> set (len_seq (p + 1) n)"
then obtain q where q: "p + 1 + of_nat q = p" and qn: "q < n"
by (auto simp: len_seq_map_upt_eq)
hence "of_nat q + 1 = (0 :: 'a word)" by (simp add: add.commute)
moreover
from qn have "of_nat q + (1::'a word) \<noteq> 0" using sz
by (fastforce intro!: less_is_non_zero_p1[where k="of_nat n :: 'a word"]
intro: word_of_nat_less simp: unat_of_nat_eq)
ultimately show False by blast
qed
section \<open>Definitions\<close>
subsection \<open>Partial Validity of Kernel Objects (i.e. cnodes)\<close>
text \<open>Same as @{term "well_formed_cnode_n"}, but allow gaps.\<close>
definition
bounded_cnode_n :: "nat \<Rightarrow> cnode_contents \<Rightarrow> bool" where
"bounded_cnode_n n \<equiv> \<lambda>cs. \<forall>x \<in> dom cs. length x = n"
text \<open>Same as @{term "valid_cs_size"}, but allowing gaps\<close>
definition
bounded_cs_size :: "nat \<Rightarrow> cnode_contents \<Rightarrow> bool" where
"bounded_cs_size sz cs \<equiv> sz < word_bits - cte_level_bits
\<and> bounded_cnode_n sz cs"
text \<open>
Kernel object respects bounds set by its own size. This is only a problem
for cnodes.
\<close>
definition
bounded_ko :: "kernel_object \<Rightarrow> bool" where
"bounded_ko ko = (case ko of CNode sz cs \<Rightarrow> bounded_cs_size sz cs
| _ \<Rightarrow> True)"
subsection \<open>
Types and sizes of abstract kernel objects without checking any
well-formedness.\<close>
text \<open>Like @{term "a_type"}, but don't check wellformed on cnodes\<close>
definition
a_base_type :: "Structures_A.kernel_object \<Rightarrow> a_type" where
"a_base_type ko \<equiv> case ko of
CNode sz cspace \<Rightarrow> ACapTable sz
| TCB tcb \<Rightarrow> ATCB
| Endpoint endpoint \<Rightarrow> AEndpoint
| Notification notification \<Rightarrow> ANTFN
| ArchObj ao \<Rightarrow> AArch (case ao of
PageTable pt \<Rightarrow> APageTable
| PageDirectory pd \<Rightarrow> APageDirectory
| DataPage sz \<Rightarrow> AIntData sz
| Arch_Structs_A.ASIDPool f \<Rightarrow> AASIDPool)"
lemmas a_base_type_simps [simp] =
a_base_type_def [split_simps kernel_object.split arch_kernel_obj.split]
text \<open>
These correspond to @{term "arch_kobj_size"} and @{term "obj_bits"}, but
since we can derive all the information necessary from the type, we use the
type.
We provide abbreviations for convenience;
@{text "a_base_type_bits (a_base_type ...)"} is rather verbose.
\<close>
definition
aa_base_type_bits :: "aa_type \<Rightarrow> nat" where
"aa_base_type_bits t \<equiv>
case t of APageTable \<Rightarrow> 10
| APageDirectory \<Rightarrow> 14
| AIntData sz \<Rightarrow> pageBitsForSize sz
| AASIDPool \<Rightarrow> pageBits"
lemmas aa_base_type_bits_simps [simp] =
aa_base_type_bits_def [split_simps aa_type.split]
definition
a_base_type_bits :: "a_type \<Rightarrow> nat" where
"a_base_type_bits t \<equiv>
case t of ACapTable sz \<Rightarrow> cte_level_bits + sz
| ATCB \<Rightarrow> 9
| AEndpoint \<Rightarrow> 4
| ANTFN \<Rightarrow> 4
| AArch aot \<Rightarrow> aa_base_type_bits aot"
lemmas a_base_type_bits_simps [simp] =
a_base_type_bits_def [split_simps a_type.split]
abbreviation
"t_obj_bits ko \<equiv> a_base_type_bits (a_base_type ko)"
lemmas t_obj_bits_def = a_base_type_bits_def
text \<open>
Whether an index is a valid cnode index for the given type, i.e.\ can we set
that cap to something and end up with a bounded object.
\<close>
definition
abt_valid_cnode_index :: "a_type \<Rightarrow> cnode_index \<Rightarrow> bool" where
"abt_valid_cnode_index atyp i \<equiv> (case atyp
of ACapTable sz \<Rightarrow> length i = sz
| ATCB \<Rightarrow> i \<in> tcb_cnode_index ` {0,1,2,3,4}
| _ \<Rightarrow> False)"
abbreviation
"valid_cnode_index ko \<equiv> abt_valid_cnode_index (a_base_type ko)"
lemmas valid_cnode_index_def = abt_valid_cnode_index_def
subsection \<open>Component structure of objects\<close>
text \<open>
Components available for given object types.
\<close>
text \<open>
What components are available for a given kernel object
(we should see a subset of these in the ghost state).
Note that [] is the ``fields'' component, containing unsplittable information for a
given object, such as non-cap fields of a tcb or all fields of an endpoint.\<close>
primrec
aa_base_type_components :: "aa_type \<Rightarrow> component set" where
"aa_base_type_components AASIDPool = {x. length x = 10}" (* 2^10 components *)
| "aa_base_type_components APageTable = {x. length x = 8}" (* 2^8 components *)
| "aa_base_type_components APageDirectory = {x. length x = 12}" (* 2^12 components *)
| "aa_base_type_components (AIntData sz) = {}" (* no core, type only *)
primrec
a_base_type_components :: "a_type \<Rightarrow> component set" where
"a_base_type_components (ACapTable sz) = {x. length x = sz}"
| "a_base_type_components ATCB = insert [] (tcb_cnode_index ` {0,1,2,3,4})"
(* core & 5 caps *)
| "a_base_type_components AEndpoint = {[]}" (* core only *)
| "a_base_type_components ANTFN = {[]}" (* core only *)
| "a_base_type_components (AArch aot) = aa_base_type_components aot"
abbreviation
"ko_components ko \<equiv> a_base_type_components (a_base_type ko)"
text \<open>Relationship between caps and components.\<close>
(* XXX: see @{text "nat_to_cref"} *)
definition
a_base_type_cmp_of :: "a_type \<Rightarrow> cnode_index \<Rightarrow> component" where
"a_base_type_cmp_of atyp i \<equiv> case atyp of ACapTable _ \<Rightarrow> i
| ATCB \<Rightarrow> i"
abbreviation
"cmp_of ko \<equiv> a_base_type_cmp_of (a_base_type ko)"
subsection \<open>Component-wise Combining of Kernel Objects\<close>
text \<open>
Combining objects of the same type (strictly speaking it's a right override,
although realistically it only makes sense if the first object's components
are disjoint from those of the second). Crucially, NOT DEFINED for two
objects of different types, as that makes no sense whatsoever.\<close>
definition
ao_override :: "arch_kernel_obj \<Rightarrow> arch_kernel_obj \<Rightarrow> component set
\<Rightarrow> arch_kernel_obj" where
"ao_override obj1 obj2 cmps \<equiv>
(case obj1
of ASIDPool o1 \<Rightarrow>
(case obj2 of ASIDPool o2 \<Rightarrow>
ASIDPool (\<lambda>bs. if to_bl bs \<in> cmps then o2 bs else o1 bs))
| PageTable o1 \<Rightarrow>
(case obj2 of PageTable o2 \<Rightarrow>
PageTable (\<lambda>bs. if to_bl bs \<in> cmps then o2 bs else o1 bs))
| PageDirectory o1 \<Rightarrow>
(case obj2 of PageDirectory o2 \<Rightarrow>
PageDirectory (\<lambda>bs. if to_bl bs \<in> cmps then o2 bs else o1 bs))
| DataPage o1 \<Rightarrow> (case obj2 of DataPage o2 \<Rightarrow> DataPage o2))"
(* DataPage has no core, type only *)
definition
tcb_override :: "Structures_A.tcb \<Rightarrow> Structures_A.tcb \<Rightarrow> component set
\<Rightarrow> Structures_A.tcb" where
(* 6 fields counted as "core" (component []), plus 5 caps (tcb_cnode_index 0..4) *)
"tcb_override t1 t2 cmps \<equiv>
t1\<lparr> tcb_state := tcb_state (if [] \<in> cmps then t2 else t1),
tcb_fault_handler := tcb_fault_handler (if [] \<in> cmps then t2 else t1),
tcb_ipc_buffer := tcb_ipc_buffer (if [] \<in> cmps then t2 else t1),
tcb_context := tcb_context (if [] \<in> cmps then t2 else t1),
tcb_fault := tcb_fault (if [] \<in> cmps then t2 else t1),
tcb_bound_notification := tcb_bound_notification (if [] \<in> cmps then t2 else t1),
tcb_ctable := tcb_ctable (if tcb_cnode_index 0 \<in> cmps then t2 else t1),
tcb_vtable := tcb_vtable (if tcb_cnode_index 1 \<in> cmps then t2 else t1),
tcb_reply := tcb_reply (if tcb_cnode_index 2 \<in> cmps then t2 else t1),
tcb_caller := tcb_caller (if tcb_cnode_index 3 \<in> cmps then t2 else t1),
tcb_ipcframe := tcb_ipcframe (if tcb_cnode_index 4 \<in> cmps then t2 else t1)
\<rparr>"
definition
ko_override :: "Structures_A.kernel_object \<Rightarrow> Structures_A.kernel_object
\<Rightarrow> component set \<Rightarrow> Structures_A.kernel_object" where
"ko_override obj1 obj2 cmps =
(case obj1
of CNode sz o1 \<Rightarrow>
(case obj2 of CNode sz2 o2 \<Rightarrow>
CNode sz2 (\<lambda>bs. if bs \<in> cmps then o2 bs else o1 bs))
| TCB o1 \<Rightarrow> (case obj2 of TCB o2 \<Rightarrow> TCB (tcb_override o1 o2 cmps))
| Endpoint o1 \<Rightarrow>
(case obj2 of Endpoint o2 \<Rightarrow>
Endpoint (if [] \<in> cmps then o2 else o1)) (* core only *)
| Notification o1 \<Rightarrow>
(case obj2 of Notification o2 \<Rightarrow>
Notification (if [] \<in> cmps then o2 else o1) (* core only *))
| ArchObj ao1 \<Rightarrow>
(case obj2 of ArchObj ao2 \<Rightarrow> ArchObj (ao_override ao1 ao2 cmps)))"
text \<open>
Object ``cleaning'', i.e. getting the components we don't have into a known
state. Otherwise if we combine @{text "(cnode1,{to_bl 2, to_bl 3})"} and
@{text "(cnode2,{to_bl 4, to_bl 5})"} we don't
know anything about component @{text "to_bl 1"}, and so can't claim commutativity.
Using undefined everywhere, as expected, except for CNodes where
CNode undefined is not necessarily well-formed, which affects its type.
\<close>
definition
ao_clean :: "arch_kernel_obj \<Rightarrow> component set \<Rightarrow> arch_kernel_obj" where
"ao_clean ao cmps \<equiv>
(case ao
of Arch_Structs_A.ASIDPool aobj \<Rightarrow>
ao_override (Arch_Structs_A.ASIDPool undefined) ao cmps
| PageTable aobj \<Rightarrow> ao_override (PageTable undefined) ao cmps
| PageDirectory aobj \<Rightarrow> ao_override (PageDirectory undefined) ao cmps
| DataPage aobj \<Rightarrow> DataPage aobj)" (* type only *)
definition
ko_clean :: "kernel_object \<Rightarrow> component set \<Rightarrow> kernel_object" where
"ko_clean ko cmps \<equiv>
(case ko
of CNode sz obj \<Rightarrow> ko_override (CNode sz empty) ko cmps
| TCB obj \<Rightarrow> ko_override (TCB undefined) ko cmps
| Endpoint obj \<Rightarrow> ko_override (Endpoint undefined) ko cmps
| Notification obj \<Rightarrow> ko_override (Notification undefined) ko cmps
| ArchObj obj \<Rightarrow> ArchObj (ao_clean obj cmps))"
text \<open>Combining objects\<close>
definition
ko_combine :: "(kernel_object \<times> component set)
\<Rightarrow> (kernel_object \<times> component set)
\<Rightarrow> (kernel_object \<times> component set)" where
"ko_combine kcmp1 kcmp2 \<equiv>
(case kcmp1 of (o1,cs1) \<Rightarrow> (case kcmp2 of (o2,cs2) \<Rightarrow>
(ko_override (ko_clean o1 cs1) (ko_clean o2 cs2) cs2, cs1 \<union> cs2)))"
text \<open>Updating a cap in a specific kernel object\<close>
text \<open>
This is the non-monadic counterpart to @{term set_cap_local}.
We use silent failure here, since we want generic lemmas to hold, such
as that @{term set_ko_cap} preserves the kernel object type. If we returned
undefined, we can't prove those without the extra assumption everywhere that
@{term "cap_of ko i = Some c"}.
\<close>
definition (* non-monadic counterpart to set_cap(_local) *)
set_ko_cap :: "kernel_object \<Rightarrow> cnode_index \<Rightarrow> cap \<Rightarrow> kernel_object" where
"set_ko_cap ko i cap \<equiv>
(case ko of CNode sz cn \<Rightarrow> CNode sz (cn(i \<mapsto> cap))
| TCB tcb \<Rightarrow>
(if i = tcb_cnode_index 0 then
TCB $ tcb \<lparr> tcb_ctable := cap \<rparr>
else if i = tcb_cnode_index 1 then
TCB $ tcb \<lparr> tcb_vtable := cap \<rparr>
else if i = tcb_cnode_index 2 then
TCB $ tcb \<lparr> tcb_reply := cap \<rparr>
else if i = tcb_cnode_index 3 then
TCB $ tcb \<lparr> tcb_caller := cap \<rparr>
else if i = tcb_cnode_index 4 then
TCB $ tcb \<lparr> tcb_ipcframe := cap \<rparr>
else
ko)
| _ \<Rightarrow> ko)"
subsection \<open>Object-component Maps\<close>
text \<open>
When we annotate the abstract kernel heap with the components of kernel
objects we are allowed to access at each address, we get an
object-component map. This map is the core of the separation logic, since
it allows us to perform local reasoning beyond the granularity of a kernel
object. In other words, if we have a kernel object at address p in two
kheaps, we can still call the heaps disjoint if they are annotated with
disjoint components.
In lemmas, ``object-component map'' is typically abbreviated to ``ocm''.
\<close>
type_synonym
obj_comp_map = "paddr \<rightharpoonup> (kernel_object \<times> component set)"
definition
ko_has_cap :: "kernel_object \<Rightarrow> component set \<Rightarrow> cnode_index \<Rightarrow> cap \<Rightarrow> bool"
where
"ko_has_cap ko cmps i c \<equiv> cap_of (ko_clean ko cmps) i = Some c \<and>
(cmp_of ko i) \<in> cmps"
definition
"ocm_has_cap ocm p ko cmps i c \<equiv> ocm p = Some (ko, cmps) \<and>
ko_has_cap ko cmps i c"
definition
obj_comp_map_add :: "obj_comp_map \<Rightarrow> obj_comp_map \<Rightarrow> obj_comp_map" where
"obj_comp_map_add h1 h2 \<equiv>
(\<lambda>p. (case h1 p
of Some oc1 \<Rightarrow> (case h2 p
of Some oc2 \<Rightarrow> Some (ko_combine oc1 oc2)
| None \<Rightarrow> Some oc1)
| None \<Rightarrow> h2 p))"
text \<open>
Disjunction (per address):
If it's in one heap but not the other (or in neither),
consider the object maps disjoint.
Looking at the objects through only the components we have:
If the objects have different types, they are not disjoint.
If the objects have the same type, but the different heaps cover different
components, then they are disjoint.
Exceptions to the above when both objects have the same type:
If an object is structurally unsound (i.e. is a cnode with entries not of
the right length), we treat the component coverage as if it was
@{term "UNIV"}.
If a component set is either @{term "{}"} or includes components outside
of sane values for the given object type, we treat it as @{term "UNIV"}.
We need the exceptions in order to be able to define a predicate that says
``we have the entire object and all information about it'', and be able to
detype/retype this object while preserving the frame rule. If we can
construct anything separate from the entire object that also talks about the
object's type, we cannot prove the frame rule. This means no objects with no
components or ficticious components (they convey no information except the
object type at that address). This also means no magical cnodes where a
cnode of size 2 can suddenly develop a entry over 9000.
\<close>
definition
"sane_components ko cmps \<equiv> bounded_ko ko \<and> cmps \<noteq> {}
\<and> cmps \<subseteq> ko_components ko"
definition
"check_components ko cmps \<equiv> if sane_components ko cmps then cmps else UNIV"
definition
obj_comp_map_disj :: "obj_comp_map \<Rightarrow> obj_comp_map \<Rightarrow> bool" where
"obj_comp_map_disj h1 h2 \<equiv>
(\<forall>p. case (h1 p, h2 p)
of (Some (o1,c1), Some (o2,c2))
\<Rightarrow> a_base_type o1 = a_base_type o2
\<and> check_components (ko_clean o1 c1) c1
\<inter> check_components (ko_clean o2 c2) c2 = {}
| _ \<Rightarrow> True)"
subsection \<open>
State used for separation algebra; encompasses the object-component map, as well as free and available memory.
\<close>
datatype sep_state = SepState obj_comp_map "obj_ref set" "obj_ref set"
(* comp. map free mem avail mem *)
type_synonym
sep_assert = "sep_state \<Rightarrow> bool"
translations
(type) "sep_assert" <= (type) "sep_state \<Rightarrow> bool"
text \<open>SepState accessors\<close>
definition
sep_state_ocm :: "sep_state \<Rightarrow> obj_comp_map" where
"sep_state_ocm s \<equiv> case s of SepState ocm _ _ \<Rightarrow> ocm"
definition
sep_state_free :: "sep_state \<Rightarrow> obj_ref set" where
"sep_state_free s \<equiv> case s of SepState _ free _ \<Rightarrow> free"
definition
sep_state_avail :: "sep_state \<Rightarrow> obj_ref set" where
"sep_state_avail s \<equiv> case s of SepState _ _ avail \<Rightarrow> avail"
lemmas sep_state_accessors =
sep_state_ocm_def sep_state_free_def sep_state_avail_def
definition
lift_sep_state :: "'z ki_state \<Rightarrow> sep_state" where
"lift_sep_state ki \<equiv>
let kh = kheap (ki_kernel_state ki)
in SepState (\<lambda>p. case kh p
of Some obj \<Rightarrow> Some (ko_clean obj (ki_components ki p),
ki_components ki p)
| _ \<Rightarrow> None)
(ki_free_mem ki)
(ki_available_mem ki)"
text \<open>
Lifting a kernel state @{text "s"} onto an existing kernel init state
@{text "kis"}.\<close>
abbreviation
"kis_lift kis s \<equiv> lift_sep_state (kis\<lparr>ki_kernel_state := s\<rparr>)"
definition
kheap_shadow :: "obj_comp_map \<Rightarrow> paddr \<Rightarrow> paddr set" where
"kheap_shadow kh p \<equiv>
set (len_seq (p+1) (2 ^ t_obj_bits (fst (the (kh p))) - 1))"
definition
"kheap_shadows kh \<equiv> \<Union>(kheap_shadow kh ` dom kh)"
text \<open>Addresses used up by objects in the kernel heap\<close>
definition
kheap_dom :: "(obj_comp_map) \<Rightarrow> paddr set" where
"kheap_dom kh \<equiv> dom kh \<union> kheap_shadows kh"
definition
sep_disj :: "sep_state \<Rightarrow> sep_state \<Rightarrow> bool" where
(* if we try to combine two sane heaps, a region can't end up being:
- free in one and available in the other
- free/available in one and in the heap in the other
- in both heaps with the same component
- an object in one heap and a shadow (the Nones that follow an object
until its last memory address) in the other
*)
"sep_disj s1 s2 =
(case s1 of SepState kh1 free1 avail1 \<Rightarrow>
(case s2 of SepState kh2 free2 avail2 \<Rightarrow>
((free1 \<union> avail1) \<inter> (free2 \<union> avail2) = {} \<and>
kheap_dom kh1 \<inter> (free2 \<union> avail2) = {} \<and>
kheap_dom kh2 \<inter> (free1 \<union> avail1) = {} \<and>
obj_comp_map_disj kh1 kh2 \<and>
kheap_shadows kh1 \<inter> dom kh2 = {} \<and>
kheap_shadows kh2 \<inter> dom kh1 = {}) ))"
definition
sep_add :: "sep_state \<Rightarrow> sep_state \<Rightarrow> sep_state" where
"sep_add s1 s2 =
(case s1 of SepState kh1 free1 avail1 \<Rightarrow>
(case s2 of SepState kh2 free2 avail2 \<Rightarrow>
SepState (obj_comp_map_add kh1 kh2) (free1 \<union> free2) (avail1 \<union> avail2)
))"
definition
sep_empty :: "sep_state" where
"sep_empty = SepState empty {} {}"
subsection \<open>Maps-to Predicates\<close>
text \<open>pretty raw function to talk about a single object's components at a given address\<close>
definition
sep_map_base :: "paddr \<Rightarrow> kernel_object \<Rightarrow> component set \<Rightarrow> sep_assert" where
"sep_map_base p ko cmps s \<equiv> (case s of SepState ocm free avail \<Rightarrow>
ocm p = Some (ko_clean ko cmps, cmps) \<and>
sane_components (ko_clean ko cmps) cmps \<and>
dom ocm = {p} \<and> (* sep_conj takes care of shadow intersections *)
is_aligned p (t_obj_bits ko) \<and>
free = {} \<and>
avail = {})"
(* XXX: can this be the same as the empty assertion when cmps = {}? *)
text \<open>same thing, but talking about the entire object at an address\<close>
definition
sep_map_ko :: "paddr \<Rightarrow> kernel_object \<Rightarrow> sep_assert" where
"sep_map_ko p ko \<equiv> sep_map_base p ko (ko_components ko)"
text \<open>
An object of the specified type with a set cap. We need to specify the type
in order to be able to reassemble cnodes, and also to not have to prove
things such as that @{const set_cap} doesn't change the object's type.\<close>
definition
sep_map_cap :: "a_type \<Rightarrow> cslot_ptr \<Rightarrow> cap \<Rightarrow> sep_assert" where
"sep_map_cap atyp cptr cap \<equiv> case cptr of (p,i) \<Rightarrow>
(\<lambda>s. \<exists>ko. sep_map_base p ko {cmp_of ko i} s \<and>
a_base_type ko = atyp \<and>
cap_of ko i = Some cap)"
text \<open>declaring a region of memory is free (unallocated)\<close>
definition
sep_free :: "paddr \<Rightarrow> nat \<Rightarrow> sep_assert" where
"sep_free p sz s = (case s of SepState ocm free avail \<Rightarrow>
(dom ocm = {} \<and> free = set (len_seq p sz) \<and> avail = {}))"
text \<open>declaring a region of memory is available (allocated but untyped)\<close>
definition
sep_available :: "paddr \<Rightarrow> nat \<Rightarrow> sep_assert" where
"sep_available p sz s = (case s of SepState ocm free avail \<Rightarrow>
(dom ocm = {} \<and> free = {} \<and> avail = set (len_seq p sz)))"
subsection \<open>Cap-level Updates of the Kernel Init State\<close>
text \<open>
The @{term sep_update_cap} function is equivalent to what
@{term set_cap_local} does at the monadic kernel state level, but phrased
non-monadically and more conveniently for the separation state level.
\<close>
definition
sep_update_cap :: "cslot_ptr \<Rightarrow> cap \<Rightarrow> sep_state \<Rightarrow> sep_state" where
"sep_update_cap cp cap s \<equiv> (case cp of (p,i) \<Rightarrow>
(case s of SepState ocm f a \<Rightarrow>
SepState (ocm(p \<mapsto> (set_ko_cap (fst (the (ocm p))) i cap,
snd (the (ocm p))))) f a ))"
section \<open>Proofs\<close> (* ------------------------------------------------- *)
subsection \<open>Component structure of objects\<close>
lemma bounded_ko_t_obj_bits:
"bounded_ko ko \<Longrightarrow> t_obj_bits ko < word_bits"
by (clarsimp simp: bounded_ko_def cte_level_bits_def word_bits_def
bounded_cs_size_def a_base_type_bits_def a_base_type_def
pageBitsForSize_def pageBits_def
split: kernel_object.splits arch_kernel_obj.splits
vmpage_size.splits)
lemma tcb_eq: (* so the simplifier doesn't barf on tcb_override_commute *)
"\<lbrakk> tcb_state (tcb1::Structures_A.tcb) = tcb_state (tcb2::Structures_A.tcb) ;
tcb_fault_handler tcb1 = tcb_fault_handler tcb2 ;
tcb_ipc_buffer tcb1 = tcb_ipc_buffer tcb2 ;
tcb_context tcb1 = tcb_context tcb2 ;
tcb_fault tcb1 = tcb_fault tcb2 ;
tcb_ctable tcb1 = tcb_ctable tcb2 ;
tcb_vtable tcb1 = tcb_vtable tcb2 ;
tcb_reply tcb1 = tcb_reply tcb2 ;
tcb_caller tcb1 = tcb_caller tcb2 ;
tcb_ipcframe tcb1 = tcb_ipcframe tcb2 ;
tcb_bound_notification tcb1 = tcb_bound_notification tcb2 \<rbrakk> \<Longrightarrow> tcb1 = tcb2"
by (cases tcb1, cases tcb2) auto
lemma tcb_cnode_index_not_Nil:
"tcb_cnode_index i \<noteq> []"
by (clarsimp simp: tcb_cnode_index_def)
lemma tcb_cnode_index_Nil_False [simp]:
"(tcb_cnode_index i = []) = False"
"([] = tcb_cnode_index i) = False"
by (auto simp: tcb_cnode_index_not_Nil tcb_cnode_index_not_Nil[symmetric])
subsection \<open>Component-wise Combining of Kernel Objects\<close>
lemma tcb_override_index_simps:
"tcb_override tcb tcb' {tcb_cnode_index 0}
= tcb \<lparr>tcb_ctable := tcb_ctable tcb'\<rparr>"
"tcb_override tcb tcb' {tcb_cnode_index (Suc 0)}
= tcb \<lparr>tcb_vtable := tcb_vtable tcb'\<rparr>"
"tcb_override tcb tcb' {tcb_cnode_index 2}
= tcb \<lparr>tcb_reply := tcb_reply tcb'\<rparr>"
"tcb_override tcb tcb' {tcb_cnode_index 3}
= tcb \<lparr>tcb_caller := tcb_caller tcb'\<rparr>"
"tcb_override tcb tcb' {tcb_cnode_index 4}
= tcb \<lparr>tcb_ipcframe := tcb_ipcframe tcb'\<rparr>"
by (simp_all add: tcb_override_def)
lemma tcb_field_cmp_right_simps:
"[] \<in> cmps \<Longrightarrow> tcb_state (tcb_override tcb tcb' cmps) = tcb_state tcb'"
"[] \<in> cmps \<Longrightarrow> tcb_fault_handler (tcb_override tcb tcb' cmps)
= tcb_fault_handler tcb'"
"[] \<in> cmps \<Longrightarrow> tcb_ipc_buffer (tcb_override tcb tcb' cmps)
= tcb_ipc_buffer tcb'"
"[] \<in> cmps \<Longrightarrow> tcb_context (tcb_override tcb tcb' cmps)
= tcb_context tcb'"
"[] \<in> cmps \<Longrightarrow> tcb_fault (tcb_override tcb tcb' cmps)
= tcb_fault tcb'"
"[] \<in> cmps \<Longrightarrow> tcb_bound_notification (tcb_override tcb tcb' cmps) = tcb_bound_notification tcb'"
"tcb_cnode_index 0 \<in> cmps \<Longrightarrow> tcb_ctable (tcb_override tcb tcb' cmps)
= tcb_ctable tcb'"
"tcb_cnode_index (Suc 0) \<in> cmps \<Longrightarrow> tcb_vtable (tcb_override tcb tcb' cmps)
= tcb_vtable tcb'"
"tcb_cnode_index 2 \<in> cmps \<Longrightarrow> tcb_reply (tcb_override tcb tcb' cmps)
= tcb_reply tcb'"
"tcb_cnode_index 3 \<in> cmps \<Longrightarrow> tcb_caller (tcb_override tcb tcb' cmps)
= tcb_caller tcb'"
"tcb_cnode_index 4 \<in> cmps \<Longrightarrow> tcb_ipcframe (tcb_override tcb tcb' cmps)
= tcb_ipcframe tcb'"
by (simp_all add: tcb_override_def)
lemma tcb_override_index_cmps_simps:
"tcb_cnode_index 0 \<in> cmps
\<Longrightarrow> tcb_override ko (ko'\<lparr>tcb_ctable := cap\<rparr>) cmps
= tcb_override ko ko' cmps \<lparr>tcb_ctable := cap\<rparr>"
"tcb_cnode_index (Suc 0) \<in> cmps
\<Longrightarrow> tcb_override ko (ko'\<lparr>tcb_vtable := cap\<rparr>) cmps
= tcb_override ko ko' cmps \<lparr>tcb_vtable := cap\<rparr>"
"tcb_cnode_index 2 \<in> cmps
\<Longrightarrow> tcb_override ko (ko'\<lparr>tcb_reply := cap\<rparr>) cmps
= tcb_override ko ko' cmps \<lparr>tcb_reply := cap\<rparr>"
"tcb_cnode_index 3 \<in> cmps
\<Longrightarrow> tcb_override ko (ko'\<lparr>tcb_caller := cap\<rparr>) cmps
= tcb_override ko ko' cmps \<lparr>tcb_caller := cap\<rparr>"
"tcb_cnode_index 4 \<in> cmps
\<Longrightarrow> tcb_override ko (ko'\<lparr>tcb_ipcframe := cap\<rparr>) cmps
= tcb_override ko ko' cmps \<lparr>tcb_ipcframe := cap\<rparr>"
by (simp_all add: tcb_override_def)
lemma tcb_override_index_sub_cmps_simps:
"tcb_override ko ko' (cmps - {tcb_cnode_index 0}) \<lparr> tcb_ctable := cap \<rparr>
= tcb_override ko ko' cmps \<lparr> tcb_ctable := cap \<rparr>"
"tcb_override ko ko' (cmps - {tcb_cnode_index (Suc 0)}) \<lparr> tcb_vtable := cap \<rparr>
= tcb_override ko ko' cmps \<lparr> tcb_vtable := cap \<rparr>"
"tcb_override ko ko' (cmps - {tcb_cnode_index 2}) \<lparr> tcb_reply := cap \<rparr>
= tcb_override ko ko' cmps \<lparr> tcb_reply := cap \<rparr>"
"tcb_override ko ko' (cmps - {tcb_cnode_index 3}) \<lparr> tcb_caller := cap \<rparr>
= tcb_override ko ko' cmps \<lparr> tcb_caller := cap \<rparr>"
"tcb_override ko ko' (cmps - {tcb_cnode_index 4}) \<lparr> tcb_ipcframe := cap \<rparr>
= tcb_override ko ko' cmps \<lparr> tcb_ipcframe := cap \<rparr>"
by (simp_all add: tcb_override_def)
text \<open>
Unfolding @{text tcb_override_def} the index is known is a really bad idea
in terms of simplifier performance in actual lemmas. These rules help avoid
that scenario.\<close>
lemmas tcb_override_index_assist = tcb_override_index_simps
tcb_override_index_cmps_simps tcb_override_index_sub_cmps_simps
tcb_field_cmp_right_simps
lemma ko_clean_preserves_type [simp]:
"a_base_type (ko_clean ko cmps) = a_base_type ko"
by (auto simp: ko_clean_def ko_override_def ao_clean_def ao_override_def
split: kernel_object.splits arch_kernel_obj.splits)
lemma t_obj_bits_ko_clean_simp [simp]:
"t_obj_bits (ko_clean ko cmps) = t_obj_bits ko"
by (clarsimp split: Structures_A.kernel_object.splits arch_kernel_obj.splits)
lemma ko_components_ko_clean_simp [simp]:
"ko_components (ko_clean ko cmps) = ko_components ko"
by (clarsimp split: Structures_A.kernel_object.splits arch_kernel_obj.splits)
lemma ko_override_a_base_type [simp]:
"a_base_type o1 = a_base_type o2
\<Longrightarrow> a_base_type (ko_override o1 o2 c2) = a_base_type o2"
by (clarsimp simp: a_base_type_def ko_override_def ao_override_def
split: kernel_object.splits arch_kernel_obj.splits)
lemma ao_clean_twice [simp]:
"ao_clean (ao_clean ao cmps) cmps = ao_clean ao cmps"
by (fastforce split: arch_kernel_obj.splits
simp: ao_clean_def ao_override_def)
lemma ko_clean_twice_subset:
"\<lbrakk> cmps' \<subseteq> cmps \<rbrakk> \<Longrightarrow> ko_clean (ko_clean ko cmps) cmps' = ko_clean ko cmps'"
apply (clarsimp simp: ko_clean_def ao_clean_def ko_override_def
ao_override_def
split: kernel_object.splits arch_kernel_obj.splits)
apply (fastforce intro!: tcb_eq simp: tcb_override_def)
done
lemma ko_clean_twice [simp]:
"ko_clean (ko_clean ko cmps) cmps = ko_clean ko cmps"
by (simp add: ko_clean_twice_subset)
lemma ko_clean_id:
"bounded_ko ko \<Longrightarrow> ko_clean ko (ko_components ko) = ko"
apply (clarsimp simp: ko_clean_def ko_override_def ao_clean_def
ao_override_def bounded_ko_def
split: kernel_object.splits arch_kernel_obj.splits)
apply (clarsimp intro!: ext simp: bounded_cs_size_def bounded_cnode_n_def)
apply (case_tac "fun bs", simp, clarsimp simp: unat_of_bl_length dom_def)
apply (fastforce intro!: tcb_eq simp: tcb_override_index_assist)
done
lemma ko_clean_ko_override_id:
"\<lbrakk> a_base_type ko = a_base_type ko' ; cmps \<inter> cmps' = {} \<rbrakk>
\<Longrightarrow> ko_clean (ko_override ko ko' cmps) cmps' = ko_clean ko cmps'"
apply (cases ko)
apply (simp_all add: ko_clean_def ko_override_def a_base_type_def
split: kernel_object.splits)
apply fastforce
apply (rule tcb_eq | fastforce simp: tcb_override_def)+
apply (case_tac arch_kernel_obj)
apply (fastforce split: arch_kernel_obj.splits
simp: ao_clean_def ao_override_def)+
done
lemma ao_override_pull_out_ao_clean [simp]:
"\<lbrakk> a_base_type (ArchObj ao1) = a_base_type (ArchObj ao2) \<rbrakk>
\<Longrightarrow> ao_override (ao_clean ao1 cmps1) ao2 cmps2
= ao_clean (ao_override ao1 ao2 cmps2) (cmps1 \<union> cmps2)"
by (auto simp: ao_clean_def ao_override_def
split: arch_kernel_obj.splits)
lemma ko_override_pull_out_ko_clean [simp]:
"\<lbrakk> a_base_type ko1 = a_base_type ko2 \<rbrakk>
\<Longrightarrow> ko_override (ko_clean ko1 cmps1) ko2 cmps2
= ko_clean (ko_override ko1 ko2 cmps2) (cmps1 \<union> cmps2)"
by (clarsimp simp: ko_clean_def ko_override_def a_base_type_def
split: kernel_object.splits)
(auto simp: tcb_override_def)
lemma ko_override_ko_clean_right [simp]:
"\<lbrakk> a_base_type ko1 = a_base_type ko2 \<rbrakk>
\<Longrightarrow> (ko_override ko1 (ko_clean ko2 cmps2) cmps2)
= (ko_override ko1 ko2 cmps2) "
apply (clarsimp simp: ko_clean_def ko_override_def a_base_type_def
split: kernel_object.splits)
apply (fastforce simp: tcb_override_def)+
apply (fastforce simp: ao_override_def ao_clean_def
split: arch_kernel_obj.splits)
done
lemma ko_override_self [simp]:
"ko_override ko ko cmps = ko"
by (cases ko)
(auto simp: ko_override_def tcb_override_def ao_override_def
split: arch_kernel_obj.splits)
lemma cap_of_ko_cleanD:
"\<lbrakk> cap_of (ko_clean ko cmps) i = Some c ; (cmp_of ko i) \<in> cmps \<rbrakk>
\<Longrightarrow> cap_of ko i = Some c"
unfolding cap_of_def ko_clean_def
by (clarsimp simp: ko_override_def a_base_type_cmp_of_def tcb_cnode_map_def
tcb_override_index_assist
split: kernel_object.splits option.splits if_split_asm)
lemma cap_of_ko_clean_contained_cap:
"cmp_of ko i \<in> cmps
\<Longrightarrow> cap_of (ko_clean ko cmps) i = cap_of ko i"
unfolding cap_of_def ko_clean_def
by (clarsimp simp: ko_override_def a_base_type_cmp_of_def
split: kernel_object.splits)
(fastforce simp: tcb_cnode_map_def a_base_type_cmp_of_def
tcb_override_index_assist)
lemma cap_of_ko_clean_same_cap [simp]:
"cap_of (ko_clean ko {cmp_of ko i}) i = cap_of ko i"
by (clarsimp simp: cap_of_ko_clean_contained_cap)
lemma ko_clean_one_cap_eq:
"\<lbrakk> cap_of ko i = Some cap ; cap_of ko' i = Some cap ;
a_base_type ko = a_base_type ko' ;
cmp = {cmp_of ko' i} \<rbrakk>
\<Longrightarrow> ko_clean ko cmp = ko_clean ko' cmp"
apply (clarsimp simp: ko_clean_def a_base_type_def cap_of_def
split: kernel_object.splits)
apply (fastforce simp: ko_override_def a_base_type_cmp_of_def
split: if_split_asm)
apply (clarsimp simp: tcb_cnode_map_def a_base_type_cmp_of_def
ko_override_def tcb_override_index_assist
split: if_split_asm)
done
lemma tcb_override_commute:
"c1 \<inter> c2 = {}
\<Longrightarrow> tcb_override (tcb_override undefined tcb1 c1)
(tcb_override undefined tcb2 c2) c2
= tcb_override (tcb_override undefined tcb2 c2)
(tcb_override undefined tcb1 c1) c1"
by (rule tcb_eq)
(fastforce simp: tcb_override_def)+
lemma tcb_override_assoc:
"tcb_override (tcb_override (a::Structures_A.tcb) b cs1) c cs2
= tcb_override a (tcb_override b c cs2) (cs1 \<union> cs2)"
by (fastforce simp: tcb_override_def)
lemma tcb_override_twice_same [simp]:
"tcb_override x (tcb_override (x::Structures_A.tcb) y cmps) cmps =
tcb_override x y cmps"
by (fastforce simp: tcb_override_def intro!: tcb_eq)
lemma tcb_cnode_map_tcb_override_left:
"i \<notin> cmps
\<Longrightarrow> tcb_cnode_map (tcb_override tcb tcb' cmps) i = tcb_cnode_map tcb i"
apply (clarsimp simp: tcb_cnode_map_def tcb_override_def
split: if_split_asm option.splits)
apply (rule conjI | clarsimp simp: eval_nat_numeral)+
done
lemma tcb_cnode_map_tcb_override_right:
"i \<in> cmps
\<Longrightarrow> tcb_cnode_map (tcb_override tcb tcb' cmps) i = tcb_cnode_map tcb' i"
by (fastforce simp: tcb_cnode_map_def tcb_override_index_assist
split: if_split_asm option.splits)
lemmas tcb_cnode_map_tcb_overrides = tcb_cnode_map_tcb_override_right
tcb_cnode_map_tcb_override_left
lemma cap_of_ko_override_left:
"\<lbrakk> cmp_of ko i \<notin> cmps ; a_base_type ko = a_base_type ko' \<rbrakk>
\<Longrightarrow> cap_of (ko_override ko ko' cmps) i = cap_of ko i"
by (clarsimp simp: a_base_type_def cap_of_def ko_clean_def
ko_override_def a_base_type_cmp_of_def
tcb_cnode_map_tcb_overrides
split: kernel_object.splits option.splits)
lemma cap_of_ko_override_right:
"\<lbrakk> cmp_of ko i \<in> cmps ; a_base_type ko = a_base_type ko' \<rbrakk>
\<Longrightarrow> cap_of (ko_override ko ko' cmps) i = cap_of ko' i"
by (clarsimp simp: a_base_type_def cap_of_def ko_clean_def
ko_override_def a_base_type_cmp_of_def
tcb_cnode_map_tcb_overrides
split: kernel_object.splits option.splits)
lemmas cap_of_ko_overrides = cap_of_ko_override_right cap_of_ko_override_left
lemma cap_of_ko_clean:
"\<lbrakk> cmp_of ko i \<in> cmps \<rbrakk>
\<Longrightarrow> cap_of (ko_clean ko cmps) i = cap_of ko i"
by (clarsimp simp: cap_of_def ko_clean_def a_base_type_cmp_of_def
ko_override_def
a_base_type_def tcb_cnode_map_tcb_overrides
split: kernel_object.splits)+
lemma bounded_ko_clean:
"bounded_ko ko \<Longrightarrow> bounded_ko (ko_clean ko cmps)"
by (auto simp: bounded_ko_def ko_clean_def ko_override_def
bounded_cs_size_def bounded_cnode_n_def
split: kernel_object.splits if_split_asm)
lemma bounded_ko_override:
"\<lbrakk> bounded_ko o1 ; bounded_ko o2 ; a_base_type o1 = a_base_type o2 \<rbrakk>
\<Longrightarrow> bounded_ko (ko_override o1 o2 cmps)"
by (fastforce simp: bounded_ko_def ko_override_def bounded_cs_size_def
a_base_type_def bounded_cnode_n_def
split: kernel_object.splits if_split_asm)
lemma bounded_ko_clean_ko_override:
"\<lbrakk> bounded_ko (ko_clean o1 c1) ; bounded_ko (ko_clean o2 c2) ;
a_base_type o1 = a_base_type o2\<rbrakk>
\<Longrightarrow> bounded_ko (ko_clean (ko_override o1 o2 c2) (c1 \<union> c2))"
by (fastforce simp: bounded_ko_def ko_clean_def ko_override_def
a_base_type_def bounded_cs_size_def bounded_cnode_n_def
split: kernel_object.splits option.splits if_split_asm)
(* XXX: long-running proof *)
lemma sane_components_ko_clean_ko_override:
"\<lbrakk> sane_components (ko_clean o1 c1) c1 ; sane_components (ko_clean o2 c2) c2;
a_base_type o1 = a_base_type o2 \<rbrakk>
\<Longrightarrow> sane_components (ko_clean (ko_override o1 o2 c2) (c1 \<union> c2)) (c1 \<union> c2)"
by (clarsimp simp: sane_components_def bounded_ko_clean_ko_override)
lemma bounded_ko_clean_ko_overrideD:
"\<lbrakk> bounded_ko (ko_clean (ko_override o1 o2 c2) (c1 \<union> c2)) ;
c1 \<inter> c2 = {} ; a_base_type o1 = a_base_type o2 \<rbrakk>
\<Longrightarrow> bounded_ko (ko_clean o1 c1) \<and> bounded_ko (ko_clean o2 c2)"
by (fastforce simp: bounded_ko_def a_base_type_def ko_clean_def
ko_override_def bounded_cs_size_def bounded_cnode_n_def
split: kernel_object.splits if_split_asm)
lemma sane_components_ko_clean_ko_overrideD:
"\<lbrakk> sane_components (ko_clean (ko_override o1 o2 c2) (c1 \<union> c2)) (c1 \<union> c2) ;
c1 \<inter> c2 = {} ; c1 \<noteq> {} ; c2 \<noteq> {} ; a_base_type o1 = a_base_type o2 \<rbrakk>
\<Longrightarrow> sane_components (ko_clean o1 c1) c1 \<and>
sane_components (ko_clean o2 c2) c2"
by (fastforce simp: sane_components_def dest!: bounded_ko_clean_ko_overrideD)
lemma ko_override_assoc:
"\<lbrakk> a_base_type o1 = a_base_type o2 ; a_base_type o2 = a_base_type o3 \<rbrakk>
\<Longrightarrow> ko_override (ko_override o1 o2 cs1) o3 cs2
= ko_override o1 (ko_override o2 o3 cs2) (cs1 \<union> cs2)"
unfolding a_base_type_def
apply (clarsimp split: kernel_object.splits)
apply (clarsimp intro!: ext simp: ko_override_def tcb_override_assoc)+
apply (clarsimp split: arch_kernel_obj.splits)
apply (clarsimp intro!: ext simp: ao_override_def)+
done
lemma ko_combine_assoc:
"\<lbrakk> a_base_type o1 = a_base_type o2 ; a_base_type o2 = a_base_type o3 \<rbrakk>
\<Longrightarrow> ko_combine (ko_combine (o1,c1) (o2,c2)) (o3,c3)
= ko_combine (o1,c1) (ko_combine (o2,c2) (o3,c3))"
by (clarsimp simp: ko_combine_def ko_override_assoc Un_assoc)
lemma ko_combine_commute:
"\<lbrakk> check_components (ko_clean o1 c1) c1
\<inter> check_components (ko_clean o2 c2) c2 = {} ;
a_base_type o1 = a_base_type o2 \<rbrakk>
\<Longrightarrow> ko_combine (o1,c1) (o2,c2) = ko_combine (o2,c2) (o1,c1)"
unfolding ko_combine_def
by (clarsimp simp: Un_commute ko_override_def ko_clean_def