به نام خداوند بخشنده و مهربان!

سلام میکنم به دوستان و هموطنان عزیز  innocent

دوباره قسمت بعدی آموزش سیستم عامل رو آماده کردم که بخونید و برید سیستم عامل بسازید، رو دست ویندوز بزنید undecided اینجوری که ما پیش میریم مایکروسافت کم میاره!

خوب از شوخی گذشته بریم سراغ آموزش..!

مثل دو مطلب گذشته این مطلب هم از جناب آقای عباس مقدم هست که از وبلاگشون رونوشت کردم! البته یه تغییرات جزئی جهت فهم بیشتر و... بهش افزودم cry

بنابراین بدون مقدمه میریم سراغ آموزش ->

خب، تا اينجاي كار ما تونستيم يه برنامه بوت لودر بنويسيم كه بتونه سيستم رو لود كنه و يه پيام روي مانيتور چاپ كنه. همونطور كه چندبار گفتيم برنامه بوت لودر بايد دقيقاً 512 بايت حجم داشته باشه و براي اينكه بتونيم هسته سيستم عاملي كه بيشتر از 512 بايت حجم داره كه تقريباً 100 درصد سيستم عامل ها رو شامل ميشه بايد اين كار رو تو دو مرحله انجام بديم. 1- اول با بوت لودر 512 بايتي سيستم رو راه اندازي كنيم 2- تنظيمات لازم براي ورود به مود 32 بيتي ( مود حفاظت شده ) رو توي اين برنامه انجام بديم و بعد هسته سيستم عامل رو توسط همين بوت لودر بارگذاري كنيم و كنترل سيستم رو به كرنل بسپاريم.

بعضي وقت ها ( در سيستم عامل هاي بزرگ هميشه ) تنظيمات لازم براي آماده سازي سيستم و لود كردن كرنل خيلي زياده و نميشه با يه برنامه 512 بايتي اين كار رو انجام داد. توي اينجور مواقع بايد از بوت لودر 2 مرحله اي استفاده كنيم. يعني اين كه بوت لودر 512 بايتي ما بعد از اجرا شدن يه برنامه فرعي ديگه رو اجرا كنه كه اين برنامه ميتونه هر حجمي داشته باشه و تنظيمات لازم توي اين برنامه انجام بشه و بعد اين برنامه كرنل رو اجرا كنه. البته براي سيستم عامل هاي 16 بيتي نيازي به اين مرحله نيست و بوت لودر 512 بايتي ميتونه مستقيماً كرنل رو لود كنه و تنظيمات بعدي توي خود كرنل انجام بشه.

به اين جور بوت لودر ها ، بوت لودر چند مرحله اي يا MultiStage Bootloader گفته ميشه. حالا شايد سوال پيش بياد كه منظور از تنظيمات لازم چيه. اين همون چيزيه كه ما توي اين پست و پست بعدي بهش ميپردازيم. يكي از چيزهايي كه لازمه در موردش بشتر بدونيد تا تنظيمات مربوطه رو انجام بديد همون بلاك OEM هستش كه تو پست قبلي يه كم بهش اشاره كرديم و تو اين پست ميخواهيم بيشتر در موردش توضيح بديم.

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

وقفه شماره 13H : اين وقفه براي انجام اعمالي بر روي ديسك استفاده ميشه و داراي توابع مختلفي هست كه چند تاش براي ما خيلي مهمه.

تابع 0H : . تابع شماره 0H از اين وقفه براي ريست كردن هد دسيك استفاده ميشه. وقتي كه ما ميخواهيم اطلاعاتي رو از فلاپي بخونيم هد فلاپي درايو ممكنه تو هر جايي باشه ولي براي اينكه بتونيم مكان اطلاعات مورد نظر روي ديسك رو درست شناسايي كنيم لازمه قبل از هر عمل خوندن روي فلاپي، هدش رو به سكتور شماره 0 منتقل كنيم. براي فراخواني اين تابع بايد ثبات AH با مقدار صفر و DL با شماره درايو مورد نظر تنظيم بشه. در صورتي كه اين تابع كارش رو با موفقيت انجام بده مقدار 0 در فلگ CF قرار ميگيره و در صورت عدم موفقيت مقدار اين ثبات 1 ميشه. براي اينكه مطمئن بشيم كه هد به سكتور صفر منتقل شده، حتماً بايد بعد از اجراي تابع مقدار CF رو تست كنيم. تكه برنامه زير اين كار رو انجام ميده.

.Reset:
mov ah, 0
mov dl, 0
int 0x13
jc .Reset

