Skip to content

Commit

Permalink
feat: yield rewrite with libcmt
Browse files Browse the repository at this point in the history
  • Loading branch information
mpolitzer committed Jan 23, 2024
1 parent 473b693 commit d447123
Show file tree
Hide file tree
Showing 5 changed files with 275 additions and 1 deletion.
2 changes: 1 addition & 1 deletion sys-utils/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#


UTILITIES := xhalt rollup ioctl-echo-loop
UTILITIES := xhalt yield rollup ioctl-echo-loop
UTILITIES_WITH_TOOLCHAIN := $(addsuffix -with-toolchain,$(UTILITIES))

all: $(UTILITIES)
Expand Down
2 changes: 2 additions & 0 deletions sys-utils/yield/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
extra/halt
halt
81 changes: 81 additions & 0 deletions sys-utils/yield/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Copyright Cartesi and individual authors (see AUTHORS)
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

UNAME:=$(shell uname)

TOOLCHAIN_IMAGE ?= cartesi/toolchain
TOOLCHAIN_TAG ?= 0.16.0
RISCV_ARCH ?= rv64gc
RISCV_ABI ?= lp64d

TOOLCHAIN_PREFIX ?= riscv64-cartesi-linux-gnu-

RVCC = $(TOOLCHAIN_PREFIX)gcc
RVCXX = $(TOOLCHAIN_PREFIX)g++
RVCOPY = $(TOOLCHAIN_PREFIX)objcopy
RVDUMP = $(TOOLCHAIN_PREFIX)objdump
STRIP = $(TOOLCHAIN_PREFIX)strip
CFLAGS :=-Wall -Wextra -pedantic -O2 \
`PKG_CONFIG_PATH=/usr/riscv64-linux-gnu/lib/pkgconfig pkg-config --cflags libcmt`
LDLIBS := \
`PKG_CONFIG_PATH=/usr/riscv64-linux-gnu/lib/pkgconfig pkg-config --libs libcmt`

CONTAINER_MAKE := /usr/bin/make
CONTAINER_BASE := /opt/cartesi/tools
KERNEL_HEADERS_PATH := /opt/riscv/usr/include

all: yield

yield.with-toolchain with-toolchain:
$(MAKE) toolchain-exec CONTAINER_COMMAND="$(CONTAINER_MAKE) $@.toolchain"

extra.ext2.with-toolchain:
$(MAKE) toolchain-exec CONTAINER_COMMAND="$(CONTAINER_MAKE) $@.toolchain"

yield: yield.c
$(RVCC) $(CFLAGS) -O2 -o yield yield.c $(LDLIBS)
$(STRIP) yield

extra.ext2: yield
mkdir -m 0755 ./extra
cp ./yield ./extra/yield
xgenext2fs -i 512 -b 8192 -d extra $(basename $@)
rm -rf ./extra

toolchain-exec:
@docker run --hostname $@ --rm \
-e USER=$$(id -u -n) \
-e GROUP=$$(id -g -n) \
-e UID=$$(id -u) \
-e GID=$$(id -g) \
-v `pwd`:$(CONTAINER_BASE) \
-w $(CONTAINER_BASE) \
$(TOOLCHAIN_IMAGE):$(TOOLCHAIN_TAG) $(CONTAINER_COMMAND)

toolchain-env:
@docker run --hostname toolchain-env -it --rm \
-e USER=$$(id -u -n) \
-e GROUP=$$(id -g -n) \
-e UID=$$(id -u) \
-e GID=$$(id -g) \
-v `pwd`:$(CONTAINER_BASE) \
-w $(CONTAINER_BASE) \
$(TOOLCHAIN_IMAGE):$(TOOLCHAIN_TAG)

clean:
@rm -rf yield extra.ext2 extra

.PHONY: toolchain-exec toolchain-env
41 changes: 41 additions & 0 deletions sys-utils/yield/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
## HTIF yield tool

### Requirements

- Docker >= 18.x
- GNU Make >= 3.81

### Building

```bash
$ cd linux/htif
$ make
```

#### Makefile targets

The following options are available as `make` targets:

- **all**: builds the RISC-V yield executable
- **extra.ext2**: builds the extra.ext2 filesystem image with the yield tool inside
- **toolchain-env**: runs the toolchain image with current user UID and GID
- **clean**: clean generated artifacts

