Processo de inicialização do ARM Linux

O kernel do Linux é inicializado na arquitetura ARM. Esta é a primeira parte.

Processo de inicialização do ARM Linux:

Vamos explicar o processo de inicialização do sistema no chip AT91RM9200, baseado no processador ARM Thumb ARM920T. Kwickbyte cria uma placa embutida chamada kb9202 baseada no AT91RM9200. Vamos tomar este fórum como um exemplo e ver como o Linux é inicializado neste fórum.

Antes de começar a ler isto, você precisa ler o passaporte AT91RM9200 (especificação)

Você também deve ler o Guia de referência de arquitetura do ARM para entender melhor o processo de inicialização.

Componentes no processo de inicialização do Linux:

O processo de inicialização do Linux consiste nos seguintes componentes.

Carregador

Imagem principal

Sistema de arquivos raiz

Antes de vermos o início do trabalho, o processo de inicialização do kernel para o braço. Esta é uma visão geral de todo o processo de inicialização do Linux. Nós usamos o carregador U-boot.

O processo de inicialização do ARM Linux: a grande figura

Boot:

_start (processador / arm920t / start.S)

start_code (cpu / arm920t / start.S)

start_armboot (lib_arm / board.c)

board_init (placa / kb9202 / kb9202.c)

timer_init (processador / arm920t / at91 / timer.c)

serial_init (drivers / serial / at91rm9200_usart.c)

main_loop (lib_arm / board.c)

Agora o u-boot está rodando, funcionando e pronto para receber comandos. Suponha que a imagem do kernel esteja carregada na RAM e o comando bootm seja inserido.

do_bootm (common / cmd_bootm.c)

bootm_start (common / cmd_bootm.c)

bootm_load_os (common / cmd_bootm.c)

do_bootm_linux (lib_arm / bootm.c)

stext (linux / arch / arm / kernel / head.S)

O controle é dado pelo Linux.

Kernel do Linux:

Stext (arco / braço / core / cabeça. S: 78)

__lookup_processor_type (arch / arm / kernel / head-common.S: 160)

__lookup_machine_type (arch / arm / kernel / head-common.S: 211)

__create_page_tables (arch / arm / kernel / head.S: 219)

__arm920_setup (arch / arm / mm / proc-arm920.S: 389)

__enable_mmu (arco / braço / núcleo / cabeça. S: 160)

__turn_mmu_on (arco / braço / núcleo / cabeça. S: 205)

__switch_data (arch / arm / kernel / head-common.S: 20)

start_kernel (init / main.c: 529)

start_kernel (init / main.c: 529)

tick_init (kernel / time / tick-common.c: 413)

setup_arch (arch / arm / kernel / setup.c: 666)

setup_machine (arch / arm / kernel / setup.c: 369)

lookup_machine_type ()

setup_command_line (init / main.c: 408)

build_all_zonelists (mm / page_alloc.c: 3031)

parse_args (kernel / params.c: 129)

mm_init (init / main.c: 516)

mem_init (arch / hand / mm / init.c: 528)

mmem_cache_init (mm / slab.c, mm / slob.c, mm / slub.c)

sched_init (kernel / sched.c)

init_IRQ (arch / arm / kernel / irq.c)

init_timers (kernel / timer.c: 1713)

hrtimers_init (kernel / hrtimer.c: 1741)

softirq_init (kernel / softirq.c: 674)

console_init (drivers / char / tty_io.c: 3084)

vfs_caches_init (fs / dcache.c: 2352)

mnt_init (fs / namespace.c: 2308)

init_rootfs ()

init_mount_tree (fs / namespace.c: 2285)

do_kern_mount (fs / namespace.c: 1053)

set_fs_pwd (fs / fs_struct.c: 29)

set_fs_root (fs / fs_struct.c: 12)

bdev_cache_init (fs / block_dev.c: 465)

chrdev_init (fs / char_dev.c: 566)

signal_init (kernel / signal.c: 2737)

rest_init (init / main.c: 425)

kernel_thread (431, arch / arm / kernel / process.c: 388)

O kernel_thread () cria um encadeamento do kernel, e o controle é fornecido pelo kernel_init ().

kernel_init (431, init / main.c: 856)

do_basic_setup (888, init / main.c: 787)

init_workqueues (789, kernel / workqueue.c: 1204)

driver_init (793, drivers / base / init.c: 20)

do_initcalls (796, init / main.c: 769) / * Chama todas as funções de inicialização do subsistema * /

prepare_namespace (906, init / do_mounts.c: 366)

initrd_load (399, init / do_mounts_initrd.c: 107)

rd_load_image (117, init / do_mounts_rd.c: 158) / * se o initrd for especificado * /

