网络宣传网站建设制作,网站上线要准备什么,网址价格,wordpress 标签模板下载printk实现原理
printk-tty_write-con_write printk格式化输出 printk的函数#xff0c;用于在控制台上输出格式化的字符串。 该函数使用了可变参数列表#xff0c;可以接受任意数量的参数。 首先#xff0c;使用va_start宏初始化一个va_list类型的变量args#x…printk实现原理
printk-tty_write-con_write printk格式化输出 printk的函数用于在控制台上输出格式化的字符串。 该函数使用了可变参数列表可以接受任意数量的参数。 首先使用va_start宏初始化一个va_list类型的变量args然后使用vsprintf函数将格式化的字符串和可变参数列表args打印到一个缓冲区buf中返回打印的字符数。 首先将fs寄存器和ds寄存器的值压入栈中然后将fs寄存器的值设置为ds寄存器的值这是为了在访问buf时使用fs寄存器因为fs寄存器通常用于指向当前进程的TSS任务状态段而TSS中包含了当前进程的内核栈。然后将打印的字符数i压入栈中接着将buf的地址和一个值为0的参数依次压入栈中调用tty_write函数将buf中的内容写入控制台。最后将栈中的值弹出恢复fs寄存器和ds寄存器的值返回打印的字符数i。 static char buf[1024];extern int vsprintf(char * buf, const char * fmt, va_list args);int printk(const char *fmt, ...)
{va_list args;int i;va_start(args, fmt);ivsprintf(buf,fmt,args);va_end(args);__asm__(push %%fs\n\tpush %%ds\n\tpop %%fs\n\tpushl %0\n\tpushl $buf\n\tpushl $0\n\tcall tty_write\n\taddl $8,%%esp\n\tpopl %0\n\tpop %%fs::r (i):ax,cx,dx);return i;
}tty_write终端输出函数 tty_write函数用于将字符数组buf中的内容写入到指定通道channel对应的终端设备中。函数的返回值是成功写入的字符数。 函数首先检查通道号是否大于2或者写入字符数nr是否小于0如果是则返回-1表示错误。 接下来函数通过将通道号channel与tty_table相加得到对应的tty_struct结构体指针tty。 然后函数进入一个循环直到写入字符数nr为0。在每次循环中函数会调用sleep_if_full函数如果写入队列tty-write_q已满则会使当前进程进入睡眠状态直到队列有足够的空间。 接着函数检查当前进程是否有信号待处理如果有则跳出循环。 然后函数进入一个嵌套循环直到写入字符数nr为0或者写入队列tty-write_q已满。在每次循环中函数从buf中读取一个字符c并根据终端设备的配置进行处理。处理包括将回车符\r转换为换行符\n如果配置允许将换行符\n转换为回车符\r如果配置允许将换行符\n转换为回车符\r并插入队列中如果配置允许将字符转换为大写如果配置允许。然后指针b向后移动一位写入字符数nr减1重置cr_flag为0并将字符c插入到写入队列tty-write_q中。 接着函数调用tty-write函数将写入队列中的字符进行实际的写入操作。 如果写入字符数nr仍大于0则调用schedule函数进行进程调度让其他进程有机会执行。 int tty_write(unsigned channel, char * buf, int nr)
{static int cr_flag0;struct tty_struct * tty;char c, *bbuf;if (channel2 || nr0) return -1;tty channel tty_table;while (nr0) {sleep_if_full(tty-write_q);if (current-signal)break;while (nr0 !FULL(tty-write_q)) {cget_fs_byte(b);if (O_POST(tty)) {if (c\r O_CRNL(tty))c\n;else if (c\n O_NLRET(tty))c\r;if (c\n !cr_flag O_NLCR(tty)) {cr_flag 1;PUTCH(13,tty-write_q);continue;}if (O_LCUC(tty))ctoupper(c);}b; nr--;cr_flag 0;PUTCH(c,tty-write_q);}tty-write(tty);if (nr0)schedule();}return (b-buf);
} con_write将字符写入终端 函数内部定义了一些变量包括nr和c分别表示写入队列中字符的数量和当前字符。 接下来使用while循环循环次数为写入队列中字符的数量。 在循环中使用GETCH宏从写入队列中获取一个字符并使用switch语句根据字符的不同进行不同的操作。 在case 0中如果字符的ASCII码在31和127之间表示是可打印字符会进行一系列的操作包括判断是否需要换行、设置字符属性、更新光标位置等。 在case 1中如果字符是[表示后面是控制序列会进入case 2进行处理。 在case 2中会解析控制序列中的参数并根据参数执行相应的操作比如移动光标、清除屏幕等。 最后调用set_cursor函数设置光标位置。 void con_write(struct tty_struct * tty)
{int nr;char c;nr CHARS(tty-write_q);while (nr--) {GETCH(tty-write_q,c);switch(state) {case 0:if (c31 c127) {if (xvideo_num_columns) {x - video_num_columns;pos - video_size_row;lf();}__asm__(movb attr,%%ah\n\tmovw %%ax,%1\n\t::a (c),m (*(short *)pos));pos 2;x;} else if (c27)state1;else if (c10 || c11 || c12)lf();else if (c13)cr();else if (cERASE_CHAR(tty))del();else if (c8) {if (x) {x--;pos - 2;}} else if (c9) {c8-(x7);x c;pos c1;if (xvideo_num_columns) {x - video_num_columns;pos - video_size_row;lf();}c9;} else if (c7)sysbeep();break;case 1:state0;if (c[)state2;else if (cE)gotoxy(0,y1);else if (cM)ri();else if (cD)lf();else if (cZ)respond(tty);else if (x7)save_cur();else if (x8)restore_cur();break;case 2:for(npar0;nparNPAR;npar)par[npar]0;npar0;state3;if ((ques(c?)))break;case 3:if (c; nparNPAR-1) {npar;break;} else if (c0 c9) {par[npar]10*par[npar]c-0;break;} else state4;case 4:state0;switch(c) {case G: case :if (par[0]) par[0]--;gotoxy(par[0],y);break;case A:if (!par[0]) par[0];gotoxy(x,y-par[0]);break;case B: case e:if (!par[0]) par[0];gotoxy(x,ypar[0]);break;case C: case a:if (!par[0]) par[0];gotoxy(xpar[0],y);break;case D:if (!par[0]) par[0];gotoxy(x-par[0],y);break;case E:if (!par[0]) par[0];gotoxy(0,ypar[0]);break;case F:if (!par[0]) par[0];gotoxy(0,y-par[0]);break;case d:if (par[0]) par[0]--;gotoxy(x,par[0]);break;case H: case f:if (par[0]) par[0]--;if (par[1]) par[1]--;gotoxy(par[1],par[0]);break;case J:csi_J(par[0]);break;case K:csi_K(par[0]);break;case L:csi_L(par[0]);break;case M:csi_M(par[0]);break;case P:csi_P(par[0]);break;case :csi_at(par[0]);break;case m:csi_m();break;case r:if (par[0]) par[0]--;if (!par[1]) par[1] video_num_lines;if (par[0] par[1] par[1] video_num_lines) {toppar[0];bottompar[1];}break;case s:save_cur();break;case u:restore_cur();break;}}}set_cursor();
}