Internet Windows Android
Kengaytirish

Operatsion tizim yadrosini qanday yozish kerak. Assembler maktabi: operatsion tizimni ishlab chiqish

So'nggi ikki yil ichida Habr-ni o'qib chiqib, men OTni ishlab chiqishga bir nechta urinishlarni ko'rdim (xususan: foydalanuvchilar tomonidan va (noma'lum muddatga qoldirildi) va (tashlanmagan, ammo hozirgacha x86-mos keladigan protsessorlarning himoyalangan rejimining tavsifiga o'xshaydi) , bu, shubhasiz, siz x86 uchun OT yozishni bilishingiz kerak); va tugagan tizimning tavsifi (noldan bo'lmasa ham, bunda hech qanday yomon narsa yo'q, ehtimol aksincha)). Ba'zi sabablarga ko'ra, menimcha, deyarli barcha tizim (va dasturning bir qismi) dasturchilar kamida bir marta, lekin o'zlarining operatsion tizimini yozish haqida o'ylashdi. Shu munosabat bilan, ushbu resursning katta jamoasidan 3 ta operatsion tizim kulgili raqamga o'xshaydi. Ko'rinishidan, o'z operatsion tizimi haqida o'ylaydiganlarning ko'pchiligi g'oyadan boshqa joyga bormaydilar, yuklovchini yozgandan so'ng kichik bir qismi to'xtaydi, yadroning bir nechta qismlarini yozadi va faqat umidsiz o'jarlar OTga masofadan o'xshash narsani yaratadilar (taqqos qilganda). Windows/Linux kabi biror narsa bilan) ... Buning sabablari juda ko'p, ammo asosiysi, mening fikrimcha, odamlar OS yozish va disk raskadrovka jarayonining tavsiflari sonining ozligi sababli rivojlanishni to'xtatadilar (ularning ba'zilari hatto boshlashga vaqtlari ham yo'q). amaliy dasturiy ta'minotni ishlab chiqishda sodir bo'ladigan voqealardan ancha farq qiladi.

Ushbu kichik eslatma bilan men shuni ko'rsatmoqchimanki, agar siz to'g'ri boshlasangiz, o'z operatsion tizimingizni yaratishda ayniqsa qiyin narsa yo'q. Kesim ostida OSni noldan yozish harakati bo'yicha qisqa va juda umumiy qo'llanma mavjud.

Qanaqasiga kerak emas boshlash
Iltimos, quyidagi matnni boshqa birovning maqolalari yoki OS yozish bo'yicha qo'llanmalarni ochiq tanqid qilish sifatida qabul qilmang. Ko'pincha baland sarlavhalar ostidagi bunday maqolalarda asosiy e'tibor qandaydir minimal tayyorgarlikni amalga oshirishga qaratiladi va u yadro prototipi sifatida taqdim etiladi. Aslida, yadro tuzilishi va umuman OT qismlarining o'zaro ta'siri haqida o'ylash kerak va bu prototip standart "Salom, dunyo!" - amaliy dasturiy ta'minot olamidagi dastur sifatida ko'rib chiqilishi kerak. Ushbu mulohazalar uchun kichik bahona sifatida shuni aytish kerakki, quyida "Salom, dunyo!"

Bootloader yozish shart emas. Aqlli odamlar Multiboot spetsifikatsiyasini o'ylab topishdi, amalga oshirildi va uning nima ekanligini va undan qanday foydalanishni batafsil tasvirlab berdi. Men o'zimni takrorlamoqchi emasman, shunchaki aytamanki, u ishlaydi, hayotni osonlashtiradi va qo'llanilishi kerak. Aytgancha, spetsifikatsiyani to'liq o'qish yaxshiroqdir, u qisqa va hatto misollarni o'z ichiga oladi.

OTni to'liq montaj tilida yozish shart emas. Bu unchalik yomon emas, aksincha - tez va kichik dasturlar har doim yuqori hurmatga sazovor bo'ladi. Ushbu tilni rivojlantirish uchun ko'proq harakat talab qilinganligi sababli, assemblerdan foydalanish faqat ishtiyoqning pasayishiga va natijada OS manbalarini orqa fonga tashlashga olib keladi.

Video xotirasiga maxsus shrift yuklash va rus tilida biror narsani ko'rsatishning hojati yo'q. Buning ma'nosi yo'q. Ingliz tilidan foydalanish ancha oson va ko'p qirrali va shriftni o'zgartirishni keyinroq qoldiring, uni qattiq diskdan fayl tizimi drayveri orqali yuklang (shu bilan birga, boshlashdan ko'ra ko'proq narsani qilish uchun qo'shimcha rag'bat bo'ladi).

Tayyorgarlik
Boshlash uchun, har doimgidek, kelgusi ish hajmi haqida bir oz tasavvurga ega bo'lish uchun umumiy nazariya bilan tanishishingiz kerak. Ko'rib chiqilayotgan masala bo'yicha yaxshi manbalar E. Tanenbaumning kitoblari bo'lib, ular Habré'da OS yozish bo'yicha boshqa maqolalarda allaqachon aytib o'tilgan. Mavjud tizimlarni tavsiflovchi maqolalar ham mavjud va turli xil qo'llanmalar / pochta ro'yxatlari / maqolalar / misollar / OSni ishlab chiqishda noto'g'ri saytlar mavjud bo'lib, ularning ba'zilariga havolalar maqolaning oxirida berilgan.

Dastlabki ta'lim dasturidan so'ng siz asosiy savollarni hal qilishingiz kerak:

  • maqsadli arxitektura - x86 (haqiqiy / himoyalangan / uzoq rejim), PowerPC, ARM, ...
  • yadro / OS arxitekturasi - monolit, modulli monolit, mikroyadro, ekzokernel, turli gibridlar
  • til va uning kompilyatori - C, C ++, ...
  • yadro fayl formati - elf, a.out, coff, binar, ...
  • rivojlanish muhiti (ha, bu ham muhim rol o'ynaydi) - IDE, vim, emacs, ...
Keyinchalik, tanlangan va quyidagi yo'nalishlar bo'yicha bilimingizni chuqurlashtirishingiz kerak:
  • video xotira va u bilan ishlash - ishning isboti sifatida xulosa eng boshidan kerak
  • HAL (Hardware Abstraction layer) - bir nechta apparat arxitekturasini qo'llab-quvvatlasa ham va yadroning eng past darajadagi qismlarini jarayonlar, semaforlar va boshqalar kabi mavhum narsalarni amalga oshirishdan malakali ravishda ajratish rejalashtirilmagan bo'lsa ham, ortiqcha bo'lmaydi.
  • xotirani boshqarish - jismoniy va virtual
  • bajarilishini nazorat qilish - jarayonlar va iplar, ularni rejalashtirish
  • qurilma boshqaruvi - drayverlar
  • virtual fayl tizimlari - turli fayl tizimlarining mazmuniga yagona interfeysni ta'minlash
  • API (Application Programming Interface) - ilovalar yadroga qanday kirishadi
  • IPC (Interprocess Communication) - ertami-kechmi jarayonlar aloqa qilishiga to'g'ri keladi
Asboblar
Tanlangan til va ishlab chiqish vositalarini hisobga olgan holda, siz kelajakda skriptlarni yozish orqali yig'ishni, tasvirni tayyorlashni va ishga tushirishni maksimal darajada osonlashtirish va tezlashtirish imkonini beradigan yordam dasturlari va ularning sozlamalarini tanlashingiz kerak. loyiha bilan virtual mashina. Keling, ushbu fikrlarning har biriga biroz batafsilroq to'xtalib o'tamiz:
  • make, cmake, ... kabi har qanday standart vositalar qurish uchun mos keladi ... Bu erda bog'lovchi skriptlari va Multiboot sarlavhasini qo'shish uchun (maxsus yozilgan) yordamchi dasturlar, nazorat summalari yoki boshqa har qanday maqsadda foydalanish mumkin.
  • tasvirni tayyorlash, uni o'rnatish va fayllarni nusxalash demakdir. Shunga ko'ra, rasm faylining formati tanlangan bo'lishi kerak, shunda ham o'rnatish / nusxa ko'chirish yordam dasturi, ham virtual mashina uni qo'llab-quvvatlaydi. Tabiiyki, hech kim yig'ilishning yakuniy qismi sifatida ham, emulyatorni ishga tushirishga tayyorgarlik sifatida ham ushbu nuqtadan harakatlarni bajarishni taqiqlamaydi. Bularning barchasi maxsus vositalarga va ulardan foydalanish uchun tanlangan variantlarga bog'liq.
  • virtual mehnat mashinasini ishga tushirishni anglatmaydi, lekin siz avval tasvirni o'chirishni unutmasligingiz kerak (bu nuqtada o'chirish, chunki virtual mashinani ishga tushirishdan oldin bu operatsiyada haqiqiy ma'no yo'q). Bundan tashqari, emulyatorni disk raskadrovka rejimida ishga tushirish uchun skriptga ega bo'lish ortiqcha bo'lmaydi (agar mavjud bo'lsa).
Agar oldingi barcha amallarni bajargan bo'lsangiz, yadro sifatida yuklanadigan va ekranda biror narsani ko'rsatadigan minimal dastur yozishingiz kerak. Tanlangan vositalarning noqulayliklari yoki kamchiliklari aniqlansa, ularni (kamchiliklarni) yo'q qilish kerak, yoki eng yomon holatda, ularni tabiiy ravishda qabul qilish kerak.

Ushbu bosqichda siz kelajakda foydalanishni rejalashtirgan ishlab chiqish vositalarining ko'plab xususiyatlarini sinab ko'rishingiz kerak. Masalan, modullarni GRUB-ga yuklash yoki rasm o'rniga virtual mashinada jismoniy disk / bo'lim / flesh-diskdan foydalanish.

Ushbu bosqich muvaffaqiyatli o'tgandan so'ng, haqiqiy rivojlanish boshlanadi.

Ish vaqtini qo'llab-quvvatlash
Yuqori darajadagi tillarda yozish taklif qilinganligi sababli, odatda kompilyator paketi mualliflari tomonidan amalga oshiriladigan ba'zi til xususiyatlarini qo'llab-quvvatlashga e'tibor berish kerak. Masalan, C ++ uchun bu quyidagilarni o'z ichiga oladi:
  • stekdagi ma'lumotlar blokini dinamik ravishda taqsimlash funktsiyasi
  • to'p bilan ishlash
  • ma'lumotlar blokidan nusxa ko'chirish funktsiyasi (memcpy)
  • dasturga kirish nuqtasi funksiyasi
  • global ob'ektlarning konstruktorlari va destruktorlariga qo'ng'iroqlar
  • istisnolar bilan ishlash uchun bir qator funktsiyalar
  • Amalga oshirilmagan sof virtual funktsiyalar uchun stub
“Salom, dunyo!” yozayotganda. bu funktsiyalarning yo'qligi o'zini hech qanday tarzda his qilmasligi mumkin, lekin kod qo'shilgandan so'ng, bog'lovchi qoniqtirilmagan bog'liqliklar haqida shikoyat qila boshlaydi.

Tabiiyki, standart kutubxonani darhol eslatib o'tish kerak. To'liq amalga oshirish shart emas, lekin funksionallikning asosiy to'plamini amalga oshirishga arziydi. Keyin kodlash ancha tanish va tezroq bo'ladi.

Nosozliklarni tuzatish
Ushbu maqolaning oxirida disk raskadrovka haqida nima deyilganini ko'rmang. Aslida, bu OTni ishlab chiqishda juda jiddiy va qiyin masala, chunki bu erda odatiy vositalar qo'llanilmaydi (ba'zi istisnolardan tashqari).

Siz quyidagilarni maslahat berishingiz mumkin:

  • berilgan uchun, disk raskadrovka chiqish
  • "tuzatish vositasi" ga darhol chiqish bilan tasdiqlang (keyingi xatboshiga qarang)
  • konsol tuzatuvchisining ba'zi o'xshashligi
  • emulyator tuzatuvchini, belgilar jadvallarini yoki boshqa narsalarni ulashga imkon beradimi yoki yo'qligini tekshiring
Yadroga o'rnatilgan tuzatuvchisiz, xatolarni topish dahshatli tushga aylanish uchun juda real imkoniyatga ega. Shunday qilib, rivojlanishning qaysidir bosqichida uni yozishdan qochib bo'lmaydi. Va bu muqarrar bo'lgani uchun, uni oldindan yozishni boshlash va shu bilan rivojlanishingizni sezilarli darajada osonlashtirish va ko'p vaqtni tejash yaxshiroqdir. Nosozliklarni tuzatish tizimning normal ishlashiga minimal ta'sir ko'rsatishi uchun disk raskadrovkani yadrodan mustaqil ravishda amalga oshirish imkoniyatiga ega bo'lish muhimdir. Foydali bo'lishi mumkin bo'lgan bir necha turdagi buyruqlar mavjud:
  • Ba'zi standart disk raskadrovka operatsiyalari: to'xtash nuqtalari, qo'ng'iroqlar to'plami, qiymatlarni chiqarish, dumpni chop etish, ...
  • rejalashtiruvchining bajarish navbati yoki turli statistik ma'lumotlar kabi turli xil foydali ma'lumotlarni ko'rsatish uchun buyruqlar (bu birinchi qarashda ko'rinadigan darajada foydasiz emas)
  • turli tuzilmalar holatining izchilligini tekshirish uchun buyruqlar: bo'sh / ishlatilgan xotira ro'yxatlari, yig'ish yoki xabarlar navbati
Rivojlanish
Keyinchalik, siz OS ning asosiy elementlarini yozishingiz va disk raskadrovka qilishingiz kerak, ular hozirgi vaqtda uning barqaror ishlashini va kelajakda - oson kengaytirilishi va moslashuvchanligini ta'minlashi kerak. Xotira menejerlari / jarayonlar / (boshqa narsa) bilan bir qatorda, drayverlar va fayl tizimlarining interfeysi juda muhimdir. Qurilmalar / FS turlarining barcha turlarini hisobga olgan holda ularning dizayniga alohida e'tibor bilan yondashish kerak. Albatta, siz ularni vaqt o'tishi bilan o'zgartirishingiz mumkin, ammo bu juda og'riqli va xatolarga moyil jarayon (va yadroni disk raskadrovka qilish oson ish emas), shuning uchun esda tuting - ularni amalga oshirishni boshlashdan oldin ushbu interfeyslar haqida kamida o'n marta o'ylab ko'ring. .
SDK bilan o'xshashlik
Loyihaning rivojlanishi bilan unga yangi drayverlar va dasturlar qo'shilishi kerak. Ehtimol, ikkinchi drayverda (ehtimol ma'lum bir turdagi) / dasturda ba'zi umumiy xususiyatlar sezilarli bo'ladi (katalog tuzilishi, boshqaruv fayllarini yaratish, modullar o'rtasidagi bog'liqliklarning spetsifikatsiyasi, asosiy yoki tizim so'rovlarini qayta ishlovchilarda takrorlangan kod (masalan,). , agar haydovchilarning o'zlari qurilma bilan mosligini tekshirsa) )). Agar shunday bo'lsa, bu sizning operatsion tizimingiz uchun har xil turdagi dasturlar uchun shablonlarni ishlab chiqish zaruratining belgisidir.

