Migration and code analysis on u-boot on GOLD44B0X development board

xiaoxiao2021-03-06  14

Based on "U-Boot in the 44B0X development board, the code analysis" is based on its own development board.

Zhang Lei 2005-2-25Revision History: Development Platform: Redhat 9.0 Development Tools: ARM-ELF-GCC Source: http://sourceforge.net/projects/u-boot1. U-boot Introduction U-boot is an Open Source Bootloader, the current version is 1.1.2. U-boot is developed based on PPCBoot and Armboot, comparable maturity and stability, has been adopted during many embedded system development. Due to its development source code, it supports a large number of development boards. . Why do we need u-boot? It is clear that Uclinux can burn directly into Flash so that no additional bootloader is required. But from the perspective of software upgrades, the software automatic update is very important. In fact, the use of bootloaders is not only the case, but only from software automatic update, our development is necessary. At the same time, the process of u-boot transplant is also a process for embedded systems including hardware and hardware and operating systems to deepen understanding. 2. U-boot portfront frame porting U-Boot to new developers only need to modify and hardware-related parts. On the code structure: 1) Create a Gold44B directory in the Board directory, create Gold44b.c, and flash.c, memsetup.s, u-boot.lds, etc. No need to start from scratch, you can choose a similar directory, copy, modify the file name, and content. I am in the transplantation U-Boot process, select the DAVE / B2 directory. Since U-Boot already contains the S3C24B0-based development board directory, the corresponding directory can also be copied. 2) Create a S3C44B0X directory in the CPU directory, mainly including Start.s, Interrupts.c, and several files of CPU.c, serial.c. It is also not necessary to create files from zero, copy directly from ARM720T, and then modify the corresponding content. 3) Add Gold44b.h to the include / configs directory, where the global macro definition is placed here. 4) Find the u-boot root directory Makefile modification to join Gold44b_config: unconfig @. / Mkconfig $ (@: _ config =) ARM S3C44B0 GOLD44B5) Run Make EV44BII_Config, if there is no error, you can start the hardware related code transplantation work 3. U- Boot's Architecture 1) Overall Structure U-Boot is a layered structure. Software personnel who doing graft work should provide serial driver, Ethernet Driver, Flash Drive (Flash Drive), USB Driver. Currently, it is not necessary to use the USB port procedure, and there is no USB interface on the development board, so there is no portion of USB driver. The drive layer is the U-Boot application, and Command delivers the human interface through the serial port. We can use some commands to do some common work, such as memory view command MD. Kermit applications are mainly used to support the use of serial ports to download applications through the HyperTeral. TFTP is downloaded through a network, such as a UCLinux operating system. 2) Memory distribution GOLD44B Flash size 2m (8bits), now 0-40000 a total of 256K as the storage space of U-boot.

