33 ms·
I work on the Linux KPTI/KAISER code (and work at Intel). The high-level description, along with the set of hardware things that get mapped into both kernel/ap
by hansendc 9y ago
I work on the Linux KPTI/KAISER code (and work at Intel).
The high-level description, along with the set of hardware things that get mapped into both kernel/app page tables are basically identical. Creating that list of things was painful, at least for me while I was getting KAISER working. If I were in their position I definitely would have leveraged the list of things that we found in the Linux work. I hope they were able to do that.
Some minor differences in the implementations:
In Linux, we allocate the two top-level page tables next to each other so we can just flip a bit to switch, and in the OpenBSD commit they seem to be allocating them separately and then storing the two pointers in a per-cpu data structure. Both are fine ways to do it.
I don't see anything like the Linux "espfix" mechanism. Guess there isn't one.
The BTS/PEBS buffers seem missing. This hardware may just not be supported.
- waynecochran 9y agoHaving separate page tables for user space vs kernel space seems like the right thing to do from the beginning -- I was surprised that they were shared. Could you elaborate on "we allocate the two top-level page tables next to each other so we can just flip a bit to switch"?
- blattimwind 9y agoOther architectures (like SPARC) have had split PTs for like, always. (And they're not optional, either)
- hansendc 9y agoSharing an address space is nice. Programs pass lots of pointers into the kernel (think read()/write()). For the kernel to get at that data, if the kernel and userspace share an address space you can just use the pointer. If userspace has a truly separate set of page tables, you have to do some relatively crazy (and slow) stuff to go and access the data from inside the kernel. It's much harder than just accessing a pointer. We can still do this with KPTI because despite having two page tables, the kernel still continues to map all of userspace. BTW, the bit flipping is pretty much // Allocate 8k which is also 8k aligned: pgd = alloc_pages(PAGE_SIZE*2); That allocates something which might go from (physical address) 0x12340000->12360000. The first top-level pagetable is at 0x12340000 (for the kernel) and the second is at 0x12341000 (for running userspace). So, when you leave the kernel you just set a bit in your CR3 register (well, you do it in assembly, but here it is logically in C): write_cr3(read_cr3() | 0x1000); // 0x12340000 -> 0x12341000 When you come back in to the kernel you clear the bit: write_cr3(read_cr3() & ~0x1000); // 0x12341000 -> 0x12340000
- deleted 9y ago[deleted]