Sistem operasi pada assembler. Penerbangan Burung Kolibri. Apa yang mampu dilakukan oleh OS, ditulis seluruhnya dalam assembler. Asal dan kritik terhadap istilah "bahasa rakitan"

24.06.2020 Kartu memori

Saya katakan segera, jangan tutup artikel dengan pikiran "Sialan, Popov lain." Dia hanya memiliki Ubuntu yang dijilat, dan saya memiliki semuanya dari awal, termasuk kernel dan aplikasi. Jadi, kelanjutan di bawah potongan.

Grup OS: di sini.
Pertama, saya akan memberikan Anda satu tangkapan layar.

Tidak ada lagi dari mereka, dan sekarang secara lebih rinci tentang mengapa saya menulisnya.

Itu adalah malam yang hangat di bulan April, Kamis. Sejak kecil, saya bermimpi menulis OS, ketika saya tiba-tiba berpikir: "Sekarang saya tahu kelebihan dan kekurangannya, mengapa tidak mewujudkan impian saya?". Saya mencari di Google situs tentang topik ini dan menemukan artikel dari Habr: "Bagaimana memulai dan tidak berhenti menulis OS". Terima kasih kepada penulisnya untuk tautan Wiki OSDev di bawah ini. Saya pergi ke sana dan mulai bekerja. Ada dalam satu artikel semua data pada OS minimum. Saya mulai membangun cross-gcc dan binutils dan kemudian menulis ulang semuanya dari sana. Anda seharusnya melihat kegembiraan saya ketika saya melihat tulisan "Halo, dunia kernel!" Saya melompat langsung dari kursi dan menyadari - saya tidak akan menyerah. Saya menulis "konsol" (dalam tanda kutip, saya tidak memiliki akses ke keyboard), tetapi kemudian saya memutuskan untuk menulis sistem jendela. Hasilnya, berhasil, tetapi saya tidak memiliki akses ke keyboard. Dan kemudian saya memutuskan untuk membuat nama berdasarkan Sistem X Window. Googled Y Window System - itu. Akibatnya, ia menyebut Z Window System 0.1, yang termasuk dalam OS365 pre-alpha 0.1. Dan ya, tidak ada yang melihatnya kecuali aku. Kemudian saya menemukan cara menerapkan dukungan keyboard. Tangkapan layar versi pertama, ketika tidak ada apa-apa, bahkan sistem jendela:

Itu bahkan tidak memindahkan kursor teks, seperti yang Anda lihat. Lalu saya menulis pasangan aplikasi sederhana berdasarkan Z. Dan di sini adalah rilis 1.0.0 alpha. Ada banyak hal, bahkan menu sistem. TETAPI pengelola file dan kalkulator tidak berfungsi.

Saya langsung diteror oleh seorang teman yang hanya peduli dengan kecantikan (Mitrofan, maaf). Dia berkata, “Mencuci mode VBE 1024 * 768 * 32, mencuci, mencuci! Yah, mereka mabuk! Yah, aku sudah bosan mendengarkannya dan masih membasuhnya. Lebih lanjut tentang implementasi di bawah ini.

Saya melakukan semuanya dengan bootloader saya, yaitu GRUB "ohm. Dengan itu, Anda dapat mengatur mode grafis tanpa komplikasi dengan menambahkan beberapa baris ajaib ke header Multiboot.

Setel SELURUH, 1<<0 .set MEMINFO, 1<<1 .set GRAPH, 1<<2 .set FLAGS, ALIGN | MEMINFO | GRAPH .set MAGIC, 0x1BADB002 .set CHECKSUM, -(MAGIC + FLAGS) .align 4 .long MAGIC .long FLAGS .long CHECKSUM .long 0, 0, 0, 0, 0 .long 0 # 0 = set graphics mode .long 1024, 768, 32 # Width, height, depth
Dan kemudian saya mengambil alamat framebuffer dan resolusi layar dari struktur informasi Multiboot dan menulis piksel di sana. VESA melakukan semuanya dengan sangat bingung - warna RGB harus dimasukkan dalam urutan terbalik (bukan R G B, tetapi B G R). Saya tidak mengerti selama beberapa hari - mengapa piksel tidak ditampilkan!? Pada akhirnya, saya menyadari bahwa saya lupa mengubah nilai 16 konstanta warna dari 0,15 menjadi setara RGB-nya. Akibatnya, saya melepaskannya, pada saat yang sama menyapu latar belakang gradien. Kemudian saya membuat konsol, 2 aplikasi dan merilis 1.2. Oh ya, saya hampir lupa - Anda dapat mengunduh OS di

Hari ini, di Kunstkamera kami, contoh yang aneh adalah sistem operasi yang ditulis dalam assembler murni. Bersama dengan driver, cangkang grafis, lusinan program dan game pra-instal, dibutuhkan kurang dari satu setengah megabita. Temui Hummingbird OS yang sangat cepat dan didominasi oleh Rusia.

Perkembangan Hummingbird berjalan cukup cepat hingga tahun 2009. Burung itu belajar terbang dengan perangkat keras yang berbeda, membutuhkan minimal Pentium pertama dan delapan megabita RAM. Persyaratan sistem minimum untuk Hummingbird adalah:

  • CPU: Pentium, AMD 5x86 atau Cyrix 5x86 tanpa MMX pada 100 MHz;
  • RAM: 8MB;
  • Kartu Grafis: VESA-kompatibel dengan dukungan untuk mode VGA (640 × 480 × 16).

Hummingbird modern adalah "pembuatan malam" yang diperbarui secara berkala dari versi resmi terbaru, yang dirilis pada akhir tahun 2009. Kami menguji build 0.7.7.0+ tertanggal 20 Agustus 2017.

PERINGATAN

Dalam pengaturan default, KolibriOS tidak memiliki akses ke disk yang terlihat melalui BIOS. Pikirkan baik-baik dan buat cadangan sebelum mengubah pengaturan ini.

Meskipun perubahan pada bangunan malam kecil, mereka telah terakumulasi cukup selama bertahun-tahun. Hummingbird yang diperbarui dapat menulis ke partisi FAT16-32 / ext2 - ext4 dan mendukung sistem file populer lainnya (NTFS, XFS, ISO-9660) dalam mode baca. Ini menambahkan dukungan untuk USB dan kartu jaringan, tumpukan TCP / IP dan codec suara ditambahkan. Secara umum, Anda sudah dapat melakukan sesuatu di dalamnya, dan tidak hanya melihat sekali pada sistem operasi ultra-ringan dengan GUI dan terkesan dengan kecepatan startup.



Seperti versi sebelumnya, Hummingbird terbaru ditulis dalam flat assembler (FASM) dan menempati satu floppy disk - 1,44 MB. Berkat ini, itu dapat sepenuhnya ditempatkan di beberapa memori khusus. Misalnya, pengrajin menulis KolibriOS langsung ke Flash BIOS. Selama operasi, itu dapat sepenuhnya ditempatkan di cache beberapa prosesor. Bayangkan saja: seluruh sistem operasi, bersama dengan program dan driver, di-cache!

