Dish
Imagine a world where the FTP Server, Status Monitor, and System Video Stream Server have been replaced by a single general purpose development application.
Dish is a programming language intended to be interpreted as a sort of interactive shell in a Deos embedded system.
The dish-server is an embedded application that can execute dish scripts loaded through a network socket. Dish scripts can invoke kernel apis (and eventually any other Deos component that exposes an api) and can layout memory in C-like structures.
Dish can be launched via inetd, thus multiple instances may exist at the same time, each created from a different process template if needed.
Source code: https://deos.ddci.com/svn/DDCI/products/dish
Potential Uses
- To replace the Deos development applications such as FTP Server and Status Monitor.
- To retrieve target information, e.g. structural coverage hit-maps.
- As a Deos component test procedure
Example Customer Use
The Maple customer wants to be able to retrieve CFFS files via a Deos FTP server modification. Using Dish might be easier. A Dish script would load the CFFS client API and call its functions to retrieve the files, essentially turning the target-side dish-server into a temporary CFFS client.
Language
Here is an example dish script that lists the files in the kernel file system:
(define DEOS_PIB (struct
(cFileName (array char 32))
(sizeInBytes uint32)
(handle uint32)
(integrityKey uint32)
(userDefined1 uint32)))
(define kernelFileSuccess 0)
(define info (new DEOS_PIB))
(define name_buffer (new (array char 256)))
(set status (stdcall "firstKernelFile" 0 (address-of info) (size-of info) (address-of name_buffer) (size-of name_buffer)))
(while (== status kernelFileSuccess)
(print
(field info sizeInBytes)
(field info integrityKey)
(from-c-str name_buffer))
(set handle (field info handle))
(set status (stdcall "nextKernelFile" handle (address-of info) (size-of info) (address-of name_buffer) (size-of name_buffer)))
)
Dish's fully-parenthesized syntax is inspired by Lisp and optimized for easy parsing. Dish's imperative semantics are inspired by C and optimized for easy interpretation.
Data Structures
Dish has two distinct flavors of types, managed types and raw types.
Raw types are analogous to C structures. Raw types have a size in bytes, and all fields of a raw type (if any) are defined simply by a byte offset into the structure and by the field's own type, which is always another raw type. In the example above, DEOS_PIB is a raw type whose fields are all of raw types as well, such as array, unit32, and char.
Managed types are everything else in dish, such as type definitions and strings. Note that (new (array char 256)) will create a raw array of characters, but "hello" will create a managed string. The function from-c-str converts a C-style null-terminated sequence of chars into a managed string.
Dish has a managed memory heap and objects are dynamically allocated and garbage collected using a reference counting algorithm. All structures that can hold references to managed objects are immutable, thereby preventing reference cycles and eliminating the need for a cycle detector. This design is to keep the implementation simple. For instance, set creates or overwrites a mutable variable and define declares and assigns a constant. set can only be used to work with raw types, whereas define can be used to store any object, such as type definitions.
Interactive Shell
Dish scripts are read and interpreted 1 character at a time, which makes it possible to behave as an interactive shell through a long-lived network socket. A command line script called "dish" can run scripts or accept interactive user input, similar to the command line program "python".
Here is an example of using the command line workstation utility to run a dish script remotely:
$ time ./bin/dish 192.168.19.100 examples/list_files.dish 7120 1217848818 deosname.dll 61368 1305182968 sm.exe 54955 2928518191 ftpserv.exe 689 3015842420 sysvstrm.config 134 2243270813 lwip.config 20990 3307229844 libansi.so 30688 3773480325 sysvstrm.exe 1209 3798469384 names.dat 9800 109893588 librtl-bouton.so 4659 1072219501 libdebuggerkernelsupport.so 11047 2252549840 platreg.bin 199576 3355985383 lwip.exe 128252 1624090046 kernel.exe 9069 3932720336 platregd.bin 31931 2310475839 gdbserver.exe 20707 1002989079 inetd.exe 17024 855446157 pal.dll 24081 1495244238 imageapi.dll 20990 3307229844 ansi.dll 58844 98178578 dish-server.exe 399 142047969 inetd.config 11684 2449703137 libmemory-heap.so real 0m2.944s user 0m0.015s sys 0m0.108s
Target Manager Integration
OpenArbor would provide users with the ability to run dish scripts through the Target Manager, possibly linked to a hotkey, etc. OpenArbor should also be able to interface with the dish-server to perform some "builtin" features, such as synchronizing files, gathering time maps, possibly even watching a video stream. Dish is designed to be flexible enough so that OpenArbor and users can "do anything" (environment permitting) without compiling and loading new binaries to the target.
Editor
OpenArbor can provide a syntax highlighting editor for dish scripts so that our customers can write their own dish scripts.
Here is a screenshot from a prototype:
Alternatives
If you think the fundamental design of Dish is lacking, here are some alternatives:
- Dish 2: To reduce the amount of parsing effort on the target, we could compile dish programs to an intermediate binary representation (similar to .pyc or .class files), and push that over the network.
- Dish 3: To avoid reinventing the wheel in the previous idea, we could reuse the LLVM bitcode format as an intermediate representation. Since frontends for C and many other languages already exist, we could write dish scripts in "anything" or whatever, and even run the bitcode through optimizer algorithms comparable to gcc -O3. There's even an interpreter already written for LLVM bitcode, called lli, which we could port to Deos, but it's 150MB.
- Dish 4: Compile and load plain old .so images, and just call some entrypoint function or something. This idea has the smallest amount of target-side overhead possible, since it's effectively equivalent to building and integrating a normal application, such as the current status monitor. This also has the most workstation-side hassle.
We end up with a spectrum of solutions that all answer the question: where to put the heavy lifting? Dish 1 (what's written now) puts all of it on the target; Dish 4 puts all of it on the workstation.
