在Unix / Linux

ARM Linux引导进程

Bu, Linux çekirdeğinin ARM mimarisinde nasıl çizildiğini açıklayan bir dizi makale olacak. Bu birinci kısımdır.

ARM Linux Önyükleme Süreci:

ARM920T ARM Thumb işlemci etrafında oluşturulan AT91RM9200 çip üzerindeki sistem önyükleme işlemini açıklayacağız. Kwickbyte, AT91RM9200'ü temel alan kb9202 adında gömülü bir kart oluşturur. Bu panoya örnek olarak bakacağız ve Linux'un bu panoda nasıl açıldığını göreceğiz.

Bunu okumaya başlamadan önce AT91RM9200 veri sayfasını (şartname) okumanız gerekir.

Bunun için ARM Mimarisi Referans Kılavuzunu da okumanız gerekir. önyükleme sürecini daha iyi anlıyoruz

Linux Önyükleme İşlemindeki Bileşenler:

Linux önyükleme işlemi aşağıdaki bileşenleri içeriyor:

Bootloader

Çekirdek Resmi

Kök Dosya Sistemi

Yukarıdaki bileşenlerin nasıl çalıştığını görmeden önce, Linux Çekirdeği önyükleme işleminin kol mimarisi için çağrı akışı aşağıdadır. Bu, tüm Linux önyükleme işlemi hakkında büyük bir resim verir. U-boot bootloader kullanıyoruz.

ARM Linux Önyükleme Süreci: Büyük Resim

U-boot:

_start (işlemci / arm920t / start.S)

start_code (işlemci / arm920t / start.S)

start_armboot (lib_arm / board.c)

/kb9202/kb9202.c)PL19659004UZtimer_init (cpu / arm920t / at91 / timer.c)

serial_init (sürücüler / seri / at91rm9200_usart.c)

main_loop (lib_arm / board9.c4) u-boot çalışıyor ve çalışıyor ve u-boot isteminde ve komutları kabul etmeye hazır. Çekirdek görüntüsünün RAM'e yüklendiğini ve bootm komutunun verildiğini varsayalım.

do_bootm (ortak / cmd_bootm.c)

bootm_start (ortak / cmd_bootm.c)

bootm_start (ortak / cmd_bootm.c)

bootm_load_os (ortak / cmd_bootm.c)

(lib_arm / bootm.c)

stext (linux / arch / arm / çekirdek / kafa.S)

kontrol linux’a verilir.

Linux Çekirdeği:

stext (kemer / kol / çekirdek / head.S: 78)

__ lookup_processor_type (kemer / kol / çekirdek / kafa ortak.S: 160)

__ lookup_machine_type (kemer / kol / çekirdek / kafa ortak.S: 211)

__ create_page_tables (arch) /arm/kernel/head.S:219)PL19659004UZ__arm920_setup (kemer / kol / mm / proc-kol920.S: 389)

__ enable_mmu (kemer / kol / çekirdek / kafa.S: 160)

__turn_mmu_on (kemer / kol / çekirdek / kafa.S: 205)

__ switch_data (kemer / kol / çekirdek / kafa ortak.S: 20)

start_kernel (init / main.c: 529)

start_kernel (init / main.c: 529)

tick_init (çekirdek / zaman / tick-common.c: 413)

setup_arch (kemer / kol / çekirdek / kurulum.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)

çekirdek / params.c: 129)

mm_init (init / main.c: 516)

mem_init (kemer / kol / mm / init.c: 528)

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

sched_init (çekirdek / sched.c)

init_IRQ (kemer / kol / çekirdek / irq.c)

init_timers (çekirdek / zamanlayıcı.c: 1713)

hrtimers_init (çekirdek / hrtimer.c: 1741)

softirq_init (çekirdek / softirq.c: 674)

c: 2352)

mnt_init (fs / namespace.c: 2308)

init_rootfs ()

init_mount_tree (fs / namespace.c: 2285)

do_kern_mount (fs / isimler.c. 19659004] set_fs_pwd (fs / fs_struct.c: 29)

set_fs_root (fs / fs_struct.c: 12)

bdev_cache_init (fs / blok_dev.c: 465)

)

signals_init (çekirdek /signal.c:2737)PL19659004 EUROPrest_init (init / main.c: 425)

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

kernel_thread () bir çekirdek ipliği oluşturur ve kernel_init ().

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

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

init_workqueues (789, kernel / workque. : 1204)

driver_init (793, sürücüler / base / init.c: 20)

do_initcalls (796, init / main.c: 769) / * Tüm alt sistemler init işlevlerini çağırır * /

prepara_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) / *, initrd * / [19659] verildiğinde ident_ramdisk_image (179, init / do_mounts_rd.c: 53)

handle_initrd (119, init / do_mounts_initrd.c: 37) / *, eğer rd_load_image başarılı olursa * /

mount_block_root (45, init / 23: 23.05.2009]

do_mount_root (247, init / do_mounts: 218)

mount_root (417, init / do_mounts.c: 334) / *, initrd belirtilmezse * /

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) [1965] [1965]

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