INFORMASI

Saat mengunjungi situs kolibrios.org, browser mungkin memperingatkan bahaya. Penyebabnya, rupanya, adalah program assembler yang di distribusikan. Sekarang VirusTotal mendefinisikan situs sebagai benar-benar aman.

"Hummingbird" mudah dimuat dari floppy disk, hard drive, flash drive, Live CD atau di mesin virtual. Untuk emulasi, cukup menentukan jenis OS "lainnya", mengalokasikan satu inti prosesor dan beberapa RAM untuk itu. Tidak perlu menghubungkan disk, dan jika ada router dengan DHCP, Hummingbird akan langsung terhubung ke Internet dan jaringan lokal. Segera setelah mengunduh, Anda akan melihat pemberitahuan.


Satu masalah - protokol HTTPS tidak didukung oleh browser Hummingbird bawaan. Oleh karena itu, tidak mungkin untuk melihat situs di dalamnya, serta membuka halaman Google, Yandex, Wikipedia, Sberbank ... sebenarnya, tidak ada alamat biasa. Semua orang beralih ke protokol yang aman sejak lama. Satu-satunya situs dengan HTTP murni jadul yang saya temui adalah "portal Pemerintah Rusia", tetapi tidak terlihat terbaik di browser teks.



Pengaturan penampilan di Hummingbird telah meningkat selama bertahun-tahun, tetapi masih jauh dari ideal. Daftar mode video yang didukung ditampilkan pada layar boot Hummingbird saat Anda menekan tombol huruf a.



Daftar opsi yang tersedia kecil, dan resolusi yang diinginkan mungkin tidak ada di dalamnya. Jika Anda memiliki kartu grafis dengan GPU AMD (ATI), maka Anda dapat langsung menambahkan pengaturan khusus. Untuk melakukan ini, Anda harus meneruskan parameter -m ke bootloader ATIKMS x x , Misalnya:

/RD/1/DRIVER/ATIKMS -m1280x800x60 -1

Di sini /RD/1/DRIVERS/ATIKMS adalah jalur ke bootloader (RD - RAM Disk).

Saat sistem sedang berjalan, mode video yang dipilih dapat dilihat dengan perintah vmode dan (secara teoritis) dialihkan secara manual. Jika Hummingbird berjalan di mesin virtual, maka jendela ini akan tetap kosong, tetapi dengan boot bersih, driver video Intel dapat ditambahkan dari i915 ke Skylake inklusif.

Anehnya, banyak game cocok di KolibriOS. Di antara mereka ada permainan logis dan arcade, tag, ular, tank (tidak, bukan WoT) - seluruh "Pusat Game"! Bahkan Doom dan Quake diporting ke Hummingbird.



Hal penting lainnya adalah pembaca FB2READ. Ini bekerja dengan benar dengan Cyrillic dan memiliki pengaturan tampilan teks.



Saya sarankan untuk menyimpan semua file pengguna di USB flash drive, tetapi harus terhubung melalui port USB 2.0. Flash drive USB 3.0 kami (dalam port USB 2.0) dengan kapasitas 16 GB dengan sistem file NTFS segera ditentukan. Jika Anda perlu menulis file, maka Anda harus menghubungkan USB flash drive dengan partisi FAT32.



Distribusi Hummingbird mencakup tiga pengelola file, utilitas untuk melihat gambar dan dokumen, pemutar audio dan video, dan aplikasi pengguna lainnya. Namun, fokusnya adalah pada pengembangan bahasa assembly.



Editor teks bawaan memiliki penyorotan sintaks ASM dan bahkan memungkinkan Anda untuk segera menjalankan program yang diketik.



Di antara alat pengembangan ada kompiler Oberon-07/11 untuk i386 Windows, Linux dan KolibriOS, serta emulator tingkat rendah: E80 - emulator ZX Spectrum, FCE Ultra - salah satu emulator NES terbaik, DOSBox v.0.74 dan yang lain. Semuanya secara khusus diangkut ke Hummingbird.

Jika Anda meninggalkan KolibriOS selama beberapa menit, screensaver akan dimulai. Baris kode akan berjalan di layar, di mana Anda dapat melihat referensi ke MenuetOS.

Lanjutan tersedia hanya untuk anggota

Opsi 1. Bergabunglah dengan komunitas "situs" untuk membaca semua materi di situs

Keanggotaan dalam komunitas selama periode yang ditentukan akan memberi Anda akses ke SEMUA materi Peretas, meningkatkan diskon kumulatif pribadi Anda dan memungkinkan Anda untuk mengumpulkan peringkat Skor Xakep profesional!

perakit

perakit(dari bahasa Inggris assemble - to assemble) - kompiler dari bahasa assembly ke perintah bahasa mesin.
Untuk setiap arsitektur prosesor dan untuk setiap OS atau keluarga OS, ada Assembler. Ada juga yang disebut "cross-assembler", yang memungkinkan mesin dengan satu arsitektur (atau di lingkungan satu OS) untuk merakit program untuk arsitektur target lain atau OS lain, dan mendapatkan kode yang dapat dieksekusi dalam format yang sesuai untuk dieksekusi pada arsitektur target atau di lingkungan target.OS.

arsitektur x86

Assembler untuk DOS

Assembler paling terkenal untuk sistem operasi DOS adalah Borland Turbo Assembler (TASM) dan Microsoft Macro Assembler (MASM). Juga pada suatu waktu, assembler sederhana A86 sangat populer.
Awalnya, mereka hanya mendukung instruksi 16-bit (sebelum munculnya prosesor Intel 80386). Versi TASM dan MASM yang lebih baru mendukung instruksi 32-bit, serta semua instruksi yang diperkenalkan pada prosesor yang lebih modern, dan sistem instruksi khusus arsitektur (seperti, misalnya, MMX, SSE, 3DNow!, dll.) .

Microsoft Windows

Dengan munculnya sistem operasi Microsoft Windows, ekstensi TASM yang disebut TASM32 muncul, yang memungkinkan untuk membuat program untuk dijalankan di lingkungan Windows. Versi Tasm terbaru yang diketahui adalah 5.3, yang mendukung instruksi MMX, dan saat ini disertakan dalam Turbo C++ Explorer. Namun secara resmi pengembangan program dihentikan sama sekali.
Microsoft memelihara produk yang disebut Microsoft Macro Assembler. Ini terus berkembang hingga hari ini, dengan versi terbaru termasuk dalam DDK. Tetapi versi program yang ditujukan untuk membuat program untuk DOS tidak sedang dikembangkan. Selain itu, Stephen Hutchesson membuat paket pemrograman MASM yang disebut "MASM32".

GNU dan GNU/Linux

Sistem operasi GNU mencakup kompiler gcc, yang mencakup assembler gas (GNU Assembler) menggunakan sintaks AT&T, tidak seperti kebanyakan assembler populer lainnya yang menggunakan sintaks Intel.

Perakit portabel

