tosc-rs / mnemos

An Operating System for Building Small Computers
https://mnemos.dev
Apache License 2.0
253 stars 18 forks source link

feat(D1): DMAC Driver 2: Electric Boogaloo #281

Closed hawkw closed 1 year ago

hawkw commented 1 year ago

This branch kinda rewrites a bunch of the DMAC code. Now, DMA channels are capable of being dynamically allocated on demand using a cool atomic bitset thingy, and released back to the DMAC pool when they're no longer in use. This will allow us to have multiple drivers that consume basically as many DMA channels as they want to, rather than having a fixed assignment of DMA channels to drivers which has to be maintained by manually updating the DMAC IRQ handler every time we add a new driver that wants to do a DMA. A channel can be allocated from the pool once and used for multiple transfers, if a driver needs to make a bunch of transfers in sequence and doesn't want to have to round trip through the channel pool, but they can also be grabbed for oneshot transfers and immediately released.

I also fixed the cancel safety of the async Channel::transfer (formerly Channel::run_descriptor) method, which would previously leave the transfer running if the future is dropped. This means that if a caller assumed dropping the transfer future meant that the transfer descriptor's buffer could be freed, the transfer might complete later and trample memory that has been reallocated. THAT SEEMS KINDA BAD LOL. So, now, dropping a Channel::transfer future will cancel the transfer if it hasn't finished yet, allowing fun stuff like attaching a timeout to a transfer if you really want to. Of course, the transfer may still have completed partially, and if we were writing to a device, the device may be unhappy to have only gotten some of the data it wanted. But, at least we don't have abandoned DMA transfers running around in random parts of the heap you probably wanted to use for normal stuff like having strings, or whatever it is that people do on the computer. So that's better.

Unfortunately, while we can easily make the DMA transfers Drop-safe, we can't really make them mem::forget-safe without passing the DMA buffer into the future and leaking it if it gets forgetted. This is probably a good idea but would require a nice higher-level interface around constructing DMA descriptors from buffer-shaped memory regions, which I didn't want to do tonight. So, the DMA transfer APIs are still unsafe and maybe we can add a nicer thing on top later. In the meantime, probably don't mem::forget DMA transfers. Honestly there is no reason for normal people to do that so I don't feel super bad about it.