Qualcomm platform Aboot saves UART log to kernel via shared memory

Source: Internet
Author: User
Document PurposeShared memory is the sharing of memories, and the sharing of information between different processes through a small segment of memory, enabling interprocess communication. This article mainly introduces the transmission of information between Qualcomm Aboot (LK) and the kernel (kernel). In the traditional lk-"kernel information is used cmdline, but this method is only suitable for passing short information, for a large segment of information (such as all the UART log in aboot) can not be passed. So here we use shared memory to pass, first of all the UART log in the aboot in a certain memory, and then lossless transfer to the kernel, read out in the kernel.
Specific Implementationaboot print log, log save, log write memory, startup kernel, read log 1.aboot Print LogThe log print function in Aboot is dprintf, and its prototype is defined in Bootable/bootloader/lk/include/debug.h:
#define DPRINTF (level, x ...) do {if (level) <= debuglevel) {_dprintf (x);}} while (0)
It also calls _dprintf (x), defined in BOOTABLE/BOOTLOADER/LK/LIB/DEBUG/DEBUG.C:
int _dprintf (const char *fmt, ...)
{
	char buf[256];
	Char ts_buf[13];
	int err;

	snprintf (ts_buf, sizeof (TS_BUF), "[%u]", (unsigned int) current_time ());  Serial log front plus timestamp
	dputs (always, ts_buf);

	Va_list ap;
	Va_start (AP, FMT);
	Err = vsnprintf (buf, sizeof (BUF), FMT, AP);  Parsing format
	Va_end (AP);

	Dputs (always, buf);

	return err;
}
Call to the Dputs function, Bootable/bootloader/lk/include/debug.h:
#define DPUTS (level, str) does {if (level) <= debuglevel) {_dputs (str);}} and (0)
Look again at the _dputs (str) function, BOOTABLE/BOOTLOADER/LK/LIB/DEBUG/DEBUG.C:
int _dputs (const char *str)
{
	while (*str! = 0) {
		_DPUTC (*str++);
	}

	return 0;
}
You can see here that the char string is split into a char with a char through the _DPUTC output, bootable/bootloader/lk/platform/msm_shared/debug.c:
void _dputc (char c)
{
#if with_debug_log_buf
	LOG_PUTC (c);
#endif
#if WITH_DEBUG_DCC
	if (c = = ' \ n ') {
		write_dcc (' \ R ');
	}
	WRITE_DCC (c);
#endif
#if with_debug_uart
	uart_putc (0, c);
#endif
#if with_debug_fbcon && with_dev_fbcon
	FBCON_PUTC (c);
#endif
#if with_debug_jtag
	JTAG_DPUTC (c);
#endif
}
Here we define a number of output methods, we usually see the UART log, is through the above UART_PUTC (0, c) output, here we are not in depth. We just have to get all the char in this method.

2.log SaveThe parameters in the above method are all char types, such as we call dprintf (Always, "test\n"), then _DPUTC will be called 5 times, the parameters are ' t ', ' e ', ' s ', ' t ', ' \ n ', here we refer to the Log_putc method, Use a char character array to save these char sequentially:
#ifdef Support_lk_uart_to_kernel
	KERNEL_LOG_PUTC (c);
#endif
Where the above macros are defined in the relevant MK file. Take a look at the related implementations of KERNEL_LOG_PUTC:
#define Uart_log_buf_size    (31*1024)/* Align on 31k *       ///Here we apply 31K space to save
bool freed = false;

struct Uart_log {        //preserve the structure of the UART
	struct Uart_log_header {
		unsigned max_size;    Maximum value
		unsigned size_written;
		unsigned idx;
	} header;
	Char data[uart_log_buf_size];   A char array that uses this array to hold char
};

static struct Uart_log log = {  //struct initialization
	. Header = {
		. max_size = sizeof (Log.data),
		. Size_written = 0,< C19/>.idx = 0,
	},
	. data = {0}
};

void Kernel_log_putc (char c) {    //important function, important function, important function
	if (!freed) {
		log.data[log.header.idx] = c;    Character array assignment
		log.header.size_written++;   Number of characters written
		log.header.idx++;   The character array subscript increments by 1
		if (unlikely (Log.header.idx >= log.header.max_size))
			log.header.idx = 0;}
}
Each sentence in the Aboot log is split into char stored in the data character array of the above log struct, and eventually the character array will be a very long array.