Ada juga proyek assembler terbuka, yang versinya tersedia untuk berbagai sistem operasi, dan yang memungkinkan Anda memperoleh file objek untuk sistem ini. Assembler ini disebut NASM (Netwide Assembler).
YASM adalah versi NASM yang ditulis ulang dengan lisensi dari awal (dengan beberapa pengecualian).
FASM (Flat Assembler) adalah assembler muda di bawah lisensi BSD yang dimodifikasi untuk melarang lisensi ulang (termasuk di bawah GNU GPL). Ada versi untuk KolibriOS, GNU/Linux, MS-DOS dan Microsoft Windows, menggunakan sintaks Intel dan mendukung instruksi AMD64.

arsitektur RISC


MCS-51
AVR
Saat ini ada 2 kompiler Atmel (AVRStudio 3 dan AVRstudio4). Versi kedua adalah upaya untuk memperbaiki yang pertama tidak terlalu berhasil. Ada juga assembler di WinAVR.
LENGAN
AVR32
MSP430
PowerPC

Perakitan dan kompilasi

Proses menerjemahkan program bahasa assembly ke dalam kode objek disebut assembly. Tidak seperti kompilasi, perakitan adalah proses yang kurang lebih tidak ambigu dan dapat dibalik. Dalam bahasa assembly, setiap mnemonic sesuai dengan satu instruksi mesin, sedangkan dalam bahasa pemrograman tingkat tinggi, sejumlah besar instruksi yang berbeda dapat bersembunyi di balik setiap ekspresi. Pada prinsipnya pembagian ini agak arbitrer, sehingga terkadang penerjemahan program assembler disebut juga kompilasi.

bahasa campuran

bahasa campuran- jenis bahasa pemrograman tingkat rendah, yang merupakan format untuk merekam instruksi mesin yang nyaman untuk persepsi manusia. Seringkali, untuk singkatnya, itu hanya disebut assembler, yang tidak benar.

Perintah bahasa rakitan sesuai satu dengan satu untuk perintah prosesor dan, pada kenyataannya, mewakili bentuk simbolis dari notasi (mnemocode) dari perintah dan argumennya. Bahasa assembly juga menyediakan abstraksi pemrograman dasar: menghubungkan bagian-bagian dari program dan data melalui label dengan nama simbolis (selama perakitan, alamat dihitung untuk setiap label, setelah itu setiap kemunculan label diganti dengan alamat ini) dan arahan.
Arahan perakitan memungkinkan Anda untuk memasukkan blok data (dijelaskan secara eksplisit atau dibaca dari file) ke dalam program; ulangi fragmen tertentu beberapa kali; kompilasi fragmen sesuai dengan kondisi; atur alamat eksekusi fragmen agar berbeda dari alamat lokasi memori[tentukan!]; ubah nilai label selama kompilasi; gunakan definisi makro dengan parameter, dll.
Setiap model prosesor, pada prinsipnya, memiliki serangkaian instruksinya sendiri dan bahasa rakitan (atau dialek) yang sesuai.

Keuntungan dan kerugian

Keuntungan dari bahasa assembly

Jumlah minimum kode redundan, yaitu penggunaan instruksi dan akses memori yang lebih sedikit, memungkinkan Anda meningkatkan kecepatan dan mengurangi ukuran program.
Memastikan kompatibilitas penuh dan penggunaan maksimum kemampuan platform yang diinginkan: penggunaan instruksi khusus dan fitur teknis platform ini.
Ketika pemrograman di assembler, fitur khusus tersedia: akses langsung ke perangkat keras, port I / O dan register prosesor khusus, serta kemampuan untuk menulis kode yang dimodifikasi sendiri (yaitu, metaprogramming, dan tanpa memerlukan penerjemah perangkat lunak) .
Teknologi keamanan terbaru yang diterapkan dalam sistem operasi tidak memungkinkan pembuatan kode yang dapat dimodifikasi sendiri, karena mereka mengecualikan eksekusi instruksi dan penulisan secara simultan di area memori yang sama (teknologi W^X dalam sistem BSD, DEP di Windows).

Kekurangan bahasa assembly

Sejumlah besar kode dan sejumlah besar tugas kecil tambahan, yang mengarah pada fakta bahwa kode menjadi sangat sulit untuk dibaca dan dipahami, dan oleh karena itu menjadi lebih sulit untuk men-debug dan menyempurnakan program, serta kesulitan mengimplementasikan pemrograman paradigma dan konvensi lainnya. yang mengarah pada kompleksitas pengembangan kolaboratif.
Lebih sedikit perpustakaan yang tersedia, kompatibilitasnya rendah satu sama lain.
Tidak portabel ke platform lain (selain kompatibel dengan biner).

Aplikasi

Langsung mengikuti dari kelebihan dan kekurangannya.
Karena sangat merepotkan untuk menulis program besar dalam bahasa rakitan, program tersebut ditulis dalam bahasa tingkat tinggi. Di assembler, mereka menulis fragmen atau modul kecil yang sangat penting:
kinerja (pengemudi);
ukuran kode (sektor boot, perangkat lunak untuk mikrokontroler dan prosesor dengan sumber daya terbatas, virus, perlindungan perangkat lunak);
fitur khusus: bekerja langsung dengan perangkat keras atau kode mesin, yaitu, pemuat sistem operasi, driver, virus, sistem perlindungan.

Menghubungkan kode rakitan ke bahasa lain

Karena hanya bagian-bagian program yang paling sering ditulis dalam assembler, mereka harus dihubungkan dengan bagian-bagian lainnya dalam bahasa lain. Ini dicapai dengan 2 cara utama:
Pada waktu kompilasi- memasukkan fragmen assembler ke dalam program (eng. assembler inline) dengan arahan bahasa khusus, termasuk prosedur penulisan dalam bahasa assembler. Metode ini nyaman untuk transformasi data sederhana, tetapi kode assembler lengkap, dengan data dan subrutin, termasuk subrutin dengan banyak input dan output yang tidak didukung oleh bahasa tingkat tinggi, tidak dapat dilakukan dengan menggunakannya.
Pada tahap membangun, atau kompilasi terpisah. Agar modul penautan dapat berinteraksi, fungsi penautan cukup mendukung konvensi pemanggilan dan tipe data yang diperlukan. Modul terpisah dapat ditulis dalam bahasa apa pun, termasuk bahasa rakitan.

Sintaksis

Tidak ada standar yang diterima secara umum untuk sintaks bahasa assembly. Namun, ada standar yang dipatuhi oleh sebagian besar pengembang bahasa assembly. Standar utama tersebut adalah sintaks Intel dan sintaks AT&T.

instruksi

Format umum untuk menulis instruksi sama untuk kedua standar:

[label:] opcode [operan] [;komentar]

