My Rambling Thoughts

What-if 80286 in an alternate world

Following our alt-8086, let's extend it to 80286. What will 80286 be like if it did not have segmentation?

This is very ironic, because 80286 is the quintessential 16-bit segmented processor. Its memory management is based on segmentation in Protected Mode. It would have worked very well if segments were not limited to 16-bit — 80286 uses 24-bit address, it should allow 24-bit segments.

The answer to our question is simple. Our alt-80286 will use paging for memory management in Protected Mode — brought forward by one generation.

If we use 16 kB pages, the virtual address will look like this:

|Bits|#bits|Purpose|
|---|---|+--|
|14 - 23|10|Page Table|
|0 - 13|14|Offset|

We only need 10 bits for the Page Table, so a Page Table entry can be just 16 bits (6 bits for flags), but it is a little tight — we need 10 bits for flags, ideally — so let's use 32 bits, and we can use the same format when we move to 32-bit.

We only need 1,024 entries, so there is only one Page Table.

If we use all 4,096 entries, we can support an address space of 64 MB — needs 26-bit address bus.

That's it, we are done.

Protected Mode

For our alt-286, Real mode means paging is off. Protected mode means paging is on.

The CPU starts in Supervisor mode with paging off. The OS may set up page tables and enable paging, entering Protected mode. It then enters User mode using IRET.

Interrupts

An interrupt has its own stack, page table and PCID, different from the kernel. ISRs are not fully trusted code!

Interrupt Vector entry:

|Ofs|#bytes|Purpose|
|---|---|+--|
|0|2|Flags|
|2|2|PCID|
|4|4|Page Table addr|
|8|4|Stack addr|
|12|4|Call Stack addr|
|16|4|Entry point|

Flags:

  • Save registers? This is for convenience
  • Run in supervisor mode?
  • Disable interrupt?

Each Interrupt Vector is 20 bytes. Let's make it 32 bytes for future expansion.

An interrupt will always use its Page Table and stack. It will never use the process's stack.

The process's context is saved in its Context memory. This includes the return address.

The process's context address and SP are pushed to the ISR stack. User-mode SP is intended for a system call to access its parameters that are pushed on the process's stack. An ISR won't be able to use it — its Page Table will not have user memory.

Interrupt handling in x86 Protected Mode is notoriously slow. We want interrupts to be fast. I don't know if I count correctly, but we should be able to do it in < 30 clock cycles.

System calls

A system call is made using software interrupt instruction. There is no call gate, jump gate or task gate. There is no TSS (Task State Segment).

There is no need to use a dedicated SYSCALL instruction as interrupts have very little overhead compared to INT on x86.

System calls use kernel page table and stack — by definition.

Optimizing save/restore

Let's say alt-80286 has alt-80287 integrated. This means an additional 8 48-bit registers to save — a total of 48 bytes, or 24 cycles.

It is tempting to save and restore them lazily, as Intel did. FP instructions are trapped in user mode. When they are used, the OS then saves the values for the previous process and restores the values for the current process.

But this leads to LazyFP attack which uses speculative read to avoid tripping the trap. The data can then be teased out of the registers by using cache side-channel read.

A solution is to trap even for speculative read.

An alternative solution is to assign a dirty bit to each optional register. It is cleared if the register is zero. All registers are saved and restored on inter-process context switch, but clean ones are skipped, saving cycles:

  • Save current process: write dirty flags, write dirty registers, skip clean ones
  • Restore new process: read dirty flags, read dirty registers, clean ones are zeroed out

Moral of the story: always zero out registers after use!

Murdle for Juniors


Murdle Jr (Book 1) [2024]

Junior edition, easier for kids below 13 years old to solve. Has 40 puzzles.

It is divided into 5 sections. Each section has 8 puzzles. For the first four sections, there are two 3x3 (2 variables), two 4x4, two 3x3x3 (3 variables) and two 4x4x4 puzzles. The last section has four 4x4 (2 variables), one 3x3x3 (3 variables), one 4x4x4 and two 3x3x3 (4 variables). The last four puzzles are adult standard.


Murdle Jr: Sleuths on the Loose [2025]

This is a mystery novel. Don't buy this book if you are looking for puzzles.

It has only one 4x4x4 logic puzzle (3 variables) that is filled up gradually as the story progresses. You are given a chance to solve the puzzle at the end of the book before the reveal.

It has a bonus 3x3 puzzle (2 variables) at the end.

I knew it was a storybook, but I thought it had puzzles sprinkled throughout. I was mistaken.

I noticed my copy is for South Asia region and is not meant for export. Its MSRP is 499 Indian Rupee, which is S$6.82! I bought it for S$15.46. Its MSRP in UK is 7.99 pounds, or S$13.65.

