ARMLINUX BootLoader Detailed

xiaoxiao2021-03-06  21

introduction

Online Bootloader article on Linux, but most of them are vivi, blob, etc., is not convenient to read, compiled files, and more guidance code for development, When the product is reduced, this has affected the development speed, which is relatively large for beginners, and analyzes a simple bootloader in the 2410 bootloader provided by Samsung, compiled. The file size does not exceed 4K, I hope to help everyone.

1. Several important concepts compressed kernel and decressed kernel compressed kernel, according to documentation, do not advocate use Decompressed Kernel, and use Compressed Kernel, which includes the compressor. Therefore, it is necessary to compress and decompress the Kernel when RAM is assigned. Provide enough space so they do not cover each other. When the execution instruction jumps to the compressed kernel, the decompression is started. If the decompression detects the decompressed code overrides the compressed kernel, then it will jump directly to the compressed kernel. Store data and reposition KERNEL, so if there is not enough space, it will be wrong. Jffs2 file system can save the data generated in the armlinux application on Flash, my board has not been used yet. Ramdisk uses ramdisk to make root file SYSTEM is started without other devices. Generally there are two ways to load, I will introduce the most commonly used, put the compressed ramdisk image to the specified address, and then pass this address to the kernel by bootloader.... Specific code analysis. Startup parameters (from IBM Developer) should be prepared for a step before calling the kernel, namely: Set the startup parameters of the Linux kernel. The kernel after Linux 2.4.x expects to pass the startup parameters in the form of tagged list. Start the parameter tag list to mark Atag_core to mark the Atag_none end. Each tag is composed of a Tag_Header structure that is identified, and subsequent parameter values ​​data structures. Data structure tag and tag_header define in the include / asm / setup.h header file of the Linux kernel source code. In embedded Linux systems, usually need to be set by the bootloader settings: ATAG_CORE, ATAG_MEM, ATAG_CMDLINE, ATAG_RAMDISK, ATAG_INITRD, etc. . (Note) The parameters can also be set with CommandLine. In my bootloader, I have two types. 2.

Development Environment and Development Board Configuration: CPU: S3C2410, Bank6 has 64M SDRAM (two), 32M Nor Flash on Bank0, the serial port is certainly can't escape. This way, the address assignment is as follows: 0x4000_0000 starts 4K's on-chip DRAM. 0x0000_0000 starts to be 32M Flash 16bit width 0x3000_0000 Starting to be 64M SDRAM 32bit Width Note: The Bank6 and Bank7 parts in the control register must be the same. 0x4000_0000 (on-chip DRAM) Starting 4K Bootloader Image 0x3000_0100 Start Start Starting Parameters 0x3120_0000 store COMPRESSED KERNEL IMAGE 0x3200_0000 store COMPRESSED RAMDISK 0x3000_8000 designated as dECOMPRESSED KERNEL IMAGE ADDRESS 0x3040_0000 designated as dECOMPRESSED RAMDISK IMAGE ADDRESS development environment: Redhat Linux, armgcc toolchain, how armlinux KERNEL establish armgcc compiler environment: It is recommended to use toolchain, rather than their own to compile Armgcc, I have a lot of time, I have ended in failure. First download ARM-GCC 3.3.2 Toolchain will decompress ARM-Linux-GCC-3.3.2.tar.bz2 to / Toolchain # tar jxvf ARM-Linux-GCC-3.3 .2.tar.bz2 # mv /usr/local/arm/3.3.2 / Toolchain In Makefile, set Arch = ARM CROSS_COMPILE to Toolchain The path is include = -i ../include -i / root / MY / USR / local / ARM / 3.3.2 / include. Otherwise, the library function cannot be used 3. Start mode: You can start in Flash, or use the JTAG emulator. Due to the use of NOR FLASH, according to the 2410 manual, 4K DRAM can be used directly without setting, while other memory must initialize first, such as telling MEMORY There are two SDRAMs in Controller, and the data width is 32bit, = =. Otherwise, Memory Control will process the memory in accordance with the default values ​​after the reset. This read / write will generate an error. So the first step, through the emulator, execute the execution code Put 0x4000_0000 (when compiling, set text_bas e = 0x40000000) Step 2, put Linux Kernel Image in the Target Address (SDRAM) through AXD, waiting to call the third step, execute bootloader code, get debugging from serial port Data, boot the armlinux 4.

