.code64 .globl bios.regs bios.regs: reax: .int 0x0 rebx: .int 0x0 recx: .int 0x0 redx: .int 0x0 redi: .int 0x0 resi: .int 0x0 rds: .short 0x0 res: .short 0x0 rss: .short 0x0 rgs: .short 0x0 rfs: .short 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 bios.call bios.call: xchg %bx, %bx 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 lidt bios_idtr sti # :Self modifying code to call arbitrary interrupts pop %ax mov $real_call_int, %bx mov %al, 1(%bx) push %ds # :Load registers mov (reax), %eax mov (rebx), %ebx mov (recx), %ecx mov (redx), %edx mov (redi), %edi mov (resi), %esi mov %ds:(res), %es mov %ds:(rss), %ss mov %ds:(rgs), %gs mov %ds:(rfs), %fs mov %ds:(rds), %ds xchg %bx, %bx real_call_int: int $0x0 pop %ds mov %ds:(rfs), %fs mov %ds:(rgs), %gs mov %ds:(rss), %ss mov %ds:(res), %es 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