/**
 * Writes 8 bits to memory, given a physical address.
 *
 * @param[in] vmi LibVMI instance
 * @param[in] paddr Physical address to write to
 * @param[in] value The value written to memory
 * @return VMI_SUCCESS or VMI_FAILURE
 */
status_t vmi_write_8_pa(
    vmi_instance_t vmi,
    addr_t paddr,
    uint8_t * value) NOEXCEPT;
// Easy write to physical memory
status_t
vmi_write_8_pa(
    vmi_instance_t vmi,
    addr_t paddr,
    uint8_t * value)
{
    return vmi_write_pa(vmi, paddr, 1, value, NULL);
}
status_t
vmi_write_pa(
    vmi_instance_t vmi,
    addr_t paddr,
    size_t count,
    void *buf,
    size_t *bytes_written)
{
    ACCESS_CONTEXT(ctx, .addr = paddr);
    return vmi_write(vmi, &ctx, count, buf, bytes_written);
}
// Classic write functions for access to memory
status_t
vmi_write(
    vmi_instance_t vmi,
    const access_context_t *ctx,
    size_t count,
    void *buf,
    size_t *bytes_written)
{
    status_t ret = VMI_FAILURE;
    addr_t start_addr;
    addr_t pt;
    addr_t paddr;
    addr_t naddr;
    addr_t offset;
    page_mode_t pm;
    size_t buf_offset = 0;
 
#ifdef ENABLE_SAFETY_CHECKS
    if (NULL == vmi) {
        dbprint(VMI_DEBUG_WRITE, "--%s: vmi passed as NULL, returning without write\n",
                __FUNCTION__);
        goto done;
    }
 
    if (NULL == buf) {
        dbprint(VMI_DEBUG_WRITE, "--%s: buf passed as NULL, returning without write\n",
                __FUNCTION__);
        goto done;
    }
 
    if (NULL == ctx) {
        dbprint(VMI_DEBUG_WRITE, "--%s: ctx passed as NULL, returning without write\n",
                __FUNCTION__);
        goto done;
    }
 
    if (ctx->version != ACCESS_CONTEXT_VERSION) {
        if ( !vmi->actx_version_warn_once )
            errprint("--%s: access context version mismatch, please update your code\n", __FUNCTION__);
        vmi->actx_version_warn_once = 1;
 
        // TODO: for compatibility reasons we still accept code compiled
        //       without the ABI signature and version fields initialized.
        //       Turn this check into enforcement after appropriate amount of
        //       time passed (in ~2023 or after).
    }
#endif
 
    // Set defaults
    pt = ctx->pt;
    pm = vmi->page_mode;
    start_addr = ctx->addr;
 
    switch (ctx->tm) {
        case VMI_TM_NONE:
            pm = VMI_PM_NONE;
            pt = 0;
            break;
        case VMI_TM_KERNEL_SYMBOL:
#ifdef ENABLE_SAFETY_CHECKS
            if (!vmi->os_interface || !vmi->kpgd)
                goto done;
#endif
            if ( VMI_FAILURE == vmi_translate_ksym2v(vmi, ctx->ksym, &start_addr) )
                goto done;
            if (!pm)
                pm = vmi->page_mode;
            pt = vmi->kpgd;
 
            break;
        case VMI_TM_PROCESS_PID:
#ifdef ENABLE_SAFETY_CHECKS
            if (!vmi->os_interface)
                goto done;
#endif
 
            if (!ctx->pid)
                pt = vmi->kpgd;
            else if (ctx->pid > 0) {
                if ( VMI_FAILURE == vmi_pid_to_dtb(vmi, ctx->pid, &pt) )
                    goto done;
            }
 
            if (!pm)
                pm = vmi->page_mode;
            if (!pt)
                goto done;
            break;
        case VMI_TM_PROCESS_DTB:
            if (!pm)
                pm = vmi->page_mode;
            break;
        default:
            errprint("%s error: translation mechanism is not defined.\n", __FUNCTION__);
            return 0;
    }
 
    while (count > 0) {
        size_t write_len = 0;
 
        if (valid_pm(pm)) {
            if (VMI_SUCCESS != vmi_nested_pagetable_lookup(vmi, ctx->npt, ctx->npm, pt, pm, start_addr + buf_offset, &paddr, &naddr))
                goto done;
 
            if (valid_npm(ctx->npm))
                paddr = naddr;
 
        } else {
            paddr = start_addr + buf_offset;
 
            if (valid_npm(ctx->npm) && VMI_SUCCESS != vmi_nested_pagetable_lookup(vmi, 0, 0, ctx->npt, ctx->npm, paddr, &paddr, NULL))
                goto done;
        }
 
        /* determine how much we can write to this page */
        offset = (vmi->page_size - 1) & paddr;
        if ((offset + count) > vmi->page_size) {
            write_len = vmi->page_size - offset;
        } else {
            write_len = count;
        }
 
        /* do the write */
        if (VMI_FAILURE ==
                driver_write(vmi, paddr,
                             ((char *) buf + (addr_t) buf_offset),
                             write_len)) {
            goto done;
        }
 
        /* set variables for next loop */
        count -= write_len;
        buf_offset += write_len;
    }
 
    ret = VMI_SUCCESS;
 
done:
    if ( bytes_written )
        *bytes_written = buf_offset;
 
    return ret;
}

🌱 Back to Garden