di mana opcode secara langsung merupakan mnemonic dari instruksi ke prosesor. Awalan dapat ditambahkan ke dalamnya (pengulangan, perubahan tipe pengalamatan, dll.).
Operand dapat berupa konstanta, nama register, alamat RAM, dll. Perbedaan antara standar Intel dan AT&T terutama berkaitan dengan urutan operan yang terdaftar dan sintaksnya untuk metode pengalamatan yang berbeda.
Mnemonik yang digunakan biasanya sama untuk semua prosesor dari arsitektur atau keluarga arsitektur yang sama (di antara mnemonik yang dikenal luas adalah prosesor dan pengontrol Motorola, ARM, x86). Mereka dijelaskan dalam spesifikasi prosesor. Kemungkinan pengecualian:
Jika assembler menggunakan sintaks AT&T lintas platform (mnemonik asli dikonversi ke sintaks AT&T)
Jika awalnya ada dua standar untuk menulis mnemonik (sistem instruksi diwarisi dari prosesor pabrikan lain).
Misalnya, prosesor Zilog Z80 mewarisi set instruksi Intel i8080, memperluasnya dan mengubah mnemonik (dan penunjukan register) dengan caranya sendiri. Misalnya, saya mengubah mov Intel menjadi ld. Prosesor Motorola Fireball mewarisi set instruksi Z80, menguranginya sedikit. Namun, Motorola telah resmi kembali ke Intel mnemonik. Dan saat ini, setengah dari perakit Fireball bekerja dengan mnemonik Intel, dan setengah lagi dengan mnemonik Zilog.

arahan

Selain instruksi, program mungkin berisi arahan: perintah yang tidak diterjemahkan langsung ke dalam instruksi mesin, tetapi mengontrol operasi kompiler. Set dan sintaksnya sangat bervariasi dan tidak bergantung pada platform perangkat keras, tetapi pada kompiler yang digunakan (menyebabkan dialek bahasa dalam keluarga arsitektur yang sama). Sebagai arahan "gentleman's set", kita dapat membedakan:
mendefinisikan data (konstanta dan variabel)
mengelola organisasi program dalam memori dan parameter file output
mengatur mode kompiler
semua jenis abstraksi (yaitu elemen bahasa tingkat tinggi) - dari desain prosedur dan fungsi (untuk menyederhanakan penerapan paradigma pemrograman prosedural) hingga struktur dan loop bersyarat (untuk paradigma pemrograman terstruktur)
makro

Contoh program

Contoh program Hello world untuk MS-DOS untuk arsitektur x86 dalam dialek TASM:

.MODEL KODE TINY SEGMEN ASUMSI CS:CODE, DS:CODE ORG 100h MULAI: mov ah,9 mov dx,OFFSET Msg int 21h int 20h Msg DB "Hello World",13,10,"$" KODE BERAKHIR AKHIR

Asal dan kritik terhadap istilah "bahasa rakitan"

Jenis bahasa ini mendapatkan namanya dari nama penerjemah (compiler) dari bahasa-bahasa ini - assembler (bahasa Inggris assembler - assembler). Nama yang terakhir adalah karena fakta bahwa pada komputer pertama tidak ada bahasa tingkat yang lebih tinggi, dan satu-satunya alternatif untuk membuat program menggunakan assembler adalah pemrograman langsung dalam kode.
Bahasa assembly dalam bahasa Rusia sering disebut "assembler" (dan sesuatu yang terkait dengannya - "assembler"), yang, menurut terjemahan bahasa Inggris dari kata tersebut, tidak benar, tetapi sesuai dengan aturan bahasa Rusia. Namun, assembler (program) itu sendiri juga disebut hanya "assembler" dan bukan "kompiler bahasa assembler", dll.
Penggunaan istilah "bahasa rakitan" juga dapat menyebabkan kesalahpahaman bahwa ada satu bahasa tingkat rendah, atau setidaknya standar untuk bahasa tersebut. Saat memberi nama bahasa di mana program tertentu ditulis, diinginkan untuk menentukan arsitektur mana yang dimaksudkan dan dialek bahasa apa yang ditulis.

Baru-baru ini saya memutuskan untuk belajar assembler, tetapi saya tidak tertarik membuang-buang baris kode. Saya berpikir bahwa ketika saya belajar assembler, saya akan menguasai beberapa mata pelajaran. Jadi pilihan saya jatuh pada menulis bootloader. Hasil temuan saya ada di blog ini.

Saya ingin segera mengatakan bahwa saya menyukai teori yang dipadukan dengan praktik, jadi mari kita mulai.

Pertama saya akan menunjukkan cara membuat yang sederhana MBR sehingga kita dapat menikmati hasilnya sesegera mungkin. Ketika kita menjadi lebih kompleks dengan contoh-contoh praktis, saya akan memberikan informasi teoretis.

Mari kita buat bootloader USB flash drive terlebih dahulu!

Perhatian!!! Program assembler pertama kami akan bekerja baik untuk flash drive dan untuk perangkat lain seperti Floppy disk atau Hard disk. Selanjutnya, agar semua contoh berfungsi dengan benar, saya akan memberikan sejumlah klarifikasi mengenai pengoperasian kode pada perangkat yang berbeda.

Kami akan menulis ke kegemaran, karena dianggap sebagai kompiler terbaik untuk menulis pemuat, yaitu MBR. Alasan kedua untuk memilih Fasm adalah karena sangat menyederhanakan proses kompilasi file. Tidak ada arahan baris perintah, dll. omong kosong yang benar-benar dapat menghambat belajar assembler dan mencapai tujuan Anda. Jadi, pada tahap awal, kami membutuhkan dua program dan beberapa tidak perlu flashdisk kecil. Saya menggali 1Gb (diformat dengan cepat, dan itu tidak disayangkan, jika ada). Setelah bootloader kami bekerja, flash drive akan berhenti berfungsi secara normal. windows 7 saya menolak untuk memformat flash drive. Saya menyarankan Anda untuk menghidupkan kembali flash drive dengan utilitas Alat Format Penyimpanan Disk USB HP ( HPUSBFW.EXE) atau utilitas lain untuk memformat flash drive.

Instal dan lempar pintasan yang sesuai di desktop atau di mana pun Anda suka.

Persiapan selesai, mari kita lanjutkan ke tindakan

Buka Fasmw.exe dan tulis yang berikut di sana. Kami akan membuat sketsa kode minimum untuk melihat hasilnya. Nanti kita akan analisa apa nakalyakano disini. Saya akan berkomentar singkat.

kode FASM: ============= boot.asm =================

org 7C00h ; alamat program kami dihitung sesuai dengan arahan ini

gunakan16 ; kode heksadesimal dihasilkan

cli ; nonaktifkan interupsi untuk mengubah alamat di register segmen

kapak bergerak, 0

mov sp, 7C00h

sti ; aktifkan interupsi (setelah mengubah alamat)

mov ax, 0003h ; atur mode video untuk menampilkan string di layar

int 10j

mov ax, 1301h ; fungsi output string aktual 13h int 10h (lebih lanjut tentang itu nanti)

mov bp, stroka ;alamat string keluaran

mov dx, 0000h ;baris dan kolom tempat teks ditampilkan

