code:physio - ikarishinjieva/unixV6-code-analyze-chs GitHub Wiki
- 用于处理"原始"输入/输出操作,即跳过缓存机制,直接在内存与磁盘中进行数据传输
- 传入4个参数:
- start : 设备处理I/O请求的函数
- abp : "特殊缓存块",设备专用于"原始"输入/输出操作的缓存块
- dev : 设备号
- rw : 读/写标志位
- 隐式调用的参数:
- u.u_base:I/O的内存起始地址
- u.u_offset:I/O的磁盘起始地址
- u.u_count:I/O的字节数
- u.u_sep:指令空间与用户空间是否分开
5248
5249 /*
5250 * Raw I/O. The arguments are
5251 * The strategy routine for the device
5252 * A buffer, which will always be a special buffer
5253 * header owned exclusively by the device for this purpose
5254 * The device number
5255 * Read/write flag
5256 * Essentially all the work is computing physical addresses
5257 * and validating them.
5258 */
5259 physio(strat, abp, dev, rw)
5260 struct buf *abp;
5261 int (*strat)();
5262 {
5263 register struct buf *bp;
5264 register char *base;
5265 register int nb;
5266 int ts;
5267
5268 bp = abp;
5269 base = u.u_base;
5270 /*
- base置为I/O传输的内存首地址
5271 * Check odd base, odd count, and address wraparound
5272 */
5273 if (base&01 || u.u_count&01 || base >= base+u.u_count)
5274 goto bad;
5275 ts = (u.u_tsize+127) & ~0177;
- 若内存起始地址是奇地址(即不是一个字的首地址),或要传输的字节为奇字节,或要传输的字节数不为正
- 进行出错处理
5276 if (u.u_sep)
- ts置为共享正文段最后一页的下一页的首块块号(即数据段第一页的首块号)
- 参看Pdp11:内存管理
5277 ts = 0;
5278 nb = (base>>6) & 01777;
- 检查指令区和数据区是否分开,对于pdp11/40,u.u_sep恒为0
5279 /*
- nb = I/O传输的内存起始块号
5280 * Check overlap with text. (ts and nb now
5281 * in 64-byte clicks)
5282 */
5283 if (nb < ts)
5284 goto bad;
5285 /*
- 若内存起始块号在正文段范围之内,进行出错处理
5286 * Check that transfer is either entirely in the
5287 * data or in the stack: that is, either
5288 * the end is in the data or the start is in the stack
5289 * (remember wraparound was already checked).
5290 */
5291 if ((((base+u.u_count)>>6)&01777) >= ts+u.u_dsize
5292 && nb < 1024-u.u_ssize)
5293 goto bad;
5294 spl6();
- 如果要传输的内容横跨数据段和代码段
- 进行出错处理
5295 while (bp->b_flags&B_BUSY) {
- 以下是对"特殊缓存块"的处理,为保持临界资源互斥,故需关中断
5296 bp->b_flags =| B_WANTED;
5297 sleep(bp, PRIBIO);
5298 }
- 若"特殊缓存块"当前被占用,置B_WANTED标志
- 进程睡眠
- 睡眠原因:struct buf
- 睡眠优先级:PRIBIO
5299 bp->b_flags = B_BUSY | B_PHYS | rw;
5300 bp->b_dev = dev;
5301 /*
5302 * Compute physical address by simulating
5303 * the segmentation hardware.
5304 */
5305 bp->b_addr = base&077;
5306 base = (u.u_sep? UDSA: UISA)->r[nb>>7] + (nb&0177);
5307 bp->b_addr =+ base<<6;
5308 bp->b_xmem = (base>>10) & 077;
5309 bp->b_blkno = lshift(u.u_offset, -9);
5310 bp->b_wcount = -((u.u_count>>1) & 077777);
5311 bp->b_error = 0;
5312 u.u_procp->p_flag =| SLOCK;
5313 (*strat)(bp);
- 对"特殊缓存块"进行相关赋值,并在最后将当前进程置SLOCK标志
5314 spl6();
- 启动设备I/O处理函数
5315 while ((bp->b_flags&B_DONE) == 0)
- 关中断,原因同上
5316 sleep(bp, PRIBIO);
5317 u.u_procp->p_flag =& ~SLOCK;
- 若"特殊缓存块"I/O尚未完成
- 进程睡眠
- 睡眠原因:struct buf
- 睡眠优先级:PRIBIO
5318 if (bp->b_flags&B_WANTED)
5319 wakeup(bp);
5320 spl0();
5321 bp->b_flags =& ~(B_BUSY|B_WANTED);
5322 u.u_count = (-bp->b_resid)<<1;
- 待"特殊缓存块"I/O结束后,判断是否有B_WANTED标志
- 若有,则唤醒睡眠在"特殊缓存块"上的进程
- 开中断
- 清B_BUSY与B_WANTED标志
5323 geterror(bp);
5324 return;
- I/O过程中的出错处理
- 将未能传输的字数赋给u.u_count
- 对错误进行相关处理
5325 bad:
5326 u.u_error = EFAULT;
5327 }
- 出错处理
- 错误代码:EFAULT
5328 /* ------------------------- */
|ref =