U yoki bu turdagi dasturlarni yozish jarayonini tavsiflovchi hujjatlarga ehtiyoj qolmaydi. Ammo standart elementlardan bo'sh joy yasashga arziydi. Bu nafaqat dasturlarni qo'shishni osonlashtiradi (mavjud dasturlarni nusxalash va keyin ularni o'zgartirish orqali amalga oshirilishi mumkin, lekin bu ko'proq vaqt talab etadi), balki interfeyslarda, formatlarda yoki o'zgarishlarda ularni yangilashni ham osonlashtiradi. boshqa bir narsa. Ko'rinib turibdiki, bunday o'zgarishlar ideal bo'lmasligi kerak, ammo OTni ishlab chiqish atipik narsa bo'lgani uchun, potentsial noto'g'ri qarorlar qabul qilish uchun juda ko'p joylar mavjud. Ammo qabul qilingan qarorlarning noto'g'riligini tushunish, har doimgidek, ular amalga oshirilgandan keyin biroz vaqt o'tgach paydo bo'ladi.

Keyingi harakatlar
Muxtasar qilib aytganda, operatsion tizimlar (va birinchi navbatda ularning qurilmasi haqida) haqida o'qing, tizimingizni rivojlantiring (aslida sur'at muhim emas, asosiysi umuman to'xtab qolmaslik va vaqti-vaqti bilan yangi kuchlar va g'oyalar bilan loyihaga qaytish) va undagi xatolarni tuzatish tabiiydir (qaysi birini topish uchun ba'zan tizimni ishga tushirish va u bilan "o'ynash" kerak). Vaqt o'tishi bilan, ishlab chiqish jarayoni osonlashadi va osonlashadi, xatolar kamroq uchraydi va siz "umidsiz o'jarlar" ro'yxatiga qo'shilasiz, ular o'z operatsion tizimini ishlab chiqish g'oyasining bema'niligiga qaramay, hali ham qildi.

Ushbu maqolalar turkumi past darajadagi dasturlashga, ya'ni kompyuter arxitekturasiga, operatsion tizimlarga, assembler tilida dasturlashga va tegishli sohalarga bag'ishlangan. Hozirgacha ikki xabrayuzchi - iley va pehat yozuvchilik bilan shug'ullanadi. Ko'pgina o'rta maktab o'quvchilari, talabalar va professional dasturchilar uchun bu mavzularni o'rganish juda qiyin bo'lib chiqadi. Past darajadagi dasturlash bo'yicha juda ko'p adabiyotlar va kurslar mavjud, ammo ulardan to'liq va keng qamrovli rasm olish qiyin. Assembler va operatsion tizimlar bo'yicha bir yoki ikkita kitobni o'qib chiqqach, hech bo'lmaganda umumiy ma'noda temir, kremniy va ko'plab dasturlardan iborat bu murakkab tizim - kompyuterning aslida qanday ishlashini tasavvur qilish qiyin.

Har kim o'quv muammosini o'zicha hal qiladi. Kimdir ko'p adabiyotlarni o'qiydi, kimdir tezda amaliyotga o'tishga va yo'lda tushunishga harakat qiladi, kimdir do'stlariga o'rganayotganini tushuntirishga harakat qiladi. Va biz ushbu yondashuvlarni birlashtirishga qaror qildik. Shunday qilib, ushbu maqolalar kursida biz oddiy operatsion tizimni qanday yozishni bosqichma-bosqich ko'rsatamiz. Maqolalar umumiy ko'rinishga ega bo'ladi, ya'ni ular to'liq nazariy ma'lumotlarni o'z ichiga olmaydi, ammo biz har doim yaxshi nazariy materiallarga havolalar berishga va yuzaga keladigan barcha savollarga javob berishga harakat qilamiz. Bizda aniq reja yo'q, shuning uchun yo'lda sizning fikr-mulohazalaringizni inobatga olgan holda ko'plab muhim qarorlar qabul qilinadi.

Ehtimol, biz sizga va o'zimizga noto'g'ri qarorning barcha oqibatlarini to'liq tushunishga, shuningdek, ba'zi texnik ko'nikmalarni rivojlantirishga imkon berish uchun rivojlanish jarayonini ataylab to'xtatib qo'yamiz. Shuning uchun siz bizning qarorlarimizni yagona to'g'ri deb qabul qilmasligingiz va bizga ko'r-ko'rona ishonmasligingiz kerak. Yana bir bor ta'kidlaymizki, biz o'quvchilarning maqolalarni muhokama qilishda faol bo'lishini kutamiz, bu esa keyingi maqolalarni ishlab chiqish va yozishning umumiy jarayoniga kuchli ta'sir qilishi kerak. Ideal holda, vaqt o'tishi bilan tizimni ishlab chiqishda ba'zi o'quvchilarni ko'rishni xohlaymiz.

Faraz qilamizki, o'quvchi allaqachon assembly va C tillari asoslari, shuningdek, kompyuter arxitekturasining asosiy tushunchalari bilan tanish. Ya'ni, biz registr yoki, aytaylik, tasodifiy kirish xotirasi nima ekanligini tushuntirmaymiz. Agar sizda etarli bilim bo'lmasa, har doim qo'shimcha adabiyotlarga murojaat qilishingiz mumkin. Maqolaning oxirida havolalarning qisqacha ro'yxati va yaxshi maqolalari bo'lgan saytlarga havolalar mavjud. Bundan tashqari, Linuxdan foydalanish imkoniyatiga ega bo'lish maqsadga muvofiqdir, chunki barcha kompilyatsiya ko'rsatmalari ushbu tizim uchun maxsus beriladi.

Va endi - nuqtaga yaqinroq. Maqolaning qolgan qismida biz klassik "Salom dunyo" dasturini yozamiz. Bizning Salom dunyomiz biroz aniq bo'lib chiqadi. U hech qanday operatsion tizimdan ishlamaydi, balki to'g'ridan-to'g'ri, ya'ni "yalang'och metallda" ishlaydi. To'g'ridan-to'g'ri kod yozishni davom ettirishdan oldin, keling, buni qanday amalga oshirishga harakat qilayotganimizni aniqlaymiz. Va buning uchun siz kompyuteringizni yuklash jarayonini ko'rib chiqishingiz kerak.

Shunday qilib, sevimli kompyuteringizni oling va tizim blokidagi eng katta tugmani bosing. Biz quvnoq ekranni ko'ramiz, tizim bloki karnay bilan xursand bo'lib signal beradi va bir muncha vaqt o'tgach, operatsion tizim yuklanadi. Siz tushunganingizdek, operatsion tizim qattiq diskda saqlanadi va bu erda savol tug'iladi: operatsion tizim sehrli ravishda RAMga qanday yuklangan va ishlashni boshlagan?

Siz bilishingiz kerak: har qanday kompyuterda bo'lgan tizim buning uchun javobgardir va uning nomi - yo'q, Windows emas, tilingizni pishadi - bu BIOS deb ataladi. Uning nomi asosiy kirish-chiqish tizimi, ya'ni asosiy kirish-chiqish tizimi degan ma'noni anglatadi. BIOS anakartdagi kichik mikrosxemada joylashgan va katta ON tugmasini bosgandan so'ng darhol boshlanadi. BIOS uchta asosiy vazifani bajaradi:

  1. Barcha ulangan qurilmalarni (protsessor, klaviatura, monitor, operativ xotira, video karta, bosh, qo'llar, qanotlar, oyoqlar va dumlar ...) aniqlang va ularning ishlashini tekshiring. Bunga POST dasturi (Power On Self Test) javob beradi. Agar muhim apparat topilmasa, unda hech qanday dasturiy ta'minot yordam bera olmaydi va bu vaqtda tizim dinamiki qandaydir dahshatli narsani chiyillaydi va OT OTga umuman etib bormaydi. Keling, qayg'uli haqida gapirmaylik, deylik, bizda to'liq ishlaydigan kompyuter bor, xursand bo'ling va ikkinchi BIOS funktsiyasini ko'rib chiqishga o'ting:
  2. Operatsion tizimni apparat bilan ishlash uchun asosiy funktsiyalar to'plami bilan ta'minlash. Masalan, BIOS funktsiyalari orqali siz ekranda matnni ko'rsatishingiz yoki klaviaturadan ma'lumotlarni o'qishingiz mumkin. Shuning uchun u asosiy kiritish-chiqarish tizimi deb ataladi. Odatda, operatsion tizim bu funksiyalarga uzilishlar orqali kirishadi.
  3. Operatsion tizim yuklagichini ishga tushirish. Bunday holda, qoida tariqasida, yuklash sektori o'qiladi - axborot tashuvchining birinchi sektori (floppi, qattiq disk, CD, flesh-disk). So'rov vositasining tartibi BIOS SETUP-da o'rnatilishi mumkin. Yuklash sektorida ba'zan asosiy yuklovchi deb ataladigan dastur mavjud. Taxminan aytganda, bootloaderning vazifasi operatsion tizimni ishga tushirishdir. Operatsion tizimning yuklash jarayoni juda aniq va uning xususiyatlariga juda bog'liq bo'lishi mumkin. Shuning uchun, asosiy yuklovchi to'g'ridan-to'g'ri OS ishlab chiquvchilari tomonidan yoziladi va o'rnatish vaqtida yuklash sektoriga yoziladi. Bootloader ishga tushirilganda, protsessor haqiqiy rejimda.
Qayg'uli yangilik: yuklash moslamasining hajmi atigi 512 bayt bo'lishi kerak. Nega juda kam? Buning uchun biz floppi qurilmasi bilan tanishishimiz kerak. Mana ma'lumot beruvchi rasm:

Rasmda disk diskining yuzasi ko'rsatilgan. Floppy disk 2 ta sirtga ega. Har bir sirtda halqa shaklidagi izlar (treklar) mavjud. Har bir trek sektorlar deb ataladigan kichik, kemerli qismlarga bo'linadi. Shunday qilib, tarixan floppi sektori 512 bayt hajmiga ega. Diskdagi eng birinchi sektor yuklash sektori BIOS tomonidan 0x7C00 ofsetida nol xotira segmentiga o'qiladi va keyin boshqaruv shu manzilga o'tkaziladi.Yuklash moslamasi odatda xotiraga OTning o'zi emas, balki boshqa yuklovchi yuklaydi. dastur diskda saqlanadi, lekin ba'zi sabablarga ko'ra (ehtimol, bu o'lchamda) bitta sektorga to'g'ri kelmaydi. Va hozirgacha bizning OS rolini oddiy Hello World bajarayotganligi sababli, bizning asosiy maqsadimiz kompyuterni, hatto bitta sektorda bo'lsa ham, bizning operatsion tizimimizning mavjudligiga ishontiring va uni ishga tushiring.

Yuklash sektori qanday ishlaydi? Kompyuterda yuklash sektori uchun yagona talab shundaki, uning oxirgi ikki bayti 0x55 va 0xAA qiymatlarini o'z ichiga oladi - yuklash sektori imzosi. Shunday qilib, nima qilishimiz kerakligi allaqachon ko'proq yoki kamroq aniq. Keling, kodni yozamiz! Yuqoridagi kod yasm assembler uchun yozilgan.

Bo'lim .text use16 org 0x7C00; dasturimiz 0x7C00 startda yuklanadi: mov ax, cs mov ds, ax; ma'lumotlar segmentini tanlang mov si, xabar cld; satr buyruqlari uchun yo'nalish mov ah, 0x0E; BIOS funktsiyasi raqami mov bh, 0x00; video xotira sahifasi puts_loop: lodsb; keyingi belgini al testiga yuklang al, al; null belgisi jz puts_loop_exit int 0x10 qatorining oxirini bildiradi; BIOS funksiyasini chaqiring jmp puts_loop puts_loop_exit: jmp $; abadiy tsikl xabari: db "Salom Dunyo!", 0 tugatish: marta 0x1FE-finish + start db 0 db 0x55, 0xAA; yuklash sektori imzosi

Ushbu qisqa dastur bir qator muhim tushuntirishlarni talab qiladi. Assembler (tilni emas, dasturni nazarda tutyapman) teglar va o'zgaruvchilar (puts_loop, puts_loop_exit, xabar) manzillarini to'g'ri hisoblashi uchun org 0x7C00 liniyasi kerak. Shunday qilib, biz unga dastur 0x7C00 manzilida xotiraga yuklanishi haqida xabar beramiz.
Qatorlarda
mov ax, cs mov ds, ax
ma'lumotlar segmenti (ds) kod segmentiga (cs) tenglashtiriladi, chunki bizning dasturimizda ma'lumotlar ham, kod ham bir segmentda saqlanadi.

Shundan so'ng, "Salom dunyo!" xabari tsiklda belgilar bo'yicha ko'rsatiladi. Buning uchun 0x10 uzilishning 0x0E funksiyasidan foydalaniladi. U quyidagi parametrlarga ega:
AH = 0x0E (funktsiya raqami)
BH = video sahifa raqami (hali bezovta qilmang, 0 ni belgilang)
AL = ASCII belgilar kodi

"Jmp $" qatorida dastur osilib turadi. Va to'g'ri, unga qo'shimcha kodni bajarishga hojat yo'q. Biroq, kompyuter qayta ishlashi uchun siz qayta ishga tushirishingiz kerak bo'ladi.

"0x1FE-finish + start db 0" qatorida dastur kodining qolgan qismi (oxirgi ikki baytdan tashqari) nollar bilan to'ldiriladi. Bu shunday amalga oshiriladiki, kompilyatsiyadan so'ng yuklash sektori imzosi dasturning oxirgi ikki baytida paydo bo'ladi.

Biz dastur kodini aniqladik, endi bu baxtni tuzishga harakat qilaylik. Kompilyatsiya qilish uchun bizga, aslida, assembler kerak - yuqorida aytib o'tilgan yasm. U ko'pgina Linux omborlarida mavjud. Dasturni quyidagicha kompilyatsiya qilish mumkin:

$ yasm -f bin -o salom.bin salom.asm

Olingan hello.bin fayli floppi diskning yuklash sektoriga yozilishi kerak. Bu shunga o'xshash tarzda amalga oshiriladi (albatta, fd o'rniga siz diskingiz nomini almashtirishingiz kerak).

