سیستم عامل شمس

پایگاه طراحی سیستم عامل

سیستم عامل شمس

پایگاه طراحی سیستم عامل

فصل دوم :‌ گام های آغازین

سه شنبه, ۱۰ آذر ۱۳۹۴، ۰۳:۲۷ ب.ظ

۲     گام های آغازین

توسعه سیستم عامل کاری آسان نیست، و این پرسش که "چگونه می توانم شروع به حل این مسئله کنم؟" نیز به تجربه مشکلات مختلف در طول کار برروی چند پروژه متفاوفت خواهد انجامید. مطالعه این فصل به شما در راه اندازی محیط توسعه  و بوت کردن یک سیستم عامل بسیار کوچک (و غیر انحصاری) کمک خواهد کرد.

۲-     ابزارها

۲--     راه اندازی سریع

ما (مولفان) از سیستم عامل Ubuntu نسخه 6 برای کار برروی توسعه سیستم عامل استفاده کردیم، و آن را به صورت فیزیکی و مجازی (با استفاده از ماشین مجازی Virtual Box) اجرا کردیم. یک راه سریع برای آماده سازی همه ی موارد و اجرا این است که از همان ابزاری که ما برای راه اندازی استفاده می کنیم استفاده کنید، به این خاطر که ما می دانیم این ابزارها با مثال های آورده شده در این کتاب کارخواهند کرد.
به محض اینکه Ubuntu نصب شد، چه نصب فیزیکی و یا مجازی، بسته های زیر باید با استفاده از apt-get نصب شوند :

 sudo apt-get install build-essential nasm genisoimage bochs bochs-sdl

۲-۲-     زبان های برنامه نویسی

سیستم عامل ما با استفاده زبان C و بهره گیری از کامپایلر GCC نوشته خواهد شد. به این خاطر از C استفاده می کنیم که توسعه سیستم عامل به کنترل بسیار دقیقی برروی کد تولید شده و دسترسی به حافظه نیاز دارد. سایر زبان های که بتوانند این ویژگی ها را ارائه دهند نیز می توانند مورد استفاده قرار گیرند، امّا این کتاب تنها C را پوشش می دهد.
این کد یکی از ویژگی های نوع داده ای است که مخصوص GCC است :

 __attribute__((packed))

این ویژگی به ما اطمینان می دهد که کامپایلر از شکل دقیقی که ما در کدمان برای تعریف یک struct بکار برده ایم تبعیت می کند. این ویژگی را در فصل بعدی با جزئیات بیشتری توضیح خواهیم داد.
به موجب استفاده از این مشخصه، کامپایل کدهای نمونه با استفاده از کامپایلرهای دیگری بجز GCC ممکن است سخت باشد.
برای نوشتن کدهای اسمبلی، ما Nasm را بعنوان اسمبلر انتخاب کرده ایم، به این خاطر که ما نحو دستوری Nasm را به اسمبلر GNU) GAS) ترجیح می دهیم.
زبان اسکریپتی که ما در کل این کتاب از آن بهره می بریم Bash خواهد بود.

۲--     سیستم عامل میزبان

تمام کدهای نمونه با فرض اینکه برروی یک سیستم عامل شبه Unix کامپایل می¬شوند قرار داده شده اند. تمام نمونه کدها به شکلی موفقیت آمیز برروی Ubuntu 6 یعنی نسخه 11.04 و 11.10 کامپایل شده اند.

۲--     ساختن سیستم

برای ساختن نمونه های Makefile از نحو دستوری برنامه Make استفاده شده است.

۲--     ماشین مجازی