identif_ramdisk_image (179, init / do_mounts_rd.c: 53)

handle_initrd (119, init / do_mounts_initrd.c: 37) / * se o rd_load_image for bem sucedido * /

mount_block_root (45, init / do_mounts.c: 233)

do_mount_root (247, init / do_mounts .: 218)

mount_root (417, init / do_mounts.c: 334) / * se o initrd não for especificado * /

mount_block_root (359, init / do_mounts.c: 233)

do_mount_root (247, init / do_mounts.c: 218)

init_post (915, init / main.c: 816)

run_init_process (847, init / main.c: 807)

Kernel_execve (810, arch / arm / kernel / sys_arm.c: 81)

Espaço do usuário

init () / * userspace / sbin / init * /

Carregador:

Um carregador é um pequeno programa que carrega uma imagem do kernel na RAM e carrega uma imagem do kernel. Isso também é chamado de bootstrapping porque funciona com o sistema. O Bootloader é iniciado quando você inicia outro software, inicializa o processador e disponibiliza o programa para o sistema operacional. A maioria dos processadores tem um endereço padrão do qual os primeiros bytes de código são aplicados. Os desenvolvedores de equipamentos usam essas informações para armazenar o código do gerenciador de inicialização na ROM ou na memória flash. Como deve inicializar o processador e executar o programa localizado em um endereço específico, as especificações do bootloader contêm um processador muito específico e uma placa específica. Cada placa integrada vem com uma inicialização inicial para carregar uma imagem ou aplicativo do kernel na placa e executar uma imagem ou aplicativo do kernel. O carregador será quando a energia for aplicada à placa processadora. Basicamente, ele terá várias opções mínimas para carregar a imagem e carregá-la.

Também é possível controlar o sistema usando uma interface de depuração de hardware como o JTAG. Essa interface pode ser usada para gravar o programa de bootloader em uma memória não volátil inicializável (por exemplo, memória flash), instruindo o processador a executar as ações necessárias no sistema de memória não volátil. Geralmente feito pela primeira vez para inicializar o carregador principal e para algum processo de recuperação. O JTAG é uma interface padrão e popular fornecida por muitos fornecedores de placas. Alguns microcontroladores fornecem interfaces de hardware especiais que podem ser usadas para obter um sistema de controle livre ou não licenciado, mas, em vez disso, permitem que o código de carregamento seja inserido na memória de inicialização não volátil (por exemplo, memória flash) usando protocolos simples. Em seguida, durante a fase de produção, essas interfaces são usadas para inserir o código de inicialização (e possivelmente outro código) na memória não volátil. Depois que o sistema é reinicializado, o microcontrolador começa a executar seu software programado na memória não volátil, já que os processadores convencionais usam ROMs para carregar. Em muitos casos, essas interfaces são implementadas usando a lógica de hardware. Em outros casos, tais interfaces podem ser criadas pelo software executado em uma ROM no chip GPIO.

Alguns outros baixadores de terceiros estão disponíveis para fornecer uma interface de usuário simples e gratuita. Você pode baixar esses bootloaders de terceiros na placa e torná-los os bootloaders padrão para sua placa. Geralmente, os bootloaders fornecidos pelos fornecedores de placas são substituídos por esses bootloaders de terceiros. Um downloader de terceiros está disponível, alguns dos quais são open source (ou downloaders gratuitos), e alguns são comerciais. Algumas delas são Das U-Boot, Inicialização Vermelha, GRUB (para computadores desktop), LILO, Loadlin, bootloader, SYSLINUX, EtherBoot, ELILO.

Nós tomaremos o bootloader como nosso bootloader. Carregador – um carregador amplamente utilizado em sistemas embarcados. Vamos explicar o código da fonte -boot-2010.03. Você pode baixar o U-boot no seguinte site. http://www.denx.de/wiki/U-Boot

O How-to-boot é construído:

Com base na configuração U-boot, todos os arquivos de compilação (.S) e arquivos C (.c) são compilados com computadores criados para uma arquitetura específica, e arquivos de objeto (.o) serão criados. Todos esses arquivos são vinculados usando o vinculador e um arquivo executável será criado. Um arquivo de objeto ou um arquivo executável é um conjunto de seções, como .text, .data, .bss e assim por diante.Os arquivos de objeto e os arquivos executáveis ​​têm um formato de arquivo, como elf. Todas as seções do arquivo serão criadas em um arquivo executável com base em um script chamado script de vinculador. O script executa todos os elementos na memória na inicialização. Compreender este script é muito importante para saber como inicializar o carregador de boot e os computadores com o kernel e como diferentes partes do carregador de inicialização ou do kernel são carregadas na memória.

