From 832807726a76d2f47012f3df5b877173201e27ba Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 4 May 2006 23:14:06 +0000 Subject: [PATCH] Add infrastructure to support access to .data16 (and .text16) variables from protected-mode code. Set up %ds to point to .data16 in prot_to_real, so that code specified via REAL_EXEC() and friends can access variables in .data16. Move most real-mode librm variables from .text16 to .data16. --- src/arch/i386/prefix/libprefix.S | 5 +- src/arch/i386/transitions/librm.S | 194 +++++++++++++++++++----------- 2 files changed, 124 insertions(+), 75 deletions(-) diff --git a/src/arch/i386/prefix/libprefix.S b/src/arch/i386/prefix/libprefix.S index 25d51bfa5..3b896ba1b 100644 --- a/src/arch/i386/prefix/libprefix.S +++ b/src/arch/i386/prefix/libprefix.S @@ -336,6 +336,7 @@ install_prealloc: call install_highmem /* Continue executing in .text16 segment */ + movw %bx, %ds pushw %cs pushw $2f pushw %ax @@ -344,11 +345,11 @@ install_prealloc: .section ".text16", "awx", @progbits 1: /* Set up protected-mode GDT, call relocate(), reset GDT */ - call init_gdt + call init_librm pushl $relocate data32 call prot_call addw $4, %sp - call init_gdt + call init_librm /* Return to executing in .prefix section */ lret diff --git a/src/arch/i386/transitions/librm.S b/src/arch/i386/transitions/librm.S index ef94ed328..07c6b2a57 100644 --- a/src/arch/i386/transitions/librm.S +++ b/src/arch/i386/transitions/librm.S @@ -24,7 +24,7 @@ /**************************************************************************** * Global descriptor table * - * Call init_gdt to set up the GDT before attempting to use any + * Call init_librm to set up the GDT before attempting to use any * protected-mode code. * * Define FLATTEN_REAL_MODE if you want to use so-called "flat real @@ -45,7 +45,7 @@ #else #define RM_LIMIT_16_19__AVL__SIZE__GRANULARITY 0x00 #endif - .section ".text16" + .section ".data16", "aw", @progbits .align 16 gdt: gdt_limit: .word gdt_length - 1 @@ -86,56 +86,71 @@ gdt_end: .equ gdt_length, gdt_end - gdt /**************************************************************************** - * init_gdt (real-mode near call, 16-bit real-mode return address) + * init_librm (real-mode near call, 16-bit real-mode return address) * * Initialise the GDT ready for transitions to protected mode. * - * Parameters: - * %edi : Physical base of protected-mode code + * Parameters: + * %cs : .text16 segment + * %ds : .data16 segment + * %edi : Physical base of protected-mode code (virt_offset) **************************************************************************** */ .section ".text16" .code16 - .globl init_gdt -init_gdt: + .globl init_librm +init_librm: /* Preserve registers */ pushl %eax - pushw %bx + pushl %ebx - /* Record virt_offset */ - movl %edi, %cs:virt_offset_rm_copy - - /* Set virtual_cs and virtual_ds base */ + /* Store _virt_offset and set up virtual_cs and virtual_ds segments */ movl %edi, %eax movw $virtual_cs, %bx call set_seg_base + movw $virtual_ds, %bx + call set_seg_base + movl %edi, _virt_offset - /* Set real_cs and real_ds base, and GDT base */ - movw $real_cs, %bx + /* Negate virt_offset */ + negl %edi + + /* Store rm_cs and _text16, set up real_cs segment */ xorl %eax, %eax movw %cs, %ax + movw %ax, rm_cs shll $4, %eax + movw $real_cs, %bx call set_seg_base - addl $gdt, %eax - movl %eax, %cs:gdt_base + leal (%eax, %edi), %ebx + movl %ebx, _text16 + /* Store rm_ds and _data16, set up real_ds segment and set GDT base */ + xorl %eax, %eax + movw %ds, %ax + movw %ax, %cs:rm_ds + shll $4, %eax + movw $real_ds, %bx + call set_seg_base + leal (%eax, %edi), %ebx + movl %ebx, _data16 + addl $gdt, %eax + movl %eax, gdt_base + /* Restore registers */ - popw %bx + negl %edi + popl %ebx popl %eax ret .section ".text16" .code16 set_seg_base: - pushl %eax - movw %ax, %cs:(0+2)(%bx) - movw %ax, %cs:(8+2)(%bx) - shrl $16, %eax - movb %al, %cs:(0+4)(%bx) - movb %al, %cs:(8+4)(%bx) - movb %ah, %cs:(0+7)(%bx) - movb %ah, %cs:(8+7)(%bx) - popl %eax +1: movw %ax, 2(%bx) + rorl $16, %eax + movb %al, 4(%bx) + movb %ah, 7(%bx) + roll $16, %eax ret /**************************************************************************** @@ -157,19 +172,25 @@ set_seg_base: .section ".text16" .code16 real_to_prot: - /* Protected-mode return address => %ebx */ - popl %ebx - - /* Real-mode %cs => %dx, %ss => %bp */ - movw %cs, %dx + /* Make sure we have our data segment available */ + movw %cs:rm_ds, %ax + movw %ax, %ds + + /* Add _virt_offset, _text16 and _data16 to stack to be + * copied, and also copy the return address. + */ + pushl _virt_offset + pushl _text16 + pushl _data16 + addw $16, %cx /* %ecx must be less than 64kB anyway */ + + /* Real-mode %ss:%sp => %bp:%esi */ movw %ss, %bp - - /* virt_offset => %edi */ - movl %cs:virt_offset_rm_copy, %edi + movzwl %sp, %esi /* Switch to protected mode */ cli - data32 lgdt %cs:gdt + data32 lgdt gdt movl %cr0, %eax orb $CR0_PE, %al movl %eax, %cr0 @@ -184,24 +205,24 @@ real_to_prot: movw %ax, %fs movw %ax, %gs - /* Record virt_offset */ - movl %edi, virt_offset - /* Move data from RM stack to PM stack and set up PM stack */ - movzwl %sp, %esi movl pm_esp, %esp subl %ecx, %esp movl %esp, %edi rep ss movsb movw %ax, %ss - /* Record real-mode %cs and %ss:sp */ - movw %dx, rm_cs + /* Record real-mode %ss:sp (after removal of data) */ movw %bp, rm_ss movw %si, rm_sp + /* Publish virt_offset, text16 and data16 for PM code to use */ + popl data16 + popl text16 + popl virt_offset + /* Return to virtual address */ - jmp *%ebx + ret /**************************************************************************** * prot_to_real (protected-mode near call, 32-bit real-mode return address) @@ -209,9 +230,9 @@ real_to_prot: * Switch from 32-bit protected mode with virtual addresses to 16-bit * real mode. The protected-mode %esp is stored in pm_esp and the * real-mode %ss:sp is restored from the saved rm_ss and rm_sp. All - * real-mode data segment registers are set equal to %ss. Interrupts - * are *not* enabled, since we want to be able to use prot_to_real in - * an ISR. All other registers may be destroyed. + * real-mode data segment registers are loaded from the saved rm_ds. + * Interrupts are *not* enabled, since we want to be able to use + * prot_to_real in an ISR. All other registers may be destroyed. * * The return address for this function should be a 32-bit (sic) * real-mode offset within .code16. @@ -224,15 +245,15 @@ real_to_prot: .section ".text" .code32 prot_to_real: - /* Real-mode return address => %ebx */ - popl %ebx + /* Add return address to data to be moved to RM stack */ + addl $4, %ecx /* Real-mode %ss:sp => %ebp:edx */ movzwl rm_ss, %ebp movzwl rm_sp, %edx subl %ecx, %edx - /* Copy data from PM stack to RM stack */ + /* Move data from PM stack to RM stack */ movl %ebp, %eax shll $4, %eax leal (%eax,%edx), %edi @@ -240,12 +261,9 @@ prot_to_real: movl %esp, %esi rep movsb - /* Record protected-mode %esp */ + /* Record protected-mode %esp (after removal of data) */ movl %esi, pm_esp - /* Real-mode %cs => %di */ - movw rm_cs, %di - /* Load real-mode segment limits */ movw $REAL_DS, %ax movw %ax, %ds @@ -257,27 +275,40 @@ prot_to_real: .section ".text16" .code16 1: - /* Set up real-mode ljmp instruction */ - movw %di, %ds:(p2r_ljmp + 3) - /* Switch to real mode */ movl %cr0, %eax andb $0!CR0_PE, %al movl %eax, %cr0 + ljmp *p2r_jump_vector +p2r_jump_target: -p2r_ljmp: - ljmp $0, $1f /* Segment is filled in by above code */ -1: - /* Set up real-mode stack and data segments, and stack pointer */ - movw %bp, %ds - movw %bp, %es - movw %bp, %fs - movw %bp, %gs + /* Set up real-mode stack */ movw %bp, %ss movw %dx, %sp + + /* Set up real-mode data segments */ + movw %cs:rm_ds, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs /* Return to real-mode address */ - jmp *%bx + data32 ret + + + /* Real-mode code and data segments. Assigned by the call to + * init_librm. rm_cs doubles as the segment part of the jump + * vector used by prot_to_real. rm_ds is located in .text16 + * rather than .data16 because code needs to be able to locate + * the data segment. + */ + .section ".data16" +p2r_jump_vector: + .word p2r_jump_target +rm_cs: .word 0 + .section ".text16" +rm_ds: .word 0 /**************************************************************************** * prot_call (real-mode near call, 32-bit real-mode return address) @@ -406,11 +437,12 @@ real_call: /* Construct call to real-mode function */ movw %sp, %bp movw RC_OFFSET_FUNCTION(%bp), %ax - movw %ax, %cs:rc_function + movw %ax, rc_function /* Call real-mode function */ popal - call *%cs:rc_function + call *RC_OFFSET_FUNCTION(%esp) + call *rc_function pushal /* Switch to protected mode and move register dump back to PM stack */ @@ -427,7 +459,9 @@ real_call: popal ret - .section ".text16" + + /* Function vector, used because */ + .section ".data16" rc_function: .word 0 /**************************************************************************** @@ -464,19 +498,33 @@ rc_function: .word 0 * to us. **************************************************************************** */ - .section ".data" .globl rm_sp rm_sp: .word 0 .globl rm_ss rm_ss: .word 0 - .globl rm_cs -rm_cs: .word 0 .globl pm_esp pm_esp: .long _estack - .section ".text16" -virt_offset_rm_copy: .long 0 +/**************************************************************************** + * Virtual address offsets + * + * These are used by the protected-mode code to map between virtual + * and physical addresses, and to access variables in the .text16 or + * .data16 segments. + **************************************************************************** + */ + /* Internal copies, created by init_librm (which runs in real mode) */ + .section ".data16" +_virt_offset: .long 0 +_text16: .long 0 +_data16: .long 0 + + /* Externally-visible copies, created by real_to_prot */ .section ".data" .globl virt_offset -virt_offset: .long 0 +virt_offset: .long 0 + .globl text16 +text16: .long 0 + .globl data16 +data16: .long 0