Since there are some environment variables in u-boot, such as IP addresses, boot file names, etc., can be configured in the command line through SATENV, and saved in 40000-50000 (64K) space through SaveEnv. If there is a saved environment variable, U-boot boots will use these environment variables directly. As can be seen from the code analysis, we will move the Flash boot code to the DRAM. U-boot's location in the DRAM in the U-boot-1.1.2 / Board / Gold44b / config.mk configuration as follows: text_base = 0x0c700000. In this way, the boot code U-boot will move from 0x0000 0000 to 0x0C700000. Special attention, due to the Gold44b UClinux interrupt vector program address at 0x0C000 0000, the program cannot be downloaded to 0x0C000 0000, usually downloaded to 0x0c008 0000. 4. START.S Code Structure 1) Defining an executable image of an entry must have an entry point and can only have a unique global portal, usually this entrance is placed at the 0x0 address of the ROM (Flash). For example, Start.s. Globl _Start_Start: It is worth noting that you must tell the compiler that this entry is mainly modified to modify the connector script file (LDS). U-BOOT.LDS on the development board is as follows: Output_Format ("Elf32-Littlearm", "Elf32-Littlearm", "Elf32-Littlearm" Output_arch (ARM) entry (_Start) {. = 0x00000000 ;. = Align (4 ) ;. text: {CPU / S3C44B0 / Start.o (.text) * (. text)}. = align (4) ;. rodata: {* (. rodata)} = align (4); data: {* (. DATA)}. = align (4) ;. Got: {* (. got)} __ u_boot_cmd_start =.; u_boot_cmd: {* (. u_boot_cmd)} __ u_boot_cmd_end =.; armboot_end_data =.;. = align 4); __ bss_start =.;. BSS: {* (. BSS)} _end =.;} 2 Setting the exception vector) exception interrupt vector table is the key to U-Boot and UCLinux kernels One of the places. Even if the UCLinux kernel has been running the processor's control, once an interrupt occurs, the processor still automatically jumps to an entry in the first level exception interrupt vector table starting from the 0x0 address (according to the interrupt type). Take the instruction run. The abnormal interrupt vector table must be started from the 0 address, continuous storage. As will include reset, undefined processing (Undef), software interrupt (SWI), pre-, data error (dabort), preserved, and IRQ, FIQ, etc. Note The value here must be consistent with Uclinux's Vector_BASE. This means that if vector_base (include / armnommu / proc-armv / system.h) in uclinux is defined as 0x0c00 0000, the handleundef should be at 0x0c00 0004.

.globl _Start_Start: B RESET / * MODFIED by ZL 2005-2-21 * // * Add PC, PC, # 0x0c000000Add PC, PC, # 0x0c000000Add PC, PC, # 0x0c000000Add PC, PC, # 0x0c000000add PC, PC, # 0x0c000000add pc, pc, # 0x0c000000add pc, pc, # 0x0c000000 * / ldr pc, = 0x0c000004ldr pc, = 0x0c000008ldr pc, = 0x0c00000cldr pc, = 0x0c000010ldr pc, = 0x0c000014ldr pc, = 0x0c000018ldr pc, = 0x0c00001c.balignl 16,0xdeadbeef here The first-stage exception interrupt vector table at address 0x0 simply contains jump instructions to the secondary abnormal interrupt vector table. In this way, it is possible to correctly handle the event that the event occurs to the UCLinux interrupt handler. This is designed because it is not used in this U-Boot transplant, 8019 and Timer are polling interrupts. If u-boot uses an interrupt (for use in USB device), you need to establish a secondary abnormal interrupt vector table. . The code is as follows (no debugging) :. GLOBL _START_START: B ResetAdd PC, PC, # 0x0c000000Add PC, PC, # 0x0c000000Add PC, PC, # 0x0c000000Add PC, PC, # 0x0c000000Add PC, PC, # 0x0c000000Add PC, PC, # 0x0c000000 .balignl 16, 0xdeadbeef .... in reset is a copy break vector table / * Now copy to SRAM THE INTERRUPT VECTOR * / ADR R2, REAL_Vectorsadd R2, R0, # 1024LDR R1, = 0x0C0000000Add R1, R1 , # 0x08Vector_copy_loop: LDMIA R0 !, {R3-R10} Stmia R1 !, {R3-R10} CMP R0, R2BLE Vector_COPY_LOOP .... Established three interrupt jump / *********** ********************************************** // * Interrupt VectorS * // ***** ************************************************************** / / * REAL_VECTORS: B RESETB Undefined_instructionb software_interruptb prefetch_abortb data_abortb not_usedb Irqb Fiq * // ************************************************************** ********** / undefined_instruction: MOV R6, # 3b resetsoftware_interrupt: MOV R6, # 4b resetprefetch_abort: MOV R6, # 5b ReSetData_abort: MOV R6, # 6b resetNot_Used: / * We * Should * Never Reach this * / MOV R6, # 7b resetirq: MOV R6, # 8b resetfiq: MOV R6, # 9b reset3) Initializing the CPU-related PL l, clock, interrupt control register sequentially close the Watch Dog Timer, close interrupt, set LockTime, PLL (Phase Lock Loop, and clock.

