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?
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?
Câu trả lời:
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 .
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ư:
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
cắm USB trên máy tính
bật nó lên
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:
Sau đó, ở đây tôi phải nhấn F12 để chọn USB làm thiết bị khởi động:
Từ đó, tôi có thể chọn USB làm thiết bị khởi động như thế nà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:
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 printf
cuộ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ả:
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:
main.img
chứa những điều sau đây
\364
in octal == 0xf4
in hex: mã hóa cho một hlt
lệ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ì \x
số 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.
%509s
sản xuất 509 không gian. Cần phải điền vào tệp cho đến byte 510.
\125\252
trong bát phân == 0x55
theo 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à printf
chủ, bạn có thể xác nhận nội dung của main.img
vớ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 20
là 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:
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"
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ả:
Và trên T430:
Đã 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:
-kernel
tù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 đó .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??
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 printf
tớ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ư FreeRTOS và Zephyr .
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:
Đó 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:
T430:
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ác phần mềm nổi tiếng bao gồm:
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, -hda
nói rằng đó main.img
là một đĩa cứng được kết nối với phần cứng và hda
là ổ đĩ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
và %es
có 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 isoimage
sử 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à:
Tôi đã tải lên:
một vài ví dụ đơn giản về QEMU C + Newlib và lắp ráp thô ở đây trên GitHub .
Các ví dụ prompt.c ví dụ có đầu vào từ thiết bị đầu cuối máy chủ của bạn và cho sản lượng lại tất cả thông qua UART mô phỏng:
enter a character
got: a
new alloc of 1 bytes at address 0x0x4000a1c0
enter a character
got: b
new alloc of 2 bytes at address 0x0x4000a1c0
enter a character
Xem thêm: Làm thế nào để tạo các chương trình ARM kim loại trần và chạy chúng trên QEMU?
một thiết lập blinker Raspberry Pi hoàn toàn tự động tại: https://github.com/cirosantilli/raspberry-pi-bare-metal-blinker
Xem thêm: Làm thế nào để chạy chương trình C không có HĐH trên Raspberry Pi?
Để "xem" các đèn LED trên QEMU, bạn phải biên dịch QEMU từ nguồn bằng cờ gỡ lỗi: /raspberrypi/56373/is-it-possible-to-get-the-state-of- the-leds-and-gpios-in-a-qemu-thi đua-like-t
Tiếp theo, bạn nên thử một thế giới xin chào UART. Bạn có thể bắt đầu từ ví dụ blinker và thay thế kernel bằng cái này: https://github.com/dwelch67/raspberrypi/tree/bce377230c2cdd8ff1e40919fdedbc2533ef5a00/uart01
Trước tiên, hãy để UART làm việc với Raspbian như tôi đã giải thích tại: /raspberrypi/38/prepare-for-ssh-without-a-screen/54394#54394 Nó sẽ trông giống như thế này:
Đảm bảo sử dụng đúng chân, nếu không bạn có thể ghi bộ chuyển đổi UART sang USB của mình, tôi đã thực hiện hai lần bằng cách nối đất ngắn mạch và 5V ...
Cuối cùng kết nối với serial từ máy chủ với:
screen /dev/ttyUSB0 115200
Đối với Raspberry Pi, chúng tôi sử dụng thẻ Micro SD thay vì thẻ USB để chứa tệp thực thi của chúng tôi, thông thường bạn cần một bộ chuyển đổi để kết nối với máy tính của mình:
Đừng quên mở khóa bộ điều hợp SD như được hiển thị tại: https://askubfox.com/questions/213889/microsd-card-is-set-to-read-only-state-how-can-i-write-data -on-it / 814585 # 814585
https://github.com/dwelch67/raspberrypi trông giống như hướng dẫn Raspberry Pi kim loại trần phổ biến nhất hiện nay.
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ó in
và out
hướ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
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ốt và tài liệu mở rộ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 :
- Tải đúng vào bộ nhớ theo địa chỉ 0000: 7C00.
- Gọi hàm BootMain được phát triển bằng ngôn ngữ cấp cao.
- 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.
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
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ả .
Tôi cũng nghĩ rằng trong bối cảnh này, điều đáng nói là có 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?