The code analysis told the steps to execute, and I want everyone to have a probably impression on the boot. Then the code analysis of the bootloader internal code. There are many online contents of the bootloader article, I am streamlined here, delete unnecessary features. Bootloader Generally, it is divided into two parts, assembly parts, and C language part. The assembly section performs simple hardware initialization, and the C part is responsible for copying data, setting startup parameters, serial communication and other functions. BootLoader lifecycle: 1. Initialize hardware, such as setting UART At least one is set), the detection memory = =. 2. Set the startup parameters, this is to tell the kernel hardware information, such as which boot interface, baud rate = =. 3. Jump to the first address of Linux Kernel. 4. Of course, in the guidance phase, like Vivi, etc., use the virtual address, if you are more troublesome, use the real address, all the same. Let's see the code: 2410init.s .global _Start // Start execution _Start: / / Below is the interrupt vector b reset @ supervisor mode // After restarting the jump ... ... Reset: LDR R0, = WatCon / WTCON address is 53000000, WatchDog control register * / ldr r1, = 0x0 / * Off WatchDog * / STR R1, [R0] LDR R0, = INTMSK LDR R1, = 0xfffffff / * Shield All Interrupt * / STR R1, [R0] LDR R0, = INTSUBMSK LDR R1, = 0x3FF / * Sub-interrupt is also the same * / STR R1, [R0] / * Initialize Ports ... for display led. * / ldr r0, = GPFCON LDR R1, = 0x55AA STR R1, [R0] LDR R0, = GPFUP LDR R1, = 0xFF STR R1, [R0] ldr r0, = GPFDAT ldr r1, = POWEROFFLED1 str r1, [r0] / * Setup clock Divider control register * you must configure CLKDIVN before LOCKTIME or MPLL UPLL * because default CLKDIVN 1,1,1 set the SDMRAM Timing Conflict nop * FCLK : Hclk: pCLK = 1: 2: 4 in this case * / ldr r0, = CLKDIVN LDR R1, = 0x3 STR R1, [R0] / * TO Reduce PLL LOCK TIME, Adjust The LockTime Register. * / LDR R0, = LockTime LDR R1, = 0xfffffff STR R1, [r0] / * configure MPLL * / LDR R0, = MPLLCON LDR R1, = (M_MDIV << 12) (M_PDIV << 4) M_SDIV) // FIN = 12MHz, fout = 203MHz STR R1, [R0] LDR R1, = GSTATUS2 LDR R10, [R1] TST R10, # offrst Bne 1000F // The above, I didn't move, I used Samsung, the following is the main change / * MEMORY C0NTROLLER (MC) setting * / add r0, pc, # mcdata - (. 8) // r0 points to the MCDATA address, where the data LDR R1 to be used in the MC initialization is stored, = BWSCON // R1 points to the first address of the MC controller register Add R2 , R0, # 52 // Copy the number, offset 52 words 1: // Cycle LDR R3, [R0], # 4 STR R3, [R1], # 4 CMP R2, R0 BNE 1b in accordance with the offset. Align 2 McData: .word (0

(B1_bwscon << 4) (b2_bwscon << 8) (b4_bwscon << 16) (b5_bwscon << 20) (b6_bwscon << 24) (B7_BWSCON << 28)) This is the data of BWSCON. The specific parameters are as follows: You need to change settings DW6 and DW7 are set to 10, ie 32bit, DW0 set to 01, that is, 16bit is the controller data of each Bank, mostly the clock, can With the default value, after setting the MC, jump to the part called the main function. Word ((b0_tacs << 13) (b0_tcos << 11) (b0_tcoh << 6) (B0_TAH << 4) (b0_tacp << 2) (b0_pmc)) .Word ((b1_tacs << 13) (b1_tcos << 11) (B1_TACC << 8) (B1_TCOH << 6) (B1_TAH < <4) (b1_tacp << 2) (b1_pmc)). Word ((b2_tacs << 13) (b2_tcos << 11) (B2_TACC << 8) (B2_TCOH << 6) (B2_TAH << 4) (b2_tacp << 2) (b2_pmc)) .Word ((b3_tacs << 13) (b3_tcos << 11) (b3_tacc << 8) (B3_TCOH << 6) (B3_TAH << 4 ) (B3_tacp << 2) (b3_pmc)) .Word ((b4_tacs << 13) (b4_tcos << 11) (b4_tacc << 8) (B4_TCOH << 6) (B4_TAH << 4) (B4_TACP << 2) (B4_PMC)) .Word ((b5_tacs << 13) (b5_tcos << 11) (b5_tacc << 8) (B5_TCOH << 6) (B5_TAH << 4) (B5_tacp << 2) (b5_pmc)) .Word ((b6_mt << 15) (b6_trcd << 2) (b6_scan)) .Word ((b7_mt << 15) (B7_TRCD << 2) ( B7_scan)) .word ((Refen << 23) (TREFMD << 22) (TRP << 20) (TCHR << 16) Refcnt) .word 0xB2 / * Refresh Control R EGISTER * / .WORD 0X30 / * BANKSIZE Register: BURST MAIN / .WORD 0X30 / * SDRAM MODE Register * / .align 2 .Global call_main // Call the main function, the function parameters are 0 Call_main: LDR SP, Stack_Start MOV FP , # 0 / * No Previous Frame, SO FP =

