uclinux-2008r1-rc8(bf561)内核的console(3):通过console输出信息

本文详细解析了Linux内核中console输出信息的过程,从release_console_sem函数开始,依次介绍了call_console_drivers、_call_console_drivers及__call_console_drivers等关键函数的作用,并最终落实到具体的硬件输出函数上。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 
在内核中,向console输出信息是通过release_console_sem函数来完成的:
/**
 * release_console_sem - unlock the console system
 *
 * Releases the semaphore which the caller holds on the console system
 * and the console driver list.
 *
 * While the semaphore was held, console output may have been buffered
 * by printk(). If this is the case, release_console_sem() emits
 * the output prior to releasing the semaphore.
 *
 * If there is output waiting for klogd, we wake it up.
 *
 * release_console_sem() may be called from any context.
 */
void release_console_sem(void)
{
     unsigned long flags;
     unsigned long _con_start, _log_end;
     unsigned long wake_klogd = 0;
 
     if (console_suspended) {
         up(&secondary_console_sem);
         return;
     }
 
     console_may_schedule = 0;
 
     for ( ; ; ) {
         spin_lock_irqsave(&logbuf_lock, flags);
         wake_klogd |= log_start - log_end;
         if (con_start == log_end)
              break;             /* Nothing to print */
         _con_start = con_start;
         _log_end = log_end;
         con_start = log_end;        /* Flush */
         spin_unlock(&logbuf_lock);
         call_console_drivers(_con_start, _log_end);
         local_irq_restore(flags);
     }
     console_locked = 0;
     up(&console_sem);
     spin_unlock_irqrestore(&logbuf_lock, flags);
     if (wake_klogd)
         wake_up_klogd();
}
在这里,实际输出通过call_console_drivers函数完成:
/*
 * Call the console drivers, asking them to write out
 * log_buf[start] to log_buf[end - 1].
 * The console_sem must be held.
 */
static void call_console_drivers(unsigned long start, unsigned long end)
{
     unsigned long cur_index, start_print;
     static int msg_level = -1;
 
     BUG_ON(((long)(start - end)) > 0);
 
     cur_index = start;
     start_print = start;
     while (cur_index != end) {
         if (msg_level < 0 && ((end - cur_index) > 2) &&
                   LOG_BUF(cur_index + 0) == '<' &&
                   LOG_BUF(cur_index + 1) >= '0' &&
                   LOG_BUF(cur_index + 1) <= '7' &&
                   LOG_BUF(cur_index + 2) == '>') {
              msg_level = LOG_BUF(cur_index + 1) - '0';
              cur_index += 3;
              start_print = cur_index;
         }
         while (cur_index != end) {
              char c = LOG_BUF(cur_index);
 
              cur_index++;
              if (c == '/n') {
                   if (msg_level < 0) {
                       /*
                        * printk() has already given us loglevel tags in
                        * the buffer. This code is here in case the
                        * log buffer has wrapped right round and scribbled
                        * on those tags
                        */
                       msg_level = default_message_loglevel;
                   }
                   _call_console_drivers(start_print, cur_index, msg_level);
                   msg_level = -1;
                   start_print = cur_index;
                   break;
              }
         }
     }
     _call_console_drivers(start_print, end, msg_level);
}
继续跟踪_call_console_drivers
/*
 * Write out chars from start to end - 1 inclusive
 */
static void _call_console_drivers(unsigned long start,
                   unsigned long end, int msg_log_level)
{
     if ((msg_log_level < console_loglevel || ignore_loglevel) &&
              console_drivers && start != end) {
         if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) {
              /* wrapped write */
              __call_console_drivers(start & LOG_BUF_MASK,
                            log_buf_len);
              __call_console_drivers(0, end & LOG_BUF_MASK);
         } else {
              __call_console_drivers(start, end);
         }
     }
}
继续跟踪__call_console_drivers
/*
 * Call the console drivers on a range of log_buf
 */
static void __call_console_drivers(unsigned long start, unsigned long end)
{
     struct console *con;
 
     for (con = console_drivers; con; con = con->next) {
         if ((con->flags & CON_ENABLED) && con->write &&
                   (cpu_online(smp_processor_id()) ||
                   (con->flags & CON_ANYTIME)))
              con->write(con, &LOG_BUF(start), end - start);
     }
}
嘿嘿,原来是调用console结构体中的write函数!记得我们在内核中是使用了bfin_serial_console做为我们的console,而这个结构体中的write回调函数则初始化为bfin_serial_console_write,这个函数在drivers/serial/bfin_5xx.c
/*
 * Interrupts are disabled on entering
 */
static void
bfin_serial_console_write(struct console *co, const char *s, unsigned int count)
{
     struct bfin_serial_port *uart = &bfin_serial_ports[co->index];
     int flags = 0;
 
     spin_lock_irqsave(&uart->port.lock, flags);
     uart_console_write(&uart->port, s, count, bfin_serial_console_putchar);
     spin_unlock_irqrestore(&uart->port.lock, flags);
}
再跟踪uart_console_write此函数位于drivers/serial/serial_core.c
/*
 *   uart_console_write - write a console message to a serial port
 *   @port: the port to write the message
 *   @s: array of characters
 *   @count: number of characters in string to write
 *   @write: function to write character to port
 */
void uart_console_write(struct uart_port *port, const char *s,
              unsigned int count,
              void (*putchar)(struct uart_port *, int))
{
     unsigned int i;
 
     for (i = 0; i < count; i++, s++) {
         if (*s == '/n')
              putchar(port, '/r');
         putchar(port, *s);
     }
}
因为uart是一个通用的抽象接口,它需要指定与具体硬件相关的函数来进行输出,在我们的调用中使用了bfin_serial_console_putchar做为回调函数,因此实际输出是通过bfin_serial_console_putchar来完成的,此函数在drivers/serial/bfin_5xx.c
static void bfin_serial_console_putchar(struct uart_port *port, int ch)
{
     struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
     while (!(UART_GET_LSR(uart) & THRE))
         barrier();
     UART_PUT_CHAR(uart, ch);
     SSYNC();
}
 
 
 
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌云阁主

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值