سطر آخر اين برنامه در صورت 1 بودن CF به اول برنامه پرش ميكنه و دوباره تابع رو اجرا ميكنه تا وقتي كه مطمئن بشه حتماً هد به سكتور 0 منتقل شده.

تابع شماره 2H : اين تابع از وقفه 13H براي خواندن از ديسك استفاده ميشه. براي استفاده از اين تابع بايد مقادير ثبات ها به شكل زير تنظيم بشه.

AH : شماره تابع كه همون 0x02 هستش.

AL : تعداد سكتورهايي كه قراره خونده بشه بايد توي اين ثبات قرار بگيره.

ES : محل قرار گيري اطلاعات در حافظه بعد از خواندن از ديسك. ( مثلاً 0x1000 )

BX : سگمنتي كه قراره اطلاعات توش قرار بگيره بايد تو اين ثبات ذخيره بشه. از اونجايي كه ما نمي خواهيم فعلاً وارد بحث سگمنت ها بشيم و اين بحث ها براي مود 32 بيتي زياد لازم نميشه فعلاً اين ثبات رو به 0 تنظيم ميكنيم. يعني اطلاعات بايد تو سگمت 0 ذخيره بشه.

DH : همونطور كه ميدونيد هر فلاپي دو تا هد داره و اين ثبات شماره هدي كه بايد خوندن رو انجام بده رو مشخص ميكنه. در واقع ما بايد از هد اول يا هد شماره 0 استفاده كنيم.

DL : شماره درايو بايد توي اين ثبات قرار بگيره كه براي فلاپي شماره درايو صفر ميشه

CH : شماره سيلندري كه خوندن بايد از اون انجام بشه توي اين ثبات قرار ميگيره.

CL : اين ثبات هم براي مشخص كردن شماره سكتوري كه خوندن بايد از اونجا شروع بشه به كار ميره.

در مورد دو مورد آخر يه كمي توضيح بيشتر لازمه. هر ديسك ( چه فلاپي يا هارد يا CD ) از يك سري شيار تشكيل شده كه اطلاعات روي اونها ذخيره ميشه اين شيارها ( Tracks ) به صورت دواير متحدالمركز روي ديسك قرار گرفته اند. همچنين هر ديسك ممكنه چند وجه داشته باشه مثل فلاپي كه دو وجه و در نتيجه دو تا هد خوندن و نوشتن هم داره. بعضي از درايورهاي هارد ديسك ممكنه چند تا ديسك داشته باشند كه هر ديسك ميتونه يك يا دو وجه داشته باشه در هر دو مورد به مجموعه شيارهايي كه در ديسك ها و وجه هاي مختلف داراي شعاع يكسان هستند، يعني روي هم قرار ميگيرند يك سيلندر گفته ميشه. در واقع وقتي ما شماره سيلندر رو برابر 2 و شماره هد رو برابر 1 قرار ميديم.يعني شيار شماره دو از وجهي كه هد شماره 1 قرار داره مد نظرمون هستش. بحث مفصل درباره اين موضوع توي اين پست نمي گنجه. توصيه مي كنم اگه اطلاعات زيادي در اين مورد نداريد حتماً در فرصت مناسب اطلاعاتتون در اين زمينه رو بيشتر كنيد. همچنين اين رو هم بگم كه هر شيار به تعدادي سكتور تقيسم ميشه كه اولين سكتور از اولين شيار از اولين وجه هر ديسكي همون سكتور راه انداز ديسك رو تشكيل ميده.

در مورد فلاپي بايد اين توضيح رو بدم كه هر فلاپي 3.5 اينچي و 1.44 مگابايتي در هر شيار داراي 18 سكتور و در كل حاوي 80 شيار هستش. بعد از اجراي اين تابع مقدار فلگ CF مثل تابع قبلي تغيير ميكنه. يعني اگر تابع با موفقيت اجرا بشه مقدار 0 و در غير اين صورت مقدار 1 رو ميگيره.

به تكه كد زير توجه كنيد. اين برنامه ابتدا هد فلاپي رو ريست ميكنه بعد يك سكتور از فلاپي رو ميخونه و در آدرس 0x1000 از حافظه در سگمنت 0 قرار ميده.

 

.Reset:
mov ah, 0
mov dl, 0
int 0x13
jc .Reset

mov ax, 0x1000
mov es, ax
xor bx, bx

.Read:
mov ah, 0x02
mov al, 1
mov ch, 1
mov cl, 2
mov dh, 0
mov dl, 0
int 0x13
jc .Read

jmp 0x1000:0x0

