وقتی دکمه Power کامپیوتر را فشار میدهیم، اتفاقهای زیادی تقریباً همزمان رخ میدهند. منبع تغذیه فعال میشود، بخشهای مختلف مادربرد برق میگیرند، حافظه و چیپست آماده میشوند و در نهایت پردازنده از حالت Reset خارج میشود.
اما CPU دقیقاً از کجا میفهمد اولین دستور را از کدام قسمت حافظه اجرا کند؟
در این لحظه هنوز Windows، Linux یا DOS وجود ندارد. حتی Bootloader هم هنوز اجرا نشده است. سیستمعامل هنوز هیچ کنترلی روی کامپیوتر ندارد.
با این حال CPU باید از یک نقطه مشخص شروع کند. آن نقطه را Reset Vector مینامیم.
CPU بعد از روشن شدن چه میکند؟
پردازنده برخلاف یک برنامه معمولی نمیتواند بعد از روشن شدن بپرسد: «فایل اجرایی سیستمعامل کجاست؟» CPU در این مرحله حتی مفهوم فایل، پارتیشن یا سیستمعامل را نمیشناسد.
بعد از Reset، تعدادی از رجیسترهای داخلی پردازنده مقادیر از پیش تعیینشدهای میگیرند. این مقادیر باعث میشوند پردازنده اجرای دستور را از یک آدرس مشخص شروع کند.
وقتی پردازنده Reset شد، اجرای کد را از یک نقطه از پیش تعیینشده آغاز کن.
این نقطه همان Reset Vector است.
Reset Vector چیست؟
Reset Vector یک آدرس از پیش تعیینشده است که CPU بعد از Reset اولین دستورهای خود را از آنجا میخواند. در پردازنده 8086 وضعیت اولیه بعد از Reset به صورت زیر است:
CS = FFFFh
IP = 0000h
در Real Mode، آدرس فیزیکی از رابطه زیر محاسبه میشود:
Physical Address = Segment × 16 + Offset
بنابراین:
FFFFh × 10h + 0000h
=
FFFF0h
پس 8086 اجرای خود را از آدرس فیزیکی زیر شروع میکند:
0xFFFF0
یعنی فقط 16 بایت قبل از انتهای فضای آدرسدهی یک مگابایتی.
FFFF:0000 و F000:FFF0 چه تفاوتی دارند؟
اگر قبلاً درباره BIOS مطالعه کرده باشید، احتمالاً دو آدرس زیر را دیدهاید:
FFFF:0000
F000:FFF0
جالب است که هر دو در مدل آدرسدهی Real Mode به یک آدرس فیزیکی میرسند.
FFFF0 + 0000 = FFFF0
F0000 + FFF0 = FFFF0
بنابراین هر دو به آدرس فیزیکی 0xFFFF0 اشاره میکنند.
اما یک نکته مهم وجود دارد: در 8086 وضعیت Reset به صورت FFFF:0000 تعریف شده است.
F000:FFF0 بیشتر هنگام نمایش نقشه حافظه و محل BIOS در PCهای کلاسیک دیده میشود.
پس این دو نمایش را نباید کاملاً یک چیز در نظر گرفت، حتی اگر در Real Mode به یک آدرس فیزیکی یکسان اشاره کنند.
یک مگابایت حافظه چگونه تقسیم میشد؟
برای فهم بهتر محل BIOS، بد نیست نگاهی کوتاه به نقشه حافظه PCهای کلاسیک بیندازیم. در معماری اولیه IBM PC، اولین 640KB از فضای آدرسدهی برای RAM معمولی برنامهها در نظر گرفته شده بود. این قسمت بعدها با نام Conventional Memory شناخته شد.
0x00000
|
| 640 KB Conventional Memory
|
0x9FFFF
بعد از آن، 384KB باقیمانده تا مرز یک مگابایت معمولاً برای سختافزار، Video Memory، ROMها و BIOS استفاده میشد:
0x00000
+-----------------------------+
| |
| Conventional Memory |
| 640 KB |
| |
+-----------------------------+
0xA0000
+-----------------------------+
| Video Memory |
+-----------------------------+
...
+-----------------------------+
| Option ROMs / Hardware ROM |
+-----------------------------+
0xF0000
+-----------------------------+
| |
| BIOS |
| |
| 0xFFFF0 |
| Reset Vector|
+-----------------------------+
0xFFFFF
پس فضای یک مگابایتی اولیه را میتوان خیلی ساده به دو بخش اصلی نگاه کرد:
0 KB → 640 KB Conventional Memory
640 KB → 1024 KB Hardware / Video / ROM / BIOS
این همان دلیل تاریخی معروف شدن عدد 640KB در PCهای قدیمی است. Reset Vector هم دقیقاً در بالاترین قسمت همین فضای آدرسدهی قرار دارد؛ جایی که BIOS در دسترس پردازنده است.
چرا Reset Vector نزدیک انتهای حافظه قرار دارد؟
با توجه به نقشه حافظه بالا، دلیل محل Reset Vector حالا واضحتر میشود. BIOS در بخش بالایی فضای آدرسدهی قرار دارد و CPU بعد از Reset مستقیماً وارد همین قسمت میشود.
CPU لازم نیست بداند BIOS چیست. فقط کاری را انجام میدهد که معماری سختافزار برایش تعیین کرده است:
Fetch instruction from Reset Vector
و کدی که در آن نقطه قرار دارد متعلق به Firmware سیستم است.
مگر فقط 16 بایت برای BIOS باقی نمانده است؟
آدرس 0xFFFF0 فقط 16 بایت قبل از 0x100000 قرار دارد.
واضح است که یک BIOS کامل نمیتواند در 16 بایت جا شود.
در Reset Vector فقط چند دستور کوچک قرار میگیرند که اجرای CPU را به محل اصلی کد Firmware منتقل میکنند.
Reset Vector
|
|
+----> Jump to BIOS initialization code
بنابراین Reset Vector را میتوان بیشتر شبیه در ورودی Firmware در نظر گرفت، نه محلی که کل BIOS در آن قرار دارد.
CPU در این مرحله در چه حالتی کار میکند؟
پردازندههای اولیه x86 بعد از Reset در Real Mode کار میکنند.
در Real Mode آدرسها معمولاً به صورت Segment:Offset نمایش داده میشوند.
مثلاً:
1234:5678
برای پیدا کردن آدرس فیزیکی:
1234h × 10h + 5678h
محاسبه میشود. این روش به پردازندههای اولیه x86 اجازه میدهد با وجود رجیسترهای 16 بیتی، فضایی در حدود یک مگابایت را آدرسدهی کنند.
یکی از نتایج جالب این روش این است که چند ترکیب مختلف Segment و Offset میتوانند به یک آدرس فیزیکی یکسان اشاره کنند؛
همان چیزی که در مثالهای FFFF:0000 و F000:FFF0 دیدیم.
BIOS بعد از گرفتن کنترل چه میکند؟
وقتی اجرای کد Firmware آغاز شد، BIOS باید سیستم را برای مراحل بعدی آماده کند.
Power On
|
v
CPU Reset
|
v
Reset Vector
|
v
BIOS / Firmware
|
v
Hardware Initialization
|
v
POST
|
v
Find Boot Device
|
v
Load Boot Code
BIOS بخشهای مختلف سختافزار را بررسی و مقداردهی اولیه میکند. برای مثال:
- CPU و Chipset
- RAM
- Video hardware
- Keyboard controller
- Storage controllers
- سایر سختافزارهای ضروری
همچنین فرآیندی که معمولاً با نام POST یا Power-On Self-Test شناخته میشود انجام میگیرد. هدف POST این است که Firmware بررسی کند حداقل سختافزار لازم برای ادامه Boot در دسترس است.
هنوز هیچ سیستمعاملی وجود ندارد
یکی از نکات مهم در فهم Boot Process این است که در این مرحله تقریباً همه چیز توسط Firmware انجام میشود. هنوز Windows، Linux، DOS، Bootloader یا Kernel اجرا نشدهاند.
حتی مفاهیمی مثل موارد زیر برای CPU معنی خاصی ندارند:
C:\
/home
.exe
NTFS
ext4
CPU فقط دستور ماشین اجرا میکند. این Firmware است که کمکم محیط لازم را میسازد تا در نهایت کنترل به مرحله بعد منتقل شود.
BIOS چگونه سیستمعامل را پیدا میکند؟
بعد از آمادهسازی اولیه سیستم، Firmware باید یک وسیله قابل Boot پیدا کند. در PCهای کلاسیک این وسیله میتواند مثلاً Floppy Disk، Hard Disk یا CD-ROM باشد.
BIOS سپس قسمت مشخصی از وسیله Boot را میخواند. در دیسکهای قابل Boot کلاسیک، یکی از مهمترین قسمتها اولین Sector دیسک است. این Sector 512 bytes حجم دارد و میتواند شامل اولین کد Boot باشد.
اینجا جایی است که داستان Boot Sector شروع میشود.
یک نکته درباره CPUهای x86 جدیدتر
توضیح FFFF:0000 → 0xFFFF0 برای درک 8086 و معماری PCهای کلاسیک بسیار مفید است،
اما CPUهای جدیدتر x86 جزئیات داخلی متفاوتی دارند.
در پردازندههای مدرن x86، Reset Vector در نزدیکی انتهای فضای آدرسدهی 32 بیتی قرار میگیرد:
0xFFFFFFF0
Firmware و سختافزار سیستم طوری Map میشوند که CPU بتواند کد اولیه Firmware را از این نقطه اجرا کند. بنابراین نباید Reset behavior پردازنده 8086 را بدون تغییر به پردازندههای مدرن تعمیم داد.
CPU بعد از Reset از یک آدرس از پیش تعیینشده شروع به اجرای Firmware میکند.
BIOS و UEFI
در کامپیوترهای مختلف امروزی میتوان هم سیستمهای مبتنی بر Legacy BIOS و هم سیستمهای مبتنی بر UEFI را مشاهده کرد.
UEFI در بسیاری از سیستمهای جدید جایگزین روش سنتی BIOS شده و امکانات بیشتری برای Firmware و Boot فراهم میکند، در حالی که سیستمهای قدیمیتر و برخی محیطهای سازگار همچنان از روش Legacy استفاده میکنند.
جزئیات Boot در UEFI با BIOS کلاسیک تفاوت زیادی دارد، اما ایده پایه همچنان مشابه است:
CPU Reset
|
v
Firmware starts
|
v
Hardware initialization
|
v
Boot process continues
پس تا اینجا چه اتفاقی افتاد؟
Power Button
|
v
CPU receives Reset
|
v
CPU starts from Reset Vector
|
v
Firmware / BIOS gains control
|
v
Hardware is initialized
|
v
POST is performed
|
v
Boot device is selected
|
v
Boot code is loaded
نکته مهم این است که CPU خودش Windows یا Linux را پیدا نمیکند. CPU فقط از نقطهای که معماری سختافزار برایش تعیین کرده شروع به اجرای دستور میکند.
اولین حلقه زنجیره Boot، Firmware است و همه چیز از چند دستور کوچک در Reset Vector آغاز میشود.
قدم بعدی: حافظه در Real Mode چگونه سازماندهی میشود؟
در ادامه این مجموعه میتوانیم دقیقتر به نقشه حافظه PCهای کلاسیک نگاه کنیم:
- 640KB Conventional Memory دقیقاً از کجا آمده است؟
- 384KB بالایی برای چه استفاده میشود؟
- Segment و Offset چگونه یک آدرس فیزیکی میسازند؟
- چرا چند آدرس مختلف میتوانند به یک محل حافظه اشاره کنند؟
- Video Memory و BIOS ROM در کجای حافظه قرار دارند؟
این موضوع قدم منطقی بعدی برای فهم بهتر Boot Process و برنامهنویسی Low-Level در معماری x86 است.