امبدد لینوکس – قسمت شانزدهم – Bootloader (بخش سوم)

0
111
امبدد لینوکس – قسمت شانزدهم – Bootloader (بخش سوم)
امبدد لینوکس – قسمت شانزدهم – Bootloader (بخش سوم)

در قسمت قبل به بررسی بوت لودر (U-boot) پرداختیم و اون رو بر روی سخت افزار خودمون اجرا کردیم، حالا توی این قسمت میخوایم استفاده از یوبوت برای اجرای لینوکس رو آموزش دهیم و سیستم فایلمون رو به لینوکس متصل کنیم.

استفاده از یوبوت برای اجرای لینوکس

یوبوت (U-Boot) از یک رابط خط-فرمان (Command-line) استفاده می‌کنه.

این رابط نسبت به رابط خط-فرمان لینوکس خیلی ابتدایی هست و تقربیا به جز backspace از هیچ کنترل دیگه‌ای نمی‌تونین استفاده کنید. البته تنظیمات یوبوت (U-Boot) رو می‌شه عوض کرد جوری که خط-فرمان اون منطبق با Hush باشه که من تا حالا این کار رو نکردم و نمی‌خوام بکنم!!!

به صورت پیش‌فرض اعداد در این خط-فرمان یوبوت (U-Boot) در مبنای ۱۶ یا همون هگزادسیمال خودمون هستن.

در قسمت‌های قبلی آموزش، مسیر حرکت و فصل‌های پیش رو، بسیاری از مفاهیم موردنیاز و سؤال‌ها و ابهامات شما در این دوره پاسخ‌داده‌شده است.
پس اگر اولین بار است که این آموزش را شروع می‌کنید، با توجه به سلسله‌مراتب پیش‌بینی‌شده برای آموزش‌ها، بهتر است از جلسه اول شروع کنید!
برای مطالعه‌ی بیشتر امبدد لینوکس لطفا بر روی لینک کلیک کنید.

متغیرهای محیطی یوبوت U-Boot

یوبوت (U-Boot) برای انتقال اطلاعات بین توابع و یا دستورات مختلف از متغیرهای محیطی استفاه میکنه.

مقادیر اولیه بسیاری از متغیرهای در سورس فایل‌های مربوط به هر برد/ پردازنده تعریف شدن.

بسته به نوع حافظه‌تون شما هم می‌توانید متغیرهای جدیدی رو تعریف و ذخیره کنید.

با دستور زیر می‌تونید تمام متغیرهای تعریف شده رو ببیند:

printenv

arch=arm

baudrate=115200

board=rpi

board_name=3 Model B+

board_rev=0xD

board_rev_scheme=1

board_revision=0xA020D3

boot_a_script=load ${devtype} ${devnum}:${distro_bootpart} ${scriptaddr} ${prefix}${script}; source ${scriptaddr}

