日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

android kernel控制台初始化过程

發(fā)布時(shí)間:2024/10/12 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android kernel控制台初始化过程 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.


對(duì)于我們的android平臺(tái),控制臺(tái)被定義到了串口1上,因此初始化過(guò)程就是把控制臺(tái)的輸出配置到串口1上

對(duì)kernel控制臺(tái)初始化是在掛載文件系統(tǒng)之前,由于沒(méi)有串口的設(shè)備文件,不能通過(guò)打開(kāi)設(shè)備文件來(lái)訪問(wèn)串口,只能直接訪問(wèn)硬件,更類(lèi)似與裸機(jī)的訪問(wèn)方式。

下面正式來(lái)看

板子初始化的過(guò)程
android\kernel_imx\arch\arm\mach-mx6\board-mx6q_sabresd.c

MACHINE_START(MX6Q_SABRESD, "Freescale i.MX 6Quad/DualLite/Solo Sabre-SD Board") /* Maintainer: Freescale Semiconductor, Inc. */ .boot_params = MX6_PHYS_OFFSET + 0x100, .fixup = fixup_mxc_board, .map_io = mx6_map_io, .init_irq = mx6_init_irq, .init_machine = mx6_sabresd_board_init, .timer = &mx6_sabresd_timer, .reserve = mx6q_sabresd_reserve, MACHINE_END





這其中有個(gè)時(shí)鐘初始化mx6_sabresd_timer我們來(lái)看它的定義