Como regra geral, o programa é iniciado (carregado), o carregador lê o arquivo executável na memória especificada e começa a executar a função de início (ponto de entrada) especificada no script de vinculação. Mas se você quiser iniciar (carregar) o carregador, você não poderá carregar nele (formato de arquivo) várias seções do arquivo executável na memória. Você precisará usar uma ferramenta que conterá todas as seções do arquivo executável e criará um arquivo binário que não possui nenhum formato de arquivo. Este é um arquivo binário que pode ser usado para memória, e pode ser gravado na ROM em qualquer lugar específico que será executado pelo processador quando a energia for aplicada à placa.

Suponha que, com base na configuração do U-boot, todos os arquivos sejam compilados e que os arquivos de objeto sejam criados. O makefile de inicialização usa o seguinte link (específico da arquitetura) para criar um arquivo executável.

Arquivo: cpu / arm920t / u-boot.lds

32 OUTPUT_FORMAT ("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")

33 OUTPUT_ARCH (mão)

34 LOGIN (_start)

35 SEÇÕES

36 {

37. = 0 trilhões;

38

39. = ALINHAMENTO (4);

40.text:

41 {

42 CPU / arm920t / start.o (.text)

43 * (. Texto)

44}

4546. = ALINHAR (4);

47.rodata: {* (SORT_BY_ALIGNMENT (SORT_BY_NAME (.rodata *)))

48

49. = ALINHAR (4);

50.data: {* (. Dados)

51

52. = ALINHAR (4);

53.got: {* (.))

54

55. =.

56 __u_boot_cmd_start =.

57.u_boot_cmd: {* (u_boot_cmd)

58 __u_boot_cmd_end =.

59

60. = ALINHAR (4);

61 __bss_start =.

62.bss (NOLOAD): {* (.Bss). = ALINHAR (4); }

63 _end =.

64}

OUTPUT_FORMAT na linha 32 indica o formato de arquivo do arquivo executável. Aqui o formato do arquivo executável é elf32, e o número de seqüência é um bit serial. OUTPUT_ARCH na linha 33 indica a arquitetura na qual este código funciona. ENTRY na linha 34 define a função de inicialização (ponto de entrada) do programa de inicialização. Aqui o ponto de entrada é _start.

SECTIONS na linha # 35 definem como as várias seções são exibidas no arquivo executável. O carregador usa os endereços nesta seção para carregar outra seção do programa na memória.

& # 39; & # 39; A linha 37 indica o endereço inicial onde as seções a seguir devem ser carregadas. Nesse caso, o endereço inicial é 0 trilhões. Depois disso, na linha nº 39, a memória está localizada por 4 bytes e na linha # 40 – a seção .text.

40.text:

41 {

42 CPU / arm920t / start.o (.text)

43 * (. Texto)

44}

Em & # 39;. posição (0x00000000) código em cpu / arm920t / start.o é exibido e segue o código que está lá. cpu / arm920t / start.o contém _start (em assembler), que é o ponto de entrada para este programa.

Agora isso é estará em 0x00000000 + sizeof (.text). Novamente, a memória é coordenada por 4 bytes e a seção .rodata na linha # 47.

= ALINHAR (4);

47.rodata: {* (SORT_BY_ALIGNMENT (SORT_BY_NAME (.rodata *)))

As seções .rodata de todos os arquivos são exibidas neste endereço. Segue as seções .data e .git.

49. = ALINHAR (4);

50.data: {* (. Dados)

51

52. = ALINHAR (4);

53.got: {* (.))

Cada comando load é um objeto do tipo “cmd_tbl_t”, que contém o nome do comando, o comando é executado. Todos esses objetos são definidos sequencialmente na memória. Cada objeto de comando é incorporado em uma seção específica da palavra U-boot. Essas seções all.u_boot_cmd são colocadas na memória após as seções acima (.data e.git).

=;

56 __u_boot_cmd_start =.

57.u_boot_cmd: {* (u_boot_cmd)

58 __u_boot_cmd_end =.

__u_boot_cmd_start contém o início dos objetos de comando e __u_boot_cmd_end – o final do comando.

E então essas são seções .bss (variáveis ​​globais não inicializadas).

60. = ALINHAR (4);

61 __bss_start =.

62.bss (NOLOAD): {* (.Bss). = ALINHAR (4); }

63 _end =.

__bss_start aponta para o endereço inicial de .bss e _end o final de todas as seções.

Usando este vinculador, o vinculador criará um arquivo executável chamado u-boot. A barra de ferramentas é usada para gerar um arquivo binário a partir do arquivo executável do u-boot.

boot.bin: boot

$ (OBJCOPY) $ {OBJCFLAGS} -O binário $

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *