B. Полный пример

Предыдущая  Содержание  Следующая V*D*V

Это рабочий пример простого загрузчика и он показывает всю информацию, описанную в этом документе. Для реального загрузчика может потребоваться больше кода, этот пример чисто иллюстративен.

 

Код этого примера распространяется под лицензией 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;

}

 

Предыдущая  Содержание  Следующая