[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] Re: [RFC, PATCH 5/24] i386 Vmi code patching




On Mar 16, 2006, at 00:00 , Pavel Machek wrote:

The question of licensing of such ROM code is a completely separate
issue.  We are not trying to hide some proprietary code by putting it
inside of a ROM to keep it hidden.  In fact, you can disassemble the
ROM code and see it quite readily - and you know all of the entry
points.

Could you disassemble one entry point for us and describe how it works?


Here is how I construct my ROM. My apologies if my email client wraps any of the lines.

I have a set of boundary functions between assembler and C code, identified by a suffix on the function names: _ext (stands for "extended" in response to the evolution of my ROM). They accept a parameter called burn_clobbers_frame_t:
struct burn_clobbers_frame_t {
    word_t burn_ret_address;   /* Return address to the ROM */
    word_t frame_pointer;          /* This parameter. */
    word_t edx;
    word_t ecx;
    word_t eax;
    word_t guest_ret_address;
    word_t params[0];   /* Anything the guest pushed on the stack */
};
I use this structure for the non-performance critical functions.

Here are some of the assembler macros for constructing the ROM:

vmi_stub_simple WRMSR, afterburn_cpu_write_msr_ext
vmi_stub_simple RDMSR, afterburn_cpu_read_msr_ext

vmi_stub_simple SetGDT, afterburn_cpu_write_gdt32_ext
vmi_stub_simple SetLDT, afterburn_cpu_lldt_ext
vmi_stub_simple SetIDT, afterburn_cpu_write_idt32_ext
vmi_stub_simple SetTR,  afterburn_cpu_ltr_ext


macro vmi_stub_simple name func
/* Invoke a front-end C function that expects a burn_clobbers_frame_t as
* the parameter.
*/
        vmi_stub_begin \name
        __afterburn_save_clobbers
        push    %esp
        subl    $8, 0(%esp)
        vmi_call_relocatable \func
        __afterburn_restore_clobbers 4
        ret
        vmi_stub_end
.endm


.macro vmi_stub_begin name
/* Define the prolog of a VMI stub.  */
        vmi_area_begin \name
        burn_counter VMI_\name
        burn_counter_inc VMI_\name
.endm

.macro vmi_stub_end
/* Define the epilog of a VMI stub.  */
        .previous
.endm

.macro vmi_area_begin name
/* Define the start of a VMI area. */
        .section .vmi_rom, "ax"
        .org vmi_rom_offset_\name
        .globl VMI_\name
        .type VMI_\name,@function
VMI_\name:
.endm

.macro vmi_call_relocatable func
        9191: call      \func
        .pushsection .vmi_patchups, "aw"
        .balign 4
        .long 9191b
        .popsection
.endm

.macro vmi_jmp_relocatable target
        9191: jmp       \target
        .pushsection .vmi_patchups, "aw"
        .balign 4
        .long 9191b
        .popsection
.endm


extern "C" void
afterburn_cpu_write_gdt32_ext( burn_clobbers_frame_t *frame )
{
    get_cpu()->gdtr =  *(dtr_t *)frame->eax;
}



The ROM entry points are only half the solution. The other half involves Xen callbacks and traps. The system call trap is constructed to directly activate Linux's system call trap. Everything else jumps directly into the ROM for filtering reasons. The page-fault handler stays in assembler (because page faults are a performance issue; on a linux kernel build, they occur almost as frequently as system calls). The remaining traps enter C code, and look like this:

trap_wrapper id=8, use_error_code=1     /* Double fault exception */
trap_wrapper id=9, use_error_code=0 /* Coprocessor segment overrun */
trap_wrapper id=10, use_error_code=1    /* Invalid TSS exception */
trap_wrapper id=11, use_error_code=1    /* Segment not present */
trap_wrapper id=12, use_error_code=1    /* Stack fault exception */
trap_wrapper id=13, use_error_code=1    /* general protection fault */

.macro trap_wrapper id, use_error_code
entry trap_wrapper_\id
.if \use_error_code
        subl    $4, %esp        /* Fault addr. */
.else
        subl    $8, %esp        /* Error code, fault addr. */
.endif
        pushl   $(\id | (\use_error_code << 31))        /* Frame ID. */
        cpu_save_all
        movl    %esp, %eax      /* A pointer to the CPU save frame. */
        call    trap
        jmp     afterburn_exit
.endm


entry afterburn_exit
        cpu_restore_all 0, 12   /* Error code, fault addr, frame id. */
        iret


extern "C" void __attribute__(( regparm(1) ))
trap( xen_frame_t *frame )
{
    if( EXPECT_FALSE(frame->iret.ip >= CONFIG_WEDGE_VIRT) ) {
con << "Unexpected fault in the ROM, ip " << (void *)frame- >iret.ip
            << '\n';
        DEBUGGER_ENTER(frame);
        panic();
    }

    u8_t *opstream = (u8_t *)frame->iret.ip;

    if( cpu_t::get_segment_privilege(frame->iret.cs) == 3 )
    {
        // A user-level fault.

       ... check for TLS issues ...

    }


// Update virtual CPU state, and deliver the trap to the guest kernel.
    xen_deliver_async_vector( frame->get_id(), frame,
            frame->uses_error_code());
}


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.