Definition new_file := mkfile O (fun _:nat => Undef).Definition fs_open_existing (fname: int) (f: file) (md: fmode): fs :=
  mkfs (get_max_fds fsys)
       (mkfsdata (fun i => if Int.eq i unused_fd then Some (md, O)
                           else get_fdtable fsys i)
                 (fun i => if Int.eq i unused_fd then Some f
                           else get_fcache fsys i)
                 (fun i => if Int.eq i unused_fd then Some fname
                           else get_fnames fsys i))
       (get_fstore fsys).Definition fs_open_new (fname: int) (md: fmode): fs :=
  mkfs (get_max_fds fsys)
       (mkfsdata (fun i => if Int.eq i unused_fd then Some (md, O)
                           else get_fdtable fsys i)
                 (fun i => if Int.eq i unused_fd then Some new_file
                           else get_fcache fsys i)
                 (fun i => if Int.eq i unused_fd then Some fname
                           else get_fnames fsys i))
       (get_fstore fsys).Definition fs_open (fname: int) (md: fmode): option fs :=
  match fwritable md, get_fstore fsys fname with
  | false, Some f => Some (fs_open_existing fname f md)
  | false, None => None
  | true, Some f => Some (fs_open_existing fname f md)
  | true, None => Some (fs_open_new fname md)
  end.Definition handled_list: list AST.external_function := SYS_READ::SYS_WRITE::SYS_OPEN::nil.Definition is_open (fsys: fs) (fname: int) := exists fd, get_fnames fsys fd = Some fname.Definition is_readable (fsys: fs) (fd: int) :=
  exists md, exists cur, exists f,
    get_fdtable fsys fd = Some (md, cur) /\ get_fcache fsys fd = Some f.Definition is_writable (fsys: fs) (fd: int) :=
  exists md, exists cur, exists f,
    get_fdtable fsys fd = Some (md, cur) /\ fwritable md=true /\
    get_fcache fsys fd = Some f.Inductive os_step: genv -> xT -> mem -> xT -> mem -> Prop :=
