Due February 25, 2003 (9:00 AM)
Elf Header
|
Program Header (Text segment)
|
Program Header (Data segment)
|
….
|
Program Instructions
|
Program Initialized Data
|
Field
|
Description
|
Ident
|
String
to identify what’s in the file
|
Phoff
|
Offset
of first program header
|
Phnum
|
Number
of program headers
|
Entry
|
Address
of first instruction in program
|
Field
|
|
Offset
|
Offset of region within file
|
Vaddr
|
Address for start of region
|
MemSize
|
Length of region
|
This figure shows how the memory of a program is returned from loadFile
and how you need to manipulate it to create a user process in memory.
The other step in creating a user program is to compile it and store it onto the file system that the kernel can read. Since your operating system is not yet ready to run the compiler, you will use a “cross compiler” to create the files and store them into the file system before booting the operating system. The directory UserProgs contains a couple of test programs, and a makefile that will load them into the file system (really the file called hd.img).
To create a user mode you will write the function Create_User_Process (struct *User_Program).. It will create a new user mode process, setup the stack as well as the text and data segments for the process.
To create a user mode process, you will also need
to set up various types of data structures that describe the memory and
privilege level associated with your new process. The steps required are:
1) Create an LDT descriptor by calling the routine Allocate_Segment_Descriptor()2) Create an LDT selector by calling the routine Selector()3) Create a text segment descriptor by calling Init_Code_Segment_Descriptor4) Create a data segment descriptor by calling Init_Data_Segment_Descriptor5) Create an data segment selector by calling the routine Selector()6) Create an text segment selector by calling the routine Selector()
Stack Data Selector (data Slector)
|
Stack Pointer (end of data memory)
|
Eflags
|
Text Selector (text Selector)
|
Program Counter (entry Addr)
|
Error Code (0)
|
Interrupt Number (0)
|
General Purpose Registers
|
Ds (data Selector)
|
Es (data Selector)
|
Fs (data Selector)
|
Ga (data Selector)
|
Name
|
Call #
|
Kernel Function
|
User Space Function
|
SYS_NULL
|
0
|
Sys_Null
|
int Null( void );
|
SYS_EXIT
|
1
|
Sys_Exit
|
void Exit( void );
|
SYS_PRINTSTRING
|
2
|
Sys_Print_String
|
int Print_String( const char* message);
|
SYS_GETKEY
|
3
|
Sys_Get_Key
|
Keycode Get_Key( void )
|
SYS_SPAWN
|
4
|
Sys_Spawn_Program
|
int Spawn_Program(char* program );
|
SYS_WAIT
|
5
|
Sys_Wait
|
int Wait( unsigned int pid );
|
As discussed in class, the way a user program makes a system call is to trap into the operating system. To make this process a bit easer for user programs, you will write a library (called libuser.c) that will implement that user space functions listed in the table above. Each function implementation will make an appropriate trap into the operating system. Inside the operating system kernel, you will extend the function Syscall_Handler to call the various Sys_XXX kernel functions listed in the table depending on the system call number. The signature (parameters and return values) of the Sys_XXX calls should be the same as their corresponding user space function.
The Sys_Exit call should terminate the user mode process that calls it.The Sys_Print_String call should print the passed string to the screen. The Sys_Get_Key call should block the process until a key has been pressed, and then return the key that was pressed. If two processes call this system call at once, only one should get the character (which ones doesn’t matter). The Sys_Spawn_Program call creates a new user process running the program that is passed as its first paramter. The return value from this call should the process id of the new processes created, or –1 if it was not possible to create the process. The Sys_Wait system call should block the calling process until the process id that is passed as the first parameter has exited.
To pass data from user mode to kernel mode you will need to copy memory from user space to kernel space as part of your system call handler. Likewise if you wish to transfer data from the kernel back to user mode you will need to copy the memory.
Ide.{c,h} IDE Device Driver Pfat.c pseudoFAT filesystem code Elf.h interface to read a program from a file User.h start of a user program context UserProgs a directory of user programs