mov cx, 15 ;jumlah karakter dalam string keluaran

mov bx, 000eh ;00-video nomor halaman (lebih baik tidak menyentuh) 0e-karakter atribut (warna, latar belakang)

int 10j

jmp $ ;stalk di tempat (mengulang program pada titik ini)

baris db "Oke, MBR dimuat!"

kali 510 - ($ - $$) db 0 ;mengisi dengan nol jarak antara byte sebelumnya dan terakhir

db 0x55 ,0xAA ;dua byte terakhir

Kompilasi kode ini (Ctrl + F9) ke dalam fasm "e dan simpan file biner yang dihasilkan sebagai boot.bin ke beberapa tempat yang nyaman. Sebelum menulis biner kita ke USB flash drive, sedikit teori.

Ketika Anda mencolokkan USB flash drive ke komputer, sama sekali tidak jelas bagi sistem BIOS bahwa Anda ingin boot dari USB flash drive, jadi dalam pengaturan BIOS Anda harus memilih perangkat dari mana Anda ingin boot. kami memilih untuk mem-boot dari USB (Anda harus memikirkan cara melakukannya sendiri , karena antarmuka BIOS memiliki berbagai variasi... Anda dapat mencari pengaturan BIOS untuk motherboard Anda di Google, biasanya tidak ada yang rumit).

Sekarang BIOS mengetahui bahwa Anda ingin melakukan booting dari flash drive, BIOS harus memastikan bahwa sektor nol pada flash drive dapat di-boot. Untuk melakukan ini, BIOS terlihat dua byte terakhir dari sektor nol dan, jika sama dengan 0x55 0xAA, baru kemudian akan dimuat ke dalam RAM. Jika tidak, BIOS hanya akan melewati flash drive Anda. Setelah menemukan dua byte ajaib ini, ia memuat sektor nol ke dalam RAM di alamat 0000: 7C00h, dan kemudian melupakan flash drive dan mentransfer kontrol ke alamat ini. Sekarang semua kekuasaan atas komputer milik bootloader Anda, dan itu, bertindak dari RAM, dapat memuat kode tambahan dari USB flash drive. Sekarang kita akan melihat bagaimana sektor ini terlihat dalam program DMDE.

1. Masukkan flash drive Anda ke komputer dan pastikan tidak berisi informasi yang Anda butuhkan.

2.Buka program DMDE. Baca semua tindakan lebih lanjut dalam gambar:

Setelah menonton komik ini, Anda akan memiliki keterampilan untuk mengunduh MBR Anda ke flash drive. Dan seperti inilah hasil bootloader kami yang sudah lama ditunggu-tunggu:


Omong-omong, jika kita berbicara tentang kode loader minimum, maka mungkin terlihat seperti ini:

Org 7C00h
jmp$
db 508 dup(0)
db 0x55.0xAA

Pemuat seperti itu, setelah menerima kontrol, cukup menutup komputer, menjalankan satu perintah jmp $ yang tidak berarti dalam satu siklus. Saya menyebutnya stagnasi.

Saya memposting video di YouTube yang mungkin bisa membantu Anda:

Akhirnya, beberapa fakta singkat tentang cara kerja bootloader:

1. Bootloader alias bootloader alias MBR memiliki ukuran 512 byte. Secara historis,
bahwa kondisi ini harus dipenuhi untuk mendukung media dan perangkat yang lebih tua.
2. Bootloader selalu berada di sektor nol dari flash drive, floppy disk, hard disk, dari sudut pandang program DMDE atau editor hex lainnya yang memungkinkan Anda bekerja dengan perangkat. Untuk memuat biner (boot.bin kami) ke salah satu perangkat yang terdaftar, kami tidak perlu memikirkan struktur fisik internalnya. Program DMDE hanya mengetahui cara membaca sektor pada perangkat ini dan menampilkannya dalam mode LBA (cukup beri nomor dari 0 hingga sektor terakhir). Anda dapat membaca tentang LBA
3. Bootloader harus selalu diakhiri dengan dua byte 0x55 0xAA.
4. Loader selalu dimuat ke dalam memori pada 0000:7C00h.
5. Bootloader memulai sistem operasi.


Asli: AsmSchool: Buat sistem operasi
Pengarang: Mike Saunders
Tanggal publikasi: 15 April 2016
Terjemahan: A. Panin
Tanggal transfer: 16 April 2016

Bagian 4: Dengan keterampilan yang telah Anda pelajari dari artikel sebelumnya dalam seri ini, Anda dapat mulai mengembangkan sistem operasi Anda sendiri!

Untuk apa?

  • Untuk memahami cara kerja compiler.
  • Untuk memahami instruksi dari unit pemrosesan pusat.
  • Untuk mengoptimalkan kode Anda dalam hal kinerja.

Selama beberapa bulan, kami telah menempuh perjalanan panjang, yang dimulai dengan pengembangan program bahasa rakitan sederhana untuk Linux dan berakhir di artikel terakhir dalam seri dengan pengembangan kode mandiri yang berjalan di komputer pribadi. tanpa sistem operasi. Nah, sekarang kami akan mencoba mengumpulkan semua informasi bersama dan membuat sistem operasi yang nyata. Ya, kami akan mengikuti jejak Linus Torvalds, tetapi pertama-tama ada baiknya menjawab pertanyaan berikut: "Apa itu sistem operasi? Fungsi mana yang harus kita buat ulang?".

Pada artikel ini, kami hanya akan fokus pada fungsi utama sistem operasi: memuat dan menjalankan program. Sistem operasi yang kompleks melakukan lebih banyak fungsi, seperti mengelola memori virtual dan memproses paket jaringan, tetapi mereka membutuhkan kerja terus menerus selama bertahun-tahun untuk diimplementasikan dengan benar, jadi dalam artikel ini kami hanya akan mempertimbangkan fungsi utama yang ada di sistem operasi apa pun. Bulan lalu kami mengembangkan sebuah program kecil yang muat di sektor 512-byte floppy disk (sektor pertamanya), dan sekarang kami akan memodifikasinya sedikit untuk menambahkan fungsi memuat data tambahan dari disk.

Pengembangan Bootloader

Kita dapat mencoba untuk menjaga sistem operasi kita sekecil mungkin untuk menempatkannya di sektor 512-byte pertama dari floppy disk, yang dimuat oleh BIOS, tetapi dalam kasus ini kita tidak akan dapat mengimplementasikannya. setiap fungsi yang menarik. Oleh karena itu, kita akan menggunakan 512 byte ini untuk menempatkan kode biner pemuat sistem sederhana, yang akan memuat kode biner kernel OS ke dalam RAM dan menjalankannya. (Setelah itu, kami akan mengembangkan kernel OS itu sendiri, yang akan memuat kode biner program lain dari disk dan juga menjalankannya, tetapi kami akan membicarakannya nanti.)

Anda dapat mengunduh kode sumber untuk contoh yang dibahas dalam artikel ini di www.linuxvoice.com/code/lv015/asmschool.zip . Dan ini adalah kode untuk bootloader kami dari file bernama boot.asm:

