📄 linuxld.c
字号:
/*****************************************************************************; Project : Common platform; Creator : Sumei Chung; File : loader.C; Abstract: ;;*****************************************************************************/#include <ctype.h>#include <mips4kc.h>#include <adm5120.h>#include <hw_profile.h>#include <helpers.h>#include <bconfig.h>#include <mx29lv320.h>#include <flash.h>#include <img_header.h>#include <xmodem.h>#include <uartdrv.h>#include <buart_extra.h>#include <stdlib.h>#include <zlib.h>#include <linuxld.h>#include <test_def.h>//#define TRY_TINF 1#ifdef TRY_TINF/* Some problems with this */#include "tinf.h"#endif/* Linux boot defined *//* Address of "_start" in System.map */#define LINUX_ENTRY_POINT 0x800026D8#define LINUX_IMAGE_SIZE LINUXLD_FLASH_KERNEL_SIZE/* gzip defined */#define _OFFSET(_t, _m) ((u_int) &(((_t *) 0)->_m))#define Z_EOF 0/* gzip flag bytes */#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */#define ORIG_NAME 0x08 /* bit 3 set: original file name present */#define COMMENT 0x10 /* bit 4 set: file comment present */#define RESERVED 0xE0 /* bits 5..7: reserved */static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header *//* LINUXLD_GZIP_HEAP = LINUXLD_DOWNLOAD_START + LINUXLD_DOWNLOAD_SIZE *//* See 'param.c' for details of how LINUXLD_DOWNLOAD_START = A0820000 *//* With LINUXLD_DOWNLOAD_SIZE = 400000 (4 MB) in 'linuxld.h', this *//* makes LINUXLD_GZIP_HEAP = A0C20000 (Kseg1) = 00C20000 (Kuseg) */unsigned int loader_heap = LINUXLD_GZIP_HEAP;char *pass = "PASS";char *fail = "FAIL";char *xdownloading = "\r\n\r\nDownloading via Xmodem........ ";char *tdownloading = "\r\n\r\nDownloading via TFTP........";char *cdownload = "\r\n\r\nDownload canceled!";int ungzip(unsigned char *);char *gzip_original_name(unsigned char *);int tftp_client_menu(char *);UINT32 tftpc(char *, int);extern void _icache_sync_all(void);/* * Show download information */ void show_dlinfo(UINT32 memloc, UINT32 size) { char digitstr[12]; ultoa(size, digitstr); buart_print("\r\nTransferred: "); buart_print(digitstr); ultoa(memloc, digitstr); buart_print(" bytes\r\nTo address : "); buart_print(digitstr); }/* * Common function to erase and program flash */int erase_and_write_flash(void *flash, char *image, UINT32 len){ int rc = -1; /* Erase flash */#if PRESERVE_FLASH == 1 buart_print("\r\nWould erase flash here....... "); if (1) {#else buart_print("\r\nErasing flash................ "); if (nf_erase(flash, len) == 0) {#endif buart_print (pass); /* Write flash */#if PRESERVE_FLASH == 1 buart_print("\r\nWould program flash here..... "); if (1) {#else buart_print("\r\nProgramming flash............ "); if (nf_write(flash, image, len) == 0) {#endif buart_print (pass); rc = 0; } } return rc;}/* * Update bootloader */int update_bootloader(){ void *flash = (void *) LINUXLD_FLASH_LOADER_START; char *image = (char *) LINUXLD_DOWNLOAD_START; int rc = -1; UINT32 len; buart_print("\r\nUPDATE_BOOTLOADER() CALLED BUT NOT RUN\r\n"); /* Download new bootloader to memory using Xmodem */// buart_print(xdownloading);// if ((len = xmodem(image, LINUXLD_FLASH_LOADER_SIZE)) > 0) {// buart_print (pass);// show_dlinfo((UINT32) image, len); /* Erase and re-program the flash memory */// rc = erase_and_write_flash(flash, image, len);// }// if (rc < 0)// buart_print(fail); return rc;}/* * Download linux image to flash using TFTP client */#ifdef SECSECTORint tftpc_download_to_flash(){ void *flash = (void *) LINUXLD_FLASH_KERNEL_START; char *image = (char *) LINUXLD_DOWNLOAD_START; int rc = -1; UINT32 len; /* Present the current network parameters and, after allowing for changes, continue only if they are acceptable to the user. */ /* THIS ROUTINE BRICKED THE ROUTER SO FIX IT */ return rc; if (tftp_client_menu("FLASH")) { buart_print(tdownloading); if ((len = tftpc(image, LINUX_IMAGE_SIZE)) > 0) { buart_print (pass); show_dlinfo((UINT32) image, len); buart_nl(); /* Erase and re-program the flash memory */ rc = erase_and_write_flash(flash, image, len); if (rc < 0) buart_print(fail); // erase_and_write_flash writes its own "PASS" } else { buart_print(fail); } } else buart_print(cdownload); buart_nl(); return rc;}int tftpc_download_to_sdram(){ char *image = (char *) LINUXLD_DOWNLOAD_START; int rc = -1; UINT32 len; /* Present the current network parameters and, after allowing for changes, continue only if they are acceptable to the user. */ if (tftp_client_menu("SDRAM")) { buart_print(tdownloading); if ((len = tftpc(image, LINUX_IMAGE_SIZE)) > 0) { int status, offset, gzinput_len, gzoutput_len = 0, is_linux = 0; volatile unsigned char *test_addr = 0; char *orig_file_name; void (*funcptr) (void); show_dlinfo((UINT32) image, len); buart_nl(); /* In order to continue there needs to be a CSYS section in the first 256K of transferred data. Unlike booting out of flash, we start searching at the very beginning of the data for CSYS. */ for (offset = 0; offset < 0x50000; offset += 0x10000) { test_addr = image + offset; if (memcmp((void *) test_addr, "CSYS", 4) == 0) { buart_print("CSYS signature found!\r\n"); break; } else buart_print("CSYS signature not found...\r\n"); } if (offset < 0x50000) { int namelen; /* Found CSYS CSYS wrapper has 2 extra bytes at the end */ gzinput_len = ((IMG_HEADER_Tp) test_addr)->len; /* The length of the ungzipped data is found in the last 4 bytes of the stream which may not be word-aligned. Cannot determine that length a priori because the CSYS length might be off by one due to padding. We'll just have to wing it and depend on the inflate routine to signal a problem if there's not enough space for all the output. */ gzoutput_len = LINUXLD_KERNEL_SIZE; /* Make at least a half-assed effort to determine it this is a Linux kernel or not. */ orig_file_name = gzip_original_name((unsigned char *) test_addr + 12); if (orig_file_name) { namelen = strlen(orig_file_name); int i; /* See if it's got "vmlinu" anywhere in it */ for (i = 0; i < namelen; i++) { if (strncmp(orig_file_name, "vmlinu", 6) == 0) { is_linux = 1; break; } } } if (is_linux) buart_print("\r\ninflate linux code... "); else buart_print("\r\ninflate code... ");#ifdef TRY_TINF /* The input length could actually be -9 but we don't know beforehand whether or not the padding byte is present. */ status = tinf_gzip_uncompress((char *) LINUXLD_KERNEL_START, &gzoutput_len, (unsigned char *) test_addr + 12, gzinput_len - 8); if (status == TINF_OK) {#else status = ungzip((unsigned char *) test_addr + 12); if (status == Z_OK) {#endif int i, namelen = 0; char ok_key = '\0'; volatile unsigned long *gpio_conf0 = (unsigned long *) (PA2VA(ADM5120_SWCTRL_BASE) + GPIO_conf0_REG); volatile unsigned char *extio1 = (unsigned char *) PA2VA(ADM5120_EXTIO1_BASE); buart_print(pass); buart_print("\r\n\r\nPress 'Y' to jump to Linux or any other key to return to the menu: "); ok_key = buart_getchar(); buart_put(ok_key); buart_nl(); if ((ok_key == 'Y') || (ok_key == 'y')) { buart_nl(); funcptr = (void *) LINUX_ENTRY_POINT; buart_print("\r\njump to "); if (is_linux) { /* This is in nor_ldrinit.S */ _icache_sync_all(); /* From Hawking32k_loader.idb. The ADM5120 datasheet says bits 15:8 are read-only and bits 7:0 are "reserved" so this is really strange. The actual result of this should be to enable GPIO 0:7 for output and set them all to 0, except for GPIO 5 which is set to 1. Value verified as 20FF_FF01 which matches Hawking32k_loader.idb in function Run_Linux. */ *gpio_conf0 = (GPIO0_INPUT_MODE | GPIO0_INPUT_MASK | GPIO1_INPUT_MASK | GPIO2_INPUT_MASK | GPIO3_INPUT_MASK | GPIO4_INPUT_MASK | GPIO5_INPUT_MASK | GPIO6_INPUT_MASK | GPIO7_INPUT_MASK | GPIO0_OUTPUT_EN | GPIO1_OUTPUT_EN | GPIO2_OUTPUT_EN | GPIO3_OUTPUT_EN | GPIO4_OUTPUT_EN | GPIO5_OUTPUT_EN | GPIO6_OUTPUT_EN | GPIO7_OUTPUT_EN | GPIO5_OUTPUT_HI); /* From Hawking32k_loader.idb. No freaking idea what it does. */ *extio1 = 0xFF; buart_print("linux "); } /********************************/ /* Invoke the code entry point */ /********************************/ buart_pair((unsigned int) funcptr, "code at"); funcptr(); } } else { buart_print(fail); buart_nl(); } } } else { buart_print(fail); buart_print(" (received len = 0)\r\n"); } } else buart_print(cdownload); buart_nl(); return rc;}#endif/* * Download linux image to flash using Xmodem */ int xmodem_download(){ void *flash = (void *) LINUXLD_FLASH_KERNEL_START; char *image = (char *) LINUXLD_DOWNLOAD_START; int rc = -1; UINT32 len; /* Download Linux image to memory using Xmodem */ buart_print(xdownloading); if ((len = xmodem(image, LINUX_IMAGE_SIZE)) > 0) { buart_print (pass); show_dlinfo((UINT32) image, len); /* Erase and re-program the flash memory */ rc = erase_and_write_flash(flash, image, len); } if (rc < 0) buart_print(fail); return rc;}/* * Boot Linux * LINUXLD_DOWNLOAD_SIZE is 4 MB (0x00400000) * LINUXLD_DOWNLOAD_START is... [0xA0820000] (value used in Hawking32k_loader.idb) * LINUXLD_LOADER_START (LINUXLD_MEMPOOL_START + LINUXLD_MEMPOOL_SIZE) [0xA0800000] (at 8 MB) * (mempool start is LINUXLD_KERNEL_START + LINUXLD_KERNEL_SIZE) [0xA0600000] (at 6 MB) * (kernel start is LINUXLD_SDRAM_START + LINUXLD_EXCEP_SIZE) [0xA0002000] * (LINUXLD_SDRAM_START = 0xA0000000) * (LINUXLD_EXCEP_SIZE = 0x2000 [64K]) * (kernel size is 0x00600000 - 0x2000) (i.e. just under 6 MB) [0x005FE000] * (mempool size is 0x00200000) * plus LINUXLD_LOADER_SIZE (64K) [0x00002000] <==== BOGUS AND NOT USED FOR ANYTHING !!! * plus LINUXLD_RESERVE_SIZE (0) * LINUXLD_GZIP_HEAP is LINUXLD_DOWNLOAD_START + 4 MB * * LINUXLD_NORFLASH_BOOTPARAM_SIZE = 0x00018000 (HS01, CS01 and DS01) * LINUXLD_NORFLASH_BOOTPARAM_START = 0xBFC08000 * LINUXLD_NORFLASH_LOADER_START = 0xBFC00000 * LINUXLD_NORFLASH_LOADER_SIZE = 0x00008000 * * LINUXLD_FLASH_KERNEL_START = LINUXLD_NORFLASH_KERNEL_START * = bootparam_start + bootparam_size = 0xBFC20000 * */void boot_linux(){ volatile unsigned long *gpio_conf0, *gpio_conf2; volatile unsigned char *extio1, *flash_addr, *test_addr = 0; int status, offset, gzinput_len, gzoutput_len = 0; void (*funcptr) (void); flash_addr = (unsigned char *) PA2VA(ADM5120_SMEM0_BASE); // same definition as LINUXLD_NORFLASH_LOADER_START gpio_conf0 = (unsigned long *) (PA2VA(ADM5120_SWCTRL_BASE) + GPIO_conf0_REG); extio1 = (unsigned char *) PA2VA(ADM5120_EXTIO1_BASE); /* Find CSYS section on flash device */ for (offset = 0x10000; offset < 0x50000; offset += 0x10000) { test_addr = flash_addr + offset; if (memcmp((void *) test_addr, "CSYS", 4) == 0) break; else buart_print("\r\nno sys signature found!!\r\n"); } if (offset < 0x50000) { /* Found CSYS The admboot code copies the flash section to RAM and then deflates it. The Hawking code deflates the data directly from FLASH to RAM. CSYS wrapper has 2 extra bytes at the end */ gzinput_len = ((IMG_HEADER_Tp) test_addr)->len; /* The length of the ungzipped data is found in the last 4 bytes of the stream which may not be word-aligned. Cannot determine that length a priori because the CSYS length might be off by one due to padding. We'll just have to wing it and depend on the inflate routine to signal a problem if there's not enough space for all the output. */ gzoutput_len = LINUXLD_KERNEL_SIZE; buart_print("\r\ninflate linux code... ");#ifdef TRY_TINF /* The input length could actually be -9 but we don't know beforehand whether or not the padding byte is present. */ status = tinf_gzip_uncompress((char *) LINUXLD_KERNEL_START, &gzoutput_len, (unsigned char *) test_addr + 12, gzinput_len - 8); if (status == TINF_OK) {#else status = ungzip((unsigned char *) test_addr + 12); if (status == Z_OK) {#endif buart_print(pass); funcptr = (void *) LINUX_ENTRY_POINT; /* This is in nor_ldrinit.S */ _icache_sync_all(); /* From Hawking32k_loader.idb. The ADM5120 datasheet says bits 15:8 are read-only and bits 7:0 are "reserved" so this is really strange. The actual result of this should be to enable GPIO 0:7 for output and set them all to 0, except for GPIO 5 which is set to 1. Value verified as 20FF_FF01 */ *gpio_conf0 = (GPIO0_INPUT_MODE | GPIO0_INPUT_MASK | GPIO1_INPUT_MASK | GPIO2_INPUT_MASK | GPIO3_INPUT_MASK | GPIO4_INPUT_MASK | GPIO5_INPUT_MASK | GPIO6_INPUT_MASK | GPIO7_INPUT_MASK | GPIO0_OUTPUT_EN | GPIO1_OUTPUT_EN | GPIO2_OUTPUT_EN | GPIO3_OUTPUT_EN | GPIO4_OUTPUT_EN | GPIO5_OUTPUT_EN | GPIO6_OUTPUT_EN | GPIO7_OUTPUT_EN | GPIO5_OUTPUT_HI); /* From Hawking32k_loader.idb. No freaking idea what it does. */ *extio1 = 0xFF; /* Invoke the function pointer which never returns */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -