Runnable örnekler
Teknik olarak, işletim sistemi olmadan çalışan bir program bir işletim sistemidir. Öyleyse, minicik bir merhaba dünya işletim sistemi oluşturmayı ve çalıştırmayı görelim.
Aşağıdaki tüm örneklerin kodu bu GitHub deposunda bulunmaktadır .
Önyükleme sektörü
X86'da yapabileceğiniz en basit ve en düşük düzey şey , bir önyükleme sektörü türü olan bir Ana Önyükleme Sektörü (MBR) oluşturmak ve ardından bir diske yüklemek.
Burada tek bir printf
çağrı ile bir tane yaratıyoruz :
printf '\364%509s\125\252' > main.img
sudo apt-get install qemu-system-x86
qemu-system-x86_64 -hda main.img
Sonuç:
Ubuntu 18.04, QEMU 2.11.1'de test edilmiştir.
main.img
aşağıdakileri içerir:
\364
octal == 0xf4
hex içinde: bir hlt
komutun işlemesi, CPU'ya çalışmayı durdurmasını söyler.
Bu nedenle programımız hiçbir şey yapmaz: sadece başla ve dur.
Sekizlik kullanıyoruz çünkü \x
onaltılık sayılar POSIX tarafından belirtilmemiştir.
Bu kodlamayı kolayca şu şekilde alabiliriz:
echo hlt > a.asm
nasm -f bin a.asm
hd a
ancak 0xf4
kodlama aynı zamanda elbette Intel el kitabında da belgelenmiştir.
%509s
509 boşluk üret. 510 bayta kadar dosyayı doldurmanız gerekiyor.
\125\252
octal == 0x55
ardından 0xaa
: donanım tarafından istenen sihirli bayt. 511 ve 512 bayt olması gerekir.
Eğer mevcut değilse, donanım bunu önyüklenebilir bir disk olarak kabul etmeyecektir.
Hiçbir şey yapmadan bile, ekrana birkaç karakter basıldığını unutmayın. Bunlar üretici yazılımı tarafından basılır ve sistemi tanımlamaya yarar.
Gerçek donanımda çalıştır
Emülatörler eğlencelidir, ancak donanım asıl meseledir.
Ancak bunun tehlikeli olduğunu ve diskinizi yanlışlıkla silebileceğinizi unutmayın: bunu yalnızca kritik veriler içermeyen eski makinelerde yapın! Daha da iyisi, Raspberry Pi gibi devboard'lar aşağıdaki ARM örneğine bakın.
Tipik bir dizüstü bilgisayar için, şöyle bir şey yapmalısınız:
Resmi bir USB çubuğuna yazın (verilerinizi mahveder!):
sudo dd if=main.img of=/dev/sdX
USB'yi bir bilgisayara takın
aç onu
USB'den başlatmasını söyle.
Bu, bellenimin sabit diskten önce USB'yi seçmesini sağlar.
Makinenizin varsayılan davranışı bu değilse, USB'den önyüklemeyi seçebileceğiniz bir önyükleme menüsü alana kadar Enter, F12, ESC veya bu tür tuhaf tuşlara basmaya devam edin.
Bu menülerdeki arama sırasını yapılandırmak genellikle mümkündür.
Örneğin, eski Lenovo Thinkpad T430, UEFI BIOS 1.16'da şunu görebilirim:
Selam Dünya
Şimdi minimal bir program yaptıktan sonra, merhaba dünyasına geçelim.
Açıkça soru şudur: IO nasıl yapılır? Birkaç seçenek:
- bizim için donanım yazılımı, örneğin BIOS veya UEFI isteyin
- VGA: Yazıldığında ekrana yazdırılan özel bellek bölgesi. Korumalı modda kullanılabilir.
- Bir sürücü yazın ve doğrudan ekran donanımıyla konuşun. Bunu yapmanın "uygun" yolu budur: daha güçlü ama daha karmaşık.
seri port . Bu, ana bilgisayar terminalinden karakterleri gönderen ve alan çok basit bir standarttır.
Kaynak .
Maalesef çoğu modern dizüstü bilgisayarda bulunmuyor, ancak geliştirme kartlarına gitmenin ortak yolu, aşağıdaki ARM örneklerine bakın.
Bu gerçekten bir utançtır, çünkü bu tür arayüzler örneğin Linux çekirdeğini hata ayıklamak için gerçekten yararlıdır .
çiplerin hata ayıklama özelliklerini kullanın. ARM , örneğin onların yarı-temelini çağırıyor . Gerçek donanımda, bazı ek donanım ve yazılım desteği gerektirir, ancak öykünücüler için ücretsiz uygun bir seçenek olabilir. Örnek .
Burada x86'da daha basit olduğu için bir BIOS örneği yapacağız. Ancak bunun en sağlam yöntem olmadığını unutmayın.
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)
}
}
Montaj ve bağlantı:
gcc -c -g -o main.o main.S
ld --oformat binary -o main.img -T linker.ld main.o
Sonuç:
Test edildi: Lenovo Thinkpad T430, UEFI BIOS 1.16. Bir Ubuntu 18.04 ana bilgisayarında oluşturulan disk.
Standart kullanıcı montaj talimatlarının yanı sıra aşağıdakilere de sahibiz:
.code16
: GAS'a 16 bitlik kod vermesini söyler
cli
: yazılım kesintilerini devre dışı bırakın. Bunlar işlemciden sonra işlemcinin tekrar çalışmaya başlamasına neden olabilir.hlt
int $0x10
: bir BIOS araması yapar. Karakterleri tek tek basan şey budur.
Önemli link bayrakları:
--oformat binary
: Çıktı ham ikili derleme kodu, normal kullanıcı çalıştırılabilir dosyaları için olduğu gibi bir ELF dosyası içinde çözmeyin.
Montaj yerine C kullanın
C derleme için derlendiğinden, standart kitaplık olmadan C'yi kullanmak oldukça basittir, sadece yapmanız gereken:
- şeyleri doğru yere hafızaya koymak için bir linker betiği
- GCC'ye standart kütüphaneyi kullanmamasını söyleyen bayraklar
main
Özellikle gereken C durumunu belirleyen küçük bir montaj giriş noktası :
TODO: GitHub’da bazı x86 örnekleri. İşte benim oluşturduğum bir ARM .
Ancak standart kütüphaneyi kullanmak istiyorsanız işler daha eğlenceli hale gelir, çünkü Linux çekirdeğine sahip değiliz, bu da POSIX aracılığıyla C standart kütüphane işlevlerinin çoğunu uygular .
Linux gibi tamamen gelişmiş bir işletim sistemine gitmeden birkaç olasılık:
KOL
ARM'de genel fikirler aynıdır. Yükledim:
Ahududu Pi için, https://github.com/dwelch67/raspberrypi bugün mevcut olan en popüler öğretici gibi gözüküyor.
X86'dan bazı farklılıklar şunlardır:
IO doğrudan sihirli adreslere yazarak yapılıyor, orada hiçbir in
ve out
talimatları.
Buna hafıza eşlenmiş IO denir .
Raspberry Pi gibi bazı gerçek donanımlar için bellenimi (BIOS) kendiniz de disk görüntüsüne ekleyebilirsiniz.
Bu, bellenimin güncellenmesini daha şeffaf hale getirdiğinden, bu iyi bir şeydir.
Yazılım
Gerçekte, önyükleme sektörünüz, sistemin CPU'sunda çalışan ilk yazılım değildir.
Aslında ilk çalışan , bir yazılım olan sözde ürün yazılımıdır:
- donanım üreticileri tarafından yapılan
- tipik olarak kapalı kaynak ancak muhtemel C-tabanlı
- salt okunur bellekte saklanır ve bu nedenle satıcının izni olmadan değişiklik yapılması zor / imkansızdır.
İyi bilinen yazılımlar şunları içerir:
- BIOS : eski tüm mevcut x86 bellenimi. SeaBIOS, QEMU tarafından kullanılan varsayılan açık kaynak uygulamasıdır.
- UEFI : BIOS halefi, daha iyi standartlaştırılmış, ancak daha yetenekli ve inanılmaz derecede şişirilmiş.
- Düzeltme : asil çapraz kemer açık kaynak girişimi
Firmware gibi şeyler yapar:
önyüklenebilir bir şey bulana kadar her sabit disk, USB, ağ vb.
Biz QEMU çalıştırdığınızda, -hda
o diyor main.img
donanıma bağlı bir sabit disk, ve
hda
ilk deneniyor ve kullanılıyor.
ilk 512 byte'ı RAM hafıza adresine yükleyin, 0x7c00
CPU's RIP'ini buraya yerleştirin ve çalışmasına izin verin.
önyükleme menüsü veya BIOS yazdırma çağrıları gibi şeyleri ekranda gösterin
Firmware, çoğu işletim sisteminin bağımlı olduğu işletim sistemi işlevini sunar. Örneğin, bir Python alt kümesi BIOS / UEFI'de çalışacak şekilde gösterilmiştir: https://www.youtube.com/watch?v=bYQ_lq5dcvM
Yazılımların OS'lerden ayırt edilemez olduğu ve yazılımın birinin yapabileceği tek "gerçek" çıplak metal program olduğu söylenebilir.
Bu CoreOS dev'in söylediği gibi :
Zor kısmı
Bir PC'yi çalıştırdığınızda, yonga setini oluşturan cipsler (kuzey köprüsü, güney köprüsü ve SuperIO) henüz doğru şekilde başlatılmadı. BIOS ROM, CPU'dan olabildiğince uzakta olsa bile, buna CPU tarafından erişilebilir, çünkü olması gerekir, aksi takdirde CPU'nun çalıştırması için hiçbir talimatı olmazdı. Bu, BIOS ROM'un tamamen eşlendiği anlamına gelmez, genellikle değil. Ancak önyükleme işlemini devam ettirmek için yeterli haritalama yapılır. Diğer cihazlar, unut gitsin.
Coreboot'u QEMU altında çalıştırdığınızda, daha yüksek Coreboot katmanlarını ve yükleri deneyebilirsiniz, ancak QEMU düşük seviye başlangıç kodunu denemek için çok az fırsat sunar. Birincisi, RAM sadece en baştan işe yarar.
BIOS başlangıç durumunu göster
Donanım çok şey gibi, standardizasyon zayıf olduğunu ve gereken şeylerden biri değil kodunuzu BIOS sonra çalışan başladığında itimat kayıtları başlangıç halidir.
Öyleyse kendinize bir iyilik yapın ve aşağıdaki gibi bazı başlatma kodlarını kullanın: https://stackoverflow.com/a/32509555/895245
Kayıt yaptırır %ds
ve %es
önemli yan etkileri vardır, bu yüzden açıkça kullanmasanız bile bunları sıfırlamanız gerekir.
Bazı emülatörlerin gerçek donanımdan daha iyi olduklarını ve size güzel bir başlangıç durumu sunduğunu unutmayın. Sonra gerçek bir donanıma gittiğin zaman her şey bozulur.
GNU GRUB Multiboot
Önyükleme kesimleri basittir ancak çok uygun değildir:
- disk başına yalnızca bir işletim sisteminiz olabilir
- yük kodu gerçekten küçük olmalı ve 512 bayta sığmalıdır. Bu int 0x13 BIOS çağrısı ile çözülebilir .
- korumalı moda geçmek gibi çok fazla başlangıç yapmanız gerekiyor
Bu sebeplerden dolayı GNU GRUB multiboot adlı daha uygun bir dosya formatı oluşturdu.
Minimal çalışma örneği: https://github.com/cirosantilli/x86-bare-metal-examples/tree/d217b180be4220a0b4a453f31275d38e697a99e0/multiboot/hello-world
Ayrıca USB'yi milyon kez yakmadan tüm donanımları gerçek donanımda kolayca çalıştırabilmek için GitHub örnekler depomda da kullanıyorum . QEMU'da şöyle görünüyor:
İşletim sisteminizi çoklu önyüklemeli bir dosya olarak hazırlarsanız, GRUB normal bir dosya sistemi içinde bulabilir.
Bu, OS görüntülerini altına koyarak, çoğu dağıtımın yaptığı şeydir /boot
.
Çoklu önyükleme dosyaları temelde özel bir başlığa sahip bir ELF dosyasıdır. GRUB tarafından şu adresten belirtilir: https://www.gnu.org/software/grub/manual/multiboot/multiboot.html
Bir çoklu önyüklemeli dosyayı önyüklenebilir bir diske dönüştürebilirsiniz grub-mkrescue
.
El Torito
CD'lere yakılabilecek format: https://en.wikipedia.org/wiki/El_Torito_%28CD-ROM_standard%29
ISO veya USB üzerinde çalışan karma bir görüntü üretmek de mümkündür. Bu ile yapılabilir edilir grub-mkrescue
( örneğin ) ve ayrıca Linux çekirdeği tarafından yapılır make isoimage
kullanarak isohybrid
.
kaynaklar