Proses Boot Linux ARM

Ini akan menjadi serangkaian artikel yang menjelaskan bagaimana kernel Linux melakukan boot pada arsitektur ARM. Ini adalah bagian pertama.

Proses Boot Linux ARM:

Kami akan menjelaskan proses boot dari AT91RM9200 system-on-chip, yang dibangun di sekitar prosesor ARM Thumb ARM920T. Kwickbyte membangun papan tertanam yang disebut kb9202 berdasarkan AT91RM9200. Kami akan mengambil papan ini sebagai contoh dan melihat bagaimana Linux melakukan boot di papan ini.

Sebelum Anda mulai membaca ini, Anda perlu membaca lembar data AT91RM9200 (spesifikasi).

Anda juga perlu membaca Referensi Arsitektur ARM Manual untuk lebih memahami proses boot.

Komponen dalam Proses Boot Linux:

Proses boot Linux melibatkan komponen-komponen berikut.

Bootloader

Gambar Kernel

Root Filesystem

Sebelum kita melihat bagaimana komponen di atas bekerja, berikut ini adalah aliran panggilan dari proses boot Kernel Linux untuk arsitektur lengan. Ini memberikan gambaran besar pada keseluruhan proses boot Linux. Kami menggunakan bootloader U-boot.

Proses Boot ARM Linux: Gambar Besar

U-boot:

_start (cpu / arm920t / start.S)

start_code (cpu / arm920t / start.S)

start_armboot (lib_arm / board.c)

board_init (board / kb9202 / kb9202.c)

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

serial_init (driver / serial / at91rm9200_usart.c)

main_loop (lib_arm / board.c)

Sekarang u-boot sedang berjalan dan sedang dalam prompt u-boot dan siap menerima perintah. Asumsikan bahwa imej kernel dimuat ke dalam RAM dan mengeluarkan perintah bootm.

do_bootm (umum / cmd_bootm.c)

bootm_start (umum / cmd_bootm.c)

bootm_load_os (umum / cmd_bootm.c)

do_bootm_linux (lib_arm / bootm.c)

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

Kontrol diberikan ke linux.

Kernel Linux:

stext (arch / arm / kernel / head.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 (arch / arm / kernel / head.S: 160)

__turn_mmu_on (arch / arm / kernel / head.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 / arm / mm / init.c: 528)

kmem_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 (driver / 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)

signals_init (kernel / signal.c: 2737)

rest_init (init / main.c: 425)

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

kernel_thread () membuat utas kernel dan kontrol diberikan ke kernel_init ().

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

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

init_workqueues (789, kernel / workqueuec: 1204)

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

do_initcalls (796, init / main.c: 769) / * Panggilan semua subsitems fungsi init * /

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) / * jika initrd diberikan * /

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

handle_initrd (119, init / do_mounts_initrd.c: 37) / * jika rd_load_image sukses * /

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) / * jika initrd tidak diberikan * /

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)

Ruang pengguna

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

Bootloader:

Bootloader adalah program kecil yang akan memuat imej kernel ke dalam RAM dan mem-boot gambar kernel. Ini juga disebut bootstrap karena membawa (menarik) sistem dengan memuat sistem operasi. Bootloader dimulai sebelum perangkat lunak lain memulai dan menginisialisasi prosesor dan membuat cpu siap menjalankan program seperti sistem operasi. Sebagian besar prosesor memiliki alamat default dari mana byte pertama kode diambil saat daya diterapkan atau papan direset. Perancang perangkat keras menggunakan informasi ini untuk menyimpan kode bootloader di alamat itu di ROM atau flash. Karena harus menginisialisasi cpu dan harus menjalankan program yang terletak di alamat khusus arsitektur bootloader sangat spesifik prosesor dan papan spesifik. Setiap papan tertanam dilengkapi dengan bootstrap untuk mengunduh imej kernel atau aplikasi yang berdiri sendiri ke dalam papan dan mulai mengeksekusi imej kernel atau aplikasi. Bootloader akan dieksekusi ketika daya diterapkan ke papan prosesor. Pada dasarnya ini akan memiliki beberapa fitur minimal untuk memuat gambar dan mem-boot-nya.