$ dd bo'lsa = hello.bin of = / dev / fd

Har kimda floppi drayvlar va floppi disklar qolmaganligi sababli, siz virtual mashinadan foydalanishingiz mumkin, masalan, qemu yoki VirtualBox. Buning uchun siz yuklovchimiz yordamida floppi disk tasvirini yasashingiz va uni "virtual floppi diskka"ga joylashtirishingiz kerak.
Disk tasvirini yarating va uni nol bilan to'ldiring:

$dd agar = / dev / nol / = disk.img bs = 1024 soni = 1440

Biz dasturimizni rasmning boshida yozamiz:
$dd agar = hello.bin of = disk.img conv = notrunc

Olingan rasmni qemu-da ishga tushiring:
$ qemu -fda disk.img -boot a

Ishga tushgandan so'ng, siz "Salom dunyo!" quvonchli qatorli qemu oynasini ko'rishingiz kerak. Bu birinchi maqolani yakunlaydi. Fikr va takliflaringizni ko'rishdan xursand bo'lamiz.

Yadro ishlab chiqish haqli ravishda mashaqqatli vazifa hisoblanadi, ammo har kim eng oddiy yadroni yozishi mumkin. Yadroni buzish sehriga teginish uchun siz shunchaki ba'zi konventsiyalarga rioya qilishingiz va assemblerni o'rganishingiz kerak. Ushbu maqolada biz buni barmoqlarimiz bilan qanday qilishni ko'rsatamiz.