kernel_execve (810, kemer / kol / çekirdek / sys_arm.c: 81)

Kullanıcı Alanı

init () / * users / sbin / init * /

Bootloader:

Bootloader, çekirdek görüntüsünü RAM'e yükleyen ve çekirdek görüntüsünü başlatan küçük bir programdır. Bu aynı zamanda bir işletim sistemi yükleyerek sistemi getirir (çeker) olarak bootstrap olarak da adlandırılır. Bootloader, başka herhangi bir yazılım başlamadan önce başlar ve işlemciyi başlatır ve işlemciyi işletim sistemi gibi bir programı çalıştırmaya hazır hale getirir. Çoğu işlemci, güç uygulandığında ya da kart sıfırlandığında ilk kod baytının alındığı varsayılan bir adrese sahiptir. Donanım tasarımcıları bu bilgileri önyükleyici kodunu bu adresteki ROM ya da flaş olarak saklamak için kullanırlar. CPU'yu başlatması ve mimaride özel adres önyükleyicilerinde bulunan bir programı çalıştırması gerektiğinden, işlemciye özgü ve panoya özgüdür. Gömülü her tahta, çekirdek görüntüsünü veya bağımsız uygulamayı tahtaya indirmek ve çekirdek görüntüsünü veya uygulamayı çalıştırmaya başlamak için bir önyüklemeyle birlikte gelir. İşlemci kartına güç uygulandığında önyükleyici çalıştırılacak. Temel olarak, görüntüyü yüklemek ve başlatmak için bazı asgari özelliklere sahip olacaktır.

Sistemi JTAG gibi bir donanım hata ayıklama arayüzü kullanarak kontrol etmek de mümkündür. Bu arabirim, önyükleyici programını önyükleyici olmayan geçici belleğe (örneğin flaş) yazmak için, işlemci çekirdeğine geçici olmayan belleği programlamak için gerekli işlemleri yapması talimatını vererek kullanılabilir. Genellikle temel açılış yükleyicisini indirmek ve bazı kurtarma işlemleri için ilk kez yapılır. JTAG, birçok kurul satıcısı tarafından sağlanan standart ve popüler bir arayüzdür. Bazı mikro denetleyiciler, bir sistemin keyfi kontrolünü almak veya doğrudan kod çalıştırmak için kullanılamayan özel donanım arabirimleri sağlar, ancak bunun yerine önyükleme kodunun basit protokoller aracılığıyla önyüklenebilir olmayan geçici belleğe (flash bellek gibi) eklenmesine izin verir. Daha sonra üretim aşamasında, bu tür arayüzler önyükleme kodunu (ve muhtemelen başka bir kodu) geçici olmayan belleğe enjekte etmek için kullanılır. Sistem sıfırlandıktan sonra mikro denetleyici, geçici işlemcilere programlanan kodu çalıştırmaya başlar, tıpkı her zamanki işlemcilerde önyükleme için ROM kullanıyor. Çoğu durumda, bu tür arayüzler kablolu mantıkla gerçekleştirilir. Diğer durumlarda, bu tür arayüzler GPIO pinlerinden entegre çipli önyükleme ROM'unda çalışan bir yazılım ile oluşturulabilir

Zengin özellikler kümesi ve kolay kullanıcı arayüzü sağlayan başka bir üçüncü taraf önyükleyici bulunmaktadır. Bu üçüncü parti önyükleyicileri panele indirebilir ve panonuz için varsayılan önyükleyiciler oluşturabilirsiniz. Genel olarak pano satıcıları tarafından sağlanan önyükleyiciler bu üçüncü taraf önyükleyicileri ile değiştirilir. Çok az sayıda üçüncü taraf boolader mevcut ve bazıları açık kaynaklı (veya ücretsiz önyükleyiciler) ve bazıları ticari. Bunlardan bazıları Das U-Boot, Kırmızı boot, GRUB (masaüstü bilgisayarlar için), LILO, Loadlin, bootsect-loader, SYSLINUX, EtherBoot, ELILO.

U-boot boot yükleyiciyi boot yükleyicimiz olarak alacağız. U-boot, gömülü sistemlerde yaygın olarak kullanılan boot yükleyicidir. Kodu u-boot-2010.03 kaynağından açıklayacağız. U-boot'ı aşağıdaki siteden indirebilirsiniz. http://www.denx.de/wiki/U-Boot

U-Önyüklemesi Nasıl Yapılır:

U-Önyükleme yapılandırmasına dayanarak, tüm derleme dosyaları (.S ) ve C dosyaları (.c), belirli bir mimari için inşa edilmiş çapraz derleyici kullanılarak derlenir ve nesne dosyaları (.o) oluşturulur. Tüm bu nesne dosyaları linker ile bağlanır ve çalıştırılabilir bir dosya oluşturulur. Bir nesne dosyası veya çalıştırılabilir dosya .text, .data, .bss vb. Gibi bölümlerin bir derlemesidir. Nesne dosyaları ve çalıştırılabilir dosyalar, elf gibi bir dosya biçimine sahiptir. Nesne dosyalarının tüm bölümleri linker betiği adı verilen bir betiği temel alarak yürütülebilir dosyada düzenlenir. Bu komut dosyası, çalıştığı sırada tüm bölümlerin belleğe nereye yükleneceğini söyler. Bu betiği anlamak, önyükleyici ve çekirdeğin nasıl oluşturulduğunu ve önyükleyici veya çekirdeğin farklı bölümlerinin belleğe nasıl yüklendiğini bilmek çok önemlidir.

