آموزش

طراحی سیستم عامل

طراحی سیستم عامل

طراحی سیستم عامل – قدم به قدم ( محـمد علی ژیـانی )

نوشتن یک سیستم عامل – برای نوشتن یک سیستم عامل به چه چیزی نیاز است ؟
خیلی وقت بود تصمیم گرفته بودم که شروع کنم به یاد گیری ساخت یک سیستم عامل شاید به قدمت 15الی 20 سال ، همیشه فکر میکردم کار من نیست ، نمیشه ، گاو نر میخواد و الی آخر….
همیشه هم همین رابه خودم گفتم که اینقدر طول کشید
این چند وقت کتابهای زیادی در مورد سخت افزار و درک مطلب کارکرد سخت افزاری کامپیوتر خوندم
که سه تا از اصلیها که یه کم فکرم را اصلاح کرد
کتاب کرنل بی درنگ نوشته جین لبروس ( ترجمه فرزاد شکاری زاده ، انتشارات نص بود که مبحث راه اندازی یک سیستم عامل بر روی میکروکنترلرها بود
و دومی کتاب اصول میکروکامپیوترها نوشته علیرضا رضائی انتشارات آیلار)
سومی هم مرجع کامل الکترونیک بود که هی فکر نکنم چرا حالا این کلیده روشن شد (زیادی رفتم از پایه )
الانم دارم اسمبلی برادر جعفر نژاد قمی را میخونم ( اگه وقت کنم )

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

خب این حرفها را که نوشتم مقدمه ای بود بر مقدمه ( این جمله یعنی شروع از قبل از شروع  )

 

