B. Полный пример |
Предыдущая Содержание Следующая |
Это рабочий пример простого загрузчика и он показывает всю информацию, описанную в этом документе. Для реального загрузчика может потребоваться больше кода, этот пример чисто иллюстративен.
Код этого примера распространяется под лицензией BSD, может быть свободно скопирован и использован, если это необходимо.
/* example.c * пример кода загрузчика для ARM Linux * этот пример распространяется под лицензией BSD */
/* список возможных тэгов */ #define ATAG_NONE 0x00000000 #define ATAG_CORE 0x54410001 #define ATAG_MEM 0x54410002 #define ATAG_VIDEOTEXT 0x54410003 #define ATAG_RAMDISK 0x54410004 #define ATAG_INITRD2 0x54420005 #define ATAG_SERIAL 0x54410006 #define ATAG_REVISION 0x54410007 #define ATAG_VIDEOLFB 0x54410008 #define ATAG_CMDLINE 0x54410009
/* структуры для каждого тэга */ struct atag_header { u32 size; /* размер тэга в словах, включая этот заголовок */ u32 tag; /* тип тэга */ };
struct atag_core { u32 flags; u32 pagesize; u32 rootdev; };
struct atag_mem { u32 size; u32 start; };
struct atag_videotext { u8 x; u8 y; u16 video_page; u8 video_mode; u8 video_cols; u16 video_ega_bx; u8 video_lines; u8 video_isvga; u16 video_points; };
struct atag_ramdisk { u32 flags; u32 size; u32 start; };
struct atag_initrd2 { u32 start; u32 size; };
struct atag_serialnr { u32 low; u32 high; };
struct atag_revision { u32 rev; };
struct atag_videolfb { u16 lfb_width; u16 lfb_height; u16 lfb_depth; u16 lfb_linelength; u32 lfb_base; u32 lfb_size; u8 red_size; u8 red_pos; u8 green_size; u8 green_pos; u8 blue_size; u8 blue_pos; u8 rsvd_size; u8 rsvd_pos; };
struct atag_cmdline { char cmdline[1]; };
struct atag { struct atag_header hdr; union { struct atag_core core; struct atag_mem mem; struct atag_videotext videotext; struct atag_ramdisk ramdisk; struct atag_initrd2 initrd2; struct atag_serialnr serialnr; struct atag_revision revision; struct atag_videolfb videolfb; struct atag_cmdline cmdline; } u; };
#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size)) #define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2) static struct atag *params; /* указывает адрес текущего тэга */
static void setup_core_tag(void * address,long pagesize) { params = (struct tag *)address; /* Начальные параметры для старта */ params->hdr.tag = ATAG_CORE; /* начинаем с основного тэга */ params->hdr.size = tag_size(atag_core); /* размер тэга */ params->u.core.flags = 1; /* обеспечить только чтение */ params->u.core.pagesize = pagesize; /* размер системной страницы (4k) */ params->u.core.rootdev = 0; /* нулевое корневое устройство (обычно перезаписывается) params = tag_next(params); /* передвинуть указатель на следующий тэг */ }
static void setup_ramdisk_tag(u32_t size) { params->hdr.tag = ATAG_RAMDISK; /* тэг Ramdisk-а */ params->hdr.size = tag_size(atag_ramdisk); /* размер тэга */ params->u.ramdisk.flags = 0; /* Загрузить ramdisk */ params->u.ramdisk.size = size; /* Размер декомпрессированного ramdisk */ params->u.ramdisk.start = 0; /* Не используется */ params = tag_next(params); /* передвинуть указатель на следующий тэг */ }
static void setup_initrd2_tag(u32_t start, u32_t size) { params->hdr.tag = ATAG_INITRD2; /* Тэг Initrd2 */ params->hdr.size = tag_size(atag_initrd2); /* размер тэга */ params->u.initrd2.start = start; /* физический старт */ params->u.initrd2.size = size; /* размер скомпрессированного ramdisk */ params = tag_next(params); /* передвинуть указатель на следующий тэг */ }
static void setup_mem_tag(u32_t start, u32_t len) { params->hdr.tag = ATAG_MEM; /* Тэг памяти */ params->hdr.size = tag_size(atag_mem); /* размер тэга */ params->u.mem.start = start; /* Начало области памяти (физический адрес) params->u.mem.size = len; /* Размер области */ params = tag_next(params); /* передвинуть указатель на следующий тэг */ }
static void setup_cmdline_tag(const char * line) { int linelen = strlen(line); if(!linelen) return; /* не вставлять тэг для пустой строки */ params->hdr.tag = ATAG_CMDLINE; /* Тэг командной строки */ params->hdr.size = (sizeof(struct atag_header) + linelen + 1 + 4) >> 2; /* размер тэга */ strcpy(params->u.cmdline.cmdline,line); /* поместить командную строчку в тэг */ params = tag_next(params); /* передвинуть указатель на следующий тэг */ }
static void setup_end_tag(void) { params->hdr.tag = ATAG_NONE; /* Пустой тэг заканчивает список */ params->hdr.size = 0; /* нулевая длина */ }
#define DRAM_BASE 0x10000000 #define ZIMAGE_LOAD_ADDRESS DRAM_BASE + 0x8000 #define INITRD_LOAD_ADDRESS DRAM_BASE + 0x800000
static void setup_tags(parameters) { setup_core_tag(parameters, 4096); /* стандартный основной тэг, размер страницы 4k */ setup_mem_tag(DRAM_BASE, 0x4000000); /* 64Mb с адреса 0x10000000 */ setup_mem_tag(DRAM_BASE + 0x8000000, 0x4000000); /* 64Mb с адреса 0x18000000 */ setup_ramdisk_tag(4096); /* создать 4Mb ramdisk */ setup_initrd2_tag(INITRD_LOAD_ADDRESS, 0x100000); /* компрессированные данные 1Mb */ setup_cmdline_tag("root=/dev/ram0"); /* командная строчка, устанавливающая корневое устройство */ setup_end_tag(void); /* завершающий тэг */ }
int start_linux(char *name,char *rdname) { void (*theKernel)(int zero, int arch, u32 params); u32 exec_at = (u32)-1; u32 parm_at = (u32)-1; u32 machine_type; exec_at = ZIMAGE_LOAD_ADDRESS; parm_at = DRAM_BASE + 0x100 load_image(name, exec_at); /* скопировать образ в RAM */ load_image(rdname, INITRD_LOAD_ADDRESS); /* скопировать образ начального ramdisk в RAM */ setup_tags(parm_at); /* установить параметры */ machine_type = get_mach_type(); /* получить тип машины */ irq_shutdown(); /* остановить прерывания */ cpu_op(CPUOP_MMUCHANGE, NULL); /* выключить MMU */ theKernel = (void (*)(int, int, u32))exec_at; /* установить адрес ядра */ theKernel(0, machine_type, parm_at); /* передать управление ядру с установленными регистрами */ return 0; }
|
Предыдущая Содержание Следующая |