Làm thế nào để chạy một chương trình mà không có hệ điều hành?


239

Làm thế nào để bạn tự chạy một chương trình mà không cần hệ điều hành chạy? Bạn có thể tạo các chương trình lắp ráp mà máy tính có thể tải và chạy khi khởi động không, ví dụ khởi động máy tính từ ổ đĩa flash và nó chạy chương trình trên CPU?


4
Trên kiến ​​trúc nào? x86? CÁNH TAY?
Kissiel

1
Tôi đã nói rất nhiều, nhưng rất có thể là x86 hoặc x64
user2320609

2
vâng, đó chính xác là cách bộ xử lý khởi động. không phải lắp ráp, C thường được sử dụng với một ít asm cho bootstrap và có lẽ một số hỗ trợ khác.
old_timer

23
Hãy nghĩ về nó: nếu không có khả năng đó, hệ điều hành sẽ tự khởi động và chạy như thế nào? :)
Seva Alekseyev

Câu trả lời:


153

Làm thế nào để bạn tự chạy một chương trình mà không cần hệ điều hành chạy?

Bạn đặt mã nhị phân của mình đến nơi mà bộ xử lý tìm kiếm sau khi khởi động lại (ví dụ địa chỉ 0 trên ARM).

Bạn có thể tạo các chương trình lắp ráp mà máy tính có thể tải và chạy khi khởi động không (ví dụ: khởi động máy tính từ ổ đĩa flash và nó chạy chương trình trên ổ đĩa)?

Câu trả lời chung cho câu hỏi: nó có thể được thực hiện. Nó thường được gọi là "lập trình kim loại trần". Để đọc từ ổ đĩa flash, bạn muốn biết USB là gì và bạn muốn có một số trình điều khiển để hoạt động với USB này. Chương trình trên ổ đĩa này cũng phải có định dạng cụ thể, trên một số hệ thống tệp cụ thể ... Đây là điều mà các bộ tải khởi động thường làm, nhưng chương trình của bạn có thể bao gồm bộ tải khởi động riêng để nó tự chứa, nếu phần sụn sẽ chỉ tải một khối nhỏ mã.

Nhiều bảng ARM cho phép bạn làm một số điều đó. Một số có bộ tải khởi động để giúp bạn thiết lập cơ bản.

Ở đây bạn có thể tìm thấy một hướng dẫn tuyệt vời về cách thực hiện một hệ điều hành cơ bản trên Raspberry Pi.

Chỉnh sửa: Bài viết này và toàn bộ wiki.osdev.org sẽ trả lời hầu hết các câu hỏi của bạn http://wiki.osdev.org/Intributiontion

Ngoài ra, nếu bạn không muốn thử nghiệm trực tiếp trên phần cứng, bạn có thể chạy nó dưới dạng một máy ảo bằng cách sử dụng các trình ảo hóa như qemu. Xem cách chạy "hello world" trực tiếp trên phần cứng ARM ảo hóa tại đây .


722

Ví dụ runnable

Chúng ta hãy tạo và chạy một số chương trình chào thế giới kim loại trần rất nhỏ chạy mà không cần hệ điều hành trên:

Chúng tôi cũng sẽ thử chúng trên trình giả lập QEMU càng nhiều càng tốt, vì điều đó an toàn hơn và thuận tiện hơn cho việc phát triển. Các thử nghiệm QEMU đã có trên máy chủ Ubuntu 18.04 với QEMU 2.11.1 được đóng gói sẵn.

Mã của tất cả các ví dụ x86 bên dưới và nhiều hơn nữa có mặt trên repo GitHub này .

Cách chạy các ví dụ trên phần cứng thực x86

Hãy nhớ rằng các ví dụ chạy trên phần cứng thực có thể nguy hiểm, ví dụ: bạn có thể xóa đĩa hoặc gạch phần cứng do nhầm lẫn: chỉ làm điều này trên các máy cũ không chứa dữ liệu quan trọng! Hoặc thậm chí tốt hơn, sử dụng các bảng điều khiển bán một lần giá rẻ như Raspberry Pi, xem ví dụ ARM bên dưới.

Đối với một máy tính xách tay x86 điển hình, bạn phải làm một cái gì đó như:

  1. Ghi hình ảnh vào thanh USB (sẽ hủy dữ liệu của bạn!):

    sudo dd if=main.img of=/dev/sdX
    
  2. cắm USB trên máy tính

  3. bật nó lên

  4. bảo nó khởi động từ USB.

    Điều này có nghĩa là làm cho phần sụn chọn USB trước đĩa cứng.

    Nếu đó không phải là hành vi mặc định của máy của bạn, hãy tiếp tục nhấn Enter, F12, ESC hoặc các phím lạ khác sau khi bật nguồn cho đến khi bạn nhận được menu khởi động nơi bạn có thể chọn để khởi động từ USB.

    Thường có thể định cấu hình thứ tự tìm kiếm trong các menu đó.

Ví dụ, trên T430 của tôi, tôi thấy như sau.

Sau khi bật, đây là lúc tôi phải nhấn Enter để vào menu khởi động:

nhập mô tả hình ảnh ở đây

Sau đó, ở đây tôi phải nhấn F12 để chọn USB làm thiết bị khởi động:

nhập mô tả hình ảnh ở đây

Từ đó, tôi có thể chọn USB làm thiết bị khởi động như thế này:

nhập mô tả hình ảnh ở đây

Ngoài ra, để thay đổi thứ tự khởi động và chọn USB có quyền ưu tiên cao hơn để tôi không phải chọn thủ công mỗi lần, tôi sẽ nhấn F1 trên màn hình "Menu ngắt khởi động", sau đó điều hướng đến:

nhập mô tả hình ảnh ở đây

Giày cao cổ

Trên x86, điều đơn giản nhất và ở mức thấp nhất bạn có thể làm là tạo Master Boot sector (MBR) , đây là một loại sector khởi động , sau đó cài đặt nó vào đĩa.

Ở đây chúng tôi tạo một printfcuộc gọi với một cuộc gọi duy nhất :

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

Kết quả:

nhập mô tả hình ảnh ở đây

Lưu ý rằng ngay cả khi không làm gì, một vài ký tự đã được in trên màn hình. Chúng được in bởi phần sụn và phục vụ để xác định hệ thống.

Và trên T430, chúng ta chỉ có một màn hình trống với con trỏ nhấp nháy:

nhập mô tả hình ảnh ở đây

main.img chứa những điều sau đây

  • \364in octal == 0xf4in hex: mã hóa cho một hltlệnh, thông báo cho CPU ngừng hoạt động.

    Do đó, chương trình của chúng tôi sẽ không làm gì cả: chỉ bắt đầu và dừng lại.

    Chúng tôi sử dụng số bát phân vì \xsố hex không được chỉ định bởi POSIX.

    Chúng tôi có thể có được mã hóa này một cách dễ dàng với:

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

    đầu ra nào:

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

    nhưng nó cũng được ghi lại trong tài liệu hướng dẫn của Intel.

  • %509ssản xuất 509 không gian. Cần phải điền vào tệp cho đến byte 510.

  • \125\252trong bát phân == 0x55theo sau 0xaa.

    Đây là 2 byte ma thuật bắt buộc phải là byte 511 và 512.

    BIOS đi qua tất cả các đĩa của chúng tôi để tìm kiếm các đĩa có khả năng khởi động và nó chỉ xem xét các đĩa có khả năng khởi động có hai byte ma thuật đó.

    Nếu không có, phần cứng sẽ không coi đây là đĩa khởi động.

Nếu bạn không phải là printfchủ, bạn có thể xác nhận nội dung của main.imgvới:

hd main.img

Điều này cho thấy sự mong đợi:

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

nơi 20là một không gian trong ASCII.

Phần sụn BIOS đọc 512 byte đó từ đĩa, đặt chúng vào bộ nhớ và đặt PC thành byte đầu tiên để bắt đầu thực thi chúng.

Xin chào ngành boot thế giới

Bây giờ chúng tôi đã thực hiện một chương trình tối thiểu, hãy chuyển sang một thế giới xin chào.

Câu hỏi rõ ràng là: làm thế nào để làm IO? Một vài lựa chọn:

  • yêu cầu phần sụn, ví dụ BIOS hoặc UEFI, làm điều đó cho chúng tôi

  • VGA: vùng nhớ đặc biệt được in ra màn hình nếu được ghi vào. Có thể được sử dụng trong Chế độ bảo vệ.

  • viết một trình điều khiển và nói chuyện trực tiếp với phần cứng màn hình. Đây là cách "phù hợp" để làm điều đó: mạnh mẽ hơn, nhưng phức tạp hơn.

  • cổng nối tiếp . Đây là một giao thức được tiêu chuẩn hóa rất đơn giản để gửi và nhận các ký tự từ một thiết bị đầu cuối máy chủ.

    Trên máy tính để bàn, nó trông như thế này:

    nhập mô tả hình ảnh ở đây

    Nguồn .

    Thật không may, nó không được tiếp xúc trên hầu hết các máy tính xách tay hiện đại, nhưng là cách phổ biến để đi đến các bảng phát triển, xem các ví dụ ARM dưới đây.

    Đây thực sự là một sự xấu hổ, vì các giao diện như vậy thực sự hữu ích để gỡ lỗi kernel Linux chẳng hạn .

  • sử dụng các tính năng gỡ lỗi của chip. ARM gọi semihosting của họ chẳng hạn. Trên phần cứng thực, nó đòi hỏi một số hỗ trợ phần cứng và phần mềm bổ sung, nhưng trên trình giả lập, nó có thể là một tùy chọn tiện lợi miễn phí. Ví dụ .

Ở đây chúng tôi sẽ làm một ví dụ BIOS vì nó đơn giản hơn trên x86. Nhưng lưu ý rằng nó không phải là phương pháp mạnh mẽ nhất.

chính.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"

GitHub ngược dòng .

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)
    }
}

Lắp ráp và liên kết với:

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

Kết quả:

nhập mô tả hình ảnh ở đây

Và trên T430:

nhập mô tả hình ảnh ở đây

Đã thử nghiệm trên: Lenovo Thinkpad T430, UEFI BIOS 1.16. Đĩa được tạo trên máy chủ Ubuntu 18.04.

Bên cạnh các hướng dẫn lắp ráp người dùng tiêu chuẩn, chúng tôi có:

  • .code16: báo cho GAS xuất mã 16 bit

  • cli: vô hiệu hóa các ngắt phần mềm. Chúng có thể khiến bộ xử lý bắt đầu chạy lại sauhlt

  • int $0x10: thực hiện cuộc gọi BIOS. Đây là những gì in từng ký tự một.

Các cờ liên kết quan trọng là:

  • --oformat binary: xuất mã lắp ráp nhị phân thô, không bọc nó trong tệp ELF như trường hợp đối với các tệp thực thi người dùng thông thường.

Để hiểu rõ hơn về phần kịch bản liên kết, hãy làm quen với bước di chuyển liên kết: Trình liên kết làm gì?

Chương trình làm mát kim loại trần x86

Dưới đây là một vài thiết lập kim loại trần phức tạp hơn mà tôi đã đạt được:

Sử dụng C thay vì lắp ráp

Tóm tắt: sử dụng GRUB multiboot, sẽ giải quyết rất nhiều vấn đề gây phiền nhiễu mà bạn chưa từng nghĩ tới. Xem phần bên dưới.

Khó khăn chính trên x86 là BIOS chỉ tải 512 byte từ đĩa vào bộ nhớ và bạn có khả năng sẽ làm nổ tung 512 byte đó khi sử dụng C!

Để giải quyết điều đó, chúng ta có thể sử dụng bộ tải khởi động hai giai đoạn . Điều này thực hiện các cuộc gọi BIOS tiếp theo, tải nhiều byte hơn từ đĩa vào bộ nhớ. Dưới đây là một ví dụ lắp ráp giai đoạn 2 tối thiểu từ đầu bằng cách sử dụng cuộc gọi BIOS int 0x13 :

Cách khác:

  • nếu bạn chỉ cần nó hoạt động trong QEMU chứ không phải phần cứng thực, hãy sử dụng -kerneltùy chọn tải toàn bộ tệp ELF vào bộ nhớ.Đây là một ví dụ ARM tôi đã tạo bằng phương pháp đó .
  • đối với Raspberry Pi, phần sụn mặc định đảm nhiệm việc tải hình ảnh cho chúng tôi từ tệp ELF có tên kernel7.img, giống như QEMU -kernel.

Chỉ dành cho mục đích giáo dục, đây là một ví dụ C tối thiểu một giai đoạn :

C chính

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");
    };
}

mục.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 = .;
}

chạy

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

Thư viện chuẩn C

Tuy nhiên, mọi thứ sẽ trở nên thú vị hơn nếu bạn cũng muốn sử dụng thư viện chuẩn C, vì chúng tôi không có nhân Linux, nơi thực hiện nhiều chức năng thư viện chuẩn C thông qua POSIX .

Một vài khả năng, mà không cần đến một hệ điều hành toàn diện như Linux, bao gồm:

  • Viết của riêng bạn. Cuối cùng, nó chỉ là một loạt các tiêu đề và tệp C, phải không? Đúng??

  • Newlib

    Ví dụ chi tiết tại: /electronics/223929/c-stiteria-lologists-on-bare-metal/223931

    Newlib cụ tất cả nhàm chán phi OS cụ thể việc cho bạn, ví dụ memcmp,memcpy vv

    Sau đó, nó cung cấp một số sơ khai để bạn thực hiện các tòa nhà mà bạn cần cho mình.

    Ví dụ: chúng ta có thể triển khai exit()trên ARM thông qua semihosting với:

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

    như thể hiện trong ví dụ này .

    Ví dụ, bạn có thể chuyển hướng printftới các hệ thống UART hoặc ARM, hoặc thực hiện exit()với semihosting .

  • các hệ điều hành nhúng như FreeRTOSZephyr .

    Các hệ điều hành như vậy thường cho phép bạn tắt lập lịch trước, do đó cung cấp cho bạn toàn quyền kiểm soát thời gian chạy của chương trình.

    Chúng có thể được coi là một loại Newlib được triển khai trước.

GNU GRUB Multiboot

Các phần khởi động rất đơn giản, nhưng chúng không thuận tiện lắm:

  • bạn chỉ có thể có một hệ điều hành trên mỗi đĩa
  • mã tải phải thực sự nhỏ và vừa với 512 byte
  • bạn phải tự khởi động rất nhiều, như chuyển sang chế độ được bảo vệ

Đó là vì những lý do mà GNU GRUB đã tạo ra một định dạng tệp thuận tiện hơn được gọi là multiboot.

Ví dụ làm việc tối thiểu: https://github.com/cirosantilli/x86-bare-metal-examples/tree/d217b180be4220a0b4a453f31275d38e697a99e0/multiboot/hello-world

Tôi cũng sử dụng nó trên repo ví dụ GitHub của tôi để có thể dễ dàng chạy tất cả các ví dụ trên phần cứng thực mà không cần ghi USB một triệu lần.

Kết quả QEMU:

nhập mô tả hình ảnh ở đây

T430:

nhập mô tả hình ảnh ở đây

Nếu bạn chuẩn bị HĐH của mình dưới dạng tệp multiboot, GRUB có thể tìm thấy nó trong một hệ thống tệp thông thường.

Đây là những gì hầu hết các distro làm, đặt hình ảnh hệ điều hành /boot.

Các tệp Multiboot về cơ bản là một tệp ELF với một tiêu đề đặc biệt. Chúng được GRUB chỉ định tại: https://www.gnu.org/software/grub/manual/multiboot/multiboot.html

Bạn có thể biến một tệp multiboot thành một đĩa có thể khởi động được grub-mkrescue.

Chương trình cơ sở

Trên thực tế, khu vực khởi động của bạn không phải là phần mềm đầu tiên chạy trên CPU của hệ thống.

Cái thực sự chạy đầu tiên là cái gọi là phần sụn , là một phần mềm:

  • được thực hiện bởi các nhà sản xuất phần cứng
  • nguồn thường đóng nhưng có khả năng dựa trên C
  • được lưu trữ trong bộ nhớ chỉ đọc và do đó khó / không thể sửa đổi nếu không có sự đồng ý của nhà cung cấp.

