OS mainan, 32bit akhirnya mengimplementasikan shell interaktif sederhana 
Daftar yang harus dilakukan:
Ada dua hard disk secara total, sistem itu sendiri dipasang pada disk utama, dan mode boot MBR diadopsi, dan proses mbr-> boot loader-> kernnel digunakan.
MBR terletak di 1 sektor dimulai LBA 0号扇区
Boot Loader terletak di 4 sektor yang dimulai dengan LBA 2号扇区dari disk
Kernel terletak di dalam 200 sektor yang dimulai dengan LBA 9号扇区
Sistem file diimplementasikan pada disk budak. Ini mungkin tidak terlalu masuk akal. Jika sistem file didasarkan pada logika sistem komersial, itu harus diimplementasikan sekarang, dan kemudian sistem operasi dipasang di partisi yang sesuai.
Paging memori, satu halaman adalah 4kb
Manajemen memori mengadopsi manajemen bitmap, dan dibedakan berdasarkan ukuran saat mengalokasikan memori. Jika lebih besar dari 1024 byte, itu dialokasikan langsung berdasarkan halaman.
Jika kurang dari 1024 byte, berdasarkan alokasi arena demi halaman, gunakan blockchain idle di arena untuk alokasi dan kontrol.
Untuk kenyamanan, meskipun mekanisme paging diaktifkan, fungsi switching dari halaman dan disk memori tidak diimplementasikan.

PCB adalah ukuran 1 halaman
Esensi inti dari penjadwalan utas adalah beralih PCB dengan mengendalikan switching pointer ESP dengan interupsi jam. Prioritas tercermin dalam panjang irisan waktu berjalan masing -masing utas.
Implementasi proses ini didasarkan pada utas, dan pemilihan TSS didasarkan pada Linux, menggunakan TSS tunggal ke stack level 0 cadangan dan pointer stack level 0. Perbedaan terbesar dari utas adalah bahwa proses tersebut memiliki alamat tabel halaman di PCB, yang merupakan perbedaan terbesar antara proses dan utas. Proses ini benar -benar memiliki ruang memori virtual independennya sendiri.
Tidak ada algoritma yang efisien dalam penjadwalan, cukup gunakan penjadwalan antrian
Implementasi utas idle
Implementasi utas idle sangat sederhana. Ketika pertama kali Anda mendapatkan jadwal, Anda memblokirnya dan memberikannya dari CPU. Ketika penjadwal menjalankan pengiriman lagi, jika tidak ada utas atau proses siap ditemukan dalam antrian siap, utas idle akan dibangunkan. Pada saat ini, benang idle menangguhkan CPU melalui hlt . Ketika slice waktu digunakan dan CPU belum menemukan proses atau benang yang siap, terus ganti benang idle dengan CPU. Pada saat ini, idle akan terus memblokir dirinya sendiri dan kemudian mulai mengulangi proses penjadwalan di atas.
// 空载任务
static void idle ( void * arg ) {
while ( 1 ) {
thread_block ( TASK_BLOCKED );
asm volatile ( "sti; hlt" : : : "memory" );
}
}Proses garpu
Fork Proses pertama -tama menyalin PCB dari proses saat ini, dan kemudian membuat tabel halaman baru melalui bitmap kumpulan virtual dari proses saat ini. Korespondensi alamat virtual persis sama seperti dalam proses asli. Akhirnya, situs interupsi dipalsukan dan proses anak ditambahkan ke antrian penjadwalan dan menunggu penjadwalan dieksekusi. Di situs interupsi yang ditempa, EAX dalam PCB dari proses anak dimodifikasi menjadi 0, yang berarti bahwa nilai pengembalian garpu adalah 0 dalam proses baru, sedangkan EAX dalam PCB dari proses induk tetap tidak berubah, mewakili PID dari proses anak. Proses induk kembali melalui akhir panggilan sistem, sementara proses anak kembali langsung melalui fungsi keluar interupsi.
Proses eksekutif
Implementasi EXEC pertama memuat file ELF dari disk ke memori, kemudian mengubah nama proses di PCB dari proses saat ini, dan menempatkan parameter yang diperlukan oleh proses untuk dieksekusi ke dalam register yang disepakati, dan memodifikasi EIP ke titik masuk ELF, pemalsuan situs interrupt, dan mengeksekusi proses baru dengan langsung dengan langsung memanggil fungsi EXIT EXIT interrupt.
Di antara mereka, titik masuk ELF diimplementasikan dengan mengimplementasikan CRT yang sangat sederhana itu sendiri, yang memberikan entri _start dan mendorong register parameter yang disepakati ke dalam tumpukan 3-level, dan memanggil fungsi utama dari perintah eksternal untuk mewujudkan passing parameter.
[bits 32]
extern main
extern exit
; 这是一个简易版的CRT
; 如果链接时候ld不指定-e main的话,那ld默认会使用_start来充当入口
; 这里的_start的简陋实现,充当了exec调用的进程从伪造的中断中返回时的入口地址
; 通过这个_start, 压入了在execv中存放用户进程参数的两个寄存器。然后call 用户进程main来实现了向用户进程传递参数
section .text
global _start
_start:
;下面这两个要和 execv 中 load 之后指定的寄存器一致
push ebx ;压入 argv
push ecx ;压入 argc
call main
; 压入main的返回值
push eax
call exit ; 不再返回,直接调度别的进程了,这个进程直接被回收了Proses Tunggu
Setelah garpu dan melaksanakan perintah lokal, agar tidak muncul, proses induk perlu diakhiri dalam proses tunggu anak lokal.
Implementasinya di sini adalah untuk memasukkan panggilan sistem SYS_WAIT, melintasi seluruh antrian proses, menemukan proses yang proses induknya adalah status yang ditangguhkan sendiri, kemudian dapatkan nilai pengembalian di PCB -nya, mendaur ulang tabel direktori PCB dan halaman, dan menghapusnya dari antrian penjadwalan. Jika tidak ada proses anak yang tertunda ditemukan setelah traversal, blokir dirinya dan tunggu proses anak untuk bangun.
Proses keluar
Selama eksekusi, perintah eksternal sebenarnya dibungkus oleh CRT sederhana yang dibuat sendiri. Utama dari perintah eksternal panggilan crt sederhana akan mendapatkan nilai pengembalian di akhir, lewati untuk keluar, dan kemudian panggilan keluar
Implementasi di sini terutama melakukan tiga hal:
Seluruh proses memuat perintah eksternal dan melaksanakannya
Pertama, perintah eksternal perlu memberikan fungsi int main(int argc, char **argv) . Saat menautkan, Anda perlu membawa CRT start.o sederhana buatan sendiri, dan akhirnya tulis perintah eksternal yang dikompilasi ke sistem file.
Ketika perintah eksternal akan dieksekusi, proses saat ini membayar suatu proses, EXECV dalam proses baru, proses saat ini mengeksekusi tunggu, melewati alamat untuk menerima nilai pengembalian proses anak, dan kemudian memblokir dan menunggu proses baru untuk kembali. The new process loads external commands from the file system to memory in exevc, and changes the relevant content in pcb to the information of external commands, and modifies the eip in the pcb interrupt stack to the CRT's _start entry (at this time the new process has completely replaced itself with the external command process to be executed), and finally uses the interrupt exit function intr_exit to fake the interrupt exit and enter the CRT and then enter the main of perintah eksternal. Ketika eksekusi utama perintah eksternal berakhir dan kembali, panggilan CRT keluar melalui nilai pengembalian utama, masukkan nilai pengembalian utama di sys_exit ke posisi yang sesuai dari proses PCB, mendaur ulang semua sumber daya kecuali tabel direktori PCB dan halaman, dan kemudian bangun proses induk dan memblokir proses anak. Setelah proses induk dibangunkan, sistem panggilan sys_wait mendapatkan nilai pengembalian dari PCB PCB PCB PCB PCB PCB PCB PCB PCB PCB PCB dan membersihkan tabel Direktori PCB dari PCB dari PCB dari proses anak, menghapus proses PCB. Pada titik ini, proses anak telah dieksekusi dan sepenuhnya didaur ulang.
Implementasi sistem file meniru inode sistem seperti unix
Partisi membatasi jumlah inode 4096. CPU mengoperasikan hard disk sesuai dengan ukuran blok (cluster), dan satu blok diatur ke sektor, dengan 512 byte.
Inode mendukung 12 blok langsung dan 1 tabel tidak langsung tingkat pertama. Satu blok adalah 512 byte di sektor, jadi satu file mendukung hingga 140 * 512 byte.
Struktur Inode

