/******************************************************************************* * Function Name : uart_close * Description : Close the USART port communication * Input : - Uart: Select the USART or the UART peripheral. * Output : None * Return : 0 *******************************************************************************/ int uart_close(const _Uart_Descriptor *Uart) { /* Disable IT */ NVIC_DisableIRQ(Uart->IRQn); /* Free control variables and buffers */ if (*Uart->Ctrl) { if ((*Uart->Ctrl)->DmaBufSize) { USART_DMACmd(Uart->UARTx, USART_DMAReq_Rx, DISABLE); NVIC_DisableIRQ(Uart->DMAx_IRQn); DMA_DeInit(Uart->DMAy_Streamx); } if (((*Uart->Ctrl)->HwCtrl & UART_HW_FLOW_CTRL_RX) || ((*Uart->Ctrl)->HwCtrl & UART_HALF_DUPLEX)) gpio_init((*Uart->Ctrl)->Gpio); _sys_free(*Uart->Ctrl); *Uart->Ctrl = 0; } /* Deactivate UART peripheral */ USART_DeInit(Uart->UARTx); /* Disable peripheral clock */ (*Uart->RCC_APBxPeriphClockCmd)(Uart->RCC_APBxPeriph, DISABLE); /* Configure GPIO to default state */ gpio_init(Uart->TxGpio); gpio_init(Uart->RxGpio); return(0); }
/* @description: Heapify helper for _sort. */ void do_heap(uint8_t *base, size_t i, size_t n, size_t size, _cmp_func_t cmp) { /* Not much can be done when size is unknown */ void *temp = _sys_alloc(size); size_t k; /* Save the node that's being overwritten below */ memcpy(temp, &base[i * size], size); /* Move all subsequent child nodes into place to maintain the heap property */ for (k = i * 2 + 1; k < n; k = i * 2 + 1) { /* Find the next child node */ if (k + 1 < n && cmp(&base[k * size], &base[(k + 1) * size]) < 0) ++k; /* Are we at the saved node's sorted position? */ if (cmp(temp, &base[k * size]) >= 0) break; /* Overwrite the parent with one of its children */ memcpy(&base[i * size], &base[k * size], size); i = k; } /* Copy the saved node into its final resting place */ memcpy(&base[i * size], temp, size); _sys_free(temp); }
/*------------------------------------------- | Name:_syscall_free | Description: | Parameters: | Return Type: | Comments: | See: ---------------------------------------------*/ int _syscall_free(kernel_pthread_t* pthread_ptr, pid_t pid, void* data){ free_t* free_dt = (free_t*)data; _sys_free(free_dt->p); __flush_syscall(pthread_ptr); __kernel_ret_int(pthread_ptr); return 0; }
/*------------------------------------------- | Name:_syscall_closedir | Description: | Parameters: | Return Type: | Comments: | See: ---------------------------------------------*/ int _syscall_closedir(kernel_pthread_t* pthread_ptr, pid_t pid, void* data){ closedir_t* closedir_dt = (closedir_t*)data; desc_t desc = closedir_dt->dir->desc; closedir_dt->ret = _vfs_closedir(closedir_dt->dir->desc); //free struct dirent (see _syscall_readdir() ) if(ofile_lst[desc].p) _sys_free(ofile_lst[desc].p); ofile_lst[desc].p=(void*)0; __flush_syscall(pthread_ptr); __kernel_ret_int(pthread_ptr); return 0; }
/* @description: qsort-friendly implementation of heapsort for guaranteed time complexity. */ void _sort(void *base, size_t n, size_t size, _cmp_func_t cmp) { /* Not much can be done when size is unknown */ void *temp = _sys_alloc(size); uint8_t *p = (uint8_t*)base; int i = n / 2; /* Heapify the array */ while (i-- > 0) do_heap(p, i, n, size, cmp); /* Extrac the heap max and place it in sorted position */ while (--n < (size_t)-1) { /* Swap the heap max with base[n] */ memcpy(temp, p, size); memcpy(p, &p[n * size], size); memcpy(&p[n * size], temp, size); /* Re-heapify after removing the heap max */ do_heap(p, 0, n, size, cmp); } _sys_free(temp); }
/******************************************************************************* * Function Name : uart_open * Description : Open the UART port communication * Input : - Uart: Select the USART or the UART peripheral * : - BaudRate: Baud rate configuration * : - DmaBufSize: DMA buffer size * : - RxBufSize: Receive buffer size * : - TxBufSize: Transmit buffer size * : - HwCtrl: Hardware control options * : - Gpio: GPIO used for hardware control * Output : None * Return : 0 if OK, -1 in case of error *******************************************************************************/ int uart_open (const _Uart_Descriptor *Uart, u32 BaudRate, u8 DmaBufSize, u16 RxBufSize, u16 TxBufSize, u8 HwCtrl, const _Gpio_Descriptor *Gpio) { USART_InitTypeDef usart_init_structure; DMA_InitTypeDef dma_init_structure; NVIC_InitTypeDef NVIC_InitStructure; /* Init control variables and bufers */ if (*Uart->Ctrl) _sys_free(*Uart->Ctrl); if ((*Uart->Ctrl = _sys_malloc(sizeof(_Uart_Ctrl) + DmaBufSize + RxBufSize + TxBufSize)) == 0) return(-1); memset(*Uart->Ctrl, 0, sizeof(_Uart_Ctrl)); (*Uart->Ctrl)->DmaBufPtr = (char *)*Uart->Ctrl + sizeof(_Uart_Ctrl); (*Uart->Ctrl)->DmaBufSize = DmaBufSize; (*Uart->Ctrl)->iDma = DmaBufSize; (*Uart->Ctrl)->RxBufSize = RxBufSize; (*Uart->Ctrl)->RxBufPtr = (*Uart->Ctrl)->DmaBufPtr + (*Uart->Ctrl)->DmaBufSize; (*Uart->Ctrl)->TxBufSize = TxBufSize; (*Uart->Ctrl)->TxBufPtr = (*Uart->Ctrl)->RxBufPtr + (*Uart->Ctrl)->RxBufSize; (*Uart->Ctrl)->HwCtrl = HwCtrl; (*Uart->Ctrl)->Gpio = Gpio; #ifdef _UART_OS_SUPPORT (*Uart->Ctrl)->Event = SYS_EVT_INCOMING_DATA; (*Uart->Ctrl)->Task = sys_task_self(); #endif /* Enable peripheral clock */ (*Uart->RCC_APBxPeriphClockCmd)(Uart->RCC_APBxPeriph, ENABLE); /* Init GPIO */ gpio_set_function(Uart->TxGpio, Uart->GPIO_AF); gpio_set_function(Uart->RxGpio, Uart->GPIO_AF); gpio_set_mode(Uart->TxGpio, GPIO_MODE_AF, 0); gpio_set_mode(Uart->RxGpio, GPIO_MODE_AF, 0); if ((*Uart->Ctrl)->HwCtrl & (UART_HW_FLOW_CTRL_RX | UART_HALF_DUPLEX)) gpio_set_mode((*Uart->Ctrl)->Gpio, GPIO_FCT_OUT, 0); /* Init UART peripheral */ USART_DeInit(Uart->UARTx); USART_StructInit(&usart_init_structure); usart_init_structure.USART_BaudRate = BaudRate; if ((*Uart->Ctrl)->HwCtrl & UART_HW_FLOW_CTRL_TX) usart_init_structure.USART_HardwareFlowControl = USART_HardwareFlowControl_CTS; USART_Init(Uart->UARTx, &usart_init_structure); /* Configure DMA (if used) */ if ((*Uart->Ctrl)->DmaBufSize) { DMA_DeInit(Uart->DMAy_Streamx); DMA_StructInit(&dma_init_structure); dma_init_structure.DMA_Channel = Uart->DMA_Channel; dma_init_structure.DMA_PeripheralBaseAddr = (u32)&Uart->UARTx->DR; dma_init_structure.DMA_Memory0BaseAddr = (u32)(*Uart->Ctrl)->DmaBufPtr; dma_init_structure.DMA_BufferSize = (*Uart->Ctrl)->DmaBufSize; dma_init_structure.DMA_MemoryInc = DMA_MemoryInc_Enable; dma_init_structure.DMA_Mode = DMA_Mode_Circular; dma_init_structure.DMA_Priority = DMA_Priority_Medium; dma_init_structure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_Init(Uart->DMAy_Streamx, &dma_init_structure); DMA_ITConfig(Uart->DMAy_Streamx, DMA_IT_TC | DMA_IT_HT, ENABLE); DMA_Cmd(Uart->DMAy_Streamx, ENABLE); NVIC_EnableIRQ(Uart->DMAx_IRQn); // //NVIC_SetPriority((IRQn_Type)Uart->DMAx_IRQn, (uint32_t)129); NVIC_SetPriority((IRQn_Type)Uart->DMAx_IRQn, (1 << __NVIC_PRIO_BITS) -3); // USART_DMACmd(Uart->UARTx, USART_DMAReq_Rx, ENABLE); USART_ITConfig(Uart->UARTx, USART_IT_IDLE, ENABLE); } else USART_ITConfig(Uart->UARTx, USART_IT_RXNE, ENABLE); /* Enable IT and start peripheral */ //NVIC_InitStructure.NVIC_IRQChannel = Uart->IRQn; // we want to configure the USART1 interrupts //NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;// this sets the priority group of the USART1 interrupts //NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // this sets the subpriority inside the group //NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // the USART1 interrupts are globally enabled //NVIC_Init(&NVIC_InitStructure); // //NVIC_SetPriority((IRQn_Type)Uart->IRQn, (uint32_t)129); NVIC_SetPriority((IRQn_Type)Uart->IRQn, (1 << __NVIC_PRIO_BITS) -4); // USART_ITConfig(Uart->UARTx, USART_IT_TC, ENABLE); NVIC_EnableIRQ(Uart->IRQn); USART_Cmd(Uart->UARTx, ENABLE); while (!gpio_read(Uart->TxGpio)); return(0); }
/*------------------------------------------- | Name:_syscall_exit | Description: | Parameters: | Return Type: | Comments: | See: ---------------------------------------------*/ int _syscall_exit(kernel_pthread_t* pthread_ptr, pid_t pid, void* data){ pid_t ppid = process_lst[pid]->ppid; exit_t* exit_dt=(exit_t*)data; if(process_lst[pid]->pthread_ptr->parent_pthread_ptr && process_lst[pid]->pthread_ptr->parent_pthread_ptr->stat&PTHREAD_STATUS_FORK ){ kernel_pthread_t* parent_pthread_ptr= process_lst[pid]->pthread_ptr; fork_t* fork_dt; //close all process(pid) file descriptor //must be execute before __atomic_in() and __stop_sched() //because in some _vfs_close() operation on driver, this operation need inter pthread communication to be completed //(ex: lwip_sock_close() deadlock risk); _close_process_fd(pid); //atomic code no task switching __atomic_in(); //wakeup locked process _sys_unlockw(); //warning all!!! micro-kernel operation is not advised. __stop_sched(); fork_dt=(fork_t*)pthread_ptr->parent_pthread_ptr->reg.data; //restore father context _sys_vfork_exit(pthread_ptr,exit_dt->status); //restart father fork_dt->pid=pid; __flush_syscall(pthread_ptr); __restart_sched(); __flush_syscall(parent_pthread_ptr); __kernel_ret_int(parent_pthread_ptr); //father }else { //close all process(pid) file descriptor //must be execute before __atomic_in() and __stop_sched() //because in some _vfs_close() operation on driver, this operation need inter pthread communication to be completed //(ex: lwip_sock_close() deadlock risk); _close_process_fd(exit_dt->pid); //atomic code no task switching __atomic_in(); //wakeup locked process _sys_unlockw(); //warning!!! all micro-kernel operation is not advised. __stop_sched(); // _sys_exit(exit_dt->pid,exit_dt->status); // __flush_syscall(pthread_ptr); //ppid threads are on waitpid()? if( ppid) { //get main thread of father process kernel_pthread_t* _pthread_ptr=process_lst[ppid]->pthread_ptr; //walking on threads chained list in parent process while(_pthread_ptr) { //is thread blocked on waitpid()? if(_pthread_ptr->stat&PTHREAD_STATUS_STOP && _pthread_ptr->reg.syscall==_SYSCALL_WAITPID){ waitpid_t* waitpid_dt = (waitpid_t*)_pthread_ptr->reg.data; //waitpid_dt->pid = pid; _syscall_waitpid(_pthread_ptr,ppid,waitpid_dt); }else{ //not then send sig child to all pthread of father processus _sys_kill(_pthread_ptr,SIGCHLD,1); //send 1 times an only the signal to the first pthread which accept SIGCHLD //better conformance with posix specification break; } _pthread_ptr=_pthread_ptr->next; } }else{ pid_t _pid; //it's a daemon process //free process _sys_free(process_lst[pid]); process_lst[pid]= 0; _dbg_printf("free(%d)\n",pid); //checkif it's the last process for(_pid=1; _pid<=PROCESS_MAX; _pid++) if(process_lst[_pid]) goto end; return -1; //in this case stop all } // } end: __restart_sched(); __atomic_out(); return 0; }
/*------------------------------------------- | Name:_sys_vfork | Description: | Parameters: | Return Type: | Comments: | See: ---------------------------------------------*/ pid_t _sys_vfork(kernel_pthread_t* pthread_ptr){ //to do: copy all father process descriptor pid_t pid = 0; pid_t ppid = pthread_ptr->pid; char* p; struct __timeval tv; int argc; kernel_pthread_t* backup_parent_pthread_ptr; // #ifdef KERNEL_PROCESS_VFORK_CLRSET_IRQ __clr_irq(); #endif //profiler __kernel_profiler_start(); // //1)process operation //pseudo process creation if(_nextpid(&pid)==-EAGAIN) { //kernel panic!!! #ifdef KERNEL_PROCESS_VFORK_CLRSET_IRQ __set_irq(); #endif return (pid_t)-ENOMEM; } //dynamic allocation:alloc p = _sys_malloc(sizeof(process_t)); if(!p) { //kernel panic!!! #ifdef KERNEL_PROCESS_VFORK_CLRSET_IRQ __set_irq(); #endif return (pid_t)(-ENOMEM); } process_lst[pid] = (process_t*)p; memset(process_lst[pid],0,sizeof(process_t)); // //_dbg_printf("fork _pid:%d\n",_pid); //copy all ppid father process properties to the son (pthread_ptr, ...) memcpy(process_lst[pid],process_lst[ppid],sizeof(process_t)); //modify specific process properties of new process _sys_gettimeofday(&tv,NULL); process_lst[pid]->pid = pid; process_lst[pid]->ppid = ppid; process_lst[pid]->pgid = process_lst[ppid]->pgid; process_lst[pid]->start_time = tv.tv_sec; //prepare kernel object chained list (see _sys_krnl_exec() ) process_lst[pid]->kernel_object_head = (kernel_object_t*)0; process_lst[pid]->inode_curdir = process_lst[ppid]->inode_curdir; //copy argument argc=0; process_lst[pid]->argc=0; process_lst[pid]->argv[argc]=strtok(process_lst[pid]->arg," "); while(process_lst[pid]->argv[argc++]) { process_lst[pid]->argv[argc]=strtok(0," "); } process_lst[pid]->argc=argc-1; //2)pthread operation backup_parent_pthread_ptr=(kernel_pthread_t*)_sys_malloc(sizeof(kernel_pthread_t)); if(!backup_parent_pthread_ptr) { // _sys_free(process_lst[pid]); //kernel panic!!! #ifdef KERNEL_PROCESS_VFORK_CLRSET_IRQ __set_irq(); #endif return -ENOMEM; //kernel panic!!! } //brutal copy parent pthread in new pthread memcpy(backup_parent_pthread_ptr,pthread_ptr,sizeof(kernel_pthread_t)); //switch pthread_ptr process_lst[pid]->pthread_ptr=pthread_ptr; process_lst[pid]->pthread_ptr->parent_pthread_ptr = backup_parent_pthread_ptr; //back_up calling thread context in parent pthread __bckup_context(backup_parent_pthread_ptr->bckup_context,backup_parent_pthread_ptr); //back_up ppid stack in parent pthread //must be placed after process_t allocation. heap external fragmentation. // see process.c _sys_exec and restore stack __bckup_stack(backup_parent_pthread_ptr); //to remove: _dbg_printf("vfork() pid:%d\n",pid); //attach thread with process process_lst[pid]->pthread_ptr->pid = pid; //reinit status process_lst[pid]->pthread_ptr->stat = PTHREAD_STATUS_NULL; // process_lst[pid]->pthread_ptr->time_out = (time_t)-1; //for alarm() //retinit parent thread status process_lst[pid]->pthread_ptr->parent_pthread_ptr->stat |= PTHREAD_STATUS_FORK; //remove pthread from the pthread list of father process _sys_process_remove_pthread(process_lst[ppid],pthread_ptr); //reinit thread chain list in new process container process_lst[pid]->pthread_ptr->next = (kernel_pthread_t*)0; //(not need kernel_put_pthread_id() and kernel_get_pthread_id() operation) //to do: reinit sigqueue struct //thread sigqueue #ifdef __KERNEL_POSIX_REALTIME_SIGNALS memcpy(&process_lst[pid]->pthread_ptr->kernel_sigqueue,&_kernel_sigqueue_initializer,sizeof(kernel_sigqueue_t)); process_lst[pid]->pthread_ptr->kernel_sigqueue.constructor(&process_lst[pid]->kernel_object_head, &process_lst[pid]->pthread_ptr->kernel_sigqueue); #endif //profiler __kernel_profiler_stop(backup_parent_pthread_ptr); __profiler_add_result(backup_parent_pthread_ptr,_SYSCALL_VFORK,__kernel_profiler_get_counter(backup_parent_pthread_ptr)); // #ifdef KERNEL_PROCESS_VFORK_CLRSET_IRQ __set_irq(); #endif return pid; }
/*-------------------------------------------- | Name: kernel_object_free | Description: | Parameters: none | Return Type: none | Comments: | See: ----------------------------------------------*/ int kernel_object_free(kernel_object_t* p){ if(!p) return -1; _sys_free(p); return 0; }