BITS 16 jmp mulai singkat; Lompat ke label skipping disk description nop ; Penambahan sebelum deskripsi disk %include "bpb.asm" start: mov ax, 07C0h ; Muat alamat mov ds, ax ; Segmen data mov ax, 9000h ; Siapkan stack mov ss, axe mov sp, 0FFFFh ; Tumpukan tumbuh ke bawah! cld ; Setel tanda arah mov si, kern_filename panggil load_file jmp 2000h:0000h ; Lompat ke biner kernel OS yang dimuat dari file kern_filename db "MYKERNELBIN" %include "disk.asm" kali 510-($-$$) db 0 ; Nol padding kode biner hingga 510 byte dw 0AA55h ; Buffer tanda akhir kode biner pemuat boot: ; Mulai buffer untuk konten disk

Dalam kode ini, instruksi CPU pertama adalah instruksi jmp, yang terletak setelah direktif BITS, yang memberitahu assembler NASM bahwa mode 16-bit sedang digunakan. Seperti yang mungkin Anda ingat dari artikel sebelumnya dalam seri ini, eksekusi kode biner 512-byte yang dimuat oleh BIOS dari disk dimulai dari awal, tetapi kita harus melompat ke label untuk melewati kumpulan data khusus. Jelas, bulan lalu kami baru saja menulis kode ke awal disk (menggunakan utilitas dd), dan membiarkan sisa ruang disk kosong.

Sekarang kita harus menggunakan floppy disk dengan sistem file MS-DOS (FAT12) yang sesuai, dan agar dapat bekerja dengan benar dengan sistem file ini, kita perlu menambahkan satu set data khusus di dekat awal sektor. Set ini disebut "BIOS Parameter Block" (BPB) dan berisi data seperti label disk, jumlah sektor, dan sebagainya. Seharusnya tidak menarik minat kami pada tahap ini, karena topik semacam itu dapat dikhususkan untuk lebih dari satu seri artikel, itulah sebabnya kami menempatkan semua instruksi dan data yang terkait dengannya dalam file kode sumber terpisah yang disebut bpb.asm .

Berdasarkan hal di atas, arahan dari kode kami ini sangat penting:

%termasuk "bpb.asm"

Ini adalah arahan NASM yang memungkinkan konten file sumber yang ditentukan untuk dimasukkan ke dalam file sumber saat ini selama perakitan. Dengan demikian, kami akan dapat membuat kode pemuat sistem kami sesingkat dan semudah mungkin dengan memindahkan semua detail implementasi blok parameter BIOS ke dalam file terpisah. Blok parameter BIOS harus ditempatkan tiga byte setelah awal sektor, dan karena instruksi jmp hanya menempati dua byte, kita harus menggunakan instruksi nop (namanya singkatan dari "tidak ada operasi" - ini adalah instruksi yang tidak melakukan apa-apa tetapi buang siklus CPU) untuk mengisi byte yang tersisa.

Bekerja dengan tumpukan

Selanjutnya, kita harus menggunakan instruksi yang mirip dengan yang dibahas dalam artikel sebelumnya untuk menyiapkan register dan tumpukan, serta instruksi cld (singkatan dari "arah yang jelas"), yang memungkinkan Anda untuk mengatur bendera arah untuk instruksi tertentu, seperti instruksi lodsb, yang ketika dieksekusi, akan menaikkan nilai dalam register SI daripada menurunkannya.

Setelah itu, kami menempatkan alamat string di register SI dan memanggil fungsi load_file kami. Tapi pikirkan sejenak - kami belum mengembangkan fitur ini! Ya, itu benar, tetapi implementasinya dapat ditemukan di file kode sumber lain yang kami sertakan bernama disk.asm .