Salom Dunyo!

Keling, x86 mos keladigan tizimlarda GRUB orqali yuklanadigan yadro yozamiz. Bizning birinchi yadromiz ekranda xabarni ko'rsatadi va u erda to'xtaydi.

X86 mashinalari qanday yuklanadi

Yadroni qanday yozish haqida o'ylashdan oldin, keling, kompyuter qanday ishga tushishini va boshqaruvni yadroga o'tkazishini ko'rib chiqaylik. X86 protsessor registrlarining aksariyati yuklangandan so'ng ma'lum qiymatlarga ega. Instruction Pointer Register (EIP) protsessor tomonidan bajariladigan buyruqning manzilini o'z ichiga oladi. Uning qattiq kodlangan qiymati 0xFFFFFF0. Ya'ni, x86 protsessori har doim 0xFFFFFF0 fizik manzilidan ishlashni boshlaydi. Bu 32 bitli manzil maydonining oxirgi 16 bayti. Ushbu manzil "qayta tiklash vektori" deb ataladi.

Chipsetdagi xotira kartasi 0xFFFFFF0 manzili RAMga emas, balki BIOS-ning ma'lum bir qismiga tegishli ekanligini aytadi. Biroq, BIOS tezroq kirish uchun o'zini RAMga ko'chiradi - bu jarayon soya nusxasini yaratish, soya qilish deb ataladi. Shunday qilib, 0xFFFFFFF0 manzili faqat BIOS o'zi nusxa ko'chirgan xotira joyiga o'tish yo'riqnomasini o'z ichiga oladi.

Shunday qilib, BIOS ishlay boshlaydi. Birinchidan, u sozlamalarda ko'rsatilgan tartibda yuklashingiz mumkin bo'lgan qurilmalarni qidiradi. U ommaviy axborot vositalarida yuklanadigan disklarni oddiylardan ajratib turadigan "sehrli raqam" mavjudligini tekshiradi: agar birinchi sektordagi 511 va 512 baytlar 0xAA55 bo'lsa, u holda disk yuklanadi.

BIOS yuklash moslamasini topishi bilanoq, u 0x7C00 manzilidan boshlab birinchi sektor tarkibini operativ xotiraga ko'chiradi va keyin bajarilishni ushbu manzilga o'tkazadi va hozirgina yuklagan kodni bajarishni boshlaydi. Ushbu kod bootloader deb ataladi.

Yuklovchi yadroni 0x100000 jismoniy manziliga yuklaydi. Aynan u x86 uchun mashhur yadrolarning ko'pchiligi tomonidan qo'llaniladi.

Barcha x86-mos protsessorlar "haqiqiy rejim" deb nomlangan ibtidoiy 16-bitli rejimda boshlanadi. GRUB yuklash moslamasi CR0 registrining pastki bitini bittaga o'rnatish orqali protsessorni 32 bitli himoyalangan rejimga o'tkazadi. Shuning uchun yadro 32 bitli himoyalangan rejimda yuklashni boshlaydi.

E'tibor bering, GRUB, Linux yadrolari uchun, tegishli yuklash protokolini tanlaydi va yadroni haqiqiy rejimda yuklaydi. Linux yadrolarining o'zi himoyalangan rejimga o'tadi.