Các phần mềm nổi tiếng bao gồm:

  • BIOS : firmware x86 cũ hiện tại. SeaBIOS là triển khai nguồn mở mặc định được QEMU sử dụng.
  • UEFI : Người kế vị BIOS, được tiêu chuẩn hóa tốt hơn, nhưng có khả năng hơn, và vô cùng bồng bột.
  • Coreboot : nỗ lực mã nguồn mở chéo cao quý

Phần sụn thực hiện những việc như:

  • lặp qua từng đĩa cứng, USB, mạng, v.v. cho đến khi bạn tìm thấy thứ gì đó có khả năng khởi động.

    Khi chúng tôi chạy QEMU, -hdanói rằng đó main.imglà một đĩa cứng được kết nối với phần cứng và hdalà ổ đĩa đầu tiên được dùng thử và nó được sử dụng.

  • tải 512 byte đầu tiên vào địa chỉ bộ nhớ RAM 0x7c00, đặt RIP của CPU ở đó và để nó chạy

  • hiển thị những thứ như menu khởi động hoặc lệnh in BIOS trên màn hình

Phần sụn cung cấp chức năng giống như hệ điều hành mà hầu hết các hệ điều hành phụ thuộc. Ví dụ: một tập hợp con Python đã được chuyển để chạy trên BIOS / UEFI: https://www.youtube.com/watch?v=bYQ_lq5dcvM

Có thể lập luận rằng các phần cứng không thể phân biệt được với các HĐH và phần sụn đó là chương trình kim loại trần "thật" duy nhất mà người ta có thể làm.

Như nhà phát triển CoreOS này đặt nó :

Phần khó

Khi bạn cấp nguồn cho PC, các chip tạo nên chipset (cầu bắc, cầu nam và SuperIO) vẫn chưa được khởi tạo đúng cách. Mặc dù ROM ROM đã bị loại bỏ khỏi CPU hết mức có thể, nhưng CPU này có thể truy cập được, bởi vì nó phải như vậy, nếu không CPU sẽ không có hướng dẫn để thực thi. Điều này không có nghĩa là BIOS ROM được ánh xạ hoàn toàn, thường thì không. Nhưng vừa đủ được ánh xạ để quá trình khởi động diễn ra. Bất kỳ thiết bị khác, chỉ cần quên nó.

Khi bạn chạy Coreboot theo QEMU, bạn có thể thử nghiệm các lớp Coreboot cao hơn và với tải trọng, nhưng QEMU cung cấp rất ít cơ hội để thử nghiệm mã khởi động cấp thấp. Đối với một điều, RAM chỉ hoạt động ngay từ đầu.

Đăng trạng thái ban đầu của BIOS

Giống như nhiều thứ trong phần cứng, tiêu chuẩn hóa là yếu và một trong những điều bạn không nên dựa vào là trạng thái đăng ký ban đầu khi mã của bạn bắt đầu chạy sau BIOS.

Vì vậy, hãy tạo cho mình một ưu tiên và sử dụng một số mã khởi tạo như sau: https://stackoverflow.com/a/32509555/895245

Các thanh ghi thích %ds%escó tác dụng phụ quan trọng, vì vậy bạn nên loại bỏ chúng ngay cả khi bạn không sử dụng chúng một cách rõ ràng.

Lưu ý rằng một số trình giả lập đẹp hơn phần cứng thực và cung cấp cho bạn trạng thái ban đầu tốt đẹp. Sau đó, khi bạn chạy trên phần cứng thực sự, mọi thứ sẽ phá vỡ.

El Torito

Định dạng có thể được ghi vào đĩa CD: https://en.wikipedia.org/wiki/El_Torito_%28CD-ROM_st Chuẩn% 29

Cũng có thể tạo ra một hình ảnh lai hoạt động trên cả ISO hoặc USB. Điều này có thể được thực hiện với grub-mkrescue( ví dụ ) và cũng được nhân Linux thực hiện khi make isoimagesử dụng isohybrid.

CÁNH TAY

Trong ARM, các ý tưởng chung là như nhau.

Không có phần mềm cài đặt sẵn bán chuẩn được phổ biến rộng rãi như BIOS để chúng tôi sử dụng cho IO, vì vậy hai loại IO đơn giản nhất mà chúng tôi có thể làm là:

  • nối tiếp, có sẵn rộng rãi trên devboards
  • nháy đèn LED

Tôi đã tải lên:

