pmon--printf显示分析

转自 LeeWg:http://blogold.chinaunix.net/u3/94960/showart_2056380.html

 

 

1: __init()函数的解释:
    Pmon中有三类constructor函数,他们都是静态函数,此类函数都有一个共性就是受__attribute__((constructor))属性修饰,例如
    Static void init_fs __P((void)) __attribute__((constructor))
下面说明三类函数:
        a:命令处理函数,位于pmon/cmds目录,其名称都叫init_cmd(),该目录下几乎每个函数都有。
        b:文件系统初始化函数,位于pmon/fs目录,其名称叫init_fs()或init_xxxfs()。例如init_diskfs、init_fs、init_netfs等。
        c:可执行文件类型初始化函数,位于pmon/loaders目录中exec_*.c文件中,函数叫init_exec()。

2:利用uart实现printf()函数功能:
1:涉及结构体
ConfigEntry ConfigTable[]数组实现设备和操作函数的关联。如下:
315 ConfigEntry ConfigTable[] =
316 {
        { (char *)COMMON_COM_BASE_ADDR, 0, ns16550, 256, CONS_BAUD, NS16550HZ },
 333 #if NMOD_VGACON >0
 334 #if NMOD_FRAMEBUFFER >0
 335         { (char *)1, 0, fbterm, 256, CONS_BAUD, NS16550HZ },
 336 #else  
 337         { (char *)1, 0, vgaterm, 256, CONS_BAUD, NS16550HZ },
 338 #endif     
 339 #endif     
 340 #ifdef DEVBD2F_FIREWALL
 341         { (char *)LS2F_COMB_ADDR, 0, ns16550, 256, CONS_BAUD, NS16550HZ/2 ,1},
 342 #endif
 343         { 0 } 
 344 };
     以上面红色为例说明:
        COMMON_COM_BASE_ADDR :串口的地址
        0 : chan在程序中用到<用途现在还不清楚>
        Ns16550 :和串口相关的操作函数
        256 :缓冲区大小<uart 接受和发送>
        COMS_BAUD :波特率
        NS16550HZ :频率
        Flag :标志<为实现此处>

    FILE结构体,对打开文件的描述
22 typedef struct FILE {
         23     int fd;
         24     int valid;
         25     int ungetcflag;
         26     int ungetchar;
         27 } FILE;

    FILE _iob[OPEN_MAX]数组实现
52     FILE   _iob[OPEN_MAX] =
         53  {
         54       {0, 1},
         55         {1, 1},
           56      {2, 1},
           57        {3, 1},
           58        {4, 1},
           59      };

具体printf实现过程:
    1:__init()函数调用init_fs()函数:实现对ns16550串口设备的初始化<devinit()函数实现>;插入基于终端的文件系统<filefs_init()函数实现>;FILE结构体初始化<实现标准I/O的适当方法>、open 0-5 6个tty设备分别对应:stdin、stdout、stderr、kbdin、vgain、vgaout。
    pmon中实现的文件系统:
        51 #define FS_NULL     0   /* Null FileSystem */
         52 #define FS_TTY       1   /* tty://   TTY */
         53 #define FS_NET       2   /* tftp://  Network */
         54 #define FS_SOCK      3   /* socket://    Socket */
         55 #define FS_DEV       4   /* dev://   Raw device */
         56 #define FS_MEM      5   /* mem://   Memory */
         57 #define FS_FILE       6   /* file://  Structured File */

    终端文件系统处理函数结构体:
552 static FileSystem termfs =
553 {
554         "tty", FS_TTY,
555         term_open,
556         term_read,
557         term_write,
558         NULL,
559         term_close,
560         term_ioctl
561 };

Init_fs()函数实现:
563 static void init_fs __P((void)) __attribute__ ((constructor));
564 
565         static void
566 init_fs()
567 {
568         SBD_DISPLAY ("DEVI", CHKPNT_DEVI);
569         devinit ();     /* initial ns16550 */
570 
571         /*
572          * Install terminal based file system.
573          */
574         filefs_init(&termfs);
575 
576         /*
577          * Create the standard i/o files the proper way
578          */
579         _file[0].valid = 1;
580         _file[0].fs = &termfs;
581         _file[1].valid = 1;
582         _file[1].fs = &termfs;
583         _file[2].valid = 1;
584         _file[2].fs = &termfs;
585         _file[3].valid = 1;
586         _file[3].fs = &termfs;
587         _file[4].valid = 1;
588         _file[4].fs = &termfs;
589         _file[5].valid = 1;
590         _file[5].fs = &termfs;
        _file[]数组的0-5的初始化,实现了文件系统和操作方法的关联

591         term_open(0, "/dev/tty0", 0, 0); /* stdin */
592         term_open(1, "/dev/tty0", 0, 0); /* stdout */
593         term_open(2, "/dev/tty0", 0, 0); /* stderr */
594         term_open(3, "/dev/tty1", 0, 0); /* kbdin */
595         term_open(4, "/dev/tty1", 0, 0); /* vgaout */
596         term_open(5, "/dev/tty2", 0, 0); /* vgaout */
        将5个基本的输入输出文件都打开,以便下面printf和vga输出调用。
597 }


    2:printf()实现:
        38 int 
         39 printf (const char *fmt, ...)
         40 {
 41     int             len;
         42     va_list     ap;
         43 
         44     va_start(ap, fmt);
         45     len = vfprintf (stdout, fmt, ap);
         46     va_end(ap);
         47     return (len);
         48 }
        Stdout的定义:
        #define stdout  (vga_available?(&_iob[4]):(&_iob[1]));stdout为输出文件描述符,用来确定输出到那个tty设备,在此可选的值符合__iob数组每个元素的第一个值。
    3:vfprintf()实现:
        49 int 
 50 vfprintf (FILE *fp, const char *fmt, va_list ap)
         51 {
         52     int  n;
         53     char buf[1024];
         54 #ifdef FASTBOOT
         55     static int inited=0;
         56     if(!inited)
         57     {
         58             if(getenv("novga"))
     59                     novga=1;
         60             inited=1;
         61     }
         62     if((fp==&_iob[1])&&!novga)
         63             return n;
         64 #endif
         65     n = vsprintf (buf, fmt, ap);
         66     fputs (buf, fp);
         67     return (n);
         68 }
    此函数仅仅将输入参数按格式存入到buf中,并调用fputs来真正实现输出。
    4:fputs()实现:
        39 int
         40 fputs(const char *p, FILE *fp)
         41 {
         42     write (fp->fd, p, strlen (p));   
         43     return(0); 
         44 }
        通过write将p中的数据输出到pf->fd所描述的文件描述符中,这里对应的是uart的输出。
    5:write()函数的实现:
    在此处,write调用的是term_write()函数,这一步的关联在init_fs()中实现。
        119 int
