+ * pm_call (real-mode near call)
+ *
+ * Call routine in 16-bit protected mode for access to extended memory
+ *
+ * Parameters:
+ * %ax : address of routine to call in 16-bit protected mode
+ * Returns:
+ * none
+ * Corrupts:
+ * %ax
+ *
+ * The specified routine is called in 16-bit protected mode, with:
+ *
+ * %cs : 16-bit code segment with base matching real-mode %cs
+ * %ss : 16-bit data segment with base matching real-mode %ss
+ * %ds,%es,%fs,%gs : 32-bit data segment with zero base and 4GB limit
+ *
+ ****************************************************************************
+ */
+
+#ifndef KEEP_IT_REAL
+
+ /* GDT for protected-mode calls */
+ .section ".data16"
+ .align 16
+gdt:
+gdt_limit: .word gdt_length - 1
+gdt_base: .long 0
+ .word 0 /* padding */
+pm_cs: /* 16-bit protected-mode code segment */
+ .equ PM_CS, pm_cs - gdt
+ .word 0xffff, 0
+ .byte 0, 0x9b, 0x00, 0
+pm_ss: /* 16-bit protected-mode stack segment */
+ .equ PM_SS, pm_ss - gdt
+ .word 0xffff, 0
+ .byte 0, 0x93, 0x00, 0
+pm_ds: /* 32-bit protected-mode flat data segment */
+ .equ PM_DS, pm_ds - gdt
+ .word 0xffff, 0
+ .byte 0, 0x93, 0xcf, 0
+gdt_end:
+ .equ gdt_length, . - gdt
+ .size gdt, . - gdt
+
+ .section ".data16"
+ .align 16
+pm_saved_gdt:
+ .long 0, 0
+ .size pm_saved_gdt, . - pm_saved_gdt
+
+ .section ".prefix.lib"
+ .code16
+pm_call:
+ /* Preserve registers, flags, GDT, and RM return point */
+ pushfl
+ sgdt pm_saved_gdt
+ pushw %gs
+ pushw %fs
+ pushw %es
+ pushw %ds
+ pushw %ss
+ pushw %cs
+ pushw $99f
+
+ /* Set up GDT bases */
+ pushl %eax
+ pushw %bx
+ xorl %eax, %eax
+ movw %ds, %ax
+ shll $4, %eax
+ addl $gdt, %eax
+ movl %eax, gdt_base
+ movw %cs, %ax
+ movw $pm_cs, %bx
+ call set_seg_base
+ movw %ss, %ax
+ movw $pm_ss, %bx
+ call set_seg_base
+ popw %bx
+ popl %eax
+
+ /* Switch CPU to protected mode and load up segment registers */
+ pushl %eax
+ cli
+ lgdt gdt
+ movl %cr0, %eax
+ orb $CR0_PE, %al
+ movl %eax, %cr0
+ ljmp $PM_CS, $1f
+1: movw $PM_SS, %ax
+ movw %ax, %ss
+ movw $PM_DS, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+ popl %eax
+
+ /* Call PM routine */
+ call *%ax
+
+ /* Set real-mode segment limits on %ds, %es, %fs and %gs */
+ movw %ss, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+
+ /* Return CPU to real mode */
+ movl %cr0, %eax
+ andb $0!CR0_PE, %al
+ movl %eax, %cr0
+
+ /* Restore registers and flags */
+ lret
+99: popw %ss
+ popw %ds
+ popw %es
+ popw %fs
+ popw %gs
+ lgdt pm_saved_gdt
+ popfl
+
+ ret
+ .size pm_call, . - pm_call
+
+set_seg_base:
+ rolw $4, %ax
+ movw %ax, 2(%bx)
+ andw $0xfff0, 2(%bx)
+ movb %al, 4(%bx)
+ andb $0x0f, 4(%bx)
+ ret
+ .size set_seg_base, . - set_seg_base
+
+#endif /* KEEP_IT_REAL */
+
+/****************************************************************************
+ * copy_bytes (real-mode or 16-bit protected-mode near call)
+ *
+ * Copy bytes
+ *
+ * Parameters:
+ * %ds:esi : source address
+ * %es:edi : destination address
+ * %ecx : length
+ * Returns:
+ * %ds:esi : next source address
+ * %ds:esi : next destination address
+ * Corrupts:
+ * None
+ ****************************************************************************
+ */
+ .section ".prefix.lib"
+ .code16
+copy_bytes:
+ pushl %ecx
+ rep addr32 movsb
+ popl %ecx
+ ret
+ .size copy_bytes, . - copy_bytes
+
+/****************************************************************************
+ * install_block (real-mode or 16-bit protected-mode near call)