Bizga nima kerak

  • X86-ga mos keladigan kompyuter (aniq)
  • Linux,
  • NASM assembler,
  • ld (GNU bog'lovchisi),
  • GRUB.

Assembly tiliga kirish nuqtasi

Albatta, biz hamma narsani C tilida yozishni xohlaymiz, lekin assemblerdan butunlay qochib qutula olmaymiz. Biz x86 assemblerda yadromiz uchun boshlang'ich nuqta bo'ladigan kichik faylni yozamiz. Barcha yig'ish kodi tashqi funktsiyani chaqirishdir, biz uni C da yozamiz va keyin dasturning bajarilishini to'xtatamiz.

Qanday qilib montaj kodini yadromiz uchun boshlang'ich nuqtaga aylantiramiz? Biz ob'ekt fayllarini bog'laydigan va yakuniy bajariladigan yadroni yaratadigan bog'lovchi skriptdan foydalanamiz (quyida batafsilroq tushuntirilgan). Ushbu skriptda biz ikkilik faylni 0x100000 da yuklashni xohlayotganimizni to'g'ridan-to'g'ri ko'rsatamiz. Bu, avvalroq yozganimdek, yuklovchi yadroga kirish nuqtasini ko'rishni kutayotgan manzil.

Mana assembler kodi.

kernel.asm
bit 32-qism .text global start extern kmain start: cli mov esp, stack_space call kmain hlt section .bss resb 8192 stack_space:

Birinchi bit 32 ko'rsatmasi x86 assembler emas, balki 32 bitli rejimda ishlaydigan protsessor uchun kod yaratish uchun NASM direktivasi. Bizning misolimiz uchun bu shart emas, lekin buni aniq bayon qilish yaxshi amaliyotdir.

Ikkinchi qator kod bo'limi sifatida ham tanilgan matn qismini boshlaydi. Bizning barcha kodimiz shu erda bo'ladi.

global yana bir NASM direktivasi bo'lib, u bizning kodimizdagi belgilarni global deb e'lon qiladi. Bu bog'lovchiga bizning kirish nuqtamiz bo'lgan boshlang'ich belgisini topishga imkon beradi.

kmain - bu bizning kernel.c faylimizda aniqlanadigan funksiya. extern funktsiya boshqa joyda e'lon qilinganligini e'lon qiladi.

Keyin kmain ni chaqiradigan va hlt buyrug'i bilan protsessorni to'xtatuvchi start funksiyasi keladi. Interruptlar hlt dan keyin protsessorni uyg'otishi mumkin, shuning uchun avval biz cli (clear interrupts) ko'rsatmasi bilan uzilishlarni o'chirib qo'yamiz.

Ideal holda, biz stek uchun ma'lum hajmdagi xotirani ajratishimiz va stek ko'rsatkichini (xususan) unga yo'naltirishimiz kerak. GRUB buni biz uchun qilganga o'xshaydi va bu nuqtada stek ko'rsatkichi allaqachon o'rnatilgan. Biroq, har qanday holatda, keling, BSS bo'limida biroz xotira ajratamiz va stek ko'rsatkichini uning boshiga qaratamiz. Biz resb ko'rsatmasidan foydalanamiz - u baytlarda ko'rsatilgan xotirani saqlaydi. Keyin ajratilgan xotira qismining chetiga ishora qiluvchi yorliq qoldiriladi. Kmainga qo'ng'iroq qilishdan oldin, stek ko'rsatkichi (esp) mov ko'rsatmasi bilan ushbu hududga yo'naltiriladi.

C yadrosi

kernel.asm faylida kmain () funksiyasini chaqirdik. Shunday qilib, C kodida ijro u erda boshlanadi.

kernel.c
void kmain (void) (const char * str = "mening birinchi yadrom"; char * vidptr = (char *) 0xb8000; unsigned int i = 0; unsigned int j = 0; while (j< 80 * 25 * 2) { vidptr[j] = " "; vidptr = 0x07; j = j + 2; } j = 0; while(str[j] != "\0") { vidptr[i] = str[j]; vidptr = 0x07; ++j; i = i + 2; } return; }

Bizning yadro qiladigan narsa ekranni tozalash va mening birinchi yadrom qatorini chiqarishdir.

Biz qiladigan birinchi narsa - 0xb8000 manziliga ishora qiluvchi vidptr ko'rsatkichini yaratish. Himoyalangan rejimda bu video xotiraning boshlanishi. Matnli ekran xotirasi manzillar maydonining faqat bir qismidir. 0xb8000 manzilidan boshlanadigan kirish/chiqarish ekrani uchun xotira bo'limi ajratilgan - unda 80 ta ASCII belgilardan iborat 25 qator joylashtirilgan.

Matn xotirasidagi har bir belgi biz o‘rganib qolgan 8 bit (1 bayt) emas, balki 16 bit (2 bayt) bilan ifodalanadi. Birinchi bayt ASCII belgilar kodi, ikkinchi bayt esa atribut-baytdir. Bu belgi formatining, shu jumladan rangining ta'rifi.

s yashil rangni qora rangda chop etish uchun biz video xotiraning birinchi baytiga s ni, ikkinchi baytga esa 0x02 qiymatini qo'yishimiz kerak. Bu yerda 0 qora fonni, 2 esa yashil rangni bildiradi. Biz ochiq kul rangdan foydalanamiz, uning kodi 0x07.

Birinchi while siklida dastur 80 ta belgidan iborat barcha 25 qatorni 0x07 atributiga ega boʻsh belgilar bilan toʻldiradi. Bu ekranni tozalaydi.

Ikkinchi while siklida, null bilan tugallangan qatordagi belgilar mening birinchi yadrom video xotiraga yoziladi va har bir belgiga 0x07 ga teng atribut-bayt beriladi. Bu chiziqni chiqarishi kerak.

Tartib

Endi biz kernel.asm ni NASM yordamida obyekt fayliga kompilyatsiya qilishimiz kerak va keyin kernel.c ni boshqa obyekt fayliga kompilyatsiya qilish uchun GCC dan foydalanishimiz kerak. Bizning vazifamiz ushbu ob'ektlarni yuklanadigan bajariladigan yadroga ulashdir. Buning uchun siz bog'lovchi (ld) uchun skript yozishingiz kerak, biz uni argument sifatida beramiz.

link.ld
OUTPUT_FORMAT (elf32-i386) KIRISH (boshlash) bo'limlari (. = 0x100000; .matn: (* (. Matn)) .data: (* (. Ma'lumotlar)) .bss: (* (. Bss)))

Bu erda biz birinchi navbatda bajariladigan faylimiz formatini (OUTPUT_FORMAT) x86 arxitekturasi uchun Unix tizimlari uchun standart ikkilik format bo'lgan 32-bitli ELF (Bajariladigan va Bog'lanadigan Format) sifatida o'rnatdik.

ENTRY bitta argumentni oladi. U bajariladigan fayl uchun kirish nuqtasi bo'lib xizmat qiladigan belgi nomini belgilaydi.

SECTIONS biz uchun eng muhim qismdir. Bu erda biz bajariladigan dasturning tartibini aniqlaymiz. Turli bo'limlar qanday birlashtirilishini va ularning har biri qaerga joylashtirilishini aniqlashimiz mumkin.

SECTIONS ifodasidan keyingi jingalak qavslarda nuqta joylashuv hisoblagichini bildiradi. U SECTIONS blokining boshida avtomatik ravishda 0x0 ga ishga tushiriladi, lekin uni yangi qiymat belgilash orqali o'zgartirish mumkin.

Avvalroq yadro kodi 0x100000 dan boshlanishi kerakligini yozgan edim. Shuning uchun biz pozitsiya hisoblagichini 0x100000 ga o'rnatdik.

.text qatoriga qarang: (* (. Matn)). Yulduzcha har qanday fayl nomiga mos keladigan niqobni o'rnatadi. Shunga ko'ra, * (. Matn) ifodasi barcha kirish fayllaridagi barcha kirish .matn bo'limlarini bildiradi.

Natijada, bog'lovchi barcha ob'ekt fayllarining barcha matn bo'limlarini bajariladigan faylning matn bo'limiga birlashtiradi va ularni pozitsiya hisoblagichida ko'rsatilgan manzilga joylashtiradi. Bizning bajariladigan faylimizning kod bo'limi 0x100000 dan boshlanadi.

Bog'lovchi matn qismini ko'rsatgandan so'ng, joylashuv hisoblagichi 0x100000 va matn qismining o'lchamiga teng. Xuddi shunday, ma'lumotlar va bss bo'limlari birlashtiriladi va joylashuv hisoblagichi tomonidan berilgan manzilga joylashtiriladi.

GRUB va multiboot

Endi barcha fayllarimiz yadro yaratishga tayyor. Ammo yadroni GRUB yordamida yuklayotganimiz uchun yana bir qadam qoldi.

Bootloader yordamida turli xil x86 yadrolarini yuklash standarti mavjud. Bu "multiboot spetsifikatsiyasi" deb ataladi. GRUB faqat unga mos keladigan yadrolarni yuklaydi.

