Section Invariants.
Definition get_sys_ret (st : RData) :=
let curid := ZMap.get st.(CPU_ID) st.(cid) in
ZMap.get U_EBX (ZMap.get curid st.(uctxt)).
Definition get_sys_arg1 (st : RData) :=
let curid := ZMap.get st.(CPU_ID) st.(cid) in
ZMap.get U_EBX (ZMap.get curid st.(uctxt)).
Definition get_sys_arg2 (st : RData) :=
let curid := ZMap.get st.(CPU_ID) st.(cid) in
ZMap.get U_EBX (ZMap.get curid st.(uctxt)).
Fixpoint compute_console' (tr : ostrace) : list (Z * Z * nat) :=
match tr with
| nil => nil
| ev :: tr' =>
let cons := compute_console' tr' in
match ev with
| IOEvRecv logIdx strIdx c =>
let cons' := if Zlength cons <? CONS_BUFFER_MAX_CHARS then cons else tl cons in
cons' ++ (c, logIdx, strIdx) :: nil
| IOEvGetc _ _ _ => tl cons
| _ => cons
end
end.
Definition compute_console tr := compute_console' (rev tr).
(* Everything in the trace was put there by the serial device. *)
Definition valid_trace_serial tr lrx :=
forall logIdx strIdx c pre post,
tr = pre ++ IOEvRecv logIdx strIdx c :: post ->
logIdx < lrx - 1 /\
match SerialEnv logIdx with
| SerialRecv str => nth_error str strIdx = Some c
| _ => False
end.
(* OS reads are ordered lexicographically by logIdx and strIdx. *)
Definition valid_trace_ordered tr :=
forall post mid pre logIdx strIdx c logIdx' strIdx' c',
tr = pre ++ IOEvRecv logIdx strIdx c :: mid ++ IOEvRecv logIdx' strIdx' c' :: post ->
(logIdx, Z.of_nat strIdx) <l (logIdx', Z.of_nat strIdx').
(* Every user read has a matching OS read earlier in the trace. *)
Definition valid_trace_user tr :=
forall logIdx strIdx c pre post,
tr = pre ++ IOEvGetc logIdx strIdx c :: post ->
In (IOEvRecv logIdx strIdx c) pre /\ hd_error (compute_console pre) = Some (c, logIdx, strIdx).
(* Every read event in the trace is unique. *)
Definition valid_trace_unique (tr : ostrace) :=
let tr' := filter (fun ev =>
match ev with | IOEvRecv _ _ _ | IOEvGetc _ _ _ => true | _ => false end) tr in
NoDup tr'.
(* The console matches compute_console. *)
Definition valid_trace_console tr cons := cons = compute_console tr.
(* All trace invariants hold. *)
Record valid_trace (st : RData) := {
vt_trace_serial : valid_trace_serial st.(io_log) st.(com1).(l1);
vt_trace_ordered : valid_trace_ordered st.(io_log);
vt_trace_user : valid_trace_user st.(io_log);
vt_trace_unique : valid_trace_unique st.(io_log);
vt_trace_console : valid_trace_console st.(io_log) st.(console).(cons_buf);
}.
Local Hint Resolve valid_trace_ordered_snoc valid_trace_ordered_app.

Corollary compute_console_app_no_space : forall evs tr,
let cons := compute_console tr in
let skip := Zlength cons + Zlength evs - CONS_BUFFER_MAX_CHARS in
(forall ev, In ev evs -> exists logIdx strIdx c, ev = IOEvRecv logIdx strIdx c) ->
Zlength cons <= CONS_BUFFER_MAX_CHARS ->
Zlength cons + Zlength evs > CONS_BUFFER_MAX_CHARS ->
compute_console (tr ++ evs) =
skipn (Z.to_nat skip) (cons ++ (map (fun ev =>
match ev with
| IOEvRecv logIdx strIdx c => (c, logIdx, strIdx)
| _ => (0, 0, O) (* impossible *)
end) evs)).