Skip to content

Commit

Permalink
Add the things needed for the host to the demo.
Browse files Browse the repository at this point in the history
  • Loading branch information
davidchisnall committed May 1, 2024
1 parent 20c98ee commit e0adc3d
Show file tree
Hide file tree
Showing 13 changed files with 450 additions and 0 deletions.
139 changes: 139 additions & 0 deletions demos/2024-04-23-cheritech/morello/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
Morello machine setup
=====================

This directory contains the files that are necessary to set up the Morello machine to act as the server in this demo.

Note: This contains the *private* key used on the server for the demo.
This would allow anyone to impersonate the server.
This does not matter because it is used *only* for the demo, never use this key for anything important!
Including the key here remove the need to generate a new header file for the client portion of the demo.

Pure-capability packages:

minicom

Hybrid packages:

bind918
isc-dhcp44-server
jq
npm
wireshark

Built from source:

cheriot-audit (no port yet)
mosquitto (xsltproc is broken and the port's no-docs mode doesn't work).

Make sure to build Release builds (-O0 is *really* slow on Morello, with -O0 Mosquitto can't keep up with two clients on FPGA!).
Install in /opt.

The following lines need to be added to /etc/rc.conf:

```
# Network interface for the demo
ifconfig_ue0="inet 10.0.0.10 netmask 255.0.0.0"

# DHCP server
dhcpd_enable="YES" # dhcpd enabled?
dhcpd_ifaces="ue0" # ethernet interface(s)
dhcpd_withumask="022" # file creation mask

# bind
named_enable="YES"

# NTP
ntpd_enable="YES"

# Mosquitto
mosquitto_enable="YES"

devfs_enable="YES"
```

Setting up DHCP
---------------

The first thing that the demo will do is try to get a DHCP lease.
This requires dhcpd to listen in the demo ethernet adaptor (configured in `rc.conf`) and to provide the host IP (10.0.0.10) as the DNS server.
The `usr/local64/etc/dhcpd.conf` file contains the configuration for the DHCP server and should be copied into `/usr/local64/etc/dhcpd.conf`.

Setting up DNS
--------------

After acquiring a DHCP lease, the demo will try to look up host names via DNS.
For disconnected operation, we will fake the two DNS names (pool.ntp.org and cheriot.demo) by configuring the DNS server to be authoritative for these zones.
Add the following lines to the end of `/usr/local64/etc/namedb/named.conf`:

```
zone "cheriot.demo" {
type master;
file "/usr/local64/etc/namedb/db.cheriot.demo";
};

zone "pool.ntp.org" {
type master;
file "/usr/local64/etc/namedb/db.pool.ntp.org";
};
```

Then copy the `db.cheriot.demo` and `db.pool.ntp.org` files from `usr/local64/etc/namedb` to `/usr/local64/etc/namedb/`.

Setting up NTP
--------------

For disconnected operation, the NTP server needs to be configured to lie and pretend that it is an authoritative server when it can't sync with a real NTP server.
The following lines in /etc/ntp.conf will do this:

```
server 127.127.1.0 prefer
fudge 127.127.1.0 #stratum 10
```

Note: It would be better to use `tos orphan 4`, but this defaults to a 10-minute timeout before deciding to become authoritative and this needs to be dropped to a few seconds.

Setting up Mosquitto
--------------------

The Mosquitto MQTT server configuration is in `opt/etc/mosquitto/`.
Copy these files into `/opt/etc/mosquitto/`.
You can also copy the [rc script](https://github.com/freebsd/freebsd-ports/blob/main/net/mosquitto/files/mosquitto.in) from the port into `/usr/local/etc/rc.d/mosquitto` (replace `%%PREFIX%%` with `/opt`).
Alternatively, you can just start mosquitto manually and run it in the foreground.

Wireshark
---------

To inspect the packets, use Wireshark.
This requires that the demo user has access to the `bpf` device.
The easiest way of doing this is to add the user to a group called `bpf` and add the following to `/etc/devfs.conf`:

```
own bpf root:bpf
perm bpf 660
```

Console UART
------------

The `home/demo/.minirc.dfl` file contains the configuration for minicom to connect to the FPGA.
Run minicom as `minicom -c on -D /dev/ttyU1` or `minicom -c on -D /dev/ttyU3` to connect to the FPGA.
The demo user will need to have access to the USB TTY devices.
The easiest way to do this is to add the user to the `dialer` group and add the following to `/etc/devfs.conf`:

```
own ttyU* root:dialer
perm ttyU* 660
```

Note that each FPGA has two FDTI devices, you need to use the *odd* numbered ones.

Driving the demo
----------------

The auditing portions of the demo are driven by the `audit.sh` script in `home/demo`.
Drop this in a directory along with the board description JSON and the firmware JSON from the final build.

The script to push new JavaScript, and an example JavaScript file, for the demo are in: `home/demo/script`
The `cheri.js` file here is the host interfaces, people may wish to modify `demo.js` to show dynamic code updates.
Note: MQTT does not do caching, so you must push out the JavaScript each time a new client connects.

9 changes: 9 additions & 0 deletions demos/2024-04-23-cheritech/morello/home/demo/.minirc.dfl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Machine-generated file - use setup menu in minicom to change parameters.
pu baudrate 115200
pu bits 8
pu parity N
pu stopbits 1
pu rtscts No
pu addlinefeed No
pu linewrap Yes
pu addcarreturn Yes
21 changes: 21 additions & 0 deletions demos/2024-04-23-cheritech/morello/home/demo/audit.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/sh

if [ $# -eq 0 ] ; then
echo Query required. Try one of the following:
echo Print all connection capabilities:
echo -e \\tdata.network_stack.all_connection_capabilities
echo Is the network stack configuration valid?
echo -e "\\t'data.network_stack.valid(kunyan_ethernet)'"
echo Print all allocator capabilities and their owners:
echo -e "\\t'[ { \"owner\": owner, \"capability\": data.rtos.decode_allocator_capability(c) } | c = input.compartments[owner].imports[_] ; data.rtos.is_allocator_capability(c) ]'"
echo Print all compartments that invoke functions in the JavaScript compartment:
echo -e "\\t'data.compartment.compartments_calling(\"javascript\")'"
echo Print all compartments that invoke functions in the allocator:
echo -e "\\t'data.compartment.compartments_calling(\"allocator\")'"
echo Print all compartments that have direct access to the LEDs / switches:
echo -e "\\t'data.compartment.compartments_with_mmio_import(data.board.devices.gpio_led0)'"
else
echo "cheriot-audit --board ibex-arty-a7-100.json --firmware-report cheritech-demo.json --module network_stack.rego --query \"$1\""
cheriot-audit --board ibex-arty-a7-100.json --firmware-report cheritech-demo.json --module network_stack.rego --query "$1" | jq
fi

87 changes: 87 additions & 0 deletions demos/2024-04-23-cheritech/morello/home/demo/script/cheri.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// FFI Imports
// Each function imported from the host environment needs to be assigned to a
// global like this and identified by a constant that the resolver in the C/C++
// code will understand.
// These constants are defined in the `Exports` enumeration.


var FFINumber = 1;

/**
* Log function, writes all arguments to the UART.
*/
export const print = vmImport(FFINumber++);

/**
* led_on(index).
*
* Turns on the LED at the specified index.
*/
export const led_on = vmImport(FFINumber++);

/**
* led_off(index).
*
* Turns off the LED at the specified index.
*/
export const led_off = vmImport(FFINumber++);

/**
* buttons_read().
*
* Reads the value of all of the buttons, returning a 4-bit value indicating
* the states of all of them.
*/
export const buttons_read = vmImport(FFINumber++);

/**
* switches_read().
*
* Reads the value of all of the switches, returning a 4-bit value indicating
* the states of all of them.
*/
export const switches_read = vmImport(FFINumber++);


export const mqtt_publish = vmImport(FFINumber++);
export const mqtt_subscribe = vmImport(FFINumber++);

/**
* led_set(index, state).
*
* Turns the LED at the specified index on or off depending on whether state is
* true or false.
*/
export function led_set(index, state)
{
if (state)
{
led_on(index);
}
else
{
led_off(index);
}
}

/**
* button_read(index).
*
* Reads the value of the button at the specified index.
*/
export function button_read(index)
{
return (buttons_read() & (1 << index)) !== 0;
}


/**
* switch_read(index).
*
* Reads the value of the switch at the specified index.
*/
export function switch_read(index)
{
return (switches_read() & (1 << index)) !== 0;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh
set -e
microvium demo.js
echo Publishing code to MQTT broker
mosquitto_pub -h cheriot.demo -p 8883 --cafile /opt/etc/mosquitto/certs/cert.pem -t cheri-code -f demo.mvm-bc
109 changes: 109 additions & 0 deletions demos/2024-04-23-cheritech/morello/home/demo/script/demo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import * as host from "./cheri.js"

var ticks = 0
var switches = 0

/**
* Subscribe to a topic, print to the UART whether the subscription was
* successful.
*/
function subscribe(topic)
{
var ret = host.mqtt_subscribe(topic)
host.print("Subscribe ", topic, " returned: ", ret)
if (ret)
{
host.print("Subscribed to", topic)
}
else
{
host.print("Failed to subscribe to ", topic)
}
}

/**
* On first run, subscribe to the switch topics.
*/
function first_run()
{
subscribe("cheri-switch-0")
subscribe("cheri-switch-1")
}

/**
* Tick function, called every 100ms (roughly).
*/
function tick()
{
if (ticks === 0)
{
first_run();
}
ticks++
// If we're not a lightswitch, don't do anything else.
if (host.switch_read(3))
{
return;
}
// If we're not a lightbulb, make sure the lights are out
host.led_off(0)
host.led_off(1)
// Uncomment the next block to validate that the tick callback is being called.
/*
if (ticks % 5 === 0)
{
host.print("tick: ", ticks)
}
*/
var new_switches = host.switches_read()
if (new_switches !== switches)
{
for (var i = 0 ; i < 2 ; i++)
{
if ((new_switches & (1 << i)) !== (switches & (1 << i)))
{
host.print("Switch ", i, " changed to ", (new_switches & (1 << i)) ? "on" : "off")
host.mqtt_publish("cheri-switch-" + i, (new_switches & (1 << i)) ? "on" : "off")
}
}
switches = new_switches
}
}

/**
* Publish notification callback, called whenever a new publish message is
* received from the MQTT broker.
*/
function message(topic, message)
{
host.print("Received message on topic: ", topic, " message: ", message)
var switchNumber = -1
// If we're not a lightbulb, don't do anything else.
if (!host.switch_read(3))
{
return;
}
if (topic === "cheri-switch-0")
{
switchNumber = 0
}
else if (topic === "cheri-switch-1")
{
switchNumber = 1
}
else
{
return
}
if (message === "on")
{
host.led_on(switchNumber)
}
else
{
host.led_off(switchNumber)
}
}

vmExport(1234, tick);
vmExport(1235, message);
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-----BEGIN CERTIFICATE-----
MIIBgzCCASmgAwIBAgIUeyRaxt/cqeeZ1JByg4V4shx4lhowCgYIKoZIzj0EAwIw
FzEVMBMGA1UEAwwMY2hlcmlvdC5kZW1vMB4XDTI0MDQwODE0NTcwMVoXDTI1MDQw
ODE0NTcwMVowFzEVMBMGA1UEAwwMY2hlcmlvdC5kZW1vMFkwEwYHKoZIzj0CAQYI
KoZIzj0DAQcDQgAE2zq+r59p+QKkoKdBguXxBl4KoX5DYb6gHyI9Wrn7o4bz8rNZ
4JPG4J+mIlEQKv9eIJYn1owIWQ5YbKaHpZqWAqNTMFEwHQYDVR0OBBYEFBdDvYEz
T9pLdHbNwBVFT9wwQGVdMB8GA1UdIwQYMBaAFBdDvYEzT9pLdHbNwBVFT9wwQGVd
MA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIgb2epifZyBtLofZsk
gs5HqfpKuiMijfe3Q+H7ETP3aIwCIQDYBIR7uQ4s24mK3dcj+u5Qc6gSr/WuBZGO
xzxrtzDGTw==
-----END CERTIFICATE-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgFF2t/aeGHzLHsP4k
63Q9yIFLeU8+mtOylWjhfwwQbNihRANCAATbOr6vn2n5AqSgp0GC5fEGXgqhfkNh
vqAfIj1aufujhvPys1ngk8bgn6YiURAq/14glifWjAhZDlhspoelmpYC
-----END PRIVATE KEY-----
Loading

0 comments on commit e0adc3d

Please sign in to comment.