ah, PDE/PTE A/D writes... what a source of variety over the decades!
some chips set them step by step, as shown in the article
others only set them at them very end, together
and then there are chips which follow the read-modify-write op with another read, to check if the RMW succeeded... which promptly causes them to hang hard when the page tables live in read-only memory i.e. ROM... fun fun fun!
as for segmentation fun... think about CS always being writeable in real mode... even though the access rights only have a R but no W bit for it...
That's because CS in real/V86 mode is actually a writable data segment. Most protection checks work exactly the same in any mode, but the "is this a code segment?" check is only done when CS is loaded in protected mode, and not on any subsequent code fetch.
Using a non-standard mechanism of loading CS (LOADALL or RSM), it's possible to have a writable CS in protected mode too, at least on these older processors.
There's actually a slight difference in the access rights byte that gets loaded into the hidden part of a segment register (aka "descriptor cache") between real and protected mode. I first noticed this on the 80286, and it looks to be the same on the 386:
- In protected mode, the byte always matches that from the GDT/LDT entry: bit 4 (code/data segment vs. system) must be set, the segment load instruction won't allow otherwise, bit 0 (accessed) is set automatically (and written back to memory).
- In real and V86 mode, both of these bits are clear. So in V86 mode the value is 0xE2 instead of the "correct" 0xF3 for a ring 3 data segment, and similarly in real mode it's 0x82 (ring 0).
The hardware seems to simply ignore these bits, but they still exist in the register, unlike other "useless" bits. For example, LDT only has bit 7 (present), and GDT/IDT/TSS have no access rights byte at all - they're always assumed to be present, and the access rights byte reads as 0xFF. At least on the 286 that was the case, I've read that on the Pentium you can even mark GDT as not-present, and then get a triple fault on any access to it.
Keeping these bits, and having them different between modes might have been an intentional choice, making it possible to determine (by ICE monitor software) in what mode a segment got loaded. Maybe even the two other possible combinations (where bit4 != bit0) have some use to mark a "special" segment type that is never set by hardware?