ऑपरेटिंग सिस्टम के बिना प्रोग्राम कैसे चलाएं?


239

बिना ऑपरेटिंग सिस्टम के आप सभी अपने आप एक प्रोग्राम कैसे चलाते हैं? क्या आप असेंबली प्रोग्राम बना सकते हैं जिसे कंप्यूटर स्टार्टअप पर लोड और चला सकता है, जैसे कि कंप्यूटर को फ्लैश ड्राइव से बूट करें और यह सीपीयू पर चलने वाले प्रोग्राम को चलाता है?


4
किस वास्तुकला पर? 86? एआरएम?
Kissiel

1
मैं सामान्य रूप से बोल रहा था, लेकिन सबसे अधिक संभावना x86 या x64
user2320609

2
हाँ, प्रोसेसर कैसे बूट होता है। असेंबली का होना जरूरी नहीं है, सी का उपयोग अक्सर बूटस्ट्रैप के लिए थोड़ी सी असम के साथ किया जाता है और शायद कुछ अन्य समर्थन करते हैं।
ओल्ड_टाइमर

24
इसके बारे में सोचो: अगर ऐसी कोई क्षमता नहीं थी, तो ओएस खुद कैसे शुरू और चलाएगा? :)
सेवा अलेक्सेयेव

जवाबों:


153

बिना ऑपरेटिंग सिस्टम के आप सभी अपने आप एक प्रोग्राम कैसे चलाते हैं?

आप अपने द्विआधारी कोड को एक ऐसे स्थान पर रखते हैं जहां प्रोसेसर रिबूट करने के बाद दिखता है (जैसे एआरएम पर पता 0)।

क्या आप असेंबली प्रोग्राम बना सकते हैं जिसे कंप्यूटर स्टार्टअप पर लोड और चला सकता है (जैसे फ्लैश ड्राइव से कंप्यूटर को बूट करें और यह उस प्रोग्राम को चलाता है जो ड्राइव पर है)?

प्रश्न का सामान्य उत्तर: यह किया जा सकता है। इसे अक्सर "नंगे धातु प्रोग्रामिंग" के रूप में जाना जाता है। फ्लैश ड्राइव से पढ़ने के लिए, आप जानना चाहते हैं कि यूएसबी क्या है, और आप इस यूएसबी के साथ काम करने के लिए कुछ ड्राइवर रखना चाहते हैं। इस ड्राइव पर प्रोग्राम कुछ विशेष प्रारूप में भी होगा, कुछ विशेष फाइलसिस्टम पर ... यह कुछ ऐसा है जो बूट लोडर आमतौर पर करते हैं, लेकिन आपके प्रोग्राम में अपना स्वयं का बूटलोडर शामिल हो सकता है, इसलिए यह केवल स्व-निहित है, यदि फर्मवेयर केवल होगा कोड का एक छोटा सा ब्लॉक लोड करें।

कई एआरएम बोर्ड आपको उन चीजों में से कुछ करने देते हैं। कुछ के पास मूल लोडर की मदद के लिए बूट लोडर हैं।

यहाँ आपको रास्पबेरी पाई पर एक बुनियादी ऑपरेटिंग सिस्टम करने के लिए एक महान ट्यूटोरियल मिल सकता है।

संपादित करें: यह लेख, और पूरे wiki.osdev.org आपके अधिकांश सवालों का सामना करेंगे । http://wiki.osdev.org/Introduction

इसके अलावा, यदि आप हार्डवेयर पर सीधे प्रयोग नहीं करना चाहते हैं, तो आप इसे एक वर्चुअल मशीन के रूप में चला सकते हैं, जो हाइमूज़र जैसे किमू का उपयोग कर रहा है। यहां वर्चुअलाइज्ड एआरएम हार्डवेयर पर सीधे "हैलो वर्ल्ड" चलाने का तरीका देखें ।


723

चल उदाहरण

आइए कुछ शून्य से नंगे धातु के हैलो वर्ल्ड प्रोग्राम बनाएं और चलाएं जो बिना OS के चलते हैं:

हम उन्हें क्यूईएमयू एमुलेटर पर भी यथासंभव प्रयास करेंगे, क्योंकि यह सुरक्षित और विकास के लिए अधिक सुविधाजनक है। QEMU परीक्षण पूर्व-पैक QEMU 2.11.1 के साथ उबंटू 18.04 होस्ट पर रहा है।

नीचे और अधिक सभी x86 उदाहरणों का कोड इस GitHub रेपो पर मौजूद है ।

