GeekOS操作系統(tǒng)課程設(shè)計(jì)項(xiàng)目介紹課件_第1頁
GeekOS操作系統(tǒng)課程設(shè)計(jì)項(xiàng)目介紹課件_第2頁
GeekOS操作系統(tǒng)課程設(shè)計(jì)項(xiàng)目介紹課件_第3頁
GeekOS操作系統(tǒng)課程設(shè)計(jì)項(xiàng)目介紹課件_第4頁
GeekOS操作系統(tǒng)課程設(shè)計(jì)項(xiàng)目介紹課件_第5頁
已閱讀5頁,還剩97頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

一、項(xiàng)目設(shè)計(jì)目的熟悉GeekOS的項(xiàng)目編譯、調(diào)試和運(yùn)行環(huán)境,掌握GeekOS運(yùn)行工作過程。二、項(xiàng)目設(shè)計(jì)要求1、搭建GeekOS的編譯和調(diào)試平臺(tái),掌握GeekOS的內(nèi)核進(jìn)程工作原理。2、熟悉鍵盤操作函數(shù),編程實(shí)現(xiàn)一個(gè)內(nèi)核進(jìn)程。該進(jìn)程的功能是:接收鍵盤輸入的字符并顯示到屏幕上,當(dāng)輸入ctrl+d時(shí),結(jié)束進(jìn)程的運(yùn)行。第八章設(shè)計(jì)項(xiàng)目0

一、項(xiàng)目設(shè)計(jì)目的第八章設(shè)計(jì)項(xiàng)目01三、項(xiàng)目0的實(shí)現(xiàn)主要由以下步驟完成(在項(xiàng)目0的/src/geekos/main.c中完成):編寫一個(gè)C語言函數(shù),函數(shù)功能是:接收鍵盤輸入的按鍵,并將鍵值在顯示器顯示出來,當(dāng)輸入ctrl+d就退出;在Main函數(shù)體內(nèi)調(diào)用Start_Kernel_Thread函數(shù),將步驟1編寫的函數(shù)地址傳遞給參數(shù)startFunc,利用Setup_Kernel_Thread函數(shù)建立一個(gè)待運(yùn)行的線程。

在Linux環(huán)境下編譯系統(tǒng)得到GeekOS鏡像文件。編寫一個(gè)相應(yīng)的bochs配置文件。在bochs中運(yùn)行GeekOS系統(tǒng)顯示結(jié)果。三、項(xiàng)目0的實(shí)現(xiàn)主要由以下步驟完成(在項(xiàng)目0的/src/ge2第九章設(shè)計(jì)項(xiàng)目1

一、項(xiàng)目設(shè)計(jì)目的熟悉ELF文件格式,了解GeekOS系統(tǒng)如何將ELF格式的可執(zhí)行程序裝入到內(nèi)存,建立內(nèi)核進(jìn)程并運(yùn)行的實(shí)現(xiàn)技術(shù)。二、項(xiàng)目設(shè)計(jì)要求1、修改/geekos/elf.c文件:在函數(shù)Parse_ELF_Executable()中添加代碼,分析ELF格式的可執(zhí)行文件(包括分析得出ELF文件頭、程序頭,獲取可執(zhí)行文件長度,代碼段、數(shù)據(jù)段等信息),并填充Exe_Format數(shù)據(jù)結(jié)構(gòu)中的域值。2、在Linux環(huán)境下編譯系統(tǒng)得到GeekOS鏡像文件。3、編寫一個(gè)相應(yīng)的bochs配置文件。4、在bochs中運(yùn)行GeekOS系統(tǒng)顯示結(jié)果。第九章設(shè)計(jì)項(xiàng)目1一、項(xiàng)目設(shè)計(jì)目的31、ELF文件格式

三、項(xiàng)目設(shè)計(jì)提示表1ELF目標(biāo)文件格式連接程序視圖

執(zhí)行程序視圖

ELF頭部ELF頭部程序頭部表(可選)程序頭部表節(jié)區(qū)1段1...節(jié)區(qū)n段2.........節(jié)區(qū)頭部表節(jié)區(qū)頭部表(可選)1、ELF文件格式三、項(xiàng)目設(shè)計(jì)提示表1ELF目標(biāo)文件格式42、內(nèi)存中的可執(zhí)行文件鏡像

2、內(nèi)存中的可執(zhí)行文件鏡像53、內(nèi)核線程的建立流程Spawn_Init_Process()Start_Kernel_Thread()Spawner()Read_Fully()Parse_ELF_Excutable()Spawn_Program()3、內(nèi)核線程的建立流程Spawn_Init_Process(6根據(jù)Exe_Format中的Exe_Segment結(jié)構(gòu)提供的用戶程序段信息,及用戶進(jìn)程堆棧大小計(jì)算用戶進(jìn)程所需的最大內(nèi)存空間,即要分配給用戶進(jìn)程的內(nèi)存空間;為用戶程序分配內(nèi)存空間,并全部初始化為零,否則系統(tǒng)后面運(yùn)行可能出錯(cuò);根據(jù)段信息將用戶程序中的各段內(nèi)容復(fù)制到分配的用戶內(nèi)存空間。根據(jù)Exe_Segment提供的用戶段信息初始化代碼段、數(shù)據(jù)段以及堆棧段的段描述符和段選擇子。

4、Spawn_Program函數(shù)的功能根據(jù)Exe_Format中的Exe_Segment結(jié)構(gòu)提供的7intParse_ELF_Executable(char*exeFileData,ulong_texeFileLength,structExe_Format*exeFormat)參數(shù):exeFileData——已裝入內(nèi)存的可執(zhí)行文件所占用空間的起始地址exeFileLength——可執(zhí)行文件長度exeFormat——保存分析得到的elf文件信息的結(jié)構(gòu)體指針根據(jù)ELF文件格式,用戶可以從exeFileData指向的內(nèi)容中得到ELF文件頭,繼續(xù)分析可以得到程序頭,程序代碼段等信息。5、Parse_ELF_Excutable函數(shù)intParse_ELF_Executable(char8第十章設(shè)計(jì)項(xiàng)目2

一、項(xiàng)目設(shè)計(jì)目的擴(kuò)充GeekOS操作系統(tǒng)內(nèi)核,使得系統(tǒng)能夠支持用戶級(jí)進(jìn)程的動(dòng)態(tài)創(chuàng)建和執(zhí)行。二、項(xiàng)目2要求用戶對(duì)以下幾個(gè)文件進(jìn)行修改:1)“src/GeekOS/user.c”文件中的函數(shù)Spawn(),其功能是生成一個(gè)新的用戶級(jí)進(jìn)程;2)“src/GeekOS/user.c”文件中的函數(shù)Switch_To_User_Context(),調(diào)度程序在執(zhí)行一個(gè)新的進(jìn)程前調(diào)用該函數(shù)以切換用戶地址空間;

3)“src/GeekOS/elf.c”文件中的函數(shù)Parse_ELF_Executable()。該函數(shù)的實(shí)現(xiàn)要求和項(xiàng)目1相同。第十章設(shè)計(jì)項(xiàng)目2一、項(xiàng)目設(shè)計(jì)目的94)“src/GeekOS/userseg.c”文件中主要是實(shí)現(xiàn)一些為實(shí)現(xiàn)對(duì)“src/GeekOS/user.c”中高層操作支持的函數(shù)。

Destroy_User_Context()函數(shù)的功能是釋放用戶態(tài)進(jìn)程占用的內(nèi)存資源。

Load_User_Program()函數(shù)的功能通過加載可執(zhí)行文件鏡像創(chuàng)建新進(jìn)程的User_Context結(jié)構(gòu)。

Copy_From_User()和Copy_To_User()函數(shù)的功能是在用戶地址空間和內(nèi)核地址空間之間復(fù)制數(shù)據(jù),在分段存儲(chǔ)器管理模式下,只要段有效,調(diào)用memcpy函數(shù)就可以實(shí)現(xiàn)這兩個(gè)函數(shù)的功能。

Switch_To_Address_Space()函數(shù)的功能是通過將進(jìn)程的LDT裝入到LDT寄存器來激活用戶的地址空間;GeekOS操作系統(tǒng)課程設(shè)計(jì)項(xiàng)目介紹105)“src/GeekOS/kthread.c”文件中的Start_User_Thread函數(shù)和Setup_User_Thread函數(shù)。Setup_User_Thread()函數(shù)的功能是為進(jìn)程初始化內(nèi)核堆棧,堆棧中是為進(jìn)程首次進(jìn)入用戶態(tài)運(yùn)行時(shí)設(shè)置處理器狀態(tài)要使用的數(shù)據(jù)。Start_User_Thread()是一個(gè)高層操作,該函數(shù)使用User_Context對(duì)象開始一個(gè)新進(jìn)程。6)“src/GeekOS/kthread.c”文件中主要是實(shí)現(xiàn)用戶程序要求內(nèi)核進(jìn)行服務(wù)的一些系統(tǒng)調(diào)用函數(shù)定義。要求用戶實(shí)現(xiàn)的有Sys_Exit()函數(shù)、Sys_PrintString()函數(shù)、Sys_GetKey()、Sys_SetAttr()、Sys_GetCursor()、Sys_PutCursor()、Sys_Spawn()函數(shù)、Sys_Wait()函數(shù)和Sys_GetPID()函數(shù)。7)在main.c文件中改寫生成第一個(gè)用戶態(tài)進(jìn)程的函數(shù)調(diào)用:Spawn_Init_Process(void)。5)“src/GeekOS/kthread.c”文件中的St111、

GeekOS進(jìn)程狀態(tài)及轉(zhuǎn)換

三、項(xiàng)目設(shè)計(jì)提示currentrunwait出現(xiàn)需要等待的事件等待的事件發(fā)生調(diào)度時(shí)間片到等圖5.1GeekOS進(jìn)程狀態(tài)轉(zhuǎn)換GeekOS系統(tǒng)最早創(chuàng)建的內(nèi)核進(jìn)程有Idle、Reaper和Main三個(gè)進(jìn)程,它們由Init_Scheduler函數(shù)創(chuàng)建:最先初始化一個(gè)核態(tài)進(jìn)程mainThread,并將該進(jìn)程作為當(dāng)前運(yùn)行進(jìn)程,函數(shù)最后還調(diào)用Start_Kernel_Thread函數(shù)創(chuàng)建了兩個(gè)系統(tǒng)進(jìn)程Idle和Reaper。所以,Idle、Reaper和Main三個(gè)進(jìn)程是系統(tǒng)中最早存在的進(jìn)程。新建1、GeekOS進(jìn)程狀態(tài)及轉(zhuǎn)換三、項(xiàng)目設(shè)計(jì)提示curre12GeekOS的內(nèi)核進(jìn)程對(duì)象

include/kthread.h中定義,具體結(jié)構(gòu)如下:structKernel_Thread{ulong_tesp; //進(jìn)程的內(nèi)核堆棧esp指針volatileulong_tnumTicks; //計(jì)時(shí)器intpriority; //進(jìn)程優(yōu)先級(jí)DEFINE_LINK(Thread_Queue,Kernel_Thread);//指針指向進(jìn)程隊(duì)列下一進(jìn)程void*stackPage; //內(nèi)核堆棧頁指針structUser_Context*userContext;//用戶進(jìn)程上下文structKernel_Thread*owner; //父進(jìn)程指針intrefCount; //引用計(jì)數(shù)boolalive; //是否活躍structThread_QueuejoinQueue; //加入隊(duì)列intexitCode; //返回代碼intpid; //進(jìn)程IDDEFINE_LINK(All_Thread_List,Kernel_Thread);//全局進(jìn)程鏈表指針#defineMAX_TLOCAL_KEYS128constvoid*tlocalData[MAX_TLOCAL_KEYS]; //本地信息intcurrentReadyQueue; //進(jìn)程當(dāng)前所在的運(yùn)行隊(duì)列的索引編號(hào)boolblocked; //是否被阻塞};GeekOS的內(nèi)核進(jìn)程對(duì)象include/kt132、GeekOS的用戶態(tài)進(jìn)程

在GeekOS中為了區(qū)分用戶態(tài)進(jìn)程和內(nèi)核進(jìn)程,在Kernel_Thread結(jié)構(gòu)體中設(shè)置了一個(gè)字段userContext,指向用戶態(tài)進(jìn)程上下文。對(duì)于內(nèi)核進(jìn)程來說,這個(gè)指針為空,而用戶態(tài)進(jìn)程都擁有自己的用戶上下文(User_Context)。因此,在GeekOS中要判斷一個(gè)進(jìn)程是內(nèi)核進(jìn)程還是用戶態(tài)進(jìn)程,只要通過userContext字段是否為空來判斷就可以了。圖10.1用戶態(tài)進(jìn)程結(jié)構(gòu)2、GeekOS的用戶態(tài)進(jìn)程在GeekOS中為14User_Context結(jié)構(gòu)結(jié)構(gòu)定義如下(在“include/geekos/user.h”中定義):

structUser_Context{

#defineNUM_USER_LDT_ENTRIES3

structSegment_Descriptorldt[NUM_USER_LDT_ENTRIES];//用戶LDT

structSegment_Descriptor*ldtDescriptor;//LDT描述符

char*memory;//指向用戶空間

ulong_tsize;//用戶空間的大小

ushort_tldtSelector;//ldt選擇子

ushort_tcsSelector;//cs選擇子

ushort_tssSelector;//ss選擇子

ushort_tdsSelector;//ds選擇子

pde_t*pageDir; //頁表指針

ulong_tentryAddr; //用戶程序入口地址

ulong_targBlockAddr; //參數(shù)塊地址

ulong_tstackPointerAddr;//用戶態(tài)進(jìn)程的堆棧指針

intrefCount; //引用數(shù)

structFile*fileList[USER_MAX_FILES];//打開文件列表

intfileCount; //打開文件計(jì)數(shù)

};User_Context結(jié)構(gòu)結(jié)構(gòu)定義如下(在“include154、用戶態(tài)進(jìn)程空間

每個(gè)用戶態(tài)進(jìn)程都擁有屬于自己的內(nèi)存段空間,如:代碼段、數(shù)據(jù)段、堆棧段等,每個(gè)段有一個(gè)段描述符(segmentdescriptor),并且每個(gè)進(jìn)程有一個(gè)段描述符表(LocalDescriptorTable),用于保存該進(jìn)程的所有段描述符。操作系統(tǒng)中還設(shè)置一個(gè)全局描述符表(GDT,GlobalDescriptorTable),用于記錄了系統(tǒng)中所有進(jìn)程的ldt描述符。圖10.2GDT、LDT和User_Context的關(guān)系4、用戶態(tài)進(jìn)程空間每個(gè)用戶態(tài)進(jìn)程都擁有屬于自16(1)調(diào)用函數(shù)Allocate_Segment_Descriptor()新建一個(gè)LDT描述符;(2)調(diào)用函數(shù)Selector()新建一個(gè)LDT選擇子;(3)調(diào)用函數(shù)Init_Code_Segment_Descriptor()新建一個(gè)文本段描述符;(4)調(diào)用函數(shù)Init_Data_Segment_Descriptor()新建一個(gè)數(shù)據(jù)段;(5)調(diào)用函數(shù)Selector()新建一個(gè)數(shù)據(jù)段選擇子;(6)調(diào)用函數(shù)Selector()新建一個(gè)文本(可執(zhí)行代碼)段選擇子。5、用戶態(tài)進(jìn)程創(chuàng)建LDT的步驟

(1)調(diào)用函數(shù)Allocate_Segment_Descri173、用戶態(tài)進(jìn)程創(chuàng)建流程Spawn()Read_Fully()Parse_ELF_Excutable()Start_User_Thread()Setup_User_Thread()Load_User_Program()Attach_User_Context()3、用戶態(tài)進(jìn)程創(chuàng)建流程Spawn()Read_Fully184、Spawn函數(shù)的功能intSpawn(constchar*program,constchar*command,structKernel_Thread**pThread)參數(shù)說明:Program對(duì)應(yīng)的是要讀入內(nèi)存緩沖區(qū)的可執(zhí)行文件,Command是用戶執(zhí)行程序執(zhí)行時(shí)的命令行字符串,pThread是存放指向剛創(chuàng)建進(jìn)程的指針。Spawn函數(shù)主要完成的主要功能是:(1)調(diào)用Read_Fully函數(shù)將名為program的可執(zhí)行文件全部讀入內(nèi)存緩沖區(qū)。(2)調(diào)用Parse_ELF_Executable函數(shù),分析ELF格式文件。Parse_ELF_Executable函數(shù)功能在項(xiàng)目1中已經(jīng)實(shí)現(xiàn)。(3)調(diào)用Load_User_Program將可執(zhí)行程序的程序段和數(shù)據(jù)段等裝入內(nèi)存,初始化User_context數(shù)據(jù)結(jié)構(gòu)。(4)調(diào)用Start_User_Thread函數(shù)創(chuàng)建一個(gè)進(jìn)程并使該進(jìn)程進(jìn)入準(zhǔn)備運(yùn)行隊(duì)列。4、Spawn函數(shù)的功能intSpawn(constch195、Load_User_Program函數(shù)Load_User_Program函數(shù)在“/src/geekos/userseg.c”文件中實(shí)現(xiàn),代碼也需要開發(fā)人員自己完成,函數(shù)原型如下:intLoad_User_Program(char*exeFileData,ulong_texeFileLength,structExe_Format*exeFormat,constchar*command,structUser_Context**pUserContext)/*參數(shù)說明:exeFileData——保存在內(nèi)存緩沖中的用戶程序可執(zhí)行文件;exeFileLength——可執(zhí)行文件的長度;exeFormat——調(diào)用Parse_ELF_Executable函數(shù)得到的可執(zhí)行文件格式信息;command——用戶輸入的命令行,包括可執(zhí)行文件的名稱及其他參數(shù);pUserContext——指向User_Conetxt的指針,是本函數(shù)完成用戶上下文初始化的對(duì)象*/5、Load_User_Program函數(shù)Load_Use20Load_User_Program主要實(shí)現(xiàn)功能如下:(1)根據(jù)Parse_ELF_Executable函數(shù)的執(zhí)行結(jié)果Exe_Format中的Exe_Segment結(jié)構(gòu)提供的用戶程序段信息,用戶命令參數(shù)及用戶態(tài)進(jìn)程堆棧大小計(jì)算用戶態(tài)進(jìn)程所需的最大內(nèi)存空間,即要分配給用戶態(tài)進(jìn)程的內(nèi)存空間。(2)為用戶程序分配內(nèi)存空間,并初始化。(3)根據(jù)Exe_Segment提供的用戶段信息初始化代碼段、數(shù)據(jù)段以及堆棧段的段描述符和段選擇子。(4)根據(jù)段信息將用戶程序中的各段內(nèi)容復(fù)制到分配的用戶內(nèi)存空間。(5)根據(jù)Exe_Format結(jié)構(gòu)初始化User_Context結(jié)構(gòu)中的用戶態(tài)進(jìn)程代碼段入口entry字段,并根據(jù)command參數(shù)初始化用戶內(nèi)存空間中的參數(shù)塊。(6)初始化User_Context結(jié)構(gòu)的用戶打開文件列表,并添加標(biāo)準(zhǔn)輸入輸出文件。(7)將初始化完畢的User_Context指針賦予*pUserContext,返回0表示成功。Load_User_Program主要實(shí)現(xiàn)功能如下:21一、項(xiàng)目設(shè)計(jì)目的研究進(jìn)程調(diào)度算法,掌握用信號(hào)量實(shí)現(xiàn)進(jìn)程間同步的方法。為GeekOS擴(kuò)充進(jìn)程調(diào)度算法——基于時(shí)間片輪轉(zhuǎn)的進(jìn)程多級(jí)反饋調(diào)度算法,并能用信號(hào)量實(shí)現(xiàn)進(jìn)程協(xié)作。二、項(xiàng)目設(shè)計(jì)要求(1)實(shí)現(xiàn)src/geekos/syscall.c文件中的Sys_SetSchedulingPolicy系統(tǒng)調(diào)用,它的功能是設(shè)置系統(tǒng)采用的何種進(jìn)程調(diào)度策略;(2)實(shí)現(xiàn)src/geekos/syscall.c文件中的Sys_GetTimeOfDay系統(tǒng)調(diào)用,它的功能是獲取全局變量g_numTicks的值;(3)實(shí)現(xiàn)函數(shù)Change_Scheduling_Policy(),具體實(shí)現(xiàn)不同調(diào)度算法的轉(zhuǎn)換。(4)實(shí)現(xiàn)syscall.c中信號(hào)量有關(guān)的四個(gè)系統(tǒng)調(diào)用:sys_createsemaphore()、sys_P()、sys_V()和sys_destroysemaphore()。第11章設(shè)計(jì)項(xiàng)目3

一、項(xiàng)目設(shè)計(jì)目的第11章設(shè)計(jì)項(xiàng)目3221、多級(jí)反饋隊(duì)列調(diào)度隊(duì)列模型三、項(xiàng)目設(shè)計(jì)提示1、多級(jí)反饋隊(duì)列調(diào)度隊(duì)列模型三、項(xiàng)目設(shè)計(jì)提示232、多級(jí)反饋隊(duì)列與分時(shí)調(diào)度進(jìn)程隊(duì)列的轉(zhuǎn)換

2、多級(jí)反饋隊(duì)列與分時(shí)調(diào)度進(jìn)程隊(duì)列的轉(zhuǎn)換24(1)添加函數(shù)Chang_Scheduling_Policy(intpolicy,intquantum),policy是設(shè)置的調(diào)度策略,quantum是設(shè)置的時(shí)間片。例如policy為1說明設(shè)置的是多級(jí)反饋隊(duì)列調(diào)度算法,此時(shí)若g_SchedPolicy(為系統(tǒng)添加的標(biāo)識(shí)算法的變量,初始化為0)為0,說明當(dāng)前的調(diào)度算法為輪轉(zhuǎn)調(diào)度,要變成MLF就必須把空閑線程放入3隊(duì)列,若g_SchedPolicy為1,說明當(dāng)前是多級(jí)反饋隊(duì)列調(diào)度算法,則返回。如果policy為0,則說明設(shè)置的是輪轉(zhuǎn)調(diào)度,此時(shí)若g_SchedPolicy為1,則必須把4個(gè)隊(duì)列變成一個(gè)隊(duì)列,即所有的線程都在隊(duì)列0上了。若g_SchedPolicy為0,則返回。3、函數(shù)設(shè)計(jì)提示(1)添加函數(shù)Chang_Scheduling_Policy25(2)在系統(tǒng)調(diào)用Sys_GetTimeOfDay()中,只需要返回g_numTicks就可以了。在Sys_SetSchedulingPolicy()中,如果state->ebx是1,則設(shè)置的是MLF算法,調(diào)用Change_Scheduling_Policy(SCHED_RR,quantum),為0則是RR算法,調(diào)用Change_Scheduling_Policy(SCHED_MLF,quantum)。如果state->ebx為其他值,則返回-1。(3)在Init_Thread()中都是把隊(duì)列放在0隊(duì)列上的,并且blocked變量為false。(4)在Get_Next_Runnable()中,從最高級(jí)的隊(duì)列開始,調(diào)用Find_Best()來找線程優(yōu)先級(jí)最大的線程,直到在某級(jí)隊(duì)列中找到符合條件可以運(yùn)行的線程。(5)在Wait()函數(shù)中,線程被阻塞,所以blocked變量被設(shè)置為true,并且如果是MLF算法,則該進(jìn)程的currentReadyQueue加一,下次運(yùn)行的時(shí)候進(jìn)入高一級(jí)的線程隊(duì)列。(2)在系統(tǒng)調(diào)用Sys_GetTimeOfDay()中,只需26GveekOS定義了信號(hào)量的結(jié)構(gòu)體:structSemaphore{intsemaphoreID;/*信號(hào)量的ID*/char*semaphoreName;/*信號(hào)量的名字*/intvalue;/*信號(hào)量的值*/intregisteredThreadCount;/*注冊(cè)該信號(hào)量的線程數(shù)量*/structKernel_Thread*registeredThreads[MAX_REGISTERED_THREADS];/*注冊(cè)的線程*/structThread_QueuewaitingThreads;/*等待該信號(hào)的線程隊(duì)列*/DEFINE_LINK(Semaphore_List,Semaphore);/*連接信號(hào)鏈表的域*/}4、信號(hào)量定義

GveekOS定義了信號(hào)量的結(jié)構(gòu)體:4、信號(hào)量定義27信號(hào)量操作:Semaphore_Create()Semaphore_Acquire(P操作)Semaphore_Release(V操作)Semaphore_Destroy()Create_Semaphore()函數(shù)首先檢查請(qǐng)求創(chuàng)建的這個(gè)信號(hào)量的名字是否存在,如果存在,那么就把這個(gè)線程加入到這個(gè)信號(hào)量所注冊(cè)的線程鏈表上;如果不存在,則分配內(nèi)存給新的信號(hào)量,清空它的線程隊(duì)列,把當(dāng)前的這個(gè)線程加入到它的線程隊(duì)列中,設(shè)置注冊(cè)線程數(shù)量為1,初始化信號(hào)量的名字,值和信號(hào)量的ID,并把這個(gè)信號(hào)量添加到信號(hào)量鏈表上,最后返回信號(hào)量的ID。5、信號(hào)量PV操作

信號(hào)量操作:5、信號(hào)量PV操作28P操作Semaphore_Acquire()中,首先檢查傳入的信號(hào)量ID是否存在,如果存在,接著檢查當(dāng)前線程是否注冊(cè)使用了這個(gè)信號(hào)量,如果這兩項(xiàng)檢查任意一項(xiàng)失敗了,那么就返回-1。如果成功了,就把信號(hào)量的值減去1,如果減去1后信號(hào)量的值小于0,那么就把當(dāng)前線程放入這個(gè)信號(hào)量的等待隊(duì)列上。V操作Semaphore_Release()中,首先也是檢查傳入的信號(hào)量ID是否存在,如果存在,接著檢查當(dāng)前線程是否注冊(cè)使用了這個(gè)信號(hào)量,如果這兩項(xiàng)檢查任意一項(xiàng)失敗了,那么就返回-1。如果成功了,那就把信號(hào)量的值加上1,如果加上1后信號(hào)量的值小于或等于0,則要把該信號(hào)量里等待隊(duì)列上的一個(gè)線程喚醒。Semaphore_Destroy()中,首先也是檢查傳入的信號(hào)量ID是否存在,如果存在,接著檢查當(dāng)前線程是否注冊(cè)使用了這個(gè)信號(hào)量,如果這兩項(xiàng)檢查任意一項(xiàng)失敗了,那么就返回-1。如果成功了,就把該線程從這個(gè)信號(hào)量的注冊(cè)的線程數(shù)組中刪除,并把注冊(cè)的線程數(shù)量減去1。如果這個(gè)信號(hào)量的注冊(cè)線程為0了,則把這個(gè)信號(hào)量從信號(hào)量鏈表中刪除,并釋放它的內(nèi)存。P操作Semaphore_Acquire()中,首先檢查傳入29第12章設(shè)計(jì)項(xiàng)目4

一、項(xiàng)目設(shè)計(jì)目的了解虛擬存儲(chǔ)器管理設(shè)計(jì)原理,掌握請(qǐng)求分頁虛擬存儲(chǔ)管理的具體實(shí)現(xiàn)技術(shù)。二、項(xiàng)目設(shè)計(jì)要求(1)在<src/geekos/paging.c>文件中編寫代碼完成以下函數(shù):Init_VM()(definedin)函數(shù)將建立一個(gè)初始的內(nèi)存頁目錄和頁表,并且安裝一個(gè)頁面出錯(cuò)處理函數(shù)。Init_Paging()函數(shù)(定義在src/geekos/paging.c)初始化操作頁面調(diào)度文件所需的所有數(shù)據(jù)結(jié)構(gòu)。就如前面說到的,Get_Paging_Device()函數(shù)指定分頁調(diào)度文件定位在哪一個(gè)設(shè)備和占用磁盤塊的地址范圍。Find_Space_On_Paging_File()函數(shù)應(yīng)該在分頁調(diào)度文件里面找到一個(gè)空閑的足夠大的頁空間。它將返回這個(gè)大塊的索引,或者當(dāng)沒有合適的空間就返回-1。第12章設(shè)計(jì)項(xiàng)目4一、項(xiàng)目設(shè)計(jì)目的30Free_Space_On_Paging_File()函數(shù)將釋放由Find_Space_On_Paging_File()函數(shù)在分頁調(diào)度文件里所分配的的磁盤塊。Write_To_Paging_File()函數(shù)將把存儲(chǔ)在內(nèi)存的一頁數(shù)據(jù)寫出到分頁調(diào)度文件里。Read_From_Paging_File()函數(shù)將讀取分頁調(diào)度文件里的一頁數(shù)據(jù)到內(nèi)存空間。(2)在<src/geekos/uservm.c>文件中編寫代碼完成以下函數(shù):Destroy_User_Context()釋放進(jìn)程所占用的所有內(nèi)存和其它資源。Load_User_Program()裝載可執(zhí)行文件到內(nèi)存里,創(chuàng)建一個(gè)就緒的用戶地址空間,功能類似于分段系統(tǒng)的實(shí)現(xiàn)。Copy_From_User()從一個(gè)用戶緩沖區(qū)復(fù)制數(shù)據(jù)到一個(gè)內(nèi)核緩沖區(qū)。Copy_To_User()從一個(gè)內(nèi)核緩沖區(qū)復(fù)制數(shù)據(jù)到一個(gè)用戶緩沖區(qū)。Switch_To_Address_Space()利用它裝載相應(yīng)頁目錄和LDT來切換到一個(gè)用戶地址空間。Free_Space_On_Paging_File()函數(shù)將311、地址轉(zhuǎn)換三、項(xiàng)目設(shè)計(jì)提示

1、地址轉(zhuǎn)換三、項(xiàng)目設(shè)計(jì)提示32GeekOS操作系統(tǒng)課程設(shè)計(jì)項(xiàng)目介紹33線性地址到物理地址的轉(zhuǎn)換過程線性地址到物理地址的轉(zhuǎn)換過程342、用戶進(jìn)程的線性地址空間2、用戶進(jìn)程的線性地址空間353、請(qǐng)求分頁系統(tǒng)實(shí)現(xiàn)操作系統(tǒng)將需要在磁盤設(shè)備上創(chuàng)建一個(gè)pagefile文件暫時(shí)保存從內(nèi)存中替換出去的頁,實(shí)現(xiàn)一個(gè)類LRU算法在內(nèi)存中選取一個(gè)替換頁把它寫到磁盤的pagefile文件中。缺頁中斷處理

表12-1缺頁處理表缺頁情況標(biāo)識(shí)相應(yīng)處理堆棧生長到新頁超出原來分配一頁的限制分配一個(gè)新頁進(jìn)程繼續(xù)此頁保存在磁盤上數(shù)據(jù)標(biāo)識(shí)這一頁在pagefile中存在從pagefile讀入需要的頁繼續(xù)因?yàn)闊o效地址缺頁非法地址訪問終止用戶進(jìn)程3、請(qǐng)求分頁系統(tǒng)實(shí)現(xiàn)操作系統(tǒng)將需要在磁盤設(shè)備上創(chuàng)建一個(gè)pag36在“/src/geekos/mem.c”文件中,已經(jīng)定義了一個(gè)函數(shù)Alloc_Pageable_Page實(shí)現(xiàn)交換一頁到磁盤的操作,具體執(zhí)行步驟如下:調(diào)用mem.c文件中已經(jīng)實(shí)現(xiàn)的Find_Page_To_Page_Out函數(shù)來確定要替換的頁(這個(gè)函數(shù)依賴于頁數(shù)據(jù)結(jié)構(gòu)中的clock域)。調(diào)用paging.c文件中已經(jīng)實(shí)現(xiàn)的Find_Space_On_Paging_File函數(shù)在pagefile中找到空閑的存儲(chǔ)空間。調(diào)用paging.c文件中已經(jīng)實(shí)現(xiàn)的Write_To_Paging_File函數(shù)把被替換的頁寫到pagefile文件中。修改頁表的相應(yīng)表項(xiàng),清除頁存在的標(biāo)志,標(biāo)識(shí)為此頁在內(nèi)存為不存在。修改頁表項(xiàng)的頁基地址為包含這一頁的第一個(gè)磁盤塊號(hào)。修改頁表項(xiàng)的kernelInfo位標(biāo)識(shí)為KINFO_PAGE_ON_DISK狀態(tài)(標(biāo)識(shí)這一頁是在磁盤上存在,而不是沒有效)。調(diào)用lowlevel.asm文件中已經(jīng)實(shí)現(xiàn)的Flush_TLB來刷新TLB。在“/src/geekos/mem.c”文件中,已經(jīng)定義了一37第13章設(shè)計(jì)項(xiàng)目5

一、項(xiàng)目設(shè)計(jì)目的了解文件系統(tǒng)的設(shè)計(jì)原理。掌握操作系統(tǒng)文件系統(tǒng)的具體實(shí)現(xiàn)技術(shù)。二、項(xiàng)目設(shè)計(jì)要求(1)為實(shí)現(xiàn)GOSFS文件系統(tǒng),用戶在“/src/geeekos/gosfs.c”中添加代碼,實(shí)現(xiàn)以下函數(shù)。GOSFS_Fstat()函數(shù):為給定的文件得到元數(shù)據(jù)。GOSFS_Read()函數(shù):從給定文件的當(dāng)前位置讀數(shù)據(jù)。GOSFS_Write()函數(shù):從給定文件的當(dāng)前位置寫數(shù)據(jù)。GOSFS_Seek()函數(shù):在給定文件中定位。GOSFS_Close()函數(shù):關(guān)閉給定文件。

第13章設(shè)計(jì)項(xiàng)目5一、項(xiàng)目設(shè)計(jì)目的38項(xiàng)目設(shè)計(jì)要求

GOSFS_Fstat_Directory()函數(shù):為一個(gè)打開的目錄得到元數(shù)據(jù)。GOSFS_Close_Directory()函數(shù):關(guān)閉給定目錄。GOSFS_Read_Entry()函數(shù):從打開的目錄表讀一個(gè)目錄項(xiàng)。GOSFS_Open()函數(shù):為給定的路徑名打開一個(gè)文件。GOSFS_Create_Directory()函數(shù):為給定的路徑創(chuàng)建一個(gè)目錄。GOSFS_Open_Directory()函數(shù):為給定的路徑打開一個(gè)目錄。GOSFS_Delete()函數(shù):為給定的路徑名刪除一個(gè)文件。GOSFS_stat()函數(shù):為給定的路徑得到元數(shù)據(jù)(大小,權(quán)限等信息)。GOSFS_Sync()函數(shù):對(duì)磁盤上的文件系統(tǒng)數(shù)據(jù)實(shí)現(xiàn)同步操作。GOSFS_Format()函數(shù):格式化GOSFS文件系統(tǒng)操作。GOSFS_Mount()函數(shù):掛載文件系統(tǒng)操作。

項(xiàng)目設(shè)計(jì)要求GOSFS_Fstat_Directory391、

GeekOS文件系統(tǒng)框架

三、項(xiàng)目設(shè)計(jì)提示1、GeekOS文件系統(tǒng)框架三、項(xiàng)目設(shè)計(jì)提示402、GOSFS讀文件處理流程

用戶進(jìn)程調(diào)用C語言庫函數(shù)Read函數(shù)軟件中斷,內(nèi)核調(diào)用Sys_Read()函數(shù)虛擬文件系統(tǒng)層的Read()函數(shù)讀出文件的數(shù)據(jù)Sys_Read()函數(shù)將數(shù)據(jù)拷貝到用戶緩沖區(qū)GOSFS讀文件過程※系統(tǒng)已經(jīng)實(shí)現(xiàn)PFAT文件系統(tǒng),用戶要實(shí)現(xiàn)的是GOSFS文件系統(tǒng),可依照PFAT文件的實(shí)現(xiàn)原理2、GOSFS讀文件處理流程用戶進(jìn)程調(diào)用軟件中斷,內(nèi)核調(diào)用41User_Context結(jié)構(gòu)結(jié)構(gòu)定義如下(在“include/geekos/user.h”中定義):

structUser_Context{

#defineNUM_USER_LDT_ENTRIES3

structSegment_Descriptorldt[NUM_USER_LDT_ENTRIES];//用戶LDT

structSegment_Descriptor*ldtDescriptor;//LDT描述符

char*memory;//指向用戶空間

ulong_tsize;//用戶空間的大小

ushort_tldtSelector;//ldt選擇子

ushort_tcsSelector;//cs選擇子

ushort_tssSelector;//ss選擇子

ushort_tdsSelector;//ds選擇子

pde_t*pageDir; //頁表指針

ulong_tentryAddr; //用戶程序入口地址

ulong_targBlockAddr; //參數(shù)塊地址

ulong_tstackPointerAddr;//用戶態(tài)進(jìn)程的堆棧指針

intrefCount; //引用數(shù)

structFile*fileList[USER_MAX_FILES];//打開文件列表

intfileCount; //打開文件計(jì)數(shù)

};2、GOSFS文件系統(tǒng)結(jié)構(gòu)

User_Context結(jié)構(gòu)結(jié)構(gòu)定義如下(在“include42(1)磁盤邏輯結(jié)構(gòu)2、GOSFS文件系統(tǒng)結(jié)構(gòu)

(1)磁盤邏輯結(jié)構(gòu)2、GOSFS文件系統(tǒng)結(jié)構(gòu)43MAX_FILES_PER_DIRGOSFS_Dir_Entryfilename[128]flagssizeacl[10]blockList[10]目錄項(xiàng)GOSFS_Dir_EntryGOSFS_Dir_EntryGOSFS_Dir_EntryGOSFS_Dir_EntryGOSFS_Dir_EntryGOSFS_Dir_EntryGOSFS_Dir_Entry目錄塊文件目錄

數(shù)據(jù)塊數(shù)據(jù)塊MAX_FILES_PER_DIRGOSFS_Dir_En44數(shù)據(jù)存儲(chǔ)分配–直接映射01234567894KBdatablockGOSFS_Dir_Entry.blockList[10]4KBdatablock4KBdatablock磁盤=已分配12KB大小的文件數(shù)據(jù)存儲(chǔ)分配–直接映射01234567894KBdata454KBdatablock4KBdatablock4KBdatablock磁盤0123456789001234...1022102304KBdatablock4KBdatablock40KB大小的文件一級(jí)間接索引塊….GOSFS_Dir_Entry.blockList[10]數(shù)據(jù)存儲(chǔ)分配–一級(jí)間接映射4KBdatablock4KBdatablock4K464KBdatablock4KBdatablock4KBdatablock磁盤012345678904KBdatablock4KBdatablock4136KB大小的文件1022102301234...0一級(jí)索引塊….1022102301234...01022102301234...0一級(jí)索引塊二級(jí)索引塊GOSFS_Dir_Entry.blockList[10]數(shù)據(jù)存儲(chǔ)分配–二級(jí)間接映射4KBdatablock4KBdatablock4K47[0,32KB]–僅僅使用直接映射方法(32KB,4128KB]–使用直接映射方法+一級(jí)間接索引塊方法(4128KB,32MB]–使用直接映射方法+一級(jí)間接索引塊方法+二級(jí)間接索引塊方法數(shù)據(jù)存儲(chǔ)空間分配總結(jié)[0,32KB]–僅僅使用直接映射方法數(shù)據(jù)存儲(chǔ)空間分配總484、GOSFS的操作

(1)FORMAT格式化操作SYS_FORMATFormat(char*dev,char*fstype)初始化磁盤格式,即各系統(tǒng)數(shù)據(jù)初始化Format操作完成文件系統(tǒng)的格式化操作。在系統(tǒng)編譯時(shí)GeekOS會(huì)自動(dòng)生成10兆大小的磁盤鏡像,并初始化內(nèi)容為全零。GOSFS_Format將這種原始磁盤格式化為GOSFS格式的磁盤,操作包括寫入引導(dǎo)塊,文件系統(tǒng)初始超級(jí)塊以及根目錄信息節(jié)點(diǎn)。只是針對(duì)GOSFS,不能格式化PFAT4、GOSFS的操作(1)FORMAT格式化操作SYS49(2)掛載GOSFSSYS_MOUNTvsf.c:Mount(char*devname,char*pathPrefix,char*fstype)gosfs.c:GOSFS_Mount(structMount_Point*mountPoint)GOSFS_Mount操作負(fù)責(zé)將一塊GOSFS格式的磁盤掛載到GeekOS。這個(gè)操作必須在磁盤訪問操作進(jìn)行之前完成。掛載操作首先初始化內(nèi)存中的實(shí)體超級(jí)塊,之后初始化虛擬超級(jí)塊,最后初始化GOSFS根目錄“d”。掛載操作成功完成后,文件系統(tǒng)就可以訪問超級(jí)塊與文件系統(tǒng)根目錄,并完成相應(yīng)操作。(2)掛載GOSFSSYS_MOUNT505、高速緩沖區(qū)思想:保留一些磁盤數(shù)據(jù)塊在內(nèi)存中(buffers);內(nèi)存中的數(shù)據(jù)讀寫比磁盤中讀寫數(shù)據(jù)要快得多。緩沖區(qū)使用過程申請(qǐng)–修改–釋放bufcache.cCreate_FS_Buffer_Cache(structBlock_Device*dev,…)Get_FS_Buffer()Modify_FS_Buffer()Sync_FS_Buffer()Release_FS_Buffer()5、高速緩沖區(qū)思想:保留一些磁盤數(shù)據(jù)塊在內(nèi)存中(buff51一、項(xiàng)目設(shè)計(jì)目的熟悉GeekOS的項(xiàng)目編譯、調(diào)試和運(yùn)行環(huán)境,掌握GeekOS運(yùn)行工作過程。二、項(xiàng)目設(shè)計(jì)要求1、搭建GeekOS的編譯和調(diào)試平臺(tái),掌握GeekOS的內(nèi)核進(jìn)程工作原理。2、熟悉鍵盤操作函數(shù),編程實(shí)現(xiàn)一個(gè)內(nèi)核進(jìn)程。該進(jìn)程的功能是:接收鍵盤輸入的字符并顯示到屏幕上,當(dāng)輸入ctrl+d時(shí),結(jié)束進(jìn)程的運(yùn)行。第八章設(shè)計(jì)項(xiàng)目0

一、項(xiàng)目設(shè)計(jì)目的第八章設(shè)計(jì)項(xiàng)目052三、項(xiàng)目0的實(shí)現(xiàn)主要由以下步驟完成(在項(xiàng)目0的/src/geekos/main.c中完成):編寫一個(gè)C語言函數(shù),函數(shù)功能是:接收鍵盤輸入的按鍵,并將鍵值在顯示器顯示出來,當(dāng)輸入ctrl+d就退出;在Main函數(shù)體內(nèi)調(diào)用Start_Kernel_Thread函數(shù),將步驟1編寫的函數(shù)地址傳遞給參數(shù)startFunc,利用Setup_Kernel_Thread函數(shù)建立一個(gè)待運(yùn)行的線程。

在Linux環(huán)境下編譯系統(tǒng)得到GeekOS鏡像文件。編寫一個(gè)相應(yīng)的bochs配置文件。在bochs中運(yùn)行GeekOS系統(tǒng)顯示結(jié)果。三、項(xiàng)目0的實(shí)現(xiàn)主要由以下步驟完成(在項(xiàng)目0的/src/ge53第九章設(shè)計(jì)項(xiàng)目1

一、項(xiàng)目設(shè)計(jì)目的熟悉ELF文件格式,了解GeekOS系統(tǒng)如何將ELF格式的可執(zhí)行程序裝入到內(nèi)存,建立內(nèi)核進(jìn)程并運(yùn)行的實(shí)現(xiàn)技術(shù)。二、項(xiàng)目設(shè)計(jì)要求1、修改/geekos/elf.c文件:在函數(shù)Parse_ELF_Executable()中添加代碼,分析ELF格式的可執(zhí)行文件(包括分析得出ELF文件頭、程序頭,獲取可執(zhí)行文件長度,代碼段、數(shù)據(jù)段等信息),并填充Exe_Format數(shù)據(jù)結(jié)構(gòu)中的域值。2、在Linux環(huán)境下編譯系統(tǒng)得到GeekOS鏡像文件。3、編寫一個(gè)相應(yīng)的bochs配置文件。4、在bochs中運(yùn)行GeekOS系統(tǒng)顯示結(jié)果。第九章設(shè)計(jì)項(xiàng)目1一、項(xiàng)目設(shè)計(jì)目的541、ELF文件格式

三、項(xiàng)目設(shè)計(jì)提示表1ELF目標(biāo)文件格式連接程序視圖

執(zhí)行程序視圖

ELF頭部ELF頭部程序頭部表(可選)程序頭部表節(jié)區(qū)1段1...節(jié)區(qū)n段2.........節(jié)區(qū)頭部表節(jié)區(qū)頭部表(可選)1、ELF文件格式三、項(xiàng)目設(shè)計(jì)提示表1ELF目標(biāo)文件格式552、內(nèi)存中的可執(zhí)行文件鏡像

2、內(nèi)存中的可執(zhí)行文件鏡像563、內(nèi)核線程的建立流程Spawn_Init_Process()Start_Kernel_Thread()Spawner()Read_Fully()Parse_ELF_Excutable()Spawn_Program()3、內(nèi)核線程的建立流程Spawn_Init_Process(57根據(jù)Exe_Format中的Exe_Segment結(jié)構(gòu)提供的用戶程序段信息,及用戶進(jìn)程堆棧大小計(jì)算用戶進(jìn)程所需的最大內(nèi)存空間,即要分配給用戶進(jìn)程的內(nèi)存空間;為用戶程序分配內(nèi)存空間,并全部初始化為零,否則系統(tǒng)后面運(yùn)行可能出錯(cuò);根據(jù)段信息將用戶程序中的各段內(nèi)容復(fù)制到分配的用戶內(nèi)存空間。根據(jù)Exe_Segment提供的用戶段信息初始化代碼段、數(shù)據(jù)段以及堆棧段的段描述符和段選擇子。

4、Spawn_Program函數(shù)的功能根據(jù)Exe_Format中的Exe_Segment結(jié)構(gòu)提供的58intParse_ELF_Executable(char*exeFileData,ulong_texeFileLength,structExe_Format*exeFormat)參數(shù):exeFileData——已裝入內(nèi)存的可執(zhí)行文件所占用空間的起始地址exeFileLength——可執(zhí)行文件長度exeFormat——保存分析得到的elf文件信息的結(jié)構(gòu)體指針根據(jù)ELF文件格式,用戶可以從exeFileData指向的內(nèi)容中得到ELF文件頭,繼續(xù)分析可以得到程序頭,程序代碼段等信息。5、Parse_ELF_Excutable函數(shù)intParse_ELF_Executable(char59第十章設(shè)計(jì)項(xiàng)目2

一、項(xiàng)目設(shè)計(jì)目的擴(kuò)充GeekOS操作系統(tǒng)內(nèi)核,使得系統(tǒng)能夠支持用戶級(jí)進(jìn)程的動(dòng)態(tài)創(chuàng)建和執(zhí)行。二、項(xiàng)目2要求用戶對(duì)以下幾個(gè)文件進(jìn)行修改:1)“src/GeekOS/user.c”文件中的函數(shù)Spawn(),其功能是生成一個(gè)新的用戶級(jí)進(jìn)程;2)“src/GeekOS/user.c”文件中的函數(shù)Switch_To_User_Context(),調(diào)度程序在執(zhí)行一個(gè)新的進(jìn)程前調(diào)用該函數(shù)以切換用戶地址空間;

3)“src/GeekOS/elf.c”文件中的函數(shù)Parse_ELF_Executable()。該函數(shù)的實(shí)現(xiàn)要求和項(xiàng)目1相同。第十章設(shè)計(jì)項(xiàng)目2一、項(xiàng)目設(shè)計(jì)目的604)“src/GeekOS/userseg.c”文件中主要是實(shí)現(xiàn)一些為實(shí)現(xiàn)對(duì)“src/GeekOS/user.c”中高層操作支持的函數(shù)。

Destroy_User_Context()函數(shù)的功能是釋放用戶態(tài)進(jìn)程占用的內(nèi)存資源。

Load_User_Program()函數(shù)的功能通過加載可執(zhí)行文件鏡像創(chuàng)建新進(jìn)程的User_Context結(jié)構(gòu)。

Copy_From_User()和Copy_To_User()函數(shù)的功能是在用戶地址空間和內(nèi)核地址空間之間復(fù)制數(shù)據(jù),在分段存儲(chǔ)器管理模式下,只要段有效,調(diào)用memcpy函數(shù)就可以實(shí)現(xiàn)這兩個(gè)函數(shù)的功能。

Switch_To_Address_Space()函數(shù)的功能是通過將進(jìn)程的LDT裝入到LDT寄存器來激活用戶的地址空間;GeekOS操作系統(tǒng)課程設(shè)計(jì)項(xiàng)目介紹615)“src/GeekOS/kthread.c”文件中的Start_User_Thread函數(shù)和Setup_User_Thread函數(shù)。Setup_User_Thread()函數(shù)的功能是為進(jìn)程初始化內(nèi)核堆棧,堆棧中是為進(jìn)程首次進(jìn)入用戶態(tài)運(yùn)行時(shí)設(shè)置處理器狀態(tài)要使用的數(shù)據(jù)。Start_User_Thread()是一個(gè)高層操作,該函數(shù)使用User_Context對(duì)象開始一個(gè)新進(jìn)程。6)“src/GeekOS/kthread.c”文件中主要是實(shí)現(xiàn)用戶程序要求內(nèi)核進(jìn)行服務(wù)的一些系統(tǒng)調(diào)用函數(shù)定義。要求用戶實(shí)現(xiàn)的有Sys_Exit()函數(shù)、Sys_PrintString()函數(shù)、Sys_GetKey()、Sys_SetAttr()、Sys_GetCursor()、Sys_PutCursor()、Sys_Spawn()函數(shù)、Sys_Wait()函數(shù)和Sys_GetPID()函數(shù)。7)在main.c文件中改寫生成第一個(gè)用戶態(tài)進(jìn)程的函數(shù)調(diào)用:Spawn_Init_Process(void)。5)“src/GeekOS/kthread.c”文件中的St621、

