ChanServ changed the topic of #rust-embedded to: Welcome to the Rust Embedded IRC channel! Bridged to #rust-embedded:matrix.org and logged at https://libera.irclog.whitequark.org/rust-embedded, code of conduct at https://www.rust-lang.org/conduct.html
causal has quit [Quit: WeeChat 3.6]
emerent_ has joined #rust-embedded
emerent is now known as Guest3030
Guest3030 has quit [Killed (tungsten.libera.chat (Nickname regained by services))]
emerent_ is now known as emerent
<re_irc> <explodingwaffle101> Trevor Gross: did an rfc get made for this “storage” api?
<re_irc> <explodingwaffle101> nevermind, just read that issue you linked a bit closer
<re_irc> <jannic> Whats the current state of the art regarding concurrent volatile reads and writes to MCU registers?
<re_irc> The documentation of "core::ptr::read_volatile" (https://doc.rust-lang.org/core/ptr/fn.read_volatile.html) is very restrictive: "In particular, a race between a read_volatile and any write operation to the same location is undefined behavior."
<re_irc> However, in practice, volatile reads/writes are atomic (at least in the limited sample of MCUs I know about), so any read access will provide a value which was valid at some point in time. And for volatile reads, the compiler can't assume that the value won't change "magically" between two reads - that's the point of volatile accesses.
<re_irc> Do we interpret the documentation of "read_volatile" as just specify the lowest common denominator? So if you write code without knowledge of the hardware (eg. code which should be portable), it's all you can assume, but if you know the target hardware, you are allowed to use that knowledge and break the rule, without automatically triggering UB from the compiler?
<re_irc> (Any pointers to documentation / blog posts / tickets ... discussing this topic are welcome!)
<re_irc> <jannic> * specifying
<re_irc> <GrantM11235> I think that in practice, an 8/16/32 bit read or write on a 32bit arm system will always happen atomically, but I don't think that is technically guaranteed
<re_irc> <GrantM11235> Is there even a guarantee that a 32 bit volatile read/write won't be split up in to four 8 bit operations?
<re_irc> <jannic> I think it must be guaranteed, otherwise some things would just not work. Eg. on the rp2040, register writes are always 32 bit. If you do an 8 bit write from the CPU, the bus will still see a 32 bit write, overwriting the other 24 bits.
<re_irc> <GrantM11235> wait, some 32 bit arm systems have 16 bit memory buses. I'm not sure how that works
<re_irc> <jannic> Yes, it very much depends on the hardware. It's probably not enough to know that it's an ARM processor, or even a specific type of core. You also need to consider the data bus fabric.
<re_irc> <GrantM11235> jannic: It definitely works in practice because there is no reason for a compiler to split up the operation (other than to be mean) but that doesn't mean it is guaranteed
<re_irc> <9names (@9names:matrix.org)> hmm. what does memory mapped IO do when multiple masters try to write simultaneously? i assume there would _have_ to be some sort of contention mechanism.
<re_irc> <GrantM11235> you can "write_volatile" a "*mut [u8; 100]", but it obviously won't be atomic
<re_irc> <GrantM11235> I think we need volatile atomics in general
<re_irc> <9names (@9names:matrix.org)> i guess it's hardware implementation defined? the rp2040 manual has a few specific examples:
<re_irc> If core 0 and core 1 both write to GPIO_OE simultaneously (or to a
<re_irc> SET/CLR/XOR alias),
<re_irc> the result is as though the write from core 0 took place first,
<re_irc> and the write from core 1 was then applied to that intermediate result.
<re_irc> <GrantM11235> for example, those compiler fences around dma operations aren't guaranteed to do anything in the absence of atomic ops. I believe that currently llvm considers volatile ops to "count" for that, but it's not guaranteed
<re_irc> <9names (@9names:matrix.org)> you can still insert a barrier in the absence of atomic ops
<re_irc> > [...] That creates synchronizes-with relationships between it and atomic operations or fences in other threads.
<re_irc> <GrantM11235> According to m-ou-se, that means
<re_irc> > They do have an effect, but not in a program without any atomic operations.
Socke has quit [Quit: WeeChat 3.6]
<re_irc> <jannic> "That creates synchronizes-with relationships between it and atomic operations *or fences in other threads*" sounds like it should work without additional atomic ops.
<re_irc> <jannic> 9names: For the rp2040 it's all well documented in the data sheet. Not only which operation "wins". If you really need to know the priority, you have to consider the specific location you are accessing, follow the path through the bus fabric, and look up which arbiters are involved and how they work.
<re_irc> For a single arbiter, there are rules like "When there are multiple simultaneous accesses to same arbiter, any requests from high-priority masters (priority level
<re_irc> 1. will be considered before any requests from low-priority masters (priority 0). If multiple masters of the same priority level attempt to access the same slave simultaneously, a round-robin tie break is applied, i.e. the arbiter grants access to each master in turn."
<re_irc> Sure, the details get complicated. In any case, there should be some defined behavior, so there should not be any UB from the hardware.
<re_irc> <jannic> For the rp2040 it's all well documented in the data sheet. Not only which operation "wins". If you really need to know the priority, you have to consider the specific location you are accessing, follow the path through the bus fabric, and look up which arbiters are involved and how they work.
<re_irc> For a single arbiter, there are rules like "When there are multiple simultaneous accesses to same arbiter, any requests from high-priority masters (priority level 1) will be considered before any requests from low-priority masters (priority 0). If multiple masters of the same priority level attempt to access the same slave simultaneously, a round-robin tie break is applied, i.e. the arbiter grants access to each master in turn."
<re_irc> Sure, the details get complicated. In any case, there should be some defined behavior, so there should not be any UB from the hardware.
<re_irc> Is this enough to be sure that "concurrent volatile reads and writes to a register *on this hardware* are fine"? Or is there some reason to assume that the compiler might still break it?
<re_irc> Splitting up 32 bit operations into smaller ones would be one possibility, but I think that can be ruled out for this question, as it would break on a more fundamental level, even if there is no concurrency involved.
<re_irc> <jannic> This discussion is very relevant: https://github.com/rust-lang/unsafe-code-guidelines/issues/152
Socke has joined #rust-embedded
Socke has quit [Quit: WeeChat 3.6]
Socke has joined #rust-embedded
bjc has quit [Remote host closed the connection]
<re_irc> <Chris [pwnOrbitals]> Hey everyone, currently working on a cortex-m executable. One of my static variable from some external C code I’m using isn’t getting initialized to its specified value (0xaaaaaaaa) but to 0xffffffff instead, any idea why ? To get around this, I’m trying to initialize it myself, but using "extern "C" {static mut uxCriticalNesting : [type];}" fails to link to the variable :/ any help appreciated, thanks...
<re_irc> ... <3
<re_irc> <newam> Where is that variable in your ELF?
<re_irc> <newam> 0xFFFF_FFFF sounds like a reset value - I'm wondering if the initial value is getting loaded correctly
<re_irc> <Chris [pwnOrbitals]> at 0x240004c0 => in .data, which goes from 0x24000000 to 0x24000000 in my case
<re_irc> <James Munns> Also, I always recommend looking at "arm-none-eabi-nm -nSC $ELF"
<re_irc> <Chris [pwnOrbitals]> +variable is
<re_irc> <Chris [pwnOrbitals]> * 0x240004c8
<re_irc> <James Munns> you can see where variables end up, and if they end up where expected
<re_irc> <James Munns> (or if they got removed)
<re_irc> <Chris [pwnOrbitals]> newam: yeah, tracing through GDB looks like it’s not being initialized to "0xaaaaaaaa" ever
<re_irc> <James Munns> wait
<re_irc> <James Munns> you might want to make sure your rust and c have a common section for .data/.rodata
<re_irc> <James Munns> and that whoever is driving the "initialization", rust or C, is doing the job for both
<re_irc> <James Munns> .data symbols get filled in at r0 time, if they use different linker symbols for start/end of section, you might be "missing" some.
<re_irc> <James Munns> again - nm will show you all the static variables, and linker _srodata/_erodata/etc flags that get used by rust's r0
<re_irc> <newam> Also silly question, that variable _is_ in the portable layer, you're compiling the right portable layer? (I have done this one myself 😅)
<re_irc> <James Munns> Chris [pwnOrbitals] if you dump the output of "nm -nSC" to a gist, I can take a peek :)
<re_irc> <Chris [pwnOrbitals]> newam: yes, board is STM32H743BIT6 so CM7 R0P1 is correct I believe
<re_irc> <Chris [pwnOrbitals]> +James Munns
<re_irc> <Chris [pwnOrbitals]> * Munns, thanks a lot
<re_irc> <James Munns> (looking...)
<re_irc> <James Munns> Yup, I see it in "data":
<re_irc> 240004bc 00000004 d csp_rdp_window_size
<re_irc> 240004c0 00000004 d uxCriticalNesting
<re_irc> 240004c8 D __edata
<re_irc> 240004c4 00000004 D uxTopUsedPriority
<re_irc> <James Munns> Hmm, I don't see any symbols in __sidata (this is where .data symbols live), let me look if that's the same in my projects
<re_irc> <James Munns> hmm, nope, my all-rust projects also don't contain that
<re_irc> <James Munns> It _might_ be worth using objcopy to create a .bin file of your elf
<re_irc> <James Munns> Then look with a hex editor around the start addr of __sidata
<re_irc> <Chris [pwnOrbitals]> James Munns: what would I be looking for ?
<re_irc> 83956
<re_irc> <James Munns> >>> 0x080747f4 - 0x08060000
<re_irc> <Chris [pwnOrbitals]> also what do you think of the workaround of initializing it myself ? It would work in my case if I managed to link to it
<re_irc> <James Munns> so, 83956 bytes in or so, you should see 0xAAAAAAAA
<re_irc> <James Munns> Well, more bytes than that, since uxCriticalNesting is the second to last variable in ".data"
<re_irc> <James Munns> >>> 0x4c0
<re_irc> 1216
<re_irc> >>> _ + 83956
<re_irc> 85172
<re_irc> <James Munns> As a workaround - it might be okay? But honestly, this smells like "something wrong with the linker script or compiler flags"
<re_irc> <James Munns> so you'd _probably_ be better served figuring out what's up with that, rather than playing whack-a-mole on symptoms, if that makes sense
<re_irc> <James Munns> >>> 0x14CB0
<re_irc> 85168
<re_irc> <James Munns> so yeah, looks right
<re_irc> <James Munns> is Rust doing your "r0"? or is C?
<re_irc> <Chris [pwnOrbitals]> Rust
<re_irc> <Chris [pwnOrbitals]> I believe
<re_irc> <James Munns> Okay, I'd probably start the code with GDB, set a breakpoint in r0::init_data (https://docs.rs/r0/latest/src/r0/lib.rs.html#127-136), and see if all the variables look right
<re_irc> <Chris [pwnOrbitals]> this is supposed to be done by "cortex_m_rt", right ?
<re_irc> <Chris [pwnOrbitals]> I’ve never heard of "r0" before tbh
<re_irc> <James Munns> REALLY off the wall idea that might be worth checking, but it's not my first guess: Make sure you have the right number of flash wait states for your CPU speed
<re_irc> <James Munns> r0 is what does the "memory init", it's called before main by cortex-m-rt
<re_irc> <James Munns> re: flash wait states: you might get "wrong" values from flash if you are cranked too high in CPU speed for the number of wait states you need - but if this is in init code, it's probably before you turn up the CPU speeds anyway?
<re_irc> <Chris [pwnOrbitals]> James Munns: yeah, r0 would happen before clock configuration
<re_irc> <James Munns> (this is important - because you are using flash to init RAM)
<re_irc> <Chris [pwnOrbitals]> actually NO !
<re_irc> <James Munns> !
<re_irc> <Chris [pwnOrbitals]> r0 would happen at full CPU speed
<re_irc> <Chris [pwnOrbitals]> cuz my app is started by a bootloader
<re_irc> <James Munns> Ah!
<re_irc> <Chris [pwnOrbitals]> which turns up the clocks before
<re_irc> <James Munns> Is your bootloader not setting the correct number of flash wait states?
<re_irc> <Chris [pwnOrbitals]> probably not indeed
<re_irc> <James Munns> If it's the HAL, I _think_ it handles that, but not sure what bootloader you are using.
<re_irc> <James Munns> Might be worth checking :)
<re_irc> <Chris [pwnOrbitals]> well, I wrote the bootloader, but it uses the HAL facilities to set the clocks
<re_irc> <Chris [pwnOrbitals]> ("stm32h7xx_hal")
<re_irc> <adamgreig> (fwiw we don't use the r0 crate any more, though c-m-rt still does static initialisation)
<re_irc> <James Munns> ah, right
<re_irc> <James Munns> stale cache :)
<re_irc> <adamgreig> It's done in asm now to avoid ub
<re_irc> <adamgreig> Just making a &mut to every static apparently wasn't cool lol
<re_irc> <Chris [pwnOrbitals]> James Munns: any chance there’s a bug in there then ?
<re_irc> <James Munns> I thought of this way later, but I wonder if just making those "*mut" instead of "&mut" would have fixed the UB.
<re_irc> <James Munns> Chris [pwnOrbitals]: That's beyond my knowledge :D
<re_irc> <James Munns> The easy way to test would be to have your bootloader NOT crank up the clocks and see what happens
<re_irc> <James Munns> if the variable DOES get initialized correctly - then yes, there is probably some error in the wait state calculations (or you have the wrong HAL feature flags?)
<re_irc> <adamgreig> If you can attach a debugger I'd set a watchpoint on the memory address while in reset and then run it
<re_irc> <adamgreig> See if it ever even tries to write it
<re_irc> <Chris [pwnOrbitals]> adamgreig: that’s what I did, didn’t see anything trying to write "0xaaaaaaaa"
<re_irc> <adamgreig> Did anything try to write at all?
<re_irc> <James Munns> (I gotta run, good luck!)
<re_irc> <Chris [pwnOrbitals]> thanks for the help !
<re_irc> <Chris [pwnOrbitals]> adamgreig: yes, It’s 0x00 at reset and is written 0xff by some init code
<re_irc> <adamgreig> Aah ok, can you try reading the address in flash where the init value is stored from the debugger?
<re_irc> <James Munns> or - check your bootloader and make sure things are being loaded from/to the right flash and ram addrs
<re_irc> <Chris [pwnOrbitals]> adamgreig: Not sure how to do this, as it’s initialized from some asm code I don’t understand
<re_irc> <Chris [pwnOrbitals]> here’s the code that initializes at Oxff
<re_irc> <Chris [pwnOrbitals]> * 0xff
<re_irc> <adamgreig> Itl be at __sidata+0x4c0 which should be in flash
<re_irc> <adamgreig> Some comments explaining the asm there
<re_irc> <Chris [pwnOrbitals]> (register values)
<re_irc> <Chris [pwnOrbitals]> so I guess the r2 value is the one we’re looking for here ?
<re_irc> <Chris [pwnOrbitals]> corresponds to the value I found previously, it’s 0x08060000 + 0x14CB0
<re_irc> <Chris [pwnOrbitals]> so I guess the r2 value is the one we’re looking for here ? 0x0874CB8
<re_irc> <adamgreig> r3 is what it read and is going to write to the static
<re_irc> <Chris [pwnOrbitals]> corresponds to the value I found previously, it’s 0x08060000 (base address) + 0x14CB0 (from bin) + 8 (variable size)
<re_irc> <Chris [pwnOrbitals]> corresponds to the value I found previously, it’s 0x08060000 (base address) + 0x14CB0 (pos of static in bin) + 8 (variable size)
<re_irc> <adamgreig> What if you try and read 8074cb0 yourself?
<re_irc> <Chris [pwnOrbitals]> "0xffffffff"
<re_irc> <Chris [pwnOrbitals]> +so it corresponds to r3
<re_irc> <adamgreig> How about that offset into the .bin?
<re_irc> <adamgreig> 0x14cb0 into the bin
<re_irc> <Chris [pwnOrbitals]> screenshot here ^
<re_irc> <jannic> Perhaps a bug in the flash algo? Looks like the binary ends at some odd offset which probably doesn't match a flash sector boundary. Perhaps the last (incomplete) flash sector doesn't get written?
<re_irc> <adamgreig> (or maybe try reading it from debugger while your code is otherwise running after init, or maybe from within the bootloader? where hopefully memory access is working on)
<re_irc> <adamgreig> jannic: Yea, maybe it's something like this, sure seems like the end of the file isn't being written or something...
<re_irc> <Chris [pwnOrbitals]> (also tried reading 0x14CB8 manually, also getting 0xff)
<re_irc> <adamgreig> Could try deleting some stuff from flash and see if having this static be lower down the bin suddenly makes it work...
<re_irc> <jannic> What's the last address before that, where you don't get 0xff?
<re_irc> <Chris [pwnOrbitals]> adamgreig: would be weird, checksums are fine when flashing.... hmm
<re_irc> <Chris [pwnOrbitals]> between 0x8074c10 and 0x8074c20
<re_irc> <Chris [pwnOrbitals]> jannic: exact address is 0x8074c1d, all before is 0x00, all after is 0xff, this value is 0xff000000
<re_irc> <jannic> LOL which also doesn't look like a flash boundary, so that theory doesn't hold.
<re_irc> <Chris [pwnOrbitals]> all of this is so weird
<re_irc> <James Munns> Maybe:
<re_irc> - Program the image with the bootloader
<re_irc> - Use the debugger to dump the entire flash
<re_irc> - Compare
<re_irc> <James Munns> you might find your bootloader isn't "flashing" completely correctly
<re_irc> <Chris [pwnOrbitals]> yep, houston we have a problem
<re_irc> <Chris [pwnOrbitals]> flash values are wrong
<re_irc> <Chris [pwnOrbitals]> until 0x14C20
<re_irc> <James Munns> It sucks there is a bug, but it's good that you found it :D
<re_irc> <James Munns> If that's the last "chunk", maybe you're ending early, OR rebooting before the write is totally complete?
<re_irc> <Chris [pwnOrbitals]> it’s the last chunk yeah
<re_irc> <James Munns> also might be a fun off by one error :p
<re_irc> <Chris [pwnOrbitals]> yeah that’s what I’m thinking of
rardiol has joined #rust-embedded
<re_irc> <Trevor Gross> What sort of setups do you all use to run some tests on the host and some on qemu? I'm hoping for something something like
<re_irc> mod tests {
<re_irc> #[test(qemu)]
<re_irc> fn test_xxx() {...}
rardiol has quit [Ping timeout: 250 seconds]
rardiol has joined #rust-embedded