एक्स 86 वास्तविक हार्डवेयर पर उदाहरण कैसे चलाएं

याद रखें कि वास्तविक हार्डवेयर पर चल रहे उदाहरण खतरनाक हो सकते हैं, जैसे आप अपनी डिस्क को मिटा सकते हैं या गलती से हार्डवेयर को ईंट कर सकते हैं: केवल पुरानी मशीनों पर ऐसा करें जिसमें महत्वपूर्ण डेटा शामिल नहीं है! या इससे भी बेहतर, रास्पबेरी पाई जैसे सस्ते अर्ध-डिस्पोजेबल डिबोर्ड का उपयोग करें, नीचे एआरएम उदाहरण देखें।

एक विशिष्ट x86 लैपटॉप के लिए, आपको कुछ करना होगा:

  1. छवि को USB स्टिक में जलाएं (आपके डेटा को नष्ट कर देगा!):

    sudo dd if=main.img of=/dev/sdX
    
  2. कंप्यूटर पर USB प्लग करें

  3. इसे चालू करो

  4. इसे USB से बूट करने के लिए कहें।

    इसका मतलब है कि हार्ड डिस्क से पहले फर्मवेयर पिक यूएसबी।

    यदि वह आपकी मशीन का डिफ़ॉल्ट व्यवहार नहीं है, तो पावर-ऑन के बाद Enter, F12, ESC या अन्य ऐसी अजीब कुंजियाँ मारते रहें, जब तक कि आपको एक बूट मेनू न मिल जाए जहाँ आप USB से बूट करना चुन सकते हैं।

    उन मेनू में खोज क्रम को कॉन्फ़िगर करना अक्सर संभव होता है।

उदाहरण के लिए, मेरे T430 पर मैं निम्नलिखित देखता हूं।

चालू करने के बाद, यह तब है जब मुझे बूट मेनू में प्रवेश करने के लिए Enter दबाया जाना है:

यहां छवि विवरण दर्ज करें

फिर, यहां मुझे बूट डिवाइस के रूप में यूएसबी का चयन करने के लिए F12 दबाना होगा:

यहां छवि विवरण दर्ज करें

वहां से, मैं USB को बूट डिवाइस के रूप में इस तरह से चुन सकता हूं:

यहां छवि विवरण दर्ज करें

वैकल्पिक रूप से, बूट ऑर्डर को बदलने के लिए और उच्च प्राथमिकता के लिए यूएसबी का चयन करने के लिए इसलिए मुझे मैन्युअल रूप से हर बार इसका चयन करने की आवश्यकता नहीं है, मैं "स्टार्टअप इंटरप्ट मेनू" स्क्रीन पर एफ 1 को मारूंगा, और फिर इसे नेविगेट करूंगा:

यहां छवि विवरण दर्ज करें

आरंभिक क्षेत्र

X86 पर, सबसे सरल और निम्नतम स्तर की चीज जो आप कर सकते हैं वह है मास्टर बूट सेक्टर (MBR) , जो एक प्रकार का बूट सेक्टर है , और फिर इसे डिस्क पर स्थापित करें।

यहाँ हम एक printfकॉल के साथ एक बनाते हैं:

printf '\364%509s\125\252' > main.img
sudo apt-get install qemu-system-x86
qemu-system-x86_64 -hda main.img

परिणाम:

यहां छवि विवरण दर्ज करें

ध्यान दें कि कुछ भी किए बिना, कुछ अक्षर स्क्रीन पर पहले से ही मुद्रित हैं। वे फर्मवेयर द्वारा मुद्रित किए जाते हैं, और सिस्टम की पहचान करने के लिए कार्य करते हैं।

और T430 पर हमें ब्लिंकिंग कर्सर के साथ एक खाली स्क्रीन मिलती है:

यहां छवि विवरण दर्ज करें