120 term_write (int fd, const void *buf, size_t nchar)
121 {
122         DevEntry       *p;
123         struct TermDev *devp;
124         char *buf2 = (char *)buf;
125         int i, n;
126         int dsel;
127         int count;
128 
129         devp = (struct TermDev *)_file[fd].data;
130         p = &DevTable[devp->dev];
131         n = nchar;
132         dsel=devp->dev;
133 
134         do
135         {
136                 p = &DevTable[dsel];
137                 buf2 = (char *)buf;
138                 n = nchar;
139 
140                 while (n > 0) {
141                         /* << LOCK >> */
142                         while(!tgt_smplock());
143 
144                         i = Qspace (p->txq);
145                         while (i > 2 && n > 0) {
146                            if ((p->t.c_oflag & ONLCR) && *buf2 == '/n') {
147                                         Qput(p->txq, '/r');
148                                         i--;
149                                 }
150                                 Qput(p->txq, *buf2++);
151                                 n--;
152                                 i--;
153                         }
154                         tgt_smpunlock();
155                         /* << UNLOCK >> */
156 
157                         while (Qused(p->txq)) {
158                                 scandevs();
159                         }
160                 }
161                 dsel=DevTable[dsel+1].handler?dsel+1:0;
162         }while(dsel!=devp->dev && output_to_both);
163 
164         return (nchar);
165 }
    在scandevs()中,通过ns16550()函数实现了对串口的读写。
    6:scandevs()函数的实现:
        179         void
180 scandevs ()
181 {
182     int     s, c, n;
183     DevEntry    *p;
184 
185 
186     for (p = DevTable; p->rxq; p++) {
187            /* << LOCK >> */
188         while(!tgt_smplock());
189 
190         /* Read queue */
191         while ((*p->handler) (OP_RXRDY, p, NULL, NULL)) {
192             c = (*p->handler) (OP_RX, p, NULL, NULL);  //ns16550调用
193             if (p->t.c_iflag & ISTRIP)
194                  c &= 0x7f;
195 
196                  if (p->t.c_lflag & ISIG) {
197                       if (c == p->t.c_cc[VINTR]) {
198                             gsignal (p->intr/*XXX*/, 2 /*SIGINT*/);
199                             continue;
200                        }
201                    }
202                    if (p->t.c_iflag & IXON) {
203                         if (p->t.c_iflag & IXANY && p->txoff) {
204                              p->txoff = 0;
205                              continue;
206                          }
207                          if (c == p->t.c_cc[V_STOP]) {
208                               p->txoff = 1;
209                               continue;
210                          }
211                          if (c == p->t.c_cc[V_START]) {
212                                p->txoff = 0;
213                                continue;
214                          }
215                    }
216 
217                    n = Qspace (p->rxq);
218                    if (n > 0) {
219                         Qput (p->rxq, c);
220                         if (n < 20 && !p->rxoff) {
221                              (*p->handler) (OP_RXSTOP, p, NULL, p->rxoff = 1);
222                              if (p->t.c_iflag & IXOFF)
223                                   chwrite (p, CNTRL ('S'));
224                          }
225                     }
226                     else break;
227               }
228 
229               /* Write queue */
230               n = Qused (p->txq);
231                while (n > 0 && !p->txoff &&
232                      (*p->handler)(OP_TXRDY, p, NULL, NULL)) {
233                      char c = Qget(p->txq);
234                      (*p->handler) (OP_TX, p, NULL, c);
235                      n--;
236                 }
237 
238                 tgt_smpunlock();
239                 /* << UNLOCK >> */
240         }
241 
242 #if defined(SMP)
243         if (tgt_smpwhoami() != 0)
244                 return;     /* Only CPU 1 is allowed to run kernel */
245 #endif
246 #if 1   //delay 10 micro seconds    
247         {
248                 int i;
249                 for(dummy=1,i=0; i<200; i++){
250                         dummy*=i;
251                 }
252         }
253 #endif
254         s = splhigh();      /* Trigg the polled interrupt system */
255         splx(s);
256 
257 #ifdef NETIO
258         tgt_netpoll ();     /* XXX this one should die! */
259 #endif
260 #if NMOD_VGACON >0
261 #if NMOD_USB_KBD >0
262         if (usb_kbd_available)
263                 usb_kbd_poll();
264 #endif
265         if (kbd_available)
266                 kbd_poll();
267 #endif
268 }

你可能感兴趣的:(pmon--printf显示分析)