mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-22 22:53:04 +00:00
Add an option to disable checksumming if possible
* Introduce feature flags which allows the proxy and m1n1 to determine which features they have in common. * Add a feature flag that disables checksumming (by replacing checksums with constant values) for the data packets exchanged by REQ_MEMREAD, REQ_MEMWRITE and REQ_EVENT. The feature is enabled if m1n1 supports it; checksumming is kept enabled for UART communication. * To ensure no packet loss when checksumming is disabled, an extra sentinel value is added after the exchanged data for memory read/write operations. Signed-off-by: Vincent Duvert <vincent@duvert.net>
This commit is contained in:
parent
16f0abe6bb
commit
3d1747466b
2 changed files with 114 additions and 14 deletions
|
@ -76,6 +76,18 @@ class UartChecksumError(UartError):
|
||||||
class UartRemoteError(UartError):
|
class UartRemoteError(UartError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class Feature(IntFlag):
|
||||||
|
DISABLE_DATA_CSUMS = 0x01 # Data transfers don't use checksums
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_all(cls):
|
||||||
|
return cls.DISABLE_DATA_CSUMS
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return ", ".join(feature.name for feature in self.__class__
|
||||||
|
if feature & self) or "<none>"
|
||||||
|
|
||||||
|
|
||||||
class START(IntEnum):
|
class START(IntEnum):
|
||||||
BOOT = 0
|
BOOT = 0
|
||||||
EXCEPTION = 1
|
EXCEPTION = 1
|
||||||
|
@ -119,6 +131,9 @@ class UartInterface:
|
||||||
REQ_BOOT = 0x04AA55FF
|
REQ_BOOT = 0x04AA55FF
|
||||||
REQ_EVENT = 0x05AA55FF
|
REQ_EVENT = 0x05AA55FF
|
||||||
|
|
||||||
|
CHECKSUM_SENTINEL = 0xD0DECADE
|
||||||
|
DATA_END_SENTINEL = 0xB0CACC10
|
||||||
|
|
||||||
ST_OK = 0
|
ST_OK = 0
|
||||||
ST_BADCMD = -1
|
ST_BADCMD = -1
|
||||||
ST_INVAL = -2
|
ST_INVAL = -2
|
||||||
|
@ -156,6 +171,7 @@ class UartInterface:
|
||||||
self.tty_enable = True
|
self.tty_enable = True
|
||||||
self.handlers = {}
|
self.handlers = {}
|
||||||
self.evt_handlers = {}
|
self.evt_handlers = {}
|
||||||
|
self.enabled_features = Feature(0)
|
||||||
|
|
||||||
def checksum(self, data):
|
def checksum(self, data):
|
||||||
sum = 0xDEADBEEF;
|
sum = 0xDEADBEEF;
|
||||||
|
@ -166,6 +182,12 @@ class UartInterface:
|
||||||
|
|
||||||
return (sum ^ 0xADDEDBAD) & 0xFFFFFFFF
|
return (sum ^ 0xADDEDBAD) & 0xFFFFFFFF
|
||||||
|
|
||||||
|
def data_checksum(self, data):
|
||||||
|
if self.enabled_features & Feature.DISABLE_DATA_CSUMS:
|
||||||
|
return self.CHECKSUM_SENTINEL
|
||||||
|
|
||||||
|
return self.checksum(data)
|
||||||
|
|
||||||
def readfull(self, size):
|
def readfull(self, size):
|
||||||
d = b''
|
d = b''
|
||||||
while len(d) < size:
|
while len(d) < size:
|
||||||
|
@ -255,7 +277,7 @@ class UartInterface:
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print(">>", hexdump(reply))
|
print(">>", hexdump(reply))
|
||||||
checksum = struct.unpack("<I", reply[-4:])[0]
|
checksum = struct.unpack("<I", reply[-4:])[0]
|
||||||
ccsum = self.checksum(reply[:-4])
|
ccsum = self.data_checksum(reply[:-4])
|
||||||
if checksum != ccsum:
|
if checksum != ccsum:
|
||||||
print("Event checksum error: Expected 0x%08x, got 0x%08x"%(checksum, ccsum))
|
print("Event checksum error: Expected 0x%08x, got 0x%08x"%(checksum, ccsum))
|
||||||
raise UartChecksumError()
|
raise UartChecksumError()
|
||||||
|
@ -334,8 +356,21 @@ class UartInterface:
|
||||||
print(" Connected")
|
print(" Connected")
|
||||||
|
|
||||||
def nop(self):
|
def nop(self):
|
||||||
self.cmd(self.REQ_NOP)
|
features = Feature.get_all()
|
||||||
self.reply(self.REQ_NOP)
|
|
||||||
|
# Send the supported feature flags in the NOP message (has no effect
|
||||||
|
# if the target does not support it)
|
||||||
|
self.cmd(self.REQ_NOP, struct.pack("<Q", features.value))
|
||||||
|
result = self.reply(self.REQ_NOP)
|
||||||
|
|
||||||
|
# Get the enabled feature flags from the message response (returns
|
||||||
|
# 0 if the target does not support it)
|
||||||
|
features = Feature(struct.unpack("<QQQ", result)[0])
|
||||||
|
|
||||||
|
if self.debug:
|
||||||
|
print(f"Enabled features: {features}")
|
||||||
|
|
||||||
|
self.enabled_features = features
|
||||||
|
|
||||||
def proxyreq(self, req, reboot=False, no_reply=False, pre_reply=None):
|
def proxyreq(self, req, reboot=False, no_reply=False, pre_reply=None):
|
||||||
self.cmd(self.REQ_PROXY, req)
|
self.cmd(self.REQ_PROXY, req)
|
||||||
|
@ -349,7 +384,7 @@ class UartInterface:
|
||||||
return self.reply(self.REQ_PROXY)
|
return self.reply(self.REQ_PROXY)
|
||||||
|
|
||||||
def writemem(self, addr, data, progress=False):
|
def writemem(self, addr, data, progress=False):
|
||||||
checksum = self.checksum(data)
|
checksum = self.data_checksum(data)
|
||||||
size = len(data)
|
size = len(data)
|
||||||
req = struct.pack("<QQI", addr, size, checksum)
|
req = struct.pack("<QQI", addr, size, checksum)
|
||||||
self.cmd(self.REQ_MEMWRITE, req)
|
self.cmd(self.REQ_MEMWRITE, req)
|
||||||
|
@ -363,6 +398,10 @@ class UartInterface:
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
if progress:
|
if progress:
|
||||||
print()
|
print()
|
||||||
|
if self.enabled_features & Feature.DISABLE_DATA_CSUMS:
|
||||||
|
# Extra sentinel after the data to make sure no data is lost
|
||||||
|
self.dev.write(struct.pack("<I", self.DATA_END_SENTINEL))
|
||||||
|
|
||||||
# should automatically report a CRC failure
|
# should automatically report a CRC failure
|
||||||
self.reply(self.REQ_MEMWRITE)
|
self.reply(self.REQ_MEMWRITE)
|
||||||
|
|
||||||
|
@ -375,9 +414,17 @@ class UartInterface:
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print(">> DATA:")
|
print(">> DATA:")
|
||||||
chexdump(data)
|
chexdump(data)
|
||||||
ccsum = self.checksum(data)
|
ccsum = self.data_checksum(data)
|
||||||
if checksum != ccsum:
|
if checksum != ccsum:
|
||||||
raise UartChecksumError("Reply data checksum error: Expected 0x%08x, got 0x%08x"%(checksum, ccsum))
|
raise UartChecksumError("Reply data checksum error: Expected 0x%08x, got 0x%08x"%(checksum, ccsum))
|
||||||
|
|
||||||
|
if self.enabled_features & Feature.DISABLE_DATA_CSUMS:
|
||||||
|
# Extra sentinel after the data to make sure no data was lost
|
||||||
|
sentinel = struct.unpack("<I", self.readfull(4))[0]
|
||||||
|
if sentinel != self.DATA_END_SENTINEL:
|
||||||
|
raise UartChecksumError(f"Reply data sentinel error: Expected "
|
||||||
|
f"{self.DATA_END_SENTINEL:#x}, got {sentinel:#x}")
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def readstruct(self, addr, stype):
|
def readstruct(self, addr, stype):
|
||||||
|
|
|
@ -21,6 +21,7 @@ typedef struct {
|
||||||
u64 size;
|
u64 size;
|
||||||
u32 dchecksum;
|
u32 dchecksum;
|
||||||
} mrequest;
|
} mrequest;
|
||||||
|
u64 features;
|
||||||
};
|
};
|
||||||
u32 checksum;
|
u32 checksum;
|
||||||
} UartRequest;
|
} UartRequest;
|
||||||
|
@ -36,6 +37,7 @@ typedef struct {
|
||||||
u32 dchecksum;
|
u32 dchecksum;
|
||||||
} mreply;
|
} mreply;
|
||||||
struct uartproxy_msg_start start;
|
struct uartproxy_msg_start start;
|
||||||
|
u64 features;
|
||||||
};
|
};
|
||||||
u32 checksum;
|
u32 checksum;
|
||||||
u32 _dummy; // Not transferred
|
u32 _dummy; // Not transferred
|
||||||
|
@ -62,10 +64,17 @@ static_assert(sizeof(UartReply) == (REPLY_SIZE + 4), "Invalid UartReply size");
|
||||||
#define ST_XFRERR -3
|
#define ST_XFRERR -3
|
||||||
#define ST_CSUMERR -4
|
#define ST_CSUMERR -4
|
||||||
|
|
||||||
|
#define PROXY_FEAT_DISABLE_DATA_CSUMS 0x01
|
||||||
|
#define PROXY_FEAT_ALL (PROXY_FEAT_DISABLE_DATA_CSUMS)
|
||||||
|
|
||||||
static u32 iodev_proxy_buffer[IODEV_MAX];
|
static u32 iodev_proxy_buffer[IODEV_MAX];
|
||||||
|
|
||||||
#define CHECKSUM_INIT 0xDEADBEEF
|
#define CHECKSUM_INIT 0xDEADBEEF
|
||||||
#define CHECKSUM_FINAL 0xADDEDBAD
|
#define CHECKSUM_FINAL 0xADDEDBAD
|
||||||
|
#define CHECKSUM_SENTINEL 0xD0DECADE
|
||||||
|
#define DATA_END_SENTINEL 0xB0CACC10
|
||||||
|
|
||||||
|
static bool disable_data_csums = false;
|
||||||
|
|
||||||
// I just totally pulled this out of my arse
|
// I just totally pulled this out of my arse
|
||||||
// Noinline so that this can be bailed out by exc_guard = EXC_RETURN
|
// Noinline so that this can be bailed out by exc_guard = EXC_RETURN
|
||||||
|
@ -102,6 +111,15 @@ static inline u32 checksum(void *start, u32 length)
|
||||||
return checksum_finish(checksum_start(start, length));
|
return checksum_finish(checksum_start(start, length));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u64 data_checksum(void *start, u32 length)
|
||||||
|
{
|
||||||
|
if (disable_data_csums) {
|
||||||
|
return CHECKSUM_SENTINEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return checksum(start, length);
|
||||||
|
}
|
||||||
|
|
||||||
iodev_id_t uartproxy_iodev;
|
iodev_id_t uartproxy_iodev;
|
||||||
|
|
||||||
int uartproxy_run(struct uartproxy_msg_start *start)
|
int uartproxy_run(struct uartproxy_msg_start *start)
|
||||||
|
@ -110,6 +128,7 @@ int uartproxy_run(struct uartproxy_msg_start *start)
|
||||||
int running = 1;
|
int running = 1;
|
||||||
size_t bytes;
|
size_t bytes;
|
||||||
u64 checksum_val;
|
u64 checksum_val;
|
||||||
|
u64 enabled_features = 0;
|
||||||
|
|
||||||
iodev_id_t iodev = IODEV_MAX;
|
iodev_id_t iodev = IODEV_MAX;
|
||||||
|
|
||||||
|
@ -180,6 +199,14 @@ int uartproxy_run(struct uartproxy_msg_start *start)
|
||||||
|
|
||||||
switch (request.type) {
|
switch (request.type) {
|
||||||
case REQ_NOP:
|
case REQ_NOP:
|
||||||
|
enabled_features = request.features & PROXY_FEAT_ALL;
|
||||||
|
if (iodev == IODEV_UART) {
|
||||||
|
// Don't allow disabling checksums on UART
|
||||||
|
enabled_features &= ~PROXY_FEAT_DISABLE_DATA_CSUMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
disable_data_csums = enabled_features & PROXY_FEAT_DISABLE_DATA_CSUMS;
|
||||||
|
reply.features = enabled_features;
|
||||||
break;
|
break;
|
||||||
case REQ_PROXY:
|
case REQ_PROXY:
|
||||||
ret = proxy_process(&request.prequest, &reply.preply);
|
ret = proxy_process(&request.prequest, &reply.preply);
|
||||||
|
@ -193,7 +220,7 @@ int uartproxy_run(struct uartproxy_msg_start *start)
|
||||||
break;
|
break;
|
||||||
exc_count = 0;
|
exc_count = 0;
|
||||||
exc_guard = GUARD_RETURN;
|
exc_guard = GUARD_RETURN;
|
||||||
checksum_val = checksum((void *)request.mrequest.addr, request.mrequest.size);
|
checksum_val = data_checksum((void *)request.mrequest.addr, request.mrequest.size);
|
||||||
exc_guard = GUARD_OFF;
|
exc_guard = GUARD_OFF;
|
||||||
if (exc_count)
|
if (exc_count)
|
||||||
reply.status = ST_XFRERR;
|
reply.status = ST_XFRERR;
|
||||||
|
@ -218,21 +245,43 @@ int uartproxy_run(struct uartproxy_msg_start *start)
|
||||||
reply.status = ST_XFRERR;
|
reply.status = ST_XFRERR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
checksum_val = checksum((void *)request.mrequest.addr, request.mrequest.size);
|
checksum_val = data_checksum((void *)request.mrequest.addr, request.mrequest.size);
|
||||||
reply.mreply.dchecksum = checksum_val;
|
reply.mreply.dchecksum = checksum_val;
|
||||||
if (reply.mreply.dchecksum != request.mrequest.dchecksum)
|
if (reply.mreply.dchecksum != request.mrequest.dchecksum) {
|
||||||
reply.status = ST_XFRERR;
|
reply.status = ST_XFRERR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (disable_data_csums) {
|
||||||
|
// Check the sentinel that should be present after the data
|
||||||
|
u32 sentinel = 0;
|
||||||
|
bytes = iodev_read(iodev, &sentinel, sizeof(sentinel));
|
||||||
|
if (bytes != sizeof(sentinel) || sentinel != DATA_END_SENTINEL) {
|
||||||
|
reply.status = ST_XFRERR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
reply.status = ST_BADCMD;
|
reply.status = ST_BADCMD;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
reply.checksum = checksum(&reply, REPLY_SIZE - 4);
|
reply.checksum = checksum(&reply, REPLY_SIZE - 4);
|
||||||
iodev_write(iodev, &reply, REPLY_SIZE);
|
iodev_queue(iodev, &reply, REPLY_SIZE);
|
||||||
|
|
||||||
if ((request.type == REQ_MEMREAD) && (reply.status == ST_OK)) {
|
if ((request.type == REQ_MEMREAD) && (reply.status == ST_OK)) {
|
||||||
iodev_write(iodev, (void *)request.mrequest.addr, request.mrequest.size);
|
iodev_queue(iodev, (void *)request.mrequest.addr, request.mrequest.size);
|
||||||
|
|
||||||
|
if (disable_data_csums) {
|
||||||
|
// Since there is no checksum, put a sentinel after the data so the receiver
|
||||||
|
// can check that no packets were lost.
|
||||||
|
u32 sentinel = DATA_END_SENTINEL;
|
||||||
|
|
||||||
|
iodev_queue(iodev, &sentinel, sizeof(sentinel));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flush all queued data
|
||||||
|
iodev_write(iodev, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -247,8 +296,12 @@ void uartproxy_send_event(u16 event_type, void *data, u16 length)
|
||||||
hdr.len = length;
|
hdr.len = length;
|
||||||
hdr.event_type = event_type;
|
hdr.event_type = event_type;
|
||||||
|
|
||||||
csum = checksum_start(&hdr, sizeof(UartEventHdr));
|
if (disable_data_csums) {
|
||||||
csum = checksum_finish(checksum_add(data, length, csum));
|
csum = CHECKSUM_SENTINEL;
|
||||||
|
} else {
|
||||||
|
csum = checksum_start(&hdr, sizeof(UartEventHdr));
|
||||||
|
csum = checksum_finish(checksum_add(data, length, csum));
|
||||||
|
}
|
||||||
iodev_queue(uartproxy_iodev, &hdr, sizeof(UartEventHdr));
|
iodev_queue(uartproxy_iodev, &hdr, sizeof(UartEventHdr));
|
||||||
iodev_queue(uartproxy_iodev, data, length);
|
iodev_queue(uartproxy_iodev, data, length);
|
||||||
iodev_write(uartproxy_iodev, &csum, sizeof(csum));
|
iodev_write(uartproxy_iodev, &csum, sizeof(csum));
|
||||||
|
|
Loading…
Reference in a new issue