در هنگام توسعه سیستم عامل بسیار مطلوب است که کدها را بجای یک کامپیوتر فیزیکی برروی یک ماشین مجازی اجرا کنیم، به این دلیل که اگرکار بروی سیستم عاملتان را در ماشین های مجازی آغاز کنید سرعت مشاهده نتایج بسیار بیشتر از شکل اجرای فیزیکی آن خواهد بود و در نتیجه شما پس از اطمینان می توانید آن را برروی ماشین فیزیکی خود اجرا کنید. مقلّد Bochs یک مقلّد برای معماری x86 (یعنی IA-32) است که با داشتن ویژگی های خطایابی یکی از ابزارهای خوب و مناسب جهت توسعه سیستم عامل بشمار می رود. دیگر انتخاب مورد توجه QEMU و Virtual Box هستند. این کتاب از Bochs استفاده می کند.
با استفاده از یک ماشین مجازی ما نمی توانیم اطمینان حاصل کنیم که سیستم عامل مان برروی سخت افزار واقعی نیز کار می کند. محیط های شبیه سازی شده توسط ماشین های مجازی بگونه ای طراحی شده اند که شباهت زیادی با بخش های فیزیکی همتای خود داشته باشند، و سیستم عامل می تواند برروی یکی از آن ها از طریق یک کپی اجرایی برروی یک CD و پیدا کردن ماشین مجازی مناسب آزمایش شود.

۲-۲    بوت کردن

بوت کردن یک سیستم عامل رویه ایست که شامل انتقال کنترل از طریق زنجیره ای از برنامه های کوچک است، هر یک از این برنامه ها قدرتمند تر از قبلی است، حال آنکه سیستم عامل آخرین برنامه می باشد. مشاهده ی شکل زیر مثالی از یک فرآیند بوت می باشد:
 

رسم توضیحی 1: مثالی از پروسه بوت شدن سیستم. هر جعبه یک برنامه می باشد.


۲بایاس

زمانی که PC روشن شود، کامپیوتر برنامه کوچکی را که خلاصه ی عبارت سیستم ورودی خروجی پایه  (BIOS) استاندارد است اجرا می کند. این برنامه معمولاً برروی یک تراشه فقط خواندنی برروی برد اصلی PC ذخیره شده است. نقش اصلی برنامه BIOS این بود که برخی از توابع را برای چاپ کردن برروی صفحه، خواندن از صفحه کلید و ... ارائه دهد. سیستم عامل های مدرن از توابع BIOS استفاده نمی کنند، آن ها از راه اندازهایی(Driver) که بشکل مستقیم با سخت افزار ارتباط برقرار می کنند بهره می برند و از BIOS گذر می کنند. امروزه، BIOS اصولاً برای اجرای چند خطایابی اولیه (خود آزمون زمان روشن شدن ) و انتقال کنترل به بوت لودر استفاده می شوند.

۲۲     بوت لودر

برنامه برنامه BIOS کنترل PC را به برنامه ای که Bootloader نام دارد منتقل می کند. وظیفه Bootloader این است که کنترل را به ما، یعنی توسعه دهندگان سیستم عامل، و کد ما منتقل کند. بهرروی، به سبب برخی از محدودیت های سخت افزاری بدلیل سازگاری با سیستم های پیشین، بوت لودر اغلب به دو قسمت تقسیم می شود: بخش اول بوت لودر که کنترل را به بخش دوم منتقل می کند، و این بخش نهایتاً کنترل کامپیوتر را به سیستم عامل می دهد.
نوشتن بوت لودر درگیر نوشتن بسیاری از کدهای سطح پائین است که بتوانند با BIOS ارتباط برقرار کنند. بنابراین از یک Bootloader آماده استفاده شده است : بوت لودر GRUB .
با استفاده از GRUB سیستم عامل می تواند بمانند یک فایل اجرایی ELF ساخته شود، در نتیجه این فایل توسط GRUB در جای مناسبی از محل های حافظه بارگذاری خواهد شد. کامپایل کردن هسته مستلزم کدهای قرار گرفته به شکلی مشخص، در حافظه می باشد (چگونگی کامپایل کردن هسته در فصل بعدی بحث خواهد شد).

۲    سیستم عامل

GRUB کنترل را از طیق پرش به محلی از حافظه به سیستم عامل منتقل می کند. قبل از پرش، GRUB به دنبال یک عدد طلایی جهت حصول اطمینان از اینکه به یک سیستم عامل واقعی پرش می کند (نه یک کد تصادفی) می گردد. این عدد تصادفی بخشی از مشخصات multiboot است که GRUB به آن وفادار می باشد. به محض اینکه GRUB پرش را انجام داد، سیستم عامل کنترل کامل سیستم را در دست می گیرد.

۲-     سلام به قهوه سرای کودکان

این بخش نحوه پیاده سازی کوچکترین سیستم عاملی را که می تواند با GRUB استفاده شود را شرح می دهد. تنها کاری که سیستم عامل انجام می دهد این است که عبارت 0xCAFEBABE (همان قهوه سرای کودکان) را در ثبات eax بنویسد (اکثر برنامه نویسان این را حتی یک سیستم عامل نمی دانند).

۲--کامپایل کردن سیستم عامل

این بخش سیستم عامل باید با کدهای اسمبلی نوشته شود، زیرا C به یک پشته نیاز دارد که موجود نیست (فصل ورود به C نحوه راه اندازی یکی از آن ها را توضیح می دهد). کدهای زیر را در فایلی به نام Loader.s ذخیره کنید :


global loader                   ; the entry symbol for ELF
MAGIC_NUMBER equ 0x1BADB002     ; define the magic number constant
FLAGS        equ 0x0            ; multiboot flags
CHECKSUM     equ -MAGIC_NUMBER  ; calculate the checksum
                                ; (magic number + checksum + flags should equal 0)

section .text:                  ; start of the text (code) section
align 4                         ; the code must be 4 byte aligned
     dd MAGIC_NUMBER             ; write the magic number to the machine code,
     dd FLAGS                    ; the flags,
    dd CHECKSUM                 ; and the checksum

loader:                         ; the loader label (defined as entry point in linker script)
     mov eax, 0xCAFEBABE         ; place the number 0xCAFEBABE in the register eax
.loop:
     jmp .loop                   ; loop forever

تنها کاری که این سیستم عامل انجام می دهد این است که عدد کاملاً مشخص 0xCAFEBABE را در ثبات eax ذخیره می کند. خیلی بعید است که عدد 0xCAFEBABE پیش از آنکه سیستم عامل آن را در ثبات eax قرار دهد در آن قرار گرفته باشد.
فایل Loader.s می تواند از طریق کد زیر به یک فایل Object 32بیتی در قالب ELF کامپایل بشود :

    nasm -f elf32 loader.s

۲--۲     پیوند دادن هسته

حال می بایست کد به منظور تولید یک فایل اجرایی پیوند داده شود، که انجاک این کار نیازمند اطلاعات اضافی است که در مقایسه با عمل پیوند دادن اغلب برنامه ها مورد نیاز است. می خواهیم که GRUB هسته ما را در آدرسی بزرگتر یا مساوی با 0x00100000 (یعنی 1 مگابایت) بارگذاری کند، زیرا آدرس های کمتر از 1 مگابایت توسط خود GRUB و دستگاه های ورودی خروجی نگاشت شده در حافظه اشغال شده اند. در نتیجه، اسکریپت پیوند زیر نیاز است (برای پیوند دهنده LD GNU نوشته شده) :


ENTRY(loader)                /* the name of the entry label */

SECTIONS {
    . = 0x00100000;          /* the code should be loaded at 1 MB */

    .text ALIGN (0x1000) :   /* align at 4 KB */
    {
        *(.text)             /* all text sections from all files */
    }

    .rodata ALIGN (0x1000) : /* align at 4 KB */
    {
        *(.rodata*)          /* all read-only data sections from all files */
    }

    .data ALIGN (0x1000) :   /* align at 4 KB */
    {
        *(.data)             /* all data sections from all files */
    }

    .bss ALIGN (0x1000) :    /* align at 4 KB */
    {
        *(COMMON)            /* all COMMON sections from all files */
        *(.bss)              /* all bss sections from all files */
    }
}