Ushbu spetsifikatsiyaga ko'ra, yadroda dastlabki 8 kilobaytda sarlavha (Multiboot header) bo'lishi mumkin. Ushbu sarlavha uchta maydonni o'z ichiga olishi kerak:

  • sehr- sarlavha aniqlangan 0x1BADB002 "sehrli" raqamini o'z ichiga oladi;
  • bayroqlar- bu maydon biz uchun muhim emas, siz nol qoldirishingiz mumkin;
  • nazorat summasi- nazorat summasi, agar sehr va bayroqlar maydonlariga qo'shilsa, nolga teng bo'lishi kerak.

Bizning kernel.asm faylimiz endi shunday ko'rinadi.

kernel.asm
bit 32 bo'lim .text; multiboot spec align 4 dd 0x1BADB002; magic dd 0x00; flags dd - (0x1BADB002 + 0x00); checksum global start extern kmain start: cli mov esp, stack_space call kmain hltresssection.bss9sce2:1bsspack2

dd ko'rsatmasi 4 baytli qo'sh so'zni belgilaydi.

Yadroni birlashtirish

Shunday qilib, kernel.asm va kernel.c dan ob'ekt faylini yaratish va ularni bizning skriptimiz yordamida bog'lash uchun hamma narsa tayyor. Biz konsolda yozamiz:

$ nasm -f elf32 kernel.asm -o kasm.o

Ushbu buyruq yordamida assembler ELF-32 bit formatida kasm.o faylini yaratadi. Endi navbat GCCga keldi:

$ gcc -m32 -c kernel.c -o kc.o

-c opsiyasi kompilyatsiyadan so'ng faylni bog'lash shart emasligini bildiradi. Biz buni o'zimiz qilamiz:

$ ld -m elf_i386 -T link.ld -o yadro kasm.o kc.o

Ushbu buyruq skriptimiz bilan bog'lovchini ishga tushiradi va yadro deb nomlangan bajariladigan faylni yaratadi.

OGOHLANTIRISH

Yadroni buzish eng yaxshi virtual mashinada amalga oshiriladi. Yadroni GRUB o'rniga QEMU da ishga tushirish uchun qemu-system-i386 -kernel kernel buyrug'idan foydalaning.

GRUBni sozlash va yadroni ishga tushirish

GRUB yadro konventsiyasiga amal qilish uchun yadro fayl nomini talab qiladi<версия>... Shunday qilib, fayl nomini o'zgartiramiz - men o'zimning yadro-701 deb nom beraman.

Endi yadroni / boot katalogiga joylashtiramiz. Bu superfoydalanuvchi imtiyozlarini talab qiladi.

GRUB konfiguratsiya faylida grub.cfg, siz shunga o'xshash narsani qo'shishingiz kerak bo'ladi:

Sarlavha myKernel root (hd0,0) kernel / boot / kernel-701 ro

Agar ko'rsatilgan bo'lsa, yashirin menyu direktivasini olib tashlashni unutmang.

GRUB 2

Yangi tarqatishlarda sukut bo'yicha yuboriladigan GRUB 2 da biz yaratgan yadroni ishga tushirish uchun sizning konfiguratsiyangiz quyidagicha ko'rinishi kerak:

"Yadro 701" menyusi (rootni o'rnatish = "hd0, msdos1" multiboot / boot / kernel-701 ro)

Ushbu qo'shimcha uchun Ruben Laguanaga rahmat.

Kompyuteringizni qayta ishga tushiring va siz yadro ro'yxatini ko'rishingiz kerak! Va uni tanlab, siz o'sha chiziqni ko'rasiz.



Bu sizning asosingiz!

Klaviatura va ekran yordami bilan yadro yozish

Biz GRUB orqali yuklanadigan, himoyalangan rejimda ishlaydigan va ekranga bitta qatorni chop etadigan minimal yadro ustida ishlashni tugatdik. Endi uni kengaytirish va klaviaturadagi belgilarni o'qiy oladigan va ularni ekranda ko'rsatadigan klaviatura drayverini qo'shish vaqti keldi.

Biz kiritish/chiqarish qurilmalari bilan I/U portlari orqali bog‘lanamiz. Aslida, ular faqat kirish / chiqish avtobusidagi manzillardir. O'qish va yozish operatsiyalari uchun maxsus protsessor ko'rsatmalari mavjud.

Portlar bilan ishlash: o'qish va chiqarish

read_port: mov edx, in al, dx ret write_port: mov edx, mov al, out dx, al ret

Kirish / chiqish portlariga x86 to'plamiga kiritilgan kirish va chiqish yo'riqnomalari yordamida kirish mumkin.

Read_port da port raqami argument sifatida uzatiladi. Kompilyator funktsiyani chaqirganda, u barcha argumentlarni stekga suradi. Argument stek ko'rsatkichi yordamida edx registriga ko'chiriladi. dx registri edx registrining pastki 16 bitidir. Bu yerdagi ko'rsatma dx da berilgan port raqamini o'qiydi va natijani al ga qo'yadi. Al registr eax registrining pastki 8 bitidir. Kollej kursidan esingizda bo'lishi mumkinki, funktsiyalar tomonidan qaytarilgan qiymatlar eax registridan o'tkaziladi. Shunday qilib, read_port kirish/chiqarish portlaridan o'qish imkonini beradi.

write_port funksiyasi ham xuddi shunday ishlaydi. Biz ikkita argumentni olamiz: port raqami va yoziladigan ma'lumotlar. Chiqish yo'riqnomasi ma'lumotlarni portga yozadi.

Xalaqit beradi

Endi, drayverni yozishga qaytishdan oldin, protsessor qandaydir qurilma operatsiyani bajarganligini qanday bilishini tushunishimiz kerak.

Eng oddiy yechim - bu qurilmalarni so'roq qilish - ularning holatini doimiy ravishda tsiklda tekshirish. Bu aniq sabablarga ko'ra samarasiz va amaliy emas. Shunday qilib, bu erda uzilishlar o'ynaydi. Uzilish - bu hodisa sodir bo'lganligini bildiruvchi qurilma yoki dastur tomonidan protsessorga yuboriladigan signal. Uzilishlar yordamida biz qurilmalarni so'roq qilish zaruratidan qochib qutulamiz va faqat bizni qiziqtirgan voqealarga javob beramiz.

Programmable Interrupt Controller (PIC) deb nomlangan chip x86 arxitekturasidagi uzilishlar uchun javobgardir. U apparat uzilishlari va marshrutlarini boshqaradi va ularni tegishli tizim uzilishlariga aylantiradi.

Foydalanuvchi qurilmaga biror narsa qilganda, PICga Interrupt Request (IRQ) deb ataladigan impuls yuboriladi. PIC qabul qilingan uzilishni tizim uzilishiga aylantiradi va protsessorga qilayotgan ishni to'xtatish vaqti kelganligi haqida xabar yuboradi. Keyinchalik uzilishlar bilan ishlash yadroning javobgarligidir.

PIC bo'lmasa, biz tizimda mavjud bo'lgan barcha qurilmalarni ulardan birortasi bilan bog'liq voqea sodir bo'lganligini bilish uchun so'rashimiz kerak edi.

Keling, bu klaviatura holatida qanday ishlashini ko'rib chiqaylik. Klaviatura 0x60 va 0x64 portlariga osilgan. 0x60 port ma'lumotlarni yuboradi (tugma bosilganda), 0x64 port esa holatni yuboradi. Biroq, biz ushbu portlarni qachon o'qishni bilishimiz kerak.

Bu erda uzilishlar foydali bo'ladi. Tugma bosilganda, klaviatura IRQ1 uzilish chizig'ida PIC signalini yuboradi. PIC ishga tushirish vaqtida saqlangan ofset qiymatini saqlaydi. U uzilish vektorini hosil qilish uchun ushbu chekinishga kirish qatori raqamini qo'shadi. Keyin protsessor uzilishni qayta ishlash funktsiyasiga uning raqamiga mos keladigan manzilni berish uchun Interrupt Deskriptor Table (IDT) deb nomlangan ma'lumotlar strukturasini qidiradi.

Keyin ushbu manzildagi kod bajariladi va uzilishni boshqaradi.

IDTni sozlash

struct IDT_entry (imzosiz short int offset_lowerbits; unsigned short int selektor; unsigned char nol; unsigned char type_attr; unsigned short int offset_higherbits;); struct IDT_entry IDT; void idt_init (void) (imzosiz uzun klaviatura_manzil; imzosiz uzun id_manzil; imzosiz uzun idt_ptr; keyboard_address = (imzosiz uzun) klaviatura_ishlab chiqaruvchisi; IDT.offset_lowerbits = klaviatura_manzili & 0xffff; IDT.selector; /_tr.ENTOF = 0xffff; IDT.selector = _tr. ENTOF; ID_t.*0 0x8e; / * INTERRUPT_GATE * / IDT.offset_higherbits = (klaviatura_manzili & 0xffff0000) >> 16; yozish_porti (0x20, 0x11); yozish_porti (0xA0, 0x11); yozish_porti (0x21, 0x20, yozish, _02); ); yozish_porti (0xA1, 0x00); yozish_porti (0x21, 0x01); yozish_porti (0xA1, 0x01); yozish_porti (0x21, 0xff); yozish_porti (0xA1, 0xff); id_manzil = (imzoni bekor qilish) IDT; (idt_of) = struct IDT_entry) * IDT_SIZE) + ((idt_address & 0xffff)<< 16); idt_ptr = idt_address >> 16; load_idt (idt_ptr); )