Hal ini juga memungkinkan untuk mengontrol sistem menggunakan antarmuka debug perangkat keras seperti JTAG. Antarmuka ini dapat digunakan untuk menulis program boot loader ke dalam memori non-volatile yang dapat di-boot (misalnya flash) dengan menginstruksikan inti prosesor untuk melakukan tindakan yang diperlukan untuk memprogram memori non-volatile. Umumnya dilakukan untuk pertama kali mengunduh bootloader dasar dan untuk beberapa proses pemulihan. JTAG adalah antarmuka standar dan populer yang disediakan oleh banyak vendor papan. Beberapa pengendali mikro menyediakan antarmuka perangkat keras khusus yang tidak dapat digunakan untuk mengambil kontrol sewenang-wenang dari suatu sistem atau menjalankan kode secara langsung, tetapi sebaliknya mereka memungkinkan penyisipan kode boot ke dalam memori non-volatil yang dapat di-boot (seperti memori flash) melalui protokol sederhana. Kemudian pada fase pembuatan, antarmuka semacam itu digunakan untuk menyuntikkan kode boot (dan mungkin kode lain) ke dalam memori yang tidak mudah menguap. Setelah pengaturan ulang sistem, pengendali mikro mulai mengeksekusi kode yang diprogram ke dalam memori non-volatile, sama seperti prosesor biasa yang menggunakan ROM untuk boot. Dalam banyak kasus, antarmuka semacam itu diimplementasikan oleh logika yang dipasangi kabel. Dalam kasus lain, antarmuka tersebut dapat dibuat oleh perangkat lunak yang berjalan pada boot ROM boot terintegrasi dari pin GPIO.

Ada beberapa bootloader pihak ketiga lain yang tersedia yang menyediakan sekumpulan fitur yang kaya dan antarmuka pengguna yang mudah. Anda dapat mengunduh bootloader pihak ketiga ini ke dalam board dan dapat menjadikannya bootloader default untuk board Anda. Umumnya bootloader yang disediakan oleh vendor papan diganti dengan bootloader pihak ketiga ini. Ada beberapa boolader pihak ketiga yang tersedia dan beberapa di antaranya adalah open source (atau bootloader gratis) dan beberapa bersifat komersial. Beberapa di antaranya adalah Das U-Boot, boot merah, GRUB (untuk desktop), LILO, Loadlin ,, bootsect-loader, SYSLINUX, EtherBoot, ELILO.

Kami akan menggunakan boot loader U-boot sebagai boot loader kami. U-boot adalah boot loader yang banyak digunakan dalam sistem embedded. Kami akan menjelaskan kode dari sumber u-boot-2010.03. Anda dapat mengunduh U-boot dari situs berikut. http://www.denx.de/wiki/U-Boot

Bagaimana U-boot dibangun:

Berdasarkan konfigurasi U-boot, semua file assembly (.S) dan file C (.c) dikompilasi menggunakan cross compiler yang dibangun untuk arsitektur tertentu dan file objek (.o) akan dihasilkan. Semua file objek ini dihubungkan oleh linker dan file yang dapat dieksekusi akan dibuat. File objek atau file yang dapat dieksekusi adalah kumpulan bagian seperti .text, .data, .bss, dll. File objek dan file yang dapat dieksekusi memiliki format file seperti elf. Semua bagian dari file objek akan diatur dalam file yang dapat dijalankan berdasarkan skrip yang disebut skrip linker. Skrip ini memberi tahu di mana semua bagian harus dimuat di memori saat dijalankan. Memahami skrip ini sangat penting untuk mengetahui bagaimana boot loader dan kernel disusun dan bagaimana bagian boot loader atau kernel yang berbeda dimuat dalam memori.

Umumnya, ketika sebuah program dijalankan (dieksekusi), sebuah loader membaca file yang dapat dieksekusi dan memuat bagian-bagian berbeda dari file yang dapat dieksekusi di lokasi memori yang ditentukan dan mulai menjalankan fungsi awal (entry point) yang ditentukan dalam skrip linker. Tapi, jika Anda ingin menjalankan (memuat) boot loader tidak akan ada loader untuk memuat (pada dasarnya untuk memahami format file) bagian yang berbeda dari file yang dapat dieksekusi ke dalam memori. Maka Anda perlu menggunakan alat yang disebut objcopy yang akan mengambil semua bagian dari file yang dapat dieksekusi dan membuat file biner yang tidak memiliki format file. File biner ini dapat dimuat ke dalam memori dan dieksekusi atau dapat ditulis ke ROM pada alamat tertentu (khusus untuk arsitektur) yang akan dijalankan oleh cpu ketika daya diterapkan ke papan.

