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.
(** Trace Invariants Preserved *)
(* Specs: serial_intr_enable_spec serial_intr_disable_spec thread_serial_intr_enable_spec thread_serial_intr_disable_spec uctx_set_retval1_spec uctx_set_errno_spec serial_putc_spec cons_buf_read_spec cons_buf_read_loop_spec thread_cons_buf_read_spec thread_serial_putc_spec thread_cons_buf_read_loop_spec sys_getc_spec sys_putc_spec sys_getcs_spec *)
Context `{ThreadsConfigurationOps}.
(** No user-visible events are generated. *)
Definition nil_trace_case t t' :=
let new := trace_of_ostrace (strip_common_prefix IOEvent_eq t t') in
t = common_prefix IOEvent_eq t t' /\
new = trace_of_ostrace nil.
(** At most one user-visible read event is generated. *)
Definition getc_trace_case t t' ret :=
let new := trace_of_ostrace (strip_common_prefix IOEvent_eq t t') in
t = common_prefix IOEvent_eq t t' /\
((ret = -1 /\ new = trace_of_ostrace nil) \/
(0 <= ret <= 255 /\ forall logIdx strIdx,
new = trace_of_ostrace (IOEvGetc logIdx strIdx ret :: nil))).
(** At most one user-visible write event is generated. *)
Definition putc_trace_case t t' c ret :=
let new := trace_of_ostrace (strip_common_prefix IOEvent_eq t t') in
t = common_prefix IOEvent_eq t t' /\
((ret = -1 /\ new = trace_of_ostrace nil) \/
(ret = c mod 256 /\ forall logIdx,
new = trace_of_ostrace (IOEvPutc logIdx c :: nil))).
Local Hint Resolve nil_trace_case_refl.

Lemma sys_putc_trace_case : forall st st' c ret,
sys_putc_spec st = Some st' ->
get_sys_arg1 st = Vint c ->
get_sys_ret st' = Vint ret ->
putc_trace_case st.(io_log) st'.(io_log) (Int.unsigned c) (Int.signed ret).