mirror of
https://github.com/CoderSherlock/CoderSherlock.github.io.git
synced 2026-06-12 23:58:11 -07:00
Update post of cs350's lab.
This commit is contained in:
@@ -30,6 +30,7 @@ Remember, it's for helping in learning. DON'T COPY & PASTE CODE!
|
|||||||
## Lab6-7-Scheduling
|
## Lab6-7-Scheduling
|
||||||
|
|
||||||
### First user process in xv6
|
### First user process in xv6
|
||||||
|
#### Kernel works
|
||||||
In xv6, as the same as conventional linux OS, the very first user level process is **init**.
|
In xv6, as the same as conventional linux OS, the very first user level process is **init**.
|
||||||
Before **init**'s running, all the OS bootstraps are happened in a high privileged mode(kernel level).
|
Before **init**'s running, all the OS bootstraps are happened in a high privileged mode(kernel level).
|
||||||
|
|
||||||
@@ -112,10 +113,166 @@ userinit(void)
|
|||||||
p->state = RUNNABLE;
|
p->state = RUNNABLE;
|
||||||
}
|
}
|
||||||
~~~
|
~~~
|
||||||
|
#### Where the user-level code was integrated?
|
||||||
If you search the keyword "_binary_initcode_start" in the source code, you can't find any references.
|
If you search the keyword "_binary_initcode_start" in the source code, you can't find any references.
|
||||||
The clue comes from the *Makefile*.
|
The clue comes from the *Makefile*.
|
||||||
|
|
||||||
|
In the makefile, **initcode** is a prerequisites to compile the kernel image.
|
||||||
|
**Step 1**: Before kernel was compiled, *initcode.S* was first compiled to a runnable binary *initcode*.
|
||||||
|
This binary was very odd because it was not supposed to let any other OS to run it.
|
||||||
|
*Initcode.s* was first compiled without any standard including, and generating the intermediate file *initcode.o*.
|
||||||
|
|
||||||
|
**Step 2**: *Initcode.o* then linked to *Initcode.out* with two uncommon settings.
|
||||||
|
First it specify the entry of this binary file as when "start" symbol points to.
|
||||||
|
This "start" symbol was declared in the assembly code.
|
||||||
|
Second it specify a absolute address(0) for the text segments.
|
||||||
|
By doing this, text segments will be placed at the start of the binary file (except the header of the ELF)[^ldman].
|
||||||
|
|
||||||
|
**Step 3**: *Initcode.out* is already a minimized binary but it's not enough.
|
||||||
|
That's why when using **objcopy** to copy it to the file *initcode*, it further strip all headers and debug information[^objcopyman].
|
||||||
|
At this point, we have a minimal binary file *initcode*.
|
||||||
|
From the first byte of this file, it's only includes runnable instructions.
|
||||||
|
And the size of the file is only 44 bytes.
|
||||||
|
~~~bash
|
||||||
|
initcode: initcode.S
|
||||||
|
$(CC) $(CFLAGS) -nostdinc -I. -c initcode.S # Step 1
|
||||||
|
$(LD) $(LDFLAGS) -N -e start -Ttext 0 -o initcode.out initcode.o # Step 2
|
||||||
|
$(OBJCOPY) -S -O binary initcode.out initcode # Step 3
|
||||||
|
$(OBJDUMP) -S initcode.o > initcode.asm
|
||||||
|
~~~
|
||||||
|
|
||||||
|
This binary later were appended to the kernel using following commands.
|
||||||
|
And during this appending, 3 symbols were generated and added to the symbol table of the *kernel*[^ldman].
|
||||||
|
**"_binary_initcode_start"** contains the address of where the initcode segment was appended to.
|
||||||
|
**"_binary_initcode_end"** contains the address of where the initcode segment was ended at.
|
||||||
|
**"_binary_initcode_size"** is a \*ABS\* type symbol with value 0x2C(45) that specify the size of the initcode segment is 45 bytes.
|
||||||
|
~~~bash
|
||||||
|
kernel: $(OBJS) entry.o entryother initcode kernel.ld
|
||||||
|
$(LD) $(LDFLAGS) -T kernel.ld -o kernel entry.o $(OBJS) -b binary initcode entryother # <- This Line
|
||||||
|
$(OBJDUMP) -S kernel > kernel.asm
|
||||||
|
$(OBJDUMP) -t kernel | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > kernel.sym
|
||||||
|
~~~
|
||||||
|
**In short summary**,
|
||||||
|
using objdump, we can verify that source code *initcode.S* has been compiled and loaded into the kernel.
|
||||||
|
Also the segment of initcode's instructions was located by the pointer "_binary_initcode_start".
|
||||||
|
That's explain when calling ***inituvm(p->pgdir, _binary_initcode_start, (int)_binary_initcode_size);***,
|
||||||
|
functionalities implemented in initcode.S will be loaded into the runtime of the first process within xv6.
|
||||||
|
~~~bash
|
||||||
|
# Header of the file kernel
|
||||||
|
kernel: file format elf32-i386
|
||||||
|
kernel
|
||||||
|
architecture: i386, flags 0x00000112:
|
||||||
|
EXEC_P, HAS_SYMS, D_PAGED
|
||||||
|
start address 0x0010000c
|
||||||
|
|
||||||
|
Program Header:
|
||||||
|
LOAD off 0x00001000 vaddr 0x80100000 paddr 0x00100000 align 2**12
|
||||||
|
filesz 0x00008c6a memsz 0x00008c6a flags r-x
|
||||||
|
...
|
||||||
|
Sections:
|
||||||
|
Idx Name Size VMA LMA File off Algn
|
||||||
|
0 .text 00008586 80100000 00100000 00001000 2**2
|
||||||
|
CONTENTS, ALLOC, LOAD, READONLY, CODE
|
||||||
|
...
|
||||||
|
SYMBOL TABLE:
|
||||||
|
...
|
||||||
|
8010b50c g .data 00000000 _binary_initcode_end
|
||||||
|
...
|
||||||
|
8010b4e0 g .data 00000000 _binary_initcode_start
|
||||||
|
...
|
||||||
|
0000002c g *ABS* 00000000 _binary_initcode_size
|
||||||
|
...
|
||||||
|
~~~
|
||||||
|
|
||||||
|
#### User-level code
|
||||||
|
|
||||||
|
Take a look of content in the *initcode.S*, you will find the code can explain itself well.
|
||||||
|
There are no other jobs but just calling system call **exec** to run a user-level binary **"init"**.
|
||||||
|
|
||||||
|
*Initcode.S*:
|
||||||
|
~~~bash
|
||||||
|
# Initial process execs /init.
|
||||||
|
|
||||||
|
#include "syscall.h"
|
||||||
|
#include "traps.h"
|
||||||
|
|
||||||
|
|
||||||
|
# exec(init, argv)
|
||||||
|
.globl start
|
||||||
|
start:
|
||||||
|
pushl $argv
|
||||||
|
pushl $init
|
||||||
|
pushl $0 // where caller pc would be
|
||||||
|
movl $SYS_exec, %eax
|
||||||
|
int $T_SYSCALL
|
||||||
|
|
||||||
|
# for(;;) exit();
|
||||||
|
exit:
|
||||||
|
movl $SYS_exit, %eax
|
||||||
|
int $T_SYSCALL
|
||||||
|
jmp exit
|
||||||
|
|
||||||
|
# char init[] = "/init\0";
|
||||||
|
init:
|
||||||
|
.string "/init\0"
|
||||||
|
|
||||||
|
# char *argv[] = { init, 0 };
|
||||||
|
.p2align 2
|
||||||
|
argv:
|
||||||
|
.long init
|
||||||
|
.long 0
|
||||||
|
~~~
|
||||||
|
|
||||||
|
The **"init"** mentioned above is not a pure user-level binary executable that compiled from the source code *init.c*.
|
||||||
|
Within *init.c*, a file named *console* will be created at the runtime for saving standard outputs and errors.
|
||||||
|
Then it will forked a child process(the second user process), and let it run program **"sh"**.
|
||||||
|
|
||||||
|
**"sh"** is the xv6's default shell, a user-level program that generated from source *sh.c*.
|
||||||
|
After the shell boots up, you can interactive with the xv6.
|
||||||
|
This's how first process (and second process) was started in the xv6.
|
||||||
|
|
||||||
|
*init.c*:
|
||||||
|
~~~c
|
||||||
|
// init: The initial user-level program
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "stat.h"
|
||||||
|
#include "user.h"
|
||||||
|
#include "fcntl.h"
|
||||||
|
|
||||||
|
char *argv[] = { "sh", 0 };
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
int pid, wpid;
|
||||||
|
|
||||||
|
if(open("console", O_RDWR) < 0){
|
||||||
|
mknod("console", 1, 1);
|
||||||
|
open("console", O_RDWR);
|
||||||
|
}
|
||||||
|
dup(0); // stdout
|
||||||
|
dup(0); // stderr
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
printf(1, "init: starting sh\n");
|
||||||
|
pid = fork();
|
||||||
|
if(pid < 0){
|
||||||
|
printf(1, "init: fork failed\n");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
if(pid == 0){
|
||||||
|
exec("sh", argv);
|
||||||
|
printf(1, "init: exec sh failed\n");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
while((wpid=wait()) >= 0 && wpid != pid)
|
||||||
|
printf(1, "zombie!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~~~
|
||||||
|
|
||||||
|
[^ldman]: [ld\(1\) - Linux man page](https://linux.die.net/man/1/ld)
|
||||||
|
[^objcopyman]: [3 objcopy - binutils mannual](https://sourceware.org/binutils/docs/binutils/objcopy.html)
|
||||||
|
|
||||||
|
### Xv6's round robin schduler
|
||||||
+166
-2
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user