main.img निम्नलिखित शामिल हैं:

  • \3640xf4हेक्स में ओक्टल == में: एक hltनिर्देश के लिए एन्कोडिंग , जो सीपीयू को काम करना बंद करने के लिए कहता है।

    इसलिए हमारा कार्यक्रम कुछ भी नहीं करेगा: केवल शुरू और रोकें।

    हम अष्टाधारी का उपयोग करते हैं क्योंकि \xहेक्स संख्या POSIX द्वारा निर्दिष्ट नहीं हैं।

    हम इस एन्कोडिंग को आसानी से प्राप्त कर सकते हैं:

    echo hlt > a.S
    as -o a.o a.S
    objdump -S a.o
    

    कौन से आउटपुट:

    a.o:     file format elf64-x86-64
    
    
    Disassembly of section .text:
    
    0000000000000000 <.text>:
       0:   f4                      hlt
    

    लेकिन यह इंटेल मैनुअल के पाठ्यक्रम में भी प्रलेखित है।

  • %509s509 रिक्त स्थान का उत्पादन। फ़ाइल को बाइट 510 तक भरने की आवश्यकता है।

  • \125\252अष्टक में == 0x55उसके बाद 0xaa

    ये 2 आवश्यक मैजिक बाइट्स हैं जो बाइट्स 511 और 512 होने चाहिए।

    BIOS बूट करने वालों की तलाश में हमारे सभी डिस्क के माध्यम से जाता है, और यह केवल उन बूट करने योग्य समझता है जिनके पास दो मैजिक बाइट्स हैं।

    यदि मौजूद नहीं है, तो हार्डवेयर इसे बूट करने योग्य डिस्क के रूप में नहीं मानेगा।

यदि आप printfमास्टर नहीं हैं , तो आप इसकी सामग्री की पुष्टि कर सकते हैं main.img:

hd main.img

जो उम्मीद दिखाता है:

00000000  f4 20 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |.               |
00000010  20 20 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |                |
*
000001f0  20 20 20 20 20 20 20 20  20 20 20 20 20 20 55 aa  |              U.|
00000200

जहाँ 20ASCII में एक स्थान है।

BIOS फर्मवेयर डिस्क से उन 512 बाइट्स को पढ़ता है, उन्हें मेमोरी में डालता है, और उन्हें निष्पादित करने के लिए पीसी को पहले बाइट पर सेट करता है।

हैलो वर्ल्ड बूट सेक्टर

अब जब हमने एक न्यूनतम कार्यक्रम बना लिया है, तो आइए हम एक नमस्ते दुनिया की ओर रुख करें।

स्पष्ट प्रश्न है: IO कैसे करें? कुछ विकल्प:

  • फर्मवेयर, उदाहरण के लिए BIOS या UEFI से पूछें, हमारे लिए यह करने के लिए

  • वीजीए: विशेष मेमोरी क्षेत्र जो स्क्रीन पर लिखे जाने पर प्रिंट हो जाता है। संरक्षित मोड में इस्तेमाल किया जा सकता है।

  • ड्राइवर लिखें और डिस्प्ले हार्डवेयर पर सीधे बात करें। यह इसे करने का "उचित" तरीका है: अधिक शक्तिशाली, लेकिन अधिक जटिल।

  • सीरियल पोर्ट । यह एक बहुत ही सरल मानकीकृत प्रोटोकॉल है जो होस्ट टर्मिनल से वर्ण भेजता और प्राप्त करता है।

    डेस्कटॉप पर, यह इस तरह दिखता है:

    यहां छवि विवरण दर्ज करें

    स्रोत

    यह दुर्भाग्य से अधिकांश आधुनिक लैपटॉप पर उजागर नहीं है, लेकिन विकास बोर्डों के लिए जाने का सामान्य तरीका है, नीचे दिए गए एआरएम उदाहरण देखें।

    यह वास्तव में एक शर्म की बात है, क्योंकि इस तरह के इंटरफेस उदाहरण के लिए लिनक्स कर्नेल को डिबग करने के लिए वास्तव में उपयोगी हैं ।

  • चिप्स की डिबग सुविधाओं का उपयोग करें। उदाहरण के लिए, एआरएम ने उन्हें सेमीहोस्टिंग कहा । वास्तविक हार्डवेयर पर, इसके लिए कुछ अतिरिक्त हार्डवेयर और सॉफ़्टवेयर सहायता की आवश्यकता होती है, लेकिन एमुलेटर पर यह एक मुफ्त सुविधाजनक विकल्प हो सकता है। उदाहरण है

यहां हम एक 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
{
    /* The BIOS loads the code from the disk to this location.
     * We must tell that to the linker so that it can properly
     * calculate the addresses of symbols we might jump to.
     */
    . = 0x7c00;
    .text :
    {
        __start = .;
        *(.text)
        /* Place the magic boot bytes at the end of the first 512 sector. */
        . = 0x1FE;
        SHORT(0xAA55)
    }
}

इकट्ठा और के साथ लिंक:

as -g -o main.o main.S
ld --oformat binary -o main.img -T link.ld main.o
qemu-system-x86_64 -hda main.img

परिणाम:

यहां छवि विवरण दर्ज करें

और T430 पर:

यहां छवि विवरण दर्ज करें

पर परीक्षण किया गया: लेनोवो थिंकपैड T430, UEFI BIOS 1.16। एक Ubuntu 18.04 होस्ट पर डिस्क उत्पन्न हुई।

मानक उपयोगकर्ता भूमि विधानसभा निर्देशों के अलावा, हमारे पास:

  • .code16: GAS को 16-बिट कोड आउटपुट करने के लिए कहता है

  • cli: अक्षम सॉफ्टवेयर बाधा। वे प्रोसेसर को फिर से चलाने के बाद शुरू कर सकते हैंhlt

  • int $0x10: एक BIOS कॉल करता है। यह वह है जो पात्रों को एक-एक करके प्रिंट करता है।

महत्वपूर्ण लिंक झंडे हैं:

  • --oformat binary: कच्चे बाइनरी असेंबली कोड को आउटपुट करें, इसे एक ईएलएफ फ़ाइल के अंदर न लपेटें क्योंकि नियमित उपयोगकर्ता निष्पादन के लिए यही स्थिति है।

लिंकर स्क्रिप्ट भाग को बेहतर ढंग से समझने के लिए, लिंकिंग के स्थानांतरण चरण से खुद को परिचित करें: लिंकर क्या करते हैं?

कूलर x86 नंगे धातु कार्यक्रम

यहां कुछ और जटिल नंगे धातु सेटअप हैं जो मैंने प्राप्त किए हैं:

विधानसभा के बजाय सी का उपयोग करें

सारांश: GRUB मल्टीबूट का उपयोग करें, जो उन कष्टप्रद समस्याओं को हल करेगा जिनके बारे में आपने कभी नहीं सोचा था। नीचे अनुभाग देखें।

X86 पर मुख्य कठिनाई यह है कि BIOS डिस्क से मेमोरी में केवल 512 बाइट्स लोड करता है, और सी का उपयोग करते समय आपको उन 512 बाइट्स को उड़ाने की संभावना है!

इसे हल करने के लिए, हम दो-चरण बूटलोडर का उपयोग कर सकते हैं । यह आगे BIOS कॉल करता है, जो डिस्क से अधिक बाइट्स को मेमोरी में लोड करता है। यहाँ int 0x13 BIOS कॉल का उपयोग करके खरोंच से एक न्यूनतम चरण 2 विधानसभा उदाहरण है :

वैकल्पिक रूप से:

  • यदि आपको केवल QEMU में काम करने की आवश्यकता है, लेकिन वास्तविक हार्डवेयर नहीं है, तो -kernelविकल्प का उपयोग करें , जो संपूर्ण ELF फ़ाइल को मेमोरी में लोड करता है। यहाँ एक ARM उदाहरण है जो मैंने उस विधि से बनाया है
  • रास्पबेरी पाई के लिए, डिफ़ॉल्ट फर्मवेयर हमारे लिए एक एलएएफ फ़ाइल से इमेज लोडिंग का ख्याल रखता है kernel7.img, जिसका नाम QEMU -kernelहै।

केवल शैक्षिक उद्देश्यों के लिए, यहां एक चरण न्यूनतम सी उदाहरण है :

main.c

void main(void) {
    int i;
    char s[] = {'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'};
    for (i = 0; i < sizeof(s); ++i) {
        __asm__ (
            "int $0x10" : : "a" ((0x0e << 8) | s[i])
        );
    }
    while (1) {
        __asm__ ("hlt");
    };
}

entry.S

.code16
.text
.global mystart
mystart:
    ljmp $0, $.setcs
.setcs:
    xor %ax, %ax
    mov %ax, %ds
    mov %ax, %es
    mov %ax, %ss
    mov $__stack_top, %esp
    cld
    call main

linker.ld

ENTRY(mystart)
SECTIONS
{
  . = 0x7c00;
  .text : {
    entry.o(.text)
    *(.text)
    *(.data)
    *(.rodata)
    __bss_start = .;
    /* COMMON vs BSS: /programming/16835716/bss-vs-common-what-goes-where */
    *(.bss)
    *(COMMON)
    __bss_end = .;
  }
  /* /programming/53584666/why-does-gnu-ld-include-a-section-that-does-not-appear-in-the-linker-script */
  .sig : AT(ADDR(.text) + 512 - 2)
  {
      SHORT(0xaa55);
  }
  /DISCARD/ : {
    *(.eh_frame)
  }
  __stack_bottom = .;
  . = . + 0x1000;
  __stack_top = .;
}