IDT - IDT_entry tuzilmalari massivi. Klaviatura uzilishini ishlov beruvchiga bog‘lashni keyinroq muhokama qilamiz, ammo hozircha PIC qanday ishlashini ko‘rib chiqamiz.

Zamonaviy x86 tizimlari ikkita PIC chipiga ega, ularning har biri sakkizta kirish liniyasiga ega. Biz ularni PIC1 va PIC2 deb ataymiz. PIC1 IRQ0 dan IRQ7 gacha, PIC2 esa IRQ8 dan IRQ15 gacha qabul qiladi. PIC1 buyruqlar uchun 0x20 va ma'lumotlar uchun 0x21 portidan foydalanadi, PIC2 esa buyruqlar uchun 0xA0 va ma'lumotlar uchun 0xA1 portidan foydalanadi.

Ikkala PIC ham Initialization buyruq so'zlari (ICW) deb nomlangan sakkiz bitli so'zlar bilan ishga tushiriladi.

Himoyalangan rejimda ikkala PIC birinchi navbatda ICW1 ishga tushirish buyrug'ini berishlari kerak (0x11). Bu PICga ma'lumotlar portiga yana uchta ishga tushirish so'zini kutish kerakligini aytadi.

Ushbu buyruqlar PIC-ni yuboradi:

  • to'ldirish vektori (ICW2),
  • PIC (ICW3) o'rtasidagi asosiy/qul munosabatlari qanday?
  • atrof-muhit haqida qo'shimcha ma'lumot (ICW4).

Ikkinchi ishga tushirish buyrug'i (ICW2) ham har bir PIC kirishiga yuboriladi. U uzilish raqamini olish uchun satr raqamini qo'shadigan qiymat bo'lgan ofsetni tayinlaydi.

PIC-lar o'zlarining pinlarini bir-birining kirishlariga kaskad qilish imkonini beradi. Bu ICW3 yordamida amalga oshiriladi va har bir bit mos keladigan IRQ uchun kaskad holatini ifodalaydi. Hozircha biz kaskadli qayta yo'naltirishdan foydalanmaymiz va uni nolga o'rnatamiz.

ICW4 qo'shimcha muhit parametrlarini o'rnatadi. PIClar 80x86 rejimida ishlayotganimizni bilishlari uchun biz faqat pastki bitni aniqlashimiz kerak.

Ta-dam! PIC-lar endi ishga tushirildi.

Har bir PICda Interrupt Mask Register (IMR) deb nomlangan ichki sakkiz bitli registr mavjud. U PICga o'tadigan IRQ satrlarining bitmapini saqlaydi. Bit o'rnatilgan bo'lsa, PIC so'rovni e'tiborsiz qoldiradi. Bu shuni anglatadiki, biz mos qiymatni 0 yoki 1 ga o'rnatish orqali ma'lum bir IRQ liniyasini yoqishimiz yoki o'chirishimiz mumkin.

Ma'lumotlar portidan o'qish IMR registridagi qiymatni qaytaradi va yozish registrni o'zgartiradi. Bizning kodimizda, PIC-ni ishga tushirgandan so'ng, biz barcha bitlarni bittaga o'rnatamiz va shu bilan barcha IRQ qatorlarini o'chiramiz. Keyinchalik, klaviatura uzilishlariga mos keladigan chiziqlarni faollashtiramiz. Lekin avval uni o'chirib qo'yaylik!

Agar IRQ liniyalari ishlayotgan bo'lsa, bizning PIC'larimiz IRQda signallarni qabul qilishi va ofset qo'shish orqali ularni uzilish raqamiga aylantirishi mumkin. Klaviaturadan kelgan uzilish soni biz yozadigan ishlov beruvchi funksiya manziliga mos kelishi uchun IDT ni to'ldirishimiz kerak.

IDT da klaviatura ishlagichini qanday uzilish raqamiga ulashimiz kerak?

Klaviatura IRQ1 dan foydalanadi. Bu kirish liniyasi 1 va PIC1 tomonidan qayta ishlanadi. Biz PIC1 ni 0x20 ofset bilan ishga tushirdik (ICW2 ga qarang). Interrupt raqamini olish uchun siz 1 va 0x20 qo'shishingiz kerak, siz 0x21 olasiz. Bu 0x21 ni uzish uchun klaviatura ishlov beruvchisining manzili IDTga bog'langanligini anglatadi.

Vazifa 0x21 uzilish uchun IDTni to'ldirishga to'g'ri keladi. Biz ushbu uzilishni assembler fayliga yozadigan keyboard_handler funksiyasiga joylashtiramiz.

Har bir IDT yozuvi 64 bit uzunlikda. Interruptga mos keladigan yozuvda biz ishlov beruvchi funktsiyasining butun manzilini saqlamaymiz. Buning o'rniga biz uni ikkita 16 bitli bo'laklarga ajratamiz. Pastki bitlar IDT yozuvining dastlabki 16 bitida, yuqori 16 bit esa oxirgi 16 bitda saqlanadi. Bularning barchasi 286 protsessor bilan muvofiqligi uchun amalga oshiriladi. Ko'rib turganingizdek, Intel bunday raqamlarni muntazam ravishda va ko'p joylarda chiqaradi!

IDT yozuvida biz uchun turni ro'yxatdan o'tkazish qoladi, buning barchasi uzilishni ushlab turish uchun qilinganligini ko'rsatadi. Shuningdek, yadro kodi segmentining ofsetini o'rnatishimiz kerak. GRUB biz uchun GDT ni o'rnatadi. Har bir GDT yozuvi 8 bayt uzunlikda bo'lib, bu erda yadro kodi deskriptori ikkinchi segmentdir, shuning uchun uning ofseti 0x08 (tafsilotlar ushbu maqolaga kirmaydi). Uzilish eshigi 0x8e sifatida ifodalanadi. O'rtadagi qolgan 8 bitni nol bilan to'ldiring. Bu klaviatura uzilishiga mos keladigan IDT yozuvini to'ldiradi.

IDT xaritasi tugagach, protsessorga IDT qayerda joylashganligini aytishimiz kerak bo'ladi. Buning uchun assembler ko'rsatmasi lidt mavjud, u bitta operandni oladi. Bu IDT ni tavsiflovchi strukturaga tutqichga ko'rsatgich.

Deskriptor bilan hech qanday qiyinchilik yo'q. U baytlardagi IDT hajmini va uning manzilini o'z ichiga oladi. Men uni yanada ixcham qilish uchun massivdan foydalandim. Xuddi shunday, struktura yordamida identifikatorni to'ldirishingiz mumkin.

Idr_ptr o'zgaruvchisida biz load_idt () funksiyasidagi lidt ko'rsatmalariga o'tadigan ko'rsatgichga egamiz.

Load_idt: mov edx, lidt sti ret

Bundan tashqari, load_idt () funktsiyasi sti ko'rsatmasidan foydalanganda uzilishni qaytaradi.

IDT-ni to'ldirib, yuklaganimizdan so'ng, biz yuqorida aytib o'tgan uzilish maskasidan foydalanib, IRQ klaviaturasiga kirishimiz mumkin.

Void kb_init (void) (write_port (0x21, 0xFD);)

0xFD - 11111101 - faqat IRQ1 (klaviatura) ni yoqing.

Funktsiya - klaviatura uzilishlarini ishlov beruvchi

Shunday qilib, biz 0x21 uzilish uchun IDT yozuvini yaratish orqali klaviatura uzilishlarini keyboard_handler funksiyasiga muvaffaqiyatli bog‘ladik. Bu funksiya har qanday tugmani bosganingizda chaqiriladi.

Keyboard_handler: keyboard_handler_main-ga qo'ng'iroq qiling

