Skip to content

Commit

Permalink
kitty: initial integration with the serial sDDF sub-system
Browse files Browse the repository at this point in the history
This patch changes MicroPython to make use of the UART driver in sDDF
instead of implementing it's own.

The commit message says 'initial' as I am not completely satisfied with
the implementation.
  • Loading branch information
Ivan-Velickovic committed Dec 19, 2023
1 parent 3a5f801 commit 7fb3912
Show file tree
Hide file tree
Showing 10 changed files with 210 additions and 53 deletions.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[submodule "sddf"]
path = sddf
url = https://github.com/au-ts/sddf.git
branch = lionsos
branch = main
[submodule "micropython"]
path = micropython
url = https://github.com/Ivan-Velickovic/micropython.git
Expand Down
38 changes: 35 additions & 3 deletions examples/kitty/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ LIBNFS=../../libnfs
NFS=../../fs/nfs
MUSL=../../musllibc

IMAGES := main.elf timer.elf vmm.elf ethernet.elf micropython.elf nfs.elf copy.elf mux_rx.elf mux_tx.elf arp.elf
IMAGES := main.elf timer.elf vmm.elf ethernet.elf micropython.elf nfs.elf copy.elf mux_rx.elf mux_tx.elf arp.elf uart_driver.elf serial_mux_rx.elf serial_mux_tx.elf
CFLAGS := \
-mtune=$(CPU) \
-mstrict-align \
Expand All @@ -55,7 +55,7 @@ CFLAGS := \
-I$(LIBVMM)/src/util \
-DBOARD_$(MICROKIT_BOARD) \
-I$(SDDF)/include
LDFLAGS := -L$(BOARD_DIR)/lib
LDFLAGS := -L$(BOARD_DIR)/lib
LIBS := -lmicrokit -Tmicrokit.ld

IMAGE_FILE := $(BUILD_DIR)/kitty.img
Expand Down Expand Up @@ -124,7 +124,7 @@ $(BUILD_DIR)/package_python_scripts.o: $(PACKAGE_PYTHON_SCRIPTS) src/kitty.py
-target $(TARGET) \
$< -o $@

$(BUILD_DIR)/micropython.elf: FORCE $(BUILD_DIR)/package_python_scripts.o $(BUILD_DIR)/sddf_timer_client.o $(BUILD_DIR)/sddf_fs_protocol.o
$(BUILD_DIR)/micropython.elf: FORCE $(BUILD_DIR)/package_python_scripts.o $(BUILD_DIR)/sddf_timer_client.o $(BUILD_DIR)/sddf_fs_protocol.o $(BUILD_DIR)/sddf_serial_sharedringbuffer.o
make -C src/micropython -j$(nproc) \
MICROKIT_SDK=$(MICROKIT_SDK) \
MICROKIT_BOARD=$(MICROKIT_BOARD) \
Expand Down Expand Up @@ -232,6 +232,38 @@ $(BUILD_DIR)/mux_tx.elf: $(BUILD_DIR)/mux_tx.o $(BUILD_DIR)/sddf_network_sharedr
$(BUILD_DIR)/arp.elf: $(BUILD_DIR)/arp.o $(BUILD_DIR)/sddf_network_sharedringbuffer.o $(BUILD_DIR)/nfs/nfs.a
aarch64-none-elf-ld $(NETWORK_COMPONENTS_LDFLAGS) $(BUILD_DIR)/sddf_network_sharedringbuffer.o $(BUILD_DIR)/arp.o $(BUILD_DIR)/nfs/lwip/core/inet_chksum.o $(BUILD_DIR)/nfs/lwip/core/def.o $(NETWORK_COMPONENTS_LIBS) -o $(BUILD_DIR)/arp.elf

# Compiling serial components
LIB_SERIAL_SHARED_RINGBUFFER := $(SDDF)/serial/libserialsharedringbuffer/
SERIAL_COMPONENTS := $(SDDF)/serial/components
UART_DRIVER := $(SDDF)/drivers/serial/meson
UART_DRIVER_OBJS := uart_driver.o sddf_serial_sharedringbuffer.o
SERIAL_MUX_RX_OBJS := serial_mux_rx.o sddf_serial_sharedringbuffer.o
SERIAL_MUX_TX_OBJS := serial_mux_tx.o sddf_serial_sharedringbuffer.o

SERIAL_INCLUDES := -I$(SDDF)/util/include -I$(UART_DRIVER)/include
SERIAL_NUM_CLIENTS := -DSERIAL_NUM_CLIENTS=1