اين برنامه يك سكتور از شيار شماره يك رو با شروع از سكتور شماره 2 مي خونه و در حافظه قرار ميده و بعد به اون قسمت از حافظه مي پره و اون رو اجرا ميكنه. دقت كنيد كه در اين حالت CPU نميتونه تشخيص بده كه كد موجود در آدرس 0x1000 از حافظه قابليت اجرايي داره يا نه و اگر اين كد قابليت اجرا شدن رو نداشته باشه سيستم ممكنه هنگ بكنه يا ريست بشه يا هر اتفاق ديگه اي ممكنه بيفته، پس بيشتر دقت كنيد.

خب حالا اگه ما بخواهيم بجاي خوندن يك سكتور از فلاپی و اجرا كردن اون يه فايل رو بخونيم و اجرا كنيم بايد چه كار كنيم. چون تا اينجا همه چيز بر مبناي شماره شيار و سكتور انجام شده نه بر اساس اسم فايل، از اونجايي كه يه فايل ممكنه تو هر سكتوري ذخيره شده باشه بايد اول سكتور مورد نظر رو پيدا كنيم. بعد فايل رو از اون سكتور مثل مثال بالا بخونيم و اجرا كنيم. اين فايل ميتونه هسته سيستم عامل يا مرحله دوم برنامه بوت لودر ما باشه. در واقع بحث اصلي اين پست درباره همين موضوعه و اون همون پارامترهاي بلاك OEM هستش.

سيستم فايل FAT12

حتماً تا حالا در مورد سيستم هاي فايل مختلف و مزايا و معايب اونا چيزهايي شنيديد. معروفترين اين سيستم هاي فايل شايد NTFS , FAT12 , FAT32 , FAT16 , ext2 , ext3 و ... باشند. سيستم فايل FAT12 مخصوص ديسك هاي فلاپي طراحي شده. اين سيستم همونطور كه از از اسمش پيداست از سيستم 12 بيتي براي آدرس دهي براي اطلاعات روي ديسك استفاده ميكنه ، در نتيجه حداكثر واحد حافظه اي كه ميتونه بشناسه برابر با 2 به توان 12 يا 4086 واحد ميشه. البته واحد حافظه روي ديسك ها با واحد حافظه روي RAM خيلي فرق داره. واحد حافظه روي ديسك كلاستر هستش كه خود كلاستر از يك يا چند سكتور تشكيل ميشه. تعداد سكتور ها در هر كلاستر ميتونه متغير باشه و در سيستم FAT12 اين عدد بين 1 و 8 بايد باشه. بنابراين اگه هر كلاستر از 8 سكتور تشكيل شده باشه، اندازه هر كلاستر 4 كيلوبايت ميشه و در نتيجه با توجه به اينكه 4086 كلاستر ميتونه تو اين سيستم آدرس دهي بشه. پس حد اكثر ظرفيت يك ديسك با سيستم فايل FAT12 برابر با 16 مگابايت ميشه كه براي ديسك هاي فلاپي 1.44 مگابايتي كافيه. حتي اگه هر كلاستر رو برابر با 1 سكتور تعريف كنيم بازهم 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
bsExtBootSignature: DB 0x29
bsSerialNumber: DD 0xa0a1a2a3
bsVolumeLabel: DB "MOS FLOPPY "
bsFileSystem: DB "FAT12 "

دو خط اول همونطور كه از اسمشون پيداست به ترتيب تعداد بايت ها در هر سكتور و تعداد سكتورها در هر كلاستر رو مشخص ميكنند كه نشون ميده تعداد سكتورها در فلاپي ما 1 هستش كه البته ميشه تغييرش داد ولي توصيه ميكنم اين كار رو نكنيد. خط سوم هم تعداد سكتورهاي رزرو شده رو مشخص ميكنه. منظور از سكتور رزرو شده، سكتوري هست كه توي جدول FAT استفاده نميشه و نميشه در حالت عادي اطلاعاتش رو تغيير داد. مثلاً تو حالت عادي شما اگه وارد يك CD ويندوز كه قابليت Bootable داره بشيد. تو محيط ويندوز نمي تونيد فايلهاي مربوط به سكتور بوت اون ديسك رو ببينيد ، در مورد درايو C يا فلاپي هم كه سكتور راه انداز دارند وضع به همين ترتيب هستش. در حالت عادي ويندوز يا بقيه سيستم عاملها اين اجازه رو به كابر نميدن كه اطلاعات اين سكتور رو تغيير بدن، ولي با برنامه هاي خاصي مثل partcopy یا همون BOOTICE خودمون ميشه اين كار رو انجام داد. به همين دليله كه وقتي شما تو پست قبلي بوت لودرتون رو به فلاپي منتقل كرديد بعد از وارد شدن به اون چيزي نميديد. از اونجايي كه ما فقط به يك سكتور براي راه اندازي احتياج داشتيم مقدار اين پارامتر رو برابر 1 قرار داديم.

