示例#1
0
uint8_t vmi_get_address_width(
    vmi_instance_t vmi)
{
    uint8_t width = 0;

    driver_get_address_width(vmi, &width);

    return width;
}
示例#2
0
文件: memory.c 项目: LoongWin/libvmi
/*
 * check that this vm uses a paging method that we support
 * and set pm/cr3/pae/pse/lme flags optionally on the given pointers
 */
status_t probe_memory_layout_x86(vmi_instance_t vmi) {
    // To get the paging layout, the following bits are needed:
    // 1. CR0.PG
    // 2. CR4.PAE
    // 3. Either (a) IA32_EFER.LME, or (b) the guest's address width (32 or
    //    64). Not all backends allow us to read an MSR; in particular, Xen's PV
    //    backend doessn't.

    status_t ret = VMI_FAILURE;
    page_mode_t pm = VMI_PM_UNKNOWN;
    uint8_t dom_addr_width = 0; // domain address width (bytes)

    /* pull info from registers, if we can */
    reg_t cr0, cr3, cr4, efer;
    int pae = 0, pse = 0, lme = 0;
    uint8_t msr_efer_lme = 0;   // LME bit in MSR_EFER

    /* get the control register values */
    if (driver_get_vcpureg(vmi, &cr0, CR0, 0) == VMI_FAILURE) {
        errprint("**failed to get CR0\n");
        goto _exit;
    }

    /* PG Flag --> CR0, bit 31 == 1 --> paging enabled */
    if (!VMI_GET_BIT(cr0, 31)) {
        dbprint(VMI_DEBUG_CORE, "Paging disabled for this VM, only physical addresses supported.\n");
        vmi->page_mode = VMI_PM_UNKNOWN;
        vmi->pae = 0;
        vmi->pse = 0;
        vmi->lme = 0;

        ret = VMI_SUCCESS;
        goto _exit;
    }

    //
    // Paging enabled (PG==1)
    //
    if (driver_get_vcpureg(vmi, &cr4, CR4, 0) == VMI_FAILURE) {
        errprint("**failed to get CR4\n");
        goto _exit;
    }

    /* PSE Flag --> CR4, bit 5 */
    pae = VMI_GET_BIT(cr4, 5);
    dbprint(VMI_DEBUG_CORE, "**set pae = %d\n", pae);

    /* PSE Flag --> CR4, bit 4 */
    pse = VMI_GET_BIT(cr4, 4);
    dbprint(VMI_DEBUG_CORE, "**set pse = %d\n", pse);

    ret = driver_get_vcpureg(vmi, &efer, MSR_EFER, 0);
    if (VMI_SUCCESS == ret) {
        lme = VMI_GET_BIT(efer, 8);
        dbprint(VMI_DEBUG_CORE, "**set lme = %d\n", lme);
    } else {
        dbprint(VMI_DEBUG_CORE, "**failed to get MSR_EFER, trying method #2\n");

        // does this trick work in all cases?
        ret = driver_get_address_width(vmi, &dom_addr_width);
        if (VMI_FAILURE == ret) {
            errprint
                ("Failed to get domain address width. Giving up.\n");
            goto _exit;
        }
        lme = (8 == dom_addr_width);
        dbprint
            (VMI_DEBUG_CORE, "**found guest address width is %d bytes; assuming IA32_EFER.LME = %d\n",
             dom_addr_width, lme);
    }   // if
    // Get current cr3 for sanity checking
    if (driver_get_vcpureg(vmi, &cr3, CR3, 0) == VMI_FAILURE) {
        errprint("**failed to get CR3\n");
        goto _exit;
    }

    // now determine addressing mode
    if (0 == pae) {
        dbprint(VMI_DEBUG_CORE, "**32-bit paging\n");
        pm = VMI_PM_LEGACY;
        cr3 &= 0xFFFFF000ull;
    }
    // PAE == 1; determine IA-32e or PAE
    else if (lme) {    // PAE == 1, LME == 1
        dbprint(VMI_DEBUG_CORE, "**IA-32e paging\n");
        pm = VMI_PM_IA32E;
        cr3 &= 0xFFFFFFFFFFFFF000ull;
    } else {  // PAE == 1, LME == 0
        dbprint(VMI_DEBUG_CORE, "**PAE paging\n");
        pm = VMI_PM_PAE;
        cr3 &= 0xFFFFFFE0;
    }   // if-else
    dbprint(VMI_DEBUG_CORE, "**sanity checking cr3 = 0x%.16"PRIx64"\n", cr3);

    /* testing to see CR3 value */
    if (!driver_is_pv(vmi) && cr3 >= vmi->max_physical_address) {   // sanity check on CR3
        dbprint(VMI_DEBUG_CORE, "** Note cr3 value [0x%"PRIx64"] exceeds memsize [0x%"PRIx64"]\n",
                cr3, vmi->size);
    }

    vmi->page_mode = pm;
    vmi->pae = pae;
    vmi->pse = pse;
    vmi->lme = lme;

_exit:
    return ret;
}
示例#3
0
文件: memory.c 项目: masthoon/libvmi
static addr_t
linux_get_taskstruct_addr_from_pgd(
    vmi_instance_t vmi,
    addr_t pgd)
{
    addr_t list_head = 0, next_process = 0;
    addr_t task_pgd = 0;
    uint8_t width = 0;
    int tasks_offset = 0;
    int mm_offset = 0;
    int pgd_offset = 0;
    linux_instance_t os = NULL;

    if (vmi->os_data == NULL) {
        errprint("VMI_ERROR: No os_data initialized\n");
        return 0;
    }

    os = vmi->os_data;

    tasks_offset = os->tasks_offset;
    mm_offset = os->mm_offset;
    pgd_offset = os->pgd_offset;

    /* First we need a pointer to the initial entry in the tasks list.
     * Note that this is task_struct->tasks, not the base addr
     *  of task_struct: task_struct base = $entry - tasks_offset.
     */
    next_process = vmi->init_task;
    list_head = next_process;

    /* May fail for some drivers, but handle gracefully below by
     * testing width
     */
    if ( VMI_FAILURE == driver_get_address_width(vmi, &width) )
        return 0;

    do {
        addr_t ptr = 0;
        vmi_read_addr_va(vmi, next_process + mm_offset, 0, &ptr);

        /* task_struct->mm is NULL when Linux is executing on the behalf
         * of a task, or if the task represents a kthread. In this context,
         * task_struct->active_mm is non-NULL and we can use it as
         * a fallback. task_struct->active_mm can be found very reliably
         * at task_struct->mm + 1 pointer width
         */
        if(!ptr && width)
            vmi_read_addr_va(vmi, next_process + mm_offset + width, 0, &ptr);
        vmi_read_addr_va(vmi, ptr + pgd_offset, 0, &task_pgd);

        task_pgd = vmi_translate_kv2p(vmi, task_pgd);
        if (task_pgd == pgd) {
            return next_process;
        }

        vmi_read_addr_va(vmi, next_process + tasks_offset, 0, &next_process);
        next_process -= tasks_offset;

        /* if we are back at the list head, we are done */
    } while (list_head != next_process);

    return 0;
}