【操作系统·Operating System】操作系统


6.828

两个神级教学项目: nand2tetris 与 MIT6.828
class : MIT 6.828
refers: inline assembly | I/O Ports | 8086寄存器略解 | x86-64架构寄存器详解
notes: [MIT] 6.828 操作系统工程导读 | MIT6.828-神级OS课程

Lab1

Exercise 2: BIOS
make gdb
[root@VM-0-8-centos lab]# make gdb
The target architecture is assumed to be i8086
[f000:fff0]    0xffff0: ljmp   $0xf000,$0xe05b
0x0000fff0 in ?? ()
+ symbol-file obj/kern/kernel
(gdb) si
[f000:e05b]    0xfe05b: cmpl   $0x0,%cs:0x6ac8
0x0000e05b in ?? ()
(gdb) si
[f000:e062]    0xfe062: jne    0xfd2e1
0x0000e062 in ?? ()
(gdb) si
[f000:e066]    0xfe066: xor    %dx,%dx
0x0000e066 in ?? ()
(gdb) si
[f000:e068]    0xfe068: mov    %dx,%ss
0x0000e068 in ?? ()
(gdb) si
[f000:e06a]    0xfe06a: mov    $0x7000,%esp
0x0000e06a in ?? ()
(gdb) si
[f000:e070]    0xfe070: mov    $0xf34c2,%edx
0x0000e070 in ?? ()
(gdb) si
[f000:e076]    0xfe076: jmp    0xfd15c
0x0000e076 in ?? ()
(gdb) si
[f000:d15c]    0xfd15c: mov    %eax,%ecx
0x0000d15c in ?? ()
(gdb) si
[f000:d15f]    0xfd15f: cli
0x0000d15f in ?? ()
(gdb) si
[f000:d160]    0xfd160: cld
0x0000d160 in ?? ()
(gdb) si
[f000:d161]    0xfd161: mov    $0x8f,%eax
0x0000d161 in ?? ()
(gdb) si
[f000:d167]    0xfd167: out    %al,$0x70    //屏蔽NMI中断信号
0x0000d167 in ?? ()
(gdb) si
[f000:d169]    0xfd169: in     $0x71,%al
0x0000d169 in ?? ()
(gdb) si
[f000:d16b]    0xfd16b: in     $0x92,%al
0x0000d16b in ?? ()
(gdb) si
[f000:d16d]    0xfd16d: or     $0x2,%al
0x0000d16d in ?? ()
(gdb) si
[f000:d16f]    0xfd16f: out    %al,$0x92    //开启A20地址线
0x0000d16f in ?? ()
(gdb) si
[f000:d171]    0xfd171: lidtw  %cs:0x6ab8    //设置中断描述表
0x0000d171 in ?? ()
(gdb) si
[f000:d177]    0xfd177: lgdtw  %cs:0x6a74    //设置全局描述表
0x0000d177 in ?? ()
(gdb) si
[f000:d17d]    0xfd17d: mov    %cr0,%eax    //CPU控制寄存器cr0
0x0000d17d in ?? ()
(gdb) si
[f000:d180]    0xfd180: or     $0x1,%eax
0x0000d180 in ?? ()
(gdb) si
[f000:d184]    0xfd184: mov    %eax,%cr0    //PE位置1,保护模式
0x0000d184 in ?? ()
(gdb) si
[f000:d187]    0xfd187: ljmpl  $0x8,$0xfd18f
0x0000d187 in ?? ()
(gdb) si
The target architecture is assumed to be i386
=> 0xfd18f:     mov    $0x10,%eax
0x000fd18f in ?? ()
(gdb) si
=> 0xfd194:     mov    %eax,%ds
0x000fd194 in ?? ()
(gdb) si
=> 0xfd196:     mov    %eax,%es
0x000fd196 in ?? ()
(gdb) si
=> 0xfd198:     mov    %eax,%ss
0x000fd198 in ?? ()
(gdb) si
=> 0xfd19a:     mov    %eax,%fs
0x000fd19a in ?? ()
(gdb) si
=> 0xfd19c:     mov    %eax,%gs
0x000fd19c in ?? ()
(gdb) si
=> 0xfd19e:     mov    %ecx,%eax
0x000fd19e in ?? ()
(gdb) si
=> 0xfd1a0:     jmp    *%edx
0x000fd1a0 in ?? ()
(gdb) si
=> 0xf34c2:     push   %ebx
0x000f34c2 in ?? ()
(gdb) si
=> 0xf34c3:     sub    $0x2c,%esp
0x000f34c3 in ?? ()
(gdb) si
=> 0xf34c6:     movl   $0xf5b5c,0x4(%esp)
0x000f34c6 in ?? ()
(gdb) si
=> 0xf34ce:     movl   $0xf447b,(%esp)
0x000f34ce in ?? ()
(gdb) si
=> 0xf34d5:     call   0xf099e
0x000f34d5 in ?? ()
(gdb) si
=> 0xf099e:     lea    0x8(%esp),%ecx
0x000f099e in ?? ()
(gdb) si
=> 0xf09a2:     mov    0x4(%esp),%edx
0x000f09a2 in ?? ()
(gdb) si
=> 0xf09a6:     mov    $0xf5b58,%eax
0x000f09a6 in ?? ()
(gdb) si
=> 0xf09ab:     call   0xf0574
0x000f09ab in ?? ()
(gdb) si
=> 0xf0574:     push   %ebp
0x000f0574 in ?? ()
(gdb) si
=> 0xf0575:     push   %edi
0x000f0575 in ?? ()
(gdb) si
=> 0xf0576:     push   %esi
0x000f0576 in ?? ()
(gdb) si
=> 0xf0577:     push   %ebx
0x000f0577 in ?? ()
(gdb) si
=> 0xf0578:     sub    $0xc,%esp
0x000f0578 in ?? ()
(gdb) si
=> 0xf057b:     mov    %eax,0x4(%esp)
0x000f057b in ?? ()
(gdb) si
=> 0xf057f:     mov    %edx,%ebp
0x000f057f in ?? ()
(gdb) si
=> 0xf0581:     mov    %ecx,%esi
0x000f0581 in ?? ()
Ecercise 3: the Boot Loader
questions
  • At what point does the processor start executing 32-bit code? What exactly causes the switch from 16- to 32-bit mode?

