Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DART support #33

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Expand Up @@ -22,7 +22,7 @@ LIBFDT_OBJECTS := $(patsubst %,libfdt/%, \
fdt_addresses.o fdt_empty_tree.o fdt_overlay.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_sw.o \
fdt_wip.o fdt.o)

OBJECTS := adt.o bootlogo_128.o bootlogo_256.o chickens.o exception.o exception_asm.o fb.o \
OBJECTS := adt.o bootlogo_128.o bootlogo_256.o chickens.o dart.o exception.o exception_asm.o fb.o \
heapblock.o kboot.o main.o memory.o memory_asm.o payload.o proxy.o smp.o start.o startup.o \
string.o uart.o uartproxy.o utils.o utils_asm.o vsprintf.o wdt.o $(MINILZLIB_OBJECTS) \
$(TINF_OBJECTS) $(DLMALLOC_OBJECTS) $(LIBFDT_OBJECTS)
Expand Down
14 changes: 14 additions & 0 deletions proxyclient/proxy.py
Expand Up @@ -353,6 +353,11 @@ class M1N1Proxy:
P_KBOOT_SET_INITRD = 0x702
P_KBOOT_PREPARE_DT = 0x703

P_DART_INIT = 0x800
P_DART_MAP = 0x801
P_DART_UNMAP = 0x802
P_DART_SHUTDOWN = 0x803

def __init__(self, iface, debug=False):
self.debug = debug
self.iface = iface
Expand Down Expand Up @@ -599,6 +604,15 @@ def kboot_set_initrd(self, base, size):
def kboot_prepare_dt(self, dt_addr):
return self.request(self.P_KBOOT_PREPARE_DT, dt_addr)

def dart_init(self, regs, device):
return self.request(self.P_DART_INIT, regs, device)
def dart_map(self, dart, iova, buffer, length):
return self.request(self.P_DART_MAP, dart, iova, buffer, length)
def dart_unmap(self, dart, iova, length):
self.request(self.P_DART_UNMAP, dart, iova, length)
def dart_shutdown(self, dart):
self.request(self.P_DART_SHUTDOWN, dart)

if __name__ == "__main__":
import serial
uartdev = os.environ.get("M1N1DEVICE", "/dev/ttyUSB0")
Expand Down
208 changes: 208 additions & 0 deletions src/dart.c
@@ -0,0 +1,208 @@
/* SPDX-License-Identifier: MIT */

#include "dart.h"
#include "assert.h"
#include "malloc.h"
#include "memory.h"
#include "string.h"
#include "utils.h"

#define DART_CONFIG 0x60
#define DART_CONFIG_LOCK BIT(15)

#define DART_ERROR 0x40
#define DART_ERROR_DOMAIN_SHIFT 24
#define DART_ERROR_DOMAIN_MASK 0xf
#define DART_ERROR_CODE_MASK 0xffffff
#define DART_ERROR_FLAG BIT(31)
#define DART_ERROR_READ_FAULT BIT(4)
#define DART_ERROR_WRITE_FAULT BIT(3)
#define DART_ERROR_NO_PTE BIT(2)
#define DART_ERROR_NO_L1 BIT(1)
#define DART_ERROR_NO_L0 BIT(0)

#define DART_DOMAIN_SELECT 0x34

#define DART_DOMAIN_COMMAND 0x20
#define DART_DOMAIN_COMMAND_BUSY BIT(2)
#define DART_DOMAIN_COMMAND_INVALIDATE BIT(20)

#define DART_DOMAIN_COMMAND_BUSY_TIMEOUT 100

#define DART_DEVICE2DOMAIN_MAP 0x80

#define DART_ERROR_ADDR_HI 0x54
#define DART_ERROR_ADDR_LO 0x50

#define DART_TCR(domain) 0x100 + 4 * (domain)
#define DART_TCR_TRANSLATE_ENABLE BIT(7)
#define DART_TCR_BYPASS_ENABLE BIT(8)

#define DART_TTBR(domain, idx) 0x200 + 16 * (domain) + 4 * (idx)
#define DART_TTBR_VALID BIT(31)
#define DART_TTBR_SHIFT 12

#define DART_PTE_VALID 0b11

struct dart_dev {
uintptr_t regs;
u8 device;

u64 *l1;
};

static void dart_tlb_invalidate(dart_dev_t dart)
{
write32(dart->regs + DART_DOMAIN_SELECT, BIT(dart->device));
write32(dart->regs + DART_DOMAIN_COMMAND, DART_DOMAIN_COMMAND_INVALIDATE);

while (read32(dart->regs + DART_DOMAIN_COMMAND) & DART_DOMAIN_COMMAND_BUSY)
;
}

dart_dev_t dart_init(uintptr_t base, u8 device)
{
dart_dev_t dart = malloc(sizeof(*dart));
if (!dart)
return NULL;

dart->regs = base;
dart->device = device;
dart->l1 = NULL;

if (read32(dart->regs + DART_CONFIG) & DART_CONFIG_LOCK) {
printf("dart: dart at %p is locked\n", dart->regs);
goto error;
}

dart->l1 = memalign(SZ_16K, 4 * SZ_16K);
if (!dart->l1)
goto error;
memset(dart->l1, 0, 4 * SZ_16K);

write32(dart->regs + DART_TTBR(device, 0),
DART_TTBR_VALID | (((uintptr_t)dart->l1) >> DART_TTBR_SHIFT));
write32(dart->regs + DART_TTBR(device, 1),
DART_TTBR_VALID | (((uintptr_t)dart->l1 + SZ_16K) >> DART_TTBR_SHIFT));
write32(dart->regs + DART_TTBR(device, 2),
DART_TTBR_VALID | (((uintptr_t)dart->l1 + 2 * SZ_16K) >> DART_TTBR_SHIFT));
write32(dart->regs + DART_TTBR(device, 3),
DART_TTBR_VALID | (((uintptr_t)dart->l1 + 3 * SZ_16K) >> DART_TTBR_SHIFT));

write32(dart->regs + DART_TCR(device), DART_TCR_TRANSLATE_ENABLE);
dart_tlb_invalidate(dart);

return dart;

error:
free(dart->l1);
free(dart);
return NULL;
}

static u64 *dart_get_l2(dart_dev_t dart, u32 idx)
{
if (dart->l1[idx] & DART_PTE_VALID)
return (u64 *)(dart->l1[idx] & ~DART_PTE_VALID);

u64 *tbl = memalign(SZ_16K, SZ_16K);
if (!tbl)
return NULL;

memset(tbl, 0, SZ_16K);
dart->l1[idx] = (uintptr_t)tbl | DART_PTE_VALID;
return tbl;
}

static int dart_map_page(dart_dev_t dart, uintptr_t iova, uintptr_t paddr)
{
u32 l1_index = (iova >> 25) & 0x1fff;
u32 l2_index = (iova >> 14) & 0x7ff;

u64 *l2 = dart_get_l2(dart, l1_index);
if (!l2) {
printf("dart: couldn't create l2 for iova %llx\n", iova);
return -1;
}

if (l2[l2_index] & DART_PTE_VALID) {
printf("dart: iova %llx already has a valid PTE: %llx\n", iova, l2[l2_index]);
return -1;
}

l2[l2_index] = (uintptr_t)paddr | DART_PTE_VALID;

return 0;
}

int dart_map(dart_dev_t dart, uintptr_t iova, void *bfr, size_t len)
{
uintptr_t paddr = (uintptr_t)bfr;
u64 offset = 0;

if (len % SZ_16K)
return -1;
if (paddr % SZ_16K)
return -1;
if (iova % SZ_16K)
return -1;

while (offset < len) {
int ret = dart_map_page(dart, iova + offset, paddr + offset);

if (ret) {
dart_unmap(dart, iova, offset);
return ret;
}

offset += SZ_16K;
}

dart_tlb_invalidate(dart);
return 0;
}

static void dart_unmap_page(dart_dev_t dart, uintptr_t iova)
{
u32 l1_index = (iova >> 25) & 0x1fff;
u32 l2_index = (iova >> 14) & 0x7ff;

if (!(dart->l1[l1_index] & DART_PTE_VALID))
return;

u64 *l2 = (u64 *)(dart->l1[l1_index] & ~DART_PTE_VALID);
l2[l2_index] = 0;
}

