1
0
Fork 0

Compare commits

..

39 Commits

Author SHA1 Message Date
Sébastien Bourdeauducq e1f493f3ca drtio: add InjectionRequest to expects_response 2024-11-26 14:58:24 +08:00
Sebastien Bourdeauducq 1f5ea41934 flake: update dependencies 2024-11-20 19:58:55 +08:00
Sebastien Bourdeauducq 7f83d56ef5 cargo fmt 2024-11-20 09:42:49 +08:00
Jonathan Coates 1d431456f4 Fix DWARF parser treating catch blocks as unconditional
Signed-off-by: Jonathan Coates <jonathan.coates@oxionics.com>
2024-11-20 09:32:38 +08:00
Sebastien Bourdeauducq b03e380c1e flake: update dependencies 2024-11-20 09:07:00 +08:00
occheung 47fc53c4bf drtio_tuple -> drtio_context 2024-11-18 13:13:10 +08:00
occheung 42eaecf9e1 remove debug message 2024-11-18 12:19:37 +08:00
occheung beb7e6f994 cargo fmt 2024-11-18 12:19:37 +08:00
occheung 4502a47aa6 drtio_proto: add allocate step for flashing
This avoids reallocation while transfering binaries.
2024-11-18 12:19:37 +08:00
occheung ac6b7d5cf0 satman: fix checksum error message 2024-11-18 12:19:37 +08:00
occheung 3019bc6123 runtime: check crc when flashing 2024-11-18 12:19:37 +08:00
occheung 95b8562812 cargo fmt 2024-11-18 12:19:37 +08:00
occheung a13f5d02fa mgmt: supplementary tuple -> tuple struct 2024-11-18 12:19:37 +08:00
occheung e52aa77068 cargo fmt 2024-11-18 12:19:37 +08:00
occheung 8e28d12ad0 runtime mgmt: avoid pull_log resource hog 2024-11-18 12:19:37 +08:00
occheung 47cddae04f runtime mgmt: avoid passing incomplete log to core_log 2024-11-18 12:19:37 +08:00
occheung 27a65df40e satman mgmt: fix uart log level change message 2024-11-18 12:19:37 +08:00
occheung 759cca3bfd satman mgmt: allow sliceable to consume log source 2024-11-18 12:19:37 +08:00
occheung aadb6fc22d satman mgmt: get logger unconditionally 2024-11-18 12:19:37 +08:00
occheung ae4d5a4228 mgmt: minor fix 2024-11-18 12:19:37 +08:00
occheung 6f1d727ca2 drtio-proto: avoid expecting response to drop link ack 2024-11-18 12:19:37 +08:00
occheung 7da5061f7e coremgmt: fix import/uses 2024-11-18 12:19:37 +08:00
occheung 47d418c69e coremgmt: remove unnecsaary cursors 2024-11-18 12:19:37 +08:00
occheung d2979e8894 runtime coremgmt: implement firmware rewrite 2024-11-18 12:19:37 +08:00
occheung 3884c14a19 satman coremgmt: code after reboot is unreachable 2024-11-18 12:19:37 +08:00
occheung c5b00d8e4e cargo fmt 2024-11-18 12:19:37 +08:00
occheung 2985875f9a satman: implement boot file rewrite sequence 2024-11-18 12:19:37 +08:00
occheung 5cb565a7e0 coremgr: current_payload -> config_payload 2024-11-18 12:19:37 +08:00
occheung 59954829a2 drtio-proto: (N)ACK -> Reply { succeeded } 2024-11-18 12:19:37 +08:00
occheung 960864c847 drtio-proto: add coremgmt-over-drtio messages 2024-11-18 12:19:37 +08:00
occheung bdc29e5709 runtime: support coremgmt on satellites 2024-11-18 12:19:37 +08:00
occheung 332732dc44 satman: implement cfg/mgmt operations 2024-11-18 12:19:37 +08:00
occheung 244c7396d9 runtime: handle drtio-eem satellite disconnection 2024-11-18 12:08:44 +08:00
newell 2c633409b8 Set FCLK0 for EBAZ4205
EBAZ4205 uses FCLK0 as the RTIO clock.

If the user modifies the gateware to use an external clock, FCLK0 is not used.
Co-authored-by: newell <newell.jensen@gmail.com>
Co-committed-by: newell <newell.jensen@gmail.com>
2024-11-17 10:08:43 +08:00
Sebastien Bourdeauducq 9774b39fd8 flake: update zynq-rs 2024-11-16 17:32:05 +08:00
Sebastien Bourdeauducq 9054e4a7cb flake: update zynq-rs, switch to oxalica rust overlay 2024-11-16 17:22:01 +08:00
newell d79bf8d54a gateware: Add default TTLs to EBAZ4205 (#335)
Co-authored-by: newell <newell.jensen@gmail.com>
Co-committed-by: newell <newell.jensen@gmail.com>
2024-11-16 10:40:45 +08:00
Sebastien Bourdeauducq 75e7fc55a3 flake: update dependencies 2024-11-16 10:39:39 +08:00
architeuthidae 24a4d79f0f README: general update 2024-11-07 19:07:38 +01:00
43 changed files with 2177 additions and 822 deletions

View File

@ -4,60 +4,92 @@ ARTIQ on Zynq
How to use
----------
1. Install the ARTIQ version that corresponds to the artiq-zynq version you are targeting.
2. To obtain firmware binaries, select the latest successful build on [Hydra](https://nixbld.m-labs.hk/) for the targeted artiq-zynq version, or use AFWS. If using Hydra, search for the job named ``<board>-<variant>-sd`` (for example: ``zc706-nist_clock-sd`` or ``zc706-nist_qc2-sd``).
3. Place the ``boot.bin`` file, obtained from Hydra's "binary distribution" download link or from AFWS, at the root of a FAT-formatted SD card.
4. Optionally, create a ``config.txt`` configuration file at the root of the SD card containing ``key=value`` pairs on each line. Use the ``ip``, ``ip6`` and ``mac`` keys to respectively set the IPv4, IPv6 and MAC address of the board. Configuring an IPv6 address is entirely optional. If these keys are not found, the firmware will use default values that may or may not be compatible with your network.
5. Insert the SD card into the board and set up the board to boot from the SD card. For the ZC706, this is achieved by placing the large DIP switch SW11 in the 00110 position.
6. Power up the board. After the firmware starts successfully, it should respond to ping at its IP addresses, and boot messages can be observed from its UART at 115200bps.
7. Create and use an ARTIQ device database as usual, but set ``"target": "cortexa9"`` in the arguments of the core device.
1. [Install ARTIQ](https://m-labs.hk/artiq/manual/installing.html). Get the corresponding version to the ``artiq-zynq`` version you are targeting.
2. To obtain firmware binaries, use AFWS or build your own; see [the ARTIQ manual](https://m-labs.hk/artiq/manual/building_developing.html) for detailed instructions or skip to "Development" below. ZC706 variants only can also be downloaded from latest successful build on [Hydra](https://nixbld.m-labs.hk/).
3. Place ``boot.bin`` file at the root ``/`` of a FAT-formatted SD card.
4. Optionally, create a ``config.txt`` configuration file containing ``key=value`` pairs on each line and place it at the root of the SD card. See below for valid keys. The ``ip``, ``ip6`` and ``mac`` keys can be used to set networking information. If these keys are not found, the firmware will use default values which may or may not be compatible with your network.
5. Insert the SD card into the board and set the board to boot from the SD card. For ZC706, this is achieved by placing the large DIP switch SW11 into the 00110 position. On Kasli-SoC, place the BOOT MODE switches to SD.
6. Power up the board. After successful boot the firmware should respond to ping at its IP addresses. Boot output can be observed from UART at 115200bps 8-N-1.
7. Create and use an ARTIQ device database as usual.
Configuration
-------------
Configuring the device is done using the ``config.txt`` text file at the root of the SD card, plus the contents of the ``config`` folder. When searching for a configuration key, the firmware first looks for a file named ``/config/[key].bin`` and, if it exists, returns the contents of that file. If not, it looks into ``/config.txt``, which contains a list of ``key=value`` pairs, one per line. The ``config`` folder allows configuration values that consist in binary data, such as the startup kernel.
Configuring the device is done using the ``config.txt`` text file at the root of the SD card plus optionally a ``config`` folder. When searching for a configuration key, the firmware first looks for a file named ``/config/[key].bin`` and, if it exists, returns the contents of that file. If not, it looks into ``/config.txt``, which should contain a list of ``key=value`` pairs, one per line. ``config.txt`` should be used for most keys but the ``config`` folder allows for setting configuration values which consist of binary data, such as the startup kernel.
The following configuration keys are available:
The following configuration keys are available among others:
- ``mac``: Ethernet MAC address.
- ``ip``: IPv4 address.
- ``ip6``: IPv6 address.
- ``startup``: startup kernel in ELF format (as produced by ``artiq_compile``).
- ``idle_kernel``: idle kernel in ELF format (as produced by ``artiq_compile``).
- ``startup_kernel``: startup kernel in ELF format (as produced by ``artiq_compile``).
- ``rtio_clock``: source of RTIO clock; valid values are ``ext0_bypass`` and ``int_125``.
- ``boot``: SD card "boot.bin" file, for replacing the boot firmware/gateware. Write only.
Configurations can be read/written/removed via ``artiq_coremgmt``. Config erase is
not implemented as it seems not very useful.
See [ARTIQ manual](https://m-labs.hk/artiq/manual-beta/core_device.html#configuration-storage) for full list. Configurations can be read/written/removed with ``artiq_coremgmt``. Config erase is not implemented, as it isn't particularly useful.
For convenience, the ``boot`` key can be used with ``artiq_coremgmt`` and a ``boot.bin`` file to replace firmware/gateware in a running system. This key is read-only. When loading ``boot.bin`` onto the SD card directly, place it at the root and not in the ``config`` folder.
Development instructions
------------------------
ARTIQ on Zynq is packaged using the [Nix](https://nixos.org) Flakes system. Install Nix 2.8+ and enable flakes by adding ``experimental-features = nix-command flakes`` to ``nix.conf`` (e.g. ``~/.config/nix/nix.conf``).
ARTIQ on Zynq is packaged using [Nix](https://nixos.org) Flakes. Install Nix 2.8+ and enable flakes by adding ``experimental-features = nix-command flakes`` to ``nix.conf`` (e.g. ``~/.config/nix/nix.conf``).
Pure build with Nix and execution on a remote JTAG server:
**Pure build with Nix:**
```shell
nix build .#zc706-nist_clock-jtag # or zc706-nist_qc2-jtag or zc706-nist_clock_satellite-jtag etc.
./remote_run.sh
nix build .#zc706-nist_clock-jtag # or zc706-nist_qc2-jtag or zc706-nist_clock-sd or etc
```
Impure incremental build and execution on a remote JTAG server:
Run ``nix flake show`` to see all valid build targets. Targets suffixed with ``-jtag`` produce separate firmware and gateware files, intended for use in booting via JTAG server/Ethernet, e.g. ``./remote_run.sh -i`` with a remote JTAG server. Targets suffixed with ``-sd`` will produce ``boot.bin`` file suitable for SD card boot. ``-firmware`` and ``-gateware`` respectively build firmware and gateware only.
The Kasli-SoC target requires a system description file as input. See ARTIQ manual for exact instructions or use incremental build.
**Impure incremental build:**
For boards with fixed variants, i.e. ZC706, etc. :
```shell
nix develop
cd src
gateware/zc706.py -g ../build/gateware -V <variant> # build gateware
make GWARGS="-V <variant>" <runtime/satman> # build firmware
cd ..
./remote_run.sh -i
gateware/<board>.py -g ../build/gateware -V <variant> # gateware
make GWARGS="-V <variant>" <runtime/satman> # firmware
```
For boards with system descriptions, i.e. Kasli-SoC, etc. :
```shell
nix develop
cd src
gateware/<board>.py -g ../build/gateware <description.json> # gateware
make TARGET=<board> GWARGS="path/to/description.json" <runtime/satman> # firmware
```
``szl.elf`` can be obtained with:
```shell
nix build git+https://git.m-labs.hk/m-labs/zynq-rs#<board>-szl
```
To generate ``boot.bin`` use ``mkbootimage``, e.g.:
```shell
echo "the_ROM_image:
{
[bootloader]result/szl.elf
gateware/top.bit
firmware/armv7-none-eabihf/release/<runtime/satman>
}
EOF" >> boot.bif
mkbootimage boot.bif boot.bin
```
Notes:
- The impure build process is also compatible with non-Nix systems.
- When calling make, you need to specify both the variant and firmware type.
- Firmware type must be either ``runtime`` for DRTIO-less or DRTIO master variants, or ``satman`` for DRTIO satellite.
- If the board is connected to the local machine, use the ``local_run.sh`` script.
- If the board is connected to the local machine by JTAG, use the ``local_run.sh`` script.
- A known Xilinx hardware bug prevents repeatedly loading the bootloader over JTAG without a POR reset. If booting over JTAG, install a jumper on ``PS_POR_B`` and use the POR reset script [here](https://git.m-labs.hk/M-Labs/zynq-rs/src/branch/master/kasli_soc_por.py).
Pre-Commit Hooks
----------------

View File

@ -53,13 +53,21 @@ device_db = {
},
}
# TTLs starting at RTIO channel 2, ending at RTIO channel 15
for i in range(2, 16):
device_db["ttl" + str(i)] = {
"type": "local",
"module": "artiq.coredevice.ttl",
"class": "TTLInOut",
"arguments": {"channel": i},
}
device_db.update(
spi0={
"type": "local",
"module": "artiq.coredevice.spi2",
"class": "SPIMaster",
"arguments": {"channel": 2},
"arguments": {"channel": 16},
},
dds0={
"type": "local",

View File

@ -11,11 +11,11 @@
"src-pythonparser": "src-pythonparser"
},
"locked": {
"lastModified": 1729249162,
"narHash": "sha256-o3UROeulca0x5LQ6PlVILKEnZfhLElUA6qnNJ4Uwjmk=",
"lastModified": 1732066716,
"narHash": "sha256-krjvt9+RccnAxSEZcFhRpjA2S3CoqE4MSa1JUg421b4=",
"ref": "refs/heads/master",
"rev": "02235b2d80780de2ce0bb3cea09fe05be191fa5b",
"revCount": 9039,
"rev": "270a417a28b516d36983779a1adb6d33a3c55a4a",
"revCount": 9102,
"type": "git",
"url": "https://github.com/m-labs/artiq.git"
},
@ -68,45 +68,13 @@
"type": "github"
}
},
"mozilla-overlay": {
"flake": false,
"locked": {
"lastModified": 1704373101,
"narHash": "sha256-+gi59LRWRQmwROrmE1E2b3mtocwueCQqZ60CwLG+gbg=",
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"rev": "9b11a87c0cc54e308fa83aac5b4ee1816d5418a2",
"type": "github"
},
"original": {
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"type": "github"
}
},
"mozilla-overlay_2": {
"flake": false,
"locked": {
"lastModified": 1704373101,
"narHash": "sha256-+gi59LRWRQmwROrmE1E2b3mtocwueCQqZ60CwLG+gbg=",
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"rev": "9b11a87c0cc54e308fa83aac5b4ee1816d5418a2",
"type": "github"
},
"original": {
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1728492678,
"narHash": "sha256-9UTxR8eukdg+XZeHgxW5hQA9fIKHsKCdOIUycTryeVw=",
"lastModified": 1731319897,
"narHash": "sha256-PbABj4tnbWFMfBp6OcUK5iGy1QY+/Z96ZcLpooIbuEI=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5633bcff0c6162b9e4b5f1264264611e950c8ec7",
"rev": "dc460ec76cbff0e66e269457d7b728432263166c",
"type": "github"
},
"original": {
@ -119,7 +87,6 @@
"root": {
"inputs": {
"artiq": "artiq",
"mozilla-overlay": "mozilla-overlay",
"zynq-rs": "zynq-rs"
}
},
@ -145,6 +112,28 @@
"type": "github"
}
},
"rust-overlay_2": {
"inputs": {
"nixpkgs": [
"zynq-rs",
"nixpkgs"
]
},
"locked": {
"lastModified": 1719454714,
"narHash": "sha256-MojqG0lyUINkEk0b3kM2drsU5vyaF8DFZe/FAlZVOGs=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "d1c527659cf076ecc4b96a91c702d080b213801e",
"type": "github"
},
"original": {
"owner": "oxalica",
"ref": "snapshot/2024-08-01",
"repo": "rust-overlay",
"type": "github"
}
},
"sipyco": {
"inputs": {
"nixpkgs": [
@ -185,11 +174,11 @@
"src-misoc": {
"flake": false,
"locked": {
"lastModified": 1728978817,
"narHash": "sha256-b4633jrhh4i+KunZq4kNlyhdm9BCsEJwKs+6KINKV2o=",
"lastModified": 1729234629,
"narHash": "sha256-TLsTCXV5AC2xh+bS7EhBVBKqdqIU3eKrnlWcFF9LtAM=",
"ref": "refs/heads/master",
"rev": "386b544776b66cea148da67d06a4b3a4151179f9",
"revCount": 2459,
"rev": "6085a312bca26adeca6584e37d08c8ba2e1d6e38",
"revCount": 2460,
"submodules": true,
"type": "git",
"url": "https://github.com/m-labs/misoc.git"
@ -233,18 +222,18 @@
},
"zynq-rs": {
"inputs": {
"mozilla-overlay": "mozilla-overlay_2",
"nixpkgs": [
"artiq",
"nixpkgs"
]
],
"rust-overlay": "rust-overlay_2"
},
"locked": {
"lastModified": 1728110308,
"narHash": "sha256-MAoFbcDgr+ZjptFCWfthK+tTnR1NcfuO6tvYhNM2Pwo=",
"lastModified": 1731749494,
"narHash": "sha256-WGigAhvVCGN5YZ1dHPyvoqAh47W1Gtph036O1aKFlLE=",
"ref": "refs/heads/master",
"rev": "cc20478d91e30e1448a4304df7003caed2981b71",
"revCount": 651,
"rev": "12975de2e110d7948bf47b768559f727d0abc8fc",
"revCount": 655,
"type": "git",
"url": "https://git.m-labs.hk/m-labs/zynq-rs"
},

View File

@ -2,15 +2,15 @@
description = "ARTIQ port to the Zynq-7000 platform";
inputs.artiq.url = git+https://github.com/m-labs/artiq.git;
inputs.mozilla-overlay = { url = github:mozilla/nixpkgs-mozilla; flake = false; };
inputs.zynq-rs.url = git+https://git.m-labs.hk/m-labs/zynq-rs;
inputs.zynq-rs.inputs.nixpkgs.follows = "artiq/nixpkgs";
outputs = { self, mozilla-overlay, zynq-rs, artiq }:
outputs = { self, zynq-rs, artiq }:
let
pkgs = import artiq.inputs.nixpkgs { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) ]; };
pkgs = import artiq.inputs.nixpkgs { system = "x86_64-linux"; overlays = [ (import zynq-rs.inputs.rust-overlay) ]; };
zynqpkgs = zynq-rs.packages.x86_64-linux;
artiqpkgs = artiq.packages.x86_64-linux;
llvmPackages_11 = zynq-rs.llvmPackages_11;
rust = zynq-rs.rust;
rustPlatform = zynq-rs.rustPlatform;
@ -125,7 +125,7 @@
lockFile = src/Cargo.lock;
outputHashes = {
"tar-no-std-0.1.8" = "sha256-xm17108v4smXOqxdLvHl9CxTCJslmeogjm4Y87IXFuM=";
"fatfs-0.4.0" = "sha256-P7IgvhwTPXtNhcyv8cFqwO2UdaEcCGJY7UBG6+yBFSg=";
"nalgebra-0.32.6" = "sha256-L/YudkVOtfGYoNQKBD7LMk/sMYgRDzPDdpGL5rO7G2I=";
};
};
@ -133,12 +133,12 @@
pkgs.gnumake
(pkgs.python3.withPackages(ps: [ ps.jsonschema artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq ]))
zynqpkgs.cargo-xbuild
pkgs.llvmPackages_18.llvm
pkgs.llvmPackages_18.clang-unwrapped
llvmPackages_11.llvm
llvmPackages_11.clang-unwrapped
];
buildPhase = ''
export XARGO_RUST_SRC="${rust}/lib/rustlib/src/rust/library"
export CLANG_EXTRA_INCLUDE_DIR="${pkgs.llvmPackages_18.clang-unwrapped.lib}/lib/clang/18/include"
export CLANG_EXTRA_INCLUDE_DIR="${llvmPackages_11.clang-unwrapped.lib}/lib/clang/11.1.0/include"
export CARGO_HOME=$(mktemp -d cargo-home.XXX)
export ZYNQ_RS=${zynq-rs}
make TARGET=${target} GWARGS="${if json == null then "-V ${variant}" else json}" ${fwtype}
@ -372,8 +372,8 @@
name = "artiq-zynq-dev-shell";
buildInputs = with pkgs; [
rust
llvmPackages_18.llvm
llvmPackages_18.clang-unwrapped
llvmPackages_11.llvm
llvmPackages_11.clang-unwrapped
gnumake
cacert
zynqpkgs.cargo-xbuild
@ -387,7 +387,7 @@
pre-commit
];
XARGO_RUST_SRC = "${rust}/lib/rustlib/src/rust/library";
CLANG_EXTRA_INCLUDE_DIR = "${pkgs.llvmPackages_18.clang-unwrapped.lib}/lib/clang/18/include";
CLANG_EXTRA_INCLUDE_DIR = "${llvmPackages_11.clang-unwrapped.lib}/lib/clang/11.1.0/include";
ZYNQ_RS = "${zynq-rs}";
OPENOCD_ZYNQ = "${zynq-rs}/openocd";
SZL = "${zynqpkgs.szl}";

66
src/Cargo.lock generated
View File

@ -46,12 +46,6 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "build_const"
version = "0.2.2"
@ -88,9 +82,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "compiler_builtins"
version = "0.1.109"
version = "0.1.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f11973008a8cf741fe6d22f339eba21fd0ca81e2760a769ba8243ed6c21edd7e"
checksum = "3748f82c7d366a0b4950257d19db685d4958d2fa27c6d164a3f069fec42b748b"
[[package]]
name = "core_io"
version = "0.1.20210325"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97f8932064288cc79feb4d343a399d353a6f6f001e586ece47fe518a9e8507df"
dependencies = [
"rustc_version",
]
[[package]]
name = "crc"
@ -138,10 +141,13 @@ dependencies = [
[[package]]
name = "fatfs"
version = "0.4.0"
source = "git+https://github.com/rafalh/rust-fatfs?rev=85f06e0#85f06e08edbd3368e1b0562f2fc1b6d178bf7b8a"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e18f80a87439240dac45d927fd8f8081b6f1e34c03e97271189fa8a8c2e96c8f"
dependencies = [
"bitflags 2.6.0",
"bitflags",
"byteorder",
"core_io",
"log",
]
@ -223,6 +229,7 @@ name = "io"
version = "0.0.0"
dependencies = [
"byteorder",
"core_io",
"libsupport_zynq",
]
@ -232,6 +239,7 @@ version = "0.1.0"
dependencies = [
"build_zynq",
"byteorder",
"core_io",
"cslice",
"dwarf",
"dyld",
@ -270,6 +278,7 @@ name = "libboard_artiq"
version = "0.0.0"
dependencies = [
"build_zynq",
"core_io",
"crc",
"embedded-hal",
"io",
@ -313,6 +322,7 @@ dependencies = [
name = "libconfig"
version = "0.1.0"
dependencies = [
"core_io",
"fatfs",
"libboard_zynq",
"log",
@ -384,9 +394,8 @@ checksum = "c75de51135344a4f8ed3cfe2720dc27736f7711989703a0b43aadf3753c55577"
[[package]]
name = "nalgebra"
version = "0.33.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26aecdf64b707efd1310e3544d709c5c0ac61c13756046aaaba41be5c4f66a3b"
version = "0.32.6"
source = "git+https://git.m-labs.hk/M-Labs/nalgebra.git?rev=dd00f9b#dd00f9b46046e0b931d1b470166db02fd29591be"
dependencies = [
"approx",
"num-complex",
@ -510,6 +519,7 @@ dependencies = [
"async-recursion",
"build_zynq",
"byteorder",
"core_io",
"cslice",
"dwarf",
"dyld",
@ -535,11 +545,23 @@ dependencies = [
"void",
]
[[package]]
name = "rustc_version"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
dependencies = [
"semver",
]
[[package]]
name = "satman"
version = "0.0.0"
dependencies = [
"build_zynq",
"byteorder",
"core_io",
"crc",
"cslice",
"embedded-hal",
"io",
@ -557,10 +579,16 @@ dependencies = [
]
[[package]]
name = "simba"
version = "0.9.0"
name = "semver"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3a386a501cd104797982c15ae17aafe8b9261315b5d07e3ec803f2ea26be0fa"
checksum = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac"
[[package]]
name = "simba"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50582927ed6f77e4ac020c057f37a268fc6aebc29225050365aacbb9deeeddc4"
dependencies = [
"approx",
"num-complex",
@ -574,7 +602,7 @@ version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e4a069bef843d170df47e7c0a8bf8d037f217d9f5b325865acc3e466ffe40d3"
dependencies = [
"bitflags 1.3.2",
"bitflags",
"byteorder",
"managed",
]
@ -596,7 +624,7 @@ version = "0.1.8"
source = "git+https://git.m-labs.hk/M-Labs/tar-no-std?rev=2ab6dc5#2ab6dc58e5249c59c4eb03eaf3a119bcdd678d32"
dependencies = [
"arrayvec",
"bitflags 1.3.2",
"bitflags",
"log",
]

View File

@ -14,5 +14,5 @@ members = [
panic = "abort"
debug = true
codegen-units = 1
opt-level = 1
opt-level = 2
lto = true

View File

@ -5,7 +5,7 @@ import argparse
import analyzer
import dma
from artiq.gateware import rtio
from artiq.gateware.rtio.phy import dds, spi2, ttl_simple
from artiq.gateware.rtio.phy import spi2, ttl_simple
from artiq.gateware.rtio.xilinx_clocking import fix_serdes_timing_path
from config import write_csr_file, write_mem_file, write_rustc_cfg_file
from migen import *
@ -91,6 +91,17 @@ _spi = [
]
# Connector DATA1
def _create_ttl():
_ttl = []
for idx, elem in enumerate([x for x in range(5, 21) if x not in (10, 12)]):
_ttl.append(
("ttl", idx, Pins("DATA1:DATA1-{}".format(elem)), IOStandard("LVCMOS33")),
)
return _ttl
class EBAZ4205(SoCCore):
def __init__(self, rtio_clk=125e6, acpki=False):
self.acpki = acpki
@ -105,6 +116,7 @@ class EBAZ4205(SoCCore):
platform.add_extension(_ddr)
platform.add_extension(_i2c)
platform.add_extension(_spi)
platform.add_extension(_create_ttl())
gmii = platform.request("gmii")
platform.add_period_constraint(gmii.rx_clk, 10)
@ -180,6 +192,13 @@ class EBAZ4205(SoCCore):
self.submodules += phy
self.rtio_channels.append(rtio.Channel.from_phy(phy))
for i in range(14):
print("TTL at RTIO channel 0x{:06x}".format(len(self.rtio_channels)))
ttl = self.platform.request("ttl", i)
phy = ttl_simple.InOut(ttl)
self.submodules += phy
self.rtio_channels.append(rtio.Channel.from_phy(phy))
print("SPI at RTIO channel 0x{:06x}".format(len(self.rtio_channels)))
spi_phy = spi2.SPIMaster(platform.request("spi"))
self.submodules += spi_phy

View File

@ -20,6 +20,7 @@ build_zynq = { path = "../libbuild_zynq" }
log = "0.4"
log_buffer = { version = "1.2" }
crc = { version = "1.7", default-features = false }
core_io = { version = "0.1", features = ["collections"] }
embedded-hal = "0.2"
nb = "1.0"
void = { version = "1", default-features = false }

View File

@ -185,6 +185,24 @@ unsafe fn align_comma(timer: &mut GlobalTimer) {
}
}
pub unsafe fn align_wordslip(timer: &mut GlobalTimer, trx_no: u8) -> bool {
pl::csr::eem_transceiver::transceiver_sel_write(trx_no);
for slip in 0..=1 {
pl::csr::eem_transceiver::wordslip_write(slip as u8);
timer.delay_us(1);
pl::csr::eem_transceiver::comma_align_reset_write(1);
timer.delay_us(100);
if pl::csr::eem_transceiver::comma_read() == 1 {
debug!("comma alignment completed with {} wordslip", slip);
return true;
}
}
false
}
pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
for trx_no in 0..pl::csr::CONFIG_EEM_DRTIO_COUNT {
unsafe {
@ -222,7 +240,6 @@ pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
unsafe {
align_comma(timer);
pl::csr::eem_transceiver::rx_ready_write(1);
}
}
}

View File

@ -1,15 +1,16 @@
use core::slice;
use core_io::{Error as IoError, ErrorKind as IoErrorKind};
use crc;
use io::{proto::{ProtoRead, ProtoWrite},
Cursor, Error as IoError};
Cursor};
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
pub use crate::drtioaux_proto::Packet;
use crate::{drtioaux_proto::Error as ProtocolError, mem::mem::DRTIOAUX_MEM, pl::csr::DRTIOAUX};
#[derive(Debug)]
pub enum Error<T> {
pub enum Error {
GatewareError,
CorruptedPacket,
@ -19,17 +20,17 @@ pub enum Error<T> {
RoutingError,
Protocol(ProtocolError<T>),
Protocol(ProtocolError),
}
impl<T> From<ProtocolError<T>> for Error<T> {
fn from(value: ProtocolError<T>) -> Error<T> {
impl From<ProtocolError> for Error {
fn from(value: ProtocolError) -> Error {
Error::Protocol(value)
}
}
impl<T> From<IoError<T>> for Error<T> {
fn from(value: IoError<T>) -> Error<T> {
impl From<IoError> for Error {
fn from(value: IoError) -> Error {
Error::Protocol(ProtocolError::Io(value))
}
}
@ -56,8 +57,8 @@ pub fn has_rx_error(linkno: u8) -> bool {
}
}
fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error<!>>
where F: FnOnce(&[u8]) -> Result<T, Error<!>> {
fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error>
where F: FnOnce(&[u8]) -> Result<T, Error> {
let linkidx = linkno as usize;
unsafe {
if (DRTIOAUX[linkidx].aux_rx_present_read)() == 1 {
@ -72,14 +73,14 @@ where F: FnOnce(&[u8]) -> Result<T, Error<!>> {
}
}
pub fn recv(linkno: u8) -> Result<Option<Packet>, Error<!>> {
pub fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
if has_rx_error(linkno) {
return Err(Error::GatewareError);
}
receive(linkno, |buffer| {
if buffer.len() < 8 {
return Err(IoError::UnexpectedEnd.into());
return Err(IoError::new(IoErrorKind::UnexpectedEof, "Unexpected end").into());
}
let mut reader = Cursor::new(buffer);
@ -96,7 +97,7 @@ pub fn recv(linkno: u8) -> Result<Option<Packet>, Error<!>> {
})
}
pub fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTimer) -> Result<Packet, Error<!>> {
pub fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTimer) -> Result<Packet, Error> {
let timeout_ms = Milliseconds(timeout_ms.unwrap_or(10));
let limit = timer.get_time() + timeout_ms;
while timer.get_time() < limit {
@ -108,8 +109,8 @@ pub fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTimer) ->
Err(Error::TimedOut)
}
fn transmit<F>(linkno: u8, f: F) -> Result<(), Error<!>>
where F: FnOnce(&mut [u8]) -> Result<usize, Error<!>> {
fn transmit<F>(linkno: u8, f: F) -> Result<(), Error>
where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
let linkno = linkno as usize;
unsafe {
while (DRTIOAUX[linkno].aux_tx_read)() != 0 {}
@ -121,7 +122,7 @@ where F: FnOnce(&mut [u8]) -> Result<usize, Error<!>> {
}
}
pub fn send(linkno: u8, packet: &Packet) -> Result<(), Error<!>> {
pub fn send(linkno: u8, packet: &Packet) -> Result<(), Error> {
transmit(linkno, |buffer| {
let mut writer = Cursor::new(buffer);

View File

@ -1,8 +1,9 @@
use core::slice;
use core_io::{Error as IoError, ErrorKind as IoErrorKind};
use crc;
use io::{proto::{ProtoRead, ProtoWrite},
Cursor, Error as IoError};
Cursor};
use libasync::{block_async, task};
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
use nb;
@ -34,8 +35,8 @@ fn tx_ready(linkno: usize) -> nb::Result<(), Void> {
}
}
async fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error<!>>
where F: FnOnce(&[u8]) -> Result<T, Error<!>> {
async fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error>
where F: FnOnce(&[u8]) -> Result<T, Error> {
let linkidx = linkno as usize;
unsafe {
if (DRTIOAUX[linkidx].aux_rx_present_read)() == 1 {
@ -50,14 +51,14 @@ where F: FnOnce(&[u8]) -> Result<T, Error<!>> {
}
}
pub async fn recv(linkno: u8) -> Result<Option<Packet>, Error<!>> {
pub async fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
if has_rx_error(linkno) {
return Err(Error::GatewareError);
}
receive(linkno, |buffer| {
if buffer.len() < 8 {
return Err(IoError::UnexpectedEnd.into());
return Err(IoError::new(IoErrorKind::UnexpectedEof, "Unexpected end").into());
}
let mut reader = Cursor::new(buffer);
@ -75,7 +76,7 @@ pub async fn recv(linkno: u8) -> Result<Option<Packet>, Error<!>> {
.await
}
pub async fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTimer) -> Result<Packet, Error<!>> {
pub async fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTimer) -> Result<Packet, Error> {
let timeout_ms = Milliseconds(timeout_ms.unwrap_or(10));
let limit = timer.get_time() + timeout_ms;
let mut would_block = false;
@ -95,8 +96,8 @@ pub async fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTime
Err(Error::TimedOut)
}
async fn transmit<F>(linkno: u8, f: F) -> Result<(), Error<!>>
where F: FnOnce(&mut [u8]) -> Result<usize, Error<!>> {
async fn transmit<F>(linkno: u8, f: F) -> Result<(), Error>
where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
let linkno = linkno as usize;
unsafe {
let _ = block_async!(tx_ready(linkno)).await;
@ -108,7 +109,7 @@ where F: FnOnce(&mut [u8]) -> Result<usize, Error<!>> {
}
}
pub async fn send(linkno: u8, packet: &Packet) -> Result<(), Error<!>> {
pub async fn send(linkno: u8, packet: &Packet) -> Result<(), Error> {
transmit(linkno, |buffer| {
let mut writer = Cursor::new(buffer);

View File

@ -1,4 +1,4 @@
use io::{Error as IoError, Read, Write};
use core_io::{Error as IoError, Read, Write};
use io::proto::{ProtoRead, ProtoWrite};
const MAX_PACKET: usize = 1024;
@ -10,13 +10,13 @@ pub const SAT_PAYLOAD_MAX_SIZE: usize = /*max size*/MAX_PACKET - /*CRC*/4 - /*p
pub const MASTER_PAYLOAD_MAX_SIZE: usize = SAT_PAYLOAD_MAX_SIZE - /*source*/1 - /*destination*/1 - /*ID*/4;
#[derive(Debug)]
pub enum Error<T> {
pub enum Error {
UnknownPacket(u8),
Io(IoError<T>),
Io(IoError),
}
impl<T> From<IoError<T>> for Error<T> {
fn from(value: IoError<T>) -> Error<T> {
impl From<IoError> for Error {
fn from(value: IoError) -> Error {
Error::Io(value)
}
}
@ -288,10 +288,81 @@ pub enum Packet {
SubkernelMessageAck {
destination: u8,
},
CoreMgmtGetLogRequest {
destination: u8,
clear: bool,
},
CoreMgmtClearLogRequest {
destination: u8,
},
CoreMgmtSetLogLevelRequest {
destination: u8,
log_level: u8,
},
CoreMgmtSetUartLogLevelRequest {
destination: u8,
log_level: u8,
},
CoreMgmtConfigReadRequest {
destination: u8,
length: u16,
key: [u8; MASTER_PAYLOAD_MAX_SIZE],
},
CoreMgmtConfigReadContinue {
destination: u8,
},
CoreMgmtConfigWriteRequest {
destination: u8,
last: bool,
length: u16,
data: [u8; MASTER_PAYLOAD_MAX_SIZE],
},
CoreMgmtConfigRemoveRequest {
destination: u8,
length: u16,
key: [u8; MASTER_PAYLOAD_MAX_SIZE],
},
CoreMgmtConfigEraseRequest {
destination: u8,
},
CoreMgmtRebootRequest {
destination: u8,
},
CoreMgmtAllocatorDebugRequest {
destination: u8,
},
CoreMgmtFlashRequest {
destination: u8,
payload_length: u32,
},
CoreMgmtFlashAddDataRequest {
destination: u8,
last: bool,
length: u16,
data: [u8; MASTER_PAYLOAD_MAX_SIZE],
},
CoreMgmtDropLinkAck {
destination: u8,
},
CoreMgmtDropLink,
CoreMgmtGetLogReply {
last: bool,
length: u16,
data: [u8; SAT_PAYLOAD_MAX_SIZE],
},
CoreMgmtConfigReadReply {
last: bool,
length: u16,
value: [u8; SAT_PAYLOAD_MAX_SIZE],
},
CoreMgmtReply {
succeeded: bool,
},
}
impl Packet {
pub fn read_from<R>(reader: &mut R) -> Result<Self, Error<R::ReadError>>
pub fn read_from<R>(reader: &mut R) -> Result<Self, Error>
where R: Read + ?Sized {
Ok(match reader.read_u8()? {
0x00 => Packet::EchoRequest,
@ -565,11 +636,120 @@ impl Packet {
destination: reader.read_u8()?,
},
0xd0 => Packet::CoreMgmtGetLogRequest {
destination: reader.read_u8()?,
clear: reader.read_bool()?,
},
0xd1 => Packet::CoreMgmtClearLogRequest {
destination: reader.read_u8()?,
},
0xd2 => Packet::CoreMgmtSetLogLevelRequest {
destination: reader.read_u8()?,
log_level: reader.read_u8()?,
},
0xd3 => Packet::CoreMgmtSetUartLogLevelRequest {
destination: reader.read_u8()?,
log_level: reader.read_u8()?,
},
0xd4 => {
let destination = reader.read_u8()?;
let length = reader.read_u16()?;
let mut key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut key[0..length as usize])?;
Packet::CoreMgmtConfigReadRequest {
destination: destination,
length: length,
key: key,
}
}
0xd5 => Packet::CoreMgmtConfigReadContinue {
destination: reader.read_u8()?,
},
0xd6 => {
let destination = reader.read_u8()?;
let last = reader.read_bool()?;
let length = reader.read_u16()?;
let mut data: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut data[0..length as usize])?;
Packet::CoreMgmtConfigWriteRequest {
destination: destination,
last: last,
length: length,
data: data,
}
}
0xd7 => {
let destination = reader.read_u8()?;
let length = reader.read_u16()?;
let mut key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut key[0..length as usize])?;
Packet::CoreMgmtConfigRemoveRequest {
destination: destination,
length: length,
key: key,
}
}
0xd8 => Packet::CoreMgmtConfigEraseRequest {
destination: reader.read_u8()?,
},
0xd9 => Packet::CoreMgmtRebootRequest {
destination: reader.read_u8()?,
},
0xda => Packet::CoreMgmtAllocatorDebugRequest {
destination: reader.read_u8()?,
},
0xdb => Packet::CoreMgmtFlashRequest {
destination: reader.read_u8()?,
payload_length: reader.read_u32()?,
},
0xdc => {
let destination = reader.read_u8()?;
let last = reader.read_bool()?;
let length = reader.read_u16()?;
let mut data: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut data[0..length as usize])?;
Packet::CoreMgmtFlashAddDataRequest {
destination: destination,
last: last,
length: length,
data: data,
}
}
0xdd => Packet::CoreMgmtDropLinkAck {
destination: reader.read_u8()?,
},
0xde => Packet::CoreMgmtDropLink,
0xdf => {
let last = reader.read_bool()?;
let length = reader.read_u16()?;
let mut data: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut data[0..length as usize])?;
Packet::CoreMgmtGetLogReply {
last: last,
length: length,
data: data,
}
}
0xe0 => {
let last = reader.read_bool()?;
let length = reader.read_u16()?;
let mut value: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut value[0..length as usize])?;
Packet::CoreMgmtConfigReadReply {
last: last,
length: length,
value: value,
}
}
0xe1 => Packet::CoreMgmtReply {
succeeded: reader.read_bool()?,
},
ty => return Err(Error::UnknownPacket(ty)),
})
}
pub fn write_to<W>(&self, writer: &mut W) -> Result<(), IoError<W::WriteError>>
pub fn write_to<W>(&self, writer: &mut W) -> Result<(), IoError>
where W: Write + ?Sized {
match *self {
Packet::EchoRequest => writer.write_u8(0x00)?,
@ -942,6 +1122,115 @@ impl Packet {
writer.write_u8(0xcc)?;
writer.write_u8(destination)?;
}
Packet::CoreMgmtGetLogRequest { destination, clear } => {
writer.write_u8(0xd0)?;
writer.write_u8(destination)?;
writer.write_bool(clear)?;
}
Packet::CoreMgmtClearLogRequest { destination } => {
writer.write_u8(0xd1)?;
writer.write_u8(destination)?;
}
Packet::CoreMgmtSetLogLevelRequest { destination, log_level } => {
writer.write_u8(0xd2)?;
writer.write_u8(destination)?;
writer.write_u8(log_level)?;
}
Packet::CoreMgmtSetUartLogLevelRequest { destination, log_level } => {
writer.write_u8(0xd3)?;
writer.write_u8(destination)?;
writer.write_u8(log_level)?;
}
Packet::CoreMgmtConfigReadRequest {
destination,
length,
key,
} => {
writer.write_u8(0xd4)?;
writer.write_u8(destination)?;
writer.write_u16(length)?;
writer.write_all(&key[0..length as usize])?;
}
Packet::CoreMgmtConfigReadContinue { destination } => {
writer.write_u8(0xd5)?;
writer.write_u8(destination)?;
}
Packet::CoreMgmtConfigWriteRequest {
destination,
last,
length,
data,
} => {
writer.write_u8(0xd6)?;
writer.write_u8(destination)?;
writer.write_bool(last)?;
writer.write_u16(length)?;
writer.write_all(&data[0..length as usize])?;
}
Packet::CoreMgmtConfigRemoveRequest {
destination,
length,
key,
} => {
writer.write_u8(0xd7)?;
writer.write_u8(destination)?;
writer.write_u16(length)?;
writer.write_all(&key[0..length as usize])?;
}
Packet::CoreMgmtConfigEraseRequest { destination } => {
writer.write_u8(0xd8)?;
writer.write_u8(destination)?;
}
Packet::CoreMgmtRebootRequest { destination } => {
writer.write_u8(0xd9)?;
writer.write_u8(destination)?;
}
Packet::CoreMgmtAllocatorDebugRequest { destination } => {
writer.write_u8(0xda)?;
writer.write_u8(destination)?;
}
Packet::CoreMgmtFlashRequest {
destination,
payload_length,
} => {
writer.write_u8(0xdb)?;
writer.write_u8(destination)?;
writer.write_u32(payload_length)?;
}
Packet::CoreMgmtFlashAddDataRequest {
destination,
last,
length,
data,
} => {
writer.write_u8(0xdc)?;
writer.write_u8(destination)?;
writer.write_bool(last)?;
writer.write_u16(length)?;
writer.write_all(&data[..length as usize])?;
}
Packet::CoreMgmtDropLinkAck { destination } => {
writer.write_u8(0xdd)?;
writer.write_u8(destination)?;
}
Packet::CoreMgmtDropLink => writer.write_u8(0xde)?,
Packet::CoreMgmtGetLogReply { last, length, data } => {
writer.write_u8(0xdf)?;
writer.write_bool(last)?;
writer.write_u16(length)?;
writer.write_all(&data[0..length as usize])?;
}
Packet::CoreMgmtConfigReadReply { last, length, value } => {
writer.write_u8(0xe0)?;
writer.write_bool(last)?;
writer.write_u16(length)?;
writer.write_all(&value[0..length as usize])?;
}
Packet::CoreMgmtReply { succeeded } => {
writer.write_u8(0xe1)?;
writer.write_bool(succeeded)?;
}
}
Ok(())
}
@ -978,7 +1267,9 @@ impl Packet {
| Packet::SubkernelLoadRunReply { .. }
| Packet::SubkernelMessageAck { .. }
| Packet::DmaPlaybackStatus { .. }
| Packet::SubkernelFinished { .. } => false,
| Packet::SubkernelFinished { .. }
| Packet::CoreMgmtDropLinkAck { .. }
| Packet::InjectionRequest { .. } => false,
_ => true,
}
}

View File

@ -1,6 +1,5 @@
use libboard_zynq::{println, stdio};
use libcortex_a9::{interrupt_handler, regs::MPIDR};
use core::arch::asm;
use libregister::RegisterR;
#[cfg(has_si549)]

View File

@ -1,8 +1,9 @@
#![no_std]
#![feature(never_type)]
#![feature(naked_functions)]
#![allow(unexpected_cfgs)]
#![feature(asm)]
extern crate core_io;
extern crate crc;
extern crate embedded_hal;
extern crate io;

View File

@ -1,5 +1,3 @@
#![allow(unexpected_cfgs)]
use std::{env,
fs::File,
io::{BufRead, BufReader, Write},

View File

@ -85,10 +85,7 @@ unsafe fn get_ttype_entry(
encoding | DW_EH_PE_pcrel,
ttype_base,
)
.map(|v| match v {
ttype_base => None,
ttype_entry => Some(ttype_entry as *const u8),
})
.map(|v| (v != ttype_base).then(|| v as *const u8))
}
pub unsafe fn find_eh_action(

View File

@ -8,6 +8,7 @@ name = "io"
path = "lib.rs"
[dependencies]
core_io = { version = "0.1", features = ["collections"] }
byteorder = { version = "1.0", default-features = false, optional = true }
libsupport_zynq = { path = "@@ZYNQ_RS@@/libsupport_zynq", default-features = false, features = ["alloc_core"] }

View File

@ -1,7 +1,7 @@
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use crate::{Read, Write};
use core_io::{Error as IoError, Read, Write};
#[derive(Debug, Clone)]
pub struct Cursor<T> {
@ -42,9 +42,7 @@ impl<T> Cursor<T> {
}
impl<T: AsRef<[u8]>> Read for Cursor<T> {
type ReadError = !;
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::ReadError> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, IoError> {
let data = &self.inner.as_ref()[self.pos..];
let len = buf.len().min(data.len());
// ``copy_from_slice`` generates AXI bursts, use a regular loop instead
@ -57,10 +55,7 @@ impl<T: AsRef<[u8]>> Read for Cursor<T> {
}
impl Write for Cursor<&mut [u8]> {
type WriteError = !;
type FlushError = !;
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::WriteError> {
fn write(&mut self, buf: &[u8]) -> Result<usize, IoError> {
let data = &mut self.inner[self.pos..];
let len = buf.len().min(data.len());
for i in 0..len {
@ -71,23 +66,20 @@ impl Write for Cursor<&mut [u8]> {
}
#[inline]
fn flush(&mut self) -> Result<(), Self::FlushError> {
fn flush(&mut self) -> Result<(), IoError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
impl Write for Cursor<Vec<u8>> {
type WriteError = !;
type FlushError = !;
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::WriteError> {
fn write(&mut self, buf: &[u8]) -> Result<usize, IoError> {
self.inner.extend_from_slice(buf);
Ok(buf.len())
}
#[inline]
fn flush(&mut self) -> Result<(), Self::FlushError> {
fn flush(&mut self) -> Result<(), IoError> {
Ok(())
}
}

View File

@ -1,9 +1,9 @@
#![no_std]
#![feature(never_type)]
#![allow(unexpected_cfgs)]
#[cfg(feature = "alloc")]
extern crate alloc;
extern crate core_io;
#[cfg(feature = "byteorder")]
extern crate byteorder;
@ -12,142 +12,8 @@ pub mod cursor;
#[cfg(feature = "byteorder")]
pub mod proto;
use core::fmt::{Display, Formatter};
pub use cursor::Cursor;
#[cfg(all(feature = "byteorder", feature = "alloc"))]
pub use proto::ReadStringError;
#[cfg(feature = "byteorder")]
pub use proto::{ProtoRead, ProtoWrite};
#[derive(Debug, Clone, PartialEq)]
pub enum Error<T> {
UnexpectedEnd,
Other(T),
}
impl<T> From<T> for Error<T> {
fn from(value: T) -> Error<T> {
Error::Other(value)
}
}
impl<T: Display> Display for Error<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
match self {
Error::UnexpectedEnd => write!(f, "unexpected end of stream"),
Error::Other(other) => write!(f, "other IO error: {}", other),
}
}
}
pub trait Read {
type ReadError;
/// Pull some bytes from this source into the specified buffer, returning
/// how many bytes were read.
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::ReadError>;
/// Read the exact number of bytes required to fill `buf`.
fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<(), Error<Self::ReadError>> {
while !buf.is_empty() {
let read_bytes = self.read(buf)?;
if read_bytes == 0 {
return Err(Error::UnexpectedEnd);
}
buf = &mut { buf }[read_bytes..];
}
Ok(())
}
}
impl<'a, T: Read> Read for &'a mut T {
type ReadError = T::ReadError;
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::ReadError> {
T::read(self, buf)
}
}
pub trait Write {
type WriteError;
type FlushError;
/// Write a buffer into this object, returning how many bytes were written.
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::WriteError>;
/// Flush this output stream, ensuring that all intermediately buffered contents
/// reach their destination.
fn flush(&mut self) -> Result<(), Self::FlushError>;
/// Attempts to write an entire buffer into `self`.
fn write_all(&mut self, mut buf: &[u8]) -> Result<(), Error<Self::WriteError>> {
while buf.len() > 0 {
let written_bytes = self.write(buf)?;
if written_bytes == 0 {
return Err(Error::UnexpectedEnd);
}
buf = &buf[written_bytes..];
}
Ok(())
}
/// Hints the writer how much bytes will be written after call to this function.
///
/// At least `min` bytes should be written after the call to this function and
/// if `max` is `Some(x)` than at most `x` bytes should be written.
fn size_hint(&mut self, _min: usize, _max: Option<usize>) {}
}
impl<'a, T: Write> Write for &'a mut T {
type WriteError = T::WriteError;
type FlushError = T::FlushError;
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::WriteError> {
T::write(self, buf)
}
fn flush(&mut self) -> Result<(), Self::FlushError> {
T::flush(self)
}
fn size_hint(&mut self, min: usize, max: Option<usize>) {
T::size_hint(self, min, max)
}
}
impl<'a> Write for &'a mut [u8] {
type WriteError = !;
type FlushError = !;
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::WriteError> {
let len = buf.len().min(self.len());
self[..len].copy_from_slice(&buf[..len]);
Ok(len)
}
#[inline]
fn flush(&mut self) -> Result<(), Self::FlushError> {
Ok(())
}
}
#[cfg(feature = "alloc")]
impl<'a> Write for alloc::vec::Vec<u8> {
type WriteError = !;
type FlushError = !;
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::WriteError> {
self.extend_from_slice(buf);
Ok(buf.len())
}
#[inline]
fn flush(&mut self) -> Result<(), Self::FlushError> {
Ok(())
}
}

View File

@ -3,9 +3,7 @@ use alloc::{string::String, vec};
use core::str::Utf8Error;
use byteorder::{ByteOrder, NativeEndian};
use Error as IoError;
use Read;
use Write;
use core_io::{Error as IoError, Read, Write};
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq)]
@ -149,7 +147,7 @@ pub trait ProtoWrite {
impl<T> ProtoRead for T
where T: Read + ?Sized
{
type ReadError = IoError<T::ReadError>;
type ReadError = IoError;
fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::ReadError> {
T::read_exact(self, buf)
@ -159,7 +157,7 @@ where T: Read + ?Sized
impl<T> ProtoWrite for T
where T: Write + ?Sized
{
type WriteError = IoError<T::WriteError>;
type WriteError = IoError;
fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::WriteError> {
T::write_all(self, buf)

View File

@ -12,12 +12,12 @@ build_zynq = { path = "../libbuild_zynq" }
cslice = "0.3"
log = "0.4"
nb = "0.1"
core_io = { version = "0.1", features = ["collections"] }
byteorder = { version = "1.3", default-features = false }
void = { version = "1", default-features = false }
log_buffer = { version = "1.2" }
libm = { version = "0.2", features = ["unstable"] }
vcell = "0.1"
nalgebra = { version = "0.33.0", default-features = false, features = ["libm", "alloc"]}
libboard_zynq = { path = "@@ZYNQ_RS@@/libboard_zynq", features = ["ipv6"]}
libsupport_zynq = { path = "@@ZYNQ_RS@@/libsupport_zynq", default-features = false, features = ["alloc_core"] }
@ -32,3 +32,9 @@ unwind = { path = "../libunwind" }
libc = { path = "../libc" }
io = { path = "../libio" }
libboard_artiq = { path = "../libboard_artiq" }
[dependencies.nalgebra]
git = "https://git.m-labs.hk/M-Labs/nalgebra.git"
rev = "dd00f9b"
default-features = false
features = ["libm", "alloc"]

View File

@ -14,9 +14,10 @@
use core::mem;
use core_io::Error as ReadError;
use cslice::{AsCSlice, CSlice};
use dwarf::eh::{self, EHAction, EHContext};
use io::{Cursor, Error as ReadError, ProtoRead, Read};
use io::{Cursor, ProtoRead};
use libc::{c_int, c_void, uintptr_t};
use log::{error, trace};
use unwind as uw;
@ -95,30 +96,30 @@ struct ExceptionBuffer {
}
static mut EXCEPTION_BUFFER: ExceptionBuffer = ExceptionBuffer {
uw_exceptions: [ const { uw::_Unwind_Exception {
uw_exceptions: [uw::_Unwind_Exception {
exception_class: EXCEPTION_CLASS,
exception_cleanup: cleanup,
private: [0; uw::unwinder_private_data_size],
} }; MAX_INFLIGHT_EXCEPTIONS],
}; MAX_INFLIGHT_EXCEPTIONS],
exceptions: [None; MAX_INFLIGHT_EXCEPTIONS + 1],
exception_stack: [-1; MAX_INFLIGHT_EXCEPTIONS + 1],
backtrace: [(0, 0); MAX_BACKTRACE_SIZE],
backtrace_size: 0,
stack_pointers: [ const { StackPointerBacktrace {
stack_pointers: [StackPointerBacktrace {
stack_pointer: 0,
initial_backtrace_size: 0,
current_backtrace_size: 0,
} }; MAX_INFLIGHT_EXCEPTIONS + 1],
}; MAX_INFLIGHT_EXCEPTIONS + 1],
exception_count: 0,
};
pub unsafe extern "C" fn reset_exception_buffer() {
trace!("reset exception buffer");
EXCEPTION_BUFFER.uw_exceptions = [ const { uw::_Unwind_Exception {
EXCEPTION_BUFFER.uw_exceptions = [uw::_Unwind_Exception {
exception_class: EXCEPTION_CLASS,
exception_cleanup: cleanup,
private: [0; uw::unwinder_private_data_size],
} }; MAX_INFLIGHT_EXCEPTIONS];
}; MAX_INFLIGHT_EXCEPTIONS];
EXCEPTION_BUFFER.exceptions = [None; MAX_INFLIGHT_EXCEPTIONS + 1];
EXCEPTION_BUFFER.exception_stack = [-1; MAX_INFLIGHT_EXCEPTIONS + 1];
EXCEPTION_BUFFER.backtrace_size = 0;
@ -294,9 +295,7 @@ pub unsafe extern "C" fn raise(exception: *const Exception) -> ! {
unreachable!();
}
fn read_exception_string<'a, 'b>(
reader: &mut Cursor<&'b [u8]>,
) -> Result<CSlice<'a, u8>, ReadError<<Cursor<&'b [u8]> as Read>::ReadError>> {
fn read_exception_string<'a>(reader: &mut Cursor<&[u8]>) -> Result<CSlice<'a, u8>, ReadError> {
let len = reader.read_u32()? as usize;
if len == usize::MAX {
let data = reader.read_u32()?;
@ -312,7 +311,7 @@ fn read_exception_string<'a, 'b>(
}
}
fn read_exception(raw_exception: &[u8]) -> Result<Exception, ReadError<<Cursor<&[u8]> as Read>::ReadError>> {
fn read_exception(raw_exception: &[u8]) -> Result<Exception, ReadError> {
let mut reader = Cursor::new(raw_exception);
let mut byte = reader.read_u8()?;

View File

@ -1,149 +0,0 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// This is the Rust personality function, adapted for use in ARTIQ. We never actually panic
// from Rust or recover from Rust exceptions (there's nothing to catch the panics), but we
// need a personality function to step back through Rust frames in order to make a backtrace.
//
// By design, this personality function is only ever called in the search phase, although
// to keep things simple and close to upstream, it is not modified
use unwind as uw;
use libc::c_int;
use dwarf::eh::{EHAction, EHContext};
// Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister()
// and TargetLowering::getExceptionSelectorRegister() for each architecture,
// then mapped to DWARF register numbers via register definition tables
// (typically <arch>RegisterInfo.td, search for "DwarfRegNum").
// See also http://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register.
#[cfg(target_arch = "x86")]
const UNWIND_DATA_REG: (i32, i32) = (0, 2); // EAX, EDX
#[cfg(target_arch = "x86_64")]
const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX
#[cfg(any(target_arch = "riscv32"))]
const UNWIND_DATA_REG: (i32, i32) = (10, 11); // X10, X11
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1
// The following code is based on GCC's C and C++ personality routines. For reference, see:
// https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc
// https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
#[lang = "eh_personality"]
#[no_mangle]
unsafe extern "C" fn rust_eh_personality(
state: uw::_Unwind_State,
exception_object: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context,
) -> uw::_Unwind_Reason_Code {
let state = state as c_int;
let action = state & uw::_US_ACTION_MASK as c_int;
let search_phase = if action == uw::_US_VIRTUAL_UNWIND_FRAME as c_int {
// Backtraces on ARM will call the personality routine with
// state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
// we want to continue unwinding the stack, otherwise all our backtraces
// would end at __rust_try
if state & uw::_US_FORCE_UNWIND as c_int != 0 {
return continue_unwind(exception_object, context);
}
true
} else if action == uw::_US_UNWIND_FRAME_STARTING as c_int {
false
} else if action == uw::_US_UNWIND_FRAME_RESUME as c_int {
return continue_unwind(exception_object, context);
} else {
return uw::_URC_FAILURE;
};
// The DWARF unwinder assumes that _Unwind_Context holds things like the function
// and LSDA pointers, however ARM EHABI places them into the exception object.
// To preserve signatures of functions like _Unwind_GetLanguageSpecificData(), which
// take only the context pointer, GCC personality routines stash a pointer to
// exception_object in the context, using location reserved for ARM's
// "scratch register" (r12).
uw::_Unwind_SetGR(context, uw::UNWIND_POINTER_REG, exception_object as uw::_Unwind_Ptr);
// ...A more principled approach would be to provide the full definition of ARM's
// _Unwind_Context in our libunwind bindings and fetch the required data from there
// directly, bypassing DWARF compatibility functions.
let eh_action = match find_eh_action(context) {
Ok(action) => action,
Err(_) => return uw::_URC_FAILURE,
};
if search_phase {
match eh_action {
EHAction::None | EHAction::Cleanup(_) => {
return continue_unwind(exception_object, context);
}
EHAction::Catch(_) => {
// EHABI requires the personality routine to update the
// SP value in the barrier cache of the exception object.
(*exception_object).private[5] =
uw::_Unwind_GetGR(context, uw::UNWIND_SP_REG);
return uw::_URC_HANDLER_FOUND;
}
EHAction::Terminate => return uw::_URC_FAILURE,
}
} else {
match eh_action {
EHAction::None => return continue_unwind(exception_object, context),
EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => {
uw::_Unwind_SetGR(
context,
UNWIND_DATA_REG.0,
exception_object as uw::_Unwind_Ptr,
);
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0);
uw::_Unwind_SetIP(context, lpad);
return uw::_URC_INSTALL_CONTEXT;
}
EHAction::Terminate => return uw::_URC_FAILURE,
}
}
// On ARM EHABI the personality routine is responsible for actually
// unwinding a single stack frame before returning (ARM EHABI Sec. 6.1).
unsafe fn continue_unwind(
exception_object: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context,
) -> uw::_Unwind_Reason_Code {
if __gnu_unwind_frame(exception_object, context) == uw::_URC_NO_REASON {
uw::_URC_CONTINUE_UNWIND
} else {
uw::_URC_FAILURE
}
}
// defined in libgcc
extern "C" {
fn __gnu_unwind_frame(
exception_object: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context,
) -> uw::_Unwind_Reason_Code;
}
}
unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) -> Result<EHAction, ()> {
let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
let mut ip_before_instr: c_int = 0;
let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr);
let eh_context = EHContext {
// The return address points 1 byte past the call instruction,
// which could be in the next IP range in LSDA range table.
ip: if ip_before_instr != 0 { ip } else { ip - 1 },
func_start: uw::_Unwind_GetRegionStart(context),
get_text_start: &|| uw::_Unwind_GetTextRelBase(context),
get_data_start: &|| uw::_Unwind_GetDataRelBase(context),
};
dwarf::eh::find_eh_action(lsda, &eh_context, false,0)
}

View File

@ -1,5 +1,5 @@
use core::sync::atomic::{AtomicBool, Ordering};
use core::arch::asm;
use libboard_zynq::{gic, mpcore, println, stdio};
use libcortex_a9::{asm, interrupt_handler, notify_spin_lock, regs::MPIDR, spin_lock_yield};
use libregister::RegisterR;

View File

@ -25,14 +25,12 @@ extern "C" {
}
unsafe fn attribute_writeback(typeinfo: *const ()) {
#[repr(C)]
struct Attr {
offset: usize,
tag: CSlice<'static, u8>,
name: CSlice<'static, u8>,
}
#[repr(C)]
struct Type {
attributes: *const *const Attr,
objects: *const *const (),

View File

@ -1,10 +1,9 @@
#![no_std]
#![feature(c_variadic)]
#![feature(lang_items)]
#![feature(const_btree_len)]
#![feature(generic_const_exprs)]
#![feature(const_btree_new)]
#![feature(const_in_array_repeat_expressions)]
#![feature(naked_functions)]
#![allow(unexpected_cfgs)]
#![feature(asm)]
#[macro_use]
extern crate alloc;
@ -22,7 +21,6 @@ pub use pl::csr::rtio_core;
use void::Void;
pub mod eh_artiq;
pub mod eh_rust;
pub mod i2c;
pub mod irq;
pub mod kernel;

View File

@ -1,8 +1,9 @@
use core::str;
use byteorder::{ByteOrder, NativeEndian};
use core_io::{Error, Read, Write};
use cslice::{CMutSlice, CSlice};
use io::{Error, ProtoRead, ProtoWrite, Read, Write};
use io::{ProtoRead, ProtoWrite};
use log::trace;
use self::tag::{split_tag, Tag, TagIterator};
@ -36,17 +37,16 @@ pub unsafe fn align_ptr_mut<T>(ptr: *mut ()) -> *mut T {
// versions for reader rather than TcpStream
// they will be made into sync for satellite subkernels later
unsafe fn recv_elements<F, R, E>(
unsafe fn recv_elements<F, R>(
reader: &mut R,
elt_tag: Tag,
length: usize,
storage: *mut (),
alloc: &mut F,
) -> Result<(), E>
) -> Result<(), Error>
where
F: FnMut(usize) -> Result<*mut (), E>,
F: FnMut(usize) -> *mut (),
R: Read + ?Sized,
E: From<Error<R::ReadError>>,
{
match elt_tag {
Tag::Bool => {
@ -57,6 +57,7 @@ where
let ptr = storage as *mut u32;
let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 4);
reader.read_exact(dest)?;
drop(dest);
let dest = core::slice::from_raw_parts_mut(ptr, length);
NativeEndian::from_slice_u32(dest);
}
@ -64,6 +65,7 @@ where
let ptr = storage as *mut u64;
let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 8);
reader.read_exact(dest)?;
drop(dest);
let dest = core::slice::from_raw_parts_mut(ptr, length);
NativeEndian::from_slice_u64(dest);
}
@ -77,11 +79,10 @@ where
Ok(())
}
unsafe fn recv_value<F, R, E>(reader: &mut R, tag: Tag, data: &mut *mut (), alloc: &mut F) -> Result<(), E>
unsafe fn recv_value<F, R>(reader: &mut R, tag: Tag, data: &mut *mut (), alloc: &mut F) -> Result<(), Error>
where
F: FnMut(usize) -> Result<*mut (), E>,
F: FnMut(usize) -> *mut (),
R: Read + ?Sized,
E: From<Error<R::ReadError>>,
{
macro_rules! consume_value {
($ty:ty, | $ptr:ident | $map:expr) => {{
@ -108,7 +109,7 @@ where
Tag::String | Tag::Bytes | Tag::ByteArray => {
consume_value!(CMutSlice<u8>, |ptr| {
let length = reader.read_u32()? as usize;
*ptr = CMutSlice::new(alloc(length)? as *mut u8, length);
*ptr = CMutSlice::new(alloc(length) as *mut u8, length);
reader.read_exact((*ptr).as_mut())?;
Ok(())
})
@ -138,7 +139,7 @@ where
let storage_offset = round_up(list_size, tag.alignment());
let storage_size = tag.size() * length;
let allocation = alloc(storage_offset + storage_size)? as *mut u8;
let allocation = alloc(storage_offset + storage_size) as *mut u8;
*ptr_to_list = allocation as *mut List;
let storage = allocation.offset(storage_offset as isize) as *mut ();
@ -157,7 +158,7 @@ where
}
let elt_tag = it.clone().next().expect("truncated tag");
*buffer = alloc(elt_tag.size() * total_len)?;
*buffer = alloc(elt_tag.size() * total_len);
recv_elements(reader, elt_tag, total_len, *buffer, alloc)
})
}
@ -174,16 +175,15 @@ where
}
}
pub fn recv_return<'a, F, R, E>(
pub fn recv_return<'a, F, R>(
reader: &mut R,
tag_bytes: &'a [u8],
data: *mut (),
alloc: &mut F,
) -> Result<&'a [u8], E>
) -> Result<&'a [u8], Error>
where
F: FnMut(usize) -> Result<*mut (), E>,
F: FnMut(usize) -> *mut (),
R: Read + ?Sized,
E: From<Error<R::ReadError>>,
{
let mut it = TagIterator::new(tag_bytes);
trace!("recv ...->{}", it);
@ -201,7 +201,7 @@ unsafe fn send_elements<W>(
length: usize,
data: *const (),
write_tags: bool,
) -> Result<(), Error<W::WriteError>>
) -> Result<(), Error>
where
W: Write + ?Sized,
{
@ -233,15 +233,8 @@ where
Ok(())
}
unsafe fn send_value<W>(
writer: &mut W,
tag: Tag,
data: &mut *const (),
write_tags: bool,
) -> Result<(), Error<W::WriteError>>
where
W: Write + ?Sized,
{
unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const (), write_tags: bool) -> Result<(), Error>
where W: Write + ?Sized {
macro_rules! consume_value {
($ty:ty, | $ptr:ident | $map:expr) => {{
let $ptr = align_ptr::<$ty>(*data);
@ -344,7 +337,7 @@ pub fn send_args<W>(
tag_bytes: &[u8],
data: *const *const (),
write_tags: bool,
) -> Result<(), Error<W::WriteError>>
) -> Result<(), Error>
where
W: Write + ?Sized,
{

View File

@ -1,5 +1,8 @@
#![no_std]
#![feature(link_cfg)]
#![feature(nll)]
#![feature(unwind_attributes)]
#![feature(static_nobundle)]
#![cfg_attr(not(target_env = "msvc"), feature(libc))]
cfg_if::cfg_if! {
@ -14,3 +17,17 @@ cfg_if::cfg_if! {
pub use backtrace::backtrace;
}
}
#[cfg(target_env = "musl")]
#[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))]
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
extern "C" {}
#[cfg(target_os = "redox")]
#[link(name = "gcc_eh", kind = "static-nobundle", cfg(target_feature = "crt-static"))]
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
extern "C" {}
#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
#[link(name = "unwind", kind = "static-nobundle")]
extern "C" {}

View File

@ -77,7 +77,8 @@ pub type _Unwind_Exception_Cleanup_Fn =
all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
link(name = "unwind", kind = "static")
)]
extern "C-unwind" {
extern "C" {
#[unwind(allowed)]
pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void;
@ -225,7 +226,8 @@ if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] {
#[cfg_attr(all(feature = "llvm-libunwind",
any(target_os = "fuchsia", target_os = "linux")),
link(name = "unwind", kind = "static"))]
extern "C-unwind" {
extern "C" {
#[unwind(allowed)]
pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
trace_argument: *mut c_void)
@ -236,7 +238,8 @@ if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] {
#[cfg_attr(all(feature = "llvm-libunwind",
any(target_os = "fuchsia", target_os = "linux")),
link(name = "unwind", kind = "static"))]
extern "C-unwind" {
extern "C" {
#[unwind(allowed)]
pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
}

View File

@ -20,6 +20,8 @@ num-derive = "0.3"
cslice = "0.3"
log = "0.4"
embedded-hal = "0.2"
core_io = { version = "0.1", features = ["collections"] }
crc = { version = "1.7", default-features = false }
byteorder = { version = "1.3", default-features = false }
void = { version = "1", default-features = false }
futures = { version = "0.3", default-features = false, features = ["async-await"] }

View File

@ -1,4 +1,3 @@
#![allow(unexpected_cfgs)]
extern crate build_zynq;
fn main() {

View File

@ -1,12 +1,12 @@
use alloc::{collections::BTreeMap, rc::Rc, string::String, vec, vec::Vec};
use core::{cell::RefCell, fmt, slice, str};
use core_io::Error as IoError;
use cslice::CSlice;
use dyld::elf;
use futures::{future::FutureExt, select_biased};
#[cfg(has_drtio)]
use io::Cursor;
use io::Error as IoError;
#[cfg(has_drtio)]
use ksupport::rpc;
use ksupport::{kernel, resolve_channel_name};
@ -78,8 +78,8 @@ impl From<smoltcp::Error> for Error {
}
}
impl<T> From<IoError<T>> for Error {
fn from(_error: IoError<T>) -> Self {
impl From<IoError> for Error {
fn from(_error: IoError) -> Self {
Error::IoError
}
}
@ -488,14 +488,14 @@ async fn handle_run_kernel(
kernel::Message::RpcRecvRequest(slot) => slot,
other => panic!("expected root value slot from core1, not {:?}", other),
};
let remaining_tags = rpc::recv_return(&mut reader, &current_tags, slot, &mut |size| -> Result<*mut ()> {
let remaining_tags = rpc::recv_return(&mut reader, &current_tags, slot, &mut |size| {
if size == 0 {
Ok(0 as *mut ())
0 as *mut ()
} else {
let mut control = control.borrow_mut();
control.tx.send(kernel::Message::RpcRecvReply(Ok(size)));
match control.rx.recv() {
kernel::Message::RpcRecvRequest(slot) => Ok(slot),
kernel::Message::RpcRecvRequest(slot) => slot,
other => {
panic!("expected nested value slot from kernel CPU, not {:?}", other)
}
@ -785,7 +785,15 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
let cfg = Rc::new(cfg);
let restart_idle = Rc::new(Semaphore::new(1, 1));
mgmt::start(cfg.clone(), restart_idle.clone());
mgmt::start(
cfg.clone(),
restart_idle.clone(),
Some(mgmt::DrtioContext(
aux_mutex.clone(),
drtio_routing_table.clone(),
timer,
)),
);
task::spawn(async move {
let connection = Rc::new(Semaphore::new(1, 1));
@ -911,7 +919,7 @@ pub fn soft_panic_main(timer: GlobalTimer, cfg: Config) -> ! {
Sockets::init(32);
let dummy = Rc::new(Semaphore::new(0, 1));
mgmt::start(Rc::new(cfg), dummy);
mgmt::start(Rc::new(cfg), dummy, None);
// getting eth settings disables the LED as it resets GPIO
// need to re-enable it here

View File

@ -1,9 +1,9 @@
#![no_std]
#![no_main]
#![recursion_limit = "1024"] // for futures_util::select!
#![allow(unexpected_cfgs)]
#![feature(alloc_error_handler)]
#![feature(const_btree_len)]
#![feature(const_btree_new)]
#![feature(panic_info_message)]
#[macro_use]
extern crate alloc;

View File

@ -1,17 +1,22 @@
use alloc::{rc::Rc, string::String, vec::Vec};
use core::cell::RefCell;
use byteorder::{ByteOrder, NativeEndian};
use crc::crc32;
use futures::{future::poll_fn, task::Poll};
use libasync::{smoltcp::TcpStream, task};
use libboard_artiq::logger::{BufferLogger, LogBufferRef};
use libboard_zynq::{slcr, smoltcp};
use libboard_artiq::{drtio_routing::RoutingTable,
logger::{BufferLogger, LogBufferRef}};
use libboard_zynq::{smoltcp, timer::GlobalTimer};
use libconfig::Config;
use libcortex_a9::semaphore::Semaphore;
use log::{self, debug, error, info, warn, LevelFilter};
use libcortex_a9::{mutex::Mutex, semaphore::Semaphore};
use log::{self, debug, error, info, warn};
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
use crate::proto_async::*;
#[cfg(has_drtio)]
use crate::rtio_mgt::drtio;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error {
@ -19,6 +24,8 @@ pub enum Error {
UnknownLogLevel(u8),
UnexpectedPattern,
UnrecognizedPacket,
#[cfg(has_drtio)]
DrtioError(drtio::Error),
}
type Result<T> = core::result::Result<T, Error>;
@ -30,6 +37,8 @@ impl core::fmt::Display for Error {
&Error::UnknownLogLevel(lvl) => write!(f, "unknown log level {}", lvl),
&Error::UnexpectedPattern => write!(f, "unexpected pattern"),
&Error::UnrecognizedPacket => write!(f, "unrecognized packet"),
#[cfg(has_drtio)]
&Error::DrtioError(error) => write!(f, "drtio error: {}", error),
}
}
}
@ -40,6 +49,13 @@ impl From<smoltcp::Error> for Error {
}
}
#[cfg(has_drtio)]
impl From<drtio::Error> for Error {
fn from(error: drtio::Error) -> Self {
Error::DrtioError(error)
}
}
#[derive(Debug, FromPrimitive)]
pub enum Request {
GetLog = 1,
@ -52,6 +68,11 @@ pub enum Request {
ConfigRead = 12,
ConfigWrite = 13,
ConfigRemove = 14,
ConfigErase = 15,
DebugAllocator = 8,
Flash = 9,
}
#[repr(i8)]
@ -112,35 +133,605 @@ async fn read_key(stream: &mut TcpStream) -> Result<String> {
Ok(String::from_utf8(buffer).unwrap())
}
async fn handle_connection(
stream: &mut TcpStream,
pull_id: Rc<RefCell<u32>>,
cfg: Rc<Config>,
restart_idle: Rc<Semaphore>,
) -> Result<()> {
if !expect(&stream, b"ARTIQ management\n").await? {
return Err(Error::UnexpectedPattern);
}
stream.send_slice("e".as_bytes()).await?;
#[cfg(has_drtio)]
mod remote_coremgmt {
use core_io::Read;
use io::ProtoWrite;
use libboard_artiq::{drtioaux_async,
drtioaux_proto::{Packet, MASTER_PAYLOAD_MAX_SIZE}};
use super::*;
pub async fn get_log(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
) -> Result<()> {
let mut buffer = Vec::new();
loop {
let msg = read_i8(stream).await;
if let Err(smoltcp::Error::Finished) = msg {
let reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtGetLogRequest {
destination,
clear: false,
},
timer,
)
.await;
match reply {
Ok(Packet::CoreMgmtGetLogReply { last, length, data }) => {
buffer.extend(&data[..length as usize]);
if last {
write_i8(stream, Reply::LogContent as i8).await?;
write_chunk(stream, &buffer).await?;
return Ok(());
}
let msg: Request = FromPrimitive::from_i8(msg?).ok_or(Error::UnrecognizedPacket)?;
match msg {
Request::GetLog => {
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
write_i8(stream, Reply::Error as i8).await?;
return Err(drtio::Error::UnexpectedReply.into());
}
Err(e) => {
error!("aux packet error ({})", e);
write_i8(stream, Reply::Error as i8).await?;
return Err(e.into());
}
}
}
}
pub async fn clear_log(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
) -> Result<()> {
let reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtClearLogRequest { destination },
timer,
)
.await;
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
write_i8(stream, Reply::Success as i8).await?;
Ok(())
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
write_i8(stream, Reply::Error as i8).await?;
Err(drtio::Error::UnexpectedReply.into())
}
Err(e) => {
error!("aux packet error ({})", e);
write_i8(stream, Reply::Error as i8).await?;
Err(e.into())
}
}
}
pub async fn pull_log(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
pull_id: &Rc<RefCell<u32>>,
) -> Result<()> {
let id = {
let mut guard = pull_id.borrow_mut();
*guard += 1;
*guard
};
let mut buffer = Vec::new();
loop {
if id != *pull_id.borrow() {
// another connection attempts to pull the log...
// abort this connection...
break;
}
let reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtGetLogRequest {
destination,
clear: true,
},
timer,
)
.await;
match reply {
Ok(Packet::CoreMgmtGetLogReply { last, length, data }) => {
buffer.extend(&data[..length as usize]);
if last {
write_chunk(stream, &buffer).await?;
buffer.clear();
task::r#yield().await;
}
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
return Err(drtio::Error::UnexpectedReply.into());
}
Err(e) => {
error!("aux packet error ({})", e);
return Err(e.into());
}
}
}
Ok(())
}
pub async fn set_log_filter(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
level: log::LevelFilter,
) -> Result<()> {
let reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtSetLogLevelRequest {
destination,
log_level: level as u8,
},
timer,
)
.await;
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
write_i8(stream, Reply::Success as i8).await?;
Ok(())
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
write_i8(stream, Reply::Error as i8).await?;
Err(drtio::Error::UnexpectedReply.into())
}
Err(e) => {
error!("aux packet error ({})", e);
write_i8(stream, Reply::Error as i8).await?;
Err(e.into())
}
}
}
pub async fn set_uart_log_filter(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
level: log::LevelFilter,
) -> Result<()> {
let reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtSetUartLogLevelRequest {
destination,
log_level: level as u8,
},
timer,
)
.await;
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
write_i8(stream, Reply::Success as i8).await?;
Ok(())
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
write_i8(stream, Reply::Error as i8).await?;
Err(drtio::Error::UnexpectedReply.into())
}
Err(e) => {
error!("aux packet error ({})", e);
write_i8(stream, Reply::Error as i8).await?;
Err(e.into())
}
}
}
pub async fn config_read(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
_cfg: &Rc<Config>,
key: &String,
) -> Result<()> {
let mut config_key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
let len = key.len();
config_key[..len].clone_from_slice(key.as_bytes());
let mut reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtConfigReadRequest {
destination: destination,
length: len as u16,
key: config_key,
},
timer,
)
.await;
let mut buffer = Vec::<u8>::new();
loop {
match reply {
Ok(Packet::CoreMgmtConfigReadReply { last, length, value }) => {
buffer.extend(&value[..length as usize]);
if last {
write_i8(stream, Reply::ConfigData as i8).await?;
write_chunk(stream, &buffer).await?;
return Ok(());
}
reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtConfigReadContinue {
destination: destination,
},
timer,
)
.await;
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
write_i8(stream, Reply::Error as i8).await?;
return Err(drtio::Error::UnexpectedReply.into());
}
Err(e) => {
error!("aux packet error ({})", e);
write_i8(stream, Reply::Error as i8).await?;
return Err(e.into());
}
}
}
}
pub async fn config_write(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
_cfg: &Rc<Config>,
key: &String,
value: Vec<u8>,
_restart_idle: &Rc<Semaphore>,
) -> Result<()> {
let mut message = Vec::with_capacity(key.len() + value.len() + 4 * 2);
message.write_string(key).unwrap();
message.write_bytes(&value).unwrap();
match drtio::partition_data(
linkno,
aux_mutex,
routing_table,
timer,
&message,
|slice, status, len: usize| Packet::CoreMgmtConfigWriteRequest {
destination: destination,
last: status.is_last(),
length: len as u16,
data: *slice,
},
|reply| match reply {
Packet::CoreMgmtReply { succeeded: true } => Ok(()),
packet => {
error!("received unexpected aux packet: {:?}", packet);
Err(drtio::Error::UnexpectedReply)
}
},
)
.await
{
Ok(()) => {
write_i8(stream, Reply::Success as i8).await?;
Ok(())
}
Err(e) => {
error!("aux packet error ({})", e);
write_i8(stream, Reply::Error as i8).await?;
Err(e.into())
}
}
}
pub async fn config_remove(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
_cfg: &Rc<Config>,
key: &String,
_restart_idle: &Rc<Semaphore>,
) -> Result<()> {
let mut config_key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
let len = key.len();
config_key[..len].clone_from_slice(key.as_bytes());
let reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtConfigRemoveRequest {
destination: destination,
length: len as u16,
key: config_key,
},
timer,
)
.await;
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
write_i8(stream, Reply::Success as i8).await?;
Ok(())
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
write_i8(stream, Reply::Error as i8).await?;
Err(drtio::Error::UnexpectedReply.into())
}
Err(e) => {
error!("aux packet error ({})", e);
write_i8(stream, Reply::Error as i8).await?;
Err(e.into())
}
}
}
pub async fn config_erase(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
) -> Result<()> {
let reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtConfigEraseRequest {
destination: destination,
},
timer,
)
.await;
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
write_i8(stream, Reply::Success as i8).await?;
Ok(())
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
write_i8(stream, Reply::Error as i8).await?;
Err(drtio::Error::UnexpectedReply.into())
}
Err(e) => {
error!("aux packet error ({})", e);
write_i8(stream, Reply::Error as i8).await?;
Err(e.into())
}
}
}
pub async fn reboot(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
) -> Result<()> {
let reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtRebootRequest {
destination: destination,
},
timer,
)
.await;
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
write_i8(stream, Reply::RebootImminent as i8).await?;
Ok(())
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
write_i8(stream, Reply::Error as i8).await?;
Err(drtio::Error::UnexpectedReply.into())
}
Err(e) => {
error!("aux packet error ({})", e);
write_i8(stream, Reply::Error as i8).await?;
Err(e.into())
}
}
}
pub async fn debug_allocator(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
) -> Result<()> {
let reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtAllocatorDebugRequest {
destination: destination,
},
timer,
)
.await;
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
write_i8(stream, Reply::Success as i8).await?;
Ok(())
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
Err(drtio::Error::UnexpectedReply.into())
}
Err(e) => {
error!("aux packet error ({})", e);
Err(e.into())
}
}
}
pub async fn image_write(
stream: &mut TcpStream,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
timer: GlobalTimer,
linkno: u8,
destination: u8,
_cfg: &Rc<Config>,
image: Vec<u8>,
) -> Result<()> {
let mut image = &image[..];
let alloc_reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtFlashRequest {
destination: destination,
payload_length: image.len() as u32,
},
timer,
)
.await;
match alloc_reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => Ok(()),
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
write_i8(stream, Reply::Error as i8).await?;
Err(drtio::Error::UnexpectedReply)
}
Err(e) => {
error!("aux packet error ({})", e);
write_i8(stream, Reply::Error as i8).await?;
Err(drtio::Error::AuxError)
}
}?;
while !image.is_empty() {
let mut data = [0; MASTER_PAYLOAD_MAX_SIZE];
let len = image.read(&mut data).unwrap();
let last = image.is_empty();
let reply = drtio::aux_transact(
aux_mutex,
linkno,
routing_table,
&Packet::CoreMgmtFlashAddDataRequest {
destination: destination,
last: last,
length: len as u16,
data: data,
},
timer,
)
.await;
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) if !last => Ok(()),
Ok(Packet::CoreMgmtDropLink) if last => drtioaux_async::send(
linkno,
&Packet::CoreMgmtDropLinkAck {
destination: destination,
},
)
.await
.map_err(|_| drtio::Error::AuxError),
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
write_i8(stream, Reply::Error as i8).await?;
Err(drtio::Error::UnexpectedReply)
}
Err(e) => {
error!("aux packet error ({})", e);
write_i8(stream, Reply::Error as i8).await?;
Err(drtio::Error::AuxError)
}
}?;
}
write_i8(stream, Reply::RebootImminent as i8).await?;
Ok(())
}
}
mod local_coremgmt {
use libboard_zynq::slcr;
use super::*;
pub async fn get_log(stream: &mut TcpStream) -> Result<()> {
let buffer = get_logger_buffer().await.extract().as_bytes().to_vec();
write_i8(stream, Reply::LogContent as i8).await?;
write_chunk(stream, &buffer).await?;
Ok(())
}
Request::ClearLog => {
pub async fn clear_log(stream: &mut TcpStream) -> Result<()> {
let mut buffer = get_logger_buffer().await;
buffer.clear();
write_i8(stream, Reply::Success as i8).await?;
Ok(())
}
Request::PullLog => {
pub async fn pull_log(stream: &mut TcpStream, pull_id: &Rc<RefCell<u32>>) -> Result<()> {
let id = {
let mut guard = pull_id.borrow_mut();
*guard += 1;
@ -157,32 +748,34 @@ async fn handle_connection(
buffer.clear();
core::mem::drop(buffer);
write_chunk(stream, &bytes).await?;
if log::max_level() == LevelFilter::Trace {
if log::max_level() == log::LevelFilter::Trace {
// temporarily discard all trace level log
let logger = unsafe { BufferLogger::get_logger().as_mut().unwrap() };
logger.set_buffer_log_level(LevelFilter::Debug);
logger.set_buffer_log_level(log::LevelFilter::Debug);
stream.flush().await?;
logger.set_buffer_log_level(LevelFilter::Trace);
logger.set_buffer_log_level(log::LevelFilter::Trace);
}
}
Ok(())
}
Request::SetLogFilter => {
let lvl = read_log_level_filter(stream).await?;
pub async fn set_log_filter(stream: &mut TcpStream, lvl: log::LevelFilter) -> Result<()> {
info!("Changing log level to {}", lvl);
log::set_max_level(lvl);
write_i8(stream, Reply::Success as i8).await?;
Ok(())
}
Request::SetUartLogFilter => {
let lvl = read_log_level_filter(stream).await?;
pub async fn set_uart_log_filter(stream: &mut TcpStream, lvl: log::LevelFilter) -> Result<()> {
info!("Changing UART log level to {}", lvl);
unsafe {
BufferLogger::get_logger().as_ref().unwrap().set_uart_log_level(lvl);
}
write_i8(stream, Reply::Success as i8).await?;
Ok(())
}
Request::ConfigRead => {
let key = read_key(stream).await?;
debug!("read key: {}", key);
pub async fn config_read(stream: &mut TcpStream, cfg: &Rc<Config>, key: &String) -> Result<()> {
let value = cfg.read(&key);
if let Ok(value) = value {
debug!("got value");
@ -192,18 +785,17 @@ async fn handle_connection(
warn!("read error: no such key");
write_i8(stream, Reply::Error as i8).await?;
}
Ok(())
}
Request::ConfigWrite => {
let key = read_key(stream).await?;
debug!("write key: {}", key);
let len = read_i32(stream).await?;
let len = if len <= 0 { 0 } else { len as usize };
let mut buffer = Vec::with_capacity(len);
unsafe {
buffer.set_len(len);
}
read_chunk(stream, &mut buffer).await?;
let value = cfg.write(&key, buffer);
pub async fn config_write(
stream: &mut TcpStream,
cfg: &Rc<Config>,
key: &String,
value: Vec<u8>,
restart_idle: &Rc<Semaphore>,
) -> Result<()> {
let value = cfg.write(&key, value);
if value.is_ok() {
debug!("write success");
if key == "idle_kernel" {
@ -215,9 +807,15 @@ async fn handle_connection(
error!("failed to write: {:?}", value);
write_i8(stream, Reply::Error as i8).await?;
}
Ok(())
}
Request::ConfigRemove => {
let key = read_key(stream).await?;
pub async fn config_remove(
stream: &mut TcpStream,
cfg: &Rc<Config>,
key: &String,
restart_idle: &Rc<Semaphore>,
) -> Result<()> {
debug!("erase key: {}", key);
let value = cfg.remove(&key);
if value.is_ok() {
@ -230,18 +828,179 @@ async fn handle_connection(
warn!("erase failed");
write_i8(stream, Reply::Error as i8).await?;
}
Ok(())
}
Request::Reboot => {
pub async fn config_erase(stream: &mut TcpStream) -> Result<()> {
error!("zynq device does not support config erase");
write_i8(stream, Reply::Error as i8).await?;
Ok(())
}
pub async fn reboot(stream: &mut TcpStream) -> Result<()> {
info!("rebooting");
write_i8(stream, Reply::RebootImminent as i8).await?;
stream.flush().await?;
slcr::reboot();
unreachable!()
}
pub async fn debug_allocator(_stream: &mut TcpStream) -> Result<()> {
error!("zynq device does not support allocator debug print");
Ok(())
}
pub async fn image_write(stream: &mut TcpStream, cfg: &Rc<Config>, image: Vec<u8>) -> Result<()> {
let mut image = image.clone();
let image_ref = &image[..];
let bin_len = image.len() - 4;
let (image_ref, expected_crc) = {
let (image_ref, crc_slice) = image_ref.split_at(bin_len);
(image_ref, NativeEndian::read_u32(crc_slice))
};
let actual_crc = crc32::checksum_ieee(image_ref);
if actual_crc == expected_crc {
info!("CRC passed. Writing boot image to SD card...");
image.truncate(bin_len);
cfg.write("boot", image).expect("failed to write boot image");
reboot(stream).await?;
} else {
error!(
"CRC failed, images have not been written to flash.\n(actual {:08x}, expected {:08x})",
actual_crc, expected_crc
);
write_i8(stream, Reply::Error as i8).await?;
}
Ok(())
}
}
pub fn start(cfg: Rc<Config>, restart_idle: Rc<Semaphore>) {
#[cfg(has_drtio)]
macro_rules! process {
($stream: ident, $drtio_context:ident, $destination:expr, $func:ident $(, $param:expr)*) => {{
if $destination == 0 {
local_coremgmt::$func($stream, $($param, )*).await
} else if let Some(DrtioContext(ref aux_mutex, ref routing_table, timer)) = $drtio_context {
let routing_table = routing_table.borrow();
let linkno = routing_table.0[$destination as usize][0] - 1 as u8;
remote_coremgmt::$func($stream, &aux_mutex, &routing_table, timer, linkno, $destination, $($param, )*).await
} else {
error!("coremgmt-over-drtio not supported for panicked device, please reboot");
write_i8($stream, Reply::Error as i8).await?;
Err(drtio::Error::LinkDown.into())
}
}}
}
#[cfg(not(has_drtio))]
macro_rules! process {
($stream: ident, $drtio_context:ident, $destination:expr, $func:ident $(, $param:expr)*) => {{
local_coremgmt::$func($stream, $($param, )*).await
}}
}
#[derive(Clone)]
pub struct DrtioContext(pub Rc<Mutex<bool>>, pub Rc<RefCell<RoutingTable>>, pub GlobalTimer);
async fn handle_connection(
stream: &mut TcpStream,
pull_id: Rc<RefCell<u32>>,
cfg: Rc<Config>,
restart_idle: Rc<Semaphore>,
_drtio_context: Option<DrtioContext>,
) -> Result<()> {
if !expect(&stream, b"ARTIQ management\n").await? {
return Err(Error::UnexpectedPattern);
}
let _destination: u8 = read_i8(stream).await? as u8;
stream.send_slice("e".as_bytes()).await?;
loop {
let msg = read_i8(stream).await;
if let Err(smoltcp::Error::Finished) = msg {
return Ok(());
}
let msg: Request = FromPrimitive::from_i8(msg?).ok_or(Error::UnrecognizedPacket)?;
match msg {
Request::GetLog => process!(stream, _drtio_context, _destination, get_log),
Request::ClearLog => process!(stream, _drtio_context, _destination, clear_log),
Request::PullLog => process!(stream, _drtio_context, _destination, pull_log, &pull_id),
Request::SetLogFilter => {
let lvl = read_log_level_filter(stream).await?;
process!(stream, _drtio_context, _destination, set_log_filter, lvl)
}
Request::SetUartLogFilter => {
let lvl = read_log_level_filter(stream).await?;
process!(stream, _drtio_context, _destination, set_uart_log_filter, lvl)
}
Request::ConfigRead => {
let key = read_key(stream).await?;
process!(stream, _drtio_context, _destination, config_read, &cfg, &key)
}
Request::ConfigWrite => {
let key = read_key(stream).await?;
let len = read_i32(stream).await?;
let len = if len <= 0 { 0 } else { len as usize };
let mut buffer = Vec::with_capacity(len);
unsafe {
buffer.set_len(len);
}
read_chunk(stream, &mut buffer).await?;
process!(
stream,
_drtio_context,
_destination,
config_write,
&cfg,
&key,
buffer,
&restart_idle
)
}
Request::ConfigRemove => {
let key = read_key(stream).await?;
process!(
stream,
_drtio_context,
_destination,
config_remove,
&cfg,
&key,
&restart_idle
)
}
Request::Reboot => {
process!(stream, _drtio_context, _destination, reboot)
}
Request::ConfigErase => {
process!(stream, _drtio_context, _destination, config_erase)
}
Request::DebugAllocator => {
process!(stream, _drtio_context, _destination, debug_allocator)
}
Request::Flash => {
let len = read_i32(stream).await?;
if len <= 0 {
write_i8(stream, Reply::Error as i8).await?;
return Err(Error::UnexpectedPattern);
}
let mut buffer = Vec::with_capacity(len as usize);
unsafe {
buffer.set_len(len as usize);
}
read_chunk(stream, &mut buffer).await?;
process!(stream, _drtio_context, _destination, image_write, &cfg, buffer)
}
}?;
}
}
pub fn start(cfg: Rc<Config>, restart_idle: Rc<Semaphore>, drtio_context: Option<DrtioContext>) {
task::spawn(async move {
let pull_id = Rc::new(RefCell::new(0u32));
loop {
@ -249,9 +1008,10 @@ pub fn start(cfg: Rc<Config>, restart_idle: Rc<Semaphore>) {
let pull_id = pull_id.clone();
let cfg = cfg.clone();
let restart_idle = restart_idle.clone();
let drtio_context = drtio_context.clone();
task::spawn(async move {
info!("received connection");
let _ = handle_connection(&mut stream, pull_id, cfg, restart_idle)
let _ = handle_connection(&mut stream, pull_id, cfg, restart_idle, drtio_context)
.await
.map_err(|e| warn!("connection terminated: {:?}", e));
let _ = stream.flush().await;

View File

@ -22,7 +22,7 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
} else {
print!("unknown location");
}
if let Some(message) = info.message().as_str() {
if let Some(message) = info.message() {
println!(": {}", message);
} else {
println!("");
@ -61,7 +61,7 @@ fn soft_panic(info: &core::panic::PanicInfo) -> ! {
} else {
error!("panic at unknown location");
}
if let Some(message) = info.message().as_str() {
if let Some(message) = info.message() {
error!("panic message: {}", message);
}
let timer = GlobalTimer::start();

View File

@ -12,9 +12,9 @@ use libboard_artiq::si549;
use libboard_zynq::i2c::I2c;
use libboard_zynq::timer::GlobalTimer;
use libconfig::Config;
#[cfg(not(feature = "target_ebaz4205"))]
use log::info;
use log::warn;
use log::{info, warn};
#[cfg(feature = "target_ebaz4205")]
use {libboard_zynq::slcr, libregister::RegisterRW};
#[derive(Debug, PartialEq, Copy, Clone)]
#[allow(non_camel_case_types)]
@ -410,6 +410,38 @@ fn get_si549_setting(clk: RtioClock) -> si549::FrequencySetting {
}
}
#[cfg(feature = "target_ebaz4205")]
fn set_fclk0_freq(clk: RtioClock, cfg: &Config) {
let io_pll_freq: u32 = 1_000_000_000; // Hardcoded in zynq-rs
let mut target_freq = 0;
let mut divisor0 = 1u8;
match clk {
RtioClock::Int_100 => {
target_freq = 100_000_000;
divisor0 = 10;
}
RtioClock::Int_125 => {
target_freq = 125_000_000;
divisor0 = 8;
}
_ => {
warn!("Unsupported RTIO Clock: '{:?}'", clk);
return;
}
}
slcr::RegisterBlock::unlocked(|slcr| {
slcr.fpga0_clk_ctrl.modify(|_, w| w.divisor0(divisor0));
});
info!(
"Set FCLK0 to {:.2} MHz (target: {} MHz).",
io_pll_freq as f64 / divisor0 as f64,
target_freq / 1_000_000
);
}
pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
let clk = get_rtio_clock_cfg(cfg);
#[cfg(has_si5324)]
@ -436,6 +468,16 @@ pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
#[cfg(not(any(has_drtio, feature = "target_ebaz4205")))]
init_rtio(timer);
#[cfg(feature = "target_ebaz4205")]
{
match clk {
RtioClock::Int_100 | RtioClock::Int_125 => {
set_fclk0_freq(clk, cfg);
}
_ => {} // Not set for external clocks
}
}
#[cfg(all(has_si549, has_wrpll))]
{
// SYS CLK switch will reset CSRs that are used by WRPLL

View File

@ -13,9 +13,13 @@ pub mod drtio {
use core::fmt;
use embedded_hal::blocking::delay::DelayMs;
#[cfg(has_drtio_eem)]
use embedded_hal::blocking::delay::DelayUs;
use ksupport::{resolve_channel_name, ASYNC_ERROR_BUSY, ASYNC_ERROR_COLLISION, ASYNC_ERROR_SEQUENCE_ERROR,
SEEN_ASYNC_ERRORS};
use libasync::{delay, task};
#[cfg(has_drtio_eem)]
use libboard_artiq::drtio_eem;
use libboard_artiq::{drtioaux::Error as DrtioError,
drtioaux_async,
drtioaux_async::Packet,
@ -26,6 +30,10 @@ pub mod drtio {
use super::*;
use crate::{analyzer::remote_analyzer::RemoteBuffer, rtio_dma::remote_dma, subkernel};
#[cfg(has_drtio_eem)]
const DRTIO_EEM_LINKNOS: core::ops::Range<usize> =
(csr::DRTIO.len() - csr::CONFIG_EEM_DRTIO_COUNT as usize)..csr::DRTIO.len();
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Error {
Timeout,
@ -55,8 +63,8 @@ pub mod drtio {
}
}
impl<T> From<DrtioError<T>> for Error {
fn from(_error: DrtioError<T>) -> Self {
impl From<DrtioError> for Error {
fn from(_error: DrtioError) -> Self {
Error::AuxError
}
}
@ -76,8 +84,18 @@ pub mod drtio {
});
}
async fn link_rx_up(linkno: u8) -> bool {
async fn link_rx_up(linkno: u8, _timer: &mut GlobalTimer) -> bool {
let linkno = linkno as usize;
#[cfg(has_drtio_eem)]
if DRTIO_EEM_LINKNOS.contains(&linkno) {
let eem_trx_no = linkno - DRTIO_EEM_LINKNOS.start;
unsafe {
csr::eem_transceiver::transceiver_sel_write(eem_trx_no as u8);
csr::eem_transceiver::comma_align_reset_write(1);
}
_timer.delay_us(100);
return unsafe { csr::eem_transceiver::comma_read() == 1 };
}
unsafe { (csr::DRTIO[linkno].rx_up_read)() == 1 }
}
@ -152,8 +170,8 @@ pub mod drtio {
}
}
async fn recv_aux_timeout(linkno: u8, timeout: u64, timer: GlobalTimer) -> Result<Packet, Error> {
if !link_rx_up(linkno).await {
async fn recv_aux_timeout(linkno: u8, timeout: u64, mut timer: GlobalTimer) -> Result<Packet, Error> {
if !link_rx_up(linkno, &mut timer).await {
return Err(Error::LinkDown);
}
match drtioaux_async::recv_timeout(linkno, Some(timeout), timer).await {
@ -168,9 +186,9 @@ pub mod drtio {
linkno: u8,
routing_table: &RoutingTable,
request: &Packet,
timer: GlobalTimer,
mut timer: GlobalTimer,
) -> Result<Packet, Error> {
if !link_rx_up(linkno).await {
if !link_rx_up(linkno, &mut timer).await {
return Err(Error::LinkDown);
}
let _lock = aux_mutex.async_lock().await;
@ -194,11 +212,11 @@ pub mod drtio {
aux_mutex: &Rc<Mutex<bool>>,
linkno: u8,
routing_table: &RoutingTable,
timer: GlobalTimer,
mut timer: GlobalTimer,
) -> u32 {
let mut count = 0;
loop {
if !link_rx_up(linkno).await {
if !link_rx_up(linkno, &mut timer).await {
return 0;
}
count += 1;
@ -462,7 +480,7 @@ pub mod drtio {
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
timer: GlobalTimer,
mut timer: GlobalTimer,
) {
let mut up_links = [false; csr::DRTIO.len()];
loop {
@ -470,16 +488,35 @@ pub mod drtio {
let linkno = linkno as u8;
if up_links[linkno as usize] {
/* link was previously up */
if link_rx_up(linkno).await {
if link_rx_up(linkno, &mut timer).await {
process_unsolicited_aux(aux_mutex, linkno, routing_table).await;
process_local_errors(linkno).await;
} else {
info!("[LINK#{}] link is down", linkno);
up_links[linkno as usize] = false;
#[cfg(has_drtio_eem)]
if DRTIO_EEM_LINKNOS.contains(&(linkno as usize)) {
unsafe {
csr::eem_transceiver::rx_ready_write(0);
}
while !matches!(drtioaux_async::recv(linkno).await, Ok(None)) {}
}
}
} else {
/* link was previously down */
if link_rx_up(linkno).await {
#[cfg(has_drtio_eem)]
if DRTIO_EEM_LINKNOS.contains(&(linkno as usize)) {
let eem_trx_no = linkno - DRTIO_EEM_LINKNOS.start as u8;
if !unsafe { drtio_eem::align_wordslip(&mut timer, eem_trx_no) } {
continue;
}
unsafe {
csr::eem_transceiver::rx_ready_write(1);
}
}
if link_rx_up(linkno, &mut timer).await {
info!("[LINK#{}] link RX became up, pinging", linkno);
let ping_count = ping_remote(aux_mutex, linkno, routing_table, timer).await;
if ping_count > 0 {
@ -523,7 +560,7 @@ pub mod drtio {
for linkno in 0..csr::DRTIO.len() {
let linkno = linkno as u8;
if task::block_on(link_rx_up(linkno)) {
if task::block_on(link_rx_up(linkno, &mut timer)) {
let reply = task::block_on(aux_transact(
&aux_mutex,
linkno,
@ -540,7 +577,7 @@ pub mod drtio {
}
}
async fn partition_data<PacketF, HandlerF>(
pub async fn partition_data<PacketF, HandlerF>(
linkno: u8,
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &RoutingTable,

View File

@ -15,6 +15,9 @@ build_zynq = { path = "../libbuild_zynq" }
[dependencies]
log = { version = "0.4", default-features = false }
byteorder = { version = "1.3", default-features = false }
core_io = { version = "0.1", features = ["collections"] }
crc = { version = "1.7", default-features = false }
cslice = "0.3"
embedded-hal = "0.2"

View File

@ -1,10 +1,12 @@
#![no_std]
#![no_main]
#![feature(alloc_error_handler, never_type)]
#![allow(unexpected_cfgs)]
#![feature(alloc_error_handler, try_trait, never_type, panic_info_message)]
#[macro_use]
extern crate log;
extern crate byteorder;
extern crate core_io;
extern crate crc;
extern crate cslice;
extern crate embedded_hal;
@ -38,16 +40,18 @@ use libboard_artiq::{drtio_routing, drtioaux,
pl::csr};
#[cfg(feature = "target_kasli_soc")]
use libboard_zynq::error_led::ErrorLED;
use libboard_zynq::{i2c::I2c, print, println, time::Milliseconds, timer::GlobalTimer};
use libboard_zynq::{i2c::I2c, print, println, slcr, time::Milliseconds, timer::GlobalTimer};
use libconfig::Config;
use libcortex_a9::{l2c::enable_l2_cache, regs::MPIDR};
use libregister::RegisterR;
use libsupport_zynq::{exception_vectors, ram};
use mgmt::Manager as CoreManager;
use routing::Router;
use subkernel::Manager as KernelManager;
mod analyzer;
mod dma;
mod mgmt;
mod repeater;
mod routing;
mod subkernel;
@ -149,8 +153,9 @@ fn process_aux_packet(
dma_manager: &mut DmaManager,
analyzer: &mut Analyzer,
kernel_manager: &mut KernelManager,
core_manager: &mut CoreManager,
router: &mut Router,
) -> Result<(), drtioaux::Error<!>> {
) -> Result<(), drtioaux::Error> {
// In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels,
// and u16 otherwise; hence the `as _` conversion.
match packet {
@ -1011,6 +1016,335 @@ fn process_aux_packet(
}
Ok(())
}
drtioaux::Packet::CoreMgmtGetLogRequest {
destination: _destination,
clear,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let mut data_slice = [0; SAT_PAYLOAD_MAX_SIZE];
let meta = core_manager.log_get_slice(&mut data_slice, clear);
drtioaux::send(
0,
&drtioaux::Packet::CoreMgmtGetLogReply {
last: meta.status.is_last(),
length: meta.len as u16,
data: data_slice,
},
)
}
drtioaux::Packet::CoreMgmtClearLogRequest {
destination: _destination,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
mgmt::clear_log();
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })
}
drtioaux::Packet::CoreMgmtSetLogLevelRequest {
destination: _destination,
log_level,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
if let Ok(level_filter) = mgmt::byte_to_level_filter(log_level) {
info!("Changing log level to {}", level_filter);
log::set_max_level(level_filter);
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })
} else {
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
}
}
drtioaux::Packet::CoreMgmtSetUartLogLevelRequest {
destination: _destination,
log_level,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
if let Ok(level_filter) = mgmt::byte_to_level_filter(log_level) {
info!("Changing UART log level to {}", level_filter);
unsafe {
logger::BufferLogger::get_logger()
.as_ref()
.unwrap()
.set_uart_log_level(level_filter);
}
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })
} else {
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
}
}
drtioaux::Packet::CoreMgmtConfigReadRequest {
destination: _destination,
length,
key,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let mut value_slice = [0; SAT_PAYLOAD_MAX_SIZE];
let key_slice = &key[..length as usize];
if !key_slice.is_ascii() {
error!("invalid key");
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
} else {
let key = core::str::from_utf8(key_slice).unwrap();
if core_manager.fetch_config_value(key).is_ok() {
let meta = core_manager.get_config_value_slice(&mut value_slice);
drtioaux::send(
0,
&drtioaux::Packet::CoreMgmtConfigReadReply {
last: meta.status.is_last(),
length: meta.len as u16,
value: value_slice,
},
)
} else {
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
}
}
}
drtioaux::Packet::CoreMgmtConfigReadContinue {
destination: _destination,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let mut value_slice = [0; SAT_PAYLOAD_MAX_SIZE];
let meta = core_manager.get_config_value_slice(&mut value_slice);
drtioaux::send(
0,
&drtioaux::Packet::CoreMgmtConfigReadReply {
last: meta.status.is_last(),
length: meta.len as u16,
value: value_slice,
},
)
}
drtioaux::Packet::CoreMgmtConfigWriteRequest {
destination: _destination,
last,
length,
data,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
core_manager.add_config_data(&data, length as usize);
let mut succeeded = true;
if last {
succeeded = core_manager.write_config().is_ok();
core_manager.clear_config_data();
}
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded })
}
drtioaux::Packet::CoreMgmtConfigRemoveRequest {
destination: _destination,
length,
key,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
let key_slice = &key[..length as usize];
if !key_slice.is_ascii() {
error!("invalid key");
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
} else {
let key = core::str::from_utf8(key_slice).unwrap();
let succeeded = core_manager.remove_config(key).is_ok();
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded })
}
}
drtioaux::Packet::CoreMgmtConfigEraseRequest {
destination: _destination,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
error!("config erase not supported on zynq device");
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
}
drtioaux::Packet::CoreMgmtRebootRequest {
destination: _destination,
} => {
info!("received reboot request");
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })?;
info!("reboot imminent");
slcr::reboot();
unreachable!();
}
drtioaux::Packet::CoreMgmtAllocatorDebugRequest {
destination: _destination,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
error!("debug allocator not supported on zynq device");
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
}
drtioaux::Packet::CoreMgmtFlashRequest {
destination: _destination,
payload_length,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
core_manager.allocate_image_buffer(payload_length as usize);
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })
}
drtioaux::Packet::CoreMgmtFlashAddDataRequest {
destination: _destination,
last,
length,
data,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
core_manager.add_image_data(&data, length as usize);
if last {
drtioaux::send(0, &drtioaux::Packet::CoreMgmtDropLink)
} else {
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })
}
}
drtioaux::Packet::CoreMgmtDropLinkAck {
destination: _destination,
} => {
forward!(
router,
_routing_table,
_destination,
*rank,
*self_destination,
_repeaters,
&packet,
timer
);
unsafe {
csr::gt_drtio::txenable_write(0);
}
core_manager.write_image();
info!("reboot imminent");
slcr::reboot();
Ok(())
}
p => {
warn!("received unexpected aux packet: {:?}", p);
@ -1029,6 +1363,7 @@ fn process_aux_packets(
dma_manager: &mut DmaManager,
analyzer: &mut Analyzer,
kernel_manager: &mut KernelManager,
core_manager: &mut CoreManager,
router: &mut Router,
) {
let result = drtioaux::recv(0).and_then(|packet| {
@ -1044,6 +1379,7 @@ fn process_aux_packets(
dma_manager,
analyzer,
kernel_manager,
core_manager,
router,
)
} else {
@ -1240,7 +1576,7 @@ pub extern "C" fn main_core0() -> i32 {
#[cfg(has_si549)]
si549::helper_setup(&mut timer, &SI549_SETTINGS).expect("cannot initialize helper Si549");
let cfg = match Config::new() {
let mut cfg = match Config::new() {
Ok(cfg) => cfg,
Err(err) => {
warn!("config initialization failed: {}", err);
@ -1315,6 +1651,7 @@ pub extern "C" fn main_core0() -> i32 {
let mut dma_manager = DmaManager::new();
let mut analyzer = Analyzer::new();
let mut kernel_manager = KernelManager::new(&mut control);
let mut core_manager = CoreManager::new(&mut cfg);
drtioaux::reset(0);
drtiosat_reset(false);
@ -1332,6 +1669,7 @@ pub extern "C" fn main_core0() -> i32 {
&mut dma_manager,
&mut analyzer,
&mut kernel_manager,
&mut core_manager,
&mut router,
);
#[allow(unused_mut)]
@ -1459,7 +1797,7 @@ pub fn panic_fmt(info: &core::panic::PanicInfo) -> ! {
} else {
print!("unknown location");
}
if let Some(message) = info.message().as_str() {
if let Some(message) = info.message() {
println!(": {}", message);
} else {
println!("");

149
src/satman/src/mgmt.rs Normal file
View File

@ -0,0 +1,149 @@
use alloc::vec::Vec;
use byteorder::{ByteOrder, NativeEndian};
use crc::crc32;
use io::{ProtoRead, ProtoWrite};
use libboard_artiq::{drtioaux_proto::SAT_PAYLOAD_MAX_SIZE,
logger::{BufferLogger, LogBufferRef}};
use libconfig::Config;
use log::{debug, error, info, warn, LevelFilter};
use crate::routing::{SliceMeta, Sliceable};
type Result<T> = core::result::Result<T, ()>;
pub fn byte_to_level_filter(level_byte: u8) -> Result<LevelFilter> {
Ok(match level_byte {
0 => LevelFilter::Off,
1 => LevelFilter::Error,
2 => LevelFilter::Warn,
3 => LevelFilter::Info,
4 => LevelFilter::Debug,
5 => LevelFilter::Trace,
lv => {
error!("unknown log level: {}", lv);
return Err(());
}
})
}
fn get_logger_buffer() -> LogBufferRef<'static> {
let logger = unsafe { BufferLogger::get_logger().as_mut().unwrap() };
loop {
if let Some(buffer_ref) = logger.buffer() {
return buffer_ref;
}
}
}
pub fn clear_log() {
let mut buffer = get_logger_buffer();
buffer.clear();
}
pub struct Manager<'a> {
cfg: &'a mut Config,
last_log: Sliceable,
config_payload: Vec<u8>,
last_value: Sliceable,
image_payload: Vec<u8>,
}
impl<'a> Manager<'_> {
pub fn new(cfg: &mut Config) -> Manager {
Manager {
cfg: cfg,
last_log: Sliceable::new(0, Vec::new()),
config_payload: Vec::new(),
last_value: Sliceable::new(0, Vec::new()),
image_payload: Vec::new(),
}
}
pub fn log_get_slice(&mut self, data_slice: &mut [u8; SAT_PAYLOAD_MAX_SIZE], consume: bool) -> SliceMeta {
// Populate buffer if depleted
if self.last_log.at_end() {
let mut buffer = get_logger_buffer();
self.last_log.extend(buffer.extract().as_bytes());
if consume {
buffer.clear();
}
}
self.last_log.get_slice_satellite(data_slice)
}
pub fn fetch_config_value(&mut self, key: &str) -> Result<()> {
self.cfg
.read(&key)
.map(|value| {
debug!("got value");
self.last_value = Sliceable::new(0, value)
})
.map_err(|_| warn!("read error: no such key"))
}
pub fn get_config_value_slice(&mut self, data_slice: &mut [u8; SAT_PAYLOAD_MAX_SIZE]) -> SliceMeta {
self.last_value.get_slice_satellite(data_slice)
}
pub fn add_config_data(&mut self, data: &[u8], data_len: usize) {
self.config_payload.write_all(&data[..data_len]).unwrap();
}
pub fn clear_config_data(&mut self) {
self.config_payload.clear();
}
pub fn write_config(&mut self) -> Result<()> {
let mut payload = &self.config_payload[..];
let key = payload.read_string().map_err(|_err| error!("error on reading key"))?;
debug!("write key: {}", key);
let value = payload.read_bytes().unwrap();
self.cfg
.write(&key, value)
.map(|()| debug!("write success"))
.map_err(|err| error!("failed to write: {:?}", err))
}
pub fn remove_config(&mut self, key: &str) -> Result<()> {
debug!("erase key: {}", key);
self.cfg
.remove(&key)
.map(|()| debug!("erase success"))
.map_err(|err| warn!("failed to erase: {:?}", err))
}
pub fn allocate_image_buffer(&mut self, image_size: usize) {
self.image_payload = Vec::with_capacity(image_size);
}
pub fn add_image_data(&mut self, data: &[u8], data_len: usize) {
self.image_payload.extend(&data[..data_len]);
}
pub fn write_image(&self) {
let mut image = self.image_payload.clone();
let image_ref = &image[..];
let bin_len = image.len() - 4;
let (image_ref, expected_crc) = {
let (image_ref, crc_slice) = image_ref.split_at(bin_len);
(image_ref, NativeEndian::read_u32(crc_slice))
};
let actual_crc = crc32::checksum_ieee(image_ref);
if actual_crc == expected_crc {
info!("CRC passed. Writing boot image to SD card...");
image.truncate(bin_len);
self.cfg.write("boot", image).expect("failed to write boot image");
} else {
panic!(
"CRC failed, images have not been written to flash.\n(actual {:08x}, expected {:08x})",
actual_crc, expected_crc
);
}
}
}

View File

@ -191,7 +191,7 @@ impl Repeater {
}
}
fn recv_aux_timeout(&self, timeout: u32, timer: &mut GlobalTimer) -> Result<drtioaux::Packet, drtioaux::Error<!>> {
fn recv_aux_timeout(&self, timeout: u32, timer: &mut GlobalTimer) -> Result<drtioaux::Packet, drtioaux::Error> {
let max_time = timer.get_time() + Milliseconds(timeout.into());
loop {
if !rep_link_rx_up(self.repno) {
@ -216,7 +216,7 @@ impl Repeater {
rank: u8,
self_destination: u8,
timer: &mut GlobalTimer,
) -> Result<(), drtioaux::Error<!>> {
) -> Result<(), drtioaux::Error> {
self.aux_send(request)?;
loop {
let reply = self.recv_aux_timeout(200, timer)?;
@ -242,14 +242,14 @@ impl Repeater {
Ok(())
}
pub fn aux_send(&self, request: &drtioaux::Packet) -> Result<(), drtioaux::Error<!>> {
pub fn aux_send(&self, request: &drtioaux::Packet) -> Result<(), drtioaux::Error> {
if self.state != RepeaterState::Up {
return Err(drtioaux::Error::LinkDown);
}
drtioaux::send(self.auxno, request)
}
pub fn sync_tsc(&self, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error<!>> {
pub fn sync_tsc(&self, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> {
if self.state != RepeaterState::Up {
return Ok(());
}
@ -275,7 +275,7 @@ impl Repeater {
destination: u8,
hops: &[u8; drtio_routing::MAX_HOPS],
timer: &mut GlobalTimer,
) -> Result<(), drtioaux::Error<!>> {
) -> Result<(), drtioaux::Error> {
if self.state != RepeaterState::Up {
return Ok(());
}
@ -299,14 +299,14 @@ impl Repeater {
&self,
routing_table: &drtio_routing::RoutingTable,
timer: &mut GlobalTimer,
) -> Result<(), drtioaux::Error<!>> {
) -> Result<(), drtioaux::Error> {
for i in 0..drtio_routing::DEST_COUNT {
self.set_path(i as u8, &routing_table.0[i], timer)?;
}
Ok(())
}
pub fn set_rank(&self, rank: u8, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error<!>> {
pub fn set_rank(&self, rank: u8, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> {
if self.state != RepeaterState::Up {
return Ok(());
}
@ -318,7 +318,7 @@ impl Repeater {
Ok(())
}
pub fn rtio_reset(&self, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error<!>> {
pub fn rtio_reset(&self, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> {
let repno = self.repno as usize;
unsafe {
(csr::DRTIOREP[repno].reset_write)(1);
@ -361,11 +361,11 @@ impl Repeater {
) {
}
pub fn sync_tsc(&self, _timer: &mut GlobalTimer) -> Result<(), drtioaux::Error<!>> {
pub fn sync_tsc(&self, _timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> {
Ok(())
}
pub fn rtio_reset(&self, _timer: &mut GlobalTimer) -> Result<(), drtioaux::Error<!>> {
pub fn rtio_reset(&self, _timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> {
Ok(())
}
}

View File

@ -4,7 +4,7 @@ use core::cmp::min;
#[cfg(has_drtio_routing)]
use libboard_artiq::pl::csr;
use libboard_artiq::{drtio_routing, drtioaux,
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE}};
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE, SAT_PAYLOAD_MAX_SIZE}};
pub struct SliceMeta {
pub destination: u8,
@ -58,6 +58,7 @@ impl Sliceable {
}
get_slice_fn!(get_slice_master, MASTER_PAYLOAD_MAX_SIZE);
get_slice_fn!(get_slice_satellite, SAT_PAYLOAD_MAX_SIZE);
}
// Packets from downstream (further satellites) are received and routed appropriately.
@ -129,7 +130,7 @@ impl Router {
_routing_table: &drtio_routing::RoutingTable,
_rank: u8,
_destination: u8,
) -> Result<(), drtioaux::Error<!>> {
) -> Result<(), drtioaux::Error> {
#[cfg(has_drtio_routing)]
{
let destination = packet.routable_destination();

View File

@ -1,21 +1,18 @@
use alloc::{
collections::BTreeMap,
use alloc::{collections::BTreeMap,
format,
string::{String, ToString},
vec::Vec,
};
use core::{slice, str};
vec::Vec};
use core::{option::NoneError, slice, str};
use core_io::{Error as IoError, Write};
use cslice::AsCSlice;
use dma::{Error as DmaError, Manager as DmaManager};
use io::{Cursor, Error as IoError, ProtoWrite, Write};
use io::{Cursor, ProtoWrite};
use ksupport::{eh_artiq, kernel, rpc, rtio};
use libboard_artiq::{
drtio_routing::RoutingTable,
use libboard_artiq::{drtio_routing::RoutingTable,
drtioaux,
drtioaux_proto::{PayloadStatus, MASTER_PAYLOAD_MAX_SIZE},
pl::csr,
};
pl::csr};
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
use libcortex_a9::sync_channel::Receiver;
use log::warn;
@ -55,7 +52,6 @@ enum KernelState {
},
}
#[allow(dead_code)]
#[derive(Debug)]
pub enum Error {
Load(String),
@ -69,8 +65,14 @@ pub enum Error {
DmaError(DmaError),
}
impl<T> From<IoError<T>> for Error {
fn from(_value: IoError<T>) -> Error {
impl From<NoneError> for Error {
fn from(_: NoneError) -> Error {
Error::KernelNotFound
}
}
impl From<IoError> for Error {
fn from(_value: IoError) -> Error {
Error::SubkernelIoError
}
}
@ -87,8 +89,8 @@ impl From<()> for Error {
}
}
impl<T> From<drtioaux::Error<T>> for Error {
fn from(_value: drtioaux::Error<T>) -> Error {
impl From<drtioaux::Error> for Error {
fn from(_value: drtioaux::Error) -> Error {
Error::DrtioError
}
}
@ -220,10 +222,7 @@ impl MessageManager {
}
}
pub fn get_outgoing_slice(
&mut self,
data_slice: &mut [u8; MASTER_PAYLOAD_MAX_SIZE],
) -> Option<SliceMeta> {
pub fn get_outgoing_slice(&mut self, data_slice: &mut [u8; MASTER_PAYLOAD_MAX_SIZE]) -> Option<SliceMeta> {
if self.out_state != OutMessageState::MessageBeingSent {
return None;
}
@ -304,13 +303,7 @@ impl<'a> Manager<'_> {
}
}
pub fn add(
&mut self,
id: u32,
status: PayloadStatus,
data: &[u8],
data_len: usize,
) -> Result<(), Error> {
pub fn add(&mut self, id: u32, status: PayloadStatus, data: &[u8], data_len: usize) -> Result<(), Error> {
let kernel = match self.kernels.get_mut(&id) {
Some(kernel) => {
if kernel.complete || status.is_first() {
@ -323,7 +316,7 @@ impl<'a> Manager<'_> {
complete: false,
},
);
self.kernels.get_mut(&id).ok_or(Error::KernelNotFound)?
self.kernels.get_mut(&id)?
} else {
kernel
}
@ -336,7 +329,7 @@ impl<'a> Manager<'_> {
complete: false,
},
);
self.kernels.get_mut(&id).ok_or(Error::KernelNotFound)?
self.kernels.get_mut(&id)?
}
};
kernel.library.extend(&data[0..data_len]);
@ -381,15 +374,10 @@ impl<'a> Manager<'_> {
if !self.running() {
return;
}
self.session
.messages
.handle_incoming(status, id, length, slice);
self.session.messages.handle_incoming(status, id, length, slice);
}
pub fn message_get_slice(
&mut self,
slice: &mut [u8; MASTER_PAYLOAD_MAX_SIZE],
) -> Option<SliceMeta> {
pub fn message_get_slice(&mut self, slice: &mut [u8; MASTER_PAYLOAD_MAX_SIZE]) -> Option<SliceMeta> {
if !self.running() {
return None;
}
@ -408,19 +396,15 @@ impl<'a> Manager<'_> {
if self.session.id == id && self.session.kernel_state == KernelState::Loaded {
return Ok(());
}
if !self.kernels.get(&id).ok_or(Error::KernelNotFound)?.complete {
if !self.kernels.get(&id)?.complete {
return Err(Error::KernelNotFound);
}
self.session = Session::new(id);
self.control.restart();
self.control.tx.send(kernel::Message::LoadRequest(
self.kernels
.get(&id)
.ok_or(Error::KernelNotFound)?
.library
.clone(),
));
self.control
.tx
.send(kernel::Message::LoadRequest(self.kernels.get(&id)?.library.clone()));
let reply = self.control.rx.recv();
match reply {
kernel::Message::LoadCompleted => Ok(()),
@ -432,10 +416,7 @@ impl<'a> Manager<'_> {
}
}
pub fn exception_get_slice(
&mut self,
data_slice: &mut [u8; MASTER_PAYLOAD_MAX_SIZE],
) -> SliceMeta {
pub fn exception_get_slice(&mut self, data_slice: &mut [u8; MASTER_PAYLOAD_MAX_SIZE]) -> SliceMeta {
match self.session.last_exception.as_mut() {
Some(exception) => exception.get_slice_master(data_slice),
None => SliceMeta {
@ -589,14 +570,7 @@ impl<'a> Manager<'_> {
}
}
match self.process_kern_message(
router,
routing_table,
rank,
destination,
dma_manager,
timer,
) {
match self.process_kern_message(router, routing_table, rank, destination, dma_manager, timer) {
Ok(true) => {
self.last_finished = Some(SubkernelFinished {
id: self.session.id,
@ -639,9 +613,7 @@ impl<'a> Manager<'_> {
for (i, (status, exception_source)) in self.session.subkernels_finished.iter().enumerate() {
if *status == id {
if exception_source.is_none() {
self.control
.tx
.send(kernel::Message::SubkernelAwaitFinishReply);
self.control.tx.send(kernel::Message::SubkernelAwaitFinishReply);
self.session.kernel_state = KernelState::Running;
self.session.subkernels_finished.swap_remove(i);
} else {
@ -669,26 +641,15 @@ impl<'a> Manager<'_> {
if self.session.kernel_state == KernelState::SubkernelAwaitLoad {
self.control
.tx
.send(kernel::Message::SubkernelLoadRunReply {
succeeded: succeeded,
});
.send(kernel::Message::SubkernelLoadRunReply { succeeded: succeeded });
self.session.kernel_state = KernelState::Running;
} else {
warn!("received unsolicited SubkernelLoadRunReply");
}
}
pub fn remote_subkernel_finished(
&mut self,
id: u32,
with_exception: bool,
exception_source: u8,
) {
let exception_src = if with_exception {
Some(exception_source)
} else {
None
};
pub fn remote_subkernel_finished(&mut self, id: u32, with_exception: bool, exception_source: u8) {
let exception_src = if with_exception { Some(exception_source) } else { None };
self.session.subkernels_finished.push((id, exception_src));
}
@ -701,19 +662,18 @@ impl<'a> Manager<'_> {
rank: u8,
self_destination: u8,
) {
if let KernelState::SubkernelRetrievingException { destination } = self.session.kernel_state
{
if let KernelState::SubkernelRetrievingException { destination } = self.session.kernel_state {
self.session
.external_exception
.as_mut()
.unwrap()
.extend_from_slice(exception_data);
if last {
self.control.tx.send(kernel::Message::SubkernelError(
kernel::SubkernelStatus::Exception(
self.control
.tx
.send(kernel::Message::SubkernelError(kernel::SubkernelStatus::Exception(
self.session.external_exception.take().unwrap(),
),
));
)));
self.session.kernel_state = KernelState::Running;
} else {
/* fetch another slice */
@ -748,12 +708,7 @@ impl<'a> Manager<'_> {
dma_manager.cleanup(router, rank, self_destination, routing_table);
return Ok(true);
}
kernel::Message::KernelException(
exceptions,
stack_pointers,
backtrace,
async_errors,
) => {
kernel::Message::KernelException(exceptions, stack_pointers, backtrace, async_errors) => {
error!("exception in kernel");
for exception in exceptions {
error!("{:?}", exception.unwrap());
@ -762,21 +717,12 @@ impl<'a> Manager<'_> {
error!("backtrace: {:?}", backtrace);
let buf: Vec<u8> = Vec::new();
let mut writer = Cursor::new(buf);
match write_exception(
&mut writer,
exceptions,
stack_pointers,
backtrace,
async_errors,
) {
match write_exception(&mut writer, exceptions, stack_pointers, backtrace, async_errors) {
Ok(()) => (),
Err(_) => error!("Error writing exception data"),
}
self.kernel_stop();
return Err(Error::KernelException(Sliceable::new(
0,
writer.into_inner(),
)));
return Err(Error::KernelException(Sliceable::new(0, writer.into_inner())));
}
kernel::Message::CachePutRequest(key, value) => {
self.cache.insert(key, value);
@ -824,13 +770,11 @@ impl<'a> Manager<'_> {
let max_time = timer.get_time() + Milliseconds(10000);
self.session.kernel_state = match self.session.kernel_state {
// if we are still waiting for the traces to be uploaded, extend the state by timeout
KernelState::DmaPendingPlayback { id, timestamp } => {
KernelState::DmaPendingAwait {
KernelState::DmaPendingPlayback { id, timestamp } => KernelState::DmaPendingAwait {
id: id,
timestamp: timestamp,
max_time: max_time,
}
}
},
_ => KernelState::DmaAwait { max_time: max_time },
};
}
@ -903,10 +847,7 @@ impl<'a> Manager<'_> {
));
}
_ => {
unexpected!(
"unexpected message from core1 while kernel was running: {:?}",
reply
);
unexpected!("unexpected message from core1 while kernel was running: {:?}", reply);
}
}
Ok(false)
@ -924,9 +865,9 @@ impl<'a> Manager<'_> {
KernelState::MsgAwait { max_time, id, tags } => {
if let Some(max_time) = *max_time {
if timer.get_time() > max_time {
self.control.tx.send(kernel::Message::SubkernelError(
kernel::SubkernelStatus::Timeout,
));
self.control
.tx
.send(kernel::Message::SubkernelError(kernel::SubkernelStatus::Timeout));
self.session.kernel_state = KernelState::Running;
return Ok(());
}
@ -934,9 +875,7 @@ impl<'a> Manager<'_> {
if let Some(message) = self.session.messages.get_incoming(*id) {
self.control
.tx
.send(kernel::Message::SubkernelMsgRecvReply {
count: message.count,
});
.send(kernel::Message::SubkernelMsgRecvReply { count: message.count });
let tags = tags.clone();
self.session.kernel_state = KernelState::Running;
self.pass_message_to_kernel(&message, tags, timer)
@ -958,9 +897,9 @@ impl<'a> Manager<'_> {
KernelState::SubkernelAwaitFinish { max_time, id } => {
if let Some(max_time) = *max_time {
if timer.get_time() > max_time {
self.control.tx.send(kernel::Message::SubkernelError(
kernel::SubkernelStatus::Timeout,
));
self.control
.tx
.send(kernel::Message::SubkernelError(kernel::SubkernelStatus::Timeout));
self.session.kernel_state = KernelState::Running;
return Ok(());
}
@ -986,12 +925,7 @@ impl<'a> Manager<'_> {
}
}
fn pass_message_to_kernel(
&mut self,
message: &Message,
tags: Vec<u8>,
timer: &GlobalTimer,
) -> Result<(), Error> {
fn pass_message_to_kernel(&mut self, message: &Message, tags: Vec<u8>, timer: &GlobalTimer) -> Result<(), Error> {
let mut reader = Cursor::new(&message.data);
let mut current_tags: &[u8] = &tags;
let mut i = message.count;
@ -1002,50 +936,29 @@ impl<'a> Manager<'_> {
};
let mut exception: Option<Sliceable> = None;
let mut unexpected: Option<String> = None;
let remaining_tags =
rpc::recv_return(&mut reader, current_tags, slot, &mut |size| -> Result<
_,
Error,
> {
let remaining_tags = rpc::recv_return(&mut reader, current_tags, slot, &mut |size| {
if size == 0 {
Ok(0 as *mut ())
0 as *mut ()
} else {
self.control
.tx
.send(kernel::Message::RpcRecvReply(Ok(size)));
self.control.tx.send(kernel::Message::RpcRecvReply(Ok(size)));
match recv_w_timeout(&mut self.control.rx, timer, 100) {
Ok(kernel::Message::RpcRecvRequest(slot)) => Ok(slot),
Ok(kernel::Message::KernelException(
exceptions,
stack_pointers,
backtrace,
async_errors,
)) => {
Ok(kernel::Message::RpcRecvRequest(slot)) => slot,
Ok(kernel::Message::KernelException(exceptions, stack_pointers, backtrace, async_errors)) => {
let buf: Vec<u8> = Vec::new();
let mut writer = Cursor::new(buf);
match write_exception(
&mut writer,
exceptions,
stack_pointers,
backtrace,
async_errors,
) {
match write_exception(&mut writer, exceptions, stack_pointers, backtrace, async_errors) {
Ok(()) => {
exception = Some(Sliceable::new(0, writer.into_inner()));
}
Err(_) => {
unexpected =
Some("Error writing exception data".to_string());
unexpected = Some("Error writing exception data".to_string());
}
};
Ok(0 as *mut ())
0 as *mut ()
}
other => {
unexpected = Some(format!(
"expected nested value slot from kernel CPU, not {:?}",
other
));
Ok(0 as *mut ())
unexpected = Some(format!("expected nested value slot from kernel CPU, not {:?}", other));
0 as *mut ()
}
}
}
@ -1091,9 +1004,8 @@ where
writer.write_u32(u32::MAX)?;
writer.write_u32(exception.message.as_ptr() as u32)?;
} else {
let msg = str::from_utf8(unsafe {
slice::from_raw_parts(exception.message.as_ptr(), exception.message.len())
})
let msg =
str::from_utf8(unsafe { slice::from_raw_parts(exception.message.as_ptr(), exception.message.len()) })
.unwrap()
.replace(
"{rtio_channel_info:0}",