Daud

set -eux
as -ggdb3 --32 -o entry.o entry.S
gcc -c -ggdb3 -m16 -ffreestanding -fno-PIE -nostartfiles -nostdlib -o main.o -std=c99 main.c
ld -m elf_i386 -o main.elf -T linker.ld entry.o main.o
objcopy -O binary main.elf main.img
qemu-system-x86_64 -drive file=main.img,format=raw

C मानक पुस्तकालय

अगर आपको सी मानक लाइब्रेरी का उपयोग करना है तो चीजें और भी मज़ेदार होती हैं, क्योंकि हमारे पास लिनक्स कर्नेल नहीं है, जो पोसिक्स के माध्यम से सी मानक पुस्तकालय की कार्यक्षमता का बहुत अधिक कार्यान्वयन करता है ।

लिनक्स जैसे पूर्ण विकसित ओएस पर जाने के बिना कुछ संभावनाएं शामिल हैं:

  • खुद लिखिए। यह सिर्फ हेडर और सी फाइलों का एक गुच्छा है अंत में, है ना? सही??

  • Newlib

    इस पर विस्तृत उदाहरण: /electronics/223929/c-standard-lbooks-on-bare-metal/223931

    Newlib औजार आप के लिए सभी बोरिंग गैर ओएस विशिष्ट बातें, जैसे memcmp, memcpyआदि

    फिर, यह आपके लिए आवश्यक स्टिस्कल्स को लागू करने के लिए कुछ स्टब्स प्रदान करता है।

    उदाहरण के लिए, हम exit()ARM पर सेमीहोस्टिंग के माध्यम से लागू कर सकते हैं :

    void _exit(int status) {
        __asm__ __volatile__ ("mov r0, #0x18; ldr r1, =#0x20026; svc 0x00123456");
    }
    

    जैसा कि इस उदाहरण में दिखाया गया है ।

    उदाहरण के लिए, आप printfUART या ARM सिस्टम पर रीडायरेक्ट कर सकते हैं, या सेमीहोस्टिंग केexit() साथ लागू कर सकते हैं

  • FreeRTOS और Zephyr जैसे एम्बेडेड ऑपरेटिंग सिस्टम ।

    इस तरह के ऑपरेटिंग सिस्टम आम तौर पर आपको पूर्व-खाली शेड्यूलिंग को बंद करने की अनुमति देते हैं, इसलिए आपको प्रोग्राम के रनटाइम पर पूर्ण नियंत्रण प्रदान करते हैं।

    उन्हें पहले से लागू न्यूलिब के एक प्रकार के रूप में देखा जा सकता है।

ग्नू ग्रुब मल्टीबूट

बूट सेक्टर सरल हैं, लेकिन वे बहुत सुविधाजनक नहीं हैं:

  • आपके पास प्रति डिस्क केवल एक OS हो सकता है
  • लोड कोड को वास्तव में छोटा होना चाहिए और 512 बाइट्स में फिट होना चाहिए
  • आपको बहुत सारे स्टार्टअप करने होंगे, जैसे संरक्षित मोड में जाना

यह उन कारणों के लिए है कि GNU GRUB ने एक अधिक सुविधाजनक फ़ाइल प्रारूप बनाया जिसे मल्टीबूट कहा जाता है।

न्यूनतम कार्यशील उदाहरण: https://github.com/cirosantilli/x86-bare-metal-examples/tree/d217b180be4220a0b4a453f31275d38e69a99a0e/multiboot/hello-world

मैं इसे अपने GitHub उदाहरण रेपो पर भी उपयोग करता हूं ताकि आसानी से USB को एक लाख बार जलाए बिना वास्तविक हार्डवेयर पर सभी उदाहरणों को चलाने में सक्षम हो।

QEMU परिणाम:

यहां छवि विवरण दर्ज करें

T430:

यहां छवि विवरण दर्ज करें

यदि आप अपने OS को एक मल्टीबूट फ़ाइल के रूप में तैयार करते हैं, तो GRUB इसे एक नियमित फाइल सिस्टम के अंदर खोजने में सक्षम है।

ओएस छवियों को नीचे रखकर यह सबसे अधिक विकृत करता है /boot

मल्टीबूट फाइलें मूल रूप से एक विशेष हेडर के साथ एक ईएलएफ फ़ाइल हैं। वे GRUB द्वारा निर्दिष्ट किए गए हैं: https://www.gnu.org/software/grub/manual/multiboot/multib.html.html