Một số khác biệt từ x86 bao gồm:

  • IO được thực hiện bằng cách viết trực tiếp vào địa chỉ ma thuật, không có inouthướng dẫn.

    Đây được gọi là bộ nhớ ánh xạ IO .

  • đối với một số phần cứng thực, như Raspberry Pi, bạn có thể tự thêm phần sụn (BIOS) vào ảnh đĩa.

    Đó là một điều tốt, vì nó làm cho việc cập nhật firmware đó trở nên minh bạch hơn.

Tài nguyên


3
Unikernels là một lựa chọn thay thế cho những người không thể / không muốn đi quá thấp và vẫn muốn hưởng lợi từ dấu chân rất thấp của họ.
AndreLDM

1
@AndreLDM Tôi đang trên bờ vực thêm tin tức Unikernel dựa trên Linux đó, nhưng cảm thấy quá khó chịu: next.redhat.com/2018/11/14/ukl-a-unikernel-basing-on-linux
Ciro Santilli 郝海东 冠状六四 事件

14
Câu trả lời thực sự chi tiết nhưng "một chương trình chạy mà không có HĐH, là HĐH" thì không đúng. Bạn có thể viết một chương trình chỉ bật / tắt đèn LED nhưng điều đó không làm cho nó trở thành một hệ điều hành. Một số mã chương trình cơ sở chạy vi điều khiển trên ổ flash của bạn không biến nó thành HĐH. Một hệ điều hành tối thiểu là một lớp trừu tượng để viết phần mềm khác dễ dàng hơn. Ở mức tối thiểu những ngày này tôi sẽ nói nếu không có lịch trình thì có khả năng đó không phải là HĐH.
Vitali

4
Câu trả lời tốt ngoại trừ điều vô lý tuyệt đối rằng bất kỳ chương trình nào không chạy trong HĐH đều là HĐH.
tò mò

3
@MichaelPetch này, chỉ để lưu null trên khu vực khởi động :-) Có thể không đáng.
Ciro Santilli 郝海东 冠状 病 事件

3

Hệ điều hành như nguồn cảm hứng

Hệ điều hành cũng là một chương trình , vì vậy chúng tôi cũng có thể tạo chương trình của riêng mình bằng cách tạo từ đầu hoặc thay đổi (giới hạn hoặc thêm) các tính năng của một trong các hệ điều hành nhỏ , sau đó chạy nó trong quá trình khởi động (sử dụng hình ảnh ISO ) .

Ví dụ: trang này có thể được sử dụng làm điểm bắt đầu:

Cách viết một hệ điều hành đơn giản

Ở đây, toàn bộ Hệ điều hành hoàn toàn phù hợp với khu vực khởi động 512 byte ( MBR )!

Hệ điều hành đơn giản tương tự hoặc tương tự có thể được sử dụng để tạo một khung đơn giản cho phép chúng tôi:

làm cho bộ tải khởi động tải các cung tiếp theo trên đĩa vào RAM và nhảy đến điểm đó để tiếp tục thực thi . Hoặc bạn có thể đọc lên FAT12, hệ thống tệp được sử dụng trên các ổ đĩa mềm và thực hiện điều đó .

Có rất nhiều khả năng, tuy nhiên. Ví dụ, để thấy một hệ điều hành ngôn ngữ lắp ráp x86 lớn hơn, chúng ta có thể khám phá hệ điều hành MykeOS , x86, một công cụ học tập để hiển thị các hệ điều hành 16 bit, chế độ thực đơn giản, với mã được nhận xét tốttài liệu mở rộng .

Boot Loader là nguồn cảm hứng

Loại chương trình phổ biến khác chạy mà không có hệ điều hành cũng là Boot Loaders . Chúng tôi có thể tạo một chương trình lấy cảm hứng từ một khái niệm như vậy, ví dụ như sử dụng trang web này:

Cách phát triển Trình tải khởi động của riêng bạn

Bài viết trên cũng trình bày kiến trúc cơ bản của một chương trình như vậy :

  1. Tải đúng vào bộ nhớ theo địa chỉ 0000: 7C00.
  2. Gọi hàm BootMain được phát triển bằng ngôn ngữ cấp cao.
  3. Hiển thị các phạm vi Xin chào, thế giới Giáo hoàng, từ tin nhắn cấp độ thấp trên màn hình.