GeekOS進(jìn)程狀態(tài)及轉(zhuǎn)換

三、項(xiàng)目設(shè)計(jì)提示currentrunwait出現(xiàn)需要等待的事件等待的事件發(fā)生調(diào)度時(shí)間片到等圖5.1GeekOS進(jìn)程狀態(tài)轉(zhuǎn)換GeekOS系統(tǒng)最早創(chuàng)建的內(nèi)核進(jìn)程有Idle、Reaper和Main三個(gè)進(jìn)程,它們由Init_Scheduler函數(shù)創(chuàng)建:最先初始化一個(gè)核態(tài)進(jìn)程mainThread,并將該進(jìn)程作為當(dāng)前運(yùn)行進(jìn)程,函數(shù)最后還調(diào)用Start_Kernel_Thread函數(shù)創(chuàng)建了兩個(gè)系統(tǒng)進(jìn)程Idle和Reaper。所以,Idle、Reaper和Main三個(gè)進(jìn)程是系統(tǒng)中最早存在的進(jìn)程。新建1、GeekOS進(jìn)程狀態(tài)及轉(zhuǎn)換三、項(xiàng)目設(shè)計(jì)提示curre63GeekOS的內(nèi)核進(jìn)程對(duì)象

include/kthread.h中定義,具體結(jié)構(gòu)如下:structKernel_Thread{ulong_tesp; //進(jìn)程的內(nèi)核堆棧esp指針volatileulong_tnumTicks; //計(jì)時(shí)器intpriority; //進(jìn)程優(yōu)先級(jí)DEFINE_LINK(Thread_Queue,Kernel_Thread);//指針指向進(jìn)程隊(duì)列下一進(jìn)程void*stackPage; //內(nèi)核堆棧頁指針structUser_Context*userContext;//用戶進(jìn)程上下文structKernel_Thread*owner; //父進(jìn)程指針intrefCount; //引用計(jì)數(shù)boolalive; //是否活躍structThread_QueuejoinQueue; //加入隊(duì)列intexitCode; //返回代碼intpid; //進(jìn)程IDDEFINE_LINK(All_Thread_List,Kernel_Thread);//全局進(jìn)程鏈表指針#defineMAX_TLOCAL_KEYS128constvoid*tlocalData[MAX_TLOCAL_KEYS]; //本地信息intcurrentReadyQueue; //進(jìn)程當(dāng)前所在的運(yùn)行隊(duì)列的索引編號(hào)boolblocked; //是否被阻塞};GeekOS的內(nèi)核進(jìn)程對(duì)象include/kt642、GeekOS的用戶態(tài)進(jìn)程

在GeekOS中為了區(qū)分用戶態(tài)進(jìn)程和內(nèi)核進(jìn)程,在Kernel_Thread結(jié)構(gòu)體中設(shè)置了一個(gè)字段userContext,指向用戶態(tài)進(jìn)程上下文。對(duì)于內(nèi)核進(jìn)程來說,這個(gè)指針為空,而用戶態(tài)進(jìn)程都擁有自己的用戶上下文(User_Context)。因此,在GeekOS中要判斷一個(gè)進(jìn)程是內(nèi)核進(jìn)程還是用戶態(tài)進(jìn)程,只要通過userContext字段是否為空來判斷就可以了。圖10.1用戶態(tài)進(jìn)程結(jié)構(gòu)2、GeekOS的用戶態(tài)進(jìn)程在GeekOS中為65User_Context結(jié)構(gòu)結(jié)構(gòu)定義如下(在“include/geekos/user.h”中定義):

structUser_Context{

#defineNUM_USER_LDT_ENTRIES3

structSegment_Descriptorldt[NUM_USER_LDT_ENTRIES];//用戶LDT

structSegment_Descriptor*ldtDescriptor;//LDT描述符

char*memory;//指向用戶空間

ulong_tsize;//用戶空間的大小

ushort_tldtSelector;//ldt選擇子

ushort_tcsSelector;//cs選擇子

ushort_tssSelector;//ss選擇子

ushort_tdsSelector;//ds選擇子

pde_t*pageDir; //頁表指針

ulong_tentryAddr; //用戶程序入口地址

ulong_targBlockAddr; //參數(shù)塊地址

ulong_tstackPointerAddr;//用戶態(tài)進(jìn)程的堆棧指針

intrefCount; //引用數(shù)

structFile*fileList[USER_MAX_FILES];//打開文件列表

intfileCount; //打開文件計(jì)數(shù)

};User_Context結(jié)構(gòu)結(jié)構(gòu)定義如下(在“include664、用戶態(tài)進(jìn)程空間

每個(gè)用戶態(tài)進(jìn)程都擁有屬于自己的內(nèi)存段空間,如:代碼段、數(shù)據(jù)段、堆棧段等,每個(gè)段有一個(gè)段描述符(segmentdescriptor),并且每個(gè)進(jìn)程有一個(gè)段描述符表(LocalDescriptorTable),用于保存該進(jìn)程的所有段描述符。操作系統(tǒng)中還設(shè)置一個(gè)全局描述符表(GDT,GlobalDescriptorTable),用于記錄了系統(tǒng)中所有進(jìn)程的ldt描述符。圖10.2GDT、LDT和User_Context的關(guān)系4、用戶態(tài)進(jìn)程空間每個(gè)用戶態(tài)進(jìn)程都擁有屬于自67(1)調(diào)用函數(shù)Allocate_Segment_Descriptor()新建一個(gè)LDT描述符;(2)調(diào)用函數(shù)Selector()新建一個(gè)LDT選擇子;(3)調(diào)用函數(shù)Init_Code_Segment_Descriptor()新建一個(gè)文本段描述符;(4)調(diào)用函數(shù)Init_Data_Segment_Descriptor()新建一個(gè)數(shù)據(jù)段;(5)調(diào)用函數(shù)Selector()新建一個(gè)數(shù)據(jù)段選擇子;(6)調(diào)用函數(shù)Selector()新建一個(gè)文本(可執(zhí)行代碼)段選擇子。5、用戶態(tài)進(jìn)程創(chuàng)建LDT的步驟

(1)調(diào)用函數(shù)Allocate_Segment_Descri683、用戶態(tài)進(jìn)程創(chuàng)建流程Spawn()Read_Fully()Parse_ELF_Excutable()Start_User_Thread()Setup_User_Thread()Load_User_Program()Attach_User_Context()3、用戶態(tài)進(jìn)程創(chuàng)建流程Spawn()Read_Fully694、Spawn函數(shù)的功能intSpawn(constchar*program,constchar*command,structKernel_Thread**pThread)參數(shù)說明:Program對(duì)應(yīng)的是要讀入內(nèi)存緩沖區(qū)的可執(zhí)行文件,Command是用戶執(zhí)行程序執(zhí)行時(shí)的命令行字符串,pThread是存放指向剛創(chuàng)建進(jìn)程的指針。Spawn函數(shù)主要完成的主要功能是:(1)調(diào)用Read_Fully函數(shù)將名為program的可執(zhí)行文件全部讀入內(nèi)存緩沖區(qū)。(2)調(diào)用Parse_ELF_Executable函數(shù),分析ELF格式文件。Parse_ELF_Executable函數(shù)功能在項(xiàng)目1中已經(jīng)實(shí)現(xiàn)。(3)調(diào)用Load_User_Program將可執(zhí)行程序的程序段和數(shù)據(jù)段等裝入內(nèi)存,初始化User_context數(shù)據(jù)結(jié)構(gòu)。(4)調(diào)用Start_User_Thread函數(shù)創(chuàng)建一個(gè)進(jìn)程并使該進(jìn)程進(jìn)入準(zhǔn)備運(yùn)行隊(duì)列。4、Spawn函數(shù)的功能intSpawn(constch705、Load_User_Program函數(shù)Load_User_Program函數(shù)在“/src/geekos/userseg.c”文件中實(shí)現(xiàn),代碼也需要開發(fā)人員自己完成,函數(shù)原型如下:intLoad_User_Program(char*exeFileData,ulong_texeFileLength,structExe_Format*exeFormat,constchar*command,structUser_Context**pUserContext)/*參數(shù)說明:exeFileData——保存在內(nèi)存緩沖中的用戶程序可執(zhí)行文件;exeFileLength——可執(zhí)行文件的長度;exeFormat——調(diào)用Parse_ELF_Executable函數(shù)得到的可執(zhí)行文件格式信息;command——用戶輸入的命令行,包括可執(zhí)行文件的名稱及其他參數(shù);pUserContext——指向User_Conetxt的指針,是本函數(shù)完成用戶上下文初始化的對(duì)象*/5、Load_User_Program函數(shù)Load_Use71Load_User_Program主要實(shí)現(xiàn)功能如下:(1)根據(jù)Parse_ELF_Executable函數(shù)的執(zhí)行結(jié)果Exe_Format中的Exe_Segment結(jié)構(gòu)提供的用戶程序段信息,用戶命令參數(shù)及用戶態(tài)進(jìn)程堆棧大小計(jì)算用戶態(tài)進(jìn)程所需的最大內(nèi)存空間,即要分配給用戶態(tài)進(jìn)程的內(nèi)存空間。(2)為用戶程序分配內(nèi)存空間,并初始化。(3)根據(jù)Exe_Segment提供的用戶段信息初始化代碼段、數(shù)據(jù)段以及堆棧段的段描述符和段選擇子。(4)根據(jù)段信息將用戶程序中的各段內(nèi)容復(fù)制到分配的用戶內(nèi)存空間。(5)根據(jù)Exe_Format結(jié)構(gòu)初始化User_Context結(jié)構(gòu)中的用戶態(tài)進(jìn)程代碼段入口entry字段,并根據(jù)command參數(shù)初始化用戶內(nèi)存空間中的參數(shù)塊。(6)初始化User_Context結(jié)構(gòu)的用戶打開文件列表,并添加標(biāo)準(zhǔn)輸入輸出文件。(7)將初始化完畢的User_Context指針賦予*pUserContext,返回0表示成功。Load_User_Program主要實(shí)現(xiàn)功能如下:72一、項(xiàng)目設(shè)計(jì)目的研究進(jìn)程調(diào)度算法,掌握用信號(hào)量實(shí)現(xiàn)進(jìn)程間同步的方法。為GeekOS擴(kuò)充進(jìn)程調(diào)度算法——基于時(shí)間片輪轉(zhuǎn)的進(jìn)程多級(jí)反饋調(diào)度算法,并能用信號(hào)量實(shí)現(xiàn)進(jìn)程協(xié)作。二、項(xiàng)目設(shè)計(jì)要求(1)實(shí)現(xiàn)src/geekos/syscall.c文件中的Sys_SetSchedulingPolicy系統(tǒng)調(diào)用,它的功能是設(shè)置系統(tǒng)采用的何種進(jìn)程調(diào)度策略;(2)實(shí)現(xiàn)src/geekos/syscall.c文件中的Sys_GetTimeOfDay系統(tǒng)調(diào)用,它的功能是獲取全局變量g_numTicks的值;(3)實(shí)現(xiàn)函數(shù)Change_Scheduling_Policy(),具體實(shí)現(xiàn)不同調(diào)度算法的轉(zhuǎn)換。(4)實(shí)現(xiàn)syscall.c中信號(hào)量有關(guān)的四個(gè)系統(tǒng)調(diào)用:sys_createsemaphore()、sys_P()、sys_V()和sys_destroysemaphore()。第11章設(shè)計(jì)項(xiàng)目3

一、項(xiàng)目設(shè)計(jì)目的第11章設(shè)計(jì)項(xiàng)目3731、多級(jí)反饋隊(duì)列調(diào)度隊(duì)列模型三、項(xiàng)目設(shè)計(jì)提示1、多級(jí)反饋隊(duì)列調(diào)度隊(duì)列模型三、項(xiàng)目設(shè)計(jì)提示742、多級(jí)反饋隊(duì)列與分時(shí)調(diào)度進(jìn)程隊(duì)列的轉(zhuǎn)換

2、多級(jí)反饋隊(duì)列與分時(shí)調(diào)度進(jìn)程隊(duì)列的轉(zhuǎn)換75(1)添加函數(shù)Chang_Scheduling_Policy(intpolicy,intquantum),policy是設(shè)置的調(diào)度策略,quantum是設(shè)置的時(shí)間片。例如policy為1說明設(shè)置的是多級(jí)反饋隊(duì)列調(diào)度算法,此時(shí)若g_SchedPolicy(為系統(tǒng)添加的標(biāo)識(shí)算法的變量,初始化為0)為0,說明當(dāng)前的調(diào)度算法為輪轉(zhuǎn)調(diào)度,要變成MLF就必須把空閑線程放入3隊(duì)列,若g_SchedPolicy為1,說明當(dāng)前是多級(jí)反饋隊(duì)列調(diào)度算法,則返回。如果policy為0,則說明設(shè)置的是輪轉(zhuǎn)調(diào)度,此時(shí)若g_SchedPolicy為1,則必須把4個(gè)隊(duì)列變成一個(gè)隊(duì)列,即所有的線程都在隊(duì)列0上了。若g_SchedPolicy為0,則返回。3、函數(shù)設(shè)計(jì)提示(1)添加函數(shù)Chang_Scheduling_Policy76(2)在系統(tǒng)調(diào)用Sys_GetTimeOfDay()中,只需要返回g_numTicks就可以了。在Sys_SetSchedulingPolicy()中,如果state->ebx是1,則設(shè)置的是MLF算法,調(diào)用Change_Scheduling_Policy(SCHED_RR,quantum),為0則是RR算法,調(diào)用Change_Scheduling_Policy(SCHED_MLF,quantum)。如果state->ebx為其他值,則返回-1。(3)在Init_Thread()中都是把隊(duì)列放在0隊(duì)列上的,并且blocked變量為false。(4)在Get_Next_Runnable()中,從最高級(jí)的隊(duì)列開始,調(diào)用Find_Best()來找線程優(yōu)先級(jí)最大的線程,直到在某級(jí)隊(duì)列中找到符合條件可以運(yùn)行的線程。(5)在Wait()函數(shù)中,線程被阻塞,所以blocked變量被設(shè)置為true,并且如果是MLF算法,則該進(jìn)程的currentReadyQueue加一,下次運(yùn)行的時(shí)候進(jìn)入高一級(jí)的線程隊(duì)列。(2)在系統(tǒng)調(diào)用Sys_GetTimeOfDay()中,只需77GveekOS定義了信號(hào)量的結(jié)構(gòu)體:structSemaphore{intsemaphoreID;/*信號(hào)量的ID*/char*semaphoreName;/*信號(hào)量的名字*/intvalue;/*信號(hào)量的值*/intregisteredThreadCount;/*注冊(cè)該信號(hào)量的線程數(shù)量*/structKernel_Thread*registeredThreads[MAX_REGISTERED_THREADS];/*注冊(cè)的線程*/structThread_QueuewaitingThreads;/*等待該信號(hào)的線程隊(duì)列*/DEFINE_LINK(Semaphore_List,Semaphore);/*連接信號(hào)鏈表的域*/}4、信號(hào)量定義

GveekOS定義了信號(hào)量的結(jié)構(gòu)體:4、信號(hào)量定義78信號(hào)量操作:Semaphore_Create()Semaphore_Acquire(P操作)Semaphore_Release(V操作)Semaphore_Destroy()Create_Semaphore()函數(shù)首先檢查請(qǐng)求創(chuàng)建的這個(gè)信號(hào)量的名字是否存在,如果存在,那么就把這個(gè)線程加入到這個(gè)信號(hào)量所注冊(cè)的線程鏈表上;如果不存在,則分配內(nèi)存給新的信號(hào)量,清空它的線程隊(duì)列,把當(dāng)前的這個(gè)線程加入到它的線程隊(duì)列中,設(shè)置注冊(cè)線程數(shù)量為1,初始化信號(hào)量的名字,值和信號(hào)量的ID,并把這個(gè)信號(hào)量添加到信號(hào)量鏈表上,最后返回信號(hào)量的ID。5、信號(hào)量PV操作

信號(hào)量操作:5、信號(hào)量PV操作79P操作Semaphore_Acquire()中,首先檢查傳入的信號(hào)量ID是否存在,如果存在,接著檢查當(dāng)前線程是否注冊(cè)使用了這個(gè)信號(hào)量,如果這兩項(xiàng)檢查任意一項(xiàng)失敗了,那么就返回-1。如果成功了,就把信號(hào)量的值減去1,如果減去1后信號(hào)量的值小于0,那么就把當(dāng)前線程放入這個(gè)信號(hào)量的等待隊(duì)列上。V操作Semaphore_Release()中,首先也是檢查傳入的信號(hào)量ID是否存在,如果存在,接著檢查當(dāng)前線程是否注冊(cè)使用了這個(gè)信號(hào)量,如果這兩項(xiàng)檢查任意一項(xiàng)失敗了,那么就返回-1。如果成功了,那就把信號(hào)量的值加上1,如果加上1后信號(hào)量的值小于或等于0,則要把該信號(hào)量里等待隊(duì)列上的一個(gè)線程喚醒。Semaphore_Destroy()中,首先也是檢查傳入的信號(hào)量ID是否存在,如果存在,接著檢查當(dāng)前線程是否注冊(cè)使用了這個(gè)信號(hào)量,如果這兩項(xiàng)檢查任意一項(xiàng)失敗了,那么就返回-1。如果成功了,就把該線程從這個(gè)信號(hào)量的注冊(cè)的線程數(shù)組中刪除,并把注冊(cè)的線程數(shù)量減去1。如果這個(gè)信號(hào)量的注冊(cè)線程為0了,則把這個(gè)信號(hào)量從信號(hào)量鏈表中刪除,并釋放它的內(nèi)存。P操作Semaphore_Acquire()中,首先檢查傳入80第12章設(shè)計(jì)項(xiàng)目4

一、項(xiàng)目設(shè)計(jì)目的了解虛擬存儲(chǔ)器管理設(shè)計(jì)原理,掌握請(qǐng)求分頁虛擬存儲(chǔ)管理的具體實(shí)現(xiàn)技術(shù)。二、項(xiàng)目設(shè)計(jì)要求(1)在<src/geekos/paging.c>文件中編寫代碼完成以下函數(shù):Init_VM()(definedin)函數(shù)將建立一個(gè)初始的內(nèi)存頁目錄和頁表,并且安裝一個(gè)頁面出錯(cuò)處理函數(shù)。Init_Paging()函數(shù)(定義在src/geekos/paging.c)初始化操作頁面調(diào)度文件所需的所有數(shù)據(jù)結(jié)構(gòu)。就如前面說到的,Get_Paging_Device()函數(shù)指定分頁調(diào)度文件定位在哪一個(gè)設(shè)備和占用磁盤塊的地址范圍。Find_Space_On_Paging_File()函數(shù)應(yīng)該在分頁調(diào)度文件里面找到一個(gè)空閑的足夠大的頁空間。它將返回這個(gè)大塊的索引,或者當(dāng)沒有合適的空間就返回-1。第12章設(shè)計(jì)項(xiàng)目4一、項(xiàng)目設(shè)計(jì)目的81Free_Space_On_Paging_File()函數(shù)將釋放由Find_Space_On_Paging_File()函數(shù)在分頁調(diào)度文件里所分配的的磁盤塊。Write_To_Paging_File()函數(shù)將把存儲(chǔ)在內(nèi)存的一頁數(shù)據(jù)寫出到分頁調(diào)度文件里。Read_From_Paging_File()函數(shù)將讀取分頁調(diào)度文件里的一頁數(shù)據(jù)到內(nèi)存空間。(2)在<src/geekos/uservm.c>文件中編寫代碼完成以下函數(shù):Destroy_User_Context()釋放進(jìn)程所占用的所有內(nèi)存和其它資源。Load_User_Program()裝載可執(zhí)行文件到內(nèi)存里,創(chuàng)建一個(gè)就緒的用戶地址空間,功能類似于分段系統(tǒng)的實(shí)現(xiàn)。Copy_From_User()從一個(gè)用戶緩沖區(qū)復(fù)制數(shù)據(jù)到一個(gè)內(nèi)核緩沖區(qū)。Copy_To_User()從一個(gè)內(nèi)核緩沖區(qū)復(fù)制數(shù)據(jù)到一個(gè)用戶緩沖區(qū)。Switch_To_Address_Space()利用它裝載相應(yīng)頁目錄和LDT來切換到一個(gè)用戶地址空間。Free_Space_On_Paging_File()函數(shù)將821、地址轉(zhuǎn)換三、項(xiàng)目設(shè)計(jì)提示

1、地址轉(zhuǎn)換三、項(xiàng)目設(shè)計(jì)提示83GeekOS操作系統(tǒng)課程設(shè)計(jì)項(xiàng)目介紹84線性地址到物理地址的轉(zhuǎn)換過程線性地址到物理地址的轉(zhuǎn)換過程852、用戶進(jìn)程的線性地址空間2、用戶進(jìn)程的線性地址空間863、請(qǐng)求分頁系統(tǒng)實(shí)現(xiàn)操作系統(tǒng)將需要在磁盤設(shè)備上創(chuàng)建一個(gè)pagefile文件暫時(shí)保存從內(nèi)存中替換出去的頁,實(shí)現(xiàn)一個(gè)類LRU算法在內(nèi)存中選取一個(gè)替換頁把它寫到磁盤的pagefile文件中。缺頁中斷處理

表12-1缺頁處理表缺頁情況標(biāo)識(shí)相應(yīng)處理堆棧生長到新頁超出原來分配一頁的限制分配一個(gè)新頁進(jìn)程繼續(xù)此頁保存在磁盤上數(shù)據(jù)標(biāo)識(shí)這一頁在pagefile中存在從pagefile讀入需要的頁繼續(xù)因?yàn)闊o效地址缺頁非法地址訪問終止用戶進(jìn)程3、請(qǐng)求分頁系統(tǒng)實(shí)現(xiàn)操作系統(tǒng)將需要在磁盤設(shè)備上創(chuàng)建一個(gè)pag87在“/src/geekos/mem.c”文件中,已經(jīng)定義了一個(gè)函數(shù)Alloc_Pageable_Page實(shí)現(xiàn)交換一頁到磁盤的操作,具體執(zhí)行步驟如下:調(diào)用mem.c文件中已經(jīng)實(shí)現(xiàn)的Find_Page_To_Page_Out函數(shù)來確定要替換的頁(這個(gè)函數(shù)依賴于頁數(shù)據(jù)結(jié)構(gòu)中的clock域)。調(diào)用paging.c文件中已經(jīng)實(shí)現(xiàn)的Find_Space_On_Paging_File函數(shù)在pagefile中找到空閑的存儲(chǔ)空間。調(diào)用paging.c文件中已經(jīng)實(shí)現(xiàn)的Write_To_Paging_File函數(shù)把被替換的頁寫到pagefile文件中。修改頁表的相應(yīng)表項(xiàng),清除頁存在的標(biāo)志,標(biāo)識(shí)為此頁在內(nèi)存為不存在。修改頁表項(xiàng)的頁基地址為包含這一頁的第一個(gè)磁盤塊號(hào)。修改頁表項(xiàng)的kernelInfo位標(biāo)識(shí)為KINFO_PAGE_ON_DISK狀態(tài)(標(biāo)識(shí)這一頁是在磁盤上存在,而不是沒有效)。調(diào)用lowlevel.asm文件中已經(jīng)實(shí)現(xiàn)的Flush_TLB來刷新TLB。在“/src/geekos/mem.c”文件中,已經(jīng)定義了一88

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論