आप मल्टीबूट फ़ाइल को बूट करने योग्य डिस्क में बदल सकते हैं grub-mkrescue

फर्मवेयर

सच में, आपका बूट सेक्टर पहला सॉफ्टवेयर नहीं है जो सिस्टम के सीपीयू पर चलता है।

वास्तव में सबसे पहले चलने वाला तथाकथित फर्मवेयर है , जो एक सॉफ्टवेयर है:

  • हार्डवेयर निर्माताओं द्वारा बनाया गया
  • आम तौर पर बंद स्रोत लेकिन संभावना सी-आधारित
  • केवल-पढ़ने के लिए मेमोरी में संग्रहीत, और इसलिए विक्रेता की सहमति के बिना संशोधित करना कठिन / असंभव है।

प्रसिद्ध फर्मों में शामिल हैं:

  • 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महत्वपूर्ण दुष्प्रभाव होते हैं, इसलिए आपको उन्हें शून्य करना चाहिए, भले ही आप उन्हें स्पष्ट रूप से उपयोग न कर रहे हों।

ध्यान दें कि कुछ एमुलेटर असली हार्डवेयर की तुलना में अच्छे होते हैं और आपको एक अच्छा प्रारंभिक राज्य देते हैं। फिर जब आप असली हार्डवेयर पर चलते हैं, तो सब कुछ टूट जाता है।

एल टोरिटो

सीडी को जलाया जा सकने वाला प्रारूप: https://en.wikipedia.org/wiki/El_Torito_%28CD-ROM_standard%29

हाइब्रिड छवि का उत्पादन करना भी संभव है जो आईएसओ या यूएसबी पर काम करता है। यह grub-mkrescue( उदाहरण के साथ ) किया जा सकता है , और make isoimageउपयोग करने पर लिनक्स कर्नेल द्वारा भी किया जाता हैisohybrid

एआरएम

एआरएम में, सामान्य विचार समान हैं।

IO के लिए उपयोग करने के लिए BIOS की तरह व्यापक रूप से उपलब्ध अर्ध-मानकीकृत पूर्व-स्थापित फर्मवेयर नहीं है, इसलिए IO के दो सबसे सरल प्रकार जो हम कर सकते हैं:

  • धारावाहिक, जो कि व्यापक रूप से देवबोर्ड पर उपलब्ध है
  • एलईडी पलक

मैंने अपलोड किया है:

X86 से कुछ अंतरों में शामिल हैं:

  • IO जादू के पते पर सीधे लिखकर किया जाता है, कोई निर्देश inऔर outनिर्देश नहीं है।

    इसे मेमोरी मैप्ड IO कहा जाता है ।

  • कुछ वास्तविक हार्डवेयर के लिए, रास्पबेरी पाई की तरह, आप फर्मवेयर (BIOS) को डिस्क छवि में स्वयं जोड़ सकते हैं।

    यह एक अच्छी बात है, क्योंकि यह उस फर्मवेयर को और अधिक पारदर्शी बनाता है।

साधन

  • http://wiki.osdev.org उन मामलों के लिए एक महान स्रोत है।
  • https://github.com/scanlime/metalkit एक अधिक स्वचालित / सामान्य नंगे धातु संकलन प्रणाली है, जो एक छोटे से कस्टम एपीआई प्रदान करती है

3
Unikernels ऐसे लोगों के लिए एक विकल्प है जो इतने निचले स्तर पर नहीं जा सकते / नहीं जा सकते और फिर भी अपने बहुत कम पदचिह्न से लाभ उठाना चाहते हैं।
आंद्रेएलडीएम

1
@AndreLDM I उस लिनक्स आधारित यूनिकबर्न समाचार को जोड़ने के कगार पर था, लेकिन अभी भी बहुत तेज़ महसूस किया: next.redhat.com/2018/11/14/ukl-a-unikernel-based-on-linux
Ciro Santilli 冠状 病 DM

14
वास्तव में विस्तृत जवाब लेकिन "एक ऐसा कार्यक्रम जो बिना ओएस के चलता है, एक ओएस है" यह सच नहीं है। आप एक ऐसा प्रोग्राम लिख सकते हैं जो सिर्फ एक एलईडी को चालू / बंद करता है लेकिन वह इसे ओएस नहीं बनाता है। कुछ फर्मवेयर कोड जो आपके फ्लैश ड्राइव पर माइक्रोकंट्रोलर चलाते हैं, वह इसे ओएस नहीं बनाते हैं। एक OS अन्य सॉफ़्टवेयर को अधिक आसानी से लिखने के लिए एक न्यूनतम अमूर्त परत पर है। इन दिनों नंगे न्यूनतम पर मैं कहूंगा कि अगर कोई शेड्यूलर नहीं है तो इसकी संभावना नहीं है कि वह ओएस नहीं है।
विटाली

