.code64 .globl real.regs real.regs: reax: .int 0x0 rebx: .int 0x0 recx: .int 0x0 redx: .int 0x0 redi: .int 0x0 resi: .int 0x0 # :real_call # This function is intended to be called from long mode # and calls another function in real mode. Note that precautions have # to be made. Recall that real mode can only access below 0xFFFFF. # So the target function, and objects of arguments passed to it cannot # be located above that. A reasonable scheme is to put the result # in a buffer and then, once back in long mode, copy its content to higher # above. # The procedure to go from Long Mode back to Real Mode is explained in much details # in the AMD64 Programmer's Manual Vol. 2, in particular, the figure 1-6. in section 1.3. .globl real.call real.call: # :Push all the segments registers push %rbx push %r12 push %r13 push %r14 push %r15 push %di cli lgdt gdtr32 pushq $(gdt32_code - gdt32) pushq $real_call_to_pmode_down retfq .code32 real_call_to_pmode_down: # :Here, we are in compatibility mode (32 bits) # :Disable paging mov %cr0, %eax and $~(1 << 31), %eax mov %eax, %cr0 # :Disabling long mode in msr mov $0xc0000080, %ecx rdmsr and $~(1 << 8), %eax wrmsr # :Here we are in true protected mode (32 bits) # Let's continue our descent to real mode # by switching our gdt to 16 bits lgdt gdtr16 ljmp $(gdt16_code - gdt16), $real_call_to_16bits_pmode_down .code16 real_call_to_16bits_pmode_down: # :Disable protected mode mov %cr0, %eax and $~1, %eax mov %eax, %cr0 ljmp $0, $real_call_to_16bits_rmode_down real_call_to_16bits_rmode_down: mov $0, %ax mov %ax, %ds mov %ax, %es mov %ax, %ss mov %ax, %gs mov %ax, %fs # :real mode, yay lidt bios_idtr sti mov rebx, %ebx mov recx, %ecx mov redx, %edx mov redi, %edi mov resi, %esi pop %ax call *%ax mov %eax, reax mov %ebx, rebx mov %ecx, recx mov %edx, redx mov %edi, redi mov %esi, resi cli # :Restore protected mode mov %cr0, %eax or $1, %eax mov %eax, %cr0 lgdt gdtr32 ljmp $(gdt32_code - gdt32), $real_call_to_pmode_up .code32 real_call_to_pmode_up: # :Restore PAE (probably unneeded) mov %cr4, %eax or $(1 << 5), %eax mov %eax, %cr4 # :Restore long mode mov $0xc0000080, %ecx rdmsr or $(1 << 8), %eax wrmsr # :Restore paging mov %cr0, %eax or $1 << 31, %eax mov %eax, %cr0 lgdt gdtr64 ljmp $(gdt64_code - gdt64), $real_call_to_longmode_up .code64 real_call_to_longmode_up: mov $(gdt64_data - gdt64), %ax mov %ax, %fs mov %ax, %gs mov %ax, %ss mov %ax, %es mov %ax, %ds real_call_end: pop %r15 pop %r14 pop %r13 pop %r12 pop %rbx ret .globl testt testt: mov $1, %al mov $0x43, %bh mov $0x6, %ah mov $0, %ch mov $0, %cl mov $5, %dh mov $5, %dl int $0x10 ret