Bu funksiya C da yozilgan boshqa funksiyani chaqiradi va iret sinfidagi ko'rsatmalar yordamida boshqaruvni qaytaradi. Bu yerda biz butun ishlov beruvchimizni yozishimiz mumkin, lekin C tilida kodlash ancha oson, shuning uchun keling, u yerga o'taylik. Boshqarish uzilishni boshqarish funksiyasidan uzilib qolgan dasturga qaytganda ret o'rniga iret / iretd ko'rsatmalaridan foydalanish kerak. Ushbu ko'rsatma klassi bayroq registrini ko'taradi, u uzilish chaqirilganda stekga suriladi.

Void keyboard_handler_main (void) (imzosiz belgi holati; char kalit kodi; / * Biz EOI * yozamiz / write_port (0x20, 0x20); status = read_port (KEYBOARD_STATUS_PORT); / * Agar bufer bo'sh bo'lmasa, pastki holat biti o'rnatiladi * / agar (holat va 0x01) (kalit kodi = o'qish_porti (KEYBOARD_DATA_PORT); agar (kalit kodi)< 0) return; vidptr = keyboard_map; vidptr = 0x07; } }

Bu erda biz birinchi navbatda EOI (End Of Interrupt) signalini PIC buyruq portiga yozib beramiz. Shundagina PIC keyingi uzilish so‘rovlariga ruxsat beradi. Biz ikkita portni o'qishimiz kerak: ma'lumotlar porti 0x60 va buyruq porti (aka holat porti) 0x64.

Avvalo, biz statusni olish uchun 0x64 portini o'qiymiz. Pastki holat biti nolga teng bo'lsa, bufer bo'sh va o'qish uchun hech qanday ma'lumot yo'q. Boshqa hollarda, biz 0x60 ma'lumotlar portini o'qiy olamiz. U bizga bosilgan tugma kodini beradi. Har bir kod bitta tugmaga mos keladi. Kodlarni mos belgilar bilan solishtirish uchun keyboard_map.h faylida aniqlangan oddiy belgilar qatoridan foydalanamiz. Keyin biz yadroning birinchi versiyasida ishlatgan texnikadan foydalangan holda belgi ekranda ko'rsatiladi.

Kodni murakkablashtirmaslik uchun bu erda men faqat a dan z gacha kichik harflar va 0 dan 9 gacha raqamlarni qayta ishlayman. Siz bemalol maxsus belgilarni qo'shishingiz mumkin, Alt, Shift va Caps Lock. Buyruq portining chiqishidan tugma bosilgan yoki bo'shatilganligini bilib, tegishli harakatni amalga oshirishingiz mumkin. Xuddi shunday, siz har qanday klaviatura yorliqlarini o'chirish kabi maxsus funktsiyalarga bog'lashingiz mumkin.

Endi siz yadroni yaratishingiz, uni haqiqiy mashinada yoki emulyatorda (QEMU) xuddi birinchi qismdagi kabi ishga tushirishingiz mumkin.

0 dan 1 gacha bo'lgan operatsion tizim GitHub-da nashr etilgan va 2000 dan ortiq yulduz va 100 vilkaga ega. Nomidan ko'rinib turibdiki, uni o'qib chiqqandan so'ng, siz o'zingizning operatsion tizimingizni yaratishingiz mumkin - va, ehtimol, dasturchilar dunyosida bir nechta narsa sovuqroq bo'lishi mumkin.

Ushbu kitob orqali siz quyidagilarni o'rganasiz:

  • Uskuna texnik hujjatlari asosida operatsion tizimni yaratishni o'rganing. Bu haqiqiy dunyoda shunday ishlaydi, tezkor javoblar uchun Googledan foydalana olmaysiz.
  • Kompyuter komponentlarining dasturiy ta'minotdan tortib apparatgacha bir-biri bilan o'zaro ta'sirini tushuning.
  • O'zingiz kod yozishni o'rganing. Kodni ko'r-ko'rona nusxalash o'rganish egri chizig'i emas, siz haqiqatan ham muammolarni qanday hal qilishni o'rganasiz. Aytgancha, ko'r-ko'rona nusxa ko'chirish ham xavflidir.
  • Past darajadagi rivojlanish uchun tanish vositalarni o'zlashtiring.
  • Assembler tili bilan tanishing.
  • Qanday dasturlardan tuzilganligini va operatsion tizim ularni qanday ishlashini bilib oling. Biz qiziquvchilar uchun ushbu mavzu bo'yicha qisqacha ma'lumot berdik.
  • GDB va QEMU yordamida dasturni to'g'ridan-to'g'ri apparatda qanday disk raskadrovka qilishni aniqlang.
  • Dasturlash tili C. Quyidagi amallar orqali uni tezda o'zlashtirishingiz mumkin.
  • Linux bo'yicha asosiy bilimlar. Buning uchun bizning veb-saytimizda o'qish kifoya.
  • Fizikadagi asosiy bilimlar: atomlar, elektronlar, protonlar, neytronlar, kuchlanish.

Operatsion tizimni yozish uchun nimani bilishingiz kerak

Operatsion tizimni yaratish dasturlashning eng qiyin vazifalaridan biridir, chunki u kompyuterning ishlashi bo'yicha keng va murakkab bilimlarni talab qiladi. Qaysilari? Keling, buni quyida ko'rib chiqaylik.

OS nima

Operatsion tizim (OT) - bu kompyuter texnikasi va uning resurslari bilan ishlaydigan dasturiy ta'minot bo'lib, kompyuterning apparat va dasturiy ta'minoti o'rtasidagi ko'prikdir.

Birinchi avlod kompyuterlarida operatsion tizimlar mavjud emas edi. Birinchi kompyuterlardagi dasturlar tizimning to'g'ridan-to'g'ri ishlashi, periferik qurilmalar bilan aloqa va hisob-kitoblar uchun kodni o'z ichiga olgan bo'lib, ularni bajarish uchun ushbu dastur yozilgan. Bunday hizalanish tufayli hatto mantiqiy jihatdan oddiy bo'lgan dasturlarni ham dasturiy ta'minotda amalga oshirish qiyin edi.

Kompyuterlar xilma-xil va murakkablashgan sari, ham OT, ham dastur sifatida ishlaydigan dasturlarni yozish oddiygina noqulay bo'lib qoldi. Shuning uchun, dasturlarni yozishni osonlashtirish uchun kompyuter egalari dasturiy ta'minotni ishlab chiqishni boshladilar. Shunday qilib operatsion tizimlar paydo bo'ldi.

OS maxsus dasturlarni ishga tushirish uchun kerak bo'lgan hamma narsani ta'minlaydi. Ularning ko'rinishi endi dasturlarga kompyuter ishining butun hajmini nazorat qilishning hojati yo'qligini anglatardi (bu inkapsulyatsiyaning ajoyib namunasidir). Endi dasturlar operatsion tizim bilan ishlash uchun kerak edi va tizimning o'zi resurslarga g'amxo'rlik qildi va tashqi qurilmalar (klaviatura, printer) bilan ishlaydi.

Operatsion tizimlar tarixi haqida qisqacha

C tili

Yuqorida aytib o'tilganidek, OT yozish uchun bir nechta yuqori darajadagi dasturlash tillari mavjud. Biroq, ulardan eng mashhuri C.

Bu tilni oʻrganishni shu yerdan boshlashingiz mumkin. Ushbu resurs sizni asosiy tushunchalar bilan tanishtiradi va sizni yanada murakkab vazifalarga tayyorlaydi.

Learn C the Hard Way - bu yana bir kitobning nomi. Odatdagi nazariyaga qo'shimcha ravishda, u ko'plab amaliy echimlarni o'z ichiga oladi. Ushbu qo'llanma tilning barcha jihatlarini qamrab oladi.

Yoki siz ushbu kitoblardan birini tanlashingiz mumkin:

  • Kernigan va Ritchining C dasturlash tili;
  • Perry va Miller tomonidan "C Programming Absolute Beginner Guide".

OS rivojlanishi

Kompyuter fanlari, assembler tili va C haqida bilishingiz kerak bo'lgan hamma narsani o'zlashtirganingizdan so'ng, siz to'g'ridan-to'g'ri OS rivojlanishi haqida kamida bir yoki ikkita kitobni o'qishingiz kerak. Buni amalga oshirish uchun ba'zi manbalar:

Linux noldan. Bu erda Linux operatsion tizimini yaratish jarayoni ko'rib chiqiladi (qo'llanma ko'plab tillarga, shu jumladan rus tiliga ham tarjima qilingan). Bu erda, boshqa darsliklarda bo'lgani kabi, sizga barcha kerakli asosiy bilimlar beriladi. Ularga tayanib, siz OS yaratishda o'zingizni sinab ko'rishingiz mumkin. OTning dasturiy qismini yanada professional qilish uchun darslikka qo'shimchalar mavjud: "