Tata letak sistem file

Korespondensi antara deskriptor file dan inode

Implementasi pipa tergantung pada struktur file dalam sistem file. Esensinya adalah mengganti inode yang semula struktur file tersebut sesuai dengan ruang buffer cincin di ruang kernel.
// 因为管道也是当作文件来对待,因此file结构体在针对真实文件和管道是有不同的意义
struct file {
// 文件操作的偏移指针, 当是管道是表示管道打开的次数
uint32_t fd_pos ;
// 文件的操作标志,当是管道是一个固定值0xFFFF
uint32_t fd_flag ;
// 对应的inode指针,当是管道时指向管道的环形缓冲区
struct inode * fd_inode ;
}; Karena ruang kernel dibagikan, komunikasi antara berbagai proses dapat dicapai melalui pipa baca dan tulis. Bacaan dan penulisan pipa dienkapsulasi dalam sys_write dan sys_read , jadi tidak ada perbedaan antara mengoperasikan pipa dan mengoperasikan file biasa.
Inti dari pengalihan adalah mengubah alamat tabel deskriptor global yang sesuai di tabel deskriptor file PCB, dan kemudian pengoperasian membaca dan menulis deskriptor file yang sesuai diarahkan ke file baru.
Implementasi Karakter Pipa | Dalam shell dicapai dengan mengarahkan ulang input standar dan output standar ke pipa.
int32_t sys_read ( int32_t fd , void * buf , uint32_t count ) {
if ( fd == stdin_no ) {
if ( is_pipe ( fd )) {
// 从已经重定向好管道中读
ret = pipe_read ( fd , buf , count );
} else {
// 从键盘获取输入
}
} else if ( is_pipe ( fd )) {
// 读管道
ret = pipe_read ( fd , buf , count );
} else {
// 读取普通文件
}
return ret ;
}
int32_t sys_write ( int32_t fd , const void * buf , uint32_t count ) {
if ( fd == stdout_no ) {
if ( is_pipe ( fd )) {
// 向已经重定向好管道中写入
return pipe_write ( fd , buf , count );
} else {
// 向控制台输出内容
}
} else if ( is_pipe ( fd )) {
// 写管道
return pipe_write ( fd , buf , count );
} else {
// 向普通文件写入
}
}