پارامتر بعدي تعداد جدول هاي FAT رو مشخص ميكنه كه براي فلاپي هميشه برابر 2 هست. دو پارامتر بعدي به ترتيب حداكثر دايركتوري هاي موجود در ريشه درايو و تعداد كل سكتورهاي درايو رو نشون ميدن كه براي فلاپي به ترتيب 224 و 2880 بايد باشه. پارامتر بعدي، يعني bpbMedia يك عدد هشت بيتيه كه هر بيت معني خاصي داره كه توضيح ميدم.

بيت 0 : اگه 0 باشه يعني فلاپي يك وجهي و اگه 1 باشه يعني دو وجهيه
بيت 1 : اگه 0 باشه يعني هر جدول FAT توي 9 سكتور جا ميگيره و اگه 1 باشه توي 8 سكتور
بيت 2 : تعداد شيارها رو نشون ميده كه اگه 0 باشه يعني 80 شيار و اگه 1 باشه يعني 40 شيار
بيت 3 : نشون دهنده نوع ديسك هست كه اگه 0 باشه يعني ثابته ( مثل هارد ) و اگه 1 باشه يعني قابل جابه جاييه ( مثل فلاپي و CD )
بيت هاي 4 تا 7 : بلا استفاده هستند.

در اينجا ما از عدد 0xF0 = 11110000 استفاده كرديم كه نشون دهنده يك ديسك جابحا شونده و تك وجهي با 80 شيار و 9 سكتور در هر FAT هست.

پارامتر بعدي هم همون 9 سكتور در هر FAT رو مشخص ميكنه. دو پارامتر بعدي هم به ترتيب تعداد سكتورها در هر شيار و تعداد هدها در هر سيلندر رو مشخص ميكنند كه برابر با 18 و 2 هستند. 

چهار پارامتر بعدي مهم نيستند و همين مقادير رو كه ميبينيد هميشه براشون استفاده كنيد.

سه پارامتر بعدي هم به ترتيب شماره سريال ديسك، برچسپ يا Label دسيك و نوع سيستم فايل ديسك رو مشخص ميكنند. توجه كنيد كه برچسب ديسك حتماً بايد 11 كاراكتر و نوع سيستم فايل 8 كاراكتر باشند. به همين دليل از جاي خالي استفاده شده. خب حتمآ ميپرسيد حالا اين چيزهايي كه گفتيم چه ربطي به ماجرا داره.

در واقع ما براي دستيابي به فايل ها روي هر ديسكي به اين پارامترها احتياج داريم. به طور ذاتي يك درايور ديسك چه از نوع سخت، چه از نوع نرم هيچ اطلاعي از نوع فايل سيستم، سكتور راه انداز، نحوه راه اندازي سيستم ، چگونگي تشكيل فايل و... نداره. حتي يك درايور هيچ تعريفي از فايل براش نشده. درايور ديسك فقط ميتونه يك سري اطلاعات رو به صورت دسته اي از بيت ها در محل هاي مشخصي از ديسك ذخيره كنه يا اونها رو بخونه. در واقع اين برنامه نويس هست كه به CPU ميفهمونه منظورش از يك فايل يا دايركتوري چيه و تمام اين مفاهيم قبل از استفاده به اون شكلي كه مثلاً توي ويندوز ديديد بايد توسط سيستم عامل تعريف بشه. مهمترين چيزي كه براي تعريف مفهوم فايل به درد ما ميخوره همين پارامترهاي بلاك OEM هستش. تو پست بعدي درباره نحوه استفاده از اين پارامترها براي دسترسي به فايل ها صحبت خواهيم كرد. پس حتماً منتظر پست بعدي باشيد. طبق معمول آخر اين پست هم بهتون توصيه مي كنم كه تا ميتونيد اطلاعاتتون در زمينه برنامه نويسي با اسمبلي و ارتباط با سخت افزار بيشتر كنيد.

خوب امیدوارم مفید بوده باشه!

این مطلبم از آقای عباس مقدم بود...‍!

فک کنم مطلب بعدی هم از ایشون خواهد بود و دیگه تموم میشه و خودمون باید بقیه اش رو ادامه بدیم!

خوب .... فعلا

یا علی مدد....!

 

  قسمت قبل : جلسه پنجم                                                         قسمت بعد : جلسه هفتم