/** Handle ac97 driver ioctl. * \par Description: * Handle ac97 driver ioctl. * \param psDriver - AC97 driver structure. * \param nCommand - Command. * \param pArgs - Args. * \param bFromKernel - Ioctl from kernel. * \author Arno Klenke *****************************************************************************/ status_t ac97_ioctl( AC97AudioDriver_s* psDriver, uint32 nCommand, void *pArgs, bool bFromKernel ) { switch( nCommand ) { case AC97_GET_CODEC_INFO: memcpy_to_user( pArgs, psDriver, sizeof( AC97AudioDriver_s ) ); break; case AC97_WAIT: { AC97RegOp_s sOp; memcpy_from_user( &sOp, pArgs, sizeof( AC97RegOp_s ) ); psDriver->pfWait( psDriver->pDriverData, sOp.nCodec ); } break; case AC97_READ: { AC97RegOp_s sOp; memcpy_from_user( &sOp, pArgs, sizeof( AC97RegOp_s ) ); sOp.nVal = ac97_read( psDriver, sOp.nCodec, sOp.nReg ); memcpy_to_user( pArgs, &sOp, sizeof( AC97RegOp_s ) ); } break; case AC97_WRITE: { AC97RegOp_s sOp; memcpy_from_user( &sOp, pArgs, sizeof( AC97RegOp_s ) ); ac97_write( psDriver, sOp.nCodec, sOp.nReg, sOp.nVal ); } break; default: return( -EINVAL ); } return( 0 ); }
status_t gfx_ioctl( void *pNode, void *pCookie, uint32 nCommand, void *pArgs, bool bFromKernel ) { struct gfx_node *psNode = pNode; int nError = 0; switch ( nCommand ) { case IOCTL_GET_APPSERVER_DRIVER: memcpy_to_user( pArgs, APPSERVER_DRIVER, strlen( APPSERVER_DRIVER ) ); break; case PCI_GFX_GET_PCI_INFO: memcpy_to_user( pArgs, &psNode->sInfo, sizeof( PCI_Info_s ) ); break; case PCI_GFX_READ_PCI_CONFIG: { struct gfx_pci_config sConfig; PCI_bus_s *psBus = get_busmanager( PCI_BUS_NAME, PCI_BUS_VERSION ); memcpy_from_user( &sConfig, pArgs, sizeof( struct gfx_pci_config ) ); if( psBus == NULL ) { nError = -ENODEV; } else { sConfig.m_nValue = psBus->read_pci_config( sConfig.m_nBus, sConfig.m_nDevice, sConfig.m_nFunction, sConfig.m_nOffset, sConfig.m_nSize ); memcpy_to_user( pArgs, &sConfig, sizeof( struct gfx_pci_config ) ); } } break; case PCI_GFX_WRITE_PCI_CONFIG: { struct gfx_pci_config sConfig; PCI_bus_s *psBus = get_busmanager( PCI_BUS_NAME, PCI_BUS_VERSION ); memcpy_from_user( &sConfig, pArgs, sizeof( struct gfx_pci_config ) ); if( psBus == NULL ) { nError = -ENODEV; } else { int nVal = psBus->write_pci_config( sConfig.m_nBus, sConfig.m_nDevice, sConfig.m_nFunction, sConfig.m_nOffset, sConfig.m_nSize, sConfig.m_nValue ); sConfig.m_nValue = nVal; memcpy_to_user( pArgs, &sConfig, sizeof( struct gfx_pci_config ) ); } } break; default: nError = -ENOIOCTLCMD; } return ( nError ); }
static int format_trapframe(struct hw_trapframe *hw_tf, char* buf, int bufsz) { // slightly hackish way to read out the instruction that faulted. // not guaranteed to be right 100% of the time uint32_t insn; if(!(current && !memcpy_from_user(current,&insn,(void*)hw_tf->epc,4))) insn = -1; int len = snprintf(buf,bufsz,"TRAP frame at %p on core %d\n", hw_tf, core_id()); static const char* regnames[] = { "z ", "ra", "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "sA", "sB", "sp", "tp", "v0", "v1", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "aA", "aB", "aC", "aD" }; hw_tf->gpr[0] = 0; for(int i = 0; i < 32; i+=4) { for(int j = 0; j < 4; j++) len += snprintf(buf+len, bufsz-len, "%s %016lx%c", regnames[i+j], hw_tf->gpr[i+j], j < 3 ? ' ' : '\n'); } len += snprintf(buf+len, bufsz-len, "sr %016lx pc %016lx va %016lx insn %08x\n", hw_tf->sr, hw_tf->epc, hw_tf->badvaddr, insn); buf[bufsz-1] = 0; return len; }
status_t sys_get_next_port_info( port_info * psInfo ) { port_info sInfo; MsgPort_s *psPort; port_id hPort; int nError; if ( memcpy_from_user( &hPort, &psInfo->pi_port_id, sizeof( hPort ) ) < 0 ) { return ( -EFAULT ); } lock_mutex( g_hPortListSema, true ); hPort = MArray_GetNextIndex( &g_sMsgPorts, hPort ); psPort = get_port_from_handle( hPort ); if ( psPort == NULL ) { nError = 0; goto error; } do_get_port_info( psPort, &sInfo ); nError = 1; if ( memcpy_to_user( psInfo, &sInfo, sizeof( sInfo ) ) < 0 ) { nError = -EFAULT; } error: unlock_mutex( g_hPortListSema ); return ( nError ); }
// Системный вызов syscall_nputs_color // Предоставляет процессам функцию nputs_color // Параметры те же, что и обычно. Строка не длиннее 255 символов. // Возвращает количество выведенных символов. // // FIXME: Нужно проверять наличие доступа к пользовательской // памяти. Предупреждать GP, PF (в смысле выхода за выделенную память. uint syscall_nputs_color(char *s, uint n, uchar attr) { uchar localbuf[256]; memcpy_from_user(localbuf, s, MIN(n, 256)); nputs_color(localbuf, MIN(n, 256), attr); return MIN(n, 256); }
static int set_modem_info( SerPort_s* psPort, int cmd, uint32* value, bool bFromKernel ) { int error; unsigned int arg; unsigned long flags; if ( bFromKernel ) { arg = *value; error = 0; } else { error = memcpy_from_user( &arg, value, sizeof(uint32) ); } if (error) return error; switch (cmd) { case TIOCMBIS: if (arg & TIOCM_RTS) psPort->sp_nMCR |= UART_MCR_RTS; if (arg & TIOCM_DTR) psPort->sp_nMCR |= UART_MCR_DTR; #ifdef TIOCM_OUT1 if (arg & TIOCM_OUT1) psPort->sp_nMCR |= UART_MCR_OUT1; if (arg & TIOCM_OUT2) psPort->sp_nMCR |= UART_MCR_OUT2; #endif break; case TIOCMBIC: if (arg & TIOCM_RTS) psPort->sp_nMCR &= ~UART_MCR_RTS; if (arg & TIOCM_DTR) psPort->sp_nMCR &= ~UART_MCR_DTR; #ifdef TIOCM_OUT1 if (arg & TIOCM_OUT1) psPort->sp_nMCR &= ~UART_MCR_OUT1; if (arg & TIOCM_OUT2) psPort->sp_nMCR &= ~UART_MCR_OUT2; #endif break; case TIOCMSET: psPort->sp_nMCR = ((psPort->sp_nMCR & ~(UART_MCR_RTS | #ifdef TIOCM_OUT1 UART_MCR_OUT1 |UART_MCR_OUT2 | #endif UART_MCR_DTR)) | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) #ifdef TIOCM_OUT1 | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0) | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0) #endif | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0)); break; default: return -EINVAL; } flags = spinlock_disable( &g_sSPinLock ); ser_out( psPort, UART_MCR, psPort->sp_nMCR ); spinunlock_enable( &g_sSPinLock, flags ); return 0; }
/** * Duplicate a string from user memory. * * Allocates a buffer large enough and copies across a string from user memory. * The allocation is not made using MM_WAIT, as there is no length limit and * therefore the length could be too large to fit in memory. Use of * strndup_from_user() is preferred to this. * * @param src Location to copy from. * @param destp Pointer to location in which to store address of * destination buffer. * * @return Status code describing result of the operation. * Returns STATUS_INVALID_ARG if the string is * zero-length. */ status_t strdup_from_user(const void *src, char **destp) { status_t ret; size_t len; char *d; ret = strlen_user(src, &len); if(ret != STATUS_SUCCESS) { return ret; } else if(len == 0) { return STATUS_INVALID_ARG; } d = kmalloc(len + 1, MM_USER); if(!d) return STATUS_NO_MEMORY; ret = memcpy_from_user(d, src, len); if(ret != STATUS_SUCCESS) { kfree(d); return ret; } d[len] = 0; *destp = d; return STATUS_SUCCESS; }
/* Same as above, but sets errno */ int memcpy_from_user_errno(struct proc *p, void *dst, const void *src, int len) { int error = memcpy_from_user(p, dst, src, len); if (unlikely(error < 0)) set_errno(-error); return error; }
/* Creates a buffer (kmalloc) and safely copies into it from va. Can return an * error code. Check its response with IS_ERR(). Must be paired with * user_memdup_free() if this succeeded. */ void *user_memdup(struct proc *p, const void *va, int len) { void* kva = NULL; if (len < 0 || (kva = kmalloc(len, 0)) == NULL) return ERR_PTR(-ENOMEM); if (memcpy_from_user(p, kva, va, len)) { kfree(kva); return ERR_PTR(-EFAULT); } return kva; }
int fd_write(int uid, int fd, const void *buf, uint32_t count) { uint8_t buff[512]; int i, j, cnt; for (j = 0; (j<<9) < count; j++) { cnt = (count-(j<<9)>512)?512:(count-(j<<9)); memcpy_from_user(buff, buf, cnt); kconsole_write(buff, cnt); } return count; }
static int set_termios( SerPort_s* psPort, struct termios* psInfo ) { struct termios sTermios; int nError; nError = memcpy_from_user( &sTermios, psInfo, sizeof( sTermios ) ); if ( nError < 0 ) { return( nError ); } if ( (psPort->sp_sTermios.c_cflag & CBAUD) != (sTermios.c_cflag & CBAUD) ) { uint32 nFlg; switch( sTermios.c_cflag & CBAUD ) { case B0: psPort->sp_nBaudRate = 0; case B50: psPort->sp_nBaudRate = 50; case B75: psPort->sp_nBaudRate = 75; case B110: psPort->sp_nBaudRate = 110; case B134: psPort->sp_nBaudRate = 134; case B150: psPort->sp_nBaudRate = 150; case B200: psPort->sp_nBaudRate = 200; case B300: psPort->sp_nBaudRate = 300; case B600: psPort->sp_nBaudRate = 600; case B1200: psPort->sp_nBaudRate = 1200; case B1800: psPort->sp_nBaudRate = 1800; case B2400: psPort->sp_nBaudRate = 2400; case B4800: psPort->sp_nBaudRate = 4800; case B9600: psPort->sp_nBaudRate = 9600; case B19200: psPort->sp_nBaudRate = 19200; case B38400: psPort->sp_nBaudRate = 38400; case B57600: psPort->sp_nBaudRate = 57600; case B115200: psPort->sp_nBaudRate = 115200; // case B230400: psPort->sp_nBaudRate = 230400; // case B460800: psPort->sp_nBaudRate = 460800; default: printk( "serial: set_termios() invalid baudrate %08x\n", sTermios.c_cflag & CBAUD ); return( -EINVAL ); } nFlg = spinlock_disable( &g_sSPinLock ); if ( psPort->sp_nBaudRate > 0 ) { uint nDivisor = 115200 / psPort->sp_nBaudRate; ser_out( psPort, UART_LCR, 0x83 ); // Set bit 7 to enable baud rate divisors ser_out( psPort, UART_DLL, nDivisor & 0xff ); // Baud rate divisor LSB ser_out( psPort, UART_DLM, nDivisor >> 8 ); // Baud rate divisor MSB ser_out( psPort, UART_LCR, 0x03 ); // Clr bit 7 to disable baud rate divisors }
/** * Copy a NULL-terminated array of strings from user memory. * * Copies a NULL-terminated array of strings from user memory. The array * itself and each array entry must be freed with kfree() once no longer * needed. * * @param src Array to copy. * @param arrayp Pointer to location in which to store address of * allocated array. * * @return Status code describing result of the operation. */ status_t arrcpy_from_user(const char *const src[], char ***arrayp) { char **array = NULL, **narr; status_t ret; int i; /* Copy the arrays across. */ for(i = 0; ; i++) { narr = krealloc(array, sizeof(char *) * (i + 1), MM_USER); if(!narr) { ret = STATUS_NO_MEMORY; goto fail; } array = narr; array[i] = NULL; ret = memcpy_from_user(&array[i], &src[i], sizeof(char *)); if(ret != STATUS_SUCCESS) { array[i] = NULL; goto fail; } else if(array[i] == NULL) { break; } ret = strdup_from_user(array[i], &array[i]); if(ret != STATUS_SUCCESS) { array[i] = NULL; goto fail; } } *arrayp = array; return STATUS_SUCCESS; fail: if(array) { for(i = 0; array[i] != NULL; i++) kfree(array[i]); kfree(array); } return ret; }
/** * Duplicate a string from user memory. * * Allocates a buffer large enough and copies across a string from user memory. * If the string is longer than the maximum length, then an error will be * returned. Because a length limit is provided, the allocation is made using * MM_WAIT - it is assumed that the limit is sensible. * * @param src Location to copy from. * @param max Maximum length allowed. * @param destp Pointer to location in which to store address of * destination buffer. * * @return Status code describing result of the operation. * Returns STATUS_INVALID_ARG if the string is * zero-length. */ status_t strndup_from_user(const void *src, size_t max, char **destp) { status_t ret; size_t len; char *d; ret = strlen_user(src, &len); if(ret != STATUS_SUCCESS) { return ret; } else if(len == 0) { return STATUS_INVALID_ARG; } else if(len > max) { return STATUS_TOO_LONG; } d = kmalloc(len + 1, MM_KERNEL); ret = memcpy_from_user(d, src, len); if(ret != STATUS_SUCCESS) { kfree(d); return ret; } d[len] = 0; *destp = d; return STATUS_SUCCESS; }