Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file target.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432moduleDune=Functoria.DunemoduleInfo=Functoria.InfomoduleInstall=Functoria.InstallmoduleAction=Functoria.ActionopenFunctoria.DSL(** A Mirage target: target consists in multiple backends grouped together. *)moduletypeTARGET=sigtypet(** The type representing a specific backend in a target. *)valcast:Key.mode->t(** Ensures the mode is a backend supported by this target. *)valdune:Info.t->Dune.stanzalist(** Dune rules to build the unikernel *)valconfigure:Info.t->unitAction.t(** Configure-time actions. *)valbuild_context:?build_dir:Fpath.t->Info.t->Dune.stanzalist(** Generate build context configuration *)valcontext_name:Info.t->string(** Dune context *)valpackages:t->packagelist(** The required packages to support this backend. *)valinstall:Info.t->Install.t(** [install i] returns which files are installed in context [i]. *)endmoduleUnix=structtypet=[`Unix|`MacOSX]letcast=function#tast->t|_->invalid_arg"not a unix target."letpackages_=[Functoria.package~min:"5.0.0"~max:"6.0.0""mirage-unix"](*Mirage unix is built on the host build context.*)letbuild_context?build_dir:__=[]letcontext_name_="default"letconfigure_=Action.ok()letmaini=Fpath.(base(rem_ext(Info.maini)))letpublic_namei=matchInfo.outputiwithNone->Info.namei|Someo->oletflags=(* Disable "70 [missing-mli] Missing interface file." as we are only
generating .ml files currently. *)[":standard";"-w";"-70"]@ifMisc.terminal()then["-color";"always"]else[]letdunei=letlibraries=Info.librariesiinletpublic_name=public_nameiinletmain=Fpath.to_string(maini)inletpp_listf=Dune.compact_listfinletdune=Dune.stanzaf{|
(rule
(target %s)
(enabled_if (= %%{context_name} "default"))
(deps %s.exe)
(action
(copy %s.exe %%{target})))
(executable
(name %s)
(libraries %a)
(link_flags (-thread))
(modules (:standard \ %a))
(flags %a)
(enabled_if (= %%{context_name} "default"))
)
|}public_namemainmainmain(pp_list"libraries")librariesFpath.pp(Fpath.rem_ext(Fpath.base(Info.config_filei)))(pp_list"flags")flagsin[dune]letinstalli=letpublic_name=public_nameiinInstall.v~bin:[Fpath.(vpublic_name,vpublic_name)]()endmoduleXen=struct(* We generate an example .xl with common defaults, and a generic
.xl.in which has @VARIABLES@ which must be substituted by sed
according to the preferences of the system administrator.
The common defaults chosen for the .xl file will be based on values
detected from the build host. We assume that the .xl file will
mainly be used by developers where build and deployment are on the
same host. Production users should use the .xl.in and perform the
appropriate variable substition.
*)letdetected_bridge_name=(* Best-effort guess of a bridge name stem to use. Note this
inspects the build host and will probably be wrong if the
deployment host is different. *)matchList.fold_left(funsofarx->matchsofarwith(* This is Linux-specific *)|NonewhenSys.file_exists(Fmt.str"/sys/class/net/%s0"x)->Somex|None->None|Somex->Somex)None["xenbr";"br";"virbr"]with|Somex->x|None->"br"moduleSubstitutions=structtypev=|Name|Kernel|Memory|BlockofBlock.block_t|Networkofstringtypet=(v*string)listletstring_of_v=function|Name->"@NAME@"|Kernel->"@KERNEL@"|Memory->"@MEMORY@"|Blockb->Fmt.str"@BLOCK:%s@"b.filename|Networkn->Fmt.str"@NETWORK:%s@"nletlookuptsv=ifList.mem_assocvtsthenList.assocvtselsestring_of_vvletdefaultsi=letblocks=List.map(funb->(Blockb,b.filename))(Hashtbl.fold(fun_vacc->v::acc)Block.all_blocks[])andnetworks=List.mapi(funin->(Networkn,Fmt.str"%s%d"detected_bridge_namei))!Network.all_networksin[(Name,Info.namei);(Kernel,Info.namei^".xen");(Memory,"256")]@blocks@networksendletappendfmts=Fmt.pffmt(s^^"@.")letconfigure_main_xl?substitutions~exti=letopenSubstitutionsinletsubstitutions=matchsubstitutionswithSomex->x|None->defaultsiinletpath=Fpath.(v(Info.namei)+ext)inAction.with_output~path~purpose:"xl file"(funfmt->letopenBlockinappendfmt"name = '%s'"(lookupsubstitutionsName);appendfmt"kernel = '%s'"(lookupsubstitutionsKernel);appendfmt"type = 'pvh'";appendfmt"memory = %s"(lookupsubstitutionsMemory);appendfmt"on_crash = 'preserve'";appendfmt"";letblocks=List.map(funb->(* We need the Linux version of the block number (this is a
strange historical artifact) Taken from
https://github.com/mirage/mirage-block-xen/blob/
a64d152586c7ebc1d23c5adaa4ddd440b45a3a83/lib/device_number.ml#L128 *)letrecstring_of_int26x=lethigh,low=((x/26)-1,(xmod26)+1)inlethigh'=ifhigh=-1then""elsestring_of_int26highinletlow'=String.make1(char_of_int(low+int_of_char'a'-1))inhigh'^low'inletvdev=Fmt.str"xvd%s"(string_of_int26b.number)inletpath=lookupsubstitutions(Blockb)inFmt.str"'format=raw, vdev=%s, access=rw, target=%s'"vdevpath)(Hashtbl.fold(fun_vacc->v::acc)all_blocks[])inappendfmt"disk = [ %s ]"(String.concat", "blocks);appendfmt"";letnetworks=List.map(funn->Fmt.str"'bridge=%s'"(lookupsubstitutions(Networkn)))!Network.all_networksinappendfmt"# if your system uses openvswitch then either edit /etc/xen/xl.conf \
and set";appendfmt"# vif.default.script=\"vif-openvswitch\"";appendfmt"# or add \"script=vif-openvswitch,\" before the \"bridge=\" below:";appendfmt"vif = [ %s ]"(String.concat", "networks))endmoduleSolo5=structopenAction.Syntaxletsolo5_manifest_path=Fpath.v"manifest.json"typesolo5_target=[`Virtio|`Muen|`Hvt|`Genode|`Spt]typexen_target=[`Xen|`Qubes]typet=[solo5_target|xen_target]letcast=function#tast->t|_->invalid_arg"not a solo5 target."letbuild_packages=[Functoria.package~min:"0.8.2"~max:"2.0.0"~scope:`Switch~build:true"ocaml-solo5";Functoria.package~min:"0.7.5"~max:"0.10.0"~scope:`Switch~build:true"solo5";]letruntime_packagestarget=matchtargetwith|#solo5_target->[Functoria.package~min:"0.10.0"~max:"0.11.0""mirage-solo5"]|#xen_target->[Functoria.package~min:"9.0.0"~max:"10.0.0""mirage-xen"]letpackagestarget=build_packages@runtime_packagestargetletcontext_name_i="solo5"(* OCaml solo5 build context. *)letbuild_context?build_dir:_i=letbuild_context=Dune.stanzaf{|
(context (default
(name %s)
(host default)
(toolchain solo5)
(merlin)
(disable_dynamically_linked_foreign_archives true)
))
|}(context_namei)in[build_context](* Configure step *)letgenerate_manifest_jsonwith_devices()=letnetworks=List.map(funn->(n,`Network))!Network.all_networksinletblocks=Hashtbl.fold(funk_vacc->(k,`Block)::acc)Block.all_blocks[]inletto_string(name,typ)=Fmt.str{json|{ "name": %S, "type": %S }|json}name(matchtypwith`Network->"NET_BASIC"|`Block->"BLOCK_BASIC")inletdevices=ifwith_devicesthenList.mapto_string(networks@blocks)else[]inlets=String.concat", "devicesinlet*()=Action.with_output~path:solo5_manifest_path~purpose:"Solo5 application manifest file"(funfmt->Fmt.pffmt{|{
"type": "solo5.manifest",
"version": 1,
"devices": [ %s ]
}
|}s)inAction.write_file(Fpath.v"manifest.ml")""letconfigurei=letname=Info.nameiinlettarget=Info.getiKey.targetinlet*()=matchtargetwith|#solo5_target->generate_manifest_jsontrue()|#xen_target->generate_manifest_jsonfalse()|_->assertfalseinmatchtargetwith|`Xen->let*()=Xen.configure_main_xl~ext:"xl"iinlet*()=Xen.configure_main_xl~substitutions:[]~ext:"xl.in"iinLibvirt.configure_main~name|`Virtio->Libvirt.configure_virtio~name|_->Action.ok()(* Build *)letext=function|`Virtio->".virtio"|`Muen->".muen"|`Hvt->".hvt"|`Genode->".genode"|`Spt->".spt"|`Xen|`Qubes->".xen"|_->invalid_arg"solo5 bindings only defined for solo5 targets"letmaini=Fpath.(base(rem_ext(Info.maini)))letouti=lettarget=Info.getiKey.targetinletpublic_name=matchInfo.outputiwithNone->Info.namei|Someo->oinpublic_name^exttargetletrenamei=letout=outiinletmain=Fpath.to_string(maini)inDune.stanzaf{|
(rule
(target %s)
(enabled_if (= %%{context_name} "%s"))
(deps %s.exe)
(action
(copy %s.exe %%{target})))
|}out(context_namei)mainmainletmanifest_i=Dune.stanzaf{|
(rule
(targets manifest.c)
(deps manifest.json)
(action
(run solo5-elftool gen-manifest manifest.json manifest.c)))
|}letsolo5_abi=function|#Key.mode_unix->assertfalse|#Key.mode_xen->"xen"|`Virtio->"virtio"|`Hvt->"hvt"|`Muen->"muen"|`Genode->"genode"|`Spt->"spt"letflags=(* Disable "70 [missing-mli] Missing interface file." as we are only
generating .ml files currently. *)[":standard";"-w";"-70"]@ifMisc.terminal()then["-color";"always"]else[]letmaini=letlibraries=Info.librariesiinletmain=Fpath.to_string(maini)inlettarget=Info.getiKey.targetinletpp_listf=Dune.compact_listfinDune.stanzaf{|
(executable
(enabled_if (= %%{context_name} "%s"))
(name %s)
(modes (native exe))
(libraries %a)
(link_flags %a -cclib "-z solo5-abi=%s")
(modules (:standard \ %a manifest))
(foreign_stubs (language c) (names manifest))
)
|}(context_namei)main(pp_list"libraries")libraries(pp_list"link_flags")flags(solo5_abitarget)Fpath.pp(Fpath.rem_ext(Fpath.base(Info.config_filei)))letsubdirnames=Dune.stanzaf"(subdir %s\n %a)\n"nameDune.pp(Dune.vs)letdunei=[maini;manifesti;renamei]letinstalli=lettarget=Info.getiKey.targetinletname=Info.nameiinletout=outiinletopenFpathinletadditional_artifacts=matchtargetwith|`Xen->[v(name^".xl");v(name^".xl.in")]|_->[]inInstall.v~bin:[(vout,vout)]~etc:additional_artifacts()endletchoose:Key.mode->(moduleTARGET)=function|#Solo5.t->(moduleSolo5)|#Unix.t->(moduleUnix)letdunei=lettarget=Info.getiKey.targetinlet(moduleTarget)=choosetargetinTarget.duneiletoutput_message=reftrueletconfigurei=letopenAction.Infixinlettarget=Info.getiKey.targetinlet(moduleTarget)=choosetargetinTarget.configurei>|=fun()->if!output_messagethen(output_message:=false;Logs.app(funm->m"Successfully configured the unikernel. Now run 'make' (or more \
fine-grained steps: 'make all', 'make depends', or 'make lock')."))letbuild_context?build_diri=lettarget=Info.getiKey.targetinlet(moduleTarget)=choosetargetinTarget.build_context?build_diriletcontext_namei=lettarget=Info.getiKey.targetinlet(moduleTarget)=choosetargetinTarget.context_nameiletpackagestarget=let(moduleTarget)=choosetargetinTarget.(packages(casttarget))letinstalli=lettarget=Info.getiKey.targetinlet(moduleTarget)=choosetargetinTarget.installi