(I checked Amazon India and it sells for 342 Ruppee, or S$4.68, there. Too bad they don't deliver to Singapore — I estimate shipping to be around S$5.)

It turns out my Murdle Book 1 is also a South Asia edition, 599 Indian Rupee (S$8.19). I bought it for S$20.38. I feel cheated. :lol: Its MSRP in UK is 14.99 pounds, or S$25.62.

It is not surprising that the same book sells much cheaper in South Asia — 1/3 to 1/2 UK MSRP. But the publisher should have at least make it harder to grey import by using a different book cover.

Why is Meta hell now?

One word, Z is desperate.

His AI is way behind.

Previously, he bet on VR. VR is nice, but it is flawed until someone invents a way to move in-place. Not just walking, but running, jumping and other movements. Not even Apple could make VR a thing, just saying.

AI was being worked on, no doubt, but apparently the R&D gamed the metrics too much. It was fine and dandy when everyone just demo'ed bits and pieces — they could get the same results by cherry-picking — but when OpenAI released ChatGPT to the public, the gap was striking. One could carry out a conversation. The other was a toy.

It was not just behind. It was flawed. So much so that they had to abandon it and start from scratch. That's how bad it was. Open source? Forget it, Z has no time for it.

Funnily enough, in the time since, Anthropic has overtaken OpenAI with its Claude LLM. ChatGPT is better with general knowledge, but Claude is better at reasoning and doing things.

Meta is also working on smart glasses. I imagine it will take off in the next few years. By then, it'll be quaint to be using mobile phones.

What-if 80386 paging

The design of 80386 paging mechanism is elegant and impeccable.

It has a 4 kB Page Directory containing 1,024 entries, each pointing to a 4 kB Page Table that contains 1,024 entries, each of which points to a 4 kB page. The symmetry is just elegant.

Except, the page size is too small — even in 1985, arguably.

Even by 1985 standards, very few programs use as little as 4 kB of code and 4 kB of data. There was no need to be granular to this degree.

Intel must have realized too, because they added large pages (4 MB) in Pentium in 1993. That was just 8 years apart. 4 MB was too large for general use, though.

Even in 1985, I'll say 16 kB would have been a better choice. 16 kB is still a reasonable — though considered the minimum — size today, imagine that.

The case against bigger page is that you waste half a page per allocation on average. This is internal fragmentation. The smaller the allocation, the more potential for waste. However, system-level allocations are usually big — run-time libraries allocate 64 kB or bigger at a time and parcel them out. Even system-level disk buffers are seldom smaller than 16 kB.

A 16 kB Page Table contains 4,096 entries (16 kB / 4) and points up to 64 MB of memory. The Page Directory contains only 64 entries.

|Bits|#bits|Purpose|
|---|---|+--|
|26 - 31|6|Page Directory|
|14 - 25|12|Page Table|
|0 - 13|14|Offset|

Large page

If we follow Pentium's approach and drop Page Table translation, we get 64 MB large page. That is way too big! (Most of the time.)

A good large size is 64 kB or 256 kB. 64 kB is kind of small for a 'large page', 256 kB barely qualifies — it is big, not large.

Format of a 256 kB page:

|Bits|#bits|Purpose|
|---|---|+--|
|26 - 31|6|Page Directory|
|18 - 25|8|Page Table|
|0 - 17|18|Offset|

The type of page is determined at the Page Directory level, so 256 kB pages must be aligned at physical 64 MB boundary and there are only 64 such regions. Once a 64 MB region is designated to use 256 kB page, the entire region must use 256 kB pages.

A big-page Page Table has only 256 entries. It is quite wasteful.

Can we support variable-size pages? Yes, but maybe in the future.

A case for >4 GB address space

4 GB is big for a single process, but we can still run short of memory in a multi-process environment!

Pentium Pro, released in 1995, supports 36-bit address space, or 64 GB of physical memory.

We need to widen the page entry to 64-bit so that we can store the upper 4 address bits. This is a one-time change. In the future, we can widen the address to 40-bit, 48-bit or even longer — though these are more likely in 64-bit systems.

A Page Table now has 2,048 entries (16 kB / 8). The Page Directory has 128 entries. There is no need for third-level Page Directory Pointers.

|Bits|#bits|Purpose|
|---|---|+--|
|25 - 31|7|Page Directory|
|14 - 24|11|Page Table|
|0 - 13|14|Offset|

We can support 36-bit address space with just two levels of page tables — with a full Page Directory of 2,048 entries.

We finally need third level to support 40-bit address space, but that is a topic for another time. :-D

Defending against Meltdown

The TLB knows whether the page is privileged. The check is done before the read. This prevents speculative read that enables Meltdown attack. By doing this, there is no need for KPTI (Kernel Page-Table Isolation).

For complete defense, the TLB must have Process-Context Identifiers (PCID) to tag processes. This truly isolates processes. PCID was originally added to avoid flushing the TLB when switching between processes.

Without hardware support, the TLB must be flushed on every context switch. Every system call requires two flushes (to kernel and from kernel).

12K Sky at Dawn


A Thousand Miles of Wind, the Sky at Dawn: Part 1 (Book 5) [2026]

First impressions: the paper is really white! Font size is standard, double line spacing and wide margin.

I've read a few chapters and my initial impression is that it feels like it is written natively in English — it does not feel translated! The Tokyopop edition is generally good, but has some awkward phrasing sometimes.

Some readers may prefer a more literal translation to preserve the original meaning, though it may not read as smoothly.

Take the title, for example. It is translated literally. It is 风之万里 . 黎明之空 in Chinese.

Part 1 mostly sets up the story. All the exciting stuff is in Part 2. You don't miss much even if you skipped this.