Như chúng ta có thể thấy, kiến trúc này rất linh hoạt và cho phép chúng tôi thực hiện bất kỳ chương trình nào , không nhất thiết phải là bộ tải khởi động.

Đặc biệt, nó cho thấy làm thế nào để sử dụng "hỗn hợp mã" kỹ thuật nhờ đó nó có thể kết hợp công trình xây dựng cao cấp (từ C hoặc C ++ ) với các lệnh ở mức độ thấp (từ Assembler ). Đây là một phương pháp rất hữu ích, nhưng chúng ta phải nhớ rằng:

để xây dựng chương trình và có được tệp thực thi, bạn sẽ cần trình biên dịch và trình liên kết của Trình biên dịch cho chế độ 16 bit . Đối với C / C ++, bạn sẽ chỉ cần trình biên dịch có thể tạo tệp đối tượng cho chế độ 16 bit .

Bài viết cũng chỉ ra cách xem chương trình đã tạo trong thực tế và cách thực hiện kiểm tra và gỡ lỗi.

Ứng dụng UEFI là nguồn cảm hứng

Các ví dụ trên đã sử dụng thực tế tải MBR của ngành trên phương tiện dữ liệu. Tuy nhiên, chúng ta có thể đi sâu hơn vào chiều sâu bằng cách ví dụ với các ứng dụng UEFI :

Ngoài việc tải một hệ điều hành, UEFI có thể chạy các ứng dụng UEFI, nằm trong các tệp trên Phân vùng hệ thống EFI. Chúng có thể được thực thi từ trình vỏ lệnh UEFI, bởi trình quản lý khởi động của phần sụn hoặc bởi các ứng dụng UEFI khác. Các ứng dụng UEFI có thể được phát triển và cài đặt độc lập với nhà sản xuất hệ thống.

Một loại ứng dụng UEFI là trình tải hệ điều hành như GRUB, rEFInd, Gummiboot và Windows Boot Manager; tải tập tin hệ điều hành vào bộ nhớ và thực thi nó. Ngoài ra, trình tải hệ điều hành có thể cung cấp giao diện người dùng để cho phép lựa chọn một ứng dụng UEFI khác chạy. Các tiện ích như vỏ UEFI cũng là các ứng dụng UEFI.

Nếu chúng tôi muốn bắt đầu tạo các chương trình như vậy, ví dụ , chúng tôi có thể bắt đầu với các trang web này:

Lập trình cho EFI: Tạo chương trình "Xin chào, thế giới" / Lập trình UEFI - Bước đầu tiên

Khám phá các vấn đề an ninh như là nguồn cảm hứng

Mọi người đều biết rằng có cả một nhóm phần mềm độc hại (là các chương trình) đang chạy trước khi hệ điều hành khởi động .

Một nhóm lớn trong số họ hoạt động trên các ứng dụng MBR hoặc UEFI, giống như tất cả các giải pháp trên, nhưng cũng có những giải pháp sử dụng một điểm nhập khác như Volume Boot Record (VBR) hoặc BIOS :

Có ít nhất bốn loại virus tấn công BIOS được biết đến , hai trong số đó là dành cho mục đích trình diễn.

hoặc có lẽ một số khác quá.

Tấn công trước khi khởi động hệ thống

Bootkits đã phát triển từ phát triển Proof-of-Concept sang phân phối đại chúng và giờ đây đã trở thành phần mềm nguồn mở một cách hiệu quả .

Những cách khác nhau để khởi động

Tôi cũng nghĩ rằng trong bối cảnh này, điều đáng nói là nhiều hình thức khởi động hệ điều hành khác nhau (hoặc chương trình thực thi dành cho việc này) . Có rất nhiều, nhưng tôi muốn chú ý đến việc tải mã từ mạng bằng tùy chọn Network Boot ( PXE ), cho phép chúng tôi chạy chương trình trên máy tính bất kể hệ điều hành của nó và thậm chí bất kể phương tiện lưu trữ nào kết nối trực tiếp với máy tính:

Khởi động mạng (PXE) là gì và bạn có thể sử dụng nó như thế nào?

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.