اسکریپت پیوند دهنده را در فایلی با نام link.ld ذخیره کنید. حال فایل اجرایی می تواند با دستور زیر پیوند داده شود :

    ld -T link.ld -melf_i386 loader.o -o kernel.elf

فایل اجرایی نهایی kernel.elf نامیده می شود.

۲--     بدست آوردن GRUB

نسخه ای از GRUB که ما از آن استفاده می کنیم نسخه legacy یا میراث قدیمی GRUB است، زیرا تصویر فایل ISO سیستم عامل می تواند با استفاده از نسخه legacy یا نسخه شماره 2 نرم افزار GRUB تولید شود. به طور مشخص تری بوت لودر GRUB Legacy با نام stage2_eltorito مورد استفاده قرار می گیرد. این فایل می تواند از طریق GRUB نسخه 0.97 و بعد از دانلود کد منبع آن از آدرس زیر تولید شود :

ftp://alpha.gnu.org/gnu/grub/grub-0.97.tar.gz

بهرروی اسکریپت Configure آن با Ubuntu خوب کار نمی کند، پس فایل دودویی آن را می توانید از آدرس زیر دانلود کنید :

http://littleosbook.github.com/files/stage2_eltorito

این فایل را در پوشه ای که فایل های Loader.s و link.ld را قرار داده اید جای دهید.

۲--     ساختن یک تصویر ISO

فایل اجرایی باید در رسانه ای قرار گیرد که بتواند توسط یک ماشین مجازی یا حقیقی بارگذاری شود. در این کتاب ما از فایل تصویر ISO بعنوان رسانه بهره می بریم، اما یکی از راه های دیگر استفاده از تصاویر Floppy است، بسته به آنکه ماشین مجازی یا حقیق شما کدامیک را پشتیبانی می کند.
تصویر iso هسته را با برنامه genisoimage می سازیم. یک پوشه برای آنچه که در تصویر iso وجود خواهد داشت باید ایجاد شود. دستور زیر پوشه مدنظر را ایجاد می کند و فایل ها را در محل مناسب نسخه برداری می کند :

    mkdir -p iso/boot/grub              # create the folder structure
    cp stage2_eltorito iso/boot/grub/   # copy the bootloader
    cp kernel.elf iso/boot/             # copy the kernel

یک فایل پیکربندی به نام menu.lst باید برای GRUB ایجاد شود. این فایل به GRUB می گوید که هسته در کجا قرار گرفته است و برخی از گزینه ها را پیکربندی می کند :

    default=0
    timeout=0

    title os
    kernel /boot/kernel.elf

فایل menu.lst را در پوشه iso/boot/grub قرار دهید. حال محتوای پوشه iso  باید شکلی بمانند زیر داشته باشند :

    iso
    |-- boot
      |-- grub
      | |-- menu.lst
      | |-- stage2_eltorito
      |-- kernel.elf

تصویر iso می تواند از طریق دستورات زیر تولید شود :

    genisoimage -R                              \
                -b boot/grub/stage2_eltorito    \
                -no-emul-boot                   \
                -boot-load-size 4               \
                -A os                           \
                -input-charset utf8             \
                -quiet                          \
                -boot-info-table                \
                -o os.iso                       \
                iso

برای کسب اطلاعات بیشتر در ارتباط با پرچم¬های استفاده شده در دستور به راهنماهای (manual) برنامه genisoimage مراجعه کنید.
تصویر ISO با نام os.iso در حال حاضر شامل هسته اجرایی، بوت لودر GRUB و فایل پیکر بندی می باشد.

۲--     اجرای Bochs