static struct sys_timer mx6_sabresd_timer = { .init = mx6_sabresd_timer_init, }; static void __init mx6_sabresd_timer_init(void) { struct clk *uart_clk; #ifdef CONFIG_LOCAL_TIMERS twd_base = ioremap(LOCAL_TWD_ADDR, SZ_256); BUG_ON(!twd_base); #endif mx6_clocks_init(32768, 24000000, 0, 0);uart_clk = clk_get_sys("imx-uart.0", NULL); early_console_setup(UART1_BASE_ADDR, uart_clk); }



可以看到這里調(diào)用了early_console_setup(UART1_BASE_ADDR, uart_clk);
這個(gè)函數(shù)就是文件系統(tǒng)掛載之前控制臺(tái)的初始化函數(shù)。下面我就開(kāi)始分析這個(gè)函數(shù)
android\kernel_imx\arch\arm\plat-mxc\cpu.c

/*** early_console_setup - setup debugging console** Consoles started here require little enough setup that we can start using* them very early in the boot process, either right after the machine* vector initialization, or even before if the drivers can detect their hw.** Returns non-zero if a console couldn't be setup.* This function is developed based on* early_console_setup function as defined in arch/ia64/kernel/setup.c* 這個(gè)注釋里寫(xiě)的很清楚,在設(shè)備驅(qū)動(dòng)執(zhí)行之前,為了調(diào)試錯(cuò)誤的需要我們* 需要在啟動(dòng)的最初就初始化控制臺(tái)*/ void __init early_console_setup(unsigned long base, struct clk *clk) { #ifdef CONFIG_SERIAL_IMX_CONSOLE mxc_early_serial_console_init(base, clk); #endif } 這里調(diào)用mxc_early_serial_console_init(base, clk); android\kernel_imx\drivers\tty\serial、mxc_uart_early.c int __init mxc_early_serial_console_init(unsigned long base, struct clk *clk) { mxc_early_device.clk = clk; mxc_early_device.port.mapbase = base;register_console(&mxc_early_uart_console); return 0; }



這里可以看到register_console(&mxc_early_uart_console);就是注冊(cè)一個(gè)設(shè)備到控制臺(tái)中,
在最開(kāi)始注冊(cè)的這個(gè)設(shè)備肯定是裸機(jī)的訪問(wèn)方式的,因此我們重點(diǎn)來(lái)看這個(gè)設(shè)備

static struct console mxc_early_uart_console __initdata = { .name = "ttymxc", .write = early_mxcuart_console_write, .setup = mxc_early_uart_setup, .flags = CON_PRINTBUFFER | CON_BOOT, .index = -1, };



這個(gè)設(shè)備提供的設(shè)備訪問(wèn)接口
.write = early_mxcuart_console_write,是串口的發(fā)送函數(shù)
.setup = mxc_early_uart_setup,是串口的初始化函數(shù)
.flags = CON_PRINTBUFFER | CON_BOOT,是控制臺(tái)標(biāo)志,CON_BOOT表明這事一個(gè)boot的控制臺(tái)設(shè)備
也就是說(shuō)是掛載設(shè)備文件之前的控制臺(tái)設(shè)備


下面我們來(lái)分析初始化函數(shù)和 數(shù)據(jù)發(fā)送函數(shù)
初始化函數(shù)

static int __init mxc_early_uart_setup(struct console *console, char *options) {struct mxc_early_uart_device *device = &mxc_early_device; struct uart_port *port = &device->port; int length;if (device->port.membase || device->port.iobase) return -ENODEV;/* Enable Early MXC UART Clock */ clk_enable(device->clk);//初始化總線時(shí)鐘port->uartclk = 5600000; port->iotype = UPIO_MEM; port->membase = ioremap(port->mapbase, SZ_4K);//串口寄存器內(nèi)存映射if (options) { device->baud = simple_strtoul(options, NULL, 0); length = min(strlen(options), sizeof(device->options)); strncpy(device->options, options, length); } else { device->baud = probe_baud(port); snprintf(device->options, sizeof(device->options), "%u", device->baud); } printk(KERN_INFO"MXC_Early serial console at MMIO 0x%x (options '%s')\n",port->mapbase, device->options); return 0; }


其實(shí)從這個(gè)初始化函數(shù)里看出,它做了很多向mxc_early_device結(jié)構(gòu)體中填入數(shù)據(jù)的工作,而這些數(shù)據(jù)

找遍所有代碼也沒(méi)有用到,因此這些事沒(méi)有意義的,官方代碼給的這點(diǎn)并不太好。但是由于uboot中我們已經(jīng)初始化了

串口因此這里就算沒(méi)有任何初始化其實(shí)串口也可以是使用。

這里真正有用的就兩句話
clk_enable(device->clk);//初始化總線時(shí)鐘
port->membase = ioremap(port->mapbase, SZ_4K);//串口寄存器內(nèi)存映射
但是在寄存器映射結(jié)束后沒(méi)有進(jìn)行任何串口寄存器初始化,這也很奇怪,我們仔細(xì)查找發(fā)現(xiàn),
寄存器初始化代碼寫(xiě)在了數(shù)據(jù)發(fā)送函數(shù)里,具體為什么我們來(lái)分析發(fā)送函數(shù)
early_mxcuart_console_write

/*!* This function is called to write the console messages through the UART port.** @param co the console structure* @param s the log message to be written to the UART* @param count length of the message*/ void __init early_mxcuart_console_write(struct console *co, const char *s, u_int count) { struct uart_port *port = &mxc_early_device.port; unsigned int status, oldcr1, oldcr2, oldcr3, cr2, cr3;/* * First save the control registers and then disable the interrupts */ oldcr1 = readl(port->membase + MXC_UARTUCR1); //讀取當(dāng)前三個(gè)串口控制寄存器的值 oldcr2 = readl(port->membase + MXC_UARTUCR2); oldcr3 = readl(port->membase + MXC_UARTUCR3); cr2 =oldcr2 & ~(MXC_UARTUCR2_ATEN | MXC_UARTUCR2_RTSEN | //初始化串口寄存器數(shù)值MXC_UARTUCR2_ESCI); cr3 =oldcr3 & ~(MXC_UARTUCR3_DCD | MXC_UARTUCR3_RI |MXC_UARTUCR3_DTRDEN); writel(MXC_UARTUCR1_UARTEN, port->membase + MXC_UARTUCR1); //使能串口 writel(cr2, port->membase + MXC_UARTUCR2); //配置寄存器 writel(cr3, port->membase + MXC_UARTUCR3);/* Transmit string */ uart_console_write(port, s, count, mxcuart_console_write_char); //發(fā)送數(shù)據(jù)/* * Finally, wait for the transmitter to become empty等待發(fā)送完成 */ do { status = readl(port->membase + MXC_UARTUSR2); } while (!(status & MXC_UARTUSR2_TXDC));/* * Restore the control registers */ writel(oldcr1, port->membase + MXC_UARTUCR1);//恢復(fù)串口寄存器數(shù)值 writel(oldcr2, port->membase + MXC_UARTUCR2); writel(oldcr3, port->membase + MXC_UARTUCR3); }



從這個(gè)函數(shù)看書(shū),它首先保存了串口控制寄存器的值,然后初始化成符合控制臺(tái)的,發(fā)送完數(shù)據(jù)后,又恢復(fù)了原來(lái)的數(shù)據(jù)
這樣做的目的就是,如果我們加載了串口的驅(qū)動(dòng),那么很有可能打亂了控制臺(tái)的配置,而系統(tǒng)啟動(dòng)以后
我們還不能動(dòng)串口驅(qū)動(dòng)的配置,因此最好的辦法就是,每次發(fā)送數(shù)據(jù)都重新配置串口,發(fā)送完后再恢復(fù)以前的配置。
到了這里控制臺(tái)初始化的第一部分已經(jīng)完成了。我們可以知道沒(méi)有文件系統(tǒng),控制臺(tái)是怎么工作的。

轉(zhuǎn)載于:https://www.cnblogs.com/james1207/p/3253853.html

總結(jié)

以上是生活随笔為你收集整理的android kernel控制台初始化过程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。