[HN Gopher] Oxide on My Wrist: Hubris on PineTime was the best w... ___________________________________________________________________ Oxide on My Wrist: Hubris on PineTime was the best worst idea Author : todsacerdoti Score : 255 points Date : 2022-03-28 09:51 UTC (13 hours ago) (HTM) web link (artemis.sh) (TXT) w3m dump (artemis.sh) | dcow wrote: | Thank you for the LoFi tunes. I dig that stuff! | protoman3000 wrote: | The github repo of hubris [0] is very nice, as they immediately | tell you where what is, e.g. drv/ contains | drivers, a mix of simple driver lib crates and fully-fledged | server bin crates. Current convention is that drv/SYSTEM-DEVICE | is the driver for DEVICE on SYSTEM (where SYSTEM is usually an | SoC name), whereas drv/SYSTEM-DEVICE-server is the server bin | crate. | | Why does nobody do this in their readmes normally? They just let | you look into their code and tell you "now figure it all out | yourself". | | [0] https://github.com/faithanalog/hubris/tree/pinetime | Jerrrry wrote: | steveklabnik wrote: | In Rust, it's because most projects follow the default layout, | and so is less needed. | | We have a custom build system on top of Cargo, and so things | are a bit weird for a normal Rust project, and so it's extra | important. | JadeNB wrote: | > Why does nobody do this in their readmes normally? They just | let you look into their code and tell you "now figure it all | out yourself". | | I think it's worth praising this repo without knocking others. | Open source authors have no obligation to their users; if they | don't have the time to, or just don't care to, so organise | their READMEs, then they need not. In fact, if it's | sufficiently important, for much open-source software anyone | _else_ can do it, and submit a patch. | nerdponx wrote: | This isn't just about open source. Developers on internal | projects should do this too, but don't. | bluGill wrote: | Have you ever tried to write useful documentation? As a | programmer you are far to close to the code. You assume | things are obvious that are not, while going into great | detail describing things that are obvious (or maybe not | obvious, but only rarely interesting and so should be | documented in a deeper link not the main documentation). Or | worse because you have to document it you document the code | lines (++i; // increment i by one). | | This is a hard problem. I try to make an effort, but too | often I get it wrong. | hemogloben wrote: | I've never understood why github shows the first line of the | most recent commit for files / folders next to their name | instead of the first line of any README.md file inside the | folder. | | Even on projects that I'm actively working on, the most recent | commit of a folder gives me no useful information, whereas if I | could edit the README.md I could atleast add a description of | each folder so that new users could understand the directory | structure better. | athenot wrote: | Same thought; I would _love_ if there were a way to toggle | between "latest commit message" and "first line of | documentation for the file", depending on whether it's a | familiar project or a new one I'm browsing. | a9h74j wrote: | > Compare these two videos of writing a solid block of color to | the screen, first through the SPI task, and second with direct | SPI hardware access: | | I wonder if the performance difference could, in some | applications, create a preference for processors with enough SPI | ports to dedicate one per peripheral (no chip select required). | Not only no shared bus (as in I2C), but no shared SPI-task. | RantyDave wrote: | Zephyr can do MPU | https://docs.zephyrproject.org/latest/reference/usermode/mem... | ComputerGuru wrote: | Can anyone clue me in on the status of async/await in hubris? I | have some HAL code that both really needs and uses async (or | callbacks) to work and currently just use my own homebrew WFE/WFI | wakers (with a fixed, known _a priori_ number of tasks) but it | would be nice to switch to something more elegant and less | brittle. | | (Context: async/await-based per-task loop to facilitate | background LoRa send/receive while other tasks can continue to | operate (DMA, SPI, etc) independently, with the overall loop | shutting the primary Cortex core down when processing is | completed/while waiting for events/updates.) | | The last I checked, hubris was strictly synchronous and I didn't | get the sense that the interaction between tasks was | architectured in such a way that would facilitate low-power | designs for battery-powered devices. | iudqnolq wrote: | For others, embassy.dev are the main people working on embedded | async. | steveklabnik wrote: | We don't use async in hubris, so there is no async/await. | Hubris is 99.99999% synchronous. | | For more: | https://hubris.oxide.computer/reference/#_why_synchronous | | (Basically, this probably hasn't changed since you looked at | it, but for anyone else who hasn't seen it yet...) | | > shutting the primary Cortex core down | | We don't have mainline support for multicore systems, and | there's a big ? in there, design-wise. So yes, you are right to | recognize that that is the current state of things. | ComputerGuru wrote: | Hi Steve. Thanks for the confirmation - obviously a | synchronous design doesn't automatically/necessarily preclude | most high-level use cases that async can support - it just | requires an alternative approach and some careful | consideration. In fact, it could make it easier to do many | things like power management. | | Can you comment on this: others have asked here on HN before | but didn't seem to get an answer - does power | management/consumption factor in at all in the architectural | design (even if it's "this makes it possible to add power | management later") or is it strictly a non-goal? (I know your | _current_ particular application domains aren 't constrained | by battery capacity.) | | It would be easy enough to hack the kernel to always WFI/WFE | if all tasks are exited/completed, but I'm thinking about | cases where task(s) are still running but the supervisor | process is aware that they're all currently in a busy-waiting | state. But that wouldn't be sufficient (on its own) if the OS | requires certain peripherals to always remain powered up, | uses a high-frequency tick interrupt that will constantly | wake the device anyway, etc, etc. | wlkjlkeleg wrote: | gnicholas wrote: | Can anyone provide a comparison of PineTime and Pebble? My Time | Steel is aging and I'm trying to figure out if the PineTime would | be a workable replacement. | wanderer_ wrote: | The pinetime can basically do anything you want it to, as long | as you're willing to make it so. I'm wearing it on my wrist | right now, but I have an iPhone and the support for it is not | great. In terms of build quality, it's quite good, and the | battery lasts for about a week. It's slimmer than an apple | watch, which is a major plus for me. But if you have an iphone, | step tracking and limited music control is all you'll get in | terms of accessory use. You can always contribute, however, and | there is a very active community working on the firmware in the | github repo (https://github.com/InfiniTimeOrg/InfiniTime). | | The thing that the PineTime does really well, however, is beat | the price tag of basically every other smartwatch out there | ($30). I'm not sure how chip-shortage prices might be affecting | this though... | visy wrote: | Thanks for the shoutout on the twister :) | f0e4c2f7 wrote: | I love projects like this. I've considered getting a smartwatch. | Something like this makes the idea more appealing. Whats the most | hackable watch? Is there a pinephone of smartwatches? | nickspacek wrote: | It's not the most hackable, but there are some dedicated folks | hacking at the Amazfit watches. I have the original Bip, which | has a ridiculous battery life (30+ days easily) and GPS. The | GPS will run your battery down with extensive use, but if I'm | running a few times a week it'll still go 2 weeks. | | It isn't that powerful, and I wish it had a second physical | button. I haven't explored the mods very much because it does | what I need it to do, but the scene has the feel of the early | Xbox hacking scene, to me at least. | | There's this watch which appears to be heavily inspired from | the Amazfit Bip: | https://www.kickstarter.com/projects/gfw/banglejs-2-the-open... | ushakov wrote: | PineTime with wasp-os! | nsb1 wrote: | There is! And it's even featured in this article! | bitdivision wrote: | The article is about running Hubris on the PineTime. Quite | literally the Pinephone of watches. | | https://www.pine64.org/pinetime/ | zozbot234 wrote: | See Tock OS https://www.tockos.org/ for another Rust-based | embedded OS with a fairly comparable design to Hubris. The | debugging capabilities of Humility make an interesting comparison | to what's provided by cargo-embed | https://probe.rs/docs/tools/cargo-embed/ and the Knurling Tools | https://knurling.ferrous-systems.com/tools/ by Ferrous Systems. | | Ultimately, the embedded space (including all sorts of low-level, | retro, "bare-metal", remote etc. programming) has common needs | and it would be convenient to see more widespread cooperation | among these projects, improving reliability and avoiding wasteful | duplication of work. More resources at https://github.com/rust- | embedded/awesome-embedded-rust | randomskk wrote: | Under the hood, cargo-embed, knurling's probe-run, and Humility | are all built atop probe-rs (https://probe.rs/) to provide | debugging - I think in this case it's actually a great example | of cooperation between projects! Probe-rs has received PRs from | both Knurling and Oxide devs; it provides the common interface | to use various types of debug hardware and talk to various | types of microcontroller cores, essentially replacing OpenOCD. | panick21_ wrote: | People often have good reason to not adopt existing systems. | Oxide started with TockOS and have written and talked about why | they didn't end up using it. | | This twitter space goes into a lot of detail: | https://www.youtube.com/watch?v=cypmufnPfLw | | But at the end of the day, no_std will allow a bigger ecosystem | and sharing between many of these projects. | zozbot234 wrote: | Thing is, it's not even clear that their added elements are | all that sensible. If you're always running trusted tasks on | your embedded hardware, what do you need the MPU for? Even in | principle, it can only save you a bounds check. And if you | start running outside code, then the clear privilege | separation in Tock between trusted "Capsules" and other | "Tasks" starts looking plenty attractive. Even OP notes that | this MPU business introduces severe overhead. | panick21_ wrote: | That is just one of many reasons and not the main one. | Again, actually watch and listen to the associated | talks/blogs/docs and so on. | TickleSteve wrote: | Data-execution exploits mean that you may accidentally run | code you weren't expecting to. If you have any kind of | message parser taking input from an external system and | examining it, you may be vulnerable to these types of | exploits without realising it. | | Having the ability to mark (for example) your stack as non- | executable is a simple change that can remove a whole class | of problems. | | That is only the skimming the surface tho. | zozbot234 wrote: | Yes, this is a concern in memory-unsafe languages like C. | But Rust can build memory-safe primitives with only a | modest amount of runtime checking wrt. inherently unsafe | operations. | | (Of course, having better formal models of how 'unsafe' | code behaves might allow us to be a lot more rigorous in | building safe primitives, such as by endowing some | 'unsafe' calls with proof objects that might reify the | outcome of a bounds check.) | TickleSteve wrote: | Rust helps, but isnt immune (e.g. stack overflows). | | Also, when you're dealing with embedded code, you're very | likely going to be using unsafe code (e.g. driver level). | With no other protection, incorrectly programming a DMA | transfer to trample over code-space is not unknown... and | Rust cannot protect you from that. | | (Having said that... an MPU window will also not | necessarilly catch a bad DMA transfer either). | zozbot234 wrote: | > Rust helps, but isnt immune (e.g. stack overflows). | | This is a good point but isn't Hubris designed to use | statically bounded amounts of memory anyway, like much | embedded software? AIUI, this was a key reason for | keeping their design focused on synchronized requests, | avoiding the hard-to-predict buffering that's needed for | supporting 'async' models. | steveklabnik wrote: | Defense in depth matters. The blog post shows an example | of Hubris correctly killing a task that's touching memory | it's not supposed to. That "supposed to" was due to a | configuration error, but configuration errors can and do | happen, and maybe would not be as benign as this one was. | rcxdude wrote: | Defence in depth. Rust isn't completely immune to memory | safety bugs, due to the need for unsafe code underlying | many primitives in the language as well as soundness bugs | in the compiler, it just makes them much rarer. It's well | worth designing the system so it doesn't fall apart as | soon as one such bug appears. | bcantrill wrote: | Other folks have mentioned this, but it's important to | understand the limitations of Rust with respect to safety. | In particular: every stack operation is -- at some level -- | an unsafe operation as it operates without a bounds check. | This isn't Rust's fault per se; non-segmented architectures | don't have an architecturally defined way to know the stack | base. As a result, even an entirely safe Rust program can | make an illegal access to memory that results in fatal | program failure. That, of course, assumes memory | protection; if you don't have memory protection (or, like | many embedded operating systems, you don't make use of it), | stack overflows will plow into adjacent memory. | | But wait, it gets worse: stack overflows are often _not_ | due to infinite stack consumption (e.g., recursion) but | rather simply going deep on an unusual code path. If stack | consumption just goes slightly beyond the base of the stack | and there is no memory protection, this is corrupt-and-run | -- and you are left debugging a problem that looks every | bit like a gnarly data race in an unsafe programming | language. And this problem becomes especially acute when | memory is scarce: you really don 't want a tiny embedded | system to be dedicating a bunch of its memory to stack | space that will never ("never") be used, so you make the | stacks as tight as possible -- making stack overflows in | fact much more likely. | | Indeed, even _with_ the MPU, these problems were acute in | the development of Hubris: we originally put the stack at | the top of a task 's data space, and its data at the bottom | -- and we found that tasks that only slightly exceeded | their stack (rather than running all of the way through its | data and into the protection boundary) were corrupting | themselves with difficult-to-debug failures. We flipped the | order to assure that every stack overflow hit the | protection boundary[0], which required us to be much more | intentional about the stack versus data split -- but had | the added benefit of allowing us to add debugging support | for it.[1] | | Stack overflows are still pesky (and still a leading cause | of task death!), but without the MPU, each one of these | stack overflows would be data corruption -- answering for | us viscerally what we "need the MPU for." | | [0] https://github.com/oxidecomputer/hubris/commit/d75e8329 | 31f67... | | [1] https://github.com/oxidecomputer/humility#humility- | stackmarg... | ctz wrote: | > non-segmented architectures don't have an | architecturally defined way to know the stack base | | ARMv8-M does have stack limit registers, which do | precisely this. Being a much simpler mechanism than the | MPU, they are quicker to switch than the entire MPU state | when switching tasks. | bcantrill wrote: | Yes, true -- it's more accurate to say "architectures | traditionally don't have a way to know the stack base." | Certainly, having an architecturally-defined way to know | the base of the stack is/would be really really helpful, | and would allow stack overflow to be at once less | dangerous and much more debuggable! | zozbot234 wrote: | > This isn't Rust's fault per se; non-segmented | architectures don't have an architecturally defined way | to know the stack base. | | Bounding stack usage is of course a whole-program | concern, but that ought to be feasible when building for | embedded, where external "plugin" components are unlikely | and there's no inherent need for true separate | compilation. (Arguably, in such cases even the need for | an actual "stack" structure is actually quite limited; a | smarter compiler might well replace many uses of the | activation stack with references to static data, | reserving it for cases where e.g. reentrancy is actively | needed. AIUI, there has been some work along those lines | for LLVM.) | bcantrill wrote: | But to get back to your original question: you can see | why the state of things today necessitates the use of the | MPU, even for Rust? | bluGill wrote: | The real question is what is the correct risk tolerance, | there are many degrees in here with trade offs. If I mostly | trust the other programmers then I'm just concerned about | mistakes. If I'm running code that might have been written | by some evil cracker trying to do some evil then I need | more protection. | smbv wrote: | https://archive.ph/E8rQv | mkesper wrote: | Cool, almost the same chip is used in the microbit v2. | https://support.microbit.org/support/solutions/articles/1900... ___________________________________________________________________ (page generated 2022-03-28 23:01 UTC)