void dart_unmap(dart_dev_t dart, uintptr_t iova, size_t len)
{
if (len % SZ_16K)
return;
if (iova % SZ_16K)
return;

while (len) {
dart_unmap_page(dart, iova);

len -= SZ_16K;
iova += SZ_16K;
}

dart_tlb_invalidate(dart);
}

void dart_shutdown(dart_dev_t dart)
{
write32(dart->regs + DART_TCR(dart->device), 0);
for (int i = 0; i < 4; ++i)
write32(dart->regs + DART_TTBR(dart->device, i), 0);
dart_tlb_invalidate(dart);

for (int i = 0; i < SZ_16K / 8; ++i) {
if (dart->l1[i] & DART_PTE_VALID)
free((void *)(dart->l1[i] & ~DART_PTE_VALID));
}

free(dart->l1);
free(dart);
}
15 changes: 15 additions & 0 deletions src/dart.h
@@ -0,0 +1,15 @@
/* SPDX-License-Identifier: MIT */

#ifndef DART_H
#define DART_H

#include "types.h"

typedef struct dart_dev *dart_dev_t;

dart_dev_t dart_init(uintptr_t base, u8 device);
int dart_map(dart_dev_t dart, uintptr_t iova, void *bfr, size_t len);
void dart_unmap(dart_dev_t dart, uintptr_t iova, size_t len);
void dart_shutdown(dart_dev_t dart);

#endif
2 changes: 2 additions & 0 deletions src/malloc.h
Expand Up @@ -3,6 +3,8 @@
#ifndef MALLOC_H
#define MALLOC_H

#include "types.h"

void *malloc(size_t);
void free(void *);
void *calloc(size_t, size_t);
Expand Down
2 changes: 2 additions & 0 deletions src/memory.h
Expand Up @@ -5,6 +5,8 @@

#include "types.h"

#define SZ_16K 0x4000

void ic_ivau_range(void *addr, size_t length);
void dc_ivac_range(void *addr, size_t length);
void dc_zva_range(void *addr, size_t length);
Expand Down
17 changes: 16 additions & 1 deletion src/proxy.c
@@ -1,11 +1,12 @@
/* SPDX-License-Identifier: MIT */

#include "proxy.h"
#include "dart.h"
#include "exception.h"
#include "heapblock.h"
#include "kboot.h"
#include "malloc.h"
#include "memory.h"
#include "proxy.h"
#include "smp.h"
#include "types.h"
#include "uart.h"
Expand Down Expand Up @@ -304,6 +305,20 @@ int proxy_process(ProxyRequest *request, ProxyReply *reply)
reply->retval = kboot_prepare_dt((void *)request->args[0]);
break;

case P_DART_INIT:
reply->retval = (u64)dart_init(request->args[0], request->args[1]);
break;
case P_DART_MAP:
reply->retval = dart_map((dart_dev_t)request->args[0], request->args[1],
(void *)request->args[2], request->args[3]);
break;
case P_DART_UNMAP:
dart_unmap((dart_dev_t)request->args[0], request->args[1], request->args[2]);
break;
case P_DART_SHUTDOWN:
dart_shutdown((dart_dev_t)request->args[0]);
break;

default:
reply->status = S_BADCMD;
break;
Expand Down
5 changes: 5 additions & 0 deletions src/proxy.h
Expand Up @@ -81,6 +81,11 @@ typedef enum {
P_KBOOT_SET_INITRD,
P_KBOOT_PREPARE_DT,

P_DART_INIT = 0x800, // DART iommu ops
P_DART_MAP,
P_DART_UNMAP,
P_DART_SHUTDOWN,

} ProxyOp;

#define S_OK 0
Expand Down
2 changes: 2 additions & 0 deletions src/types.h
Expand Up @@ -44,4 +44,6 @@ typedef s64 ptrdiff_t;
#define HAVE_UINTPTR_T 1
#define UPTRDIFF_T uintptr_t

#define BIT(x) (1L << (x))

#endif
2 changes: 0 additions & 2 deletions src/utils.h
Expand Up @@ -7,8 +7,6 @@

#define printf debug_printf

#define BIT(x) (1L << (x))

static inline u64 read64(u64 addr)
{
u64 data;
Expand Down