I am attempting to create a custom operating system (for educational purposes) for which I am also creating the bootloader (multiboot 2). I am attempting to create a 64-bit system.
After entering long mode, I want to "clean up" by loading all data segment registers with 0
. To do this, I have the following code:
long_mode_start:
mov ax, 0
mov ss, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
ret
The moment mov ss, ax
is executed, the boot process fails and the CPU is reset (eventually leading up to a triple-fault). I'm using QEMU to emulate a X86_64 system. In the logs I get the following (I'm not sure how to fully interpret the logs): CPU Reset (CPU 0)
. For full log file, see:
https://github.com/WJJongkind/TicTacTOS/blob/develop/log.txt
I'm really not sure what I am doing wrong in my code. The full assembly file that sets up long mode and paging can be found here: https://github.com/WJJongkind/TicTacTOS/blob/develop/Bootloader/boot.asm
Note: I'm very much a beginner if it comes to assembly language & OS programming, so my comments in the code are probably not 100% accurate.
What causes the CPU to reset when setting the SS register value?
Correction, this answer was based on a misreading of the manual: the pseudo-code it contains only applies to 32-bit protected mode. See the linked duplicate where Michael Petch's answer covers this in much more detail.
This code will fault if executed in 32-bit protected mode, but not in 64-bit long mode at CPL=0. Or if you are executing this code in 32-bit mode before switching to long mode, then yes you should expect it to fault on the spot for SS, unlike later when a load or store tries to use it for the other segments.
Old answer, lightly edited to point out that it's answering the wrong question: 64-bit user space or 32-bit mode.
ds
andes
can be the null selector (0
) in 64-bit mode (unlike 32-bit PM), as canfs
andgs
.That's what Linux does, as I can confirm with GDB for a user-space process.
But SS needs to select a valid descriptor for some reason, maybe to set the stack address width to 64, even though that's the only valid choice when CS selects a 64-bit code segment. (Correction, no, 64-bit mode allows SS=0 when CPL<3, as long as CPL==RPL.)
Surprised QEMU doesn't give you more of a log about what exception triggered the reset. I think Bochs could do that, at least if you single-stepped with its built-in debugger.
According to Intel's manual (Operation section for mov-to-Sreg in protected mode) it should be a
#GP(0)
, and then double-fault and then triple-fault, assuming you don't have IDT entries for those. Which is fine if you have a simulator that shows you exception details.For details on what can cause exceptions in 64-bit mode, see that later section of the same manual entry: https://www.felixcloutier.com/x86/mov#64-bit-mode-exceptions