ljmp $PROT_MODE_CSEG, $protcseg
设置了A20地址线

  • What is the last instruction of the boot loader executed, and what is the first instruction of the kernel it just loaded?

boot/main.c中 ELFHDR->e_entry 0x7d61

  • Where is the first instruction of the kernel?

kernel: 0x10018

  • How does the boot loader decide how many sectors it must read in order to fetch the entire kernel from disk? Where does it find this information?

Part 3: The Kernel

我们将会开始稍微细节地研究JOS的内核的最小部分,(而且我们终于即将开始写一些代码)。像bootloader一样,Kernel也从一些汇编代码开始,设置好环境以便C语言可以方便地运行。
使用虚拟内存来位置依赖工作
boot loader的链接地址和加载地址是完美一致的,但kernel的链接地址和加载地址就有分歧了。
操作系统内核通常被在高虚拟地址被链接和运行,例如0xf0100000,这是为了给用户程序留下处理器的低虚拟地址空间来运行。下个lab会更加清晰。
很多机器没有这么多的物理空间,所以不能指望把kernel放在那里。替代地,我们会使用处理器内存管理硬件来讲虚拟地址映射到物理地址。这样,kernel的虚拟地址就足够高而留给用户程序足够地址空间了。kernel被加载到物理空间0x00100000,1MB位置,就在BIOS ROM之上。
现在我们只需要映射4MB的物理地址就足够了。我们通过一个手写的、静态初始化的kern/entrypgdir.c里的页目录和页表来实习。现在,我们不需要理解这些工资的细节,只需了解到这项可以达成的结果。指导kern/entry.S设置CR0_PG标志之后,内存引用才被当作物理地址,而且我们也不会改变这个。一旦CR0_PG被设定,内存引用就是被虚拟内存硬件从虚拟地址翻译到的物理地址了。entrypgdir将0xf0000000到0xf04000000的虚拟地址翻译成0x00000000到0x00400000的物理地址(反之亦然)。任何超出范围的虚拟地址都会造成硬件异常,而且因为我们还没有设置终端处理,进而会造成QEMU抛出机器状态和退出。
Exercise 7:
  • Use QEMU and GDB to trace into the JOS kernel and stop at the movl %eax, %cr0. Examine memory at 0x00100000 and at 0xf0100000. Now, single step over that instruction using the stepi GDB command. Again, examine memory at 0x00100000 and at 0xf0100000. Make sure you understand what just happened.
