tokomak has quit [Ping timeout: 252 seconds]
rardiol has quit [Ping timeout: 265 seconds]
starblue has quit [Ping timeout: 256 seconds]
starblue has joined #rust-embedded
emerent_ has joined #rust-embedded
emerent is now known as Guest2577
Guest2577 has quit [Killed ( (Nickname regained by services))]
emerent_ is now known as emerent
procton_ has joined #rust-embedded
procton__ has quit [Ping timeout: 256 seconds]
dcz_ has quit [Ping timeout: 265 seconds]
PyroPeter has quit [Ping timeout: 252 seconds]
PyroPeter has joined #rust-embedded
tokomak has joined #rust-embedded
dcz_ has joined #rust-embedded
<re_irc> <> Hello! I need some help on RISC-V fence here. If anyone have a run able RISC-V device on hand, run this line of code:
<re_irc> <> unsafe { asm!(".word 0x0100000F", options(nomem, nostack)) };
<re_irc> <> This is a PAUSE instruction encoded in hint space, it shouldn't raise illegal instruction on any RISC-V devices.
<re_irc> <> Please tell me if this instruction runs successfully, or it results in exception. Thanks! :)
<re_irc> <> looks more like an rv32 `FENCE` with `pred=---W succ=----` to me, or am I reading that wrong?
<re_irc> <> Yes you are right, it's a special encoding for pause hint instruction, or NOP if not supported
procton has joined #rust-embedded
<re_irc> <> Just published the first version of `byte-slab`, a statically-allocated pool allocator used by Powerbus, and soon the Anachro protocol as well.
<re_irc> <>
<re_irc> <> It's a bit like `heapless::Pool`, but it also supports the ability to turn `Box`s into reference counted `Arc`s, which is useful if you need to hold on to data in a couple places for a bit.
<re_irc> <> The intent is a bit like `BBQueue`, in that I mostly use it for DMA in and out, but unlike BBQueue, it doesn't require strict first-in-first-out ordering, which I needed for my network stack
<re_irc> <> docs should be up in a bit, but the docs queue is pretty long today :D
<re_irc> <> It's also fully zero-initialized, so it shouldn't take up any flash space, and fits entirely in `.bss`
rardiol has joined #rust-embedded
tokomak has quit [Ping timeout: 252 seconds]
tokomak has joined #rust-embedded
<re_irc> <> Sounds very handy!
tokomak has quit [Ping timeout: 252 seconds]
<re_irc> <> hello room, meeting time again! agenda is, please add anything you'd like to discuss and we'll start in 5min :)
<re_irc> <> ok, let's start
<re_irc> <> couple of announcements first: the discovery book rewrite is now live! you can read the new book at, and a huge thank-you to hargonix for all their work on it!
<re_irc> <> and second, svd2rust 0.20.0 is now out, you can read the changelog here:
<re_irc> <> does anyone else have any announcements?
<re_irc> <> Someone put something in the blog? 😉
<re_irc> <> excellent idea! I can put a pr together later unless you're volunteering?
<re_irc> <> I bring the idea, you bring the implementation. 😀
<re_irc> <> I'll try and remember later, then
<re_irc> <> ok, next up is a reminder about this `itm` RFC in, I expect it will be approved soon and thus we'll move that repo and add tmplt as an owner on
<re_irc> <> conveniently it's one of the crates we recently regained the ability to add owners to, alongside cross, heh
<re_irc> <> and second, the RFC for moving `cross` to its own organisation is now up too, if tools team members could have a look:
rardiol has quit [Ping timeout: 240 seconds]
<re_irc> <> we can discuss either of those now if anyone wants to, or otherwise comments on the PR threads is fine
<re_irc> <> hm, that's about it for agenda items beyond the regular reminder that we're happy to take entries for the newsletter via PR to
<re_irc> <> eldruin / therealprof are there any HAL PRs that would be worth checking in on?
<re_irc> <> Do you want me to set up the voting for the RFC?
<re_irc> <> I've already requested review from the tools team members and generally we vote by approving it, github shows the ticks
<re_irc> <> not sure when we started doing checklists but I think approving via review is fine for PRs
<re_irc> <> adamgreig: I didn't have the bandwidth to check in last week, I'm afraid.
<re_irc> <> adamgreig: Well, ticky boxes don't get lost, when you e.g. fix the rust typo. 😉
<re_irc> <> oh no, I already fixed that last night but now see I didn't push the fix -_-
<re_irc> <> you can remove me from cross team, as I have too little undertanding how it works
<re_irc> <> burrbull: In a nutshell, that's what the RFC proposes to do. 😉
<re_irc> <> 👍ïļ, I expect to ask which of the tools team members want to be in the new cross org afterwards
<re_irc> <> sorry, PR updated, reviews dismissed :P
<re_irc> <> anything else for this week?
<re_irc> <> Maybe eldruin has something?
<re_irc> <> not really
<re_irc> <> Where are we with the E-H 1.0 finalisation?
<re_irc> <> there is but I think we can discuss in the issue first
<re_irc> <> also, not a blocker for 1.0
<re_irc> <> for 1.0 the only thing missing is the spi trait reorg
<re_irc> <> a PR from dirbaio
<re_irc> <> for that I said it would be good to provide proof implementations
<re_irc> <> since the idea sounds good
rardiol has joined #rust-embedded
<re_irc> <> GrantM11235 is working on one in embassy (I think)
<re_irc> <> but the traits work fine (TM) at the moment
<re_irc> <> there's also the time trait stuff
<re_irc> <> didn't we agree on removing those traits?
<re_irc> <> and if we think the reorg is a good thing, it should be applied to the other traits (I did it just for SPI first to get feedback)
<re_irc> <> there was a question on pwmpin
<re_irc> <> which could stay in but the pr removes it
<re_irc> <> yes, yes
<re_irc> <> now that you mention it, the proof burden increases then
<re_irc> <> I guess it applies to i2c and serial as well
<re_irc> <> the rest is fine I think
<re_irc> <> we are not touching CAN are we :rofl:
<re_irc> <> Speaking of CAN, does it make sense to impl those traits for `&RefCell`?
<re_irc> <> Are you see atat::Clock? Looks like replacement for ClockDown (using fugit)
<re_irc> <> replied
<re_irc> <> I have not seen that
<re_irc> <> but I think removing the traits first and then figuring out which Time to use would be better
<re_irc> <> then we can defer the decision
<re_irc> <> regarding &RefCell we can discuss in the issue TL;DR I think it is not obvious that acquiring a refcell cannot panic in the field. adding a branch with panic would invalidate anything like panic-never and so on. the alternative with try_borrow_but would require a "big" change to the error types as well, so
<re_irc> <> yeah I find it a bit scary too
<re_irc> <> Yeah, I agree.
<re_irc> <> and it's something the user can do outside e-h with a newtype
<re_irc> <> exactly
<re_irc> <> (you could say the same about `&mut` though, but that one didn't have the panicky downside)
<re_irc> <> I think it would be good to address this in the docs somewhere. I see this question come up a lot.
<re_irc> <> yeah...
<re_irc> <> it'd be nice to have some "semi-officially-blessed" crate (or crates) for sharing buses
<re_irc> <> but it seems there's no "perfect solution", all of them have downsides/tradeoffs
* re_irc needs to leave now and has no other topics, sorry. Thanks!
<re_irc> <> Yeah... A diverse ecosystem of hardware sometimes requires a diverse set of solutions.
<re_irc> <> I don't think that the possibility of a panic branch is that big of a deal
<re_irc> <> so maybe perhaps list a few crates that do it, with a quick summary of the differences/tradeoffs
<re_irc> <> so users at least get some pointers instead of getting lost
<re_irc> <> It is, if you're trying to guarantee that the code will never panic.
<re_irc> <> `embedded-hal-refcell` crate? :P
<re_irc> <> If you want to do that, you can make your own refcell newtype that doesn't panic. I don't think that is a reason not to include a sensible impl for everyone else
<re_irc> <> perhaps it could be maintained inside the repo/wg
<re_irc> <> but keeping it separate to make it clear that by using it you're making that particular tradeoff
<re_irc> <> maybe also `embedded-hal-mutex`? it'd be `impl Write for &Mutex<impl Write>`
<re_irc> <> that one can't panic but it blocks irqs
<re_irc> <> different tradeoff ðŸĪ·
<re_irc> <> ah, no, Mutex doesn't have interior mutability, you'd need `&Mutex<RefCell<impl Write>>`. blarg
<re_irc> <> yea...
<re_irc> <> wonder what we should do about Mutex
<re_irc> <> did you see the slight shade thrown at it in the hubris FAQs
<re_irc> <> (the critical section mutex, the std mutex does, maybe it's useful together with `linux-embedded-hal` or similar)
<re_irc> <> in any event keeping a refcell version outside the main crate seems reasonable
<re_irc> <> sort of thing a HAL could reasonably re-export or even provide itself
<re_irc> <> HALs should stay unopinionated on how to share the buses, though?
<re_irc> <> I guess? it seems like some HALs would be in a good position to offer ways to share the bus that are natural for the platform they target, like linux-embedded-hal and a linux mutex, or maybe embassy and something to do with the executor?
<re_irc> <> yea
<re_irc> <> > we've reported the behavior upstream, but upstream doesn't seem to be particularly worried about shipping unsound code.
<re_irc> <> WTF
<re_irc> <> I think the issue is more about a conflation of the HAL and the cortex-m crate, of course the embedded-hal traits are OK
<re_irc> <> yeah...
<re_irc> <> they *are* right about `cortex_m::interrupt::Mutex` though
<re_irc> <> it's fair to say the cortex-m mutex is unsound in unpriv mode (as well as on multi-core systems)
<re_irc> <> Yeah, this is confusing multiple separate issues.
<re_irc> <> it's kind of gross all around, but without some other executor or framework like rtic or whatever, what are you to do?
<re_irc> <> `critical-section` solves this
<re_irc> <> well, maybe the answer is "split the part that assumes priv-only single-core simple runtime out of the cortex-m main crate" perhaps
<re_irc> <> have all libs use it, then have the user pick the right `critical-section` impl
<re_irc> <> baremetal singlecore -> `cpsid/cpsie`
<re_irc> <> hubris userland -> could be a noop since it's single threaded (?)
<re_irc> <> baremetal multicore -> custom chip-specific hw spinlock
<re_irc> <> I wonder who they contacted about this and when...
<re_irc> <> various oxide people have regularly chatted to us here and opened issues and PRs
<re_irc> <> they don't generally have a big 'i work for oxide btw' banner
<re_irc> <> dirbaio: critical-section still requires the current code can't be pre-empted in its docs, right?
<re_irc> <> they've certainly talked several times about the limits of the current general ecosystem design around assuming everything is running in priv mode and can just access anything and turn off interrupts
<re_irc> <> Sure, but I don't see us saying anything that would indicate that we're not willing to address such an issue.
<re_irc> <> (it still seems like the FAQ could be clarified to refer to cortex-m instead of embedded-hal)
<re_irc> <> (or basket of different issues)
<re_irc> <> well regardless of saying anything we've not done anything...
<re_irc> <> adamgreig: it is required to enforce "no two critical sections can run concurrently in the current program"
<re_irc> <> the key is in the definition of "program"
<re_irc> <> if you consider the kernel another "program" then it's OK for the kernel to preempt a userland task
<re_irc> <> as long as it never synchronously "calls back" into userland
<re_irc> <> for RTIC for example though, you want sharing based on mutual resource access across priorities, but c-s would still require no pre-emption at all?
<re_irc> <> same for the nrf softdevice, it "calls back" to the user's "program" via a dedicated irq, so as long as you disable that one it's OK to not disable the rest
<re_irc> <> adamgreig: yeah if you mix many priorities in your "program" you have to block off all of them, you can't be more granular like RTIC
<re_irc> <> it's a "program-global critical section" after all
<re_irc> <> I wonder if that would matter, since rtic handles its own locks and sharing
<re_irc> <> but maybe makes it annoying if you want to interoperate libraries
<re_irc> <> the problem they have in hubris extends to the global singleton peripherals in PACs, too
<re_irc> <> but that's sort of separate
<re_irc> <> well, RTIC still interoperates fine with `critical-section`, just "too coarse"
<re_irc> <> but it's sound
<re_irc> <> (part of the general assumption that the firmware is in priv mode and the only thing running, though)
<re_irc> <> ah, sure, because you'd use a global cpsid/cpsie?
<re_irc> <> I think we have to get rid of owned singletons in PACs
<re_irc> <> and make cortex-m a PAC, and get rid it them there too
<re_irc> <> adamgreig: the default yeah, and if the user overrides it it's their job to pick an impl that's sound in their environment
<re_irc> <> do the c-s docs talk about how to set it anywhere?
<re_irc> <> c-s has no docs at all ðŸĪĢ
<re_irc> <> I still have to write them
<re_irc> <> but it's super nontrivial
<re_irc> <> heh
<re_irc> <> how do you define "program"
<re_irc> <> so I've been postponing it
<re_irc> <> lolol
<re_irc> <> but I do have the feeling there HAS to be a "sane" definition that works for everything and makes c-s sound
<re_irc> <> Or maybe we need to peek into what they're doing and let us inspire for a better approach? Certainly they're not using vanilla `cortex-m` if it includes such outrageous unsoundness?
<re_irc> <> They are.
<re_irc> <> they are using it, just not `cortex_m::interrupt::Mutex`
<re_irc> <> Then that FAQ makes even less sense to me. ðŸĪ·ðŸŧ‍♂ïļ
<re_irc> <> they've documented pretty clearly how cortex-m could update to be useful here
<re_irc> <> I think someone was just frustrated and did not express it very well?
<re_irc> <> I think their complaint is many libs use `cortex_m::interrupt::Mutex` internally
<re_irc> <> adamgreig: Yeah, that confused me a bit... i asked for a clarification on twitter but got pointed to embedded-hal repo ðŸĪ·â€â™‚ïļ
<re_irc> <> like the PACs `Peripherals::take()`
<re_irc> <> I dread to imagine what their twitter notifications were like, to be fair, lol
<re_irc> <> and a lot of libs with disable interrupts when setting up things like GPIOs, which isn't ideal if you want to setup peripherals in userland
<re_irc> <> saw at least one person saying "they haven't realised it, but they've almost made a rate monotonic rtos! they should move all the tasks into a single stack next though, that would be better"
<re_irc> <> if a lib uses `cortex_m::interrupt::Mutex` you're screwed if it doesn't work in your environment, you have to fork it
<re_irc> <> I run into it all the time with `nrf-softdevice`, it's really annoying
<re_irc> <> Hm, maybe we should have another look. I completely forgot that existed after the lang awkward pause.
<re_irc> <> I think a lot of ideas have been circulating to design a better general ecosystem, it's just hard because it's extremely wide-ranging
<re_irc> <> some sort of user-configurable critical-section to replace mutex is nice, any current use of mutex is pretty awkward...
<re_irc> <> the owned PAC singletons are _so_ widespread in HALs... it would be a disruptive change
<re_irc> <> adamgreig: Also we are kind of held back by the maturity of language features that _really_ help embedded. There is still only one RTOS that compiles on stable (RTIC), and it is pretty low level.
<re_irc> <> sure
<re_irc> <> would it help to transfer `critical-section` to the WG?
<re_irc> <> inline_asm so soon...
<re_irc> <> then remove `cortex_m::interrupt::Mutex`
<re_irc> <> perhaps write one (or a few) embedonomicon chapters ðŸĪĢ
<re_irc> <> a chapter "here's what all the terms mean" for example...
<re_irc> <> program, execution context, hmm
<re_irc> <> and remove PAC owned singletons :P
<re_irc> <> adamgreig: I think it is a valid concern though. The best time to change direction is sooner rather than later.
<re_irc> <> yea
<re_irc> <> hals are full of "stealing" pac singletons though
<re_irc> <> all GPIO HALs do it
<re_irc> <> but I'd like to be fairly confident we'd wrapped up enough big breaking changes
<re_irc> <> or that we have a single coherent plan for the various large things that change, anyway
<re_irc> <> but they "steal" something that gives them an owned singleton in the end
<re_irc> <> it's not like they could upgrade by just stealing Peripherals at the start and keeping the rest the same
<re_irc> <> if you steal the owned singeton from anywhere, it's no longer owned, is it? 🙈
<re_irc> <> there wouldn't be anything to steal any more
<re_irc> <> so at the least, a lot of APIs would change?
<re_irc> <> adamgreig: In that case can we just switch to chiptool 😛
<re_irc> <> I don't know, maybe it could be small enough
<re_irc> <> it's not *YOUR* singleton, it's *OUR* singleton!
<re_irc> <> adamgreig: The biggest change would be RTIC, since it relies on the output of svd2rust being a owned singleton, and a lot of people use RTIC.
<re_irc> <> Why can't we expose the individual peripherals in addition to the singleton?
<re_irc> <> I don't see why that would be any worse than stealing and it would keep the most-used-API.
<re_irc> <> because the ownership goes away regardless
<re_irc> <> It does. But it wouldn't break the world. 😉
<re_irc> <> so it wouldn't be sound for RTIC to keep offering those peripherals via cx.device, if the user's also using a HAL that provides safe access to same
<re_irc> <> A transition release with `take` marked as deprecated would probably do the job.
<re_irc> <> gotta run for a bit, and we're out of time for meeting anyway, thanks all!
<re_irc> <> adamgreig: this is already the case with embassy...
<re_irc> <> IMO "fully safe multi-HAL" is impossible
<re_irc> <> How do you imagine ever coordinating that?
<re_irc> <> We talked about a sort of weird singletons crate once
<re_irc> <> Which could include DMA channels and stuff
<re_irc> <> yeah, but I'm somewhat pessimistic on that too
<re_irc> <> embassy does a lot of "opinionated" decisions on how it chops up the singletons
<re_irc> <> other HALs may want to do different decisions on that
<re_irc> <> yjrz
<re_irc> <> Plus someone could just invent `peripherals2` which hands out a duplicate set of singletons
<re_irc> <> maybe the "peripherals" crate could do the most "conservative" choice of not splitting singletons, and let HALs add `.split()`s
<re_irc> <> like `DMA1 -> channels` or `GPIOA -> pins`
<re_irc> <> but a thing I like a lot of embassy's singletons is precisely that the user *doesn't* have to do that
<re_irc> <> so... ðŸĪ·
troth has quit [Ping timeout: 252 seconds]
troth has joined #rust-embedded
<re_irc> <> Right, specifically hubris are upset cortex-m #233.
jasperw has quit [Ping timeout: 268 seconds]
<re_irc> <> We also have an apology from cliff.
jasperw has joined #rust-embedded
<re_irc> <> What alternative API would y'all have vice owning reg block structs etc?
<re_irc> <> no owned reg blocks
<re_irc> <> regblock structs behave like pointers (are Clone+Copy) and you can get one for any regblock at any time (they're consts)
<re_irc> <> and then all reg access is unsafe
<re_irc> <> that's what chiptool/stm32-metapac do
<re_irc> <> Could you provide a syntax example for a reading or writing a MCU register?
<re_irc> <> In some sense the register write syntax is a separate problem
<re_irc> <> the syntax can be the same as now
<re_irc> <> It could be just like current svd2rust or totally different like stm32ral
<re_irc> <> *Btw, I'm aware of Agg's stm32-RAL alternative reg syntax
<re_irc> <> using macros for a cleaner API
<re_irc> <> one small difference chiptool does is instead of having `&RegisterBlock` you'd have `RegisterBlock`
<re_irc> <> `#[derive(Copy,Clone)] pub struct RegisterBlock(ptr: *mut u8)`
<re_irc> <> So not zst?
<re_irc> <> So, instead of
<re_irc> <> dp.RCC.ahbenr.modify(//...
<re_irc> <> ```rust
<re_irc> <> let mut dp = pac::Peripherals::take();
<re_irc> <> adamgreig: not ZST, but the current `&RegisterBlock` isn't ZST either
<re_irc> <> the `&RegisterBlock` -> `RegisterBlock` change is to fix
<re_irc> <> But the current owned peripheral structs are zst, right?
<re_irc> <> which is somewhat orthogonal
<re_irc> <> Mostly people pass them instead of RegisterBlock iirc
<re_irc> <> the current PACs have two types the user deal with
<re_irc> <> Owned singletons: `pac::USART1`. It's ZST
<re_irc> <> RegisterBlock: `&pac::usart::RegisterBlock`. Not ZST
<re_irc> <> chiptool PACs have just one
<re_irc> <> egisterBlock: `&pac::usart::RegisterBlock`. Not ZST
<re_irc> <> there's no equivalent to the owned singleton `pac::USART1`
<re_irc> <> Btw, I haven't found the owned singletons to be particularly restrictive, or the current modify/write syntax etc that bad
<re_irc> <> But am open to improvements
<re_irc> <> `pac::USART1` is instead a `const` of type `pac::usart::RegisterBlock`
<re_irc> <> The modify/write syntax is verbose if you're only editing a single field, but I think it's nice to have a single syntax instead of an additional shorthand if you don't need teh closure
<re_irc> <> My main beef is needing to skip a semicolon for the last item
<re_irc> <> it's awk/inconsistent
<re_irc> <> That would be simpler
<re_irc> <> Sure
<re_irc> <> and it's up to the HAL to define the ZST singletons
<re_irc> <> and that has another HUGE advantage, which is the user only interacts with HAL types. The PAC becomes an implementation detail of the HAL
<re_irc> <> which is huge because now you can major-bump the PAC without major-bumping the HAL
<re_irc> <> today a PAC major-bump breaks *the entire universe*
<re_irc> <> because PACs have to actively disallow linking multiple major versions to make `Peripehrals::take()` sound... so a PAC major-bump requires updating all crates *at the same time*
<re_irc> <> no PAC owned singletons means it's fine to mix multiple PAC major versions
<re_irc> <> so a user can use PAC 0.32 while the HAL is still on PAC 0.31
<re_irc> <> or HAL 0.6.3 -> 0.6.4 (minor) can bump PAC 0.31->0.32 (major) without breaking anything
<re_irc> <> Hot take: `pac::Peripherals::take()` still isn't sound because I can create a new duplicate pac and call `pac2::Peripherals::take()` also
<re_irc> <> if both PACs are "svd2rust compliant" no, you can't
<re_irc> <> this `no_mangle` is there to intentionally make linking fail if you try
<re_irc> <> `pac2` is svd2rust2 compliant 😜
<re_irc> <> well yeah then sure
<re_irc> <> svd2rust2 is just as sound as svd2rust, pac2 is just as sound as pac
<re_irc> <> well, pac2 uses some `unsafe` internally and exposes it in a safe api
<re_irc> <> so it's "accepting the responsibility of the consequences"
<re_irc> <> of violating the "standard"
<re_irc> <> you get crates A and B which are sound in isolation but unsound when you use both ðŸĪ·
<re_irc> <> If they are unsound when you use both, then they (or at least one) is unsound
<re_irc> <> uuh
<re_irc> <> we're talking about "global context" here
<re_irc> <> there's this "global context": an USART1 instance
<re_irc> <> there's only one of it, you can only access it with unsafe, and the compiler knows nothing about it
<re_irc> <> I think if we take "If they are unsound when you use both, then they (or at least one) is unsound" then it's 100% impossible to offer a safe API to accessUSART1 :D
<re_irc> <> because whatever your crate does, another crate can do too, then they're unsound when used together
<re_irc> <> The only solution I can think of is if a runtime provides a singleton
<re_irc> <> what runtime? :D
<re_irc> <> IDK. cortex-m-rt maybe?
<re_irc> <> then you have the same problem at the runtime layer: what if the user mixes two runtimes?
<re_irc> <> What if your main function was `fn main(singleton: Singleton) -> !`
<re_irc> <> Can you mix runtimes? Something has to live at the reset vector, right?
<re_irc> <> cortex-m-rt is also "technically unsound" in the same way svd2rust pacs are
<re_irc> <> yeah.. but it's again stuff that the compiler doesn't know about
<re_irc> <> the linker script places the reset vector
<re_irc> <> you could have two runtimes each providing a reset vector with different symbol names so that they don't clash
<re_irc> <> so it links and produces a "broken frankenstein binary" that would definitely cause UB
<re_irc> <> so again "sound in isolation, unsound when mixed"
<re_irc> <> Doesn't the linker need to choose which reset vector to actually use?
<re_irc> <> the linker doesn't even know what a reset vector is
<re_irc> <> The linker script I guess
<re_irc> <> that's "place everything in the .reset_vector section here"
<re_irc> <> cortex-m-rt names the symbol `__RESET_VECTOR`, evil-rt could name it `__EVIL_RESET_VECTOR` and it'd all link fine
<re_irc> <> That means that whatever gets put in that section first is the real reset vector, right?
<re_irc> <> yeah
<re_irc> <> but the user could then use `evil-rt` to get a dupe singleton
<re_irc> <> But only the first reset vector runs, right?
<re_irc> <> `evil-rt` could have a `Peripherals::take()`. No need for `evil-rt`'s main to run. It's sound in isolation!
<re_irc> <> Only unsound when combined with `cortex-m-rt` which would do the `fn main(singleton: Singleton) -> !` thing
<re_irc> <> Man, this stuff is difficult to get right. On the one hand you want to use ownership to avoid unsafe everywhere and on the other hand you want to be able to share access to the peripherals.
<re_irc> <> I don't think you can fix both, you can only choose. Unless there's a third option?
<re_irc> <> I think it's impossible ðŸĪĢ
<re_irc> <> Yeah
<re_irc> <> best you can do is "conventions" like svd2rust's `#[no_mangle] static mut DEVICE_PERIPHERALS: bool`
<re_irc> <> and hire the "Soundness Police" to shoot anyone that doesn't follow the convention
<re_irc> <> cortex-m-rt could unsafely take the peripherals in the reset vector
<re_irc> <> cortex-m-rt wouldn't know anything about evil-rt
<re_irc> <> But your evil crate could unsafely take them not in the reset vector
<re_irc> <> And if you agree a convention "only take them in the reset vector" that everyone agrees to follow.... you end up where we are today
<re_irc> <> yeah the convention is "reset vector symbol must be __RESET_VECTOR" then ðŸĪ·
<re_irc> <> If you want to be annoying perhaps HALs should make their constructors unsafe with the precondition that no other code in your program accesses the peripheral
<re_irc> <> actually chiptool PACs are "fine" because all register access is unsafe. It's `embassy` that should be jailed by the Soundness Police :D
<re_irc> <> But that's annoying, so...
<re_irc> <> adamgreig: I'm starting to think this might be the best idea
<re_irc> <> That would make so much code unsafe though...
<re_irc> <> IMO "if you use only one HAL you're fine, if you mix then you have to manually make sure to not use the same peripheral with both" is fine
dcz_ has quit [Ping timeout: 240 seconds]
<re_irc> <> It's kind of pedantic and a bit unhelpful but Technically Maybe Accurate?
<re_irc> <> How sound are other big crates when you import multiple? Like Tokio? Can those have problems?
<re_irc> <> I'm sure you can construct similar examples about rust's `std`, with stuff like pthreads or unix signals
<re_irc> <> They don't really have to address the same issues with hardware singletons
<re_irc> <> they're fine because there's no "global context" they have to deal with
<re_irc> <> you can get tokio+async-std polling different sockets from different threads fine
<re_irc> <> Well then in theory you could make the normal 'take' unsafe with the precaution that you may not also call 'evil_take'
<re_irc> <> Admittedly the thing we do atm with the owned singletons is pretty much a convenient falsehood
<re_irc> <> because you get a comfy OS that allows you to multiplex the "singleton" hardware you have into multiple sockets in the first place ðŸĪ·
<re_irc> <> It may or may not be "fine", it is definitely unsound 😜
<re_irc> <> assuming your debatable axiom yes ðŸĪŠ
<re_irc> <> well
<re_irc> <> fwiw I think the axiom is correct
<re_irc> <> it's just that it's "convenient" to reject, otherwise you can't have safe apis at all
<re_irc> <> Admittedly, not allowing any use of hardware peripherals would make rust for embedded much safer
<re_irc> <> just run pure, side-effect-free code in the isolated ideal world of the cortex-m core
<re_irc> <> The compiler can probably optimise it all awa--- I mean, make it really fast
<re_irc> <> HAHAHA
<re_irc> <> it also helps tremendously with the chip shortage
<re_irc> <> swap out your mcu with a brick
<re_irc> <> those aren't in shortage
<re_irc> <> Hah, get some of those soldering practice packages
<re_irc> <> Just need to pr support to probe-rs
<re_irc> <> `NoopProbe`
<re_irc> <> adamgreig: You mean in an interrupt vector, or in something called from `main`?
<re_irc> <> even if *your* runtime takes the peripherals at reset, you can't force evil-rt to do so
<re_irc> <> without the Soundness Police (aka conventions)
<re_irc> <> I don't think you can make a safe API if you need to worry about that. Any fixed address can just be pointed to in evil code. There's no solution except making everything unsafe
<re_irc> <> But that is `unsafe`, right?
<re_irc> <> evil-rt can assume they're the only runtime in the world, and make that API safe. Just as your runtime does
<re_irc> <> because that access *is* safe if only one runtime is doing it
<re_irc> <> Well, not if you don't want to
<re_irc> <> ```rust
<re_irc> <> unsafe { &*GPIO_PTR }
<re_irc> <> fn evil_safe_gpio() -> &GPIO {
<re_irc> <> }
<re_irc> <> good-rt assumes that it has the only reset vector in the world
<re_irc> <> If you do something dumb in your code, expect dumb things to happen
<re_irc> <> I think the nice thing about Rust's memory model is that it catches subtle things (Albeit this is more useful for the sort of errors that occur on the heap)
<re_irc> <> But in this case no one's doing anything dumb or unreasonable, it's just it becomes unsound when two are used at once
<re_irc> <> Yeah, this discussion is that evil code can do evil things
<re_irc> <> I think that the reset vector is the key to soundly providing singletons without requiring `unsafe` in user code.
<re_irc> <> Not unreasonable for someone to use two HALs or for each HAL to provide safe peripheral access
<re_irc> <> I do see your point yeah
<re_irc> <> adamgreig: I don't think it is possible for something to "become" unsound when you add something else that is "sound"
<re_irc> <> I guess it's something of a philosophical point and otherwise the HALs just have to require the user do something unsafe
<re_irc> <> But like, do you want the hall to just have `unsafe i_solemnly_swear_you_are_the_only_hal()` before allowing use?
<re_irc> <> adamgreig: Maybe, unless cortex-m-rt can do that for you
<re_irc> <> And everything after that is "on the user to ensure it's ok", the function has a safety precondition in the docs that says "only call me if I'm the only hal"
<re_irc> <> How could c-m-rt safely call that? It can't know it's calling the only HAL
<re_irc> <> I'm still working on that part, lol
<re_irc> <> Hmm, I guess what you're getting at is that program entry happens exactly once so can we turn that into additional "once" properties
<re_irc> <> Exactly
<re_irc> <> It's not entirely clear if that should be a c-m-rt responsibility or how you'd define such a convention that everyone uses but maybe it's possible...
<re_irc> <> shifting it to CMRT is shifting the problem, not solving it
<re_irc> <> someone could write another runtime
<re_irc> <> Make a dep and feature for every PAC out there and select based on that ðŸĪĢ
<re_irc> <> for example I'm sure hubris userland doesn't use CMRT
<re_irc> <> you don't want HALs to require CMRT
<re_irc> <> I think hubris kernel does, but I guess userland doesn't need a runtime at all
<re_irc> <> Sure, it would mean the user has to call the unsafe function instead
<re_irc> <> But this has nothing to do with the hals, right? Just the PACs I thought
<re_irc> <> If svd2rust removes the owned singletons, then that responsibility shifts to the hals
<re_irc> <> Ah ok, right
<re_irc> <> I'm currently getting build errors in signal-hook-0.3.11 while installing probe-run on Windows, can someone with a windows box verify? (Works fine on Ubuntu 20.04)
<re_irc> <> but again, that unsafe function is a "convention"
<re_irc> <> not sure how it improves vs the current `#[no_mangle] static mut DEVICE_PERIPHERALS: bool` convention
<re_irc> <> well, the idea is that the HALs should/could require the user to call some unsafe function that has a documented precondition that they're not using another HAL, before providing safe access to peripherals
<re_irc> <> They could both depend on a crate which just defines a singleton type
<re_irc> <> because then it's the user's fault instead of the HALs if two are used at once
<re_irc> <> if we want PACs with no owned singletons, we'd just move the `DEVICE_PERIPHERALS` to the HAL
<re_irc> <> I don't really hold to this idea, just exploring the concept
<re_irc> <> with an `unsafe fn steal()` to bypass it
<re_irc> <> imo just having the HAL document that it's on you if you use it at the same time as another HAL for the same peripheral seems just as good, practically speaking
<re_irc> <> okay so
<re_irc> <> new convention:
<re_irc> <> - If enabled, they expose a safe `Peripherals::take()` func.
<re_irc> <> - HALs have a `peripherals-take` feature, enabled by default.
<re_irc> <> - They always expose an unsafe `Peripherals::steal()` func too.
<re_irc> <> `Peripherals::take()` uses `#[no_mangle] static mut DEVICE_PERIPHERALS: bool`, so linking fails if you try to use two hals with feature `peripherals-take`
<re_irc> <> is there any advantage to collecting all the peripherals together like that?
<re_irc> <> it makes it way harder to interop between HALs
<re_irc> <> ah, yea, if you have a static mut bool somewhere then it's convenient
<re_irc> <> to use two hals you have to set `default-features=false` on one, then `steal()`
<re_irc> <> then it's on you to ensure you don't make the HALs conflict
<re_irc> <> I guess the HALs can do whatever but personally I wouldn't miss the take() and steal() APIs or the every-peripheral-in-one API
<re_irc> <> and as a bonus, since `DEVICE_PERIPHERALS` is the same name, it ensures safety in the "PAC with owned singletons -> PAC without" transition
<re_irc> <> having a default feature that can be disabled and provides the safe API could be a nice convenience
<re_irc> <> (I have that in stm32ral for example)
<re_irc> <> the problem with PACs is you can't disable it, so you can't mix PACs *at all*
<re_irc> <> oh, yea, I still think nuke it from PACs
<re_irc> <> but HALs don't even need to _set_ this variable
<re_irc> <> just only include it if the magic feature is enabled
<re_irc> <> it'l cause a link error regardless of setting it
<re_irc> <> yeah
<re_irc> <> well, presumably the HAL will have a `Peripherals::take()` or something similar
<re_irc> <> hm, though I guess you still need to track how many times you've created a peripheral, yea
<re_irc> <> kinda boo for still having to have a mega Peripherals struct and static 'taken' bool though
<re_irc> <> sucks to have a bool for every peripheral too of course
<re_irc> <> yeah it wastes RAM
<re_irc> <> yea
<re_irc> <> and also every HAL would have to agree on symbol names for every peripheral
<re_irc> <> or worse, you'd need a Cargo feature for each peripheral
<re_irc> <> no
<re_irc> <> adamgreig: Alternative is everything unsafe, but I'm not sure that's better
<re_irc> <> bad
<re_irc> <> well they can still coordinate via a single shared ZST name
<re_irc> <> `fn take('&'a mut Singleton) -> Self<'a>`
<re_irc> <> shame the cargo links key can't be enabled by a feature
<re_irc> <> hmm....
<re_irc> <> I guess we could have a magic crate that does set links
<re_irc> <> and HALs add a dependency to it if the safe-access feature is enabled
<re_irc> <> hmmmmmm
<re_irc> <> no, I guess that won't work, lol
<re_irc> <> yeah that's bugged in today's cargo
<re_irc> <> or it'd still build because there's still only one copy of the "magic" crate
<re_irc> <> each HAL would need it's own magic crate
<re_irc> <> yea, sigh, nevermind
<re_irc> <> Huh, when I open my RTIC project in vim with rust-analyzer, this is what is shown initially 🙃
<re_irc> <> horrifying
<re_irc> <> mine... does not do that lol
<re_irc> <> Btw, I don't think that it is possibly to soundly use multiple independant HALs without requiring `unsafe`
<re_irc> <> Might be because it's an ARM project and rust-analyzer runs on the host?
<re_irc> <> but my vim also doesn't have your fancy inline errors lol
<re_irc> <> I have r-a running on my rtic firmware OK in vim... at least I think it's ok
<re_irc> <> adamgreig: if I re-open the project (:e) the error's gone.
<re_irc> <> Ah, but it's back once it re-analyzes 😕
<re_irc> <> But if one hal1 depended on hal2, it could create a peripheral driver from hal2 and give it to you
<re_irc> <> Danilo: if it gives you trouble, you can set `"rust-analyzer.experimental.procAttrMacros": false`. That makes it ignore the attr though, so it won't see the generated resource structs etc
<re_irc> <> dirbaio: thanks, that's useful.
<re_irc> <> This is the full error msg: `thread 'main' panicked at 'use-after-free in `proc_macro` handle', crates/proc_macro_srv/src/abis/abi_1_47/proc_macro/bridge/\nstack backtrace:\n note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n`
<re_irc> <> I'm using ale for r-a in vim and have not figured out how to set settings like that, ugh
<re_irc> <> I wonder how I can set that variable in LSP.
<re_irc> <> proc-macros in RA are super cursed
<re_irc> <> it's slowly getting better
<re_irc> <> but attr macros aren't quite there yet
<re_irc> <> adamgreig: do you use neovim as well? Here's my config:
<re_irc> <> Danilo: are you using rust nightly? check that it isn't too old
<re_irc> <> sometimes too old rustc makes RA explode in fun ways
<re_irc> <> no I'm too lazy/oldschool and just on regular vim
<re_irc> <> adamgreig: I switched once I noticed that LSP kinda works out-of-the-box in neovim, while it's a bit of a pain to set up in regular vim :)
<re_irc> <> you need to take the time to replace a few plugins, but in my opinion it's worth it.
<re_irc> <> my vimrc is almost old enough to vote, i'm not sure i'm ready for it lol
<re_irc> <> dirbaio: rust-analyzer is from the arch repos, so I assume it's fairly recent.
<re_irc> <> too old rust, not too old rust-analyzer
<re_irc> <> 1.54
<re_irc> <> LSP inside Ale was fairly OK to get going but it only supports some error checking not all the clever refactoring and completions etc
<re_irc> <> (in the project, using a `rust-toolchain` file. on the host, stable rust is the latest, I think 1.57)
<re_irc> <> maybe that's too old yep
<re_irc> <> I wanted to upgrade anyways, I'll give that a try.
<re_irc> <> it's from before RA added proc-macro-attr support
<re_irc> <> dirbaio: hah, that scary error is gone! now I get "Structure `read_measurement_resultsLocals` should have CamelCase name, e.g. `ReadMeasurementResultsLocals`" instead 😄
<re_irc> <> RA is nitpicky about the naming of types generated by a proc macro. that's... *very* pedantic.
<re_irc> <> but it's amazing that it works.
<re_irc> <> the macro should emit an #allow I guess
<re_irc> <> although I have to take that back a bit, autocompletion inside the RTIC app doesn't seem to work yet.
<re_irc> <> true
<re_irc> <> or you can add it yourself
<re_irc> <> Consider the following:
<re_irc> <> ```rust
<re_irc> <> impl Singleton {
<re_irc> <> struct Singleton;
<re_irc> <> A. Is is sound for cortex-m-rt to call `Singleton::new()` in the reset vector? I think that it is.
<re_irc> <> how can cortex-m-rt know that you won't call `new` elsewhere in your code?
<re_irc> <> it knows it hasn't happened _yet_ I guess
<re_irc> <> adamgreig: Because there is no way for your code to run *before* the reset vector (I think)
<re_irc> <> If *you* call new after the reset vector does, that's your problem
<re_irc> <> I guess the point is more that cortex-m-rt can't read the comments and understand the precondition
<re_irc> <> so it's down to the user to tell cortex-m-rt to call it...
<re_irc> <> at which point the user might as well call it?
<re_irc> <> how do you tell c-m-rt to call it, anyway?
<re_irc> <> and how do you get the result out of it?
<re_irc> <> I guess it could pass the result into main(), as some sort of 'argc, argv' deal?
<re_irc> <> adamgreig: yeah
<re_irc> <> conceptually you could give it the function as part of the `#[entry]` macro, and it gives you the result in the argument to main
<re_irc> <> but what's the benefit? you might as well call the function yourself?
<re_irc> <> Your main function would be `fn main(singleton: Singleton) -> !`
<re_irc> <> Now you have a singleton in your main function, and you didn't need to write any `unsafe` yourself
<re_irc> <> but now cortex-m-rt is unsound
<re_irc> <> it'l just run whatever unsafe function you tell it and give you the result
<re_irc> <> sure, in this case the precondition is "only call me once", but another unsafe function might have a totally different precondition, so you have to promise you're giving cortex-m-rt a function that's OK for it to call
<re_irc> <> and the only for cortex-m-rt to make you pinky promise it's OK is to also require unsafe?
<re_irc> <> adamgreig: You don't give it `Singleton::new()`, cortex-m-rt does that all by itself
<re_irc> <> but how do you tell it whose Singleton::new you'd like it to call?
<re_irc> <> oh, is Singleton more like a token here, which c-m-rt creates and owns?
<re_irc> <> cortex-m-rt depends on a singleton crate
<re_irc> <> and you pass ownership of the token into the HAL to "prove" it's unique?
<re_irc> <> like bare-metal's CriticalSection tokens
<re_irc> <> Yeah, that is part B
<re_irc> <> ```rust
<re_irc> <> impl Peripherals {
<re_irc> <> unsafe {
<re_irc> <> fn take(_: Singleton) -> Self {
<re_irc> <> so the HAL's take is like `Peripherals::take(Singleton)`
<re_irc> <> yea
<re_irc> <> kinda sucks that you only get one singleton token to give away
<re_irc> <> wonder how you handle cortex-m peripherals and HAL and device peripherals/HAL
<re_irc> <> right now both cortex-m and the PAC have a flag to say 'peripherals taken'
<re_irc> <> `fn main(core: cortex_m::Peripherals, singleton: Singleton) -> !`?
<re_irc> <> I'm not sure if that solves the whole problem though
<re_irc> <> what about multicore? 💀
<re_irc> <> `hal2::Peripherals::take` could take a `Singleton2`, and it is technically sound to call `Singleton2::new()` at the start of main. Now you could have peripherals from both hal1 and hal2 at the same time
<re_irc> <> corex-m-rt doesn't actually have to call `Singleton::new()` in order to call main, assuming it is a ZST, right?
<re_irc> <> I'm not sure if that helps or not
<re_irc> <> I am going to pretend I didn't hear you lol 😜
<re_irc> <> `fn main(stuff: Option<(cortex_m::Peripherals, Singleton)>) -> !` ??
<re_irc> <> Wait, is there only one set of `cortex_m::Peripherals`, or is there a different one for each core?
<re_irc> <> Or are some of the peripherals shared and some core-specific
<re_irc> <> Maybe it isn't the worst thing in the world to require a bit of `unsafe` in user code when there are multicore shenanigans involved