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;
}