static int devi_devctl(resmgr_context_t *ctp, io_devctl_t *msg, RESMGR_OCB_T *ocb) { devi_attr_t *attr; iov_t iov; char *buffer, *allocd; long dcmd; int error, nbytes; attr = ocb->ocb.attr; error = EOK; if ((error = iofunc_devctl(ctp, msg, &ocb->ocb, &attr->attr)) != _RESMGR_DEFAULT) return (error); /* ripped off from deva....:-) */ if (!(get_device_direction(dcmd = msg->i.dcmd) & DEVDIR_TOFROM)) nbytes = 0, buffer = allocd = NULL; else if ((nbytes = msg->i.nbytes) <= ctp->msg_max_size - sizeof(*msg)) buffer = _DEVCTL_DATA(*msg), allocd = NULL; else if ((buffer = allocd = malloc((nbytes + 3) & ~3)) == NULL) return (_RESMGR_ERRNO(ENOMEM)); else if ((get_device_direction(dcmd) & DEVDIR_TO)) { SETIOV(&iov, buffer, nbytes); if (resmgr_msgreadv(ctp, &iov, 1, sizeof(msg->i)) == -1) goto error_out; } /* TODO: now call a helper function to actually do the devctl returns < 0 on error, else nbytes to xfer back on EOK */ msg->o.ret_val = error; if (error == EOK && get_device_direction(dcmd) & DEVDIR_FROM) { SETIOV(&iov, buffer, nbytes); if (resmgr_msgwritev(ctp, &iov, 1, sizeof(msg->o)) == -1) goto error_out; } if (allocd != NULL) free(allocd); return((error == EOK) ? _RESMGR_PTR(ctp, &msg->o, sizeof(msg->o)) : _RESMGR_ERRNO(error)); error_out: error = errno; if (allocd != NULL) free(allocd); return(_RESMGR_ERRNO(error)); }
static int mem_read_write(resmgr_context_t *ctp, resmgr_iomsgs_t *msg, struct mem_ocb *ocb) { void *addr; unsigned nbytes; unsigned size; PROCESS *proc; union object *obp; unsigned *pos; unsigned offset; size_t skip; // IO_READ and IO_WRITE messages exactly overlay, as does XTYPE_OFFSET! if(!ocb) { nbytes = 0; goto ok; } if(!(ocb->ioflag & ((msg->type == _IO_READ) ? _IO_FLAG_RD : _IO_FLAG_WR))) { return EBADF; } nbytes = msg->read.i.nbytes; obp = ocb->object; if((msg->type == _IO_WRITE) && (ocb->ioflag & O_APPEND) && obp) { ocb->pos = OBJECT_SIZE(obp); } switch (msg->read.i.xtype & _IO_XTYPE_MASK) { case _IO_XTYPE_NONE: pos = &ocb->pos; skip = sizeof(msg->read.i); break; case _IO_XTYPE_OFFSET: offset = ((io_pread_t*)msg)->offset.offset; pos = &offset; skip = sizeof(io_pread_t); break; default: /* this really shouldn't happen, but just in case */ return ENOSYS; } proc = sysmgr_prp; size = obp ? OBJECT_SIZE(obp) : UINT_MAX; if( *pos > size - nbytes || *pos + nbytes > size) { if(obp && msg->type == _IO_WRITE) { int status; status = memmgr.resize(obp, *pos + nbytes); if(status != EOK) { return status; } size = OBJECT_SIZE(obp); } if(*pos >= size) { nbytes = 0; } else { nbytes = size - *pos; } } if(nbytes) { int status, err; int flags; part_id_t mpid; if(proc_thread_pool_reserve() != 0) { return EAGAIN; } ProcessBind(SYSMGR_PID); proc_wlock_adp(proc); flags = MAP_SHARED; if(obp != NULL) { proc_mux_lock(&obp->mem.mm.mux); mpid = obp->hdr.mpid; } else { flags |= MAP_PHYS; mpid = part_id_t_INVALID; } status = memmgr.mmap(proc, 0, nbytes, PROT_READ|PROT_WRITE, flags, obp, *pos, 0, nbytes, NOFD, &addr, &size, mpid); if(obp != NULL) proc_mux_unlock(&obp->mem.mm.mux); proc_unlock_adp(proc); if(status != EOK) { ProcessBind(0); proc_thread_pool_reserve_done(); return status; } SETIOV(ctp->iov + 0, addr, nbytes); if(msg->type == _IO_READ) { status = resmgr_msgwritev(ctp, ctp->iov + 0, 1, 0); } else { status = resmgr_msgreadv(ctp, ctp->iov + 0, 1, skip); } err = errno; proc_wlock_adp(proc); (void) memmgr.munmap(proc, (uintptr_t)addr, size, 0, mempart_getid(proc, sys_memclass_id)); proc_unlock_adp(proc); if(status == -1) { ProcessBind(0); proc_thread_pool_reserve_done(); return err; } *pos += nbytes; if(obp && msg->type == _IO_WRITE) { obp->mem.pm.mtime = time(0); } ProcessBind(0); proc_thread_pool_reserve_done(); } ok: _IO_SET_READ_NBYTES(ctp, nbytes); return EOK; }