These values ​​(except for LockTime) can be found in the manual of Samsung 44B0. / ************************************************** ************************** CPU_INIT_CRISTERS ** SETUP IMPORTANT Registers * setup memory Timing ******************** *********************************************************** ************* / # Define intcon (0x01c00000 0x200000) #define INTMSK (0x01c00000 0x20000c) #define locktime (0x01c00000 0x18000c) #define PLLCON (0x01c00000 0x180000) #define CLKCON 0x01c00000 0x180004) #define WTCON (0x01c00000 0x130000) CPU_INIT_CRIT: / * Disable Watch Dog * / LDR R0, = WTCONLDR R1, = 0x0Str R1, [R0] / ** Mask All Irqs By Clearing All Bits in the INTMRS * / LDR R1, = INTMSKLDR R0, = 0x03ffFeffstr R0, [R1] LDR R1, = INTCONLDR R0, = 0x05Str R0, [R1] / * SET Clock Control Register * / LDR R1, = LockTimelDRB R0, = 800STRB R0, [R1] ldr r1, = PLLCON # if CONFIG_S3C44B0_CLOCK_SPEED == 64ldr r0, = 0x38021 / * smdk4110: Xtal = 8MHz Fclk = 64MHz * / # elif CONFIG_S3C44B0_CLOCK_SPEED == 66ldr r0, = 0x34031 / * 66MHz (Quartz = 11MHz) * / # elif CONFIG_S3C44B0_CLOCK_SPEED == 75LDR R0, = 0x610C1 / * B2: XTAL = 20MHz FCLK = 75MHz * / # Else # Error config_s3c44b0_clock_speed undefined # endifstr R0, [R1] LDR R1, = CLKCONLDR R0, = 0x7ff8Str R0, [R1] MOV PC, LR4) Initializing SDRAM controller memory controller (mainly SDRAM controller), mainly by setting The 13 registers starting from 1C80000 are set, including bus width, 8 memory Bank, Bank size, SCLK, and two Bank Mode.

#ifdef CONFIG_INIT_CRITICALbl cpu_init_crit / ** before relocating, we have to setup RAM timing * because memory timing is board-dependend, you will * find a memsetup.S in your board directory. * / Code bl memsetup # endif initialize the memory controller Store in U-BOOT-1.1.2 / Board / Gold44b / MemSetup.s is consistent with the boot code under ADS or SDT, but the assembly format is a bit different. 5) Copy the program in the ROM to the RAM first use the PC to obtain the bootloader at the start address of the Flash, and then calculate the size of this program code. These labels, the compiler generates the correct distribution value when connecting (LINK). After obtaining the correct information, the code is copied into the RAM by register (R3 to R10) as a copy. Relocate: / * relocate u-boot to ram * / adj R0, _Start / * r0 <- current position of code * / ldr r1, _text_base / * test if we run from flash or ram * / cmp r0, r1 / * don 'T Reloc During Debug * / BEQ Stack_Setupldr R2, _armboot_startldr R3, _BSS_StartSub R2, R3, R2 / * R2 <- SIZE OF ARMBOOT * / Add R2, R0, R2 / * R2 <- Source End Address * / Copy_LOOP: LDMIA R0 !, {R3-R10} / * Copy from Source Address [R0] * / STMIA R1 !, {R3-R10} / * Copy to Target Address [R1] * / CMP R0, R2 / * Until Source End Addree [R2 ] * / BLE COPY_LOOP6) Initializing Stack Entering Various Mode Settings Stacks of Pictures ./* Set Up The Stack * / Stack_SetUp: LDR R0, _Text_Base / * Upper 128 KIB: R0, #CFG_Malloc_len / * malloc area * / sub r0, r0, #CFG_GBL_DATA_SIZE / * bdinfo * / # ifdef CONFIG_USE_IRQsub r0, r0, # (CONFIG_STACKSIZE_IRQ CONFIG_STACKSIZE_FIQ) #endifsub sp, r0, # 12 / * leave 3 words for abort-stack * / 7 ) Go to the RAM to perform the use of the command LDR, PC, and the C function address in the RAM can go to the RAM. LDR PC, _Start_armboot5. System Initialization Section 1) The set of serial portions (U-boot-1.1.2 / cpu / s3c44b0 / serial port) mainly includes initializing the serial port part, it is worth noting the BAUDRATE of the serial port with the clock MCLK. The relationship is calculated by: Rubrdiv0 = ((int) (MCLK / 16. / (GD -> BAUDRATE) 0.5) -1). This can be found in the manual. Since U-Boot supports a variable baud rate, the default baud rate (64MHz, 115200 bps) and other baud rate are set with macro definition.

