/* ** Name: void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize) ** Function: Copies a packet from user area to board (Prog. I/O, 16bits). */ static void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize) { u8_t two_bytes[2]; phys_bytes phys_user, phys_2bytes = vir2phys(two_bytes); vir_bytes ecount = (pktsize + 1) & NOT(0x0001); int bytes, ix = 0, odd_byte = 0; iovec_dat_t *iovp = &dep->de_write_iovec; outb_reg0(dep, DP_ISR, ISR_RDC); dp_read_setup(dep, ecount, pageno * DP_PAGESIZE); do { bytes = iovp->iod_iovec[ix].iov_size; if (bytes > pktsize) bytes = pktsize; phys_user = numap(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr, bytes); if (!phys_user) panic(UmapErrMsg); if (odd_byte) { phys_copy(phys_user, phys_2bytes + 1, (phys_bytes) 1); out_word(dep->de_data_port, *(u16_t *)two_bytes); pktsize--; bytes--; phys_user++; odd_byte = 0; if (!bytes) continue; } ecount = bytes & NOT(0x0001); if (ecount != 0) { phys_outsw(dep->de_data_port, phys_user, ecount); pktsize -= ecount; bytes -= ecount; phys_user += ecount; } if (bytes) { phys_copy(phys_user, phys_2bytes, (phys_bytes) 1); pktsize--; bytes--; phys_user++; odd_byte = 1; } if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */ dp_next_iovec(iovp); ix = 0; } } while (bytes > 0); if (odd_byte) out_word(dep->de_data_port, *(u16_t *) two_bytes); for (ix = 0; ix < 100; ix++) { if (inb_reg0(dep, DP_ISR) & ISR_RDC) break; } if (ix == 100) { panic(RdmaErrMsg); } return; }
/* ** Name: void dp_pio16_nic2user(dpeth_t *dep, int pageno, int pktsize) ** Function: Copies a packet from board to user area (Prog. I/O, 16bits). */ static void dp_pio16_nic2user(dpeth_t * dep, int nic_addr, int count) { phys_bytes phys_user; vir_bytes ecount; int bytes, i; u8_t two_bytes[2]; phys_bytes phys_2bytes; int odd_byte; ecount = (count + 1) & ~1; phys_2bytes = vir2phys(two_bytes); odd_byte = 0; dp_read_setup(dep, ecount, nic_addr); i = 0; while (count > 0) { if (i >= IOVEC_NR) { dp_next_iovec(iovp); i = 0; continue; } bytes = iovp->iod_iovec[i].iov_size; if (bytes > count) bytes = count; phys_user = numap(iovp->iod_proc_nr, iovp->iod_iovec[i].iov_addr, bytes); if (!phys_user) panic(UmapErrMsg); if (odd_byte) { phys_copy(phys_2bytes + 1, phys_user, (phys_bytes) 1); count--; bytes--; phys_user++; odd_byte = 0; if (!bytes) continue; } ecount = bytes & ~1; if (ecount != 0) { phys_insw(dep->de_data_port, phys_user, ecount); count -= ecount; bytes -= ecount; phys_user += ecount; } if (bytes) { *(u16_t *) two_bytes = in_word(dep->de_data_port); phys_copy(phys_2bytes, phys_user, (phys_bytes) 1); count--; bytes--; phys_user++; odd_byte = 1; } } return; }
/***************************************************************************** * 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; }
PRIVATE void cons_setc(const int pos, const int c) { char ch; ch= c; phys_copy(vir2phys((vir_bytes)&ch), COLOR_BASE+(20*80+pos)*2, 1); }
PUBLIC int arch_get_params(char *params, int maxsize) { phys_copy(seg2phys(mon_ds) + params_offset, vir2phys(params), MIN(maxsize, params_size)); params[maxsize-1] = '\0'; return OK; }
PUBLIC void arch_get_aout_headers(const int i, struct exec *h) { /* The bootstrap loader created an array of the a.out headers at * absolute address 'aout'. Get one element to h. */ phys_copy(aout + i * A_MINHDR, vir2phys(h), (phys_bytes) A_MINHDR); }
////复制父进程的地址空间 static int copy_mem(int pid,struct task_struct *p) { struct descriptor *dp = &proc_table[pid].ldts[INDEX_LDT_C]; int text_base = get_base(dp); int text_limit = get_limit(dp); int text_size = (text_limit + 1) * ((dp->limit_high_attr2 * 0x80)?4096:1); dp = &proc_table[pid].ldts[INDEX_LDT_D]; int data_base = get_base(dp); int data_limit= get_limit(dp); int data_size = (text_limit + 1) * ((dp->limit_high_attr2 * 0x80)?4096:1); assert((text_base == data_base) && (text_limit == data_limit) && (text_size == data_size) ); int child_base = alloc_mem(p->pid,text_size); // printk("child_base = %d\t text_base = %d\t text_size = %d\n",child_base,text_base,text_size); // memcpy((void *)child_base,(void *)(text_base),text_size); // printk("child_base = %d\t text_base = %d\t text_size = %d\n",child_base,text_base,text_size); phys_copy((char *)child_base,(char *)(text_base),text_size); return child_base; }
/** * <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 int arch_set_params(char *params, int size) { if(size > params_size) return E2BIG; phys_copy(vir2phys(params), seg2phys(mon_ds) + params_offset, size); return OK; }
/************************************************************************************************** * 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; }
/*===========================================================================* * intr_init * *===========================================================================*/ PUBLIC int intr_init(const int mine, const int auto_eoi) { /* Initialize the 8259s, finishing with all interrupts disabled. This is * only done in protected mode, in real mode we don't touch the 8259s, but * use the BIOS locations instead. The flag "mine" is set if the 8259s are * to be programmed for MINIX, or to be reset to what the BIOS expects. */ /* The AT and newer PS/2 have two interrupt controllers, one master, * one slaved at IRQ 2. (We don't have to deal with the PC that * has just one controller, because it must run in real mode.) */ outb( INT_CTL, machine.ps_mca ? ICW1_PS : ICW1_AT); outb( INT_CTLMASK, mine == INTS_MINIX ? IRQ0_VECTOR : BIOS_IRQ0_VEC); /* ICW2 for master */ outb( INT_CTLMASK, (1 << CASCADE_IRQ)); /* ICW3 tells slaves */ if (auto_eoi) outb( INT_CTLMASK, ICW4_AT_AEOI_MASTER); else outb( INT_CTLMASK, ICW4_AT_MASTER); outb( INT_CTLMASK, ~(1 << CASCADE_IRQ)); /* IRQ 0-7 mask */ outb( INT2_CTL, machine.ps_mca ? ICW1_PS : ICW1_AT); outb( INT2_CTLMASK, mine == INTS_MINIX ? IRQ8_VECTOR : BIOS_IRQ8_VEC); /* ICW2 for slave */ outb( INT2_CTLMASK, CASCADE_IRQ); /* ICW3 is slave nr */ if (auto_eoi) outb( INT2_CTLMASK, ICW4_AT_AEOI_SLAVE); else outb( INT2_CTLMASK, ICW4_AT_SLAVE); outb( INT2_CTLMASK, ~0); /* IRQ 8-15 mask */ /* Copy the BIOS vectors from the BIOS to the Minix location, so we * can still make BIOS calls without reprogramming the i8259s. */ #if IRQ0_VECTOR != BIOS_IRQ0_VEC phys_copy(BIOS_VECTOR(0) * 4L, VECTOR(0) * 4L, 8 * 4L); #endif #if IRQ8_VECTOR != BIOS_IRQ8_VEC phys_copy(BIOS_VECTOR(8) * 4L, VECTOR(8) * 4L, 8 * 4L); #endif return OK; }
/* * <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; } }
/* * Write bytes to task address space for debugger. */ void db_write_bytes( vm_offset_t addr, int size, char *data, task_t task) { int n,max; addr64_t phys_dst; addr64_t phys_src; pmap_t pmap; while (size > 0) { phys_src = db_vtophys(kernel_pmap, (vm_offset_t)data); if (phys_src == 0) { db_printf("\nno memory is assigned to src address %08x\n", data); db_error(0); /* NOTREACHED */ } /* space stays as kernel space unless in another task */ if (task == NULL) pmap = kernel_pmap; else pmap = task->map->pmap; phys_dst = db_vtophys(pmap, (vm_offset_t)addr); if (phys_dst == 0) { db_printf("\nno memory is assigned to dst address %08x\n", addr); db_error(0); /* NOTREACHED */ } /* don't over-run any page boundaries - check src range */ max = round_page_64(phys_src + 1) - phys_src; if (max > size) max = size; /* Check destination won't run over boundary either */ n = round_page_64(phys_dst + 1) - phys_dst; if (n < max) max = n; size -= max; addr += max; phys_copy(phys_src, phys_dst, max); /* resync I+D caches */ sync_cache64(phys_dst, max); phys_src += max; phys_dst += max; } }
/************************************************************** * 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; }
/** * 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); }
PRIVATE __dead void arch_bios_poweroff(void) { u32_t cr0; /* Disable paging */ cr0 = read_cr0(); cr0 &= ~I386_CR0_PG; write_cr0(cr0); /* Copy 16-bit poweroff code to below 1M */ phys_copy( (u32_t)&poweroff16, BIOS_POWEROFF_ENTRY, (u32_t)&poweroff16_end-(u32_t)&poweroff16); poweroff_jmp(); }
static u32_t phys_get32(phys_bytes addr) { const u32_t v; int r; if(!vm_running) { phys_copy(addr, vir2phys(&v), sizeof(v)); return v; } if((r=lin_lin_copy(NULL, addr, proc_addr(SYSTEM), vir2phys(&v), sizeof(v))) != OK) { panic("lin_lin_copy for phys_get32 failed: %d", r); } return v; }
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); }
/* * <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); } }
/** * 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; } } } }
/*===========================================================================* * DEBUG routines here * *===========================================================================*/ PUBLIC void p_dmp() { /* Proc table dump */ register struct proc *rp; char *np; vir_clicks base, limit, first, last; phys_bytes ltmp, dst; int index; int i; char *cp; printf( "\r\nproc pid pc sp splow flag user sys base limit recv command\r\n"); dst = umap(proc_addr(SYSTASK), D, (vir_bytes)nbuff, (vir_bytes)NSIZE); for (rp = &proc[0]; rp < &proc[NR_PROCS+NR_TASKS]; rp++) { if (rp->p_flags & P_SLOT_FREE) continue; first = rp->p_map[T].mem_phys; last = rp->p_map[S].mem_phys + rp->p_map[S].mem_len; ltmp = ((long) first << CLICK_SHIFT) + 512L; base = (vir_clicks) (ltmp/1024L); ltmp = (((long) last << CLICK_SHIFT) + 512L); limit = (vir_clicks) (ltmp/1024L); prname((int)(rp - proc)); printf("%4d %6X %6X %6X %6x %4D %6D %4dK %4dK ", rp->p_pid, (long)rp->p_reg.pc, (long)rp->p_reg.sp, (long)rp->p_splow, rp->p_flags, rp->user_time, rp->sys_time, base, limit); if (rp->p_flags == 0) printf(" "); else prname(NR_TASKS + rp->p_getfrom); /* Fetch the command string from the user process. */ index = (int)(rp - proc) - NR_TASKS; if (index > LOW_USER && aout[index] != 0) { phys_copy(aout[index], dst, (long) NSIZE); nbuff[NSIZE] = 0; for (np = &nbuff[0]; np < &nbuff[NSIZE]; np++) if (*np <= ' ' || *np >= 0177) *np = 0; if (index == LOW_USER + 1) cp = "/bin/sh"; else cp = nbuff; for(i=0;i<100;i++) if(cp[i] == '\0') break; if(i > 6) printf("\r\n\t"); printf("%s", cp); } printf("\r\n"); } #ifdef NEEDED printf("\r\nproc callq sendlk mesbuf from nready pend blkd held alarm\r\n"); for (rp = &proc[0]; rp < &proc[NR_PROCS+NR_TASKS]; rp++) { if (rp->p_flags & P_SLOT_FREE) continue; prname((int)(rp - proc)); printf(" %6X %6X %6X %4d %6X %4d %4d %4d %X\r\n", rp->p_callerq, rp->p_sendlink, rp->p_messbuf, rp->p_getfrom, rp->p_nextready, rp->p_pending, rp->p_int_blocked, rp->p_int_held, rp->p_alarm ); } for (index = 0; index < NQ; index++) { printf("q=%d: ", index); for (rp = rdy_head[index]; rp != NIL_PROC; rp = rp->p_nextready) printf(" %d", (int)(rp-proc)); printf("\r\n"); } printf("held_head = 0x%X\r\n", held_head); #endif NEEDED printf("\r\n"); }
/** * <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; }
/** * 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; }
/*===========================================================================* * main * *===========================================================================*/ PUBLIC void main() { /* Start the ball rolling. */ register struct proc *rp; register int t; int hdrindex; phys_clicks text_base; vir_clicks text_clicks; vir_clicks data_clicks; phys_bytes phys_b; reg_t ktsb; /* kernel task stack base */ struct memory *memp; struct tasktab *ttp; struct exec e_hdr; licznik_elementow = 0; /* Initialize the interrupt controller. */ intr_init(1); /* Interpret memory sizes. */ mem_init(); /* Clear the process table. * Set up mappings for proc_addr() and proc_number() macros. */ for (rp = BEG_PROC_ADDR, t = -NR_TASKS; rp < END_PROC_ADDR; ++rp, ++t) { rp->p_nr = t; /* proc number from ptr */ (pproc_addr + NR_TASKS)[t] = rp; /* proc ptr from number */ } /* Resolve driver selections in the task table. */ mapdrivers(); /* Set up proc table entries for tasks and servers. The stacks of the * kernel tasks are initialized to an array in data space. The stacks * of the servers have been added to the data segment by the monitor, so * the stack pointer is set to the end of the data segment. All the * processes are in low memory on the 8086. On the 386 only the kernel * is in low memory, the rest is loaded in extended memory. */ /* Task stacks. */ ktsb = (reg_t) t_stack; for (t = -NR_TASKS; t <= LOW_USER; ++t) { rp = proc_addr(t); /* t's process slot */ ttp = &tasktab[t + NR_TASKS]; /* t's task attributes */ strcpy(rp->p_name, ttp->name); if (t < 0) { if (ttp->stksize > 0) { rp->p_stguard = (reg_t *) ktsb; *rp->p_stguard = STACK_GUARD; } ktsb += ttp->stksize; rp->p_reg.sp = ktsb; text_base = code_base >> CLICK_SHIFT; /* tasks are all in the kernel */ hdrindex = 0; /* and use the first a.out header */ rp->p_priority = PPRI_TASK; } else { hdrindex = 1 + t; /* MM, FS, INIT follow the kernel */ rp->p_priority = t < LOW_USER ? PPRI_SERVER : PPRI_USER; } /* The bootstrap loader has created an array of the a.out headers at * absolute address 'aout'. */ phys_copy(aout + hdrindex * A_MINHDR, vir2phys(&e_hdr), (phys_bytes) A_MINHDR); text_base = e_hdr.a_syms >> CLICK_SHIFT; text_clicks = (e_hdr.a_text + CLICK_SIZE-1) >> CLICK_SHIFT; if (!(e_hdr.a_flags & A_SEP)) text_clicks = 0; /* Common I&D */ data_clicks = (e_hdr.a_total + CLICK_SIZE-1) >> CLICK_SHIFT; rp->p_map[T].mem_phys = text_base; rp->p_map[T].mem_len = text_clicks; rp->p_map[D].mem_phys = text_base + text_clicks; rp->p_map[D].mem_len = data_clicks; rp->p_map[S].mem_phys = text_base + text_clicks + data_clicks; rp->p_map[S].mem_vir = data_clicks; /* empty - stack is in data */ /* Remove server memory from the free memory list. The boot monitor * promises to put processes at the start of memory chunks. */ for (memp = mem; memp < &mem[NR_MEMS]; memp++) { if (memp->base == text_base) { memp->base += text_clicks + data_clicks; memp->size -= text_clicks + data_clicks; } } /* Set initial register values. */ rp->p_reg.pc = (reg_t) ttp->initial_pc; rp->p_reg.psw = istaskp(rp) ? INIT_TASK_PSW : INIT_PSW; if (t >= 0) { /* Initialize the server stack pointer. Take it down one word * to give crtso.s something to use as "argc". */ rp->p_reg.sp = (rp->p_map[S].mem_vir + rp->p_map[S].mem_len) << CLICK_SHIFT; rp->p_reg.sp -= sizeof(reg_t); } if (!isidlehardware(t)) lock_ready(rp); /* IDLE, HARDWARE neveready */ rp->p_flags = 0; alloc_segments(rp); }
PUBLIC __dead void arch_shutdown(int how) { u16_t magic; vm_stop(); /* Mask all interrupts, including the clock. */ outb( INT_CTLMASK, ~0); if(minix_panicing) { unsigned char unused_ch; /* We're panicing? Then retrieve and decode currently * loaded segment selectors. */ printseg("cs: ", 1, get_cpulocal_var(proc_ptr), read_cs()); printseg("ds: ", 0, get_cpulocal_var(proc_ptr), read_ds()); if(read_ds() != read_ss()) { printseg("ss: ", 0, NULL, read_ss()); } /* Printing is done synchronously over serial. */ if (do_serial_debug) reset(); /* Print accumulated diagnostics buffer and reset. */ mb_cls(); mb_print("Minix panic. System diagnostics buffer:\n\n"); mb_print(kmess_buf); mb_print("\nSystem has panicked, press any key to reboot"); while (!mb_read_char(&unused_ch)) ; reset(); } #if USE_BOOTPARAM if (how == RBT_DEFAULT) { how = mon_return ? RBT_HALT : RBT_RESET; } if(how != RBT_RESET) { /* return to boot monitor */ outb( INT_CTLMASK, 0); outb( INT2_CTLMASK, 0); /* Return to the boot monitor. Set * the program if not already done. */ if (how != RBT_MONITOR) arch_set_params("", 1); if (mon_return) arch_monitor(); /* monitor command with no monitor: reset or poweroff * depending on the parameters */ if (how == RBT_MONITOR) { how = RBT_RESET; } } switch (how) { case RBT_REBOOT: case RBT_RESET: /* Reset the system by forcing a processor shutdown. * First stop the BIOS memory test by setting a soft * reset flag. */ magic = STOP_MEM_CHECK; phys_copy(vir2phys(&magic), SOFT_RESET_FLAG_ADDR, SOFT_RESET_FLAG_SIZE); reset(); NOT_REACHABLE; case RBT_HALT: /* Poweroff without boot monitor */ arch_bios_poweroff(); NOT_REACHABLE; case RBT_PANIC: /* Allow user to read panic message */ for (; ; ) halt_cpu(); NOT_REACHABLE; default: /* Not possible! trigger panic */ assert(how != RBT_MONITOR); assert(how != RBT_DEFAULT); assert(how < RBT_INVALID); panic("unexpected value for how: %d", how); NOT_REACHABLE; } #else /* !USE_BOOTPARAM */ /* Poweroff without boot monitor */ arch_bios_poweroff(); #endif NOT_REACHABLE; }