ArMlinux Bootloader Detailed Details (Based on Samsung 2410)

xiaoxiao2021-03-06  43

Armlinux Bootloader Detailed Article / Column: DONGLEIJUN2002 Posted by Taling January 14, 2005 - 12:42 PM

Detailed ArmLinux BOOTLOADER full of: 1. Lam Dong Lei several important concepts COMPRESSED KERNEL and DECOMPRESSED KERNEL Jffs2 File System RAMDISK boot parameters (taken from IBM developer) 2. Development Environment and Development Board configuration: 3. Start: 4. Online Code Analysis About Linux's bootloader article is a lot, but most of them are vivi, blob, etc., it is not convenient to read, and the compiled documents are also relatively large, and more is the development-oriented boot code, making a product It is also necessary to cut, this extent affects the development speed, which is relatively large for beginners, and analyzes a simple bootloader, which is a slightly modified result on the 2410 bootloader provided by Samsung. Size, compiled file size No more than 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, it includes understanding Therefore, it is necessary to provide sufficient space when the RAM is assigned, so they do not cover each other. When the execution instruction jumps to the compressed kernel, the decapulizer starts working, if the decompression detects the decompressed code coverage Remove the compressed kernel, then you will send data directly to the compressed kernel, 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 It hasn't been used yet. Ramdisk uses ramdisk to enable root file system to start 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, then Bootloader Pass this address to Kernel by starting the parameters. Specific code analysis. Starting parameters (Excerpted from IBM Developer) Before calling the kernel, you should work, namely: Set the boot 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 use it. 2. Development Environment and Development Board Configuration: CPU: S3C2410, Bank6 has 64M SDRAM (two), Bank0 There are 32m nor flash, the serial port is of course an escape. This way, according to the data manual, address assignment is as follows: 0x4000_0000 Starting with 4K on-chip DRAM. 0x0000_0000 Starting is 32M Flash 16bit Width 0x3000_0000 Starting is 64M SDRAM 32bit Width Note: Control register BANK6 and BANK7 portion must be the same. 0x4000_0000 (chip DRAM) stored within 4k BOOTLOADER IMAGE 0x3000_0100 stored starting startup parameters 0x3120_0000 store COMPRESSED KERNEL IMAGE 0x3200_0000 store COMPRESSED RAMDISK 0x3000_8000 designated dECOMPRESSED KERNEL IMAGE ADDRESS 0x3040_0000 designated dECOMPRESSED RAMDISK IMAGE ADDRESS Development Environment: Redhat Linux, Armgcc Toolchain, ARMLINUX KERNEL How to build ARMGCC Compilation Environment: It is recommended to use Toolchain, not to compile Armgcc, and do you have a failure. First download ARM-GCC 3.3.2 Toolchain ARM-Linux-GCC-3.3.2.tar.bz2 Decomposed to / Toolchain # tar jxvf arm-linux-gcc-3.3.2.tar.bz2 # mv /usr/local/Arm/3.3.2 / Toolchain in Makefile There is an incrude = -i ../include -i /root/my/USR /CLUDE -I /ROOT/MY/USR /CLUDE -I /ROOT/MY/USR /CLUDE-I / ROOT/MY/USR /CLUDE-I /ROOT/MY/USR/INCLUDE-I / ROOT/MY/USR /LOCAL/ARM/3.3.2/include. Otherwise, the library function cannot be used 3 Startup mode: You can start in Flash, or use the JTAG emulator. Due to the NOR FLASH, according to the 2410 manual, the 4K DRAM can be used directly without setting, and other memory must initialize first, such as telling Memory Controller, B There are two SDRAMs in ANK6, and the data width is 32bit, = =. Otherwise, Memory Control will process memory according to the default value after reset. This read / write will generate an error. So the first step, put the executive code through the emulator 0x4000_0000, (When compiled, 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 the bootloader code, get debug data from the serial port, Boot armlinux 4. Code analysis tells so many steps, you want everyone to have a probably impression on the boot, then the code analysis of the bootloader internal code is a lot, I am streamlined here, delete unnecessary Features. BootLoader is generally 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. Initialization hardware, For example, set UART (at least one), detect memory = =. 2. Set the startup parameters, this is to tell the kernel hardware information, such as which boot interface, baud rate = =. 3. Jump to Linux Kernel Address. 4. Dividation, of course, in the boot phase, like vivi, etc., use the virtual address, if you are more troublesome, use the real address, all. Let's see the code: 2410init.s .Global _Start // Start executive office _Start: // The following is the interrupt vector b reset @ supervisor mode // Restart Jump ...... reset: ldr r0, =

