Mengembangkan OS seperti Unix monolitik - Perpustakaan C (2)

Dalam artikel sebelumnya, kami belajar cara menjalankan kernel Hello World dan menulis beberapa fungsi untuk bekerja dengan string. Sekarang saatnya untuk memperluas pustaka C sehingga Anda dapat mengimplementasikan kprintf dan fungsi-fungsi lain yang diperlukan. Ayo pergi!

Daftar isi


  1. Membangun sistem (make, gcc, gas). Boot awal (multiboot). Luncurkan (qemu). Pustaka C (strcpy, memcpy, strext).
  2. Pustaka C (sprintf, strcpy, strcmp, strtok, va_list ...). Membangun perpustakaan dalam mode kernel dan mode aplikasi pengguna.
  3. Log sistem kernel. Memori video Output ke terminal (kprintf, kpanic, kassert).
  4. Memori dinamis, tumpukan (kmalloc, kfree).
  5. Organisasi memori dan penanganan interupsi (GDT, IDT, PIC, syscall). Pengecualian
  6. Memori virtual (direktori halaman dan tabel halaman).
  7. Proses Perencana Multitasking. Panggilan sistem (bunuh, keluar, ps).
  8. Sistem file kernel (initrd), elf, dan internalnya. Panggilan sistem (exec).
  9. Driver perangkat karakter. Panggilan sistem (ioctl, fopen, fread, fwrite). Pustaka C (fopen, fclose, fprintf, fscanf).
  10. Shell sebagai program lengkap untuk kernel.
  11. Mode perlindungan pengguna (ring3). Segmen Status Tugas (tss).

Perpustakaan C


Pertama, Anda perlu menerapkan tipe dengan dimensi eksplisit.

Karena kami akan mengumpulkan di bawah satu platform, sampai definisi dan implementasi kami benar. Ini tidak universal, tetapi itu sebabnya itu mudah dibaca dan sederhana. Saya berpegang pada pendekatan bahwa kadang-kadang lebih baik melakukan sesuatu yang tidak universal, tetapi memenuhi persyaratan saat ini, karena sangat sulit untuk mempertahankan solusi universal.

typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; typedef unsigned char u_char; typedef unsigned short u_short; typedef unsigned int u_int; typedef unsigned int u_long; 

Tidak ada salahnya untuk memperkenalkan tipe Boolean.

 #pragma once /* types */ typedef int bool; #define true 1 #define false 0 #define null 0 

Juga, beberapa makro untuk bekerja dengan byte tidak akan merugikan kita.

 typedef unsigned long size_t; #define HIGH_WORD(addr) ((addr & 0xffff0000) >> 16) #define LOW_WORD(addr) ((addr & 0xffff)) #define LOW_BYTE(addr) ((addr & 0x00ff)) #define HIGH_BYTE(addr) ((addr & 0xff00) >> 8) 

Makro berikut diperlukan untuk bekerja dengan sejumlah variabel argumen. Pendekatan ini hanya berfungsi jika fungsi mengikuti konvensi pemanggilan bahasa C, di mana argumen fungsi dilewatkan melalui tumpukan mulai dari yang terakhir.

 typedef size_t* va_list; #define va_start(l, a) (l = (void*)((size_t)&a) + sizeof(a)) #define va_end(l) (l = (void*)0) #define va_arg(l, s) (*(s*)(l++)) 

Tentu saja, orang bisa pergi ke arah lain. Alih-alih mendefinisikan fungsi Anda sendiri, coba gunakan perpustakaan bawaan dan ganti fungsi yang akan mengakses kernel melalui LD_PRELOAD. Tapi saya suka mengontrol proses sepenuhnya, jadi mari kita tinggalkan opsi ini sebagai ide bagi mereka yang mulai menulis OS mereka di tutorial ini.

Selanjutnya, dalam tutorial video, kami akan mempertimbangkan implementasi fungsi pustaka berikut. Implementasinya tidak mengklaim sebagai optimalitas dan kelengkapan, tetapi saya pikir itu mengklaim kesederhanaan dan keterbacaan. Saya hanya mencatat bahwa kita menggunakan implementasi fungsi strtok yang aman, yang disebut strtok_r. Dan kami menemukan fungsi strinv dan strext dalam pelajaran terakhir. Jika Anda terbiasa dengan C, saya pikir Anda akan terbiasa dengan hampir semua fungsi yang tercantum di bawah ini.

 extern int strlen(const char* s); extern char* strcpy(char* s1, const char* s2); extern char* strncpy(char* s1, const char* s2, u_int n); extern void* memcpy(void* buf1, const void* buf2, u_int bytes); extern void* memset(void* buf1, u8 value, u_int bytes); extern int strcmp(const char* s1, const char* s2); extern int strncmp(const char* s1, const char* s2, u_int n); extern char* strcat(char* s1, const char* s2); extern char* strext(char* buf, const char* str, char sym); extern int strspn(char* str, const char* accept); extern int strcspn(char* str, const char* rejected); char* strchr(const char* str, char ch); extern char* strtok_r(char* str, const char* delims, char** save_ptr); extern char* memext(void* buff_dst, u_int n, const void* buff_src, char sym); extern char* itoa(unsigned int value, char* str, unsigned int base); extern unsigned int atou(char* str); extern char* strinv(char* str); extern unsigned int sprintf(char* s1, const char* s2, ...); extern unsigned int snprintf(char* s1, u_int n, const char* s2, ...); extern unsigned int vsprintf(char* s1, const char* s2, va_list list); extern unsigned int vsnprintf(char* s1, unsigned int n, const char* s2, va_list list); 

Rutinitas selesai dengan. Akhir kode boilerplate. Pelajaran selanjutnya akan jauh lebih rumit dan menarik. Jika Anda ingin mensponsori suatu proyek, Anda dapat menawarkan implementasi fungsi perpustakaan yang optimal.

Referensi


Mengembangkan OS Seperti Unix-Monolitik - Memulai
Video tutorial untuk artikel ini
Kode sumber (Anda membutuhkan cabang lesson2)

Referensi


  1. James Molloy. Gulung mainan Anda sendiri UNIX-clone OS.
  2. Zubkov. Assembler untuk DOS, Windows, Unix
  3. Kalashnikov. Assembler mudah!
  4. Tanenbaum. Sistem operasi. Implementasi dan pengembangan.
  5. Robert Love. Kernel Linux Deskripsi proses pengembangan.

Source: https://habr.com/ru/post/id466709/


All Articles