$(BUILD_DIR)/sddf_serial_sharedringbuffer.o: FORCE
BUILD_DIR=$(abspath $(BUILD_DIR)) MICROKIT_INCLUDE=$(BOARD_DIR)/include make -C $(LIB_SERIAL_SHARED_RINGBUFFER)

$(BUILD_DIR)/uart_driver.o: $(UART_DRIVER)/uart.c
$(CC) -c $(SERIAL_INCLUDES) $(CFLAGS) $< -o $@

$(BUILD_DIR)/serial_mux_rx.o: $(SERIAL_COMPONENTS)/mux_rx.c
$(CC) -c $(SERIAL_INCLUDES) $(CFLAGS) $(SERIAL_NUM_CLIENTS) $< -o $@

$(BUILD_DIR)/serial_mux_tx.o: $(SERIAL_COMPONENTS)/mux_tx.c
$(CC) -c $(SERIAL_INCLUDES) $(CFLAGS) $(SERIAL_NUM_CLIENTS) $< -o $@

$(BUILD_DIR)/uart_driver.elf: $(addprefix $(BUILD_DIR)/, $(UART_DRIVER_OBJS))
$(LD) $(LDFLAGS) $^ $(LIBS) -o $@

$(BUILD_DIR)/serial_mux_rx.elf: $(addprefix $(BUILD_DIR)/, $(SERIAL_MUX_RX_OBJS))
$(LD) $(LDFLAGS) $^ $(LIBS) -o $@

$(BUILD_DIR)/serial_mux_tx.elf: $(addprefix $(BUILD_DIR)/, $(SERIAL_MUX_TX_OBJS))
$(LD) $(LDFLAGS) $^ $(LIBS) -o $@

directories:
$(info $(shell mkdir -p $(BUILD_DIR)/lwip/src)) \
$(info $(shell mkdir -p $(BUILD_DIR)/lwip/src/core)) \
Expand Down
88 changes: 87 additions & 1 deletion examples/kitty/kitty.system
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,18 @@

<protection_domain name="micropython" priority="1" budget="100">
<program_image path="micropython.elf" />
<map mr="uart" vaddr="0x5000000" perms="rw" cached="false" setvar_vaddr="uart_base" />
<map mr="uio_map0" vaddr="0x30000000" perms="rw" cached="false" setvar_vaddr="uio_framebuffer_region" />
<map mr="shared_nfs_micropython" vaddr="0x7_800_000" perms="rw" cached="true" setvar_vaddr="nfs_share" />
<map mr="nfs_command_queue" vaddr="0x7_900_000" perms="rw" cached="true" setvar_vaddr="nfs_command_queue" />
<map mr="nfs_completion_queue" vaddr="0x7_902_000" perms="rw" cached="true" setvar_vaddr="nfs_completion_queue" />

<map mr="serial_tx_free_micropython" vaddr="0x60_000_000" perms="rw" cached="true" setvar_vaddr="serial_tx_free" />
<map mr="serial_tx_used_micropython" vaddr="0x60_200_000" perms="rw" cached="true" setvar_vaddr="serial_tx_used" />
<map mr="serial_tx_data_micropython" vaddr="0x50_400_000" perms="rw" cached="true" setvar_vaddr="serial_tx_data" />

<map mr="serial_rx_free_micropython" vaddr="0x70_000_000" perms="rw" cached="true" setvar_vaddr="serial_rx_free" />
<map mr="serial_rx_used_micropython" vaddr="0x70_200_000" perms="rw" cached="true" setvar_vaddr="serial_rx_used" />
<map mr="serial_rx_data_micropython" vaddr="0x50_600_000" perms="rw" cached="true" setvar_vaddr="serial_rx_data" />
</protection_domain>

<protection_domain name="timer_driver" priority="150" pp="true" passive="true">
Expand Down Expand Up @@ -88,6 +95,22 @@
<!-- UIO framebuffer -->
<memory_region name="uio_map0" size="0x1800000" />

<!-- Shared memory regions for the serial sub-system -->
<memory_region name="serial_tx_data_driver" size="0x200_000" page_size="0x200_000" />
<memory_region name="serial_tx_data_micropython" size="0x200_000" page_size="0x200_000" />
<memory_region name="serial_rx_data_driver" size="0x200_000" page_size="0x200_000" />
<memory_region name="serial_rx_data_micropython" size="0x200_000" page_size="0x200_000" />

