c1ad0fc5/1/2026, 8:41:11 PM
.asm
Assembly
(text/assembly)
%macro enable_protected_mode 0
	%%.setup:
		mov si, enableProtectedModeMessage
		call print_string

		cli

		; NOTE(fkp): This requires that we have already
		; described the GDT and IDT tables.
		lgdt [gdtEntry]
		lidt [idtEntry]

		mov word [bootloaderStackPointer], sp

	%%.enable:
		; Enables protected mode
		mov eax, cr0
		or eax, 1
		mov cr0, eax

		; Also clears the prefetch queue
		jmp gdtCode32Offset:%%.setup_segments
		nop
		nop

	%%.setup_segments:
		bits 32
		; Selects the data descriptor for all segments (except cs)
		mov eax, gdtData32Offset
		mov ds, eax
		mov es, eax
		mov fs, eax
		mov gs, eax
		mov ss, eax
		mov esp, 0x20000		; Still within usable memory
%endmacro

%macro enable_real_mode 0
	%%.setup:
		cli

		; Also clears the prefetch queue
		jmp gdtCode16Offset:%%.switch_to_16_bit_gdt
		nop
		nop

	%%.switch_to_16_bit_gdt:
		bits 16
		mov ax, gdtData16Offset
		mov ds, ax
		mov es, ax
		mov fs, ax
		mov gs, ax
		mov ss, ax

	%%.disable_protected_mode:
		mov eax, cr0
		and eax, 0x7ffffffe		; Disables protected mode and paging
		mov cr0, eax

		; Also clears the prefetch queue
		jmp 0x00:%%.reset_gdt_selector
		nop
		nop

	%%.reset_gdt_selector:
		xor ax, ax
		mov ds, ax
		mov es, ax
		mov fs, ax
		mov gs, ax
		mov ss, ax
		mov sp, word [bootloaderStackPointer]

	%%.load_real_mode_idt:
		lidt [idtEntryRealMode]

	%%.cleanup:
		sti
		mov si, enableRealModeMessage
		call print_string
%endmacro