boot_efi_binary=load ${devtype} ${devnum}:${distro_bootpart} ${kernel_addr_r} efi/boot/bootaa64.efi; if fdt addr -q ${fdt_addr_r}; then bootefi ${keri

boot_efi_bootmgr=if fdt addr -q ${fdt_addr_r}; then bootefi bootmgr ${fdt_addr_r};else bootefi bootmgr;fi

boot_extlinux=sysboot ${devtype} ${devnum}:${distro_bootpart} any ${scriptaddr} ${prefix}${boot_syslinux_conf}

boot_net_usb_start=usb start

boot_prefixes=/ /boot/

boot_script_dhcp=boot.scr.uimg

boot_scripts=boot.scr.uimg boot.scr

boot_syslinux_conf=extlinux/extlinux.conf

boot_targets=mmc0 mmc1 mmc2 usb0 pxe dhcp

bootcmd=run distro_bootcmd

bootcmd_dhcp=devtype=dhcp; run boot_net_usb_start; if dhcp ${scriptaddr} ${boot_script_dhcp}; then source ${scriptaddr}; fi;setenv efi_fdtfile ${fdtf;

bootcmd_mmc0=devnum=0; run mmc_boot

bootcmd_mmc1=devnum=1; run mmc_boot

bootcmd_mmc2=devnum=2; run mmc_boot

bootcmd_pxe=run boot_net_usb_start; dhcp; if pxe get; then pxe boot; fi

bootcmd_usb0=devnum=0; run usb_boot

bootdelay=2

cpu=armv8

dhcpuboot=usb start; dhcp u-boot.uimg; bootm

distro_bootcmd=for target in ${boot_targets}; do run bootcmd_${target}; done

efi_dtb_prefixes=/ /dtb/ /dtb/current/

ethaddr=b8:27:eb:44:5a:00

fdt_addr=2eff8100

fdt_addr_r=0x02600000

fdt_high=ffffffffffffffff

fdtcontroladdr=3b3cc9c0

fdtfile=broadcom/bcm2837-rpi-3-b-plus.dtb

initrd_high=ffffffffffffffff

kernel_addr_r=0x00080000

load_efi_dtb=load ${devtype} ${devnum}:${distro_bootpart} ${fdt_addr_r} ${prefix}${efi_fdtfile}

loadaddr=0x1000000

mmc_boot=if mmc dev ${devnum}; then devtype=mmc; run scan_dev_for_boot_part; fi

preboot=usb start

pxefile_addr_r=0x02500000

ramdisk_addr_r=0x02700000

scan_dev_for_boot=echo Scanning ${devtype} ${devnum}:${distro_bootpart}...; for prefix in ${boot_prefixes}; do run scan_dev_for_extlinux; run scan_de;

scan_dev_for_boot_part=part list ${devtype} ${devnum} -bootable devplist; env exists devplist || setenv devplist 1; for distro_bootpart in ${devplistt

scan_dev_for_efi=setenv efi_fdtfile ${fdtfile}; for prefix in ${efi_dtb_prefixes}; do if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${ee

scan_dev_for_extlinux=if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${boot_syslinux_conf}; then echo Found ${prefix}${boot_syslinux_coni

scan_dev_for_scripts=for script in ${boot_scripts}; do if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${script}; then echo Found U-Boot e

scriptaddr=0x02400000

serial#=0000000048445a00

soc=bcm283x

stderr=serial,vidconsole

stdin=serial,usbkbd

stdout=serial,vidconsole

usb_boot=usb start; if usb dev ${devnum}; then devtype=usb; run scan_dev_for_boot_part; fi

usbethaddr=b8:27:eb:44:5a:00

vendor=raspberrypi

 

با این دستور هم می‌تونید متغیر جدید my_website رو با مقدار aniroot.com تعریف کنید:

 setenv my_website aniroot.com

 

با دستور saveenv هم می‌تونید متغیر خودتون رو واسه همیشه ذخیره کنید.

 

آماده سازی فایل‌ها برای لود شدن توسط یوبوت (U-Boot)

یوبوت (U-Boot) فایل سیستم نداره و از یک سرایند بیتی برای شناسایی فایل‌ها استفاده میکنه، برای ساختن این سرایند ابزاری هست به نام mkimage که هم می‌تونید از طریق مدیربسته‌های ابونتو نصبش کنید و هم اینکه از توی فولدر tools استفاده‌ش کنید:

~/EmbeddedLinux/RPI3BP/bootldr/u-boot/tools/mkimage

Error: Missing output filename

Usage: mkimage -l image

          -l ==> list image header information

       mkimage [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image

          -A ==> set architecture to 'arch'

          -O ==> set operating system to 'os'

          -T ==> set image type to 'type'

          -C ==> set compression type 'comp'

          -a ==> set load address to 'addr' (hex)

          -e ==> set entry point to 'ep' (hex)

          -n ==> set image name to 'name'

          -d ==> use image data from 'datafile'

          -x ==> set XIP (execute in place)

       mkimage [-D dtc_options] [-f fit-image.its|-f auto|-F] [-b <dtb> [-b <dtb>]] [-i <ramdisk.cpio.gz>] fit-image

           <dtb> file is used with -f auto, it may occur multiple times.

          -D => set all options for device tree compiler

          -f => input filename for FIT source

          -i => input filename for ramdisk file

Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)

       mkimage -V ==> print version information and exit

Use '-T list' to see a list of available image types

 

با تایپ کردن خط بالا در خط-فرمان لینوکس یک سری توضیحات در مورد این ابزار بهتون می‌ده و با سرچ کردن هم می‌تونید اطلاعات بیشتری به دست بیارید.

مثلاً این یک مدل از استفاده از این دستور هست.

sudo mkimage -A arm64 -O linux -T script -d ~/EmbeddedLinux/RPI3BP/bootldr/boot.cmd ~/EmbeddedLinux/RPI3BP/bootldr/boot.scr

داریم برای معماری ARM اون هم از نوع ۶۴ بیتی برای سیستم عامل لینوکس یه فایل از نوع اسکریبپ رو آماده می‌کنیم.

 

بارگزاری ایمیج توسط یوبوت (U-Boot)

با توجه به حافظه‌ای که می‌خوایم از اون ایمیج یا هر اطلاعاتی رو بارگزاری کنیم و فایل سیستم اون حافظه دستورات مختلفی داره یوبوت (U-Boot).

مثلاً برای بارگزاری از حافظه SD که با فایل سیستم FAT32 فرمت شده میتوینم از دستور زیر استفاده کنیم:

fatload mmc 0 $kernel_addr_r Image

در این مثال از حافظه شماره SD شماره صفر میخوایم فایل Image رو در آدرس kernel_addr_r (که خود kernel_addr_r  از متغیرهای محیطی  یوبوت U-Boot هست) بارگزاری کنیم.

 

بوت کردن لینوکس

خب حالا می‌خوایم از یوبوت (U-Boot) استفاده کنیم و لینوکس رو روی بردمون اجرا کنیم.

برای این کار به یک سری فایل‌ نیاز هست که توی فصول بعدی باشون آشنا می‌شیم و یاد میگیریم چه‌جوری بسازیمشون. چون اینجا لازمشون داریم  من این فایل‌ها رو ساختم و آماده‌ش رو واسه دانلود توی این مقاله قرار دادم تا بتونیم با هم پیش بریم و با یوبوت U-Boot بیشتر آشنا بشیم.

این فایل‌ها چیاهستن؟

کرنل لینوکس، دیوایس‌تریز و فایل سیستم روت اولیه.

اول تک تک این فایل‌ها رو در آدرس مربوطه بارگزاری میکنیم.

سوال: این آدرس رو از کجا باید بدونیم؟

جواب این آدرسها بعضی وقتا یونیک هستن ولی اغلب یونیک نیستن و با داشتن اطلاعاتی از حافظه رم و نحوه آدرس دهیشون توسط پردازنده و حجم فایل میشه بشون رسید ولی اغلب در راهنماهای شرکت سازنده مقادیر مناسب پیشنهاد شده.

تذکر از کپی پیست کردن دستورات زیر خودداری کنید و دستور را کامل تایپ کنید!

fatload mmc 0 $kernel_addr_r Image

20140544 bytes read in 905 ms (21.2 MiB/s)





fatload mmc 0 $fdt_addr_r             bcm2837-rpi-3-b-plus.dtb

21781 bytes read in 5 ms (4.2 MiB/s)





fatload mmc 0 $ramdisk_addr_r uInitrd

1395264 bytes read in 67 ms (19.9 MiB/s)

 

خب بعدش متغیر محیطی  bootargs رو مقدار دهی می‌کنیم که درحقیقت همون ارگومان‌هایی هست که به کرنل میدیم:

setenv bootargs console=tty1  console=ttyAMA0,115200 earlyprintk root=/dev/root rootwait panic=10

 

در نهایت با این دستور کرنل رو بارگزاری میکنیم:

booti $kernel_addr_r $ramdisk_addr_r $fdt_addr_r

Moving Image from 0x80000 to 0x200000, end=1670000

## Loading init Ramdisk from Legacy Image at 02700000 ...

   Image Name:   uInitrd

   Image Type:   AArch64 Linux RAMDisk Image (uncompressed)

   Data Size:    1395200 Bytes = 1.3 MiB

   Load Address: 00000000

   Entry Point:  00000000

   Verifying Checksum ... OK

## Flattened Device Tree blob at 02600000

   Booting using the fdt blob at 0x2600000

   Using Device Tree in place at 0000000002600000, end 0000000002608514





Starting kernel …

 

خب کرنل شروع شد…

البته به لطف رسپبری پای تا اینجا رو بیشتر نداریم و نمیتونید وارد محیط لینوکس بشید.

قصه‌اش هم مفصل هست رسپبری پای از سریال اصلی برای بلوتوث استفاده میکنه و اصلا رسپبری پای بوت لودر خودش رو داره و میونه خوبی با یوبوت (U-Boot) نداره و بهتره از همون بوت لودر خودش که سورسش در دسترس نیست استفاده کنید…

البته که منطقی نبود در دو خط نحوه استفاده از بوت لودر رسپبری پای رو بگیم و این فصل رو با دو خط آموزش منتشر کنیم ?

ولی خب برای یادگیری  یوبوت (U-Boot) و استفاده از اون برای بقیه‌ی پروژه‌ها الان آماده هستین تقریبا.

چرا تقریبا؟

چون کدوم برد رو دیدن هر دفعه برای اجرای لینوکس یکی بیاد با سریال بش وصل بشه و یه سری دستورات رو تایپ کنه و …

بله روند بوت باید به صورت خودکار انجام بشه.

برای این کار یه فایل باید کنار بقیه فایل‌ها توی SD کارت بذارین

محتویاتش دقیقاً همون‌هایی هست که در خط-فرمان  یوبوت (U-Boot) تایپ کردیم و بعدش باید با mkimage برای یوبوت (U-Boot) آماده‌ش کنید:

<span style="font-size: 10pt;">booti $kernel_addr_r $ramdisk_addr_r $fdt_addr_r</span>

 

و حالا با این دستور آماده‌ش کنیم برای ریختن روی SD کارت:

<span style="font-size: 10pt;">sudo mkimage -A arm64 -O linux -T script -d ~/EmbeddedLinux/RPI3BP/bootldr/boot.cmd ~/EmbeddedLinux/RPI3BP/bootldr/boot.scr</span>

 

از این به بعد با روشن شدن برد خود به خود لینوکس اجرا میشه.

اگه یه روزی خواستیم بریم توی محیط یوبوت (U-Boot) کافیه اولش تند تند تایپ کنیم ? در اینجا این فصل هم تمام میشه، اما آنچه ما بدان نپرداختیم و شاید روزی به کارتان اید پورت کردن  یوبوت (U-Boot) برای برد جدید هست. میتونه هم کار خیلی راحتی باشه هم کار بیش از حد سختی. پیشنهاد میکنم برید دنبالش و به عنوان تمرین یوبوت (U-Boot) رو روی لیچی‌پای و برای پردازنده F1C100s اجرا کنید.

 

یه سری هم به نظرات این پایین بندازید، نظرات رو بخونید و اگر شما هم نظری دارید، لطفا با ما به اشتراک بگذارید!
همه آموزش های امبدد لینوکس

 

پایان این فصل

 

 

منبع: سیسوگ

مطلب قبلیمکان‌یابی در مکانهای بسته با WiFi (بدون GPS)
مطلب بعدیکنترل سرعت نور ممکن شد

پاسخ دهید

لطفا نظر خود را وارد کنید!
لطفا نام خود را در اینجا وارد کنید