4
निरर्थक बकवास के अलावा अच्छा जवाब यह है कि कोई भी प्रोग्राम जो एक ओएस में नहीं चलता है वह एक ओएस है।
जिज्ञासु ने

3
@MichaelPetch हे, बस बूट सेक्टर पर नल को बचाने के लिए :-) संभवतः इसके लायक नहीं है।
सिरो सैंतिली 郝海东 i i i

3

प्रेरणा के रूप में ऑपरेटिंग सिस्टम

ऑपरेटिंग सिस्टम भी एक प्रोग्राम है , इसलिए हम छोटे ऑपरेटिंग सिस्टमों में से किसी एक को खरोंचने या बदलने (सीमित करने या जोड़ने) से बनाकर अपना प्रोग्राम भी बना सकते हैं , और फिर इसे बूट प्रक्रिया के दौरान चला सकते हैं ( आईएसओ इमेज का उपयोग करके ) ।

उदाहरण के लिए, इस पृष्ठ का उपयोग प्रारंभिक बिंदु के रूप में किया जा सकता है:

एक साधारण ऑपरेटिंग सिस्टम कैसे लिखें

यहां, संपूर्ण ऑपरेटिंग सिस्टम पूरी तरह से 512-बाइट बूट सेक्टर ( MBR ) में फिट होता है !

इस तरह के या समान सरल ओएस का उपयोग एक सरल फ्रेमवर्क बनाने के लिए किया जा सकता है जो हमें अनुमति देगा:

RAM पर डिस्क में बूटलोडर लोड बाद के सेक्टर बनाएं , और निष्पादन को जारी रखने के लिए उस बिंदु पर जाएं । या आप FAT12 पर पढ़ सकते हैं, फ़्लॉपी ड्राइव पर उपयोग की जाने वाली फाइलसिस्टम और इसे लागू करते हैं

हालांकि, कई संभावनाएं हैं। उदाहरण के लिए एक बड़ी x86 असेंबली भाषा का OS देखने के लिए हम MykeOS , x86 ऑपरेटिंग सिस्टम का पता लगा सकते हैं जो कि एक सरल टूल है जिसमें 16-बिट, रियल-मोड OSes कार्य को अच्छी तरह से टिप्पणी किए गए कोड और व्यापक प्रलेखन के साथ दिखाया जा सकता है ।

प्रेरणा के रूप में बूट लोडर

ऑपरेटिंग सिस्टम के बिना चलने वाले अन्य सामान्य प्रकार के प्रोग्राम भी बूट लोडर हैं । हम इस साइट का उपयोग करके उदाहरण के लिए इस तरह की अवधारणा से प्रेरित एक कार्यक्रम बना सकते हैं:

अपने खुद के बूट लोडर कैसे विकसित करें

उपरोक्त लेख भी ऐसे कार्यक्रमों की मूल वास्तुकला प्रस्तुत करता है :

  1. 0000: 7C00 पते द्वारा मेमोरी को सही लोड करना।
  2. BootMain फ़ंक्शन को कॉल करना जो उच्च-स्तरीय भाषा में विकसित किया गया है।
  3. प्रदर्शन पर "" हैलो, दुनिया ... ", निम्न-स्तर के संदेश से दिखाएं।

जैसा कि हम देख सकते हैं, यह वास्तुकला बहुत लचीला है और हमें किसी भी कार्यक्रम को लागू करने की अनुमति देता है , जरूरी नहीं कि एक बूट लोडर।

विशेष रूप से, यह दिखाता है कि "मिश्रित कोड" तकनीक का उपयोग कैसे करें जिसके लिए उच्च-स्तरीय निर्माण ( सी या सी ++ से ) को निम्न-स्तरीय कमांड ( असेंबलर से ) से जोड़ना संभव है । यह एक बहुत ही उपयोगी तरीका है, लेकिन हमें यह याद रखना होगा:

प्रोग्राम बनाने और निष्पादन योग्य फ़ाइल प्राप्त करने के लिए आपको 16-बिट मोड के लिए असेंबलर के कंपाइलर और लिंकर की आवश्यकता होगी । C / C ++ के लिए आपको केवल कंपाइलर की आवश्यकता होगी जो ऑब्जेक्ट फ़ाइलों को 16-बिट मोड के लिए बना सके