3.log Write MemoryThe struct above is a temporary variable, and all we need to do is write the data array in the struct to memory before starting the kernel, and save the memory for use by other processes. First we have to find a blank memory in memory, for the sake of security, we put the device tree and RAMDisk load the address of the back offset 32k (0x8000), set aside 32k for us to save log use:
The starting position of each address is at Bootable/bootloader/lk/platform/msm8952/include/platform/iomap.h:
#ifdef Support_lk_uart_to_kernel    //Ddr_start 0x10000000
#define ABOOT_FORCE_UART_ADDR              Ddr_start + 0x3400000/      * 31k */
#define ABOOT_FORCE_UART_COUNT_ADDR         Ddr_start + 0x3407c00  */1k */
#define Aboot_force_tags_addr              Ddr_start + 0x3408000    //offset 0x8000
#define ABOOT_FORCE_RAMDISK_ADDR           ddr_ START + 0x3608000    //offset 0x8000
#else
#define ABOOT_FORCE_TAGS_ADDR              Ddr_start + 0x3400000
# Define ABOOT_FORCE_RAMDISK_ADDR           Ddr_start + 0x3600000
#endif
Writes the data array to memory before the boot_linux ends in aboot:
#ifdef Support_lk_uart_to_kernel
	Send_uart_to_kernel ();
#endif
void Send_uart_to_kernel () {
	char cnt_buf[6];
	snprintf (char *) cnt_buf, sizeof (CNT_BUF), "%d", log.header.idx);
	memcpy ((void*) aboot_force_uart_addr, (char*) log.data, sizeof (Log.data));
	memcpy (void*) aboot_force_uart_count_addr, Cnt_buf, sizeof (CNT_BUF));
	Freed = true;
}
The above functions have two functions:
A. Use memcpy to write the character array to the ABOOT_FORCE_UART_ADDR address (0x13400000)
B. Use memcpy to write the number of characters to the ABOOT_FORCE_UART_COUNT_ADDR address (0X13407C00)
Then start the kernel kernel.
4.log ReadIn the kernel, you can create a new proc node and then implement the read log operation in the proc node's Read method. (How to create a new proc node is not within the scope of this article) the following is the implementation method:
#define PAGE_BUF_SIZE 1024x768 #define UART_LOG_TOTAL_SIZE 0x7c00/* 0x7c00 is 31k, refers to aboot * * static int Abo
	Ot_uart_show (struct seq_file *m, void *v) {unsigned long uart_start_phy_addr, uart_cnt_phy_addr;
	void * UART_START_VIRT_ADDR;
	void * UART_CNT_VIRT_ADDR;
	Char Buf[page_buf_size], cnt[8];
	unsigned long Count;

	int page = 0;    UART_START_PHY_ADDR = Simple_strtoul (aboot_add_buf, NULL, 0);   0x13400000 uart_cnt_phy_addr = uart_start_phy_addr + uart_log_total_size;   0X13407C00 uart_start_virt_addr = Phys_to_virt (UART_START_PHY_ADDR);    Convert to virtual address uart_cnt_virt_addr = Phys_to_virt (UART_CNT_PHY_ADDR);   Convert to Virtual address memcpy (CNT, uart_cnt_virt_addr, sizeof (CNT));

	Initialize count = Simple_strtoul (CNT, NULL, 0);
	seq_printf (M, "total buf count =%lu\n", count); seq_printf (M, "\n>>>>>>>>>>>>>>> lk UART log <<<<<<

	<<<<<<<<<\n\n "); for (page = 0; page <= (int) (count/pAge_buf_size); page++) {if (page = = (int) (count/page_buf_size)) {//Last read memcpy (BUF, uart_start_virt_addr + page * page_buf_s
			IZE, (int) (count%page_buf_size));
			Buf[count%page_buf_size-1] = ' + ';
		seq_printf (M, "%s\n", buf);
			} else {//read Page_buf_size bytes (1024x768) memcpy (BUF, uart_start_virt_addr + page * page_buf_size, page_buf_size) per reading;
			Buf[page_buf_size-1] = ' + ';
		seq_printf (M, "%s", buf);
}} return 0; }
Gets the starting physical address of the data array in Aboot, the start address of the character count store, and then converts to the virtual address, starting with the data start address, reading 1024 bytes each time, and the address pointer being offset by 1024 bytes until the count character is read.
In addition, in order to prevent 0x13400000-0x13408000 this address is reassigned, we want to keep this paragraph, modify Kernel/msm-3.18/arch/arm64/boot/dts/msm8937.dtsi, add the following statement:
		aboot_uart_mem:aboot_uart_region@13400000 {
			compatible = "Removed-dma-pool";
			No-map;
			reg = <0x0 0x13400000 0x0 0x7c00>;
		};

		aboot_uart_cnt_mem:aboot_uart_cnt_region@0 {
			compatible = "Removed-dma-pool";
			No-map;
			reg = <0x0 0x13407c00 0x0 0x400>;
		};



Process Overview Map:

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.