حال ما می توایم سیستم عامل را با استفاده از تصویر iso فایل os.iso در مقلّد Bochs اجرا کنیم. مقلّد bochs به یک فایل پیکربندی به جهت شروع نیاز دارد و نمونه ای از فایل پیکر بندی در زیر قرار گرفته شده است:

    megs:            32
    display_library: sdl
    romimage:        file=/usr/share/bochs/BIOS-bochs-latest
    vgaromimage:     file=/usr/share/bochs/VGABIOS-lgpl-latest
    ata0-master:     type=cdrom, path=os.iso, status=inserted
    boot:            cdrom
    log:             bochslog.txt
    clock:           sync=realtime, time0=local
    cpu:             count=1, ips=1000000

ممکن است شما نیاز داشته باشید که مسیر romimage و vgaromimage را بسته به نحوه نصب bochs تغییر دهید. برای کسب اطلاعات بیشتر درباره فایل پیکربندی bochs می توانید به تارنمای Bochs مراجعه کنید.
اگر فایل پیکربندی را با نام bochsrc.txt ذخیره کرده اید می توانید با استفاده از دستور زیر bochs را اجرا کنید:

    bochs -f bochsrc.txt -q

پرچم f- به bochs می گوید که از فایل پیکربندی استفاده کند و پرچم q- به bochs می گوید که از نمایش منوی شروع تعاملی صرف نظر کند. در این زمان شما باید شروع کار bochs و نمایش کنسولی با اندکی اطلاعات از GRUB در آن را ببینید.
بعد از خاتمه ی اجرای bochs، فایل رخداد نگار تولید شده توسط bochs را نمایش دهید :

    cat bochslog.txt

حال شما باید محتوای ثبات های پردازنده را که توسط Bochs شبیه سازی شده اند را در جایی از خروجی دستور بالا ببینید. اگر RAX=00000000CAFEBABE یا EAX=CAFEBABE را (بسته به آنکه آیا Bochs را با پشتیبانی 64 بیتی یا بدون آن اجرا کرده اید) در خروجی پیدا کردید پس سیستم عامل شما بدرستی بوت شده است !

۲-    مطالعه های بعدی

گوستاوو دورتس  مقاله ای مفصل درباره آنچه که در کامپیوترهای x86 در زمان بوت شدن اتفاق می افتد نوشته است، برای مطالعه این مقاله به آدرس زیر مراجعه کنید :

http://duartes.org/gustavo/blog/post/how-computers-boot-up

گوستاوو در ادامه مقاله قبلی، مقاله ای در ارتباط با نحوه عملکرد هسته در گام های آغازین نوشته که آن را نیز می توانید در آدرس زیر مطالعه نمائید :

http://duartes.org/gustavo/blog/post/kernel-boot-process

دانشنامه OSDev نیز شامل مقاله ی خوبی در ارتباط با روند بوت شدن در کامپیوترهای x86 قرار داده است که آن را نیز از آدرس زیر می توانید تهیه کنید :

http://wiki.osdev.org/Boot_Sequence



* صفحه بندی این کتاب فصل به فصل انجام شده و در این ارسال افزوده خواهد شد.


نظرات  (۱)

  • مهدی سلیمانی
  • سلام
    خیلی خوشحال شدم وقتی تلاش شما را دیدم و خیلی ناراحت از اینکه ظاهرا یک سال هست که کار را تعطیل کرده اید. به هر حال یکی دو تا از کتابهایی که معرفی کرده اید را دیدم همه از ماشین مجازی استفادده کرده اند. من در ماشین مجازی توانسته ام خروجی بگیرم اما هرکاری کردم در کامبیوتر خودم نشد. فایل بوت لودر را روی سکتور فلابی هم کبی کردم نشد. در سی دی هم رایت کردم نشد. هنگام لود شدن بیغام می دهد که فایل بوت نیست و همینطور می ماند نمی دانم چه کار کنم لطف می کنید اگر راهنمایی ام کنید. خیلی خیلی ممنون می شوم
    ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
    شما میتوانید از این تگهای html استفاده کنید:
    <b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
    تجدید کد امنیتی