Sistem file FAT12, yang digunakan pada disket yang diformat dalam MS-DOS, adalah salah satu sistem file paling sederhana yang pernah ada, tetapi juga memerlukan cukup banyak kode untuk bekerja dengan isinya. Subrutin load_file panjangnya sekitar 200 baris dan tidak akan ditampilkan dalam artikel ini, karena kami sedang mempertimbangkan pengembangan sistem operasi, bukan driver untuk sistem file tertentu, oleh karena itu, sangat tidak bijaksana untuk membuang-buang ruang di halaman log lewat sini. Secara umum, kami menyertakan file kode sumber disk.asm hampir sebelum akhir file sumber saat ini dan kami dapat melupakannya. (Jika Anda masih tertarik dengan struktur sistem file FAT12, Anda dapat membaca ikhtisar yang sangat baik di http://tinyurl.com/fat12spec , dan kemudian melihat ke file kode sumber disk.asm - kode yang terkandung di dalamnya adalah dikomentari dengan baik.)

Bagaimanapun, subrutin load_file memuat kode biner dari file dengan nama yang diberikan dalam register SI ke segmen 2000 dengan offset 0, setelah itu kita melompat ke awal untuk eksekusi. Dan itu saja - kernel sistem operasi dimuat dan pemuat sistem telah menyelesaikan tugasnya!

Anda mungkin telah memperhatikan bahwa kode kami menggunakan MYKERNELBIN sebagai ganti MYKERNEL.BIN sebagai nama file kernel sistem operasi, yang cocok dengan skema penamaan 8+3 yang digunakan pada floppy disk di DOS. Faktanya, sistem file FAT12 menggunakan representasi internal nama file, dan kami menghemat ruang dengan menggunakan nama file yang dijamin tidak memerlukan subrutin load_file kami untuk menerapkan mekanisme untuk mencari karakter titik dan mengubah nama file menjadi representasi internal berkas sistem.

Setelah baris dengan arahan untuk menghubungkan file kode sumber disk.asm, ada dua baris yang dirancang untuk mengisi kode biner pemuat sistem dengan nol hingga 512 byte dan menyertakan tanda akhir kode binernya (ini telah dibahas di artikel terakhir). Terakhir, di akhir kode terdapat label "buffer", yang digunakan oleh subrutin load_file. Secara umum, subrutin load_file membutuhkan ruang kosong di RAM untuk melakukan beberapa tindakan perantara dalam proses menemukan file di disk, dan kami memiliki ruang kosong yang cukup setelah memuat boot loader, jadi kami menempatkan buffer di sini.

Untuk merakit bootloader, gunakan perintah berikut:

nasm -f bin -o boot.bin boot.asm

Sekarang kita perlu membuat image floppy disk virtual MS-DOS dan menambahkan biner bootloader kita ke 512 byte pertamanya menggunakan perintah berikut:

Mkdosfs -C floppy.img 1440 dd conv=notrunc if=boot.bin of=floppy.img

Ini menyelesaikan proses pengembangan bootloader! Kami sekarang memiliki image floppy disk yang dapat di-boot yang memungkinkan kami memuat biner kernel sistem operasi dari file bernama mykernel.bin dan menjalankannya. Selanjutnya, kami menunggu bagian pekerjaan yang lebih menarik - pengembangan kernel sistem operasi itu sendiri.

kernel sistem operasi

Kami ingin kernel sistem operasi kami melakukan banyak tugas penting: menampilkan salam, menerima input dari pengguna, menentukan apakah input adalah perintah yang didukung, dan menjalankan program dari disk setelah pengguna menentukan namanya. Ini adalah kode kernel sistem operasi dari file mykernel.asm:

Mov ax, 2000h mov ds, axe mov es, axe loop: mov si, prompt call lib_print_string mov si, user_input call lib_input_string cmp byte , 0 je loop cmp word , "ls" je list_files mov ax, si mov cx, 32768 panggil lib_load_file jc load_fail panggil 32768 jmp loop load_fail: mov si, load_fail_msg panggil lib_print_string jmp loop list_files: mov si, file_list panggil lib_get_file_list panggil lib_print_string jmp loop Prompt db 13, 10, "MyOS > ", 0 load_fail_msg, "Tidak ditemukan db 13! ", 0 user_input kali 256 db 0 file_list kali 1024 db 0 %include "lib.asm"

Sebelum melihat kode, perhatikan baris terakhir dengan arahan untuk menyertakan file kode sumber lib.asm, yang juga terletak di arsip asmschool.zip dari situs web kami. Ini adalah perpustakaan subrutin yang berguna untuk bekerja dengan layar, keyboard, baris, dan disk yang juga dapat Anda gunakan - dalam hal ini kami menyertakan file kode sumber ini di bagian paling akhir dari file kode sumber utama kernel sistem operasi secara berurutan untuk membuat yang terakhir ini sekompak dan seindah mungkin. Lihat bagian "Lib.asm Library Routines" untuk informasi lebih lanjut tentang semua rutinitas yang tersedia.

Dalam tiga baris pertama kode kernel sistem operasi, kami mengisi register segmen dengan data untuk menunjuk ke segmen 2000 di mana kode biner dimuat. Ini penting untuk memastikan bahwa instruksi seperti lodsb , yang harus membaca data dari segmen saat ini dan bukan dari segmen lainnya, bekerja dengan benar. Setelah itu, kami tidak akan melakukan operasi tambahan pada segmen tersebut; sistem operasi kami akan berjalan dengan 64 KB RAM!

Selanjutnya dalam kode ada label yang sesuai dengan awal siklus. Pertama-tama, kita menggunakan salah satu rutin dari library lib.asm, yaitu lib_print_string , untuk mencetak salam. Byte 13 dan 10 sebelum baris ucapan adalah karakter baris baru, karena ucapan itu tidak akan ditampilkan segera setelah output dari program apa pun, tetapi selalu pada baris baru.

Setelah itu, kami menggunakan rutin lain dari perpustakaan lib.asm yang disebut lib_input_string , yang mengambil karakter yang dimasukkan oleh pengguna menggunakan keyboard dan menyimpannya dalam buffer, penunjuk yang ada di register SI. Dalam kasus kami, buffer dideklarasikan menjelang akhir kode kernel sistem operasi sebagai berikut:

Masukan_pengguna kali 256 db 0

Deklarasi ini memungkinkan buffer berisi nol 256 karakter, yang seharusnya cukup lama untuk menampung perintah untuk sistem operasi sederhana seperti milik kita!

Selanjutnya, kami melakukan validasi input pengguna. Jika byte pertama buffer input_pengguna adalah nol, maka pengguna cukup menekan tombol Enter tanpa memasukkan perintah apa pun; jangan lupa bahwa semua string diakhiri dengan karakter null. Jadi dalam hal ini, kita harus melompat ke awal loop dan mencetak salam lagi. Namun, jika pengguna memasukkan perintah apa pun, pertama-tama kita harus memeriksa apakah dia memasukkan perintah ls. Sampai saat ini, Anda hanya melihat perbandingan byte tunggal dalam program bahasa assembly kami, tetapi jangan lupa bahwa juga memungkinkan untuk membandingkan nilai dua byte atau kata mesin. Dalam kode ini, kami membandingkan kata mesin pertama dari buffer input_pengguna dengan kata mesin yang sesuai dengan baris ls, dan jika mereka identik, kami pindah ke blok kode di bawah ini. Dalam blok kode ini, kami menggunakan rutin lain dari perpustakaan lib.asm untuk mendapatkan daftar file yang dipisahkan koma pada disk (yang harus disimpan dalam buffer file_list), mencetak daftar itu ke layar, dan mengulang kembali ke proses masukan pengguna.

Eksekusi program pihak ketiga

Jika pengguna tidak memasukkan perintah ls, kami berasumsi bahwa dia memasukkan nama program dari disk, jadi masuk akal untuk mencoba memuatnya. Pustaka lib.asm kami berisi implementasi subrutin lib_load_file yang berguna, yang mem-parsing tabel sistem file FAT12 disk: dibutuhkan penunjuk ke awal baris dengan nama file menggunakan register AX, serta nilai offset untuk memuat kode biner dari file program menggunakan register CX. Kami sudah menggunakan register SI untuk menyimpan pointer ke string input pengguna, jadi kami menyalin pointer itu ke register AX dan kemudian memasukkan nilai 32768, yang digunakan sebagai offset untuk memuat kode biner dari file program, ke dalam register CX.

Tetapi mengapa kita menggunakan nilai ini sebagai offset untuk memuat kode biner dari file program? Yah, itu hanya salah satu opsi peta memori untuk sistem operasi kami. Karena kami bekerja di segmen 64KB tunggal dan biner kernel kami dimuat pada offset 0, kami harus menggunakan memori 32KB pertama untuk data kernel dan 32KB sisanya untuk data program yang dapat dimuat. Dengan demikian, offset 32768 adalah bagian tengah dari segmen kami dan memungkinkan kami menyediakan jumlah RAM yang cukup untuk kernel sistem operasi dan program yang dimuat.

Setelah itu, rutin lib_load_file melakukan operasi yang sangat penting: jika tidak dapat menemukan file dengan nama yang diberikan pada disk, atau karena alasan tertentu tidak dapat membacanya dari disk, ia hanya keluar dan menetapkan flag carry khusus. Ini adalah flag status CPU yang disetel selama beberapa operasi matematika dan seharusnya tidak menarik bagi kami saat ini, tetapi kami dapat menentukan keberadaan flag ini untuk membuat keputusan cepat. Jika subrutin lib_load_asm menyetel flag carry, kita menggunakan instruksi jc (jump if carry) untuk melompat ke blok kode yang mencetak pesan kesalahan dan kembali ke awal loop input pengguna.

Dalam kasus yang sama, jika bendera transfer tidak disetel, kita dapat menyimpulkan bahwa subrutin lib_load_asm berhasil memuat kode biner dari file program ke RAM di alamat 32768. Yang kita butuhkan dalam kasus ini adalah memulai eksekusi kode biner dimuat di alamat ini , yaitu, mulai menjalankan program yang ditentukan oleh pengguna! Dan setelah instruksi ret digunakan dalam program ini (untuk kembali ke kode panggilan), kita hanya perlu kembali ke loop input pengguna. Jadi kami telah membuat sistem operasi: ini terdiri dari mekanisme paling sederhana untuk mengurai perintah dan memuat program, diimplementasikan dalam sekitar 40 baris kode perakitan, meskipun dengan banyak bantuan dari subrutin dari perpustakaan lib.asm.

Untuk merakit kode kernel sistem operasi, gunakan perintah berikut:

Nasm -f bin -o mykernel.bin mykernel.asm

Setelah itu, kita harus menambahkan file mykernel.bin ke file image floppy disk. Jika Anda terbiasa dengan trik memasang image disk dengan perangkat loopback, Anda dapat mengakses konten image disket floppy.img menggunakannya, tetapi ada cara yang lebih mudah dengan menggunakan GNU Mtools (www.gnu.org/software /mtools ). Ini adalah satu set program floppy disk yang menggunakan sistem file MS-DOS/FAT12, tersedia dari repositori paket perangkat lunak dari semua distribusi Linux populer, jadi Anda hanya perlu menggunakan apt-get , yum , pacman atau utilitas lain yang digunakan untuk menginstal paket perangkat lunak pada distribusi Anda.

Setelah menginstal paket perangkat lunak yang sesuai, untuk menambahkan file mykernel.bin ke file image disket floppy.img, Anda harus menjalankan perintah berikut:

Mcopy -i floppy.img mykernel.bin::/

Perhatikan karakter lucu di akhir perintah: titik dua, titik dua, dan garis miring. Sekarang kita hampir siap untuk meluncurkan sistem operasi kita, tapi apa gunanya sampai ada aplikasi untuk itu? Mari kita perbaiki kesalahpahaman ini dengan mengembangkan aplikasi yang sangat sederhana. Ya, sekarang Anda akan mengembangkan aplikasi untuk sistem operasi Anda sendiri - bayangkan seberapa besar otoritas Anda akan naik di jajaran geeks. Simpan kode berikut dalam file bernama test.asm:

Org 32768 mov ah, 0Eh mov al, "X" int 10h ret

Kode ini hanya menggunakan fungsi BIOS untuk menampilkan karakter "X" di layar, setelah itu mengembalikan kontrol ke kode yang memanggilnya - dalam kasus kami, kode ini adalah kode sistem operasi. Baris org yang memulai kode sumber aplikasi bukanlah instruksi CPU, tetapi arahan assembler NASM yang memberi tahu bahwa kode biner akan dimuat ke RAM pada offset 32768, oleh karena itu, perlu untuk menghitung ulang semua offset dengan mempertimbangkan keadaan ini .

Kode ini juga perlu dirakit, dan file biner yang dihasilkan perlu ditambahkan ke file gambar floppy disk:

Nasm -f bin -o test.bin test.asm mcopy -i floppy.img test.bin::/

Sekarang, tarik napas dalam-dalam, bersiaplah untuk menyaksikan hasil tak tertandingi dari pekerjaan Anda sendiri, dan boot image floppy disk menggunakan emulator PC seperti Qemu atau VirtualBox. Misalnya, perintah berikut dapat digunakan untuk tujuan ini:

Qemu-system-i386 -fda floppy.img

Voila: bootloader boot.img yang kita integrasikan ke dalam sektor pertama citra disk memuat kernel sistem operasi mykernel.bin, yang menampilkan salam. Ketik perintah ls untuk mendapatkan nama kedua file di disk (mykernel.bin dan test.bin), lalu ketik nama file terakhir yang akan dieksekusi dan menampilkan karakter X di layar.

Ini keren, bukan? Sekarang Anda dapat mulai menyesuaikan shell sistem operasi Anda, menambahkan implementasi perintah baru, dan menambahkan file program tambahan ke disk. Jika Anda ingin menjalankan sistem operasi ini pada PC asli, Anda harus merujuk ke bagian "Menjalankan bootloader pada platform perangkat keras nyata" dari artikel sebelumnya dalam seri ini - Anda akan memerlukan perintah yang persis sama. Bulan depan kami akan membuat sistem operasi kami lebih kuat dengan mengizinkan program yang dapat diunduh untuk menggunakan fungsi sistem, sehingga menerapkan konsep pemisahan kode untuk mengurangi duplikasi kode. Banyak pekerjaan masih di depan.

rutinitas perpustakaan lib.asm

Seperti disebutkan sebelumnya, perpustakaan lib.asm menyediakan satu set besar subrutin yang berguna untuk digunakan dalam kernel sistem operasi Anda dan program individual. Beberapa dari mereka menggunakan instruksi dan konsep yang belum tercakup dalam artikel dalam seri ini, yang lain (seperti rutinitas untuk bekerja dengan disk) terkait erat dengan struktur sistem file, tetapi jika Anda menganggap diri Anda kompeten dalam hal ini, Anda dapat membiasakan diri dengan implementasinya dan memahami prinsip kerja. Namun, lebih penting untuk memahami cara memanggilnya dari kode Anda sendiri:

  • lib_print_string - Membawa pointer ke string yang diakhiri null melalui register SI dan mencetak string itu ke layar.
  • lib_input_string - mengambil pointer ke buffer melalui register SI dan mengisi buffer ini dengan karakter yang dimasukkan oleh pengguna menggunakan keyboard. Setelah pengguna menekan tombol Enter, string dalam buffer diakhiri dengan null dan kontrol kembali ke kode program pemanggil.
  • lib_move_cursor - Memindahkan kursor pada layar ke posisi dengan koordinat yang melewati register DH (nomor baris) dan DL (nomor kolom).
  • lib_get_cursor_pos - panggil subrutin ini untuk mendapatkan nomor baris dan kolom saat ini masing-masing menggunakan register DH dan DL.
  • lib_string_uppercase - Membawa pointer ke awal string yang diakhiri null menggunakan register AX dan mengubah karakter dalam string menjadi huruf besar.
  • lib_string_length - Membawa pointer ke awal string yang diakhiri null menggunakan register AX dan mengembalikan panjangnya menggunakan register AX.
  • lib_string_compare - Membawa pointer ke awal dua string yang diakhiri null melalui register SI dan DI dan membandingkan string tersebut. Menyetel flag wrap jika stringnya identik (untuk menggunakan instruksi cabang tergantung pada flag jc carry), atau menghapus flag ini jika stringnya berbeda (untuk menggunakan instruksi jnc).
  • lib_get_file_list - Mengambil pointer ke awal buffer melalui register SI dan menempatkan string diakhiri-nol yang berisi daftar nama file yang dipisahkan koma dari disk ke buffer itu.
  • lib_load_file - Membawa pointer ke awal string yang berisi nama file menggunakan register AX dan memuat konten file pada offset yang diberikan oleh register CX. Mengembalikan jumlah byte yang disalin ke dalam memori (yaitu, ukuran file) menggunakan register BX, atau menyetel flag carry jika tidak ada file dengan nama tertentu yang ditemukan.