Toy OS, 32 บิตในที่สุดก็ใช้เปลือกแบบโต้ตอบแบบง่าย ๆ 
รายการสิ่งที่ต้องทำ:
มีฮาร์ดดิสก์ทั้งหมดสองตัวระบบจะถูกติดตั้งบนดิสก์หลักและใช้โหมดบูตของ MBR และใช้กระบวนการ MBR-> boot loader-> kernnel
MBR ตั้งอยู่ใน 1 ภาคเริ่มต้น LBA 0号扇区
Boot Loader ตั้งอยู่ใน 4 ภาคส่วนเริ่มต้นด้วย LBA 2号扇区ของดิสก์
Kernel ตั้งอยู่ภายใน 200 ภาคเริ่มต้นด้วย Disk LBA 9号扇区
ระบบไฟล์ถูกนำไปใช้บนดิสก์ทาส นี่อาจไม่สมเหตุสมผลมาก หากระบบไฟล์ขึ้นอยู่กับตรรกะของระบบเชิงพาณิชย์ควรใช้งานตอนนี้และจากนั้นระบบปฏิบัติการจะถูกติดตั้งในพาร์ติชันที่เกี่ยวข้อง
เพจหน่วยความจำหนึ่งหน้าคือ 4KB
การจัดการหน่วยความจำใช้การจัดการบิตแมปและมีขนาดแตกต่างกันเมื่อจัดสรรหน่วยความจำ หากมากกว่า 1024 ไบต์จะถูกจัดสรรโดยตรงตามหน้า
หากมีน้อยกว่า 1,024 ไบต์บนพื้นฐานของการจัดสรรเวทีโดยหน้าให้ใช้ blockchain ที่ไม่ได้ใช้งานในเวทีสำหรับการจัดสรรและการควบคุม
เพื่อความสะดวกแม้ว่าจะเปิดใช้งานกลไกการเพจ แต่ก็ไม่ได้ใช้ฟังก์ชั่นการสลับหน้าหน่วยความจำและดิสก์

PCB คือขนาด 1 หน้า
สาระสำคัญหลักของการตั้งเวลาเธรดคือการสลับ PCB โดยการควบคุมการสลับตัวชี้ ESP โดยการขัดจังหวะนาฬิกา ลำดับความสำคัญจะสะท้อนให้เห็นในความยาวของชิ้นเวลาทำงานของแต่ละเธรด
การใช้งานของกระบวนการขึ้นอยู่กับเธรดและการเลือก TSS ขึ้นอยู่กับ Linux โดยใช้ TSS เดี่ยวไปยังระดับสำรอง 0 สแต็คและพอยน์เตอร์ระดับ 0 สแต็ก ความแตกต่างที่ใหญ่ที่สุดจากเธรดคือกระบวนการมีที่อยู่ตารางหน้าใน PCB ซึ่งเป็นความแตกต่างที่ใหญ่ที่สุดระหว่างกระบวนการและเธรด กระบวนการนี้มีพื้นที่หน่วยความจำเสมือนจริงของตัวเองอย่างแท้จริง
ไม่มีอัลกอริทึมที่มีประสิทธิภาพในการกำหนดเวลาเพียงแค่ใช้การตั้งเวลาแบบวนรอบคิว
การใช้เธรดที่ไม่ได้ใช้งาน
การใช้งานเธรดที่ไม่ได้ใช้งานนั้นง่ายมาก เมื่อครั้งแรกที่คุณได้รับกำหนดการคุณบล็อกและให้ออกจาก CPU เมื่อตัวกำหนดตารางเวลาดำเนินการจัดส่งอีกครั้งหากไม่พบเธรดหรือกระบวนการพร้อมในคิวพร้อมเธรดที่ไม่ได้ใช้งานจะถูกปลุก ในเวลานี้เธรดที่ไม่ได้ใช้งานจะระงับ CPU ผ่าน hlt เมื่อชิ้นเวลาถูกใช้งานและ CPU ไม่พบกระบวนการหรือเธรดที่พร้อมใช้งานให้เปลี่ยนเธรดที่ไม่ได้ใช้งานด้วย CPU ในเวลานี้การไม่ได้ใช้งานจะยังคงบล็อกตัวเองแล้วเริ่มทำซ้ำกระบวนการกำหนดเวลาข้างต้น
// 空载任务
static void idle ( void * arg ) {
while ( 1 ) {
thread_block ( TASK_BLOCKED );
asm volatile ( "sti; hlt" : : : "memory" );
}
}ส้อมกระบวนการ
ส้อมของกระบวนการคัดลอก PCB ของกระบวนการปัจจุบันก่อนจากนั้นสร้างตารางหน้าใหม่ผ่านบิตแมปพูลเสมือนจริงของกระบวนการปัจจุบัน การติดต่อของที่อยู่เสมือนนั้นเหมือนกับในกระบวนการดั้งเดิม ในที่สุดไซต์ขัดจังหวะจะถูกปลอมแปลงและกระบวนการเด็กจะถูกเพิ่มเข้าไปในคิวการกำหนดเวลาและรอการกำหนดเวลาที่จะดำเนินการ ในไซต์ขัดจังหวะการปลอมแปลง EAX ใน PCB ของกระบวนการเด็กได้รับการแก้ไขเป็น 0 ซึ่งหมายความว่าค่าคืนสินค้าของส้อมคือ 0 ในกระบวนการใหม่ในขณะที่ EAX ใน PCB ของกระบวนการแม่ยังคงไม่เปลี่ยนแปลงซึ่งแสดงถึง PID ของกระบวนการเด็ก กระบวนการหลักจะส่งคืนผ่านการสิ้นสุดของการเรียกระบบในขณะที่กระบวนการเด็กจะกลับมาโดยตรงผ่านฟังก์ชั่นการออกจากอินเตอร์รัปต์
ประมวลผล
การใช้งาน EXEC First โหลดไฟล์ ELF จากดิสก์ไปยังหน่วยความจำจากนั้นเปลี่ยนชื่อกระบวนการใน PCB ของกระบวนการปัจจุบันและวางพารามิเตอร์ที่กระบวนการที่ต้องดำเนินการในการลงทะเบียนที่ตกลงกันไว้และปรับเปลี่ยน EIP ไปยังจุดเริ่มต้นของ ELF
ในหมู่พวกเขาจุดเริ่มต้นของเอลฟ์ถูกนำไปใช้โดยการใช้ CRT ที่ง่ายมากเองซึ่งให้รายการ _Start และผลักดันการลงทะเบียนพารามิเตอร์ที่ตกลงกันไว้ในสแต็ก 3 ระดับและเรียกฟังก์ชั่นหลักของคำสั่งภายนอกเพื่อตระหนักถึงพารามิเตอร์ที่ผ่าน
[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 ; 不再返回,直接调度别的进程了,这个进程直接被回收了กระบวนการรอ
หลังจากส้อมและดำเนินการคำสั่งท้องถิ่นเพื่อไม่ให้ปรากฏขึ้นกระบวนการหลักจะต้องสิ้นสุดในกระบวนการรอเด็กในท้องถิ่น
การใช้งานที่นี่คือการเข้าสู่การเรียกระบบ SYS_WAIT สำรวจคิวกระบวนการทั้งหมดค้นหากระบวนการที่กระบวนการแม่เป็นสถานะที่ถูกระงับของตัวเองจากนั้นรับค่าคืนใน PCB รีไซเคิลตารางไดเรกทอรี PCB และหน้าและลบออกจากคิวการกำหนดเวลา หากไม่พบกระบวนการเด็กที่รอดำเนินการหลังจากผ่านการสำรวจให้ปิดกั้นตัวเองและรอให้กระบวนการเด็กตื่นขึ้นมา
การออกจากกระบวนการ
ในระหว่างการดำเนินการคำสั่งภายนอกจะถูกห่อหุ้มด้วย CRT ง่าย ๆ ที่สร้างขึ้นด้วยตัวเอง หลักของคำสั่ง CRT Call External Simple จะได้รับค่าส่งคืนในตอนท้ายส่งผ่านไปยังทางออกแล้วโทรออก
การใช้งานที่นี่ส่วนใหญ่ทำสามสิ่ง:
กระบวนการทั้งหมดของการโหลดคำสั่งภายนอกและดำเนินการ
ขั้นแรกคำสั่งภายนอกจะต้องจัดเตรียมฟังก์ชัน int main(int argc, char **argv) เมื่อเชื่อมโยงคุณจะต้องนำ CRT start.o แบบโฮมเมดมาใช้และในที่สุดก็เขียนคำสั่งภายนอกที่รวบรวมไว้ในระบบไฟล์
เมื่อต้องดำเนินการคำสั่งภายนอกกระบวนการปัจจุบันจะเรียกกระบวนการ EXECV ในกระบวนการใหม่กระบวนการปัจจุบันจะดำเนินการรอผ่านที่อยู่เพื่อรับค่าส่งคืนของกระบวนการลูกแล้วบล็อกและรอกระบวนการใหม่เพื่อส่งคืน กระบวนการใหม่โหลดคำสั่งภายนอกจากระบบไฟล์ไปยังหน่วยความจำใน EXEVC และเปลี่ยนเนื้อหาที่เกี่ยวข้องใน PCB เป็นข้อมูลของคำสั่งภายนอกและปรับเปลี่ยน EIP ในสแต็กขัดจังหวะ intr_exit ไปยังรายการ _start ของ CRT (ในเวลานี้ คำสั่งภายนอก เมื่อคำสั่งภายนอกการดำเนินการหลักสิ้นสุดลงและส่งคืนการโทร CRT ออกจากค่าส่งคืนหลักให้ใส่ค่าผลตอบแทนหลักใน sys_exit ลงในตำแหน่งที่สอดคล้องกันของกระบวนการ PCB รีไซเคิลทรัพยากรทั้งหมดยกเว้นตารางไดเรกทอรี PCB และหน้า หลังจากกระบวนการพาเรนต์ถูกปลุกระบบเรียก sys_wait ได้รับค่าตอบแทนจาก PCB ของ PCB ของ PCB ของ PCB ของ PCB ของ PCB ของ PCB ของ PCB ของ PCB ของ PCB ของ PCB ของ PCB ณ จุดนี้กระบวนการเด็กได้ถูกดำเนินการและรีไซเคิลอย่างสมบูรณ์
การใช้งานระบบไฟล์เลียนแบบ inode ของระบบ unix-like
พาร์ติชั่น จำกัด จำนวน inodes 4096 CPU ทำงานฮาร์ดดิสก์ตามขนาดของบล็อก (คลัสเตอร์) และหนึ่งบล็อกถูกตั้งค่าเป็นภาคส่วน 512 ไบต์
Inode รองรับ 12 บล็อกโดยตรงและ 1 ตารางทางอ้อมระดับแรก หนึ่งบล็อกคือ 512 ไบต์ในภาคดังนั้นไฟล์เดียวรองรับได้ถึง 140 * 512 ไบต์
โครงสร้าง inode

เค้าโครงระบบไฟล์

การติดต่อระหว่างตัวอธิบายไฟล์และ inode

การใช้งานไปป์ไลน์ขึ้นอยู่กับโครงสร้างไฟล์ในระบบไฟล์ สาระสำคัญของมันคือการแทนที่ inode ที่โครงสร้างไฟล์ควรสอดคล้องกับพื้นที่บัฟเฟอร์วงแหวนในพื้นที่เคอร์เนล
// 因为管道也是当作文件来对待,因此file结构体在针对真实文件和管道是有不同的意义
struct file {
// 文件操作的偏移指针, 当是管道是表示管道打开的次数
uint32_t fd_pos ;
// 文件的操作标志,当是管道是一个固定值0xFFFF
uint32_t fd_flag ;
// 对应的inode指针,当是管道时指向管道的环形缓冲区
struct inode * fd_inode ;
}; เนื่องจากพื้นที่เคอร์เนลใช้ร่วมกันการสื่อสารระหว่างกระบวนการที่แตกต่างกันสามารถทำได้ผ่านการอ่านและเขียนท่อ การอ่านและเขียนของไปป์ไลน์ถูกห่อหุ้มใน sys_write และ sys_read ดังนั้นจึงไม่มีความแตกต่างระหว่างการใช้งานไปป์ไลน์และไฟล์ธรรมดา
สาระสำคัญของการเปลี่ยนเส้นทางคือการเปลี่ยนที่อยู่ของตาราง descriptor ทั่วโลกที่เกี่ยวข้องในตารางตัวอธิบายไฟล์ PCB จากนั้นการดำเนินการอ่านและเขียนตัวอธิบายไฟล์ที่เกี่ยวข้องจะถูกชี้ไปที่ไฟล์ใหม่
การใช้งานอักขระไปป์ไลน์ | ในเชลล์ทำได้โดยการเปลี่ยนเส้นทางอินพุตมาตรฐานและเอาต์พุตมาตรฐานไปยังไปป์ไลน์
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 {
// 向普通文件写入
}
}