Genellikle, bir program çalıştırıldığında (çalıştırıldığında) bir yükleyici yürütülebilir dosyayı okur ve yükler çalıştırılabilir dosyanın belirtilen bölümdeki farklı bölümleri ve linker betiğinde belirtilen start işlevini (giriş noktası) çalıştırmaya başlar. Ancak, bir önyükleyici çalıştırmak (yüklemek) istiyorsanız, çalıştırılabilir dosyanın farklı bölümlerini belleğe yüklemek (temelde dosya biçimini anlamak için) yoktur. Daha sonra çalıştırılabilir dosyadan tüm bölümleri alan objcopy adlı bir araç kullanmanız ve herhangi bir dosya formatına sahip olmayan bir ikili dosya oluşturmanız gerekir. Bu ikili dosya belleğe yüklenebilir ve ROM'a, panoya güç uygulandığında cpu tarafından yürütülecek olan belirli bir adreste (mimariye özgü) yazılabilir veya yazılabilir.

U-boot yapılandırması tüm dosyalar derlenir ve nesne dosyaları oluşturulur. U-boot makefile çalıştırılabilir bir dosya oluşturmak için (mimariye özgü) aşağıdaki linker komut dosyasını kullanır.

Dosya: cpu / arm920t / u-boot.lds

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

33 OUTPUT_ARCH (kol)

34 GİRİŞ (_start)

35 BÖLÜMLER

36 {

37. = 0x00000000;

38

39. = ALIGN (4);

40.text:

41 {

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

43 * (. Metin)

44}

4546. = ALIGN (4);

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

48

49. = ALIGN (4);

50. veri: {* (. Veri)}

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}

32. satırdaki OUTPUT_FORMAT, yürütülebilir dosyanın dosya biçimini belirtir. Burada çalıştırılabilir dosya formatı elf32 ve endianness küçük endian. OUTPUT_ARCH # 33 satırında bu kodun çalıştığı mimariyi belirtin. 34. satırdaki ENTRY, u-boot programının start fonksiyonunu (giriş noktası) belirtir. Burada giriş noktası _start.

# 35 numaralı satırdaki BÖLÜMLER, yürütülebilir dosyada farklı bölümlerin nasıl eşlendiğini tanımlar. Yükleyici, programın farklı bölümlerini belleğe yüklemek için bu bölümde belirtilen adresleri kullanır.

'.' 37 numaralı satırda aşağıdaki bölümlerin yüklenmesi gereken başlangıç ​​adresini belirtir. Bu durumda başlangıç ​​adresi: 0x00000000. 39 no'lu satırdan sonra, bellek 4 byte ile hizalanır ve metin kısmı # 40 satırında takip eder.

40.text:

41 {

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

43 * (. metin)

44}

'de.' pozisyonu (0x00000000) cpu / arm920t / start.o içindeki kod eşleştirilir ve diğer tüm nesne (.o) dosyalarının .text bölümlerinde bulunan kodu izler. cpu / arm920t / start.o, bu programın giriş noktası olan _start () işlevini (assembly dilinde) içerir.

Şimdi '.' 0x00000000 + sizeof (.text) konumunda olacaktır. Yine bellek 4 byte ile hizalanır ve .rodata bölümü 47 numaralı satırda ilerler.

. = ALIGN (4);

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

. Tüm nesne dosyalarından rorotata bölümleri bu adreste eşlenir. Veri ve veri bölümlerini takip eder.

49. = ALIGN (4);

50. veri: {* (. Veri)}

51

52. = ALIGN (4);

53.got: {* (. Got)}

Her U-boot komutu, 'cmd_tbl_t' türünde bir nesnedir; bu komut çalıştırıldı. Tüm bu komut nesneleri belleğe sırayla yerleştirilir. Bu komut nesnesinin her biri, nesne dosyasında .u_boot_cmd adlı U önyükleme tanımlı bir bölüme yerleştirilmiştir. Bu all.u_boot_cmd bölümleri, yukarıdaki bölümlerden sonra (.data.git) belleğe yerleştirilir.

. =.; komut nesneleri

Ve daha sonra .bs. (başlatılmamış global değişkenler) bölümlerini takip ediyor.

60. = ALIGN (4);

61 __bss_start = .;

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

63 _end = .;

__ bss_start, .bss başlangıç ​​adresine işaret eder ve _end, tüm bölümlerin sonunu içerir.

Bu linker komut dosyasını kullanarak, u-boot adı verilen çalıştırılabilir bir dosya oluşturulur. Objcopy aracı, u-boot çalıştırılabilir dosyasından ikili bir dosya oluşturmak için kullanılır.

u-boot.bin: u-boot

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