/** * <Ring 1> This routine handles DEV_READ and DEV_WRITE message. * * @param p Message ptr. *****************************************************************************/ PRIVATE void hd_rdwt(MESSAGE * p) { // p->DEVICE 為 0x20,也就是 hd2a int pDev = p->DEVICE; int drive = DRV_OF_DEV(p->DEVICE); u64 pos = p->POSITION; assert((pos >> SECTOR_SIZE_SHIFT) < (1 << 31)); /** * We only allow to R/W from a SECTOR boundary: */ assert((pos & 0x1FF) == 0); u32 sect_nr = (u32)(pos >> SECTOR_SIZE_SHIFT); /* pos / SECTOR_SIZE */ //取出logic index int logidx = (p->DEVICE - MINOR_hd1a) % NR_SUB_PER_DRIVE; // 找出某個partition的LBA, // MAX_PRIM=9,代表Hd0~Hd9為primary的編號,超過9以上的編號都是logic sect_nr += p->DEVICE < MAX_PRIM ? hd_info[drive].primary[p->DEVICE].base : hd_info[drive].logical[logidx].base; ERIC_HD("\nHDRW=%x", sect_nr); struct hd_cmd cmd; cmd.features = 0; cmd.count = (p->CNT + SECTOR_SIZE - 1) / SECTOR_SIZE; cmd.lba_low = sect_nr & 0xFF; cmd.lba_mid = (sect_nr >> 8) & 0xFF; cmd.lba_high= (sect_nr >> 16) & 0xFF; cmd.device = MAKE_DEVICE_REG(1, drive, (sect_nr >> 24) & 0xF); cmd.command = (p->type == DEV_READ) ? ATA_READ : ATA_WRITE; hd_cmd_out(&cmd); int bytes_left = p->CNT; void * la = (void*)va2la(p->PROC_NR, p->BUF); while (bytes_left) { //一次只讀512 byte int bytes = min(SECTOR_SIZE, bytes_left); if (p->type == DEV_READ) { interrupt_wait(); port_read(REG_DATA, hdbuf, SECTOR_SIZE); phys_copy(la, (void*)va2la(TASK_HD, hdbuf), bytes); } else { if (!waitfor(STATUS_DRQ, STATUS_DRQ, HD_TIMEOUT)) panic("hd writing error."); port_write(REG_DATA, la, bytes); interrupt_wait(); } bytes_left -= SECTOR_SIZE; la += SECTOR_SIZE; } }
PUBLIC void register_filesystem(MESSAGE * m){ struct file_system * tmp; memcpy(va2la(TASK_FS, tmp), va2la(m->source, m->BUF), sizeof(struct file_system)); printl("VFS: Register filesystem: name: %s\n", tmp->name); if (file_systems == NULL) { file_systems = tmp; } }
/************************************************************************************************** * msg_send ************************************************************************************************** * <Ring 0> Send a message to the dest proc. If dest is blocked waiting for the message, * copy the message to it and unblock dest. * Otherwise the caller will be blocked and appended to the dest's sending queue. * * @param current The caller, the sender. * @param dest To whom the message is sent. * @param msg Pointer to the MESSAGE struct. * * @return 0 if success. *************************************************************************************************/ PRIVATE int msg_send(PROCESS* current, int dest, MESSAGE* msg){ PROCESS* sender = current; PROCESS* p_dest = proc_table + dest; assert(proc2pid(sender) != dest); if(deadlock(proc2pid(sender), dest)){ /* Is there deadlock chain? */ panic(">>DEADLOCK<< %s->%s", sender->name, p_dest->name); } /* dest is waiting for that msg or ANY msg. */ if((p_dest->flags & RECEIVING) && (p_dest->recv_from == proc2pid(sender) || p_dest->recv_from == ANY)){ assert(p_dest->p_msg); assert(msg); phys_copy(va2la(dest, p_dest->p_msg), va2la(proc2pid(sender), msg), sizeof(MESSAGE)); p_dest->p_msg = 0; p_dest->flags &= ~RECEIVING; /* dest has received the message */ p_dest->recv_from = NO_TASK; unblock(p_dest); assert(p_dest->flags == 0); assert(p_dest->p_msg == 0); assert(p_dest->recv_from == NO_TASK); assert(p_dest->send_to == NO_TASK); assert(sender->flags == 0); assert(sender->p_msg == 0); assert(sender->recv_from == NO_TASK); assert(sender->send_to == NO_TASK); }else{ /* However, dest is not waiting for the message */ sender->flags |= SENDING; assert(sender->flags == SENDING); sender->send_to = dest; sender->p_msg = msg; /* append to the sending queue */ PROCESS* p; if(p_dest->q_sending){ p = p_dest->q_sending; while(p->next_sending){ p = p->next_sending; } p->next_sending = sender; }else{ p_dest->q_sending = sender; } sender->next_sending = 0; block(sender); assert(sender->flags == SENDING); assert(sender->p_msg != 0); assert(sender->recv_from == NO_TASK); assert(sender->send_to == dest); } return 0; }
/* * <ring 1> this routine handles DEV_READ and DEV_WRITE message. * * @param msg - message */ static void hd_rdwt(MESSAGE *msg) { int drive = DRV_OF_DEV(msg->DEVICE); u64 pos = msg->POSITION; assert((pos >> SECTOR_SIZE_SHIFT) < (1 << 31)); assert((pos & 0x1ff) == 0); u32 sect_nr = (u32)(pos >> SECTOR_SIZE_SHIFT); int logidx = (msg->DEVICE - MINOR_hd1a) % NR_SUB_PER_DRIVE; sect_nr += msg->DEVICE < MAX_PRIM ? hd_info[drive].primary[msg->DEVICE].base : hd_info[drive].logical[logidx].base; struct hd_cmd cmd; cmd.features = 0; cmd.count = (msg->CNT + SECTOR_SIZE - 1) / SECTOR_SIZE; cmd.lba_low = sect_nr & 0xff; cmd.lba_mid = (sect_nr >> 8) & 0xff; cmd.lba_high = (sect_nr >> 16) & 0xff; cmd.device = MAKE_DEVICE_REG(1, drive, (sect_nr >> 24) & 0xf); cmd.command = (msg->type == DEV_READ) ? ATA_READ : ATA_WRITE; hd_cmd_out(&cmd); int bytes_left = msg->CNT; void *la = (void*)va2la(msg->PROC_NR, msg->BUF); while (bytes_left > 0) { int bytes = min(SECTOR_SIZE, bytes_left); if (msg->type == DEV_READ) { interrupt_wait(); port_read(REG_DATA, hdbuf, SECTOR_SIZE); phys_copy(la, (void*)va2la(TASK_HD, hdbuf), bytes); } else { if (!waitfor(STATUS_DRQ, STATUS_DRQ, HD_TIMEOUT)) { panic("hd writing error."); } port_write(REG_DATA, la, bytes); interrupt_wait(); } bytes_left -= SECTOR_SIZE; la += SECTOR_SIZE; } }
/* 1.函数内部需要注意:while(1),while(-1)都会执行循环体,只有while(0)时才跳出循环体 2.目前只能处理读写数据长度为SECTOR_SIZE整数倍的请求,否则会出错 */ static void hd_rdwt(MESSAGE *message){ int hd_index=HD_INDEX(message->device); int hd_part_index=HD_PART_INDEX(message->device); u64 position=message->position; #ifdef DEBUG_HD printl("position=%d\n",position); #endif assert((position>>SECTOR_SIZE_SHIFT)<(1<<31),""); assert(position%SECTOR_SIZE==0,"hd readwrite start position must be the multiple of SECTOR_SIZE");//读取的起始位置必须在扇区的起始位置 HD_COMMAND hd_command; u32 base=get_part_info(&hd_info[hd_index],hd_part_index)->base; u32 sector_index=base+(u32)(position>>SECTOR_SIZE_SHIFT); int sector_length=(message->length+SECTOR_SIZE-1)/SECTOR_SIZE; int cmd=(message->type==INFO_FS_READ)?ATA_READ:ATA_WRITE; set_command(&hd_command,hd_index,0,0,sector_length,sector_index,cmd); hd_command_out(&hd_command); int bytes_left=message->length; #ifdef DEBUG_HD printl("sector_index=%d sector_length=%d bytes_left=%d\n",sector_index,sector_length,bytes_left); #endif void *la=(void *)va2la(message->source_pid,message->arg_pointer); #ifdef DEBUG_HD printl("source_pid=%d la[0]=%d\n",message->source_pid,*(int*)la); #endif //此处需要注意:while(1),while(-1)都会执行循环体,只有while(0)时才跳出循环体 while(bytes_left>0){ int bytes=min(SECTOR_SIZE,bytes_left); if(message->type==INFO_FS_READ){ interrupt_wait(); port_read(REG_P_DATA,hdbuf,SECTOR_SIZE); memcpy(la,(void *)va2la(TASK_HD,hdbuf),bytes); }else{ if(!wait_for(STATUS_DRQ_MASK,STATUS_DRQ,HD_TIME_OUT)) panic("hd writing error!\n"); /* printl("bytes=%d",bytes); */ port_write(REG_P_DATA,la,bytes); /* printl("test1"); */ interrupt_wait(); /* printl("test2"); */ } bytes_left-=bytes; la+=bytes; /* printl("(bytes_left>0)=%d\n",bytes_left>0); */ } #ifdef DEBUG_HD printl("hd_rdwt ok!\n"); #endif }
PRIVATE void hd_ioctl(MESSAGE* p_msg) { int device = p_msg -> DEVICE; int drive = DRV_OF_DEV(device); HD_INFO* hdi = &hd_info[drive]; if (p_msg -> REQUEST == DIOCTL_GET_GEO) { void* dst = va2la(p_msg -> PROC_NR, p_msg -> BUF); void* src = va2la(TASK_HD, device < MAX_PRIM ? &hdi->primary[drive] : &hdi->logical[(device - MINOR_hd1a) % NR_SUB_PER_DRIVE]); memcpy(dst, src, sizeof(PART_ENT)); } else { spin("HD No IO CTL"); } }
/** * Perform syslog() system call . * * @return *****************************************************************************/ PUBLIC int do_disklog() { char buf[STR_DEFAULT_LEN]; /* get parameters from the message */ int str_len = fs_msg.CNT; /* length of filename */ int src = fs_msg.source; /* caller proc nr. */ assert(str_len < STR_DEFAULT_LEN); phys_copy((void*)va2la(TASK_FS, buf), /* to */ (void*)va2la(src, fs_msg.BUF), /* from */ str_len); buf[str_len] = 0; /* terminate the string */ return disklog(buf); }
/***************************************************************************** * do_stat *************************************************************************//** * Perform the stat() syscall. * * @return On success, zero is returned. On error, -1 is returned. *****************************************************************************/ PUBLIC int do_stat() { char pathname[MAX_PATH]; /* parameter from the caller */ char filename[MAX_PATH]; /* directory has been stipped */ /* get parameters from the message */ int name_len = fs_msg.NAME_LEN; /* length of filename */ int src = fs_msg.source; /* caller proc nr. */ assert(name_len < MAX_PATH); phys_copy((void*)va2la(TASK_FS, pathname), /* to */ (void*)va2la(src, fs_msg.PATHNAME), /* from */ name_len); pathname[name_len] = 0; /* terminate the string */ int inode_nr = search_file(pathname); if (inode_nr == INVALID_INODE) { /* file not found */ printl("{FS} FS::do_stat():: search_file() returns " "invalid inode: %s\n", pathname); return -1; } struct inode * pin = 0; struct inode * dir_inode; if (strip_path(filename, pathname, &dir_inode) != 0) { /* theoretically never fail here * (it would have failed earlier when * search_file() was called) */ assert(0); } pin = get_inode(dir_inode->i_dev, inode_nr); struct stat s; /* the thing requested */ s.st_dev = pin->i_dev; s.st_ino = pin->i_num; s.st_mode= pin->i_mode; s.st_rdev= is_special(pin->i_mode) ? pin->i_start_sect : NO_DEV; s.st_size= pin->i_size; put_inode(pin); phys_copy((void*)va2la(src, fs_msg.BUF), /* to */ (void*)va2la(TASK_FS, &s), /* from */ sizeof(struct stat)); return 0; }
PUBLIC int sys_sendrec(PROCESS *p, int function, int src_dest, MESSAGE *m) { assert(k_reenter == 0); assert((src_dest >= 0 && src_dest < NR_TASKS + NR_PROCS) || src_dest == ANY || src_dest == INTERRUPT); int ret = 0; int caller = proc2pid(p); MESSAGE *mla = (MESSAGE *)va2la(caller, m); mla->source = caller; assert(mla->source != src_dest); if (function == SEND) { ret = msg_send(p, src_dest, m); } else if (function == RECEIVE) { ret = msg_receive(p, src_dest, m); } else { panic("{sys_sendrec} invalid function: " "%d (SEND:%d, RECEIVE:%d).", function, SEND, RECEIVE); } return ret; }
/************************************************************************************************** * sys_sendrec ************************************************************************************************** * <Ring 0> The core routine of system call 'sendrec'. * * @param function SEND, RECEIVE, BOTH * @param src_dest To / From whom the message is transferred * @param msg Pointer to the MESSAGE struct * @param proc The caller process * * @return 0 if success *************************************************************************************************/ PUBLIC int sys_sendrec(int function, int src_dest, MESSAGE* msg, PROCESS* proc){ assert(k_reenter == 0); /* make sure we are not in ring0 */ assert((src_dest >= 0 && src_dest < NR_TASKS + NR_PROCS) || src_dest == ANY || src_dest == INTERRUPT); int ret = 0; int caller = proc2pid(proc); MESSAGE* mla = (MESSAGE*) va2la(caller, msg); mla->source = caller; /* from caller */ assert(mla->source != src_dest); /** * Actually we have the third message type: BOTH. However, it is not allowed to be passed * to the kernel directly. Kernel doesn't know it at all. It is transformed into a SEND * followed by RECEIVE by 'send_recv()'. */ if(function == SEND){ ret = msg_send(proc, src_dest, msg); if(ret != 0){ return ret; } }else if(function == RECEIVE){ ret = msg_receive(proc, src_dest, msg); if(ret != 0){ return ret; } }else{ panic("{sys_sendrec} invalid function: %d (SEND: %d, RECEIVE: %d).", function, SEND, RECEIVE); } return 0; }
PRIVATE void hd_ioctl(MESSAGE *p) { int device = p->DEVICE; int drive = DRV_OF_DEV(device); struct hd_info *hdi = &hdinfo[drive]; if (p->REQUEST == DIOCTL_GET_GEO) { void *dst = va2la(p->PROC_NR, p->BUF); void *src = va2la(TASK_HD, device < MAX_PRIM ? &hdi->primary[device] : &hdi->logical[(device - MINOR_hd1a) % NR_SUB_PER_DRIVE]); phys_copy(dst, src, sizeof (struct part_info)); } else { kprintf("[KERNEL ERROR]error ioctl cmd\n"); } }
PRIVAATE void hd_rdwt(MESSAGE *p) { int drive = DRV_OF_DEV(p->DEVICE); u64_t pos = p->POSITION; u32_t sect_nr = (u32_t)(pos >> SECTOR_SIZE_SHIFT); int logidx = (p->DEVICE - MINOR_HD1a) % NR_SUB_PER_DRIVE; sect_nr += p->DEVICE < MAX_PRIM ? hd_info[drive].primary[p->DEVICE].base : hd_info[drive].logical[logidx].base; struct hd_cmd cmd; cmd.features = 0; cmd.count = (p->CNT + SECTOR_SIZE - 1) / SECTOR_SIZE; cmd.lba_low = sect_nr & 0xff; cmd.lba_mid = (sect_nr >> 8) & 0xff; cmd.lba_high = (sect_nr >> 16) & 0xff; cmd.device = MAKE_DEVICE_REG(1, drive, (sect_nr >> 24) & 0xf); cmd.command = (p->type == DEV_READ) ? ATA_READ : ATA_WRITE; hd_cmd_out(&cmd); int bytes_left = p->CNT; void *la = (void*)va2la(p->PROC_NR, p->BUF); while (bytes_left) { int bytes = min(SECTOR_SIZE, bytes_left); if (p->type == DEV_READ) { interrupt_wait(); port_read(REG_DATA, hdbuf, SECTOR_SIZE); phys_copy(la, (void*)va2la(TASK_HD, hdbuf), bytes); } else { if (!waitfor(STATUS_DRQ, STATUS_DRQ, HD_TIMEOUT)) { kprintf("[KERNEL ERROR]hd writing error.\n"); break; } port_write(REG_DATA, la, bytes); interrupt_wait(); } bytes_left -= SECTOR_SIZE; la += SECTOR_SIZE; } }
/** * Invoked when task TTY receives DEV_WRITE message. * * @param tty To which TTY the calller proc is bound. * @param msg The MESSAGE. *****************************************************************************/ PRIVATE void tty_do_write(TTY* tty, MESSAGE* msg) { char buf[TTY_OUT_BUF_LEN]; char * p = (char*)va2la(msg->PROC_NR, msg->BUF); int i = msg->CNT; int j; while (i) { int bytes = min(TTY_OUT_BUF_LEN, i); phys_copy(va2la(TASK_TTY, buf), (void*)p, bytes); for (j = 0; j < bytes; j++) out_char(tty->console, buf[j]); i -= bytes; p += bytes; } msg->type = SYSCALL_RET; send_recv(SEND, msg->source, msg); }
PUBLIC int do_stat() { char pathname[MAX_PATH]; char filename[MAX_PATH]; int name_len = fs_msg.NAME_LEN; int src = fs_msg.source; memcpy((void*)va2la(TASK_FS, pathname), (void*)va2la(src, fs_msg.PATHNAME), name_len); pathname[name_len] = 0; int inode_nr = search_file(pathname); if (inode_nr == INVALID_INODE) { printl("FS::do_stat() failed, search file %s return INVALID INODE.\n", pathname); return -1; } struct inode* pin = 0; struct inode* dir_inode = 0; if(strip_path(filename, pathname, &dir_inode) != 0) { assert(0); } pin = get_inode(dir_inode -> i_dev, inode_nr); struct stat s; s.st_dev = pin -> i_dev; s.st_ino = pin -> i_num; s.st_mode = pin -> i_mode; s.st_rdev = pin -> i_mode == I_CHAR_SPECIAL ? pin -> i_start_sect : NO_DEV; s.st_size = pin -> i_size; put_inode(pin); memcpy((void*)va2la(src, fs_msg.BUF), (void*)va2la(TASK_FS, &s), sizeof(struct stat)); return 0; }
/* * <ring 1> this routine handles the DEV_IOCTL messge. * * @param msg - message. */ static void hd_ioctl(MESSAGE *msg) { int device = msg->DEVICE; int drive = DRV_OF_DEV(device); struct hd_info *hdi = &hd_info[drive]; if (msg->REQUEST == DIOCTL_GET_GEO) { void *dst = va2la(msg->PROC_NR, msg->BUF); void *src = va2la(TASK_HD, device < MAX_PRIM ? &hdi->primary[device] : &hdi->logical[(device - MINOR_hd1a) % NR_SUB_PER_DRIVE]); phys_copy(dst, src, sizeof(struct part_info)); } else { assert(0); } }
PRIVATE void hd_rdwt(MESSAGE* p_msg) { int drive = DRV_OF_DEV(p_msg -> DEVICE); u64 pos = p_msg -> POSITION; assert((pos & 0x1FF) == 0); /* 只允许从扇区边界开始读 */ u32 sect_nr = (u32)(pos >> SECTOR_SIZE_SHIFT); int logidx = (p_msg -> DEVICE - MINOR_hd1a) % NR_SUB_PER_DRIVE; sect_nr += p_msg -> DEVICE < MAX_PRIM ? hd_info[drive].primary[p_msg -> DEVICE].base : hd_info[drive].logical[logidx].base; HD_CMD cmd; cmd.features = 0; cmd.count = (p_msg -> CNT + SECTOR_SIZE - 1) / SECTOR_SIZE; cmd.lba_low = sect_nr & 0xFF; cmd.lba_mid = (sect_nr >> 8) & 0xFF; cmd.lba_high = (sect_nr >> 16) & 0xFF; cmd.device = MAKE_DEVICE_REG(1, drive, (sect_nr >> 24) & 0xF); cmd.command = (p_msg -> type == DEV_READ) ? ATA_READ : ATA_WRITE; hd_cmd_out(&cmd); int bytes_left = p_msg -> CNT; void* la = (void*)va2la(p_msg -> PROC_NR, p_msg -> BUF); while (bytes_left > 0) { int bytes = min(bytes_left, SECTOR_SIZE); if (p_msg -> type == DEV_READ) { /* 一次中断一个扇区 */ interrupt_wait(); port_read(REG_DATA, hdbuf, SECTOR_SIZE); memcpy(la, (void*)va2la(TASK_HD, hdbuf), bytes); } else { if (!waitfor(STATUS_DRQ, STATUS_DRQ, HD_TIMEOUT)) panic("HD writing error"); port_write(REG_DATA, la, bytes); interrupt_wait(); } la += bytes; bytes_left -= bytes; } }
/** * Invoked when task TTY receives DEV_READ message. * * @note The routine will return immediately after setting some members of * TTY struct, telling FS to suspend the proc who wants to read. The real * transfer (tty buffer -> proc buffer) is not done here. * * @param tty From which TTY the caller proc wants to read. * @param msg The MESSAGE just received. *****************************************************************************/ PRIVATE void tty_do_read(TTY* tty, MESSAGE* msg) { /* tell the tty: */ tty->tty_caller = msg->source; /* who called, usually FS */ tty->tty_procnr = msg->PROC_NR; /* who wants the chars */ tty->tty_req_buf = va2la(tty->tty_procnr, msg->BUF);/* where the chars should be put */ tty->tty_left_cnt = msg->CNT; /* how many chars are requested */ tty->tty_trans_cnt= 0; /* how many chars have been transferred */ msg->type = SUSPEND_PROC; send_recv(SEND, tty->tty_caller, msg); }
/************************************************************** * do_stat ************************************************************** @function:get the information of a pathname The information we need for stat hided in the inode. So we just need to get the info of inode of pathname. @input: @return:0 if sucess **************************************************************/ int hykdo_stat() { char filename[MAX_FILENAME_LEN]; char pathname[MAX_PATH_LEN]; int pathname_len = fs_msg.NAME_LEN; int src = fs_msg.source; // pathname = fs_msg.PATHNAME; /*no!!! you can not do this directly! For they are not in the same address space*/ phys_copy( (void *)va2la(TASK_FS, pathname),\ (void *)va2la(src, fs_msg.PATHNAME),\ fs_msg.NAME_LEN); pathname[pathname_len] = 0; int inode_nr_path = search_file(pathname); if(inode_nr_path == INVALID_INODE) { printl("[FS]:stat faild becase of invalid inode\n"); return -1; } struct inode *dir_inode; if(strip_path(filename, pathname, &dir_inode)!=0) { assert(0); } struct inode *file_inode=get_inode(dir_inode->i_dev, inode_nr_path); struct stat s; s.dev = file_inode->i_dev; s.size = file_inode->i_size; s.mode = file_inode->i_mode; s.ino = file_inode->i_num; s.rdev = is_special(file_inode->i_mode) ? file_inode->i_start_sect: NO_DEV; put_inode(file_inode); phys_copy( (void *)va2la(src, fs_msg.BUF),\ (void *)va2la(TASK_FS, &stat),\ sizeof(struct stat)); printl("fs_msg.buf.size:%x", ((struct stat *)va2la(src, fs_msg.BUF))->size); return 0; }
static void hd_ioctl(MESSAGE *message){ int hd_index=HD_INDEX(message->device); int hd_part_index=HD_PART_INDEX(message->device); struct s_hd_info *hdi=&hd_info[hd_index]; #ifdef DEBUG_HD printl("hd_index=%d hd_part_index=%d\n",hd_index,hd_part_index); #endif if(message->subtype==DIOCTL_GET_PART_INFO){ void *dest=va2la(message->source_pid,message->arg_pointer); /* void *src=va2la(TASK_HD, */ /* hd_part_index<=HD_PART_PRIM_COUNT? */ /* &hdi->primary[hd_part_index]: */ /* &hdi->logical[hd_part_index-HD_PART_LOGICAL_MIN]); */ void *src=va2la(TASK_HD,get_part_info(&hdi[hd_index],hd_part_index)); memcpy(dest,src,sizeof(struct s_hd_part_info)); }else{ assert(FALSE,"unknown message subtype in hd_ioctl"); } }
static int do_read(MESSAGE * m) { TTY * tty_p = &(tty_table[m->tty_read_TTY_NR]); int nbytes = ((MESSAGE*)(m->tty_read_REQUEST_M))->read_NBYTES; u8 * buf = va2la(((MESSAGE*)(m->tty_read_REQUEST_M))->sender_pid, (u8*)((MESSAGE*)(m->tty_read_REQUEST_M))->read_BUF); int curr_rst = ((MESSAGE*)(m->tty_read_REQUEST_M))->read_RST; char * last_read_p = (char*)(m->LAST_READ_POS); char c; if (curr_rst == 0) { last_read_p = tty_p->in_tail_p; } while (last_read_p != tty_p->in_head_p) { c = *last_read_p; /* if (curr_rst == nbytes && c != '\n') { /\* 已经足够,但是本次char不是\n *\/ */ /* last_read_p++; */ /* if (last_read_p == tty_p->tty_in_cache + TTY_CHAR_CACHE_SIZE) { */ /* last_read_p = tty_p->tty_in_cache; */ /* } */ /* m->LAST_READ_POS = (u32)last_read_p; */ /* return 0; */ /* } */ /* if (curr_rst == nbytes && c == '\n') { /\* 已经足够而且本次char==\n *\/ */ /* return 1; */ /* } */ buf[curr_rst] = c; tty_p->in_tail_p ++ ; if (tty_p->in_tail_p == tty_p->tty_in_cache + TTY_CHAR_CACHE_SIZE) { tty_p->in_tail_p = tty_p->tty_in_cache; } last_read_p = tty_p->in_tail_p; tty_p->in_count -- ; curr_rst ++ ; ((MESSAGE*)(m->tty_read_REQUEST_M))->read_RST ++ ; if (curr_rst == nbytes) { /* 加上本次char刚好足够nbytes */ // if (c == '\n') { /* 本次char ==\n, 直接成功返回 */ ((MESSAGE*)(m->tty_read_REQUEST_M))->read_RST = nbytes; return 1; // } } } m->LAST_READ_POS = (u32)last_read_p; return 0; }
/* int sys_write(char *buf,int len,struct task_struct *p_proc) { tty_write(&tty_table[p_proc->nr_tty],buf,len); return 0; } */ int sys_printx(char *s,int len,struct task_struct *p_proc) { const char *p; char ch; char reenter_err[] = "? k_reenter is incorrect for unknown reason\n"; if(k_reenter == 0) //用户态下 { p = (char *)va2la(proc2pid(p_proc),s); } else if(k_reenter > 0) //内核态 { p =s; } else { p = reenter_err; } ch = *p; if((ch == MAG_CH_PANIC) || (ch == MAG_CH_ASSERT && current < &proc_table[NR_SYSTEM_PROCS])) { disable_int(); //关中断 char *v = (char *)V_MEM_BASE; const char *c = p + 1; //skip magic char while( v < ((char *)(V_MEM_BASE + V_MEM_SIZE)) && *c) { *v++ = *c++; *v++ = RED_COLOR; } //halt processor until an enabled interrupt __asm__ __volatile__ ("hlt"); } else { while((ch = *p++) != 0) { out_char(tty_table[p_proc->nr_tty].p_console,ch); } } return 0; }
PUBLIC int sys_sendrec(int function, int src_dest, Message *p_msg, Process *p_proc) { assert(k_reenter == 0); assert((src_dest >= 0 && src_dest < NR_TASKS + NR_PROCS) || src_dest == ANY || src_dest == INTERRUPT); int ret = 0; int caller = proc2pid(p_proc); Message *mla = (Message *)va2la(caller, p_msg); mla->source = caller; assert(mla->source != src_dest); /* Actually we have the third message type: BOTH. However, it is not * allowed to be passed to the kernel directly. Kernel doesn't know * it at all. It is transformed into a SEDN followed by a RECEIVE * by 'send_recv()'. */ if(function == SEND) { ret = msg_send(p_proc, src_dest, p_msg); if(ret != 0) { return ret; } } else if(function == RECEIVE) { ret = msg_receive(p_proc, src_dest, p_msg); if(ret != 0) { return ret; } } else { panic("{sys_sendrec} invalid function: " "%d (SEND: %d, RECEIVE: %d).", function, SEND, RECEIVE); } return 0; }
static int do_write(MESSAGE * m) { TTY * tty_p = &(tty_table[m->tty_write_TTY_NR]); int nbytes = ((MESSAGE*)(m->tty_write_REQUEST_M))->write_NBYTES; u8 * buf = va2la(((MESSAGE*)(m->tty_write_REQUEST_M))->sender_pid, (u8*)((MESSAGE*)(m->tty_write_REQUEST_M))->write_BUF); int curr_rst = ((MESSAGE*)(m->tty_write_REQUEST_M))->write_RST; char * last_write_p = (char*)(m->LAST_WRITE_POS); if(nbytes == 0) { ((MESSAGE*)(m->tty_write_REQUEST_M))->write_RST = 0; return 1; } if (curr_rst == 0) last_write_p = tty_p->out_head_p; while(1) { *last_write_p = buf[curr_rst]; last_write_p ++ ; if (last_write_p == tty_p->tty_out_cache + TTY_CHAR_CACHE_SIZE) last_write_p = tty_p->tty_out_cache; curr_rst ++ ; tty_p->out_head_p ++ ; if (tty_p->out_head_p == tty_p->tty_out_cache + TTY_CHAR_CACHE_SIZE) tty_p->out_head_p = tty_p->tty_out_cache; if (tty_p->out_tail_p == tty_p->out_head_p) { assert(tty_p->out_count == TTY_CHAR_CACHE_SIZE); tty_p->out_tail_p ++ ; if (tty_p->out_tail_p == tty_p->tty_out_cache + TTY_CHAR_CACHE_SIZE) tty_p->out_tail_p = tty_p->tty_out_cache; } else { tty_p->out_count ++ ; } if (curr_rst == nbytes) { ((MESSAGE*)(m->tty_write_REQUEST_M))->write_RST = curr_rst; return 1; } } m->LAST_WRITE_POS = last_write_p; return 0; }
/** * Echo the char just pressed and transfer it to the waiting process. * * @param tty Ptr to a TTY struct. *****************************************************************************/ PRIVATE void tty_dev_write(TTY* tty) { while (tty->ibuf_cnt) { char ch = *(tty->ibuf_tail); tty->ibuf_tail++; if (tty->ibuf_tail == tty->ibuf + TTY_IN_BYTES) tty->ibuf_tail = tty->ibuf; tty->ibuf_cnt--; if (tty->tty_left_cnt) { if (ch >= ' ' && ch <= '~') { /* printable */ out_char(tty->console, ch); assert(tty->tty_req_buf); void * p = tty->tty_req_buf + tty->tty_trans_cnt; phys_copy(p, (void *)va2la(TASK_TTY, &ch), 1); tty->tty_trans_cnt++; tty->tty_left_cnt--; } else if (ch == '\b' && tty->tty_trans_cnt) { out_char(tty->console, ch); tty->tty_trans_cnt--; tty->tty_left_cnt++; } if (ch == '\n' || tty->tty_left_cnt == 0) { out_char(tty->console, '\n'); assert(tty->tty_procnr != NO_TASK); MESSAGE msg; msg.type = RESUME_PROC; msg.PROC_NR = tty->tty_procnr; msg.CNT = tty->tty_trans_cnt; send_recv(SEND, tty->tty_caller, &msg); tty->tty_left_cnt = 0; } } } }
/** * <Ring 0> Try to get a message from the src proc. If src is blocked sending * the message, copy the message from it and unblock src. Otherwise the caller * will be blocked. * * @param current The caller, the proc who wanna receive. * @param src From whom the message will be received. * @param m The message ptr to accept the message. * * @return Zero if success. *****************************************************************************/ PRIVATE int msg_receive(struct proc* current, int src, MESSAGE* m) { struct proc* p_who_wanna_recv = current; /** * This name is a little bit * wierd, but it makes me * think clearly, so I keep * it. */ struct proc* p_from = 0; /* from which the message will be fetched */ struct proc* prev = 0; int copyok = 0; assert(proc2pid(p_who_wanna_recv) != src); if ((p_who_wanna_recv->has_int_msg) && ((src == ANY) || (src == INTERRUPT))) { /* There is an interrupt needs p_who_wanna_recv's handling and * p_who_wanna_recv is ready to handle it. */ MESSAGE msg; reset_msg(&msg); msg.source = INTERRUPT; msg.type = HARD_INT; assert(m); phys_copy(va2la(proc2pid(p_who_wanna_recv), m), &msg, sizeof(MESSAGE)); p_who_wanna_recv->has_int_msg = 0; assert(p_who_wanna_recv->p_flags == 0); assert(p_who_wanna_recv->p_msg == 0); assert(p_who_wanna_recv->p_sendto == NO_TASK); assert(p_who_wanna_recv->has_int_msg == 0); return 0; } /* Arrives here if no interrupt for p_who_wanna_recv. */ if (src == ANY) { /* p_who_wanna_recv is ready to receive messages from * ANY proc, we'll check the sending queue and pick the * first proc in it. */ if (p_who_wanna_recv->q_sending) { p_from = p_who_wanna_recv->q_sending; copyok = 1; assert(p_who_wanna_recv->p_flags == 0); assert(p_who_wanna_recv->p_msg == 0); assert(p_who_wanna_recv->p_recvfrom == NO_TASK); assert(p_who_wanna_recv->p_sendto == NO_TASK); assert(p_who_wanna_recv->q_sending != 0); assert(p_from->p_flags == SENDING); assert(p_from->p_msg != 0); assert(p_from->p_recvfrom == NO_TASK); assert(p_from->p_sendto == proc2pid(p_who_wanna_recv)); } } else { /* p_who_wanna_recv wants to receive a message from * a certain proc: src. */ p_from = &proc_table[src]; if ((p_from->p_flags & SENDING) && (p_from->p_sendto == proc2pid(p_who_wanna_recv))) { /* Perfect, src is sending a message to * p_who_wanna_recv. */ copyok = 1; struct proc* p = p_who_wanna_recv->q_sending; assert(p); /* p_from must have been appended to the * queue, so the queue must not be NULL */ while (p) { assert(p_from->p_flags & SENDING); if (proc2pid(p) == src) { /* if p is the one */ p_from = p; break; } prev = p; p = p->next_sending; } assert(p_who_wanna_recv->p_flags == 0); assert(p_who_wanna_recv->p_msg == 0); assert(p_who_wanna_recv->p_recvfrom == NO_TASK); assert(p_who_wanna_recv->p_sendto == NO_TASK); assert(p_who_wanna_recv->q_sending != 0); assert(p_from->p_flags == SENDING); assert(p_from->p_msg != 0); assert(p_from->p_recvfrom == NO_TASK); assert(p_from->p_sendto == proc2pid(p_who_wanna_recv)); } } if (copyok) { /* It's determined from which proc the message will * be copied. Note that this proc must have been * waiting for this moment in the queue, so we should * remove it from the queue. */ if (p_from == p_who_wanna_recv->q_sending) { /* the 1st one */ assert(prev == 0); p_who_wanna_recv->q_sending = p_from->next_sending; p_from->next_sending = 0; } else { assert(prev); prev->next_sending = p_from->next_sending; p_from->next_sending = 0; } assert(m); assert(p_from->p_msg); /* copy the message */ phys_copy(va2la(proc2pid(p_who_wanna_recv), m), va2la(proc2pid(p_from), p_from->p_msg), sizeof(MESSAGE)); p_from->p_msg = 0; p_from->p_sendto = NO_TASK; p_from->p_flags &= ~SENDING; unblock(p_from); } else { /* nobody's sending any msg */ /* Set p_flags so that p_who_wanna_recv will not * be scheduled until it is unblocked. */ p_who_wanna_recv->p_flags |= RECEIVING; p_who_wanna_recv->p_msg = m; if (src == ANY) p_who_wanna_recv->p_recvfrom = ANY; else p_who_wanna_recv->p_recvfrom = proc2pid(p_from); block(p_who_wanna_recv); assert(p_who_wanna_recv->p_flags == RECEIVING); assert(p_who_wanna_recv->p_msg != 0); assert(p_who_wanna_recv->p_recvfrom != NO_TASK); assert(p_who_wanna_recv->p_sendto == NO_TASK); assert(p_who_wanna_recv->has_int_msg == 0); } return 0; }
/** * <Ring 0> Send a message to the dest proc. If dest is blocked waiting for * the message, copy the message to it and unblock dest. Otherwise the caller * will be blocked and appended to the dest's sending queue. * * @param current The caller, the sender. * @param dest To whom the message is sent. * @param m The message. * * @return Zero if success. *****************************************************************************/ PRIVATE int msg_send(struct proc* current, int dest, MESSAGE* m) { struct proc* sender = current; struct proc* p_dest = proc_table + dest; /* proc dest */ assert(proc2pid(sender) != dest); /* check for deadlock here */ if (deadlock(proc2pid(sender), dest)) { panic(">>DEADLOCK<< %s->%s", sender->name, p_dest->name); } if ((p_dest->p_flags & RECEIVING) && /* dest is waiting for the msg */ (p_dest->p_recvfrom == proc2pid(sender) || p_dest->p_recvfrom == ANY)) { assert(p_dest->p_msg); assert(m); phys_copy(va2la(dest, p_dest->p_msg), va2la(proc2pid(sender), m), sizeof(MESSAGE)); p_dest->p_msg = 0; p_dest->p_flags &= ~RECEIVING; /* dest has received the msg */ p_dest->p_recvfrom = NO_TASK; unblock(p_dest); assert(p_dest->p_flags == 0); assert(p_dest->p_msg == 0); assert(p_dest->p_recvfrom == NO_TASK); assert(p_dest->p_sendto == NO_TASK); assert(sender->p_flags == 0); assert(sender->p_msg == 0); assert(sender->p_recvfrom == NO_TASK); assert(sender->p_sendto == NO_TASK); } else { /* dest is not waiting for the msg */ sender->p_flags |= SENDING; assert(sender->p_flags == SENDING); sender->p_sendto = dest; sender->p_msg = m; /* append to the sending queue */ struct proc * p; if (p_dest->q_sending) { p = p_dest->q_sending; while (p->next_sending) p = p->next_sending; p->next_sending = sender; } else { p_dest->q_sending = sender; } sender->next_sending = 0; block(sender); assert(sender->p_flags == SENDING); assert(sender->p_msg != 0); assert(sender->p_recvfrom == NO_TASK); assert(sender->p_sendto == dest); } return 0; }
/*======================================================================* sys_write *======================================================================*/ PUBLIC int sys_printx(int _unused1, int _unused2, char* s, struct proc* p_proc) { const char * p; char ch; char reenter_err[] = "? k_reenter is incorrect for unknown reason"; reenter_err[0] = MAG_CH_PANIC; /** * @note Code in both Ring 0 and Ring 1~3 may invoke printx(). * If this happens in Ring 0, no linear-physical address mapping * is needed. * * @attention The value of `k_reenter' is tricky here. When * -# printx() is called in Ring 0 * - k_reenter > 0. When code in Ring 0 calls printx(), * an `interrupt re-enter' will occur (printx() generates * a software interrupt). Thus `k_reenter' will be increased * by `kernel.asm::save' and be greater than 0. * -# printx() is called in Ring 1~3 * - k_reenter == 0. */ if (k_reenter == 0) /* printx() called in Ring<1~3> */ p = va2la(proc2pid(p_proc), s); else if (k_reenter > 0) /* printx() called in Ring<0> */ p = s; else /* this should NOT happen */ p = reenter_err; /** * @note if assertion fails in any TASK, the system will be halted; * if it fails in a USER PROC, it'll return like any normal syscall * does. */ if ((*p == MAG_CH_PANIC) || (*p == MAG_CH_ASSERT && p_proc_ready < &proc_table[NR_TASKS])) { disable_int(); char * v = (char*)V_MEM_BASE; const char * q = p + 1; /* +1: skip the magic char */ while (v < (char*)(V_MEM_BASE + V_MEM_SIZE)) { *v++ = *q++; *v++ = RED_CHAR; if (!*q) { while (((int)v - V_MEM_BASE) % (SCR_WIDTH * 16)) { /* *v++ = ' '; */ v++; *v++ = GRAY_CHAR; } q = p + 1; } } __asm__ __volatile__("hlt"); } while ((ch = *p++) != 0) { if (ch == MAG_CH_PANIC || ch == MAG_CH_ASSERT) continue; /* skip the magic char */ out_char(tty_table[p_proc->nr_tty].p_console, ch); } return 0; }
/** * Read/Write file and return byte count read/written. * * Sector map is not needed to update, since the sectors for the file have been * allocated and the bits are set when the file was created. * * @return How many bytes have been read/written. *****************************************************************************/ PUBLIC int do_rdwt() { int fd = fs_msg.FD; /**< file descriptor. */ void * buf = fs_msg.BUF;/**< r/w buffer */ int len = fs_msg.CNT; /**< r/w bytes */ int src = fs_msg.source; /* caller proc nr. */ assert((pcaller->filp[fd] >= &f_desc_table[0]) && (pcaller->filp[fd] < &f_desc_table[NR_FILE_DESC])); if (!(pcaller->filp[fd]->fd_mode & O_RDWR)) return -1; int pos = pcaller->filp[fd]->fd_pos; struct inode * pin = pcaller->filp[fd]->fd_inode; assert(pin >= &inode_table[0] && pin < &inode_table[NR_INODE]); int imode = pin->i_mode & I_TYPE_MASK; if (imode == I_CHAR_SPECIAL) { int t = fs_msg.type == READ ? DEV_READ : DEV_WRITE; fs_msg.type = t; int dev = pin->i_start_sect; assert(MAJOR(dev) == 4); fs_msg.DEVICE = MINOR(dev); fs_msg.BUF = buf; fs_msg.CNT = len; fs_msg.PROC_NR = src; assert(dd_map[MAJOR(dev)].driver_nr != INVALID_DRIVER); send_recv(BOTH, dd_map[MAJOR(dev)].driver_nr, &fs_msg); assert(fs_msg.CNT == len); return fs_msg.CNT; } else { assert(pin->i_mode == I_REGULAR || pin->i_mode == I_DIRECTORY); assert((fs_msg.type == READ) || (fs_msg.type == WRITE)); //讀寫不能超過檔案大小 int pos_end; if (fs_msg.type == READ) pos_end = min(pos + len, pin->i_size); else /* WRITE */ pos_end = min(pos + len, pin->i_nr_sects * SECTOR_SIZE); //secNum的offset int off = pos % SECTOR_SIZE; //哪一個sector int rw_sect_min=pin->i_start_sect+(pos>>SECTOR_SIZE_SHIFT); //結束在那個sector int rw_sect_max=pin->i_start_sect+(pos_end>>SECTOR_SIZE_SHIFT); //扇區讀寫使用chunk為單位,如果一次buf傳的完的話,就使用rw_sect_max - rw_sect_min + 1 int chunk = min(rw_sect_max - rw_sect_min + 1, FSBUF_SIZE >> SECTOR_SIZE_SHIFT); int bytes_rw = 0; int bytes_left = len; int i; for (i = rw_sect_min; i <= rw_sect_max; i += chunk) { /* read/write this amount of bytes every time */ int bytes = min(bytes_left, chunk * SECTOR_SIZE - off); rw_sector(DEV_READ, pin->i_dev, i * SECTOR_SIZE, chunk * SECTOR_SIZE, TASK_FS, fsbuf); if (fs_msg.type == READ) { phys_copy((void*)va2la(src, buf + bytes_rw), (void*)va2la(TASK_FS, fsbuf + off), bytes); } else { /* WRITE */ phys_copy((void*)va2la(TASK_FS, fsbuf + off), (void*)va2la(src, buf + bytes_rw), bytes); rw_sector(DEV_WRITE, pin->i_dev, i * SECTOR_SIZE, chunk * SECTOR_SIZE, TASK_FS, fsbuf); } off = 0; bytes_rw += bytes; pcaller->filp[fd]->fd_pos += bytes; bytes_left -= bytes; } if (pcaller->filp[fd]->fd_pos > pin->i_size) { /* update inode::size */ pin->i_size = pcaller->filp[fd]->fd_pos; /* write the updated i-node back to disk */ sync_inode(pin); } return bytes_rw; } }
PUBLIC int do_open() { int i = 0; int fd = -1; // return value char pathname[MAX_PATH]; int flags = fs_msg.FLAGS; int name_len = fs_msg.NAME_LEN; int src = fs_msg.source; assert(name_len < MAX_PATH); phys_copy( (void *)va2la(TASK_FS, pathname), (void *)va2la(src, fs_msg.PATHNAME), name_len ); pathname[name_len] = 0; /* 先在调用者进程中查找空闲文件描述符 */ for (i = 0; i < NR_FILES; i++) if (pcaller->filp[i] == 0) { fd = i; break; } if ((fd < 0) || (fd >= NR_FILES)) panic("filp[] is full (PID:%d)", proc2pid(pcaller)); /* 然后在 f_desc_table 中查找空闲位置 */ for (i = 0; i < NR_FILE_DESC; i++) if (f_desc_table[i].fd_inode == 0) break; if (i >= NR_FILE_DESC) panic("f_desc_table[] is full (PID:%d)", proc2pid(pcaller)); /* 在磁盘中查找文件 */ int inode_nr = search_file(pathname); /* 准备创建或打开文件 */ struct inode *pin = 0; if (flags & O_CREAT) { if (inode_nr) { printl("file exists.\n"); return -1; } else { // 文件不存在且标志位 O_CREAT pin = creat_file(pathname, flags); } } else { assert(flags & O_RDWR); char filename[MAX_PATH]; struct inode * dir_inode; if (strip_path(filename, pathname, &dir_inode) != 0) return -1; pin = get_inode(dir_inode->i_dev, inode_nr); } /* 关联文件描述符 */ if (pin) { /* proc <- fd (connects proc with file_descriptor) */ pcaller->filp[fd] = &f_desc_table[i]; /* fd <- inode (connects file_descriptor with inode) */ f_desc_table[i].fd_mode = flags; f_desc_table[i].fd_pos = 0; f_desc_table[i].fd_inode = pin; int imode = pin->i_mode & I_TYPE_MASK; if (imode == I_CHAR_SPECIAL) { MESSAGE driver_msg; driver_msg.type = DEV_OPEN; int dev = pin->i_start_sect; driver_msg.DEVICE = MINOR(dev); assert(MAJOR(dev) == 4); assert(dd_map[MAJOR(dev)].driver_nr != INVALID_DRIVER); /* 如果是字符设备则交给该设备的驱动处理 */ send_recv(BOTH, dd_map[MAJOR(dev)].driver_nr, &driver_msg); } else if (imode == I_DIRECTORY) assert(pin->i_num == ROOT_INODE); else assert(pin->i_mode == I_REGULAR); } else return -1; // open file failed return fd; }
/** * Open a file and return the file descriptor. * * @return File descriptor if successful, otherwise a negative error code. *****************************************************************************/ PUBLIC int do_open() { int fd = -1; /* return value */ char pathname[MAX_PATH]; /* get parameters from the message */ int flags = fs_msg.FLAGS; /* access mode */ int name_len = fs_msg.NAME_LEN; /* length of filename */ int src = fs_msg.source; /* caller proc nr. */ assert(name_len < MAX_PATH); phys_copy((void*)va2la(TASK_FS, pathname), (void*)va2la(src, fs_msg.PATHNAME), name_len); pathname[name_len] = 0; /* find a free slot in PROCESS::filp[] */ int i; for (i = 0; i < NR_FILES; i++) { if (pcaller->filp[i] == 0) { fd = i; break; } } if ((fd < 0) || (fd >= NR_FILES)) panic("filp[] is full (PID:%d)", proc2pid(pcaller)); /* find a free slot in f_desc_table[] */ for (i = 0; i < NR_FILE_DESC; i++) if (f_desc_table[i].fd_inode == 0) break; if (i >= NR_FILE_DESC) panic("f_desc_table[] is full (PID:%d)", proc2pid(pcaller)); int inode_nr = search_file(pathname); struct inode * pin = 0; if (flags & O_CREAT) { if (inode_nr) { printl("file exists.\n"); return -1; } else { pin = create_file(pathname, flags); } } else { assert(flags & O_RDWR); char filename[MAX_PATH]; struct inode * dir_inode; if (strip_path(filename, pathname, &dir_inode) != 0) return -1; pin = get_inode(dir_inode->i_dev, inode_nr); } if (pin) { /* connects proc with file_descriptor */ pcaller->filp[fd] = &f_desc_table[i]; /* connects file_descriptor with inode */ f_desc_table[i].fd_inode = pin; f_desc_table[i].fd_mode = flags; /* f_desc_table[i].fd_cnt = 1; */ f_desc_table[i].fd_pos = 0; int imode = pin->i_mode & I_TYPE_MASK; if (imode == I_CHAR_SPECIAL) { MESSAGE driver_msg; driver_msg.type = DEV_OPEN; int dev = pin->i_start_sect; driver_msg.DEVICE = MINOR(dev); assert(MAJOR(dev) == 4); assert(dd_map[MAJOR(dev)].driver_nr != INVALID_DRIVER); send_recv(BOTH, dd_map[MAJOR(dev)].driver_nr, &driver_msg); } else if (imode == I_DIRECTORY) { assert(pin->i_num == ROOT_INODE); } else { assert(pin->i_mode == I_REGULAR); } } else { return -1; } return fd; }