+ retf ; return to protected mode\r
+_BackFromUserCode ENDP\r
+\r
+_EntryPoint DD offset _ToUserCode - offset m16Start\r
+ DW 8h\r
+_16Idtr FWORD (1 SHL 10) - 1\r
+_16Gdtr LABEL FWORD\r
+ DW offset GdtEnd - offset _NullSegDesc - 1\r
+_16GdtrBase DD offset _NullSegDesc\r
+\r
+_ToUserCode PROC\r
+ mov edx, ss\r
+ mov ss, ecx ; set new segment selectors\r
+ mov ds, ecx\r
+ mov es, ecx\r
+ mov fs, ecx\r
+ mov gs, ecx\r
+ mov cr0, eax\r
+ mov cr4, ebp ; real mode starts at next instruction\r
+ mov ss, esi ; set up 16-bit stack segment\r
+ xchg sp, bx ; set up 16-bit stack pointer\r
+ DB 66h\r
+ call @Base ; push eip\r
+@Base:\r
+ pop bp ; ebp <- offset @Base\r
+ mov cs:[esi + (offset SavedSs - offset @Base)], edx\r
+ mov cs:[esi + (offset SavedEsp - offset @Base)], bx\r
+ DB 66h\r
+ lidt fword ptr cs:[esi + (offset _16Idtr - offset @Base)]\r
+ popaw ; popad actually\r
+ pop ds\r
+ pop es\r
+ pop fs\r
+ pop gs\r
+ popf ; popfd\r
+ DB 66h\r
+ retf ; transfer control to user code\r
+_ToUserCode ENDP\r
+\r
+_NullSegDesc DQ 0\r
+_16CsDesc LABEL QWORD\r
+ DW -1\r
+ DW 0\r
+ DB 0\r
+ DB 9bh\r
+ DB 8fh ; 16-bit segment, 4GB limit\r
+ DB 0\r
+_16DsDesc LABEL QWORD\r
+ DW -1\r
+ DW 0\r
+ DB 0\r
+ DB 93h\r
+ DB 8fh ; 16-bit segment, 4GB limit\r
+ DB 0\r
+GdtEnd LABEL QWORD\r
+\r
+;\r
+; @param RegSet Pointer to a IA32_DWORD_REGS structure\r
+; @param Transition Pointer to the transition code\r
+; @return The address of the 16-bit stack after returning from user code\r
+;\r
+InternalAsmThunk16 PROC USES ebp ebx esi edi ds es fs gs\r
+ mov esi, [esp + 36] ; esi <- RegSet\r
+ movzx edx, (IA32_REGS ptr [esi])._SS\r
+ mov edi, (IA32_REGS ptr [esi])._ESP\r
+ add edi, - (sizeof (IA32_REGS) + 4) ; reserve stack space\r
+ mov ebx, edi ; ebx <- stack offset\r
+ imul eax, edx, 16 ; eax <- edx * 16\r
+ push sizeof (IA32_REGS) / 4\r
+ add edi, eax ; edi <- linear address of 16-bit stack\r
+ pop ecx\r
+ rep movsd ; copy RegSet\r
+ mov eax, [esp + 40] ; eax <- address of transition code\r
+ mov esi, edx ; esi <- 16-bit stack segment\r
+ lea edx, [eax + (offset SavedCr0 - offset m16Start)]\r
+ mov ecx, eax\r
+ and ecx, 0fh\r
+ shl eax, 12\r
+ lea ecx, [ecx + (offset _BackFromUserCode - offset m16Start)]\r
+ mov ax, cx\r
+ stosd ; [edi] <- return address of user code\r
+ sgdt fword ptr [edx + (offset SavedGdt - offset SavedCr0)]\r
+ sidt fword ptr [esp + 36] ; save IDT stack in argument space\r
+ mov eax, cr0\r
+ mov [edx], eax ; save CR0 in SavedCr0\r
+ and eax, 7ffffffeh ; clear PE, PG bits\r
+ mov ebp, cr4\r
+ mov [edx + (offset SavedCr4 - offset SavedCr0)], ebp\r
+ and ebp, 300h ; clear all but PCE and OSFXSR bits\r
+ push 10h\r
+ pop ecx ; ecx <- selector for data segments\r
+ lgdt fword ptr [edx + (offset _16Gdtr - offset SavedCr0)]\r
+ call fword ptr [edx + (offset _EntryPoint - offset SavedCr0)]\r