2 ; NTS: We use NASM to achieve our goals here because WASM sucks donkey balls
3 ; Maybe when they bother to implement a proper conditional macro system, I'll consider it...
7 %error You must specify MMODE variable (memory model) for 16-bit real mode code
11 %if TARGET_MSDOS == 16
13 %define retnative retf
14 %define cdecl_param_offset 6 ; RETF addr + PUSH BP
17 %define retnative retf
18 %define cdecl_param_offset 6 ; RETF addr + PUSH BP
21 %define cdecl_param_offset 4 ; RET addr + PUSH BP
26 %define cdecl_param_offset 8 ; RET addr + PUSH EBP
29 ; NTS: Associate our data with Watcom's data segment
30 segment .data public align=4 class=data
32 ; NTS: Help NASM put the code segment in the right place for Watcom to link it in properly
33 segment text public align=1 class=code
35 %if TARGET_MSDOS == 16
37 ; int flatrealmode_test()
38 global flatrealmode_test_
45 ; clear interrupts, to ensure IRQ 5 is not mistaken for a GP fault
48 ; set DS=0 to carry out the test, and zero AX
52 ; hook interrupt 0x0D (general protection fault and IRQ 5)
55 mov word [si],_flatrealmode_test_fail
61 ; now try it. either we'll make it through unscathed or it will cause a GP fault and branch to our handler
65 ; either nothing happened, or control jmp'd here from the exception handler (who also set AX=1)
66 ; restore interrupt routine and clean up
67 _flatrealmode_test_conclude:
79 _flatrealmode_test_fail:
80 add sp,6 ; throw away IRETF address (IP+CS+FLAGS)
81 inc ax ; make AX nonzero
82 jmp short _flatrealmode_test_conclude
84 ; void __cdecl flatrealmode_force_datasel(void *ptr);
85 global _flatrealmode_force_datasel
86 _flatrealmode_force_datasel:
93 mov word [cs:_flatrealmode_force_datasel_j2_hackme+3],ax ; overwrite segment portion of JMP FAR instruction
95 ; LARGE and COMPACT memory models: a far pointer is passed onto the stack
106 ; LARGE memory model version (we're given a FAR pointer)
107 ; caller passes us the address of the constructed GDT (near ptr)
109 mov si,[bp+cdecl_param_offset]
111 ; now convert to physical addr
113 mov ax,[bp+cdecl_param_offset+2]
116 %else ; SMALL memory model version (we're given a NEAR pointer)
117 ; caller passes us the address of the constructed GDT (near ptr)
119 mov si,[bp+cdecl_param_offset]
121 ; now convert to physical addr
128 ; disable interrupts, we're going to fuck with the CPU mode and thunk into protected mode
131 ; allocate room on the stack for the GDT and store the original GDTR
136 ; and another for the new GDT
145 ; save previous segment regs
149 ; enable protected mode
154 ; now load the segment registers
155 mov ax,8 ; GDT selector value
159 ; force CPU to go into protected mode, clear cache
160 jmp 16:word _flatrealmode_force_datasel_j1
161 _flatrealmode_force_datasel_j1:
163 ; disable protected mode
169 ; opcode format: 0xEA <ofs> <seg>
170 _flatrealmode_force_datasel_j2_hackme:
171 jmp 0:word _flatrealmode_force_datasel_j2
172 _flatrealmode_force_datasel_j2:
174 ; reload sane realmode selectors
178 ; discard the new GDT