<memory_region name="serial_rx_free_driver" size="0x200_000" page_size="0x200_000"/>
<memory_region name="serial_rx_used_driver" size="0x200_000" page_size="0x200_000"/>
<memory_region name="serial_tx_free_driver" size="0x200_000" page_size="0x200_000"/>
<memory_region name="serial_tx_used_driver" size="0x200_000" page_size="0x200_000"/>

<memory_region name="serial_tx_free_micropython" size="0x200_000" page_size="0x200_000"/>
<memory_region name="serial_tx_used_micropython" size="0x200_000" page_size="0x200_000"/>
<memory_region name="serial_rx_free_micropython" size="0x200_000" page_size="0x200_000"/>
<memory_region name="serial_rx_used_micropython" size="0x200_000" page_size="0x200_000"/>

<protection_domain name="VMM" priority="254">
<program_image path="vmm.elf" />
<map mr="guest_ram" vaddr="0x20000000" perms="rw" setvar_vaddr="guest_ram_vaddr" />
Expand Down Expand Up @@ -258,6 +281,69 @@
<map mr="shared_dma_tx_nfs" vaddr="0x2_600_000" perms="rw" cached="true" setvar_vaddr="shared_dma_vaddr_tx" />
</protection_domain>

<protection_domain name="uart_driver" priority="100" >
<program_image path="uart_driver.elf" />

<map mr="uart" vaddr="0x5_000_000" perms="rw" cached="false" setvar_vaddr="uart_base" />

<map mr="serial_rx_free_driver" vaddr="0x40_000_000" perms="rw" cached="true" setvar_vaddr="rx_free" />
<map mr="serial_rx_used_driver" vaddr="0x40_200_000" perms="rw" cached="true" setvar_vaddr="rx_used" />
<map mr="serial_tx_free_driver" vaddr="0x40_400_000" perms="rw" cached="true" setvar_vaddr="tx_free" />
<map mr="serial_tx_used_driver" vaddr="0x40_600_000" perms="rw" cached="true" setvar_vaddr="tx_used" />

<map mr="serial_tx_data_driver" vaddr="0x50_000_000" perms="rw" cached="true" />
<map mr="serial_rx_data_driver" vaddr="0x50_200_000" perms="rw" cached="true" />

<!-- IRQ for UART -->
<irq irq="225" id="1" trigger="edge" />
</protection_domain>

<protection_domain name="serial_mux_tx" priority="99" >
<program_image path="serial_mux_tx.elf" />

<map mr="serial_tx_free_driver" vaddr="0x40_400_000" perms="rw" cached="true" setvar_vaddr="tx_free_driver" />
<map mr="serial_tx_used_driver" vaddr="0x40_600_000" perms="rw" cached="true" setvar_vaddr="tx_used_driver" />

<map mr="serial_tx_free_micropython" vaddr="0x60_000_000" perms="rw" cached="true" setvar_vaddr="tx_free_client" />
<map mr="serial_tx_used_micropython" vaddr="0x60_200_000" perms="rw" cached="true" setvar_vaddr="tx_used_client" />

<map mr="serial_tx_data_driver" vaddr="0x50_000_000" perms="rw" cached="true" setvar_vaddr="tx_data_driver" />
<map mr="serial_tx_data_micropython" vaddr="0x50_400_000" perms="rw" cached="true" setvar_vaddr="tx_data_client" />
</protection_domain>

<protection_domain name="serial_mux_rx" priority="98" >
<program_image path="serial_mux_rx.elf" />

<map mr="serial_rx_free_driver" vaddr="0x40_000_000" perms="rw" cached="true" setvar_vaddr="rx_free_driver" />
<map mr="serial_rx_used_driver" vaddr="0x40_200_000" perms="rw" cached="true" setvar_vaddr="rx_used_driver" />

<map mr="serial_rx_free_micropython" vaddr="0x60_000_000" perms="rw" cached="true" setvar_vaddr="rx_free_client" />
<map mr="serial_rx_used_micropython" vaddr="0x60_200_000" perms="rw" cached="true" setvar_vaddr="rx_used_client" />

<map mr="serial_rx_data_driver" vaddr="0x50_200_000" perms="rw" cached="true" setvar_vaddr="rx_data_driver" />
<map mr="serial_rx_data_micropython" vaddr="0x50_600_000" perms="rw" cached="true" setvar_vaddr="rx_data_client" />
</protection_domain>

<channel>
<end pd="uart_driver" id="8"/>
<end pd="serial_mux_tx" id="9"/>
</channel>

