How to enable x86 paging only in ring 3

I understand that setting the PG bit of CR0 enables paging in x86 and further all addresses generated will be logical and translated using page directories and tables. However I want that logical addresses be generated only for ring 3 and wish to keep all generated addresses in ring 0 as physical. Can this be achieved somehow? I had thought of setting the PG bit just before IRET. However I doubt that would help because IRET uses ESP to pop out CS, EIP, EFLAGS, SS, ESP etc. And if the PG bit is set, then ESP would point to a logical address and the command would fail, right?

1 answer

  • answered 2020-07-30 01:24 mevets

    The basic problem with what you want is that x86 isn't very good at pc-relative addressing; so you need to link your kernel at some address. What will that address be?

    1M (2^20) is a pretty good choice.

    Next up is how much memory do you have? 4G? Thats a bit ugly, your "one true physical map" leaves no address space for user programs. Look at [2] for a fix. Supposing you don't actually need all of memory mapped, just the kernel-y bits, and your kernel is likely less than 1G, you could keep kernel mapped pages 1:1 for the lower 1G of address space. User programs would then be in virtual addresses > 1G, with arbitrary mappings.

    Not really sure the point of it all; but it is quite doable.

    [2] for the tougher case, you can do something funky that has a side effect of stomping on a few of the spectre derived bugs. When an application is running, only provide kernel mappings for a very small area - the code to handle initial kernel/trap entry and the in-kernel user context. As part of the initial register save code, switch to a kernel only cr3 which is a unity mapping of all memory. If you wanted, you could actually disable paging instead, the re-enable it before re-entering user mode. Again, not sure the point, but feasible.