274 karma · joined May 2, 2021
On Github: https://github.com/eigenform
On Twitter: https://twitter.com/eigenform
On Mastodon: @eigenform@treehouse.systems
On Bluesky: @reflexive.space
If this were the case, you could perform SYSCALL in the shadow of a mispredicted branch, and then try to use it to leak data from privileged code.
When the machine encounters an instruction that changes privilege level, you need to validate that you're on a correct path before you start scheduling and executing instructions from another context. Otherwise, you might be creating a situation where instructions in userspace can speculatively influence instructions in the kernel (among probably many other things).
That's why you typically make things like this drain the pipeline - once all younger instructions have retired, you know that you're on a correct [not-predicted] path through the program.
edit: Also, here's a recent example[^1] of how tricky these things can be (where SYSCALL isn't even serializing enough to prevent effects in one privilege level from propagating to another)
[^1]: https://comsec.ethz.ch/wp-content/files/bprc_sec25.pdf
https://github.com/eigenform/perfect/blob/e5da0c693ba5d1b654...
.. and here's another example in the case of EntryBleed:
https://github.com/eigenform/perfect/blob/e5da0c693ba5d1b654...
Remember that Spectre V1 is about causing the kernel to [incorrectly and] speculatively perform a load, and then trying to leak the loaded value by measuring the state of the cache. You might reasonably want to try this since MTE tags are stored in kernel memory.
But if the set of all possible target addresses for relevant loads on a path subject to influence by userspace can be constrained to a particular memory region, you [presumably] cannot trivially use Spectre V1 to leak values from a different region.
Also, see this[^2] paper referenced in the article.
[^1]: https://mastodon.online/@ezhes_/115175838087995856
[^2]: https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=983...
(But then again, do the AMD e-cores have uop caches?)
Yeah, you [ideally] want to predict the existence of taken branches or jumps in a cache line! Otherwise you have cycles where you're inserting bubbles into the pipeline (if you aren't correctly predicting that the next-fetched line is just the next sequential one ..)
AFAICT if you're hinting that a branch is biased-taken, really the only thing you might be doing is avoiding potential latency/incorrect speculation that comes with an initial misprediction (when you discover a branch that isn't currently being tracked). I think it's basically just an injunction to "don't wait for a misprediction, just install this branch in your BTB immediately" (or something along those lines).
But the parent comment is talking about "hinting" for branches where the compiler cannot compute this ahead of time, and the CPU is responsible for resolving it during runtime. This is usually exposed by the ISA, ie. a bit in the branch instruction encoding that tells the machine "when you encounter this instruction for the first time, the default prediction should be 'taken'."
In practice, branches are usually predicted "not-taken" by default:
- It's advantageous to assume that control-flow is sequential because [pre-]fetching sequentially is the easy case
- It's wasteful to track the target addresses of branches in your predictor if they aren't taken at least once!
It doesn't change the fact that when you implement a RISC-V core, you're going to have to partition/tag/track resources for threads that you want to be separated. Or, if you're keeping around shared state, you're going to be doing things like "flush all caches and predictors on every context switch" (can't tell if thats more or less painful).
Anyway, that all still seems expensive and hard regardless of whether or not the ISA exposes it to you :(
I think of Amaranth as "a way of using Python to organize/generate/simulate RTL." Being embedded in Python is part of the utility behind it!
- Predictor updates may be deferred until sometime after a branch retires. Makes sense, otherwise I guess you'd expect that branches would take longer to retire!
- Dispatch-serializing instructions don't stall the pipeline for pending updates to predictor state. Also makes sense, considering you've already made a distinction between "committing the result of the branch instruction" and "committing the result of the prediction".
- Privilege-changing instructions don't stall the pipeline for pending updates either. Also makes sense, but only if you can guarantee that the privilege level is consistent between making/committing a prediction. Otherwise, you might be creating a situation where predictions generated by code in one privilege level may be committed to state used in a different one?
Maybe this is hard because "current privilege level" is not a single unambiguous thing in the pipeline?
> Here we present a full-waveform seismic tomographic model
So presumably, you would actually do the seismic tomography (if they haven't already). Instead of radar, you use the waves from earthquakes!
Don't know about the format, but if you look thru old ITJ articles[^1], it seems like the "direct access" interface for reading out different memories exists on older Pentium parts too. Presumably, if it were possible to dump over JTAG, it would be at least a little bit similar to what Peter/Mark have already looked at on newer parts.
[^1: https://www.intel.com/content/dam/www/public/us/en/documents...
- Collect bits from many "points" in space, but a single "point" in time
- Collect bits from a single "point" in space, but many "points" in time
In either case, you are not eliminating the possibility that your "random" bits are subject to external influence, you're just moving it into some different domain.
I think you are the one who hasn't read documentation or tested the behavior of Zen cores. Read literally any AMD material about Zen4: it mentions that the AVX512 implementation is done over two cycles because there are 256-bit datapaths.
On page 34 of the Zen4 Software Optimization Guide[^1], it literally says:
> Because the data paths are 256 bits wide, the scheduler uses two consecutive cycles to issue a 512-bit operation.
[^1]: https://www.amd.com/content/dam/amd/en/documents/processor-t...
- Capturing 2x512b from the L1D cache
- Sending 2x512b to the vector register file
- Capturing 4x512b values from the vector register file
- Actually multiplying 4x512b values
- Sending 2x512b results to the vector register file
.. and probably more?? That's already like 14*512 wires [switching constantly at 5Ghz!!], and there are probably even more intermediate stages?
[^1]: https://www.emsc-csem.org/Files/event/1765158/20250213b-sant...
When you have a machine that can only infer rules for reasoning from inputs [which are, more often than not, encoded in a very roundabout way within a language which is very ambiguous, like English], you have necessarily created something without "ground."
That's obviously useful in certain situations (especially if you don't know the rules in some domain!), but it's categorically not capable of the same correctness guarantees as a machine that actually embodies a certain set of rules and is necessarily constrained by them.
> Minimum MilanPI_1.0.0.F is required to allow for hot-loading future microcode versions higher than those listed in the PI.
Now that runtime loading of microcode patches cannot be implicitly trusted, the machine should not attempt to prove AMD's authorship of the newly-loaded patch without a concrete guarantee that the current microcode patch is trustworthy.
Presumably (load-bearing italics), the contents of an AGESA release (which contains the patch applied by your BIOS at boot-time) can be verified in a different way that isn't broken.
[^1]: https://www.amd.com/en/resources/product-security/bulletin/a...
I think you're making a good point about immediate encodings probably making ARM code more amenable to LVP, but I'm not sure I totally buy this statement.
If you take some random x86 program, chances are there are still many loads that are very very predictable. There's a very recent ISCA'24 paper[^1] about this (which also happens to be half-attributed to authors from Intel PARL!):
> [...] we first study the static load instructions that repeatedly fetch the same value from the same load address across the entire workload trace. We call such a load global-stable.
> [..] We make two key observations. First, 34.2% of all dynamic loads are global-stable. Second, the fraction of global-stable loads are much higher in Client, Enterprise, and Server work-loads as compared to SPEC CPU 2017 workloads.
Otherwise, there are known examples of related-but-less-aggressive optimizations for resolving loads early. I'm pretty sure both AMD[^1] and Intel[^2] have had predictive store-to-load forwarding.
edit: Just noticed the FLOP paper also has a nice footnote about distinguishing LVP from forwarding during testing (ie. you want to drain your store queue)!
[^1]: https://www.amd.com/content/dam/amd/en/documents/processor-t...
[^2]: https://www.intel.com/content/www/us/en/developer/articles/t...