<channel>
<end pd="uart_driver" id="10"/>
<end pd="serial_mux_rx" id="11"/>
</channel>

<channel>
<end pd="micropython" id="8"/>
<end pd="serial_mux_rx" id="1"/>
</channel>

<channel>
<end pd="micropython" id="9"/>
<end pd="serial_mux_tx" id="1"/>
</channel>

<channel>
<end pd="nfs" id="9" />
<end pd="timer_driver" id="3" />
Expand Down
5 changes: 2 additions & 3 deletions examples/kitty/src/micropython/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,13 @@ CPU ?= cortex-a55
BOARD_DIR := $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG)

# Set CFLAGS and libraries.
CFLAGS += -I. -I$(BUILD) -I$(TOP) -I$(SDDF) -I$(SDDF)/include -I$(BOARD_DIR)/include -I$(LIBCO) -I$(LIONSOS)/fs/include -nostdlib -ffreestanding -mtune=$(CPU)
CFLAGS += -I. -I$(BUILD) -I$(TOP) -I$(SDDF) -I$(SDDF)/util/include -I$(SDDF)/include -I$(BOARD_DIR)/include -I$(LIBCO) -I$(LIONSOS)/fs/include -nostdlib -ffreestanding -mtune=$(CPU)
LDFLAGS += -L$(BOARD_DIR)/lib -nostdlib
LIBS += -lm -lmicrokit -Tmicrokit.ld

# Define the required source files.
SRC_C = \
micropython.c \
uart.c \
mphalport.c \
modmyport.c \
modtime.c \
Expand All @@ -49,7 +48,7 @@ SRC_C = \
SRC_QSTR += shared/readline/readline.c shared/runtime/pyexec.c modmyport.c modfb.c vfs_sddf_fs_file.c vfs_sddf_fs.c

# Define the required object files.
OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) ../../build/sddf_timer_client.o ../../build/sddf_fs_protocol.o
OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) ../../build/sddf_timer_client.o ../../build/sddf_fs_protocol.o ../../build/sddf_serial_sharedringbuffer.o

all: $(BUILD)/micropython.elf

Expand Down
32 changes: 28 additions & 4 deletions examples/kitty/src/micropython/micropython.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "shared/runtime/pyexec.h"
#include "vfs_sddf_fs.h"
#include <extmod/vfs.h>
#include <sddf/serial/shared_ringbuffer.h>

/* Data for the Kitty Python script. */
extern char _kitty_python_script[];
Expand All @@ -23,6 +24,17 @@ cothread_t t_event, t_mp;

char *nfs_share;

/* Shared memory regions for sDDF serial sub-system */
uintptr_t serial_rx_free;
uintptr_t serial_rx_used;
uintptr_t serial_tx_free;
uintptr_t serial_tx_used;
uintptr_t serial_rx_data;
uintptr_t serial_tx_data;

ring_handle_t serial_rx_ring;
ring_handle_t serial_tx_ring;

int active_events = mp_event_source_none;
int mp_blocking_events = mp_event_source_none;

Expand Down Expand Up @@ -50,7 +62,7 @@ STATIC bool init_nfs(void) {
#ifndef NDEBUG
void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) {
// @ivanv: improve/fix, use printf?
microkit_dbg_puts("MICROPYTHON|ERROR: Assertion failed!\n");
microkit_dbg_puts("MP|ERROR: Assertion failed!\n");
while (true) {}
}
#endif
Expand All @@ -73,7 +85,7 @@ static void exec_str(const char *src, mp_parse_input_kind_t input_kind) {
}