اول
زبانهایی که برای نوشتن یک سیستم عامل نیاز هست اسمبلی هست و بعد سی
اسمبلی که پایه ترین زبان هست و برای استارت کار حتما نیاز بهش داریم ، چرا ؟
چون سیستم عامل برای لود شدن نیاز به یک بوت لودر داره ، بوت لودر چیه ؟
بوت لود کدیست که در محلی از هارد دیسک(یا هرچی تو این مایه Cd-rom-Flopy-FlashMemory ) هست که در اولین سکتور این دیوایس نوشته میشه و چه بخواهین چه نخواهین حداکثر حجمی که قابل برنامه نویسی هست فقط 512 بایت هست
در پرانتز : بوت لودر یک امضاء دارد که در فرمت هگز به شکل 55AA نوشته میشه ، یعنی عملا شما بوت لودرتون باید درکمتر از 512 بایت نوشته بشه ( خیلی کم هست ولی خب علت داره ، علتش چیه ؟
وقتی کامپیوتر بوت میشه ، ROM Bios که در واقع اولین کدی هست که اجرا میشه میاد روی دیوایس ها میگرده ببینه که آیا بوت ایبل هست یا نه( همان تنظیمی که توی ستاپ میکنید برای معرفی First Boot) ، و این اتفاق فقط روی 512 بایت اول که در واقع برابر حجم هر سکتور یک فلاپی دیسک هست انجام میشه
پس تا اینجا منظور این بوده که وقتی کامپیوتر ریست میشه ، بایوس میاد و اولین سکتور از هارد را میخونه و میخواد که اجراش کنه ! همین 
(عکس ضمیمه )

پس نیاز داریم که با کامپایلری کار کنیم که اولا 16 بیتی را ساپورت کنه دوما مینیمم حجم را اشغال کنه ، پس از C نمیتونیم استفاده کنیم چون حداقل فایلی که تحویل میده حجمش بیشتر از این حرفاست
ویکی دیگه از دلایل اینه که فایلهای خروجی سی به علت ساختاری که دارند (PE) از همون بایت اول اجرائی نیستند ، و ما در بوت سکتور از همان بایت اول باید دست و آستین بالا بزنیم چون چیزی برای شناختن فرمت فایلها و غیره اصلا وجود نداره.
*** ادیت شد : با سی هم میشه 

خب ممکنه سوال پیش بیاد که چرا همه سیستم عامل را با اسمبلی نمینویسیم ؟ سی یک زبان سطح بالا هست و برنامه نویسی باهاش راحت تره و به علاوه بسیاری از دستورات را به صورت کتابخانه های آماده در اختیارمون میذاره ، پس وقت ، که همون طلاست را بیخودی نباید با نوشتن کدهای اسمبلی هدر بدیم ( البته در نهایت برای طراحی بیس یک سیستم عامل نیاز فراوانی به اسمبلی داریم )
پس اول یک برنامه اسمبلی مینویسم که سیستم اصطلاحا بوت بشود و بعد درونش در واقع یک JUMP میکنیم به محلی که قراره Kernel اصلی سیستم عامل قرار داره برای اجرا به قول معروف Entry Point ، از اینجا به بعد دیگه محدودیتی به نام 512 بایت نداریم دیگه…
( مثلا برای ویندوز ما NTLDR را داریم)
مورد توجه نویسندگان بوت کیت ها 

( خلاصه با هرچیزی میشه نوشت با سی یا بورلند سی یا فری بیسیک یا …..  که میشه برنامه های 32بیتی مستقل نوشت )
(با برنامه هایی که تحت ویندوز الان دارند کارمیکنند و از API ها استفاده میکنند و…اشتباه نشه )

پس در واقع ما برای اینکه یک سیستم عامل 32 بیتی داشته باشیم ، نیاز به مخلوطی از 16 بیتی و 32 بیتی داریم .

خب ما نیاز داریم به دونستن یکسری مطالب پایه مثل اشاره گرها ، آدرس های فضای فیزیکی ،تخصیص حافظه ،و….

در همین حین شما برای اینکه بیکار نمونید ابزارهائی که در آینده نیاز دارید را دانلود کنید
NASM
Pcopy
VFD
Bochs
Visual Studio 2005
C++
HxD Hex Editor
لینک ندادم توضیح هم ندادم که بیکار نمونید ، برگشتم دیدم دانلود نکردین ، خب خودم با ذکر توضیحات آپلود میکنم 😉

 

 

بخش دوم :

 

این قسمت هم یکسری تعاریف اولیه را کامل میکنم و بعد دیگه…… ( حتی ممکنه جائیش را اشتباه بگم ، چاره ای نیست خودمم تازه شروع کردم ،ادعایی نیست ، شما ها هم خودتون کمک کنید تصحیح بشه خطاهای نوشتاری و درک مطلبی و… )

Pointer : یا اشاره گرها ، در واقع کارشون اینه که قسمتی از حافظه را به شما معرفی میکنند و در اختیار شما میگذارند ، چون در حالت معمولی خدا میدونه اطلاعات کجای حافظه سخت افزار PAS قراره ریخته بشه ! پس به واسطه متغییر از جنس اشاره گرها کلی کارمون راه می افته ، البته همونقدر که خوبه ، اگر هم درست آدرس دهی ها تعریف نشه همونقدر این اشاره گرها ممکن هستند گیج بزنند.

کد PHP:
;char* pointer  
PAS چیه؟ Physical Address Space فضای آدرس سخت افزاری ! فکر کنید یه جائی توی ramکامپیوتر هست ( البته حافظه سخت افزاری حتی میتونه این روزها روی کارت گرافیک یا هر دیوایس دیگه هم عنوان بشه ، فعلا کاریش نداریم )
IVT
Interrupt Vector Table یا جدول بردار وقفه ، که هر زمان وقفه ای رخ بده سیستم میاد از این جدول مکانی که آدرس اجرای پروسه مربوط به اون وقفه هست را پیدا میکنه و برای ادامه به اونجا منتقل میشه ( معمولا قبلش از رجیسترهای حافظه یک کپی در پشته میگیره (push کردن) که بعدا توضیح میدم. ( نکته ما یک جدول بردار وقفه سخت افزاری داریم ، و یک جدول وقفه نرم افزاری DOS که مال سیستم عامل داس هست وتوی اکثر کتابهای آموزشی از این جدول داس استفاده کردن که خودش یک سیستم عامل جدا هست برای خودش ، گفتم گیج نشین بعدا” )
مورد بعدی Dynamic Memory Allocation هست یا تخصیص حافظه پویا
که احتمالا قبلا توابع مربوطه را دیدین malloc() – free() – new – delete
کارشون این هست که بلوکی از حافظه را برای شما نگه میدارن ما در سیستم هایی که از پایه نوشته میشن ( سیستم عامل ) با این قضیه استفاده بهینه از حافظه ، تخصیص حافظه ، آزاد کردن حافظه بلا استفاده و اینها خیلی کار داریم. توجه کنید در موقع نوشتن سیستم عامل دستمون اونقدرها هم باز نیست که هر غلطی دلمون خواست بکنیم 
مورد بعدی استفاده از دستورات اسمبلی در دیگرزبانهایی هست که قراره برای توسعه استفاده کنید به قول خودشون ” Inline Assembly “
مثلا در زبان سی وقتی میخواهیم اسمبلی بنویسیم اینطوری شروع میکنیم:
مثال
کد:
_asm cli ; disable interrupts

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

کد:
_asm {
	cli
	hlt
}

خب و مورد بعدی که باید یه توضیحی در مورد بدم RTL هست
Standard Library and the Run Time Library
استفاده از کتابخانه های برنامه نویسی که قبلا آماده شده ، مثلا دیگه نیاز نیست دستور printf() را بشینیم با اسمبلی بازنویسی کنیم ، یک کلمه مینویسیم اسم تابع را میریم پی کارمون
اینطوری میشه گفت حدود 90% از سیستم عامل کذائ که قراره نوشته بشه را از توابع آماده موجود از قبل استفاده میکنیم.

خب و اما یه بحث که یه کم میایم توی عمل ( با اون عمل پای منقل فرق میکنه ، معتادای بی جنبه )
Debug و خطایابی
خب اگه قرار باشه هربار که کدی برای سیستم عامل مینویسیم ، یکبار سیستم را ریست کنیم که نه تنها  سیستم را مورد عنایت قرار میدیم بلکه کلی از وقتمون را هم هدر میدیم
اینجا برای تستها از یه ابزاری به نام Bochs استفاده میکنیم ، یه چیزی شبیه به VMWare هست ولی خب راحت تر و سریعتره…

( از هر نرم افزار دیگه ای هم میتونید استفاده کنید مثلا vpc میکروسافت یا …. هرکی هرچی دوست داره )
ببینم اصلا دانلود کردین اون لیستی که در قسمت بالا نوشتم  ؟

لینک دانلود Bochs : http://Www.ALT.ir/os/Bochs-2.4.5.exe
نرم افزار جالبیه برای تستهای نوشتن یک سیستم عامل ( دلم به حال بیل گیتس اون زمانهایی که این شبیه سازها نبوده میسوزه )
ِ

میکروسافت ویندوز – ورژن 1 به سنه 1985

بخش سوم :

خب بریم برای مباحث شیرین تر 
اصلا سیستم عامل چیه ؟ اینا را چرا مینویسیم؟ هدفمون چیه از داشتن یک به اصطلاح سیستم عامل؟
همه این کارها برای اینه که بتونیم این کامپیوتر دیجیتاله زبون نفهم را یه جوری رامش کنیم که کاربر بتونه باهاش ارتباط برقرار کنه و ازش کار بکشه ( نمونه هم که دیگه نیاز نیست مثال بزنم؟ ویندوز ، لینوکس ، مکینتاش و…. ) این که چرا خودمون میخوایم شروع کنیم به یادگیری هم که تکلیفش معلومه…
سیستم عامل یک نرم افزار نیست ، در واقع مجموعه ای از نرم افزارها هستند در کنار هم
زبانهای رایج برای توسعه سیستم عامل هم معمولا c++ و اسمبلی 80×86 هستند ( معمولا)
البته با زبانهای دیگه هم میشه ولی خب کار سخت تر میشه احتمالا
منابع خارجی برای آموزش سی :
cprogramming.com
Thinking in C++
و…. منبع آموزشی به تعداد موهای سر خودتون توی اینترنت هست ، فت و فراوون.

زبان اسمبلی هم که مناسب ترین زبان هست که میتونه با سخت افزار در پائین ترین سطح ارتباط برقرار کنه هم آموزش زیاد هست ( البته فهمش برای من یکی که همیشه سخت بوده )
مثلا خارجکی ها :
Assembly Language: Step by Step
Art of Assembly
ولی کلا این لینک دومیه جالبه ، یه جورائی گرافیکش را قبلا توی آموزشهای اسمبلی ندیده بودم، حتما ببینید
خب از ابزاری که لازم داریم مهمترینش NASM هست ، یک کامپایلر اسمبلی ،
http://www.nasm.us
هم پیج های دولوپرهاش را هم ببینید ، هرکدومشون ماشالا پروژه های جالبی را اجرا کردند.
نکته اینه که این کامپایلر برای ما ترجیح داره به توربو اسمبلی و میکروسافت اسمبلی _ TASM – MASM به علت اینکه هم 16 بیتی فلت را ساپورت میکنه هم 32 بیتی و هم 64 بیتی !!
به قول خودش :

 

!!!bit-64 (x86-64/x64/AMD64/Intel 64) Support Is Here

البته روی سورس فورج هست و این بی پدر مادرها هم که با ip ایران مشکل دارند
ابزار بعدی که نیاز داریم
Microsoft Visual C++ 2005 or 2008
کد نویسی توی محیط ویژوال ، مورد توجه اون دوستمون 😉
نسخه های جدید را از اینجا : http://www.microsoft.com/express/Downloads میتونید دانلود کنید و نسخه 2005 اون را از اینجا دانلود کنید
البته همچنان محدود به اینها نیستید ، از GCC یا DJGPP یا Mingw یا Pelles یا… هم میتونید استفاده کنید
خودم هم بعضی از این کامپایلرها را برای اولین بار توی عمرم بود که اسمشون را خوندم..!!!
اما به نظر میاد انجین همشون یکی باشه ، قیافه هاشون (IDE )را قشنگ طراحی کردند.
خب یکی دیگه از ابزارهایی که گفتم دانلود کنید و میدونم نکردید “پارت کپی” هست ، کارش چیه؟ کارش کپی کردن فایل بوت لودر هست در اولین سکتور هارد ( یا فلش مموری یا ایمیج یا رم درایو یا …)
خواستید از اینجا میتونید دانلود کنید : http://www.ALT.ir/os/pcopy02.zip
البته ابزارهای دیگه هم برای این کار هستند که بعدا بهشون میرسیم ، اما این حجمی نداره ، 10 کیلوبایت دانلود کنید ضرری نداره 
مثلا از Debug خود ویندوز هم میشه برای کپی کردن اطلاعات روی بوت سکتور استفاده کرد
کد:
C:\>debug boot_loader.bin
-w 100 0 0 1
-q

ابزار بعدی که بهش نیاز داریم ( برای راحتی کار )
VFD – Virtual Floppy Drive
از اینجا دانلود کنید ( بعدا آموزشش را موقع کار مینویسیم ، البته یادگیریش سخت نیست !)
http://www.ALT.ir/os/VFD.zip
برنامه خیلی خوبیه برای ساخت یک فلاپی دیسک مجازی که بوت لودری که بعدا مینویسیم را بتونیم روش رایت کنیم و تستهامون را خیلی سریع بگیریم… همه مدل فرمتی را هم قبول میکنه 
البته یهو دلتون بخواد CD بوت ایبل بسازید ، اونم غمی نداره با MAgicISO میتونید.

به طور خلاصه مراحل استفاده از ابزارهای معرفی شده در بالا این میشه که
1- تنظیمات اولیه لازم برای شروع کار 
شامل ساخت فلاپی مجازیVFD و داشتن یک ماشین مجازی Bochs
2- بوت لودر 
شامل برنامه نویسی به زبان اسمبلی و کامپایلش با NASM و کپی کردن برنامه کامپایل شده روی بوت سکتور مثلا با PartCopy یا Debug یا HxD Hex Editor یا…
3-نوشتن کرنل 
با استفاده از زبانهای سطح بالائی که معرفی شد مثلا c++ یا هرچی دیگه
و کپی فایل نهائی روی فلاپی دیسکت
4- تست کارکرد 
Bochs Emulator را هم که پست قبلی لینک دادم حتما دانلود کنید

بخش چهارم :

برای داشتن یک سیستم عامل در حد قابل قبول نیاز داریم به :
Memory Management – مدیریت حافظه
Program Management – مدیریت برنامه ها
Multitasking – چند وظیفه ای یا اجرای همزمان چند پروسه
Memory Protection – حفاظت از خرابی حافظه
Multiuser – پشتیبانی از یک یا چند اپراتور سیستم
Kernel – هسته اصلی سیستم عامل برای مدیریت بقیه گزینه ها
File System – یک فایل سیستم برای کار کردن با فایلها
Command Shell – رابط خط فرمان
Graphical User Interface – یک محیط گرافیکی جایگزین خط فرمان
Bootloader – و بوت لودر که به زودی میریم سراغش

حتما تاریخچه سیستم عامل ها را میدونید ، اول فقط تک وظیفه ای و خط فرمانی مثل داس بودند ، بعد به صورت مولتی تسک در اومدن و حالا به صورت گرافیکی و و چند هسته ای و و و و …. پس انتظار زیادی از خودمون فعلا نداشته باشیم 

خب امیدوارم تمام مطالب 3 تا پست قبلی را هم خوب خونده باشین( خط به خط ) چون “الف” کار طراحی سیستم عامل و نیازهای ابتدائی بودن …
خب…..
ساده ترین کد که قاطی این بوت لودرهای آموزشی کف اینترنت دیدم اینه و امشب اولین بوت لودر را مینویسم و کامپایل میکنیم و تست و اجرا میکنم.

کد:
 
org		0x7c00				; We are loaded by BIOS at 0x7C00
 
bits	16					; We are still in 16 bit Real Mode
 
Start:
 
	cli					; Clear all Interrupts
	hlt					; halt the system
	
times 510 - ($-$$) db 0				; We have to be 512 bytes. Clear the rest of the bytes with 0
 
dw 0xAA55					; Boot Signiture

خب خطوط نوشته شده هرکدوم چه معنی میدن ؟

کد:
org		0x7c00				; We are loaded by BIOS at 0x7C00
فایلهای com پیش فرض در آدرس 100 هگز بارگذاری میشوند ، ولی به صورت استثنا در بوت لودرها باید به کامپایلر بگیم که فایل در آدرس 0x7C00 قراره اجرا بشه ، چون بایوس و cpu به صورت قراردادی میدونن که برنامه بوت باید از این آدرس شروع بشه و اولین نقطه ای که میره میخونه اینجاست
البته یک روش دیگه هم هست که خب نهایتا به همین جا ختم میشه
کد:
[ORG 0]

            jmp 07C0h:start     ; Goto segment 07C0

    start:
            ; Update the segment registers
خب خط بعدی برنامه چی میگه ؟
کد:
bits	16					; We are still in 16 bit Real Mode
این به کامپایلر میگه این فایلی که قراره تحویلمون بده یک فایل باینتری 16 بیتی هست
تکلیف Start:
هم که مشخصه ، شروع 
کد:
CLI
hlt
CLI به معنی Clear کردن یا پاک کردن تمام اینتراپتهای سخت افزاری هست که ممکنه رخ بده
( از فشار دادن صفحه کلید گرفته تا هر اتفاق سخت افزاری روی تجهیزات کامپیوتر که به مادربرد متصل هستند)
خط بعدی هم سیستم را به حالت Halt میبره ، همون هنگ کردم خودمون ، به معنی توقف سیستم.
کد:
times 510 - ($-$$) db 0
خب گفتیم هر سکتور 512 بایت هست… و 2 باید اون هم 55 AA امضاء بوت سکتور بودن هست
یعنی 510 بایت
پس ما با این دستور میایم فاصله بین کد بوت تا رسیدن به امضاء را با 00 پرمیکنیم ( کامپیوتر در این مرحله شعورش نمیرسه و ممکنه هر دیتایی که اینجا از قبل نوشته شده باشه را بخونه و قصد اجراشون را داشته باشه )
کد:
dw 0xAA55
خط آخر هم امضاء بوت سکتور هست ( اگه این نباشه ، بایوس نبفهمه که این سکتور ( با استفاده از اینتراپت 19 این کار را میکنه )، سکتور بوت هست و فکر میکنه الکی بهش معرفی کردین که این دیوایس یک بوت سکتور داشته )
خب NASM را که لینکش را دادم را نصب کنید و فولدری که نصب شده را پیدا کنید
پیش فرض » Program Files\nasm
یک فایل با پسوند .asm در کنارش بسازید و کد بالا را توش کپی کنید ( مثلا boot1.asm)
و بعد در خط فرمان وارد بشید CMD
کد:
nasm -f bin Boot1.asm -o Boot1.bin

اگه همه چیز درست باشه یک فایل با پسوند .bin برای شما ساخته میشه
خب حالا نرم افزار VFD را اجرا کنید و یک فلاپی مجازی بسازید

خب برنامه PartCopy را هم که لینکش را دادم با این خط دستور اجرا کنید

کد:
partcopy Boot1.bin 0 200 -f1

معنیش چیه ؟
اولین پارامترش اسم فایل هست را در
دومین پارامتر میگه از بایت x شروع کن
تا سومین پارامتر بایت Y ( که اینجا 200 هست و در مبنای دسیمال همون 512 میشه ) در درایور f0 که برابر هست با A: یا f1 که برابر هست با B: کپی کن
خب بعد از این کار میتونید در برنامه VFD فلاپی مجازی که در ram ساختین و تبدیل به بوت هم شده را SAVE کنید و از این بوت ، یک ایمیج بوت ایبل همیشه داشته باشید
خب پس سیوش میکنیم مثلا به اسم test.img
دیگه میتونید VFD را هم ببندید.
خب برنامه Bochs را اجرا کنید ،
طبق عکس جلو برید

 

و بعد هم کلید start 

یه چیزی به این شکل میبینید

 

خب حالا شما اولین بوت لودر خودتون را نوشتید و کامپایل کردید و اجرا هم کردید ( البته الان هیچ غلطی نمیکنه  )
در ادامه روش نوشتن و استفاده از kernel ایشالا…

پیوست : یه بنده خدائی هست که یه سیستم عامل نوشته به اسم آراکس ، مطالب خوبی روی سایت برنامه نویس در این مورد بوت و سیستم عامل منتشر کرده که جا داره تشکر کنم ازش ( هرچند که فکر نمیکنم اینجا آیدی داشته باشه http://osdever.blogfa.com )
پیوست 2: یک لینک برای مطالعه در زمانهای بیکاری 😉 : http://www.nondot.org/sabre/os/articles/ProtectedMode/

 

بخش پنجم :

 

خب امشب میرسیم به سوال قبلی من در اینجا
اینکه یک دیسکت بوت ایبل داریم ولی توی ویندوز که میخوایم بازش کنیم میگه فرمت نشده!
برای این منظور یه چیزی داریم به اسم بلوک OEM که یکسری مشخصات درایو توی اون نوشته شده

کد:
bpbBytesPerSector:  	DW 512
bpbSectorsPerCluster: 	DB 1
bpbReservedSectors: 	DW 1
bpbNumberOfFATs: 	    DB 2
bpbRootEntries: 	    DW 224
bpbTotalSectors: 	    DW 2880
bpbMedia: 	            DB 0xF0
bpbSectorsPerFAT: 	    DW 9
bpbSectorsPerTrack: 	DW 18
bpbHeadsPerCylinder: 	DW 2
bpbHiddenSectors: 	    DD 0
bpbTotalSectorsBig:     DD 0
bsDriveNumber: 	        DB 0
bsUnused: 	            DB 0
b***tBootSignature: 	DB 0x29
bsSerialNumber:	        DD 0xa0a1a2a3
bsVolumeLabel: 	        DB "MOS FLOPPY "
bsFileSystem: 	        DB "FAT12   "
اسامیش تقریبا مشخصه که هرکدوم کارشون چیه
منم کاری به کارشون ندارم و عینا توی برنامه استفاده میکنم به اضافه اینکه امشب میخوایم علاوه بر اینکه بوت شد یه غلط کوچیک هم بکنه ، یعنی نمایش یک کاراکتر بعد از بوت شدن سیستم
کد:
;*********************************************
;	Boot1.asm
;		- A Simple Bootloader
;
;	Operating Systems Development Tutorial
;*********************************************

bits	16							; We are still in 16 bit Real Mode

org		0x7c00						; We are loaded by BIOS at 0x7C00

start:          jmp loader					; jump over OEM block

;*************************************************;
;	OEM Parameter block
;*************************************************;

TIMES 0Bh-$+start DB 0

bpbBytesPerSector:  	DW 512
bpbSectorsPerCluster: 	DB 1
bpbReservedSectors: 	DW 1
bpbNumberOfFATs: 	    DB 2
bpbRootEntries: 	    DW 224
bpbTotalSectors: 	    DW 2880
bpbMedia: 	            DB 0xF0
bpbSectorsPerFAT: 	    DW 9
bpbSectorsPerTrack: 	DW 18
bpbHeadsPerCylinder: 	DW 2
bpbHiddenSectors: 	    DD 0
bpbTotalSectorsBig:     DD 0
bsDriveNumber: 	        DB 0
bsUnused: 	            DB 0
b***tBootSignature: 	DB 0x29
bsSerialNumber:	        DD 0xa0a1a2a3
bsVolumeLabel: 	        DB "MOS FLOPPY "
bsFileSystem: 	        DB "FAT12   "

;*************************************************;
;	Bootloader Entry Point
;*************************************************;

loader:

	cli			; Clear all Interrupts
	hlt			; halt the system
	
times 510 - ($-$$) db 0		; We have to be 512 bytes. Clear the rest of the bytes with 0

dw 0xAA55			; Boot Signiture
خب اگه نگاه کنید میبینید که بلوک OEM وظیفه اجرائی نداره ، پس برنامه باید به محض اجرا از روش بگذره و به بره جائی که اجرائیه
پس یک لیبل به اسم Loader: تعریف میکنیم و کد اجرائی را از اونجا به بعد مینویسم و اول برنامه هم مینویسم :
کد:
start:          jmp loader					; jump over OEM block
JMP هم که توی اسمبلی به معنی خودشه دیگه ، جامپ کن ، بپر …
قبل از بلوک OEM هم یک خط داریم که نوشته
کد:
TIMES 0Bh-$+start DB 0

اینو شما معنیشو بگین که چرا 11 بایت را برابر با 0 قرار میده؟!!!

 

خب برای چاپ یک کاراکتر نیاز به اینتراپت 0x10 داریم
پارامترهای این اینتراپت به این صورت هستند

کد:
AH = 0x0E
AL = Character to write
BH - Page Number (Should be 0)
BL = Foreground color (Graphics Modes Only)
ما اینجا میتونیم دوتای آخری را فاکتور بگیریم 
پس نتیجه میشه :
کد:
	xor	bx, bx		; A faster method of clearing BX to 0
	mov	ah, 0x0e
	mov	al, 'A'
	int	0x10
خط اول مقدار Bx را صفر میکنه
خط دوم مقدار 0x0E را در رجیستر ah قرار میده
خط سوم کاراکتری که میخواهیم چاپ بشه را در رجیستر al قرار میده و با فراخوانی اینتراپت 10 اون را روی صفحه نمایش میدیم
کد نهائی میشه این :
کد:
;*********************************************
;	Boot1.asm
;		- A Simple Bootloader
;
;	Operating Systems Development Tutorial
;*********************************************

bits	16							; We are still in 16 bit Real Mode

org		0x7c00						; We are loaded by BIOS at 0x7C00

start:          jmp loader					; jump over OEM block

;*************************************************;
;	OEM Parameter block
;*************************************************;

TIMES 0Bh-$+start DB 0

bpbBytesPerSector:  	DW 512
bpbSectorsPerCluster: 	DB 1
bpbReservedSectors: 	DW 1
bpbNumberOfFATs: 	    DB 2
bpbRootEntries: 	    DW 224
bpbTotalSectors: 	    DW 2880
bpbMedia: 	            DB 0xF0
bpbSectorsPerFAT: 	    DW 9
bpbSectorsPerTrack: 	DW 18
bpbHeadsPerCylinder: 	DW 2
bpbHiddenSectors: 	    DD 0
bpbTotalSectorsBig:     DD 0
bsDriveNumber: 	        DB 0
bsUnused: 	            DB 0
b***tBootSignature: 	DB 0x29
bsSerialNumber:	        DD 0xa0a1a2a3
bsVolumeLabel: 	        DB "MOS FLOPPY "
bsFileSystem: 	        DB "FAT12   "

;*************************************************;
;	Bootloader Entry Point
;*************************************************;

loader:

	cli			; Clear all Interrupts

	xor	bx, bx		; A faster method of clearing BX to 0
	mov	ah, 0x0e
	mov	al, 'J'
	int	0x10

	hlt			; halt the system
	
times 510 - ($-$$) db 0		; We have to be 512 bytes. Clear the rest of the bytes with 0

dw 0xAA55			; Boot Signiture

خب کامپایلش کنید و با دستور partcopy اون را روی فلاپی مجازی بریزید و ازش یک سیو بگیرید و با یک شبیه ساز که اینجا Bochs هست اجراش کنید
از vmware میتونید استفاده کنید
از فلاپی واقعی میتونید استفاده کنید
حتی میتونید فلش مموری خودتون را هم به این صورت ویرایش کنید و اون را بوت ایبل کنید و با تنظیم دیسک بوت در Setup کامپیوترتون به صورت واقعی یک تست بگرید

 

بخش ششم :

خب فقط الان یه توضیح کوتاه بدم در مورد چاپ رشته ها ( قاطی این آموزشها بود گفتم منم بنویسمشون)
توی زبان استمبلی !( اسمبلی سابق) رشته ها را به این صورت تعریف میکنند :

کد:
msg	db	"Welcome to My Operating System!", 0
و برای چاپ رشته میتونیم به این روش عمل کنیم
کد:
;***************************************
;	Prints a string
;	DS=>SI: 0 terminated string
;***************************************

Print:
			lodsb
			or			al, al				; al=current character
			jz			PrintDone			; null terminator found
			mov			ah,	0eh			; get next character
			int			10h
			jmp			Print
PrintDone:
			ret
دستور lodsb کارش اینه که :

LODSB Load byte at address DS:(E)SI into AL

پس ما باید بنویسیم :
کد:
	mov	si, msg
	call	Print
یک مثال کامل :
کد:
;*********************************************
;	Boot1.asm
;		- A Simple Bootloader
;
;	Operating Systems Development Tutorial
;*********************************************

bits	16							; We are still in 16 bit Real Mode

org		0x7c00						; We are loaded by BIOS at 0x7C00

start:          jmp loader					; jump over OEM block

;*************************************************;
;	OEM Parameter block
;*************************************************;

; Error Fix 2 - Removing the ugly TIMES directive -------------------------------------

;;	TIMES 0Bh-$+start DB 0					; The OEM Parameter Block is exactally 3 bytes
								; from where we are loaded at. This fills in those
								; 3 bytes, along with 8 more. Why?

bpbOEM			db "My OS   "				; This member must be exactally 8 bytes. It is just
								; the name of your OS 🙂 Everything else remains the same.

bpbBytesPerSector:  	DW 512
bpbSectorsPerCluster: 	DB 1
bpbReservedSectors: 	DW 1
bpbNumberOfFATs: 	    DB 2
bpbRootEntries: 	    DW 224

 

 

 

یه کم توضیحات.

حلقه ها یا Ring
سیستم های نرم افزاری از چند حلقه تشکیل شده اند Ring0 که پائینترین سطح را داره ( سیستم عامل اینجاست ) و حلقه 2 و 3 که حلقه 3 یا rin3 سطحیه که کاربر توی اون قرار داره

حلقه صفر بیشترین دسترسی به سیستم و همینطور دسترسی کم میشه تا برسه به سطح کاربر
سیستم عامل قاعدتا باید بیشترین سطح دسترسی را به سیستم داشته باشه ، پس قاعدتا در حلقه صفر باید باشه
تنها مرحله ای که ما نهایت محدودیت را داریم مرحله اول یا هموان بوت لودر هست که فضائی در حد 512 بایت داریم ( موجود در اولین سکتور دیسک ( سکتورصفر)) ، نه بیشتر و اسمبلی و زبانی که توش ساپورت میشه اسمبلی 16 بیتی هست ، پس برای رسیدن به یک سیستم عامل 32 بیتی باید یه نرم افزار واسط بنویسم (همان کرنل) یا مرحله دوم ( stage 2 )
بعضی جاها خودشون را راحت کردند ، بهش گفتن بوت لودر دو مرحله ای 
پس ما برای اینکه به بقیه فضای دیسک بتونیم دسترسی داشته باشیم باید بتونیم بقیه سکتورها را بخونیم.
خب پس ما نیاز داریم به وقفه ( اینتراپت ) ای که بتونه بره و دیسکت را بخونه و اطلاعاتشو به ما برگردونه این وقفه شماره 13 هست ( INT13 )
پس اول باید دیسک را ریست کنیم ، چون نمیدونیم که موقع شروع ، سخت افزار دقیقاکجا بوده
قبلا

کد:
.Reset:
	mov		ah, 0					; reset floppy disk function
	mov		dl, 0					; drive 0 is floppy drive
	int		0x13					; call BIOS
	jc		.Reset					; If Carry Flag (CF) is set, there was an error. Try resetting again

INT 0x13/AH=0x0 – DISK : RESET DISK SYSTEM
AH = 0x0
DL = Drive to Reset

Returns:
AH = Status Code
CF (Carry Flag) is clear if success, it is set if failure

پس با این کد ما عملا هد خواندن از دیسک را میاریم در نقطه صفر قرار میدیم میکنیم. به عنوان یک نقطه مبنا و مبداءشروع.
پس تا اینجا شد وقفه 13 با پارامتر Ah = 0 ( این یعنی ریست و اومدن به نقطه 0 واقعی )
خب برای خوندن سکتورها یک فانکشن یا پارامتر دیگه که به این وقفه 13 بدیم ، زحمت خوندن سکتورها انجام میشه

BIOS Interrupt (INT) 0x13 Function 0x02 – Reading Sectors

INT 0x13/AH=0x02 – DISK : READ SECTOR(S) INTO MEMORY
AH = 0x02
AL = Number of sectors to read
CH = Low eight bits of cylinder number
CL = Sector Number (Bits 0-5). Bits 6-7 are for hard disks only
DH = Head Number
DL = Drive Number (Bit 7 set for hard disks)
ES:BX = Buffer to read sectors to

Returns:
AH = Status Code
AL = Number of sectors read
CF = set if failure, cleared is successfull

خب این
سیلندر چیه ؟ کلا هد چیه ؟ سکتور چیه ؟
شکل زیر را برای درک بهتر مسئله ببینید:

 

 

هر Track معمولا به 512 قسمت تقسیم شده
نکته : یک فلاپی دیسکت دارای 2 هد بیشتر نیست .
اگه مقادیری زیادتر از حد بهش بدیم ، سیستم نبفهمه و قاط میزنه 
این از قسمتی مربوط به CH = Low eight bits of cylinder number

در موردDH = Head Number هم با اینکه فلاپی دوتا هد داره ولی همیشه باید از هد شماره 0 استفاده بکنیم.

در مورد DL = Drive Number (Bit 7 set for hard disks
شماره درایوی هست که میخواهیم باهاش کار کنیم ، شماره 0 همیشه فلاپی یا همون A: هست
شماره 1 معمولا به 5-1/4″ Floppy drives. گفته میشه که الان دیگه جزو عتیقه جاته ولی خب هنوز توسط کامپیوترها به صورت یک سنت قدیمی ساپورت میشه 

یک کد مثال :

کد:
Reset:
	mov		ah, 0					; reset floppy disk function
	mov		dl, 0					; drive 0 is floppy drive
	int		0x13					; call BIOS
	jc		.Reset					; If Carry Flag (CF) is set, there was an error. Try resetting again
 
	mov		ax, 0x1000				; we are going to read sector to into address 0x1000:0
	mov		es, ax
	xor		bx, bx
 
.Read:
	mov		ah, 0x02				; function 2
	mov		al, 1					; read 1 sector
	mov		ch, 1					; we are reading the second sector past us, so its still on track 1
	mov		cl, 2					; sector to read (The second sector)
	mov		dh, 0					; head number
	mov		dl, 0					; drive number. Remember Drive 0 is floppy drive.
	int		0x13					; call BIOS - Read the sector
	jc		.Read					; Error, so try again
 
	jmp		0x1000:0x0				; jump to execute the sector!
این کد کارش اینه که ، فلاپی را ریست کنه و فقط یک سکتور را بخونه ( سکتور شماره 2)
قبلش یک مروری داشته باشیم بر روی بلوک OEM که در واقع راهنمای ما هست در خواندن سکتورها .
کد:
bpbBytesPerSector:  	DW 512
bpbSectorsPerCluster: 	DB 1
bpbReservedSectors: 	DW 1
bpbNumberOfFATs: 	    DB 2
bpbRootEntries: 	    DW 224
bpbTotalSectors: 	    DW 2880
bpbMedia: 	            DB 0xF0
bpbSectorsPerFAT: 	    DW 9
bpbSectorsPerTrack: 	DW 18
bpbHeadsPerCylinder: 	DW 2
bpbHiddenSectors: 	    DD 0
bpbTotalSectorsBig:     DD 0
bsDriveNumber: 	        DB 0
bsUnused: 	            DB 0
b***tBootSignature: 	DB 0x29
bsSerialNumber:	        DD 0xa0a1a2a3
bsVolumeLabel: 	        DB "MOS FLOPPY "
bsFileSystem: 	        DB "FAT12   "
……
اطلاعات بالا مربوط به FAT12 هست ( برای اطلاعات بیشتر نسبت به فت 32 و NTFS به سایت میکروسافت میتونید مراجعه کنید و بلوکoem های مربوطه را ببینید)
این دوتا به چه معنی هست ؟
کد:
bpbBytesPerSector:  	DW 512
bpbSectorsPerCluster: 	DB 1
اولی میگه چه تعداد بایت در هر سکتور قرار داره و دومی هم میگه روی هر کلاستر چند سکتور هست
کد:
bpbReservedSectors: 	DW 1
bpbNumberOfFATs: 	    DB 2
اولی را همیشه 1 میزاریم چون ترجمه اش را متوجه نشدم منظورش چیه ، شما معنیشو بنویسید:

A Reserved Sector is the number of sectors not included in FAT12. ie, not part of the Root Directory. In our case, The Bootsector, which contains our bootloader, will not be part of this directory. Because of this, bpbReservedSectors should be 1.

دومی هم نوع فت را مشخص میکنه که برای fat 12 ما عدد 2 را داریم.
کد:
bpbRootEntries: 	    DW 224
bpbTotalSectors: 	    DW 2880
قسمت اول میگه شما میتونید در ریشه، حداکثر 224 تا دایرکتوری داشته باشد
دومی هم حداکثر تعداد سکتورها را مشخص میکنه ( توی فلاپی 2880 تا سکتور داریم )
کد:
bpbMedia: 	            DB 0xF0
bpbSectorsPerFAT: 	    DW 9
قسمت اول توضیحی میده در مورد خواص دیسکتی که داریم باهاش کار میکنیم
کد:
The Media De******or Byte (bpbMedia) is a byte code that contains information about the disk. This byte is a Bit Pattern:

    * Bits 0: Sides/Heads = 0 if it is single sided, 1 if its double sided
    * Bits 1: Size = 0 if it has 9 sectors per FAT, 1 if it has 8.
    * Bits 2: Density = 0 if it has 80 tracks, 1 if it is 40 tracks.
    * Bits 3: Type = 0 if its a fixed disk (Such as hard drive), 1 if removable (Such as floppy drive)
    * Bits 4 to 7 are unused, and always 1.
اینجا
کد:
bpbSectorsPerTrack: 	DW 18
bpbHeadsPerCylinder: 	DW 2
اگه مطمئن نبودیم که تعداد سیلندر چندتاست ، از همون وقفه 13 برای پیدا کردن این مقادیر میشه استفاده کرد
کد:
bpbHiddenSectors: 	    DD 0
نشون میده از سکتور شماره چند باید شروع کنیم ، ( میتونید چندتا سکتور را ندید بگیرید به این روش ، فکر کنم ، )
کد:
bpbTotalSectorsBig:     DD 0
bsDriveNumber: 	        DB 0
برای فلاپی همیشه صفر 
کد:
bsUnused: 	            DB 0
b***tBootSignature: 	DB 0x29
این ستاره ها هم همون s*E*x هست که فیلتر میشه !
اولی که همیشه صفر هست ، بلا استفاده. و اما دومی امضاء نوع بوت هست که در بایوس مثلا برای 28 و 29 نوع داس تعریف شدن ( به قول خودشون Bios Parameter Block
0x28 and 0x29 indicate this is a MS/PC-DOS version 4.0
اگه مقدار 0x29 داشته باشیم باید مقادیر زیر را هم تعریف کنیم
کد:
bsSerialNumber:	        DD 0xa0a1a2a3
bsVolumeLabel: 	        DB "MOS FLOPPY "
bsFileSystem: 	        DB "FAT12   "
توجه داشته باشین که ولوم لیبل حداکثر 11 کاراکتره و فایل سیستم حداکر 8 کاراکتر
یک مثال : ( ببینم اشکالشو کسی پیدا میکنه ، اصلا کسی هست این نوشته ها را بخونه و همزمان بیاد جلو؟ )
کد:
;*********************************************
;	Boot1.asm
;		- A Simple Bootloader
;
;	Operating Systems Development Tutorial
;*********************************************
 
bits	16							; We are still in 16 bit Real Mode
 
org		0x7c00						; We are loaded by BIOS at 0x7C00
 
start:          jmp loader					; jump over OEM block
 
;*************************************************;
;	OEM Parameter block / BIOS Parameter Block
;*************************************************;
 
TIMES 0Bh-$+start DB 0
 
bpbBytesPerSector:  	DW 512
bpbSectorsPerCluster: 	DB 1
bpbReservedSectors: 	DW 1
bpbNumberOfFATs: 	DB 2
bpbRootEntries: 	DW 224
bpbTotalSectors: 	DW 2880
bpbMedia: 	        DB 0xF0
bpbSectorsPerFAT: 	DW 9
bpbSectorsPerTrack: 	DW 18
bpbHeadsPerCylinder: 	DW 2
bpbHiddenSectors:       DD 0
bpbTotalSectorsBig:     DD 0

نکته:

با وجود سازگاری

NASM تو فایل manual

7.1.1 ORG: Binary File Program Origin

Its sole function is to specify one offset which is added to all internal address references within the section

Double ORG , New Segment Define , 32 bit و … جواب نداد
راه حل منطقی پیدا نشد
این لودر رو پیدا کردم که به روش خودش ( تعریف فایل کرنل ) مشکل رو حل کرده و لودر خوبی هم هست

کد:
;
; Copyright (c) Eike Dehling 2004, all rights reserved
;
; Compile with nasm, write to first sector of a floppy, have fun
;

[BITS 16]
[ORG 0x7c00]

; -------------------------------------
; disk de******ion
; -------------------------------------
	jmp short start	; 3 bytes to e.g. jump
	nop
	db "EikeBoot"	; 8 byte label / OemId
	dw 512		; bytes per sector
	db 1		; sectors per cluster
	dw 1		; size of the bootloader, in sectors
	db 2		; number of copies of the FAT
	dw 224		; number of entries in Root-Dir
	dw 2880 	; 16-bit number of sectors
	db 0xf0		; media de******or
	dw 9		; number of sectors per FAT
	dw 18		; sectors per track
	dw 2		; number of heads
	dd 0		; number of hidden sectors
	dd 0		; 32-bit number of sectors
	db 0		; bios drive number
	db 0		; reserved
	db 0x29 	; extended boot signature
	dd 0		; volume ID
	db "NO NAME    "; volume label
	db "FAT12   "	; filesystem type

; -------------------------------------
; bootloader code
; -------------------------------------
print_io_error_trampoline:
	jmp print_io_error	; out of range crap 🙁

start:
	; set segments, bios may set 0x07c0:0x0000 or 0x0000:0x7c00
	jmp 0:start2
start2: mov ax, 0
	mov ds, ax
	mov es, ax
	mov ss, ax
	mov sp, 0x7000

	; save boot device
	mov byte [bootdev], dl
	
	; reset disks 
	mov ah, 0
	mov dl, byte [bootdev]
	int 0x13

	; load FAT
	mov ah, 0x02			; read from disk
	mov al, 9			; number of sectors to read
	mov bx, fatbuf			; es: bx = buffer
	mov ch, 0			; track ((1 / 18) / 2)
	mov cl, 2			; sector (1 % 18 + 1)
	mov dh, 0			; head ((1 / 18) % 2)
	mov dl, byte [bootdev]		; dl = device, but that's still correct
	int 0x13
	jc print_io_error_trampoline

	; load root directory
	mov ah, 0x02			; read from disk
	mov al, 14			; number of sectors to read
	mov bx, rootdir			; es: bx = buffer
	mov ch, 0			; track ((19 / 18) / 2)
	mov cl, 2			; sector (19 % 18 + 1)
	mov dh, 1			; head ((19 / 18) % 2)
	mov dl, byte [bootdev]		; dl = device, but that's still correct
	int 0x13
	jc print_io_error_trampoline
	
	; find file
	mov ax, rootdir			; ax = pointer to current dir-entry
	cld

find_start:
	mov si, ax			; point si to current filename
	mov di, filename		; point di to the filename we need
	mov cx, 11			; compare max 11 bytes

	repe cmpsb
	je found_file
	
	add ax, 32			; done yet?
	cmp ax, rootdir_end
	jne find_start

	; print error and halt
	mov si, file_not_found
	call print
	jmp $

found_file:
	; save cluster
	mov si, ax
	mov ax, word [si + 26]		; load cluster of file from the directory entry
	mov word [cluster], ax

	; decode FAT
	mov cx, 512*(9/3)		; number of entries in the fat.
	mov si, fatbuf
	mov di, fatdecoded

	;
	; XXX - WATCH OUT, THIS REALLY NEEDS TO USE EAX, EBX & CO!!!
	;
fat_decode_loop:		; load dword, split into two pieces of 12 bits, and discard last byte
	lodsd				; load dword
	dec si				; need only 3 bytes
	mov ebx, eax
	and eax, 0xFFF			; mask
	stosw
	mov eax, ebx
	shr eax, 12			
	and eax, 0xFFF			; shift & mask
	stosw
	loop fat_decode_loop
	
	; load file:
	;	es:bx = buffer
	;	ds:si = decoded fat buffer
	;	rest is for temporary usage only	
	
	; prepare buffer
	mov ax, 0x1000
	mov es, ax
	mov bx, 0
	mov ax, word [cluster]

load_loop:
	; calculate next cluster
	mov si, ax
	shl si, 1
	mov cx, word [fatdecoded + si]
	mov word [cluster], cx
	
	; calculate track, head and sector
	add ax, 31			; ax = logical sector
	mov dx, 0
	mov di, 18
	div di
	mov cl, dl
	add cl, 1			; cl = sector = (logical % 18 + 1)
	mov dx, 0
	mov di, 2
	div di
	mov ch, al			; ch = track = ((logical / 18) / 2)
	mov dh, dl			; dh = head = ((logical / 18) % 2)

	; read data
	mov ah, 0x02
	mov al, 1
	mov dl, byte [bootdev]
	int 0x13
	jc print_io_error
	add bx, 512

	; done?
	mov ax, word [cluster]
	cmp ax, 0xFF8
	jb load_loop

	; DEBUG: print loaded file && halt
	;mov si, 0
	;mov di, 0
	;mov ax, 0x1000
	;mov ds, ax
	;mov ax, 0xb800
	;mov es, ax
	;mov cx, 2000
	;mov al, ' '
	;print_file_loop:
	;movsb
	;stosb
	;loop print_file_loop
	;jmp $

	; execute file?
	; jmp 0x1000:0x0000
	; jmp $

	; disable interrupts
	cli

	; load our GDT
	lgdt [gdt]
	
	; enable protected mode  ...
	mov eax, cr0
	or eax, 1
	mov cr0, eax
	jmp 0x08 : dword cs_flush	; jump into 32-bit

[BITS 32]
cs_flush:

	; setup segements
	mov eax, 0x10
	mov ds, eax
	mov es, eax
	mov ss, eax
	mov fs, eax
	mov gs, eax

	; make stack-register p-mode compliant
	shl esp, 4

	; clear flags
	push dword 0
	popf

	; Execute loaded file ...
	jmp 0x10000

[BITS 16]
; -------------------------------------
; procedures
; -------------------------------------

print_io_error:
	mov si, io_error
	call print
	jmp $

	; print zero-terminated string (without formatting)
	;	ds:si = string
	;	es:di = position on screen
print:
	mov ax, 0xb886
	mov es, ax
	mov di, 0
print_loop:
	lodsw
	cmp al, 0
	jz print_done
	stosw
	jmp print_loop
print_done:
	ret

; -------------------------------------
; data & variables (not in a separate section, cause that makes padding to the
; 	512 byte border easier)
; -------------------------------------

	; filename
	filename: db "KERNEL  BIN"

	; messages
	io_error:		db "I / O   e r r o r ", 0
	file_not_found:	db "[   O S   K e r n e l   n o t   f o u n d   ] ", 0
	executing:		db "E x e c u t i n g . . . ", 0

gdt:
	dw (gdtend - gdt)
	dd gdt
	dw 0						; first entry is our gdt-pointer
	dd 0x0000ffff, 0x00cf9a00	; second entry: code
	dd 0x0000ffff, 0x00cf9200	; third entry: data
	gdtend:						; end

	; boot signature
;	resb 510 - ($ - $$) ; align at 512 bytes
	times 510 - ($ - $$) db 0 ; align at 512 bytes
	dw 0xAA55

; -------------------------------------
; BSS data (starts at 0x8000, that leaves 32k space in the first 64k segment)
; -------------------------------------

[ABSOLUTE 0x8000]
	
	; boot device
	bootdev: resb 1
	
	; first cluster of the file we need
	cluster: resw 1
	
	; FAT buffer
	fatbuf: resb 9 * 512

	; root directory
	rootdir: resb 224 * 32
	rootdir_end:

	; buffer for decoding the FAT
	fatdecoded: resb (9 * 512 * 3) / 2

تست شده و کاملا کار میکنه

این هم برای پیگیری بیشتر تصحیح مورد بالا
http://forum.osdev.org/viewtopic.php?f=1&t=15497

بخش هفتم :

هرچی میخوام این مطالب که چطوری محاسبه میشه و بوت لودر میاد هارد را سکتور به سکتور میخونه را بنویسم میبینم هم خودم کم فهمیدم هم مطالبش خیلی گنگه برام اینه که کلا بیخیال و یه پله را جا میندازیم میریم یه پله بعد و مستقیم یک لودر را تشریح میکنیم که عملا پله قبلی را توی دل خودش داره

کد:
;*********************************************
;	Boot1.asm
;		- A Simple Bootloader
;
;	Operating Systems Development Series
;*********************************************

bits	16						; we are in 16 bit real mode

org	0						; we will set regisers later

start:	jmp	main					; jump to start of bootloader

;*********************************************
;	BIOS Parameter Block
;*********************************************

; BPB Begins 3 bytes from start. We do a far jump, which is 3 bytes in size.
; If you use a short jump, add a "nop" after it to offset the 3rd byte.

bpbOEM			db "My OS   "			; OEM identifier (Cannot exceed 8 bytes!)
bpbBytesPerSector:  	DW 512
bpbSectorsPerCluster: 	DB 1
bpbReservedSectors: 	DW 1
bpbNumberOfFATs: 	DB 2
bpbRootEntries: 	DW 224
bpbTotalSectors: 	DW 2880
bpbMedia: 		DB 0xf8  ;; 0xF1
bpbSectorsPerFAT: 	DW 9
bpbSectorsPerTrack: 	DW 18
bpbHeadsPerCylinder: 	DW 2
bpbHiddenSectors: 	DD 0
bpbTotalSectorsBig:     DD 0
bsDriveNumber: 	        DB 0
bsUnused: 		DB 0
b***tBootSignature: 	DB 0x29
bsSerialNumber:	        DD 0xa0a1a2a3
bsVolumeLabel: 	        DB "MOS FLOPPY "
bsFileSystem: 	        DB "FAT12   "

;************************************************;
;	Prints a string
;	DS=>SI: 0 terminated string
;************************************************;
Print:
			lodsb				; load next byte from string from SI to AL
			or	al, al			; Does AL=0?
			jz	PrintDone		; Yep, null terminator found-bail out
			mov	ah, 0eh			; Nope-Print the character
			int	10h
			jmp	Print			; Repeat until null terminator found
	PrintDone:
			ret				; we are done, so return

;************************************************;
; Reads a series of sectors
; CX=>Number of sectors to read
; AX=>Starting sector
; ES:BX=>Buffer to read to
;************************************************;

ReadSectors:
     .MAIN
          mov     di, 0x0005                          ; five retries for error
     .SECTORLOOP
          push    ax
          push    bx
          push    cx
          call    LBACHS                              ; convert starting sector to CHS
          mov     ah, 0x02                            ; BIOS read sector
          mov     al, 0x01                            ; read one sector
          mov     ch, BYTE [absoluteTrack]            ; track
          mov     cl, BYTE [absoluteSector]           ; sector
          mov     dh, BYTE [absoluteHead]             ; head
          mov     dl, BYTE [bsDriveNumber]            ; drive
          int     0x13                                ; invoke BIOS
          jnc     .SUCCESS                            ; test for read error
          xor     ax, ax                              ; BIOS reset disk
          int     0x13                                ; invoke BIOS
          dec     di                                  ; decrement error counter
          pop     cx
          pop     bx
          pop     ax
          jnz     .SECTORLOOP                         ; attempt to read again
          int     0x18
     .SUCCESS
          mov     si, msgProgress
          call    Print
          pop     cx
          pop     bx
          pop     ax
          add     bx, WORD [bpbBytesPerSector]        ; queue next buffer
          inc     ax                                  ; queue next sector
          loop    .MAIN                               ; read next sector
          ret

;************************************************;
; Convert CHS to LBA
; LBA = (cluster - 2) * sectors per cluster
;************************************************;

ClusterLBA:
          sub     ax, 0x0002                          ; zero base cluster number
          xor     cx, cx
          mov     cl, BYTE [bpbSectorsPerCluster]     ; convert byte to word
          mul     cx
          add     ax, WORD [datasector]               ; base data sector
          ret
     
;************************************************;
; Convert LBA to CHS
; AX=>LBA Address to convert
;
; absolute sector = (logical sector / sectors per track) + 1
; absolute head   = (logical sector / sectors per track) MOD number of heads
; absolute track  = logical sector / (sectors per track * number of heads)
;
;************************************************;

LBACHS:
          xor     dx, dx                              ; prepare dx:ax for operation
          div     WORD [bpbSectorsPerTrack]           ; calculate
          inc     dl                                  ; adjust for sector 0
          mov     BYTE [absoluteSector], dl
          xor     dx, dx                              ; prepare dx:ax for operation
          div     WORD [bpbHeadsPerCylinder]          ; calculate
          mov     BYTE [absoluteHead], dl
          mov     BYTE [absoluteTrack], al
          ret

;*********************************************
;	Bootloader Entry Point
;*********************************************

main:

     ;----------------------------------------------------
     ; code located at 0000:7C00, adjust segment registers
     ;----------------------------------------------------
     
          cli						; disable interrupts
          mov     ax, 0x07C0				; setup registers to point to our segment
          mov     ds, ax
          mov     es, ax
          mov     fs, ax
          mov     gs, ax

     ;----------------------------------------------------
     ; create stack
     ;----------------------------------------------------
     
          mov     ax, 0x0000				; set the stack
          mov     ss, ax
          mov     sp, 0xFFFF
          sti						; restore interrupts

     ;----------------------------------------------------
     ; Display loading message
     ;----------------------------------------------------
     
          mov     si, msgLoading
          call    Print
          
     ;----------------------------------------------------
     ; Load root directory table
     ;----------------------------------------------------

     LOAD_ROOT:
     
     ; compute size of root directory and store in "cx"
     
          xor     cx, cx
          xor     dx, dx
          mov     ax, 0x0020                           ; 32 byte directory entry
          mul     WORD [bpbRootEntries]                ; total size of directory
          div     WORD [bpbBytesPerSector]             ; sectors used by directory
          xchg    ax, cx
          
     ; compute location of root directory and store in "ax"
     
          mov     al, BYTE [bpbNumberOfFATs]            ; number of FATs
          mul     WORD [bpbSectorsPerFAT]               ; sectors used by FATs
          add     ax, WORD [bpbReservedSectors]         ; adjust for bootsector
          mov     WORD [datasector], ax                 ; base of root directory
          add     WORD [datasector], cx
          
     ; read root directory into memory (7C00:0200)
     
          mov     bx, 0x0200                            ; copy root dir above bootcode
          call    ReadSectors

     ;----------------------------------------------------
     ; Find stage 2
     ;----------------------------------------------------

     ; browse root directory for binary image
          mov     cx, WORD [bpbRootEntries]             ; load loop counter
          mov     di, 0x0200                            ; locate first root entry
     .LOOP:
          push    cx
          mov     cx, 0x000B                            ; eleven character name
          mov     si, ImageName                         ; image name to find
          push    di
     rep  cmpsb                                         ; test for entry match
          pop     di
          je      LOAD_FAT
          pop     cx
          add     di, 0x0020                            ; queue next directory entry
          loop    .LOOP
          jmp     FAILURE

     ;----------------------------------------------------
     ; Load FAT
     ;----------------------------------------------------

     LOAD_FAT:
     
     ; save starting cluster of boot image
     
          mov     si, msgCRLF
          call    Print
          mov     dx, WORD [di + 0x001A]
          mov     WORD [cluster], dx                  ; file's first cluster
          
     ; compute size of FAT and store in "cx"
     
          xor     ax, ax
          mov     al, BYTE [bpbNumberOfFATs]          ; number of FATs
          mul     WORD [bpbSectorsPerFAT]             ; sectors used by FATs
          mov     cx, ax

     ; compute location of FAT and store in "ax"

          mov     ax, WORD [bpbReservedSectors]       ; adjust for bootsector
          
     ; read FAT into memory (7C00:0200)

          mov     bx, 0x0200                          ; copy FAT above bootcode
          call    ReadSectors

     ; read image file into memory (0050:0000)
     
          mov     si, msgCRLF
          call    Print
          mov     ax, 0x0050
          mov     es, ax                              ; destination for image
          mov     bx, 0x0000                          ; destination for image
          push    bx

     ;----------------------------------------------------
     ; Load Stage 2
     ;----------------------------------------------------

     LOAD_IMAGE:
     
          mov     ax, WORD [cluster]                  ; cluster to read
          pop     bx                                  ; buffer to read into
          call    ClusterLBA                          ; convert cluster to LBA
          xor     cx, cx
          mov     cl, BYTE [bpbSectorsPerCluster]     ; sectors to read
          call    ReadSectors
          push    bx
          
     ; compute next cluster
     
          mov     ax, WORD [cluster]                  ; identify current cluster
          mov     cx, ax                              ; copy current cluster
          mov     dx, ax                              ; copy current cluster
          shr     dx, 0x0001                          ; divide by two
          add     cx, dx                              ; sum for (3/2)
          mov     bx, 0x0200                          ; location of FAT in memory
          add     bx, cx                              ; index into FAT
          mov     dx, WORD [bx]                       ; read two bytes from FAT
          test    ax, 0x0001
          jnz     .ODD_CLUSTER
          
     .EVEN_CLUSTER:
     
          and     dx, 0000111111111111b               ; take low twelve bits
         jmp     .DONE
         
     .ODD_CLUSTER:
     
          shr     dx, 0x0004                          ; take high twelve bits
          
     .DONE:
     
          mov     WORD [cluster], dx                  ; store new cluster
          cmp     dx, 0x0FF0                          ; test for end of file
          jb      LOAD_IMAGE
          
     DONE:
     
          mov     si, msgCRLF
          call    Print
          push    WORD 0x0050
          push    WORD 0x0000
          retf
          
     FAILURE:
     
          mov     si, msgFailure
          call    Print
          mov     ah, 0x00
          int     0x16                                ; await keypress
          int     0x19                                ; warm boot computer
     
     absoluteSector db 0x00
     absoluteHead   db 0x00
     absoluteTrack  db 0x00
     
     datasector  dw 0x0000
     cluster     dw 0x0000
     ImageName   db "KRNLDR  SYS"
     msgLoading  db 0x0D, 0x0A, "Loading Boot Image ", 0x0D, 0x0A, 0x00
     msgCRLF     db 0x0D, 0x0A, 0x00
     msgProgress db ".", 0x00
     msgFailure  db 0x0D, 0x0A, "ERROR : Press Any Key to Reboot", 0x0A, 0x00
     
          TIMES 510-($-$$) DB 0
          DW 0xAA55
خب تقریبا توی سورس بالا میبینیم که هرکدوم از مقادیر Block OEM کجا استفاده میشن و کمک میکنن به شناسائی سکتورها و کلاسترها
مثلادر خط 63 که داریم ReadSectors:
میبنیدکه چطور بر اساس مقدار تعریف شده هر بایت در یک سکتور با استفاده از loop تمام یک سکتور خونده میشه و مقادیرش استخراج میشه
کد:
          add     bx, WORD [bpbBytesPerSector]        ; queue next buffer
          inc     ax                                  ; queue next sector
          loop    .MAIN                               ; read next sector

همچنین معرفی ImageName در اواخر برنامه که نام فایل کرنل را مشخص میکنه ،
و خلاصه سورس جالبه ، فقط یک نکته داره ، اونم اینه که وقتی ما فایل کرنل را برای تست روی فلاپی کپی میکنیم ، هنوز این سیستم عامل ویندوز هست که فایل را کپی میکنه و فایل مپ را در واقع میسازه
خیالتون را راحت کنم فعلا منم هنوز چیزی در این مورد نخوندم ولی در ادامه تا وقتی که
stage3 یا کرنل 32بیتی را میخوایم اجرا کنیم به مرور این مطالب را بهش میرسیم 

فقط جهت دونستن کلیات این مورد فعلا :

 

خب تا اینجا فرض میگیرم این لودر را دقیقا میدونیم چیکار میکنه ! ، اصلا بیخیال ، صبر و حوصله شو نداریم و همین که کار میکنه بسه بهتره بریم سر اصـــــــــــــــــــــــ ــــــــــــل مطلب ، یعنی لود کردن یک فایل کرنل ساده 
یک فایل ساده مینویسم که فقط یک متن نشون بده

کد:
;*********************************************
;	Stage2.asm
;		- Second Stage Bootloader
;
;	Operating Systems Development Series
;*********************************************

org 0x0					; offset to 0, we will set segments later

bits 16					; we are still in real mode

; we are loaded at linear address 0x10000

jmp main				; jump to main

;*************************************************;
;	Prints a string
;	DS=>SI: 0 terminated string
;************************************************;

Print:
	lodsb					; load next byte from string from SI to AL
	or			al, al		; Does AL=0?
	jz			PrintDone	; Yep, null terminator found-bail out
	mov			ah,	0eh	; Nope-Print the character
	int			10h
	jmp			Print		; Repeat until null terminator found
PrintDone:
	ret					; we are done, so return

;*************************************************;
;	Second Stage Loader Entry Point
;************************************************;

main:
	cli					; clear interrupts
	push			cs		; Insure DS=CS
	pop			ds

	mov			si, Msg
	call			Print

	cli					; clear interrupts to prevent triple faults
	hlt					; hault the syst

;*************************************************;
;	Data Section
;************************************************;

Msg	db	"Preparing to load operating system...",13,10,0

کامپایلش میکنیم
و فایل ساخته شده را به اسم KRNLDR.SYS تغییر نام میدیم
تا اینجا پس 2تا فایل داریم ، اولین که همون بوت لودر هست و با دستور
partcopy Boot1.bin 0 200 -f0
اون را روی فلاپی ریختیم
و این دومی که یک فایله و به صورت معمولی اون را Copy&Paste میکنیم روی فلاپی ( این دیگه partcopy نمیخواد )
حالا چی داریم ؟ یک دیسکت بوت که بعد از بوت شدن میگرده دنبال فایل کرنل و اون را اجرا میکنه
از حالا دیگه فقط باید فکرمون را بزاریم روی تکمیل این کرنل و بحث بوت لودر را تا وقتی که برسیم به قسمتهایی که باید بهش رجوع مجدد کنیم و تغییراتی برای سیستم عامل 32 بیتی توش بدیم همینجا بسته نگهش میداریم..

 

ادامه دارد…

بخش هشتم :

اگه سیستم شما فلاپی درایو واقعی داشته باشه ، مقدارش برابر با f0 هست
اگه درایو جدید با vfd میسازید و b: میشه باید به جای اون مقدار f1 را قرار بدید
این پیغام وقتی داده میشه که نتونه روی درایو write انجام بشود.

خب امروز یه کم تئوری داریم. مبحث شیرین مد محافظت شده Protect Mode
( هنوز سر بحث قبلی که نشد کامل توضیح بدم یعنی “ساختار فایل سیستم FAT ” وژدانم ناراحته  )

خب تا اینجا دیدین که سیستم بوت شد و همزمان یک کار( یک وظیفه ) قابل انجام بود و هیچی دیگه !
در حالت واقعی Real Mode ما میتونیم یک بایت را یکجائی بنویسیم ولی همزمان نمیشه هم پورتهای سیستم را خوند ، هم نوشت، هم پشتک و وارو زد
خلاصه کامپیوتر در این مد ، عملا فرقی با یک مرکز کنترل دیجیتال 0 . 1 بی خاصیت نداشت.

PMode این حالت در میکروپروسسورهای 80286 به بعد به وجود اومد برای استیبل تر شدن سیستمها و جلوگیری از خطاهایی که در ادامه میگم چیا بودن * ( این ستاره را اون آخر میگم)

در حالت ReadMode شما حافظتی از حافظه نداشتید (هرجائیش هرموقع ، بی حساب کتاب میتونستید دیتابنویسید و بخونید)
در حالت RM شما دسترسی به 16بیت رجیستر داشید که نهایتا میتونستید تا 1 مگابایت حافظه را آدرس دهی کنید
در RM شما هیچ پشتیبانی از حافظت حافظه سخت افزاری و یا مولتی تسکینگ نداشتید.

و مهمترین مشکل نبود Ring های مختلف در حالت RM بود ، یعنی چی ؟ یعنی همه کدهایی که نوشته میشن در واقع در Ring0 نوشته میشوند.! و این توی دنیای سیستم عاملهای امروز اصلا جالب نیست. مثلا با اجرای یک دستور CLI یا HLT تمام سیستم فاتحه اش خونده میشه. یعنی یک خرابی ( فقط یکی رخ بده ) عملا سیستم عامل و ادامه کار کامپیوتر به کشک تبدیل میشد.

 

اما خواص Protect Mode که همه جا به PMode معروفه

Protected Mode:

* Has Memory Protection
* Has hardware support for Virtual Memory and Task State Switching (TSS)
* Hardware support for interruting programs and executing another
* 4 Operating Modes: Ring 0, Ring 1, Ring 2, Ring 3
* Access to 32 bit registers
* Access to up to 4 GB of memory

 

دارای حفاظت از حافظه (memory )
پشتیبانی سخت افزاری از حافظه مجازی و انجام وظیفه سوئیچینگ خارجی (منظورشو نفهمیدم)
پشتیبانی اینتراپت ها و قابل استفاده کردنشون در برنامه های دیگر.
داشتن رینگ های کاری مختلف ( از 0 تا 3)
دسترسی به رجیسترهای 32 بیتی ( پس فکر کردین میگن سیستم عامل 32بیتی منظورشون چیه 
به دلیل فوق ، امکان سازماندهی حافظه تا 4گیگابایت.
شاید دیده باشین مادربوردهای قدیمی ( نه چندان قدیمی ) بیشتر از 4 گیگ رم ساپورت نمیکنن! ( احتمالا از همینه )
خب دیدیم که برنامه های اولیه ما در رینگ 0 اجرا میشدند در حالی که میدونیم برنامه های کاربر باید در رینگ 3 اجرا بشوند ، بنابراین ما در اینجا باید از یکی از ثابتها و دستورالعملهای پردازنده استفاده کنیم به نام LGDT

آشنایی با معماری سیستم و چگونگی کارکرد پردازنده به ما کمک خواهد کرد برای درک خیلی بهتر این مسئله.
یه نگاه به صورت کلی به خانوده x86 یا همین کامپیوترهامون بندازیم میبینم سرتاپاشون 3تا چیز بیشتر نیست
CPU
MEMORY
I/O _Input/Output
به قول یکی از دوستان ، سرخپوستی کامل ، خودش و شرتش و اسبش .

شکل فوق یک سرخپوست x86 را نشون میده 

این طرز کار بالا در عین سادگی ، در واقع شیرینی کامپیوتر را نشون میده… با یک روش کار ساده و اصولی ، همه ما ها داریم حال میکنیم دیگه.

تمام ورودی ها و خروجیهای کامپیوتر ( از کیبورد و موس و مانیتور گرفته تا کارتهای PCI – ISA و پورتهای usb و cd-rom و واحد Memory یا RAM همه از طریق رابطی به نام System BUS با قلب پردازش یا CPU در ارتباط هستند و یک فروند cpu همه اینها را فرماندهی میکنه.
هر اتفاقی بی افته از فشار دادن یک کلید تا نوشتن و خواندن روی حافظه قابل دسترسی میشه برامون.
ما به عنوان یک برنامه نویس سیستمی در اول کار باید همه اینائی که اون بالا گفتیم را بتونیم در پایئن ترین سطح (رینگ0) بتونیم پوشش بدیم.
در system bus ما یک Data bus داریم و یک address Bus
همه اینها در مجموع عملا چیزی نیست جز سطح ولتاژ منطقی 0 و 1

خب اول DATA bus را یه توضیحی بدم
موجی از این صفر و یک هاست که عملا بعد از جمع شدن پشت سر هم معنی پیدا میکنند
الکترونیکی ها با عبارت TTL آشنا هستند ، این سیستم باس دقیقا از همین استفاده میکنند

این منطق رد و بدل شدن اطلاعات به صورت همزمان در سه سطح تعریف شده
16 – 32 – 64 ( یعنی مثلا 32 بیت همزمان به cpu ارسال میشه یعنی 32 تا نقطه درنظربگریدی در یک لحظه ممکنه هرکدوم روشن یا خاموش باشند ) و عملا معنی cpu ی مثلا 64 بیتی ازهمینجا نشات میگیره ( در ادامه رجیسترها را در هرکدوم حالات یه توضیحی میدم )
خب وقتی یک cpu بتونه به جای 16 تا داده مثلا 32 حالت را تشخیص بده ، عملا سرعت اون cpu خیلی خیلی بیشتر از 16تائی میشه ، و به همین نسبت 64 بیتی و این اواخر هم 256 بیتی شنیدم بروبچ اونطرف آبی ، از ما بهترون ، در صنایع نظامی استفاده میکنند.

پس ما عملا در هر سیکل کاری cpu بسته به نوعش بسته های 16 الی 64 تائی از این 0ویک ها رد و بدل میکنیم.
و منبعد منظور ما از 16 بیتی یا 32 بیتی ، عملا مقدار اطلاعات قابل عبور ازاین گذرگاه باس هست. مثلا میگیم :

کد:
32 bit processor

اما Address Bus جیست ، اگه به شکل نگاه کنید همه دیوایس ها و حافظه و قطعات از طریق یک مجرا به هم وصل هستند، اگه ما فرمانی مثلا به ram بدیم قاعدتا باید i/o قاطی کنه
ااینجا آدرس باس به کمک میاد و برای هر چیزی یک آدرس منحصر به فرد در نظر میگیره
اگه به این BUS به شکل معنی اتوبوس واحد نگاه کنیم بد نیست ،
یک سیستم قدیمی 80186 کلا 20 خط را ساپورت میکرد
یک سیستم 80286 یا 80386 تا 24 خط را روی باسش ساپورت میکنه
یک سیستم از 80386 به بالا تا 32 بیت ( bit/line بیت بر خط )
………….
اومدم یک آمپول متوکلروپرامید را بشکنم انگشتم را همین الان بریدم … تایپ باشه برای یه شب دیگه 🙁

* :
( زکی پس ما تو بخش الکترونیک زدیم روی avr ی 8 بیتی سیستم عامل مولتی پروسس پیاده کردیم و شد  )

 

خب یه کم دیگه در مورد حافظه توضیح بدم
حتما حافظه های DDR , DDR2 و اینا به گوشتون خورده
حافظه های DDR یا Double Data Rate (DDR) Controller برای هر بار خواندن یا نوشتن از یک پالس سیستم استفاده میکنند
و در حالت Dual Channel Controller در هر پالس سیستم هم میشه از حافظه خواند و هم نوشت
خوشبختانه دردسر سرو کله زدن با دیوایس حافظه به عهده یک قطعه فیزیکی روی مادربرد هست به اسم 1337 Multiplexer که توضیحات فنی و دیتاشیت اون برای علاقه مندان روی گوگل هست

اما بریم سراغ زیربنای ارتباطات ما که همان subsystem I/O یا به زبون راحت تر PORT ها هستند…
ما دو دسته پورت داریم ، سخت افزاری و نرم افزاری
از پورتهای سخت افزاری میشه پورت کیبورد . موس . سریال – پارالل – یو اس بی . 1394 . وووو نام برد
از نظر الکترونیکی این پورتها حامل سیگنالها هستند که اطلاعات خودشون را روی باس سیستم به cpu تحویل میدهند
شما با نوشتن یا خواندن مستقیم روی آدرس این پورتهاو ارسال دیتا به اونها میتونید عملا اونها را کنترل کنید
اما قسمت مهم جائیه که بهش میگیم پورتهای نرم افزاری که عملا با اختصاص یک شماره ، دسترسی به پورتهای سخت افزاری را ایجاد میکنه. محل نگهداری این اعداد ( بخونید آدرسها) اصطلاحا به Memory Mapped I/O معروف هست.
مثلا آدرس 0xA000:0 هرچی توش بنویسید عملا انگار روی قسمت مربوط به خروجی گرافیک سیستم نوشتید و بلافاصله نتیجه را روی خروجی ( مانیتور) میتونید ببینید
در حالت Real Mode در سیستم های X86 ما یک جدول ثابت داریم
x86 Real Mode Memory Map 

کد:

* 0x00000000 – 0x000003FF – Real Mode Interrupt Vector Table * 0x00000400 – 0x000004FF – BIOS Data Area * 0x00000500 – 0x00007BFF – Unused * 0x00007C00 – 0x00007DFF – Our Bootloader * 0x00007E00 – 0x0009FFFF – Unused * 0x000A0000 – 0x000BFFFF – Video RAM (VRAM) Memory * 0x000B0000 – 0x000B7777 – Monochrome Video Memory * 0x000B8000 – 0x000BFFFF – Color Video Memory * 0x000C0000 – 0x000C7FFF – Video ROM BIOS * 0x000C8000 – 0x000EFFFF – BIOS Shadow Area * 0x000F0000 – 0x000FFFFF – System BIOS

با استفاده از جدول بالا ( که ایشالا همیشه ثابته ) ما عملا دسترسی به زیربنای یک کامپیوتر داریم
خب به عنوان مثال شاید خوندین که INT19 سیستم را ریست میکنه ، این دستور عملا میاد مقدار 0x1234 را در آدرس 0x0040:0x0072 مینویسه و بعد جامپ میکنه ( پرش میکنه ) به آدرس 0xFFFF:0, نتیجه این عمل ریست شدن کامپیوتره ( به قول خودشون ریست گرم ) یا همان مشابه عمل Ctrl+Alt+del در داس یا ویندوزهای قدیمی هست.
احتمالا الان متوجه میشید که این Int19 یک پورت نرم افزاری تعریف شده ، پس میتونه توی یک سیستم عامل سیستم را تعریف کنیم که کامپیوتر را ریست کنه و توی یک سیستم دیگه کامپیوتر ریست نشه.
تبدیل آدرس 0x0040 : 0x0072 به آدرس مطلق( واقعی ) میشه : 0x000000472
که مکانی است که در بایوس وظیفه ریست سیستم را دارد.
و به همین منوال… مثلا آدرس 0x000B8000 اگه بنویسیم انگار افکت دادیم به متن نوشته های روی مانیتور 
( ( اون قسمت Our Bootloader براتون آدرس آشنا نیست؟  )

خب برگردیم به مبحث Port Mapping
وقتی سیستم بوت میشه ، ROM Bios که یک IC هست روی مادربرد وظیفه آدرس دهی به سخت افزارهای متصل به خودش را داره و با ساخت جدول برداری وقفه هارا اجازه میده که با استفاده از این اعداد ، سخت افزارها کار کنندو تحت کنترل باشند.
خب ما اینجا نیاز به یک استاندارد داریم که هربار یک آدرس رندوم به هر دیوایسی داده نشه ، و الا بدبخت بودیم که  و عملا پردازنده میاد یک آدرس همیشگی برای آدرس باسهای دیوایسهای مختلف به عنوان استاندارد برای دسترسی بهشون اعمال میکنه
این نکته خیلی مهمه ، چون تنها راه محافظت شده و تضمین شده به سخت افزار هست
hardware protect Mode
مقداری از این جدول را در زیر مینویسم ( این جدول خیلی طولانیه )

توجه کنید که این جدول کامل کامل نیست …
و شاید در کل این جدول ، آدرس پورت پارالل براتون آشنا باشه (0x378)
اما میتونید به عنوان یک مرجع برای دسترسی به پورتهای سخت افزاری ازش هر موقع استفاده کرد ، ایشالا که نویسنده اصلیش حاجی Mike اش توش عیب و ایرادی نزاشته باشه 

در ادامه میرسیم به بحث رجیسترها ( از 16 تا 64 بیتی) و دستورالعملهای ویژه cpu و…

 

 

خب در ساختار استاندارد پردازنده های x86 ما همیشه یک In و out داریم ، یعنی چی؟ یعنی هم میتونیم دیتابگیریم هم بدیم. و بدین شکل با دیوایس ها ارتباط برقرار کنیم.
برای یک مثال عملی مثلا خواندن اطلاعات از کیبورد!
طبق جدول دسترسی به کیبورد از نوع ps2درآدرس 0x60 هست
خب در این دیواس که اختصاصا رجیستر کنترلیش در آدرس 0x64 هست ( پس این جدوله چی گفته این مکان ماله موس هست ؟)
اگر بیت اول این مکان 1 باشه یعنی دستگاه در حالت INput هست و دیتا اومده توی بافرش

کد:
WaitLoop:    in     al, 64h    			 ; Get status register value
             and    al, 10b    			 ; Test bit 1 of status register
             jz     WaitLoop   			 ; If status register bit not set, no data is in buffer
             in     al, 60h    			 ; Its set--Get the byte from the buffer (Port 0x60), and store it

کد بالا را یک نمونه اولیه از درایورنویسی برای سخت افزار ببینید (خیلی تخمیه نه؟ )
نمونه بالا یک کد خواندن مستقیم از سخت افزار هست ، روش نوشتن هم همینطوره ، یعنی آدرس را میدیم به باس و اطلاعات را میزاریم و مینویسیم روش ( دستور out )
به قول خارجیا این دیگه آخرشه direct hardware access
نکته کنکوری : به بحث اینتراپتها هم میرسیم 
ولی در مجموع این Port mapping و Port I/O را خوب به خاطر بسپارید که خیلی کار باهاش در مد محافظت شده سخت افزاری باهاشون داریم.

اما خود Processor
خود میکروپروسسور هم یکسری دستورات خاص داره ، در خانواده 8086 ها جدول زیر داشته باشید، بعدا هرکدوم را به موقع توضیح میدم

 

اجرای هرکدوم از این دستورات در پایه ترین سطح میکروپروسسور رخ میده و اگه برنامه ای اشتباهی در فراخوانی این دستورات داشته باشه، فاتحه سیستم خونده میشه و کرش میکنه

و 80×86 Registers
هر میکروپروسسوری یکسری ثبات داخلی داره که همه کارها و محاسبات ، فلگ ها و ووو به واسطه این ثباتها قابل دسترسی هست.

کد:
RAX (EAX(AX/AH/AL)), RBX (EBX(BX/BH/BL)), RCX (ECX(CX/CH/CL)), RDX (EDX(DX/DH/DL)), CS,SS,ES,DS,FS,GS, RSI (ESI (SI)), RDI (EDI (DI)), RBP (EBP (BP)). RSP (ESP (SP)), RIP (EIP (IP)), RFLAGS (EFLAGS (FLAGS)), DR0, DR1, DR2, DR3, DR4, DR5, DR6, DR7, TR1, TR2, TR3, TR4, TR5, TR6, TR7, CR0, CR1, CR2, CR3, CR4, CR8, ST, mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, GDTR, LDTR, IDTR, MSR, and TR.
یه توضیح کوچولو توی پرانتز بدم ، ممکنه رجیستر مثلا RAX براتون ناآشنا باشه
RAX در سیستم های 64 بیتی فقط معنی داره ،
EAX در 32 بیتی و 64 بیتی
AX در 16بیتی و 32 بیتی و 64 بیتی
خلاصه این رجیستر ها در مکانی مشخص در حافظه میکروپروسسور بعضا در دسترس برنامه نویس سیستم هستند.و البته بعضی از این ثباتها را فقط خود cpu به صورت داخلی بهشون دسترسی داره.
جهت کسب اطلاعات فنی میتونید به معماری پردازنده ها مراجعه کنید ( اشک آور هست )
ولی از دید ما CPU را همین طور به شکل رجیسترهاش ببینیم کافیه ، کار دیگه باهاش نداریم.
همچنین ممکنه رجیسترهای دیگیری هم باشد که در داکیومنتهای عمومی نامی ازشون نیومده باشه ، شاید فردائی اطلاعاتی به بیرون درز کرد…
اما در یک سیستم 32 بیتی ما به تعدادی از این رجیسترها سروکار داریم
مثلا
EAX :که برای محاسبات ریاضی و نگهداری مقادیر بکار میره
حالشو ندارم اینا رادیگه ترجمه شا بنویسم
کد:
    * EAX - Accumlator Register. Primary purpose: Math calculations
    * EBX - Base Address Register. Primary purpose: Indirectly access memory through a base address.
    * ECX - Counter Register. Primary purpose: Use in counting and looping.
    * EDX - Data Register. Primary purpose: um... store data. Yep, thats about it 🙂
هر رجیستر 32 بیتی در واقع از دو قسمت High و Low که هرکدوم 16 بیتی هستند تشکیل شده
هر رجیستر 64 بیتی هم در واقع از دو 32 بیتی تشکیل شده ( رجیسترهای RAX, RBX, RCX, RDX)
و هر کدوم از اون 16 بیتی هم تازه خودش به 2تا 8 بیتی AX تقسیم شده که به قسمتهای L , H معروفن مثلا شاید AH , AL را توی سورسها ساده اسمبلی دیده باشین که استفاده میشوند.
خلاصه یه ساختار تو در تور حساب کنید که از از AL هشت بیتی شروع میشه و به RAX 64 بیتی ختم میشه
کد:
					       +--- AH ----+--- AL ---+
					       |           |          |
	+-------------------------------------------------------------+
	|		      |     	       |                      |
	+-------------------------------------------------------------+
	|		      |					      |
	|		      +--------EAX lower 32 bits--------------|  
	|							      |
	|------------------ RAX Complete 64 bits----------------------|

خدا رحم کنه سیستم عاملهای 256 بیتی را…
شوخی کردم ، پخی نیستن ، ما در ادامه این آموزش فقط روی سیستم عامل 32 بیتی کار میکنیم ، ولی این 64 هم چیز خفنی نیست. همه شون مثل همن

 

 

یه مقدار مجبورم قبل از مراحل عملی کمی جفنگیات بنویسم ، تحمل کنید ، چاره ای نیست 

خب بعد از رجیسترهای عمومی ، نوبت رجیسترهای سگمنت میشه

کد:
    * CS - Segment address of code segment
    * DS - Segment address of data segment
    * ES - Segment address of extra segment
    * SS - Segment address of stack segment
    * FS - Far Segment address
    * GS - General Purpose Register
یه نکته ای که باید توجه داشته باشید در Real Mode نحوه آدرس دهی به این صورت هست
کد:
segment:offset
به طور معمول DS:SI یعنی بخش داده ها ( دیتا سگمنت ) که شامل SI ( سورس ایندکس ) هست
کلا برای دسترسی به حافظه از ایندکس رجیسترها استفاده میشه Index Registers
کد:
The x86 uses several registers that help when access memory.

    * SI - Source Index
    * DI - Destination Index
    * BP - Base Pointer
    * SP - Stack Pointer
مقادیر بالا برای 16 بیتی ها هستند
برای 32 بیتی با نامهای ESI, EDI, EBP, and ESP. میشناسیم
و برای 64 بیتی با نامهای : RSI, RDI, RBP, and RSP.
نکته SP یا اشاره گر پشته به صورت اتوماتیک افزایش یا کاهش پیدا میکنه
توابعی که مستقیما با این موضوع کار دارند push*, pop* instructions, ret/iret, call, syscall هستند
این آدرسی دهی تضمین میکنه که برنامه از نقطه صحیح و درست اجرا بشه و به نقطه درستی هم بازگشت پیدا کنه.
مورد بعدی Instruction Pointer / Program Counter هست
یا نشانگر محل دستورالعمل ،
کلا رجیستر IP ( در 16 بیتی ) و یا EIP ( در32 بیتی ) یا RIP ( در 64 بیتی ) کارش اینه که به cpu میگه محل اجرای دستور در حافظه کجاست . و کجا را باید بخونه و دستوراالعمل موجود در آن را اجرا بکند .
یادتون باشه که آدرس آفست اجرائی ، همیشه یک آدرس مطلق نیست ، و هربار ممکنه در حافظه تغییر کنه ( به استثنای آدرس 512بایتی اجرائی بوت )
یک رجیستر دیگه داریم بنام Instruction Register که در دسترس ما نیست و از رجیسترهایی هست که CPU در داخل خودش ازش استفاده میکنه ( مربوط به امور Cache و مخلفاتش ) ما هم کاری به کارش نداریم.
جهت کسب اطلاعات بیشتر راجع به معماری داخلی CPU ها به سایتهای اینتل و Amd میتونید مراجعه کنید و راهنماهایی که برای توسعه دهندگان قرار دادند را مطالعه کنید
مثلا برای AMD قسمت Developer Guides مطالب جالبی میتونید پیدا کنید
( یه آدم خیییر پیدا بشه ترجمه و توضیح بده مطالبشون را خیلی خوبه ، به جان خودم شما دانشجوها ترجمه کنید بدین استاداتون هم ماحال میکنیم هم استادتون هم نمره میگیرن  )
Flags Register
که همیشه آخرین نتیجه وضعیت اتفاق افتاده توی اینها قرار میگیرند ، و الخصوص برای چک کردن شرطها کاربرد دارند مثلادستورالعملهای شرطی jc, jnc, jb, jnb و…
در مدل 16بیتی بهشون میگن Flags Register
در مدل 32 بیتی بهشون میگن EFlags Register
در مدل 64 بیتی بهشون میگن RFlags Register
کد:
+---------- EFLAGS (32 Bits) ----+
 |                                |
 |-- FLAGS (16 bits)-             |
 |                  |             |
 ====================================================================  < Register Bits
 |                                                                  |
 +------------------------- RFLAGS (64 Bits) -----------------------+
 |                                                                  |
Bit 0                                                              Bit 63

کلا کاربرد زیادی دارند این رجیسترهای وضعیت ( Flag Register )
جدل ضمیمه نوع و خاصیت هر کدوم از بیتهای وضعیت را مشخص میکنه

 

 

 

توی جدول بالا یه توضیحی در مورد IOPL بدم IO Privilege Level (IOPL
وقتی این مقدار 0 یا 1 باشه ، فقط به هسته سیستم عامل اجازه داده میشه از دستوراتی مثل CLI – STI -IN – OUT استفاده بشه ، در غیر دیگر برنامه ها دسترسی به این توابع پایه ندارند و cpu خطای General Protection Fault (GPF را صادر میکنه

Test Registers : رجیسترهایی وجود دارند که کارشون فقط تست کردن هست
و اکثرا هیچ داکیومنت و توضیحاتی براشون منتشر نشده ( TR4,TR5,TR6,TR7. )
TR6 برای چک کردن اجرا شدن فرامین هست
TR7 برای ثبت داده هاست ( data register )
این رجیسترها فقط در Ring0 قابل دسترسی هستند( فقط با دستور MOV ) و در خارج از این رینگ منتجر به خطای GPF میشه General Protection Fault ( ترجمه تخمی داره ، گس مخافظت شده عمومی )

Debug Registers رجیستر های اشکال زدائی که شامل رجیستر های زیر است :
DR0 ، DR1 ، DR2 ، DR3 ، DR4 ، DR5 ، DR6 ، DR7

فقط در رینگ 0 و ( فقط با دستور MOV ) قابل دسترسی هستند

Beakpoint Registers :رجیسترهای نقطه توقف
DR0, DR1, DR2, DR3
شروط بیشتر در رجیستر DR7 که یک رجیستر 32 بیتی هست تعریف شده که بهشون میگن
Debug Control Register
حال ترجمه شا ندارم :

کد:
DR7 is a 32 bit register that uses a bit pattern to identify the current debugging task. Here it is:

    * Bit 0...7 - Enable the four debug registers (See below)
    * Bit 8...14 - ?
    * Bit 15...23 - When the breakpoints will trigger. Each 2 bits represents a single Debug Register. This can be one of the following:
          o 00 - Break on execution
          o 01 - Break on data write
          o 10 - Break on IO read or write. No hardware currently supports this.
          o 11 - Break on data read or write
    * Bit 24...31 - Defines how large of memory to watch. Each 2 bits represents a single Debug Register. This can be one of the following:
          o 00 - One bytes
          o 01 - Two bytes
          o 10 - Eight bytes
          o 11 - Four bytes
دیباگ رجیستر ها به دو صورت فعال میشوند Local محلی و Global عمومی
طرز کارشون یه چیزی تو مایه متغییر های محلی و عمومی هستند ، نوع لوکال فقط برای یک پروسه هستند وبا از بین رفتن پرسه این اطلاعات هم پاک میشوند ولی نوع گلوبال در کل سیستم انجام میشوند.
کد:
In Bits 0...7 in the above list:

    * Bit 0: Enable local DR0 register
    * Bit 1: Enable global DR0 register
    * Bit 2: Enable local DR1 register
    * Bit 3: Enable global DR1 register
    * Bit 4: Enable local DR2 register
    * Bit 5: Enable global DR2 register
    * Bit 6: Enable local DR3 register
    * Bit 7: Enable global DR3 register
Debug Status Register
اینم که معلومه وقتی دیباگ فعال یا غیر فعال باشه یک رجیستر را علامت میزاره
DR6 هیچ وقت در زمان دیباگ خالی نیست. اما اگر قرار باشه برنامه شما همیشه اجرا باشه و به مد دیباگ نره ، این رجیستر را باید خالیش کنید. ( فکر کنم منظور نویسنده نول کردن کاملش بوده ایشالا )
Model Specific Register
این هم شرایط خاصی را در رینگ صفر برای یه کارائی با cpu به هسته سیستم عامل میده
در سری x86 دو دستورالعمل برای دسترسی به این MSR هست ( نوشتن و خواندن روی این رجیتسر)
کد:
    * RDMSR - Read from MSR
    * WRMSR - Write from MSR

البته این دستورات خاص هستند و اینتل ازشون به عنوان یک CPUID در ساختار x86 ها رسما استفاده کرده

البته این لیست همیشه در حال آپدیت است…. و خواهد بود.
اطلاعات تکمیلی از سایت اینتل در این مورد MST برای علاقه مندان با این جفنگیات: 
http://developer.intel.com/Assets/PDF/manual/253669.pdf
system programming guid جالبی از اینتل به حجم 7 مگ حدودا.
یکی را میخوایم اینو بخونه و ترجمه کنه !  تا دقیقتر بهفهمین چیکارا میشه کرد.

روش استفاده هم اینطوریه مثلا ( برای خوندن )

کد:
	; This reads from the IA32_SYSENTER_CS MSR
 
	mov	cx, 0x174			; Register 0x174: IA32_SYSENTER_CS
	rdmsr					; Read in the MSR
 
	; Now EDX:EAX contains the lower and upper 32 bits of the 64 bit register
روش نوشتن هم :
کد:
	; This writes to the IA32_SYSENTER_CS MSR
 
	mov	cx, 0x174			; Register 0x174: IA32_SYSENTER_CS
	wrmsr					; Write EDX:EAX into the MSR

پیوست :
( باور کنید نصف این چیزایی که نوشتم را هنوز حتی ندیدم، ایشالا رفتیم جلوتر ، توی عمل شاید بهشون بر بخوریم و عملی تو سرومغز هم دیگه بزنیم )
پیوست2» فکر نکنید فقط من چرت و پرت میگم ؛ امروز خوندم که فرهنگستان لغت گفته به جای فیلتر بگیم : پالایه !!!

 

 

خب بریم سراغ Control Registers
این رجیستر برای ما خیلی مهمه ، چرا ؟
چون به ما اجازه میده رفتار CPU را بتونیم تغییر بدیم ، یعنی چی ؟
ترجمه شا بیخیال ولی اونائی که قرمز کردم را توجه کنید
CR0 Control Register
CR0 is the primary control register. It is 32 bits, which are defined as follows:

کد:
    * Bit 0 (PE) : Puts the system into protected mode
    * Bit 1 (MP) : Monitor Coprocessor Flag This controls the operation of the WAIT instruction.
    * Bit 2 (EM) : Emulate Flag. When set, coprocessor instructions will generate an exception
    * Bit 3 (TS) : Task Switched Flag This will be set when the processor switches to another task.
    * Bit 4 (ET) : ExtensionType Flag. This tells us what type of coprocesor is installed.
          o 0 - 80287 is installed
          o 1 - 80387 is installed.
    * Bit 5 (NE): Numeric Error
          o 0 - Enable standard error reporting
          o 1 - Enable internal x87 FPU error reporting
    * Bits 6-15 : Unused
    * Bit 16 (WP): Write Protect
    * Bit 17: Unused
    * Bit 18 (AM): Alignment Mask
          o 0 - Alignment Check Disable
          o 1 - Alignment Check Enabled (Also requires AC flag set in EFLAGS and ring 3)
    * Bits 19-28: Unused
    * Bit 29 (NW): Not Write-Through
    * Bit 30 (CD): Cache Disable
    * Bit 31 (PG) : Enables Memory Paging.
          o 0 - Disable
          o 1 - Enabled and use CR3 register
بیت 0 را اگه یک کنیم ، cpu به مد Protect Mode میره، که ادامه طراحی سیستم عامل ریشش گیر اینه.
یا بیت 31 که کار صفحه بندی حافظه را در اختیار میگیره و……… بهش میرسیم.
کد:
		mov	ax, cr0			; get value in CR0
		or	ax, 1			; set bit 0--enter protected mode
		mov	cr0, ax			; Bit 0 now set, we are in 32 bit mode!
آسون بود نه  ( واقعا نه ، بعدا دهنتون سرویس میشه )
حال ترجمه شا ندارم ( ترجمه کنم هم فایده ای نداره خب ، ولی بنویسم که جزو آرشیو باشه برای آدمهای پیله )
کد:
CR1 Control Register
Reserved by Intel, do not use.
CR2 Control Register
Page Fault Linear Address. If a Page Fault Exception accures, CR2 contains the address that was attempted accessed
CR3 Control Register
Used when the PG bit in CR0 is set. Last 20 bits Contains the Page Directory Base Register (PDBR)
CR4 Control Register
Used in protected mode to control operations, such as v8086 mode, enabling I/O breakpoints, Page size extension and machine check exceptions.
این CR4 بیشتر برای پردازش خطاها استفاده میشه
کد:
    * Bit 0 (VME) : Enables Virtual 8086 Mode Extensions
    * Bit 1 (PVI) : Enables Protected Mode Virtual Interrupts
    * Bit 2 (TSD) : Time Stamp Enable
          o 0 - RDTSC instruction can be used in any privilege level
          o 1 - RDTSC instruction can only be used in ring 0
    * Bit 3 (DE) : Enable Debugging Extensions
    * Bit 4 (PSE) : Page Size Extension
          o 0 - Page size is 4KB
          o 1 - Page size is 4MB. With PAE, it is 2MB.
    * Bit 5 (PAE) : Physical Address Extension
    * Bits 6 (MCE) : Machine Check Exception
    * Bits 7 (PGE) : Page Global Enable
    * Bits 8 (PCE) : Performance Monitoring Counter Enable
          o 0 - RDPMC instruction can be used in any privilege level
          o 1 - RDPMC instruction can only be used in ring 0
    * Bits 9 (OSFXSR) : OS Support for FXSAVE and FXSTOR instructions (SSE)
    * Bits 10 (OSXMMEXCPT) : OS Support for unmasked SIMD FPU exceptions
    * Bits 11-12 : Unused
    * Bits 13 (VMXE) : VMX Enable

و

کد:
CR8 Control Register
Provides Read and Write access to the Task Prority Register (TPR)
نگران نباشید اگه چیزی از این جفنگیات نفهمیدین ، منم مطالب توی این پست را که چیزی نفهمیدم هیچ ،؛ نویسنده اصلیش هم خودش گفته چیزی نفهمیده .
PMode Segmentation Registers
این چهارتا:
کد:
    * GDTR - Global De******or Table Register
    * IDTR - Interrupt De******or Table Register
    * GDTR - Local De******or Table Register
    * TR - Task Register

در آینده ای نزدیک در محیط PMODE که قرار خبرمون سیستم عامل را توش پیاده سازی کنیم ، کلی به کار میاد…
ولی خدائیش اینcpu خیلی خودش تخمیه! قیافه شو نگاه کنید ، خواه نا خواه کار کردن باهاش نیاز به دونستن خیلی خیلی چرت و پرت داره خب 
ریخت و قیافه و ذات کثیف یک پنتیوم 3 به صورت لخت شده و کاملا سِکسی :

    * L2: Level 2 Cache
    * CLK: Clock
    * PIC: Programmable Interrupt Controller
    * EBL: Front Bus Logic
    * BBL: Back Bus Logic
    * IEU: Integer Execution Unit
    * FEU: Floating Point Execution Unit
    * MOB: Memory Order Buffer
    * MIU / MMU: Memory Interface Unit / Memory Management Unit
    * DCU: Data Cach Unit
    * IFU: Instruction Fetch Unit
    * ID: Instruction Decoder
    * ROB: Re-Order Buffer
    * MS: Microinstruction Sequencer
    * BTB: Branch Target Buffer
    * BAC: Branch Allocater Buffer
    * RAT: Register Alias Table
    * SIMD: Packed floating point
    * DTLB: Data TLB
    * RS: Reservation Station
    * PMH: Page Miss Handler
    * PFU: Pre-Fetch Unit
    * TAP: Test Access Port

 

بخش نهم :

یه توضیح کوچولو و دوباره و بعد ورود به دنیای برنامه نویسی هسته سیستم عامل 32 بیتی
Protect Mode در این مد شما به عنوان برنامه نویس به هیچ چیز آماده ای از قبل دسترسی ندارید
نه اینتراپت ، نه سیستم call ها ، نه کتابخانه های استاندارد Lib برنامه نویسی ، نه هیچی ، و یک اشتباه کافیه که سیستم کرش کنه. پس حواس باید جمع باشه 
برای ادامه GDT را هم باید وسطشو باز کنیم نیگا کنیم 
خب پس شروع میکنیم:
1 – با حالت تئوری مد محافظت شده که اینهمه توضیح تاحالا دادم که حتما آشنائین PM
2- آدرس دهی در حالت PM
3- ورود به محیط PM
4- جدول عمومی GDT- Global De******or Table – نمیدونم به چه اسمی ترجمش کنم … در ادامه یه اسمی بلاخره براش میسازیم 

خب براش شروع خودمون یک کتابخانه میسازیم STDIO را حتما برنامه نویسهای سی باهاش آشنائی کامل دارند ، پس از یک اسم این مدلی برای شروع استفاده میکنیم ( عشقی)
اسم فایل را میزاریم stdio.inc
خلاصه اینکه این فایل را با فایل stdio.lib خود سی قاطی نکنید
( فعلا فقط نگاهش کنید ، کاربردش را در آینده ای نزدیک به صورت کد اجرائی توضیح میدم )

کد:
;*************************************************
;	stdio.inc
;		-Input/Output routines
;
;	OS Development Series
;*************************************************
 
%ifndef __STDIO_INC_67343546FDCC56AAB872_INCLUDED__
%define __STDIO_INC_67343546FDCC56AAB872_INCLUDED__
 
;************************************************;
;	Puts16 ()
;		-Prints a null terminated string
;	DS=>SI: 0 terminated string
;************************************************;
 
bits	16
 
Puts16:
		pusha				; save registers
.Loop1:
		lodsb				; load next byte from string from SI to AL
		or	al, al			; Does AL=0?
		jz	Puts16Done		; Yep, null terminator found-bail out
		mov	ah, 0eh			; Nope-Print the character
		int	10h			; invoke BIOS
		jmp	.Loop1			; Repeat until null terminator found
Puts16Done:
		popa				; restore registers
		ret				; we are done, so return
 
%endif ;__STDIO_INC_67343546FDCC56AAB872_INCLUDED__

.inc هم که حتما میدونید مخفف include هست ، یک استاندارد تعریف پسوند هست که برنامه نویس بدونه این فایل قراره اینکلود بشه توی برنامه اصلی.
اون %ifndef های اول هم برای اینه که دوباردوبار برنامه نیاد توی دل برنامه اصلی قرار بگیره
نکته کنکوری که توی این سورس میبینید pusha و popA هست . میبینید که هیچ تابعی نیست که چیزی را برگردونه
در اول کار کلیه رجیسترها ذخیره میشن و در انتها هم دوباره بازیابی میشن.
نه خانی اومده ، نه خانی رفته.
خب اگه یادتون بیاد ما محدودیت شدید 512 بایت را برای بوت لودر داشتیم ، پس بهتره تمام موارد غیر ضروری را ازش حذف کنیم و همه را منتقل کنیم به برنامه دومی ( اسمشو میزاریم KRNLDR که مخفف عنوان Kernel loader هست )
این کرنل لودر یا مرحله 2 کارش چیه؟:
1-فعال کردن و رفتن به حالت محافظت شده
2-بازیابی اطلاعات موجود در بایوس برای ادامه فعالیت و داشتن آدرس سخت افزارها و …
3-لود کردن و اجرای کرنل اصلی.
( میتونه اینجا لود کردن حالتی مثل safe mode ویندوز هم باشه ، نوعی هسته خالص تر شده)
( یا میتونه اینجا از حالت مولتی بوت استفاده بشه و چندتا سیستم عامل را بوت کنه ( مثل بوت کامندرها)
4-فعال کردن 20th برای دسترسی به 4گیگ حافظه ( یادم نیست توضیحش را دادم قبلا یا نه ،-فعلا دارم تایپ میکنم حال رفتن و دیدن ندارم ؛ به حد کافی حواسم پرت هست )
5- فراهم کردن هندل برای وقفه های پایه.
6- و کارهای دیگه…
و خلاصه یک محیطی آماده میکنه که بتونیم از اینجا به بعد برنامه های نوشته شده سطح بالاتر را بتونیم اجرا کنیم. ( نیت ندارید که کل هسته سیستم عامل را با اسمبلی بنویسید  )
خب از حالا به بعد این Protect Mode را بهش میگن حالت حافظت از حافظه. یعنی چی؟
یعنی تمام آدرس دهی ها را فرض میگیرم در حافظه وقتی برای اولین بار تهیه میشن تا آخر کسی بهشون دست نمیزاره و محافظت شده هستند در برابر تغییرات.
البته مکانهایی خاص از حافظه مد نظر هست ، نه همه حافظه. ( توضیح میدم )
در پروسسور های 80×86 ما میایم یک نقشه از حافظه تهیه میکنیم Memory Map که بیسش همون جدول GDT میشه و پروسسور یک General Protection Fault (GPF) میسازه برای پردازش خطاهای رخ داده در این جدول تا بتونه به وقفه های رخ داده شده رسیدگی کنه ( و الا پروسسور گوگیجه بگیره انگار که همون معنی کرش کردن براش اجرا شده باشه )
De******or Tables
ما یکسری جداول توصیفی داریم ، که هرکدوم توش مقادیری قرار میگیرند ، این مقادیر پایه و بنیان دسترسی low level ارتباط و تعامل با حافظه سیستم جهت پیاده سازی و اجرای سیستم عامل هست .
Global De******or Table (GDT),
Local De******or Table (LDT)
Interrupt De******or Table (IDT)
که آدرسهای پایه ای رجیسترهای ذخیره شده تحت عنوان
GDTR, LDTR, and IDTR
شناسائی میشن
توجه کنید که در صورت هرگونه درخواست دسترسی ring3 به این جداول که در ring0 ساخته میشوند ، خطای سیستمی برمیگرده ( cpu فحشتون میده )

اصلی ترین جدولی که باهاش کار داریم GDT هست که حالا جزئیاتش را میگم این جدول هم در بوت لودر باهاش کار داریم هم در کرنل.
کارش چیه ؟ یک نقشه کلی از مموری در اختیار طراح سیستم عامل قرار میده … دقیقا فکرکنید نقشه راههای یک کشور چقدر کار میکنه ؟ در این حد 
این جدول شامل سه بخش هست که اول Null descreptor بهش میگن و همه مقادیرش 00 هست ، دو بخش بعدی Code De******or و Data De******or هستند.
این جدول یک جدول 8 بایتی هست که هر بیت اون یه خاکی تو سرش میکنه ( ماشالا )
به ترتیب ارزش بیتها از آخر به اول مینویسم ( ترجمه مطالب این ریختی را ببرین دارلترجمه )

کد PHP:
    * Bits 56-63: Bits 24-32 of the base address
* Bit 55: Granularity
o 0: None
o 1: Limit gets multiplied by 4K
* Bit 54: Segment type
o 0: 16 bit
o 1: 32 bit
* Bit 53: Reserved-Should be zero
* Bits 52: Reserved for OS use
* Bits 48-51: Bits 16-19 of the segment limit
* Bit 47 Segment is in memory (Used with Virtual Memory)
* Bits 45-46: De******or Privilege Level
o 0: (Ring 0) Highest
o 3: (Ring 3) Lowest
* Bit 44: De******or Bit
o 0: System De******or
o 1: Code or Data De******or
* Bits 41-43: De******or Type
o Bit 43: Executable segment
+ 0: Data Segment
+ 1: Code Segment
o Bit 42: Expansion direction (Data segments), conforming (Code Segments)
o Bit 41: Readable and Writable
+ 0: Read only (Data Segments); Execute only (Code Segments)
+ 1: Read and write (Data Segments); Read and Execute (Code Segments)
* Bit 40: Access bit (Used with Virtual Memory)
* Bits 16-39: Bits 0-23 of the Base Address
* Bits 0-15: Bits 0-15 of the Segment Limit  
در مورد ترجمه همین بس که نویسنده اصلیش ورداشته نوشته “.Pretty ugly, huh ” حالا منظورش چی بوده ، مهم نیست محض احتیاط خودشه و جد و آبادش . 
خلاصه هرکدوم از این بیتها یک خاصیتی برای قطعه ای از حافظه هست که مورد استفاده قراره قرار بگیره.
به کمک این جدول هست که رسما ما امکان نوشتن و خواندن از آدرس 0 تا 0xFFFFFFFFرا در اختیار خواهیم گرفت ( حالا خورد خورد توضیح میدم کی کجاس و کی بچه را ….. )
خب این یک نمونه اولیه برای ساخت این جدول را ببینید :
کد PHP:

 ; This is the beginning of the GDT. Because of this, its offset is 0.

; null de******or
dd 0                 ; null de******or–just fill 8 bytes with zero
dd 0

; Notice that each de******or is exactally 8 bytes in size. THIS IS IMPORTANT.
; Because of this, the code de******or has offset 0x8.

; code de******or:            ; code de******or. Right after null de******or
dw 0FFFFh             ; limit low
dw 0                 ; base low
db 0                 ; base middle
db 10011010b             ; access
db 11001111b             ; granularity
db 0                 ; base high

; Because each de******or is 8 bytes in size, the Data descritpor is at offset 0x10 from
; the beginning of the GDT, or 16 (decimal) bytes from start.

; data de******or:            ; data de******or
dw 0FFFFh             ; limit low (Same as code)
dw 0                 ; base low
db 0                 ; base middle
db 10010010b             ; access
db 11001111b             ; granularity
db 0                ; base high

در مثال بالا هر بیت مستقیما مقدار دهی شده است.
خب توصیف نول که چیزی نیاز نداره همه چیز صفر مطلق هست
میریم سراغ دو بخش بعدی
کد PHP:
; code de******or:            ; code de******or. Right after null de******or
dw 0FFFFh             ; limit low
dw 0                 ; base low
db 0                 ; base middle
db 10011010b             ; access
db 11001111b             ; granularity
db 0                 ; base high  
که حالت دو دوئی آن به این شکل میشه :
کد PHP:
11111111 11111111 00000000 00000000 00000000 10011010 11001111 00000000  
دو بایت اول را یعنی 0 تا 15 را چی براش نوشتیم ؟ سگمنت لیمیت ، در اینجا ما فقط میتونیم مقدار 0xffffرا به سیستم حالی کنیم که معادل 65535 بایت از حافظه هست ( در ادامه میگم چطور میشه که نهایتا در سیستم 32بیتی تا حدود 4 گیگ حافظه یعنی 0xffffffff را میتونیم در اختیار بگیریم )
23 بیت بعدی آدرس پایه Base address را مشخص میکند که عملا شروع آدرس سگمنت مورد استفاده برای ما از 0x0 شروع میشه( تا 0xffff ) و ما میتوانیم به بیت به بیت این فضای حافظه از طریق داشتن آدرس مبدا دسترسی مستقیم داشته باشیم.
بایتهای بعدی یعنی 6 بایت بعدی کارهای جالبی برامون میکنه :
کد:
db 10011010b 			; access
کد PHP:
# Bit 0 (Bit 40 in GDT): Access bit (Used with Virtual Memory). Because we don't use virtual memory (Yet, anyway), we will ignore it. Hence, it is 0
# Bit 1 (Bit 41 in GDT): is the readable/writable bit. Its set (for code selector), so we can read and execute data in the segment (From 0x0 through 0xFFFF) as code
# Bit 2 (Bit 42 in GDT): is the "expansion direction" bit. We will look more at this later. For now, ignore it.
# Bit 3 (Bit 43 in GDT): tells the processor this is a code or data de******or. (It is set, so we have a code de******or)
# Bit 4 (Bit 44 in GDT): Represents this as a "system" or "code/data" de******or. This is a code selector, so the bit is set to 1.
# Bits 5-6 (Bits 45-46 in GDT): is the privilege level (i.e., Ring 0 or Ring 3). We are in ring 0, so both bits are 0.
# Bit 7 (Bit 47 in GDT): Used to indicate the segment is in memory (Used with virtual memory). Set to zero for now, since we are not using virtual memory yet  

بیتهای دسترسی شامل موارد زیر هستند:
بیت 0 این موضوع که همان بیت 40 جدول GDT هست مشخص میکنه که از حافظه مجازی Virtual memory استفاده بکنیم یا نه ( ما میگیم نه و مقدارش را 0 میزاریم )
بیت 1 یا همان بیت 41 جدول GDT : این بیت به ما اجازه خواندن و نوشتن از این مکان حافظه ( یعنی 0 تا ffff را میدهد)

بیت 2 یا همان بیت 42 جدول GDT : این بیت به expansion direction معروف هست و ما کاری فعلا باهاش نداریم ( یه جونمرد پیدا نشد بره این دیتاشیت اینتل را ترجمه کنه؟)

بیت 3 یا همان بیت 43 جدول GDT : به سی پی یو میگه این تکه کد اجرائی یا دیتا هست. که البته در مورد ما Code هست نه Data

بیت 4 یا همان بیت44 جدول GDT :این یک کد سلکتور هست که میزاریمش همیشه 1 باشه

بیت 5 و 6 : رینگ کاربردی را مشخص میکنه که ما چون رینگ 0 هستیم همیشه این مقدار هر دو بیت 0 هست.

بیت 7 : برای نشان دادن قطعه ای در حافظه مجازی هست که چون ما فعلا دنبال این بحث حافظه مجازی نیستیم براش یابو اب میدیم و مقدراش را میزاریم 0

این بایت دسترسی access byte مهم هستند چون وقتی نزدیک میشیم به رینگ 3 یا برنامه های کاربردی باید حواسمون بهش باشه.

خب از اینجا به بعدش یه کم توضیحاتش پیچیده میشه و مخ من امشب گیجه ، یه چند روز دیگه ایشالا ریست شدم ادامه این بحث را مینویسم.
میدونم همه دوست دارین فرتی بریم سراغ اصل سیستم عامل ، ولی باور کنید اگه اصول را حتی همینقدر دست و پا شکسته ندونید ؛ هیچ فرقی بین نوشتن و استفاده یک سیستم عامل مستقل با استفاده از یک سیستم عامل ویندوز معمولی در آینده نخواهید داشت. پس تحمل کنید 

در ادامه داستان ، بایت granularity را توضیح میدم ….)

دانلود کتاب سیستم عامل تانن باوم با فرمت PDF
به نقل از اینجا
اینم کتاب معروف سیستم عامل برای کسایی که می خوان بدونن یه سیستم عامل چه جوری کار می کنه و چه جوری پیاده سازی می شه

دانلود مستقیم
http://www.ALT.ir/os/Operating.Syste…rd.Edition.zip
حجم 5.5 مگ

 

 

 

بریم سراغ بایت بعدی یعنی granularity

کد:
db 11001111b 			; granularity
	db 0 			; base high
توضیحی زیادی نمیدم چون زیاد نفهمیدم 
کد PHP:
# Bit 0-3 (Bits 48-51 in GDT): Represents bits 16-19 of the segment limit. So, lessee... 1111b is equal to 0xf. Remember that, in the first two bytes if this de******or, we set 0xffff as the first 15 bites. Grouping the low and high bits, it means we can access up to 0xFFFFF. Cool? It gets better... By enabling the 20th address line, we can access up to 4 GB of memory using this de******or. We will look closer at this later...
# Bit 4 (Bit 52 in GDT): Reserved for our OS's use--we could do whatever we want here. Its set to 0.
# Bit 5 (Bit 53 in GDT): Reserved for something. Future options, maybe? Who knows. Set to 0.
# Bit 6 (Bit 54 in GDT): is the segment type (16 or 32 bit). Lessee.... we want 32 bits, don't we? After all-we are building a 32 bit OS! So, yeah--Set to 1.
# Bit 7 (Bit 55 in GDT): Granularity. By setting to 1, each segment will be bounded by 4KB.
The last byte is bits 24-32 of the base (Starting) address–which, of course is 0.

بیت 0 تا 3 کارش اینه که وقتی 1111 باشه ، به همراه استفاده از ادرس لاین 20 به ما این اجازه داده میشه که تا 4 گیگ حافظه را آدرس دهی کنیم. ( علت و عوامل رجوع شود به رفرنس cpu اینتل یا amd )
بیت 4 و 5 رزرو هستند و با 0 پر میشن
بیت 6 برای اینکه به محیط 32 بیتی دسترسی داشته باشیم باید 1 باشه
بیت 7 وقتی یک باشه ، قطعات حافظه( سگمنت ) را حداکثر 4 کیلوبایت تعیین میکنه

8 بیت بعدی که در واقع بیس آدرس ( آدرس شروع ) هستند هم برابر با 0 قرار داده میشن

( همش همینقدر تو این مدت نوشتم  ، شرمنده ، ایشالا فسفر مغز بزاره زودتر تکمیلش میکنم)

 

این نوشته ها هم از دوست عزیز xman_1365_x در سایت برنامه نویس دیدم
گفتم اینجا بزارمش شاید به درد یکی که افتاده توی این خط اعتیاد سیستم عاملی خورد…
::

نقل قول: مقدمه ایی بر اسمبلی 64 بیتی

مرجع پست اول اینجاست
که ایبوک در ارتباط با abi هم داره که مفیده!
مقدمه ای در ارتباط با IA-64
x86 Instruction Set Architecture Comprehensive 32-64-bit Coverage
اینم هست که اگر عضو نیستین از گوگل پیدا کنید شاید بعدا خودم آپلودش کنم
http://book.pdfchm.net/32-64-bit-80x…9781598220025/
و
http://www.cs.cmu.edu/~fp/courses/15213-s07/misc/asm64-handout.pdf

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

 

 

شاید ادامه داشته باشد ، شاید هم ادامه اش را شما بنویسید……….

 

برچسب ها
نمایش بیشتر

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

facilisis pulvinar commodo adipiscing ipsum ut ut