Asumsikan bahwa berdasarkan konfigurasi U-boot semua file dikompilasi dan file objek dibuat. U-boot makefile menggunakan skrip linker berikut (khusus untuk arsitektur) untuk membangun file yang dapat dieksekusi.

File: cpu / arm920t / u-boot.lds

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

33 OUTPUT_ARCH (lengan)

34 ENTRY (_start)

35 BAGIAN

36 {

37. = 0x00000000;

38

39. = ALIGN (4);

40.tanda:

41 {

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

43 * (. Teks)

44}

4546. = ALIGN (4);

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

48

49. = ALIGN (4);

50.data: {* (. Data)}

51

52. = ALIGN (4);

53.got: {* (. Got)}

54

55. = .;

56 __u_boot_cmd_start = .;

57.u_boot_cmd: {* (. U_boot_cmd)}

58 __u_boot_cmd_end = .;

59

60. = ALIGN (4);

61 __bss_start = .;

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

63 _end = .;

64}

OUTPUT_FORMAT in line # 32 menentukan format file dari file yang dapat dieksekusi. Di sini format file yang dapat dieksekusi adalah elf32 dan endianness adalah little endian. OUTPUT_ARCH in line # 33 menentukan arsitektur tempat kode ini berjalan. ENTRY in line # 34 menspesifikasikan fungsi awal (entry point) dari program u-boot. Di sini titik masuk adalah _mulai.

SECTIONS in line # 35 mendefinisikan bagaimana bagian yang berbeda dipetakan dalam file yang dapat dieksekusi. Loader menggunakan alamat yang ditentukan di bagian ini untuk memuat bagian yang berbeda dari program ke dalam memori.

'.' di baris # 37 menentukan alamat awal di mana bagian berikut harus dimuat. Dalam hal ini alamat awal adalah 0x00000000. Setelah ini sejalan # 39, memori disejajarkan dengan 4 byte dan bagian .text akan mengikuti garis # 40.

40.tanda:

41 {

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

43 * (. Teks)

44}

Pada '.' position (0x00000000) kode di cpu / arm920t / start.o dipetakan dan mengikuti kode yang ada di bagian in.text dari semua file object (.o) lainnya. cpu / arm920t / start.o berisi fungsi _start () (dalam bahasa assembly) yang merupakan titik masuk dari program ini.

Sekarang '.' akan berada di 0x00000000 + sizeof (.text). Sekali lagi memori sejajar dengan 4 byte dan.produk mengikuti baris # 47.

. = ALIGN (4);

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

Bagian .rodata dari semua objek file dipetakan pada alamat ini. Ikuti bagian.data dan.git.

49. = ALIGN (4);

50.data: {* (. Data)}

51

52. = ALIGN (4);

53.got: {* (. Got)}

Setiap perintah U-boot adalah objek bertipe 'cmd_tbl_t' yang berisi nama perintah, string bantuan, dan penunjuk fungsi untuk dieksekusi ketika perintah ini dijalankan. Semua objek perintah ini ditempatkan dalam memori secara berurutan. Masing-masing objek perintah ini dibangun menjadi bagian yang didefinisikan U-boot yang disebut.u_boot_cmd dalam file objek. Semua bagian all.u_boot_cmd ini ditempatkan dalam memori setelah bagian di atas (.data dan.git).

. = .;

56 __u_boot_cmd_start = .;

57.u_boot_cmd: {* (. U_boot_cmd)}

58 __u_boot_cmd_end = .;

__u_boot_cmd_start berisi permulaan objek perintah dan __u_boot_cmd_end berisi akhir dari objek perintah.

Dan selanjutnya mengikuti bagian the.bss (variabel global terinisialisasi).

60. = ALIGN (4);

61 __bss_start = .;

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

63 _end = .;

__bss_start menunjuk ke alamat awal the.bss dan _end berisi akhir dari semua bagian.

Menggunakan linker skriper tautan ini akan menghasilkan file yang dapat dieksekusi yang disebut u-boot. Alat objcopy digunakan untuk menghasilkan file biner dari file executable u-boot.

u-boot.bin: u-boot

$ (OBJCOPY) $ {OBJCFLAGS} -O $ biner