void t_mp_entrypoint(void) {
printf("MICROPYTHON|INFO: initialising!\n");
printf("MP|INFO: initialising!\n");

// Initialise the MicroPython runtime.
mp_stack_ctrl_init();
Expand All @@ -90,11 +102,20 @@ void t_mp_entrypoint(void) {
gc_sweep_all();
mp_deinit();

printf("MICROPYTHON|INFO: exited!\n");
printf("MP|INFO: exited!\n");
co_switch(t_event);
}

void init(void) {
ring_init(&serial_rx_ring, (ring_buffer_t *)serial_rx_free, (ring_buffer_t *)serial_rx_used, false, BUFFER_SIZE, BUFFER_SIZE);
for (int i = 0; i < NUM_BUFFERS - 1; i++) {
enqueue_free(&serial_rx_ring, serial_rx_data + ((i + NUM_BUFFERS) * BUFFER_SIZE), BUFFER_SIZE, NULL);
}
ring_init(&serial_tx_ring, (ring_buffer_t *)serial_tx_free, (ring_buffer_t *)serial_tx_used, false, BUFFER_SIZE, BUFFER_SIZE);
for (int i = 0; i < NUM_BUFFERS - 1; i++) {
enqueue_free(&serial_tx_ring, serial_tx_data + ((i + NUM_BUFFERS) * BUFFER_SIZE), BUFFER_SIZE, NULL);
}

t_event = co_active();
// @ivanv: figure out a better stack size
t_mp = co_derive((void *)mp_stack, MICROPY_HEAP_SIZE, t_mp_entrypoint);
Expand All @@ -103,6 +124,9 @@ void init(void) {

void notified(microkit_channel ch) {
switch (ch) {
case SERIAL_RX_CH:
active_events |= mp_event_source_serial;
break;
case TIMER_CH:
active_events |= mp_event_source_timer;
break;
Expand All @@ -114,7 +138,7 @@ void notified(microkit_channel ch) {
active_events |= mp_event_source_nfs;
break;
default:
printf("MICROPYTHON|ERROR: unknown notification received from channel: 0x%lx\n", ch);
printf("MP|ERROR: unexpected notification received from channel: 0x%lx\n", ch);
}
if (active_events & mp_blocking_events) {
co_switch(t_mp);
Expand Down
4 changes: 3 additions & 1 deletion examples/kitty/src/micropython/micropython.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ extern cothread_t t_mp;
#define VMM_CH 0
#define TIMER_CH 1
#define NFS_CH 7
#define SERIAL_RX_CH 8
#define SERIAL_TX_CH 9

enum {
mp_event_source_none = 0,
mp_event_source_timer = 1,
mp_event_source_uart = 2,
mp_event_source_serial = 2,
mp_event_source_network = 4,
mp_event_source_nfc = 8,
mp_event_source_framebuffer = 16,
Expand Down
57 changes: 53 additions & 4 deletions examples/kitty/src/micropython/mphalport.c
Original file line number Diff line number Diff line change
@@ -1,18 +1,67 @@
#include <microkit.h>
#include <unistd.h>
#include "micropython.h"
#include "py/mpconfig.h"
#include "uart.h"
#include <sddf/serial/shared_ringbuffer.h>

// @ivanv: TEMPORARY until the meson serial driver is in sDDF
extern ring_handle_t serial_rx_ring;
extern ring_handle_t serial_tx_ring;

// Receive single character, blocking until one is available.
int mp_hal_stdin_rx_chr(void) {
return uart_get_char();
// Wait for notification from RX multiplexor.
mp_blocking_events = mp_event_source_serial;
co_switch(t_event);
mp_blocking_events = mp_event_source_none;
// Dequeue buffer and return char
uintptr_t buffer = 0;
unsigned int buffer_len = 0;
void *cookie = 0;
int ret = dequeue_used(&serial_rx_ring, &buffer, &buffer_len, &cookie);
if (ret) {
microkit_dbg_puts("MP|ERROR: could not dequeue serial RX used buffer\n");
return 0;
}

char ch = ((char *)buffer)[0];

ret = enqueue_free(&serial_rx_ring, buffer, BUFFER_SIZE, cookie);
if (ret) {
microkit_dbg_puts("MP|ERROR: could not enqueue serial RX free buffer\n");
return 0;
}

return ch;
}

// Send the string of given length.
void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
uintptr_t buffer = 0;
unsigned int buffer_len = 0;
void *cookie = 0;
int ret = dequeue_free(&serial_tx_ring, &buffer, &buffer_len, &cookie);
if (ret) {
microkit_dbg_puts("MP|ERROR: could not dequeue serial TX free buffer\n");
return;
}

// @ivanv, fix
if (buffer_len < len) {
microkit_dbg_puts("MP|ERROR: todo, handle large buffers in serial");
return;
}

// @ivanv: use memcpy instead? Wait for libc integration first
char *str_buf = (char *) buffer;
for (int i = 0; i < len; i++) {
uart_put_char(str[i]);
str_buf[i] = str[i];
}

ret = enqueue_used(&serial_tx_ring, buffer, len, cookie);
// @ivanv: this error condition is a real possibilily and should be handled properly
if (ret) {
microkit_dbg_puts("MP|ERROR: could not enqueue used serial TX buffer\n");
}

microkit_notify(SERIAL_TX_CH);
}
Loading

0 comments on commit 7fb3912

Please sign in to comment.