kernel
=> 0x10001d:    mov    %cr0,%eax
0x0010001d in ?? ()
(gdb) info registers
eax            0x110000 1114112
ecx            0x0      0
edx            0x9d     157
ebx            0x10094  65684
esp            0x7bec   0x7bec
ebp            0x7bf8   0x7bf8
esi            0x10094  65684
edi            0x0      0
eip            0x10001d 0x10001d
eflags         0x46     [ PF ZF ]
cs             0x8      8
ss             0x10     16
ds             0x10     16
es             0x10     16
fs             0x10     16
gs             0x10     16
(gdb) si
=> 0x100020:    or     $0x80010001,%eax
0x00100020 in ?? ()
(gdb) info registers
eax            0x11     17
ecx            0x0      0
edx            0x9d     157
ebx            0x10094  65684
esp            0x7bec   0x7bec
ebp            0x7bf8   0x7bf8
esi            0x10094  65684
edi            0x0      0
eip            0x100020 0x100020
eflags         0x46     [ PF ZF ]
cs             0x8      8
ss             0x10     16
ds             0x10     16
es             0x10     16
fs             0x10     16
gs             0x10     16
(gdb) si
=> 0x100025:    mov    %eax,%cr0
0x00100025 in ?? ()
(gdb) info registers
eax            0x80010011       -2147418095
ecx            0x0      0
edx            0x9d     157
ebx            0x10094  65684
esp            0x7bec   0x7bec
ebp            0x7bf8   0x7bf8
esi            0x10094  65684
edi            0x0      0
eip            0x100025 0x100025
eflags         0x86     [ PF SF ]
cs             0x8      8
ss             0x10     16
ds             0x10     16
es             0x10     16
fs             0x10     16
gs             0x10     16
(gdb) x/8x 0x00100000
0x100000:       0x1badb002      0x00000000      0xe4524ffe      0x7205c766
0x100010:       0x34000004      0x0000b812      0x220f0011      0xc0200fd8
(gdb) x/8x 0xf0100000
0xf0100000 : 0x00000000      0x00000000      0x00000000      0x00000000
0xf0100010 :   0x00000000      0x00000000      0x00000000      0x00000000
(gdb) si
=> 0x100028:    mov    $0xf010002f,%eax
0x00100028 in ?? ()
(gdb) si
=> 0x10002d:    jmp    *%eax
0x0010002d in ?? ()
(gdb) si
=> 0xf010002f :      mov    $0x0,%ebp
relocated () at kern/entry.S:74
74              movl    $0x0,%ebp                       # nuke frame pointer
(gdb) x/8x 0x00100000
0x100000:       0x1badb002      0x00000000      0xe4524ffe      0x7205c766
0x100010:       0x34000004      0x0000b812      0x220f0011      0xc0200fd8
(gdb) x/8x 0xf0100000
0xf0100000 : 0x1badb002      0x00000000      0xe4524ffe      0x7205c766
0xf0100010 :   0x34000004      0x0000b812      0x220f0011      0xc0200fd8

  • What is the first instruction after the new mapping is established that would fail to work properly if the mapping weren't in place? Comment out the movl %eax, %cr0 in kern/entry.S, trace into it, and see if you were right.
    将CR0最高位置1,paging可以了,然后通过*%rax进入0xf010002f。
qemu fatal
[root@VM-0-8-centos lab]# make qemu-gdb
+ as kern/entry.S
+ ld obj/kern/kernel
ld: warning: section `.bss' type changed to PROGBITS
+ mk obj/kern/kernel.img
***
*** Now run 'make gdb'.
***
qemu-system-i386 -drive file=obj/kern/kernel.img,index=0,media=disk,format=raw -serial mon:stdio -gdb tcp::                                                                                                                              25000 -D qemu.log  -S
VNC server running on `::1:5900'
qemu: fatal: Trying to execute code outside RAM or ROM at 0xf010002c

EAX=f010002c EBX=00010094 ECX=00000000 EDX=0000009d
ESI=00010094 EDI=00000000 EBP=00007bf8 ESP=00007bec
EIP=f010002c EFL=00000086 [--S--P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     00007c4c 00000017
IDT=     00000000 000003ff
CR0=00000011 CR2=00000000 CR3=00110000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000084 CCD=80010011 CCO=EFLAGS
EFER=0000000000000000
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000
make: *** [qemu-gdb] Aborted
格式化输出到控制台
在OS kernel中,我们需要自己完成所有类似 printf() 的I/O函数。
通读kern/printf.c, lib/printfmt.c 和 kern/console.c,了解它们之间的关系。之后你会更清晰为什么printfmt.c在于单独的lib目录。
Exercise 8.
  • We have omitted a small fragment of code - the code necessary to print octal numbers using patterns of the form "%o". Find and fill in this code fragment.

Process Management

内存中的进程|操作系统内的进程表示PCB
进程调度

graph LR; A(job queue)-->B(ready queue) A-->C(device queue)

IPC

Memory Management

Storage Management


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM