for some reason I was setting the state of a canvas to not drawable
when the clip rectangle was being reset, causing dynamic dialog boxes
to become static if the content inside changes size.
I think this is an artifact of a previous generation of this code,
so commenting that out, but left a breadcrumb is case I'm wrong.
this contains a dependency to `failure` two levels down that has a critical
vulnerability. Unfortunately no new versions of debug-here have been
published in a while. It's no longer used, so just stripping it out
altogether.
- Opcodes are mapped to static IDs
- connection ID is now visible to someone who already owns
the keyboard object. This can then be shared with the FFI
interface to do calls to the keyboard server.
Merge in the latest progress as it includes some fixes to the PDDB
(read_all() now works as expected), and to the keyboard listener
API on the dynamic notifications dialog box.
Spent the last couple days tracing down a dastardly bug, which was
slew only upon the creation of mjolnir.
The SpinalHDL USB core is unique in that it has a hardware
implementation of a linked list for its descriptors. This can
be very high performance because you can receive packets much
faster than software can keep up with it in short bursts --
assuming the stack can deal with it.
Unfortunately the poor Rust stack that we adopted from
the STM32 land only assumes single descriptors. Alas, we cannot
unlock the full power of linked list descriptors, and instead
we use "single entry lists" with static allocations, to match
the paradigm of the STM32.
Anyways. Early on, when creating the linked list allocator,
I contemplated doing it the Rusty way, and the C way. The Rusty
way would create a structure that mapped the descriptor headers
plus the variable-sized data chunk into some magical structure
that got us bounds checking and had proper accessors etc.
The C way would just be raw pointer manipulation using unsafes.
Unfortunately, my Rust-fu was no match for the linked list.
The problem is that the descriptors could be of any data size,
and they had to be mapped to a very specific piece of memory.
So I had to create a `repr (C)` struct that matched Rust's
alignment requirements and also somehow could deal with
a variable length array *but could not be a slice* because
the hardware implementation does not have the flexibility
to accommodate a fat pointer. I couldn't figure out how
to get const generics to work, and the size of the array
could be anything from 0 bytes to a couple kilobytes. So,
I ditched the safety of Rust and went with a C-style unsafe
pointer implementation.
Sure enough, it came to haunt me. When I wrote the allocator,
I forgot to allocate space for the descriptor headers. This
worked fine for the keyboard, because the keyboard asks for
32-byte descriptors but only ever does a 25-byte report. That's
just enough to fit the descriptor headers, ironically.
When implementing FIDO/U2F, it asks for 64-byte descriptors
and uses exactly 64-byte messages for everything. This caused
a bug where I could receive one incoming packet, but when
responding with an outgoing packet we'd overwrite the descriptors
of the receiving packet, zeroing it out, causing the the descriptor
to fail in the hardware state machine. Of course I never saw
this because I would print the descriptors of the individual
endpoints upon creating them, but the pointer-overflow problem
only occurs later.
Thus mjolnir was created, it is basically a tool that gives me
a raw hex dump of the endpoint and descriptor banks, which I
can then analyze and diff. It's very powerful, but also very
unweildy -- if invoked indiscriminantly, the overhead of
all the prints would cause other failures due to timing problems.
Thus mjolnir exists as a feature that introduces special
locks around the USB endpoints so that they NAK while mjolnir
does its analysis, disallowing concurrent mutation of the
memory state.
Upon deploying mjolnir, the problem became obvious, and it is
now fixed.
Thus, while on the one hand, it's a great story of how maybe
we should avoid unsafe Rust, it's also a story of how hardware
structures like a hardware linked list may be fundamentally
incompatible with Rust. I think if the hardware USB descriptor
linked list was modified to allow for a fat pointer to track
a data slice, the implementation would almost be trivial. But,
rewriting HDL to fit Rust also has its hazards, as the exact
layout of a fat pointer in RAM is not guaranteed and it would
probably foolhardy to commit to something not guaranteed in
hardware.
this fixes two things:
1. writes no longer generate a spurious interrupt on completion
that also triggers a "non-read".
2. writes are not automatically set to send on allocation. this
solves issue #170. they are only set to send after a write.
This macro will be removed, since it is no longer necessary. Remove this
macro across the project and replace it with a standard `main()`
function.
Signed-off-by: Sean Cross <sean@xobs.io>