#### Makefile container options

You can pass the following variables to the make target if you wish to use different docker image tags.

- TOOLCHAIN\_IMAGE: toolchain image name
- TOOLCHAIN\_TAG: toolchain image tag

```
$ make TOOLCHAIN_TAG=mytag
```

It's useful when you want to use prebuilt images like `cartesi/toolchain:latest`

#### Usage

The purpose of the yield tool please see the emulator documentation.

The purpose of the `extra.ext2` image is to help the development creating a filesystem that contains the yield tool so it can be used with the emulator. For instructions on how to do that, please see the emulator documentation.
150 changes: 150 additions & 0 deletions sys-utils/yield/yield.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/* Copyright Cartesi and individual authors (see AUTHORS)
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libcmt/io.h"

static void help(const char *progname) {
fprintf(stderr,
"Usage: %s <mode> <reason> [<data>]\n"
"Where: \n"
" <mode> \"manual\" or \"automatic\"\n"
" <reason> \"progress\", \"rx-accepted\", \"rx-rejected\",\n"
" \"tx-voucher\", \"tx-notice\", \"tx-exception\" or\n"
" \"tx-report\"\n"
" <data> 32-bit unsigned integer (decimal, default 0)\n",
progname);

exit(1);
}

struct name_value {
const char *name;
uint64_t value;
};
static int find_value(const struct name_value *pairs, size_t n, const char *s, uint64_t *value)
{
for (size_t i=0; i<n; ++i) {
if (strcmp(s, pairs[i].name) == 0) {
*value = pairs[i].value;
return 1;
}
}
return 0;
}

int get_mode(const char *s, uint64_t *mode) {
struct name_value modes[] = {
{"manual", CMT_IO_CMD_MANUAL},
{"automatic", CMT_IO_CMD_AUTOMATIC},
};
return find_value(modes, sizeof(modes)/sizeof(*modes), s, mode);
}

int get_reason(const char *s, uint64_t *reason) {
struct name_value reasons[] = {
{"progress", CMT_IO_REASON_PROGRESS},
{"rx-accepted", CMT_IO_REASON_RX_ACCEPTED},
{"rx-rejected", CMT_IO_REASON_RX_REJECTED},
{"tx-exception", CMT_IO_REASON_TX_EXCEPTION},
{"tx-output", CMT_IO_REASON_TX_OUTPUT},
{"tx-report", CMT_IO_REASON_TX_REPORT},
};
return find_value(reasons, sizeof(reasons)/sizeof(*reasons), s, reason);
}

int get_data(const char *s, uint64_t *data) {
int end = 0;
if (sscanf(s, "%" SCNu64 "%n", data, &end) != 1 ||
s[end] != 0 ||
*data > UINT32_MAX) {
return 0;
}
return 1;
}

struct parsed_args {
uint64_t mode;
uint64_t reason;
uint64_t data;
};

void parse_args(int argc, char *argv[], struct parsed_args *p) {
int i = 0;
const char *progname = argv[0];

memset(p, 0, sizeof(*p));

i = 1;
if (i >= argc) {
fprintf(stderr, "Too few arguments.\n\n");
help(progname);
}

if (!get_mode(argv[i], &p->mode)) {
fprintf(stderr, "Invalid <mode> argument.\n\n");
help(progname);
}

i++;
if (i >= argc) {
help(progname);
}

if (!get_reason(argv[i], &p->reason)) {
fprintf(stderr, "Invalid <reason> argument.\n\n");
help(progname);
}

i++;
if (i < argc) {
if (get_data(argv[i], &p->data)) {
i++;
} else {
fprintf(stderr, "Invalid <data> argument.\n\n");
help(progname);
}
}

if (i != argc) {
fprintf(stderr, "Too many arguments.\n\n");
help(progname);
}
}

int main(int argc, char *argv[]) {
struct parsed_args args;
cmt_io_driver_t io[1];

parse_args(argc, argv, &args);
cmt_io_yield_t req[1] = {{
.dev = CMT_IO_DEV,
.cmd = args.mode,
.reason = args.reason,
.data = args.data,
}};

int rc = cmt_io_init(io);
if (rc)
return rc;

return cmt_io_yield(io, req);
}

0 comments on commit d447123

Please sign in to comment.