0 * / MOV A1, # 0 / * set argc to 0 * / mov A2, # 0 / * set argv to nul * / bl main / * call main * / stack_start: .word stack_base undefined_instruction: Software_Interrupt: prefetch_abort: Data_Abort: NOT_USED: IRQ: FIQ: / * The above is the main assembly section, which implements the clock settings, serial port settings WatchDog off, interrupt closing function (if necessary, can be used to use), then transfer to main * / 2410init.c file int Main (int Argc, char ** argv) {u32 test = 0; void (* thekernel) (int zero, int arch, unsigned long params_addr) = (void (*) (int, int, unsigned long) RAM_COMPRESSED_KERNEL_BASE; / / IMAGE compressed address int i, k = 0; // downPt = (RAM_COMPRESSED_KERNEL_BASE); chkBs = (_ RAM_STARTADDRESS); // SDRAM local start // fromPt = (FLASH_LINUXKERNEL); MMU_EnableICache (); ChangeClockDivider (1,1 ); // 1: 2: 4 CHANGEMPLLVALUE (m_mdiv, m_pdiv, m_sdiv); // fin = 12MHz fCLK = 200MHz port_init (); // Setting I / O port, before using the COM port, you must call this function, otherwise The communication chip does not get the data uART_INIT (PCLK, 115200); // PCLK uses the default 200000, the strat rate 115200 / ***************** (Check RAM space **************************** / UART_SENDSTRING ("/ N / TLINUX S3C2410 NOR Bootloader / N"); UART_SENDSTRING ("/ N / Tchecking SDRAM 2410Load ... / N "); for (; chKB) S <0x33fa0140; chKBS = Chkbs 0x4, Test ) // // According to my experience, it is best to increase with one byte, our board, is not problematic when the 256byte is increment, but // Take 1byte The increment is wrong, the 13th side of the data line will take "1", detect it is hardware problem, the phenomenon is as follows // Up the simulation of the code test SDRAM, starting with the 28F128A3J Flash film, the test result is very good, but After the FLASH film //, the test data (DATA) has been written for the 0x00000400, and the memory space will be erroneous, // and random. The error data is always turned to 0x00002400, and the data bus is 10 and 13 bits without short circuit. Test with other data //, such as 0x00000200; 0x00000800 is not there. DX help.

// Since it is not solved, I can't use Flash. {Chkpt1 = chkbs; * (u32 *) chkpt1 = test; // write data IF (* (U32 *) chkpt1 == 1024) // read data and write Is it just? {Chkpt1 = 4; led_display (1); led_display (2); led_display (3); led_display (4);} else goto error;} uart_sendstring ("/ n / tsdram check surcessful! / N / tmemory Maping ... "); get_memory_map (); // Get the available Memory information, make a list, which will be transmitted to kernel // so-called memory mapping as a start-up parameter means which address ranges are allocated in the 4GB physical address space To address the RAM unit of the system.

UART_SENDSTRING ("/ N / TMEMORY MAP SUCCESSFUL! / N"); // I use the emulator to put the kernel, ramdisk directly on the SDRAM, so the following paragraph is unnecessary, but if kernel, ramdisk is in Flash, then Just need. / ****************** (Copy Linux kernel) ****************** / UART_SENDSTRING "/ TLoading Kernel Image from Flash ... / N"); UART_SENDSTRING ("/ TAND Copy Kernel Image to SDRAM AT 0x31000000 / N"); UART_SENDSTRING ("/ T / TBY Leijun Dong Dongleijun4000@hotmail.com / n") For (k = 0; k <196608; k , downpt = 1, frompt = 1) // 3 * 1024 * 1024 / 32linux kernel des, src, length = 3m * (u32 *) DownPT = * (U32 *) frompt; / ****************** (Load Ramdisk) ****************** / UART_SENDSTRING "/ t / tloading compressed ramdisk ... / n"); Downpt = (RAM_COMPRESSED_RAMDISK_BASE); frompt = (flash_ramdisk_base); for (k = 0; k <196608; k , downpt = 1, frompt = 1) / / 3 * 1024 * 1024 / 32linux kernel des, src, length = 3m * (U32 *) DOWNPT = * (U32 *) frompt; / ****** jffs2 file system, if you don't use Flash if you don't use Flash, This paragraph can also not ******** / uart_sendstring ("/ t / tloading jffs2 ... / n"); DOWNPT = (RAM_JFFS2); frompt = (Flash_JFFS2); for (k = 0; k < (1024 * 1024/32); K , Downpt = 1, frompt = 1) * (U32 *) DOWNPT = * (U32 *) frompt; uart_sendstring ("Load Success ... Run ... / n"); / ********** ********* (SETUP param) ****************** / setup_start_tag (); // Start setting startup parameter setup_memory_tags (); // memory Impression setup_commandline_tag ("console = TTYS0, 115200N8); // Start command line setup_initrd2_tag (); // root device setup_ramdisk_tag (); // ramdisk image setup_end_tag ​​(); / * Off I-cache * / asm (" MRC P15 , 0,% 0, C1, C0, 0 ":" = R "(i)); I & = ~ 0x1000; ASM (" MCR P15, 0,% 0, C1, C0, 0 "::" R " (i)); / * flush i-cache * / asm ("

MCR P15, 0,% 0, C7, C5, 0 "::" r "(i)); // This line jumps to the first address of Compressed Kernel Thekernel (0, Arch_Number, (unsigned long *) (RAM_BOOT_PARAMS )); // When the Kernel is started, I-Cache can be opened, and R0 must be 0, and R1 must be a CPU model (which can be found from Linux / Arch / ARM / Tools / Mach-Types), R2 must be parameters Physical start address / ****************** * *************************************** / Error: UART_SENDSTRING (" / N / NPANIC SDRAM Check Error! / N "); return 0;} static void setup_start_tag (void) {params = (struct tag *) RAM_BOOT_PARAMS; // Start the address of the start of the address params-> hdr.tag = ATAG_CORE; Params -> hdr.size = tag_size (tag_core); params-> u.core.flags = 0; params-> u.core.pageSize = 0; params-> u.core.rootdev = 0; params = tag_next (params) } static void setup_memory_tags (void) {INT i; for (i = 0; i hdr.tag = ATAG_MEM; params-> hdr.size = tag_size (tag_mem32); params-> u.Mem.Start = Memory_map [i] .start; params-> u.Mem.size = memory_map [i] .len; params = tag_next (params);}}}} static void Setup_commandline_tag (char * commandline) {INT i = 0; / * SKIP NON-EXISTENT COMMA ND Lines So The Kernel Will Still * Use its default command line. * / params-> hdr.tag = atag_cmdline; params-> hdr.size = 8; // console = TTYS0, 115200N8 STRCPY (params-> u.cmdline. cmdline, p); params = tag_next (params);.} static void setup_initrd2_tag (void) {/ * an ATAG_INITRD node tells the kernel where the compressed * ramdisk can be found ATAG_RDIMG is a better name, actually * / params->. hdr.tag = ATAG_INITRD2; params-> hdr.size = tag_size (tag_initrd); params-> u.initrd.start = RAM_COMPRESSED_RAMDISK_BASE; params-> u.initrd.size = 2047; // k byte params = tag_next (params) ;

.} Static void setup_ramdisk_tag (void) {/ * an ATAG_RAMDISK node tells the kernel how large the * decompressed ramdisk will become * / params-> hdr.tag = ATAG_RAMDISK; params-> hdr.size = tag_size (tag_ramdisk); params- > u.ramdisk.start = RAM_DECOMPRESSED_RAMDISK_BASE; params-> u.ramdisk.size = 7.8 * 1024; // k byte params-> u.ramdisk.flags = 1; // automatically load ramdisk params = tag_next (params);} Static void setup_end_tag ​​(void) {params-> hdr.tag = atag_none; params-> hdr.size = 0;} Void UART_INIT (INT BAUD) // Serial port is important {INT i; if (PCLK = = 0) PCLK = PCLK; rufcon0 = 0x0; // UART CHANNEL 0 FIFO Control Register, FIFO Disable Rumcon0 = 0x0; // UART Chaneel 0 Modem Control Register, AFC Disable // UART0 RULCON0 = 0x3; // Line Control register: Normal, No Parity, 1 Stop, 8 Bits, the Samsung is not a matter of writing, but I am calculated in accordance with Normal, No Parity, 1 Stop, 8 BITS is indeed 0x245 // [10] [9] [8 ] [7] [6] [5] [4] [3: 2] [1: 0] // Clock Sel, TX INT, RX INT, RX TIME OUT, RX ERR, LOOP-BACK, Send Break, Transmit Mode , Receive Mode // 0 1 0 0 1 0 0, 01 01 // PCLK Level Pulse Disable generate Normal Normal Interrupt or polling rucon0 = 0x245; // Control Register Rubrdiv0 = (PCLK / 16. / Baud) -1); // baud rate Divisior Register 0 delay (10);} After the above toss, next is the life of Kernel. Can you start Kernel, you can see your compilation kernel's level. This bootloader does not need to interact information like BLOB, use virtual addresses, In general, it is very simple. ------------------------------

Article Source: http://www.palmheart.net/modules.php? Op = MODLOAD & Name = News & File = Article & SID = 197

转载请注明原文地址:https://www.9cbs.com/read-42985.html

New Post(0)