WTCON / WTCON address is 53000000, Watchdog's control register * / ldr r1, = 0x0 / * Off WatchDog * / STR R1, [R0] LDR R1, = INTMSK LDR R1, = 0xffffffff / * Shield all interrupt * / STR R1, [r0] LDR R0, = INTSUBMSK LDR R1, = 0x3ff / * subinterpreted also * / 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 / / During this paragraph, I didn't move, I used Samsung, and below is the mainly changed place / * MEMORY C0NTROLLER (MC) setting * / add r0, pc, # mcdata - (. 8) // r0 pointing McData address, there is a MC initialization The data LDR R1, = BWSCON // R1 points to the first address ADD R2, R0, # 52 // copy number of MC controller registers, and offset by 52 words 1: // Cyclic replication of LDR R3 according to the offset, [r0], # 4 STR R3, [R1], # 4 CMP R2, R0 BNE 1b .align 2 McData: .Word (0 (b1_bwscon << 4) (b2_bwscon << 8) (b3_bwscon << 12 ) (B4_bwscon << 16) (b6_bwscon << 24) (b7_bwscon << 28)) The above line is BWSCON data, the specific parameters are as follows: You need to change the settings DW6 and DW7 Set to 10, ie 32bit, DW0 set to 01, ie 16 bit below the controller data of each Bank, mostly the clock correlation, can be used by default, after setting the MC, jump to the part of the calling main function. ((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_tah << 4) (B1_TAH << 2) (B1_TACP << 2) B1_PMC)). Word ((b2_tacs << 13) (b2_tcos << 11) (b2_tacc << 8) (B2_TCOH << 4) (B2_TAH << 2) (B2_PMC )) .word ((b3_tacs << 13) (b3_tcos << 11) (B3_TACC << 6) (B3_TAH << 4) (B3_TACP << 2) (B3_PMC) ) .word ((b4_tacs << 13) (B4_TCOS << 11) (B4_TACC << 8) (B4_TAH << 4) (B4_TACP << 2) (B4_PMC)) .word ((b5_tacs << 13) (b5_tcos << 11) (B5_TACC << 8) (B5_TAH << 4) (B5_TAH << 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 Register * / .word 0x30 / * Banksize Register: Burst MODE * / .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 Stac K_Base undefined_instruction: Software_interrupt: prefetch_abort: Data_abort: not_used: IRQ: FIQ: / * The above is the main assembly section, implements the clock setting, serial port setting WatchDog off, interrupt closing function (if necessary, can be used to use), then turn入 m * / 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; // Compressed image address INT i, k = 0; // DownPT = (RAM_COMPRESSED_KERNEL_BASE); chkbs = (_ ram_startaddress); // SDRAM Starting Places // frompt = (flash_linuxkernel); mmu_enableicache (); ChangeClockdivider (1, 1); // 1: 2: 4 ChangeMpllValue (m_mdiv, m_pdiv, m_sdiv); // FIN = 12MHz FCLK = 200MHz port_init (); // Set I / O port, you must call this function before using the COM port, 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 2410Loader.c ... / n "); for (; chkbs <0x33fa0140; chkbs = chkbs 0x4, test ) // // According to my experience, it is best to take one Bytes are incremented, our board, there is no problem in 256byte increment detection, but // is income with 1byte, the 13th and data line will take a few "1", detect it is hardware problem, The phenomenon is as follows // Test SDRAM with the simulation machine, starting with the 28f128a3j flash film, the test result is very good, but after the FLASH card //, the test data (DATA) is written for the 0x00000400, and is written. Operation is about 1k memory space, // 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. This article comes from the embedded research network http://www.palmheart.net/ This article is: http://www.palmheart.net/modules.php?op= MODLOAD & NAME = News & File = Article & SID = 197

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

New Post(0)