Code is as follows: void serial_setbrg (void) {DECLARE_GLOBAL_DATA_PTR; u32 divisor = 0; / * get correct divisor * / switch (gd-> baudrate) {case 1200: #if CONFIG_S3C44B0_CLOCK_SPEED == 66divisor = 3124; #elif CONFIG_S3C44B0_CLOCK_SPEED == 75divisor = 3905; #elif CONFIG_S3C44B0_CLOCK_SPEED == 64 // default divisor = 3332; # else # error CONFIG_S3C44B0_CLOCK_SPEED undefined # endifbreak; case 9600: #if CONFIG_S3C44B0_CLOCK_SPEED == 66divisor = 390; #elif CONFIG_S3C44B0_CLOCK_SPEED == 75divisor = 487; #elif CONFIG_S3C44B0_CLOCK_SPEED == 64 // default divisor = 416; # else # error CONFIG_S3C44B0_CLOCK_SPEED undefined # endifbreak; case 19200: #if CONFIG_S3C44B0_CLOCK_SPEED == 66divisor = 194; #elif CONFIG_S3C44B0_CLOCK_SPEED == 75divisor = 243; #elif CONFIG_S3C44B0_CLOCK_SPEED == 64 // default divisor = 207 ; # else # error CONFIG_S3C44B0_CLOCK_SPEED undefined # endifbreak; case 38400: #if CONFIG_S3C44B0_CLOCK_SPEED == 66divisor = 97; #elif CONFIG_S3C44B0_CLOCK_SPEED == 75divisor = 121; #elif CONFIG_S3C44B0_CLOCK_SPEED == 64 // default divisor = 103; # else # error CONFIG_S3C44B0_CLOCK_SPEED und efined # endif break; case 57600: #if CONFIG_S3C44B0_CLOCK_SPEED == 66divisor = 64; #elif CONFIG_S3C44B0_CLOCK_SPEED == 75divisor = 80; #elif CONFIG_S3C44B0_CLOCK_SPEED == 64 // Default divisor = 68; # else # error CONFIG_S3C44B0_CLOCK_SPEED undefined # endif break; case 115200: #if CONFIG_S3C44B0_CLOCK_SPEED == 66divisor = 32; #elif CONFIG_S3C44B0_CLOCK_SPEED == 64divisor = 34; #elif CONFIG_S3C44B0_CLOCK_SPEED == 75 // default divisor = 40; # else # error CONFIG_S3C44B0_CLOCK_SPEED undefined # endif break;} serial_flush_output (); serial_flush_input ( );

UFCON0 = 0x0; ulcon0 = 0x03; ucon0 = 0x05; ubrdiv0 = divisor; ufcon1 = 0x0; ulcon1 = 0x03; ucon1 = 0x05; ubrdiv1 = divisor; for (Divisor = 0; Divisor <100; Divisor ) {/ * nop * / }} Other functions include sending, receiving. At this time, there is no interrupt, and it is to determine whether the action is completed by a loop wait. For example, receive functions: static int serial_flush_input (void) {Volatile U32 TMP; / * Keep On Reading As long as the receiver is not empty * / while (utstat0 & 0x01) {tmp = regb (urxh0);} return 0;} 2) The clock section (U-boot-1.1.2 / cpu / s3c44b0 / interrupt.c) implements the delay function udelay. The GET_TIMER here is accumulated using global variables because there is no interrupt. Void udelay (unsigned long) {ulong tmo; tmo = usec / 1000; tmo * = cfg_hz; TMO / = 8; TMO = GET_TIMER (0); while (get_timer_masked ()

unsigned long flash_init (void) {# ifdef __DEBUG_START_FROM_SRAM__return CFG_DUMMY_FLASH_SIZE; #elseunsigned long size_b0; int i; / * Init: no FLASHes known * / for (i = 0; i

int flash_erase (flash_info_t * info, int s_first, int s_last) {volatile CFG_FLASH_WORD_SIZE * addr = (CFG_FLASH_WORD_SIZE *) (info-> start [0]); volatile CFG_FLASH_WORD_SIZE * addr2; int flag, prot, sect, l_sect; ulong start, Now, Last; INT I; IF (S_First <0) || (S_First> S_LAST)) {if (Info-> Flash_ID == Flash_Unknown) {Printf ("- missing / n");} else {printf (" - no sectors to erase / n ");} return 1;} if (info-> flash_id == flash_unknown) {printf (" can't Erase Unknown Flash Type - Aborted / N "); Return 1;} prot = 0 For (SECT = S_First; SECT <= S_LAST; SECT) {IF (Info-> Protect [SECT]) {Prot ;}} if (prot) {printf ("- warning:% D protected Sectors Will NOTBE ERASED! / N ", prot);} else {printf (" / n ");} l_sect = -1; / * disable interrupts which might cause a timeout here * / flag = disable_interrupts (); / * start erase on unprotacected Sectors * / for (SECT = S_First; SECT <= S_LAST; SECT ) {if (Info-> Protect [SECT] == 0) {/ * not protected * / addr2 = (cfg_flash_word_size *) (Info-> Start [STA ]); if (INFO-> Flash_ID & Flash_vendmas K) == FLASH_MAN_SST) {addr [CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x00AA00AA; addr [CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x00550055; addr [CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x00800080; addr [CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x00AA00AA; addr [CFG_FLASH_ADDR1 ] = (Cfg_flash_word_size) 0x00550055; Addr2 [0] = (cfg_flash_word_size) 0x00500050; / * block ERASE * / for (i = 0; i <50; i ) udelay (1000); / * Wait 1 ms * /} else { IF (SECT == S_First) {addr [cfg_flash_addr0] = (cfg_flash_word_size) 0x00AA00AA; AddR [cfg_flash_addr1] =

(CFG_FLASH_WORD_SIZE) 0x00550055; addr [CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x00800080; addr [CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x00AA00AA; addr [CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x00550055;} addr2 [0] = (CFG_FLASH_WORD_SIZE) 0x00300030; / * sector erase * /} l_sect = SECT;}} / * re-enable interrupts if Necessary * / if (flag) enable_interrupts (); / * Wait at Least 80us - let's wait 1 ms * / udelay (1000); / ** We Wait For the last triggered sector * / if (l_sect <0) goto done; start = get_timer (0); Last = start; addr = (cfg_flash_word_size *) (Info-> Start [l_sect]); while ((AddR [0] & (CFG_FLASH_WORD_SIZE) 0x00800080) = (CFG_FLASH_WORD_SIZE) 0x00800080) {if ((now = get_timer (start))> CFG_FLASH_ERASE_TOUT) {printf ( "Timeout / n");! return 1;} / * show that we're waiting * / IF ((now - last)> 50000000) {/ * every second * / putc ('.'); Last = now;}} DONE: / * RESET to read mode * / addr = (cfg_flash_word_size *) info-> START [0]; addr [0] = (cfg_flash_word_size) 0x00f000f0; / * reset bank * / printf ("done / n"); return 0;} WIRT E_WORD wants to write the data of the unsigned long type in Flash, because Flash can only write 16bits at a time, so it is written twice.

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

New Post(0)