लेख यह भी दिखाता है कि कैसे बनाए गए कार्यक्रम को कार्रवाई में देखा जाए और इसका परीक्षण और डिबग कैसे किया जाए।

UEFI प्रेरणा के रूप में आवेदन करता है

उपरोक्त उदाहरणों ने डेटा माध्यम पर सेक्टर एमबीआर को लोड करने के तथ्य का उपयोग किया। हालांकि, हम गहराई में गहरे जा सकते हैं के साथ उदाहरण के लिए plaing द्वारा UEFI अनुप्रयोगों :

ओएस लोड करने से परे, यूईएफआई यूईएफआई अनुप्रयोगों को चला सकता है, जो ईएफआई सिस्टम विभाजन पर फाइलों के रूप में रहते हैं। उन्हें यूईएफआई कमांड शेल से, फर्मवेयर के बूट मैनेजर द्वारा, या अन्य यूईएफआई अनुप्रयोगों द्वारा निष्पादित किया जा सकता है। यूईएफआई अनुप्रयोगों को सिस्टम निर्माता द्वारा स्वतंत्र रूप से विकसित और स्थापित किया जा सकता है।

एक प्रकार का यूईएफआई आवेदन एक ओएस लोडर है जैसे कि GRUB, rEFInd, Gummiboot, और Windows बूट प्रबंधक; जो एक OS फ़ाइल को मेमोरी में लोड करता है और इसे निष्पादित करता है। इसके अलावा, एक ओएस लोडर एक उपयोगकर्ता इंटरफ़ेस प्रदान कर सकता है ताकि दूसरे यूईएफआई एप्लिकेशन के चयन की अनुमति मिल सके। यूईएफआई शेल जैसी उपयोगिताएं भी यूईएफआई अनुप्रयोग हैं।

यदि हम ऐसे कार्यक्रम बनाना शुरू करना चाहते हैं , तो हम उदाहरण के लिए, इन वेबसाइटों से शुरू कर सकते हैं:

ईएफआई के लिए प्रोग्रामिंग: "हैलो, वर्ल्ड" प्रोग्राम / यूईएफआई प्रोग्रामिंग बनाना - पहले चरण

प्रेरणा के रूप में सुरक्षा मुद्दों की खोज

यह सर्वविदित है कि दुर्भावनापूर्ण सॉफ़्टवेयर का एक पूरा समूह है (जो प्रोग्राम हैं) जो ऑपरेटिंग सिस्टम शुरू होने से पहले चल रहे हैं

उनमें से एक बड़ा समूह एमबीआर सेक्टर या यूईएफआई अनुप्रयोगों पर काम करता है, उपरोक्त सभी समाधानों की तरह, लेकिन ऐसे भी हैं जो एक और प्रवेश बिंदु का उपयोग करते हैं जैसे वॉल्यूम बूट रिकॉर्ड (वीबीआर) या BIOS :

कम से कम चार ज्ञात BIOS हमले वायरस हैं , जिनमें से दो प्रदर्शन उद्देश्यों के लिए थे।

या शायद एक और भी।

सिस्टम स्टार्टअप से पहले हमलों

बूटकिट्स प्रूफ-ऑफ-कॉन्सेप्ट डेवलपमेंट से बड़े पैमाने पर वितरण तक विकसित हुए हैं और अब प्रभावी रूप से ओपन-सोर्स सॉफ्टवेयर बन गए हैं

बूट करने के विभिन्न तरीके

मुझे यह भी लगता है कि इस संदर्भ में यह भी ध्यान देने योग्य है कि ऑपरेटिंग सिस्टम (या इसके लिए निष्पादन योग्य कार्यक्रम) को बूट करने के विभिन्न रूप हैं । कई हैं, लेकिन मैं नेटवर्क बूट विकल्प ( पीएक्सई ) का उपयोग करके नेटवर्क से कोड लोड करने पर ध्यान देना चाहूंगा , जो हमें इसके ऑपरेटिंग सिस्टम की परवाह किए बिना और यहां तक ​​कि किसी भी भंडारण माध्यम की परवाह किए बिना कंप्यूटर पर प्रोग्राम चलाने की अनुमति देता है। कि सीधे कंप्यूटर से जुड़ा:

नेटवर्क बूटिंग (पीएक्सई) क्या है और आप इसका उपयोग कैसे कर सकते हैं?

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.