चल उदाहरण
तकनीकी रूप से, एक कार्यक्रम जो बिना ओएस के चलता है, एक ओएस है। तो आइए देखते हैं कि कैसे कुछ माइनसक्यूल हैलो वर्ल्ड OSes बनाएं और चलाएं।
इस GitHub रेपो पर नीचे दिए गए सभी उदाहरणों का कोड मौजूद है ।
आरंभिक क्षेत्र
X86 पर, सबसे सरल और निम्नतम स्तर की चीज़ जो आप कर सकते हैं, वह है मास्टर बूट सेक्टर (MBR) , जो एक प्रकार का बूट सेक्टर है , और फिर इसे डिस्क पर स्थापित करें।
यहाँ हम एक printf
कॉल के साथ एक बनाते हैं:
printf '\364%509s\125\252' > main.img
sudo apt-get install qemu-system-x86
qemu-system-x86_64 -hda main.img
परिणाम:
उबंटू 18.04, QEMU 2.11.1 पर परीक्षण किया गया।
main.img
निम्नलिखित शामिल हैं:
\364
0xf4
हेक्स में ऑक्टल == में: एक hlt
निर्देश के लिए एन्कोडिंग , जो सीपीयू को काम करना बंद करने के लिए कहता है।
इसलिए हमारा कार्यक्रम कुछ भी नहीं करेगा: केवल शुरू और रोकें।
हम अष्टाधारी का उपयोग करते हैं क्योंकि \x
हेक्स संख्या POSIX द्वारा निर्दिष्ट नहीं हैं।
हम इस एन्कोडिंग को आसानी से प्राप्त कर सकते हैं:
echo hlt > a.asm
nasm -f bin a.asm
hd a
लेकिन 0xf4
एन्कोडिंग को बेशक इंटेल मैनुअल पर भी प्रलेखित किया गया है।
%509s
509 रिक्त स्थान का उत्पादन। फ़ाइल को बाइट 510 तक भरने की आवश्यकता है।
\125\252
ऑक्टल == में 0x55
इसके बाद 0xaa
: हार्डवेयर द्वारा आवश्यक मैजिक बाइट्स। उन्हें बाइट्स 511 और 512 होना चाहिए।
यदि मौजूद नहीं है, तो हार्डवेयर इसे बूट करने योग्य डिस्क के रूप में नहीं मानेगा।
ध्यान दें कि कुछ भी किए बिना, कुछ अक्षर स्क्रीन पर पहले से ही मुद्रित हैं। वे फर्मवेयर द्वारा मुद्रित किए जाते हैं, और सिस्टम की पहचान करने के लिए कार्य करते हैं।
वास्तविक हार्डवेयर पर चलाएँ
एमुलेटर मजेदार हैं, लेकिन हार्डवेयर असली सौदा है।
ध्यान दें कि यह खतरनाक है, और आप अपनी डिस्क को गलती से मिटा सकते हैं: केवल पुरानी मशीनों पर ऐसा करें जिसमें महत्वपूर्ण डेटा नहीं है! या इससे भी बेहतर, रास्पबेरी पाई जैसे डेबोर्ड, नीचे दिए गए एआरएम उदाहरण देखें।
एक विशिष्ट लैपटॉप के लिए, आपको कुछ करना होगा:
छवि को USB स्टिक में जलाएं (आपके डेटा को नष्ट कर देगा!):
sudo dd if=main.img of=/dev/sdX
कंप्यूटर पर USB प्लग करें
इसे चालू करो
इसे USB से बूट करने के लिए कहें।
इसका मतलब है कि हार्ड डिस्क से पहले फर्मवेयर को USB चुनें।
यदि वह आपकी मशीन का डिफ़ॉल्ट व्यवहार नहीं है, तो पावर-ऑन के बाद Enter, F12, ESC या अन्य ऐसी अजीब कुंजियाँ मारते रहें, जब तक आपको बूट मेनू नहीं मिल जाता है जहाँ आप USB से बूट करना चुन सकते हैं।
उन मेनू में खोज क्रम को कॉन्फ़िगर करना अक्सर संभव होता है।
उदाहरण के लिए, अपने पुराने लेनोवो थिंकपैड T430, UEFI BIOS 1.16 पर, मैं देख सकता हूं:
नमस्ते दुनिया
अब जब हमने एक न्यूनतम कार्यक्रम बना लिया है, तो आइए हम एक नमस्ते दुनिया की ओर रुख करें।
स्पष्ट प्रश्न है: IO कैसे करें? कुछ विकल्प:
- फर्मवेयर के लिए पूछें, उदाहरण के लिए BIOS या यूईएफआई, अगर हमारे लिए करना है
- वीजीए: विशेष मेमोरी क्षेत्र जो स्क्रीन पर लिखे जाने पर प्रिंट हो जाता है। संरक्षित मोड पर इस्तेमाल किया जा सकता है।
- ड्राइवर लिखें और सीधे डिस्प्ले हार्डवेयर पर बात करें। यह इसे करने का "उचित" तरीका है: अधिक शक्तिशाली, लेकिन अधिक जटिल।
सीरियल पोर्ट । यह एक बहुत ही सरल मानकीकृत प्रोटोकॉल है जो होस्ट टर्मिनल से वर्ण भेजता और पुनर्प्राप्त करता है।
स्रोत ।
यह दुर्भाग्य से अधिकांश आधुनिक लैपटॉप पर उजागर नहीं है, लेकिन विकास बोर्डों के लिए जाने का सामान्य तरीका है, नीचे दिए गए एआरएम उदाहरण देखें।
यह वास्तव में शर्म की बात है, क्योंकि इस तरह के इंटरफेस उदाहरण के लिए लिनक्स कर्नेल को डिबग करने के लिए वास्तव में उपयोगी हैं ।
चिप्स की डिबग सुविधाओं का उपयोग करें। उदाहरण के लिए एआरएम ने उनकी सेमीहोस्टिंग को कॉल किया । वास्तविक हार्डवेयर पर, इसके लिए कुछ अतिरिक्त हार्डवेयर और सॉफ़्टवेयर सहायता की आवश्यकता होती है, लेकिन एमुलेटर पर यह एक मुफ्त सुविधाजनक विकल्प हो सकता है। उदाहरण है ।
यहाँ हम एक BIOS उदाहरण करेंगे क्योंकि यह x86 पर सरल है। लेकिन ध्यान दें कि यह सबसे मजबूत तरीका नहीं है।
main.S
.code16
mov $msg, %si
mov $0x0e, %ah
loop:
lodsb
or %al, %al
jz halt
int $0x10
jmp loop
halt:
hlt
msg:
.asciz "hello world"
link.ld
SECTIONS
{
. = 0x7c00;
.text :
{
__start = .;
*(.text)
. = 0x1FE;
SHORT(0xAA55)
}
}
इकट्ठा और के साथ लिंक:
gcc -c -g -o main.o main.S
ld --oformat binary -o main.img -T linker.ld main.o
परिणाम:
पर परीक्षण किया गया: लेनोवो थिंकपैड T430, UEFI BIOS 1.16। एक Ubuntu 18.04 होस्ट पर डिस्क उत्पन्न हुई।
मानक उपयोगकर्ता भूमि विधानसभा निर्देशों के अलावा, हमारे पास:
.code16
: GAS को 16-बिट कोड आउटपुट करने के लिए कहता है
cli
: अक्षम सॉफ्टवेयर बाधा। वे प्रोसेसर को फिर से चलाने के बाद शुरू कर सकते हैंhlt
int $0x10
: एक BIOS कॉल करता है। यह वह है जो पात्रों को एक-एक करके प्रिंट करता है।
महत्वपूर्ण लिंक झंडे हैं:
--oformat binary
: कच्चे बाइनरी असेंबली कोड को आउटपुट करें, इसे ELF फ़ाइल के अंदर न डालें जैसा कि नियमित यूजरलैंड एक्जीक्यूटिव के लिए होता है।
विधानसभा के बजाय सी का उपयोग करें
चूंकि सी असेंबली के लिए संकलित है, मानक पुस्तकालय के बिना सी का उपयोग करना बहुत सरल है, आपको मूल रूप से बस आवश्यकता है:
- एक लिंकर स्क्रिप्ट सही जगह पर स्मृति में चीजों को रखने के लिए
- झंडे जो जीसीसी को मानक पुस्तकालय का उपयोग नहीं करने के लिए कहते हैं
- एक छोटे विधानसभा प्रवेश बिंदु
main
, जो विशेष रूप से C राज्य के लिए आवश्यक सेट करता है :
TODO: GitHub पर कुछ x86 उदाहरण लिंक करें। यहाँ एक ARM एक है जिसे मैंने बनाया है ।
यदि आप मानक पुस्तकालय का उपयोग करना चाहते हैं तो चीजें अधिक मजेदार होती हैं, क्योंकि हमारे पास लिनक्स कर्नेल नहीं है, जो पोसिक्स के माध्यम से सी मानक पुस्तकालय कार्यक्षमता का बहुत अधिक कार्यान्वयन करता है ।
लिनक्स जैसे पूर्ण विकसित ओएस पर जाने के बिना कुछ संभावनाएं शामिल हैं:
एआरएम
एआरएम में, सामान्य विचार समान हैं। मैंने अपलोड किया है:
रास्पबेरी पाई के लिए, https://github.com/dwelch67/raspberrypi आज सबसे लोकप्रिय ट्यूटोरियल उपलब्ध है।
X86 से कुछ अंतरों में शामिल हैं:
IO सीधे जादू के पते पर लिखकर किया जाता है, कोई निर्देश in
और out
निर्देश नहीं है।
इसे मेमोरी मैपेड IO कहा जाता है ।
कुछ वास्तविक हार्डवेयर के लिए, रास्पबेरी पाई की तरह, आप फर्मवेयर (BIOS) को डिस्क छवि में स्वयं जोड़ सकते हैं।
यह एक अच्छी बात है, क्योंकि यह उस फर्मवेयर को अधिक पारदर्शी बनाता है।
फर्मवेयर
सच में, आपका बूट सेक्टर पहला सॉफ्टवेयर नहीं है जो सिस्टम के सीपीयू पर चलता है।
वास्तव में सबसे पहले चलने वाला तथाकथित फर्मवेयर है , जो एक सॉफ्टवेयर है:
- हार्डवेयर निर्माताओं द्वारा बनाया गया
- आमतौर पर बंद स्रोत लेकिन सी-आधारित होने की संभावना है
- केवल-पढ़ने के लिए मेमोरी में संग्रहीत किया जाता है, और इसलिए विक्रेता की सहमति के बिना संशोधित करना कठिन / असंभव है।
प्रसिद्ध फर्मों में शामिल हैं:
- BIOS : पुराने सभी-वर्तमान x86 फर्मवेयर। सीबीआईओएस QEMU द्वारा उपयोग किया जाने वाला डिफ़ॉल्ट ओपन सोर्स कार्यान्वयन है।
- UEFI : BIOS उत्तराधिकारी, बेहतर मानकीकृत, लेकिन अधिक सक्षम, और अविश्वसनीय रूप से फूला हुआ।
- कोरबूट : नोबल क्रॉस आर्क ओपन सोर्स प्रयास
फर्मवेयर कुछ इस तरह करता है:
प्रत्येक हार्ड डिस्क, USB, नेटवर्क आदि पर लूप तब तक रखें जब तक आपको कुछ बूट करने योग्य न मिल जाए।
जब हम QEMU चलाते हैं, तो -hda
कहते हैं कि main.img
हार्डवेयर से जुड़ी एक हार्ड डिस्क है, और
hda
पहला प्रयास किया जाना है, और इसका उपयोग किया जाता है।
रैम मेमोरी एड्रेस में पहले 512 बाइट्स लोड करें 0x7c00
, सीपीयू के आरआईपी को वहां रखें, और इसे चलने दें
डिस्प्ले पर बूट मेनू या BIOS प्रिंट कॉल जैसी चीजें दिखाएं
फर्मवेयर OS जैसी कार्यक्षमता प्रदान करता है, जिस पर अधिकांश OS-es निर्भर करते हैं। उदाहरण के लिए पायथन सबसेट को BIOS / UEFI पर चलाने के लिए पोर्ट किया गया है: https://www.youtube.com/watch?v=bYQ_lq5dcvM
यह तर्क दिया जा सकता है कि फ़र्मवेयर OSes से अविभाज्य हैं, और यह फर्मवेयर केवल "सच" है नंगे धातु प्रोग्रामिंग एक कर सकता है।
जैसा कि यह कोरओएस देव डालता है :
कठिन हिस्सा
जब आप एक पीसी को पावर करते हैं, तो चिपसेट (नॉर्थब्रिज, साउथब्रिज और सुपरियो) बनाने वाले चिप्स अभी तक ठीक से शुरू नहीं किए गए हैं। भले ही BIOS ROM सीपीयू से उतना ही दूर है जितना कि यह हो सकता है, यह सीपीयू द्वारा सुलभ है, क्योंकि यह होना चाहिए, अन्यथा सीपीयू को निष्पादित करने के लिए कोई निर्देश नहीं होगा। इसका मतलब यह नहीं है कि BIOS ROM पूरी तरह से मैप किया गया है, आमतौर पर नहीं। लेकिन बूट प्रक्रिया को पूरा करने के लिए बस पर्याप्त मैप किया गया है। कोई अन्य उपकरण, बस इसे भूल जाओ।
जब आप QEMU के तहत Coreboot चलाते हैं, तो आप Coreboot की उच्च परतों और पेलोड के साथ प्रयोग कर सकते हैं, लेकिन QEMU निम्न स्तर के स्टार्टअप कोड के साथ प्रयोग करने का बहुत कम अवसर प्रदान करता है। एक बात के लिए, रैम शुरू से ही सही काम करता है।
पोस्ट BIOS प्रारंभिक स्थिति
हार्डवेयर में कई चीजों की तरह, मानकीकरण कमजोर है, और जिन चीजों पर आपको भरोसा नहीं करना चाहिए उनमें से एक रजिस्टर की प्रारंभिक स्थिति है जब आपका कोड BIOS के बाद चलना शुरू होता है।
तो अपने आप को एक एहसान करो और निम्नलिखित जैसे कुछ इनिशियलाइज़ेशन कोड का उपयोग करें : https://stackoverflow.com/a/32509555/5255245
रजिस्टरों को पसंद करते हैं %ds
और %es
महत्वपूर्ण दुष्प्रभाव होते हैं, इसलिए आपको उन्हें शून्य करना चाहिए, भले ही आप उन्हें स्पष्ट रूप से उपयोग न कर रहे हों।
ध्यान दें कि कुछ एमुलेटर असली हार्डवेयर की तुलना में अच्छे होते हैं और आपको एक अच्छा प्रारंभिक राज्य देते हैं। फिर जब आप असली हार्डवेयर पर चलते हैं, तो सब कुछ टूट जाता है।
ग्नू ग्रुब मल्टीबूट
बूट सेक्टर सरल हैं, लेकिन वे बहुत सुविधाजनक नहीं हैं:
- आपके पास प्रति डिस्क केवल एक OS हो सकता है
- लोड कोड को वास्तव में छोटा होना चाहिए और 512 बाइट्स में फिट होना चाहिए। इसे int 0x13 BIOS कॉल के साथ हल किया जा सकता है ।
- आपको बहुत सारे स्टार्टअप खुद करने होंगे, जैसे संरक्षित मोड में जाना
यह उन कारणों के लिए है कि GNU GRUB ने एक अधिक सुविधाजनक फ़ाइल प्रारूप बनाया जिसे मल्टीबूट कहा जाता है।
न्यूनतम कार्यशील उदाहरण: https://github.com/cirosantilli/x86-bare-metal-examples/tree/d217b180be4220a0b4a453f31275d38e69a99a0e/multiboot/hello-world
मैं अपने GitHub उदाहरण रेपो पर भी इसका उपयोग करता हूं ताकि आसानी से USB को एक लाख बार जलाए बिना वास्तविक हार्डवेयर पर सभी उदाहरणों को चलाने में सक्षम हो। QEMU पर यह इस तरह दिखता है:
यदि आप अपने OS को एक मल्टीबूट फ़ाइल के रूप में तैयार करते हैं, तो GRUB इसे एक नियमित फाइल सिस्टम के अंदर खोजने में सक्षम है।
ओएस छवियों को नीचे रखकर यह सबसे अधिक विकृत करता है /boot
।
मल्टीबूट फाइलें मूल रूप से एक विशेष हेडर के साथ एक ईएलएफ फ़ाइल हैं। वे GRUB द्वारा यहां निर्दिष्ट हैं: https://www.gnu.org/software/grub/manual/multiboot/multib.html.html
आप मल्टीबूट फ़ाइल को बूट करने योग्य डिस्क में बदल सकते हैं grub-mkrescue
।
एल टोरिटो
सीडी को जलाया जा सकने वाला प्रारूप: https://en.wikipedia.org/wiki/El_Torito_%28CD-ROM_standard%29
हाइब्रिड छवि का उत्पादन करना भी संभव है जो आईएसओ या यूएसबी पर काम करता है। यह grub-mkrescue
( उदाहरण के साथ ) किया जा सकता है , और make isoimage
उपयोग करने पर लिनक्स कर्नेल द्वारा भी किया जाता है isohybrid
।
साधन