| os_corestep: forall ge z c fs m c' m',
  corestep csem ge c m c' m' ->
  os_step ge (mkxT z c fs) m (mkxT z c' fs) m'
| os_open: forall ge z s m c md0 fname0 md fname unused_fd fs',
  let fs := get_fs s in
  at_external csem (get_core s) = Some (SYS_OPEN, SYS_OPEN_SIG, fname0::md0::nil) ->
  alloc_fd fs = Some unused_fd ->
  val2omode md0 = Some md ->
  val2oint fname0 = Some fname ->
  ~is_open fs fname ->
  fs_open fs unused_fd fname md = Some fs' ->
  after_external csem (Some (Vint unused_fd)) (get_core s) = Some c ->
  os_step ge s m (mkxT z c fs') m
| os_read: forall ge z s m c fd0 fd buf adr nbytes0 nbytes bytes m',
  let fs := get_fs s in
  at_external csem (get_core s) = Some (SYS_READ, SYS_READ_SIG, fd0::buf::nbytes0::nil) ->
  val2oint fd0 = Some fd ->
  val2oadr buf = Some adr ->
  val2oint nbytes0 = Some nbytes ->
  fs_read fs fd (nat_of_Z (Int.unsigned nbytes)) = Some bytes ->
  Forall is_defchar bytes ->
  (Zlength bytes > 0)%Z ->
  Mem.storebytes m (fst adr) (Int.unsigned (snd adr)) bytes = Some m' ->
  after_external csem (Some (Vint (Int.repr (Zlength bytes)))) (get_core s) = Some c ->
  os_step ge s m (mkxT z c fs) m'
(*| os_write: forall ge z s m c fd0 fd adr buf nbytes0 nbytes bytes fs' nbytes_written sig,
  let fs := get_fs s in
  at_external csem (get_core s) = Some (SYS_WRITE, sig, fd0::buf::nbytes0::nil) ->
  val2oint fd0 = Some fd ->
  val2oadr buf = Some adr ->
  val2oint nbytes0 = Some nbytes ->
  Mem.loadbytes m (fst adr) (Int.unsigned (snd adr)) (Int.unsigned nbytes) = Some bytes ->
  fs_write fs fd bytes = Some (nbytes_written, fs') ->
  after_external csem (Some (Vint (Int.repr (Z_of_nat nbytes_written)))) (get_core s) = Some c ->
  os_step ge s m (mkxT z c fs') m*).Inductive os_step: genv -> xT -> mem -> xT -> mem -> Prop :=
| os_corestep: forall ge z c fs m c' m',
  corestep csem ge c m c' m' ->
  os_step ge (mkxT z c fs) m (mkxT z c' fs) m'
| os_open: forall ge z s m c md0 fname0 md fname unused_fd fs',
  let fs := get_fs s in
  at_external csem (get_core s) = Some (SYS_OPEN, SYS_OPEN_SIG, fname0::md0::nil) ->
  alloc_fd fs = Some unused_fd ->
  val2omode md0 = Some md ->
  val2oint fname0 = Some fname ->
  ~is_open fs fname ->
  fs_open fs unused_fd fname md = Some fs' ->
  after_external csem (Some (Vint unused_fd)) (get_core s) = Some c ->
  os_step ge s m (mkxT z c fs') m
| os_read: forall ge z s m c fd0 fd buf adr nbytes0 nbytes bytes m',
  let fs := get_fs s in
  at_external csem (get_core s) = Some (SYS_READ, SYS_READ_SIG, fd0::buf::nbytes0::nil) ->
  val2oint fd0 = Some fd ->
  val2oadr buf = Some adr ->
  val2oint nbytes0 = Some nbytes ->
  fs_read fs fd (nat_of_Z (Int.unsigned nbytes)) = Some bytes ->
  Forall is_defchar bytes ->
  (Zlength bytes > 0)%Z ->
  Mem.storebytes m (fst adr) (Int.unsigned (snd adr)) bytes = Some m' ->
  after_external csem (Some (Vint (Int.repr (Zlength bytes)))) (get_core s) = Some c ->
  os_step ge s m (mkxT z c fs) m'
(*| os_write: forall ge z s m c fd0 fd adr buf nbytes0 nbytes bytes fs' nbytes_written sig,
  let fs := get_fs s in
  at_external csem (get_core s) = Some (SYS_WRITE, sig, fd0::buf::nbytes0::nil) ->
  val2oint fd0 = Some fd ->
  val2oadr buf = Some adr ->
  val2oint nbytes0 = Some nbytes ->
  Mem.loadbytes m (fst adr) (Int.unsigned (snd adr)) (Int.unsigned nbytes) = Some bytes ->
  fs_write fs fd bytes = Some (nbytes_written, fs') ->
  after_external csem (Some (Vint (Int.repr (Z_of_nat nbytes_written)))) (get_core s) = Some c ->
  os_step ge s m (mkxT z c fs') m*).Inductive os_step: genv -> xT -> mem -> xT -> mem -> Prop :=
| os_corestep: forall ge z c fs m c' m',
  corestep csem ge c m c' m' ->
  os_step ge (mkxT z c fs) m (mkxT z c' fs) m'
| os_open: forall ge z s m c md0 fname0 md fname unused_fd fs',
  let fs := get_fs s in
  at_external csem (get_core s) = Some (SYS_OPEN, SYS_OPEN_SIG, fname0::md0::nil) ->
  alloc_fd fs = Some unused_fd ->
  val2omode md0 = Some md ->
  val2oint fname0 = Some fname ->
  ~is_open fs fname ->
  fs_open fs unused_fd fname md = Some fs' ->
  after_external csem (Some (Vint unused_fd)) (get_core s) = Some c ->
  os_step ge s m (mkxT z c fs') m
| os_read: forall ge z s m c fd0 fd buf adr nbytes0 nbytes bytes m',
  let fs := get_fs s in
  at_external csem (get_core s) = Some (SYS_READ, SYS_READ_SIG, fd0::buf::nbytes0::nil) ->
  val2oint fd0 = Some fd ->
  val2oadr buf = Some adr ->
  val2oint nbytes0 = Some nbytes ->
  fs_read fs fd (nat_of_Z (Int.unsigned nbytes)) = Some bytes ->
  Forall is_defchar bytes ->
  (Zlength bytes > 0)%Z ->
  Mem.storebytes m (fst adr) (Int.unsigned (snd adr)) bytes = Some m' ->
  after_external csem (Some (Vint (Int.repr (Zlength bytes)))) (get_core s) = Some c ->
  os_step ge s m (mkxT z c fs) m'
(*| os_write: forall ge z s m c fd0 fd adr buf nbytes0 nbytes bytes fs' nbytes_written sig,
  let fs := get_fs s in
  at_external csem (get_core s) = Some (SYS_WRITE, sig, fd0::buf::nbytes0::nil) ->
  val2oint fd0 = Some fd ->
  val2oadr buf = Some adr ->
  val2oint nbytes0 = Some nbytes ->
  Mem.loadbytes m (fst adr) (Int.unsigned (snd adr)) (Int.unsigned nbytes) = Some bytes ->
  fs_write fs fd bytes = Some (nbytes_written, fs') ->
  after_external csem (Some (Vint (Int.repr (Z_of_nat nbytes_written)))) (get_core s) = Some c ->
  os_step ge s m (mkxT z c fs') m*).Inductive os_step: genv -> xT -> mem -> xT -> mem -> Prop :=
| os_corestep: forall ge z c fs m c' m',
  corestep csem ge c m c' m' ->
  os_step ge (mkxT z c fs) m (mkxT z c' fs) m'
| os_open: forall ge z s m c md0 fname0 md fname unused_fd fs',
  let fs := get_fs s in
  at_external csem (get_core s) = Some (SYS_OPEN, SYS_OPEN_SIG, fname0::md0::nil) ->
  alloc_fd fs = Some unused_fd ->
  val2omode md0 = Some md ->
  val2oint fname0 = Some fname ->
  ~is_open fs fname ->
  fs_open fs unused_fd fname md = Some fs' ->
  after_external csem (Some (Vint unused_fd)) (get_core s) = Some c ->
  os_step ge s m (mkxT z c fs') m
| os_read: forall ge z s m c fd0 fd buf adr nbytes0 nbytes bytes m',
  let fs := get_fs s in
  at_external csem (get_core s) = Some (SYS_READ, SYS_READ_SIG, fd0::buf::nbytes0::nil) ->
  val2oint fd0 = Some fd ->
  val2oadr buf = Some adr ->
  val2oint nbytes0 = Some nbytes ->
  fs_read fs fd (nat_of_Z (Int.unsigned nbytes)) = Some bytes ->
  Forall is_defchar bytes ->
  (Zlength bytes > 0)%Z ->
  Mem.storebytes m (fst adr) (Int.unsigned (snd adr)) bytes = Some m' ->
  after_external csem (Some (Vint (Int.repr (Zlength bytes)))) (get_core s) = Some c ->
  os_step ge s m (mkxT z c fs) m'
(*| os_write: forall ge z s m c fd0 fd adr buf nbytes0 nbytes bytes fs' nbytes_written sig,
  let fs := get_fs s in
  at_external csem (get_core s) = Some (SYS_WRITE, sig, fd0::buf::nbytes0::nil) ->
  val2oint fd0 = Some fd ->
  val2oadr buf = Some adr ->
  val2oint nbytes0 = Some nbytes ->
  Mem.loadbytes m (fst adr) (Int.unsigned (snd adr)) (Int.unsigned nbytes) = Some bytes ->
  fs_write fs fd bytes = Some (nbytes_written, fs') ->
  after_external csem (Some (Vint (Int.repr (Z_of_nat nbytes_written)))) (get_core s) = Some c ->
  os_step ge s m (mkxT z c fs') m*).Definition os_initial_core (ge: genv) (v: val) (args: list val): option xT :=
  match initial_core csem ge v args with
  | Some c => Some (mkxT init_world c (mount_fs (fun _: int => None)))
  | None => None
  end.Definition os_at_external (s: xT) :=
  match at_external csem (get_core s) with
  | Some (SYS_READ, sig, args) => None
  | Some (SYS_WRITE, sig, args) => None
  | Some (SYS_OPEN, sig, args) => None
  | Some (ef, sig, args) => Some (ef, sig, args)
  | None => None
  end.

(* Specifications: *)
Lemma os_at_external_core1: forall s ef sig args, os_at_external s = Some (ef, sig, args) -> at_external csem (get_core s) = Some (ef, sig, args).
Lemma os_at_external_core2: forall s ef sig args, at_external csem (get_core s) = Some (ef, sig, args) -> ef<>SYS_READ -> ef<>SYS_WRITE -> ef<>SYS_OPEN -> os_at_external s = Some (ef, sig, args).
Lemma os_at_external_core3: forall s ef sig args, at_external csem (get_core s) = Some (ef, sig, args) -> ef=SYS_READ \/ ef=SYS_WRITE \/ ef=SYS_OPEN -> os_at_external s = None.
Lemma os_at_external_core4: forall s ef sig args, at_external csem (get_core s) = Some (ef, sig, args) -> os_at_external s = None -> ef=SYS_READ \/ ef=SYS_WRITE \/ ef=SYS_OPEN.