-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathlab5-File system, Spawn and Shell.html
1025 lines (734 loc) · 68.3 KB
/
lab5-File system, Spawn and Shell.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE HTML>
<html lang="" >
<head>
<meta charset="UTF-8">
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<title>Lab5: File system, Spawn and Shell · GitBook</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="description" content="">
<meta name="generator" content="GitBook 3.2.3">
<link rel="stylesheet" href="gitbook/style.css">
<link rel="stylesheet" href="gitbook/gitbook-plugin-intopic-toc/style.css">
<link rel="stylesheet" href="gitbook/gitbook-plugin-search-pro/search.css">
<link rel="stylesheet" href="gitbook/gitbook-plugin-splitter/splitter.css">
<link rel="stylesheet" href="gitbook/gitbook-plugin-highlight/website.css">
<link rel="stylesheet" href="gitbook/gitbook-plugin-fontsettings/website.css">
<link rel="stylesheet" href="gitbook/gitbook-plugin-theme-comscore/test.css">
<meta name="HandheldFriendly" content="true"/>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link rel="apple-touch-icon-precomposed" sizes="152x152" href="gitbook/images/apple-touch-icon-precomposed-152.png">
<link rel="shortcut icon" href="gitbook/images/favicon.ico" type="image/x-icon">
<link rel="next" href="lab6-Network Driver.html" />
<link rel="prev" href="lab4-Preemptive Multitasking.html" />
</head>
<body>
<div class="book">
<div class="book-summary">
<div id="book-search-input" role="search">
<input type="text" placeholder="Type to search" />
</div>
<nav role="navigation">
<ul class="summary">
<li class="chapter " data-level="1.1" data-path="./">
<a href="./">
序言
</a>
</li>
<li class="chapter " data-level="1.2" data-path="introduction.html">
<a href="introduction.html">
introduction
</a>
</li>
<li class="chapter " data-level="1.3" data-path="preparation.html">
<a href="preparation.html">
准备工作
</a>
</li>
<li class="chapter " data-level="1.4" >
<span>
JOS
</span>
<ul class="articles">
<li class="chapter " data-level="1.4.1" data-path="lab1-Booting a PC.html">
<a href="lab1-Booting a PC.html">
Lab1: Booting a PC
</a>
</li>
<li class="chapter " data-level="1.4.2" data-path="lab2-Memory Management.html">
<a href="lab2-Memory Management.html">
Lab2: Memory Management
</a>
</li>
<li class="chapter " data-level="1.4.3" data-path="Lab3-User Environments.html">
<a href="Lab3-User Environments.html">
Lab3: User Environments
</a>
</li>
<li class="chapter " data-level="1.4.4" data-path="lab4-Preemptive Multitasking.html">
<a href="lab4-Preemptive Multitasking.html">
Lab4: Preemptive Multitasking
</a>
</li>
<li class="chapter active" data-level="1.4.5" data-path="lab5-File system, Spawn and Shell.html">
<a href="lab5-File system, Spawn and Shell.html">
Lab5: File system, Spawn and Shell
</a>
</li>
<li class="chapter " data-level="1.4.6" data-path="lab6-Network Driver.html">
<a href="lab6-Network Driver.html">
Lab6: Network Driver
</a>
</li>
</ul>
</li>
<li class="chapter " data-level="1.5" >
<span>
xv6
</span>
<ul class="articles">
<li class="chapter " data-level="1.5.1" data-path="hw-boot xv6.html">
<a href="hw-boot xv6.html">
boot xv6
</a>
</li>
<li class="chapter " data-level="1.5.2" data-path="hw-syscall.html">
<a href="hw-syscall.html">
syscall
</a>
</li>
<li class="chapter " data-level="1.5.3" data-path="hw-alarmtest.html">
<a href="hw-alarmtest.html">
alarmtest
</a>
</li>
</ul>
</li>
<li class="divider"></li>
<li>
<a href="https://www.gitbook.com" target="blank" class="gitbook-link">
Published with GitBook
</a>
</li>
</ul>
</nav>
</div>
<div class="book-body">
<div class="body-inner">
<div class="book-header" role="navigation">
<!-- Title -->
<h1>
<i class="fa fa-circle-o-notch fa-spin"></i>
<a href="." >Lab5: File system, Spawn and Shell</a>
</h1>
</div>
<div class="page-wrapper" tabindex="-1" role="main">
<div class="page-inner">
<div id="book-search-results">
<div class="search-noresults">
<section class="normal markdown-section">
<h2 id="lab-5-file-system-spawn-and-shell">Lab 5: File system, Spawn and Shell</h2>
<p><img src="lab5-File system, Spawn and Shell/Lab 5 File system Spawn and Shell.png" alt=""></p>
<p>系统中的spawn功能(fork+exec,主要是exec需要加载硬盘中的二进制文件)和console功能(调用相关的功能时要么是遍历文件系统,要么也是加载相应的二进制文件。重定向、管道等特性也是文件系统的特性)都需要文件系统的支持。</p>
<h3 id="file-system-preliminaries">File system preliminaries</h3>
<p>JOS的文件系统基本特征有文件的增删读写,支持文件的结构化。</p>
<p>JOS文件系统仅有单用户,因此不支持多用户的权限管理。同时不支持硬链接,symbolic links, 时间戳和特殊设备的读取。</p>
<h4 id="on-disk-file-system-structure">On-Disk File System Structure</h4>
<p>大多数<code>UNIX</code>文件系统将硬盘划分成两种区域:</p>
<ul>
<li>inode region</li>
<li>data regions</li>
</ul>
<p>每一个文件都会分配一个inode。inode会保存一个文件的重要的元数据,并且指向自己的数据块。</p>
<p>目录含有文件夹的名字和指向inode的指针。</p>
<p>如果一个文件的inode被多个文件目录包含,那么可以说这是文件硬链接。</p>
<p>JOS系统不会支持硬链接,并且JOS不支持inode的管理。JOS仅仅通过简单的保存一个文件或者目录的元数据,从而达到索引的目的(后面有图进行详细的说明)</p>
<p>JOS允许用户态的程序读取目录的元数据,因此实现ls功能将是轻而易举的事情。这样做的缺点是应用程序文件格式需要依赖JOS目录元数据的格式,使得兼容性变得特别的差。(相当于是固定的简陋格式很难允许其他格式的程序进行运行,而inode有更好调节的灵活性)</p>
<h5 id="sectors-and-blocks">Sectors and Blocks</h5>
<p>硬盘的基本单位是sector = 512Bytes, JOS读取的基本单位是block = 4096Bytes。</p>
<h5 id="superblocks">Superblocks</h5>
<p>superblock保存了文件系统总共有多少的block和根目录位置,索引其他文件夹或者文件的指针。</p>
<p>一般保存在block 1。之所以没保存在block 0是预留位置给boot loader和partition table。</p>
<p>许多系统中保存着多个superblock,因此当其中的一个块损坏后,其他的仍然能够保持整个文件系统正常的运转。</p>
<h5 id="file-meta-data">File Meta-data</h5>
<p>JOS将文件的元数据通过mmap进行分配:</p>
<pre><code class="lang-c"><span class="hljs-keyword">if</span> ((diskmap = mmap(<span class="hljs-literal">NULL</span>, nblocks * BLKSIZE, PROT_READ|PROT_WRITE,
MAP_SHARED, diskfd, <span class="hljs-number">0</span>)) == MAP_FAILED)
panic(<span class="hljs-string">"mmap %s: %s"</span>, name, strerror(errno));
</code></pre>
<p>只用记住分配了一块内存给了File 结构体元数据,使得之后能够进行指针的操作。</p>
<p>JOS有10个直接访问块和1个间接访问块,总共能够管理的数据大小为(10+1024)*4KB 约等于4MB。</p>
<p>如果想要支持更大文件的管理,则需要2个间接或者3次间接寻址的方式(xv6中就支持这种操作)。</p>
<p><img src="lab5-File system, Spawn and Shell/file.png" alt=""></p>
<p>其中管理文件数据的元数据File是通过mmap进行分配的。</p>
<h5 id="directories-versus-regular-files">Directories versus Regular Files</h5>
<p>文件夹和普通的文件通过元数据<code>type</code>进行区分,JOS都是通过File指针保存到元数据中,从而进行结构的索引的。</p>
<p><img src="lab5-File system, Spawn and Shell/open.png" alt=""></p>
<p>若想找到某个文件或者文件夹,那么就去遍历10个direct block和1024个indirect block。通过比对路径的类型和文件名,从而确定是否找到并返回。其中每一个block中保存的都是struct File,如下图所示:</p>
<p><img src="lab5-File system, Spawn and Shell/filename.png" alt=""></p>
<p>若文件的类型是文件,而不是文件夹,那么每一个索引的数据项10+1024=1034项中保存的都是<strong>硬盘的块号</strong>。(可以在<code>file_block_walk</code>和<code>file_get_block</code>中的函数逻辑知道)</p>
<h3 id="the-file-system">The File System</h3>
<p>这一部分的实验并不需要我们去实现一个文件系统,但是我们需要对实现提供的一些文件的操作函数比较的熟悉。本实验新增代码约有5k行。</p>
<h4 id="disk-access">Disk Access</h4>
<p>JOS使用 IDE disk driver去访问硬盘数据。我们需要修改相应的文件服务进程的权限,从而使得只有该进程能够获取硬盘的数据。</p>
<p>通过polling和programmed I/O,我们就可以在用户态实现磁盘数据的读取。当然我们可以基于中断来实现该功能,但是这相对而言比较的难。</p>
<p>x86通过%eflags中的IOPL位来判断保护模式下的代码能否使用特殊的设备I/O指令如<code>IN</code>和<code>out</code>。</p>
<p>在JOS中,我们希望仅有file system environment(文件服务系统)有上面设备I/O的权限,其他的进程统统都没有该权限。</p>
<h5 id="exercise-1">exercise 1</h5>
<blockquote>
<p>i386_init中,通过<code>ENV_TYPE_FS</code>判断是否是文件服务系统进程,之后给操作文件的特权。</p>
</blockquote>
<p>首先我们在创建进程的时候,带有进程的种类:</p>
<pre><code class="lang-c">ENV_CREATE(fs_fs, ENV_TYPE_FS);
</code></pre>
<p>由于文件服务系统的特殊性,要在初始化eflags寄存器的时候进行判断,代码如下:</p>
<pre><code class="lang-c"><span class="hljs-keyword">if</span> (type == ENV_TYPE_FS) {
newenv->env_tf.tf_eflags |= FL_IOPL_MASK;
}
</code></pre>
<h5 id="question-1">question 1</h5>
<blockquote>
<p>怎么保证进程切换,这样的 device I/O priviledge能够保持?</p>
</blockquote>
<p>因为该权限保存在进程的帧中,当陷入其他进程时,都会弹出相应进程当时寄存器的值,而不会错误的使用文件服务系统特有的寄存器值。如何保存栈帧和弹出栈帧,我们在之前的实验中就已经详细的阐述了。</p>
<p>注意本实验fs.img我们设置的是disk 1, boot loader设置的disk 0。</p>
<h4 id="the-block-cache">The Block Cache</h4>
<p>通过系统的虚拟内存管理,我们实现一个简单的文件的buffer cache。</p>
<p>我们的文件系统会映射到[DISKMAP, DIAKMAP+DISKMAX] = [0X10000000, 0xD0000000] = 3G大小。</p>
<p>并且这一部分会映射到文件服务系统的页目录和页表中。但是这样的作法在目前的操作系统中并不正确,因为磁盘的大小动辄上T。</p>
<p>如果将磁盘的整个内容移动到内存中,那么代价将是非常大的。因此,我们借鉴lab4中的思想,先做映射,当发生缺页中断了,那么再进行相应的映射。</p>
<h5 id="exercise-2">exercise 2</h5>
<blockquote>
<p>实现<code>fs/bc.c</code>中的<code>bc_pgfault</code>和<code>flush_block</code>函数。</p>
<p>实现<code>bc_pgfault</code>时注意下面的事项:</p>
<ul>
<li>addr可能不是和一个block对齐的</li>
<li>ide_read操作的单位是sectors(512Bytes),而不是block(4096Bytes)。</li>
</ul>
<p>如果某页没有被映射或者不为脏,那么flush_block不干任何事情。</p>
<p>其中脏位(PTE_D)是由硬件进行设置的,并且保存在uvpt中。<code>flush_block</code>使用sys_page_map来清除<code>PTE_D</code>位。</p>
</blockquote>
<p><code>fs_init</code>中有着如何使用block cache的例子。</p>
<p>当block cache初始化完后(实际上仅仅是设置了一个bc_pgfault的处理函数),当我们访问相关的内容时,如果内容不在内存中,那么就会触发缺页中断。但是整个过程就像是内容就在内存中一样。</p>
<pre><code class="lang-c">static void
bc_pgfault(struct UTrapframe *utf)
{
void *addr = (void *) utf->utf_fault_va;
uint32_t blockno = ((uint32_t)addr - DISKMAP) / BLKSIZE;
int r;
// Check that the fault was within the block cache region
if (addr < (void*)DISKMAP || addr >= (void*)(DISKMAP + DISKSIZE))
panic("page fault in FS: eip %08x, va %08x, err %04x",
utf->utf_eip, addr, utf->utf_err);
// Sanity check the block number.
if (super && blockno >= super->s_nblocks)
panic("reading non-existent block %08x\n", blockno);
// Allocate a page in the disk map region, read the contents
// of the block from the disk into that page.
// Hint: first round addr to page boundary. fs/ide.c has code to read
// the disk.
//
// LAB 5: you code here:
// envid 传入 0表示当前进程。
addr =(void *) ROUNDDOWN(addr, PGSIZE);
if ( (r = sys_page_alloc(0, addr, PTE_P|PTE_W|PTE_U)) < 0) {
panic("in bc_pgfault, sys_page_alloc: %e", r);
}
// size_t secno = (addr - DISKMAP) / BLKSIZE;
if ( (r = ide_read(blockno*BLKSECTS, addr, BLKSECTS)) < 0) {
panic("in bc_pgfault, ide_read: %e",r);
}
// Clear the dirty bit for the disk block page since we just read the
// block from disk
// 清除脏位
if ((r = sys_page_map(0, addr, 0, addr, uvpt[PGNUM(addr)] & PTE_SYSCALL)) < 0)
panic("in bc_pgfault, sys_page_map: %e", r);
// Check that the block we read was allocated. (exercise for
// the reader: why do we do this *after* reading the block
// in?)
if (bitmap && block_is_free(blockno))
panic("reading free block %08x\n", blockno);
}
</code></pre>
<pre><code class="lang-c"><span class="hljs-comment">// Flush the contents of the block containing VA out to disk if</span>
<span class="hljs-comment">// necessary, then clear the PTE_D bit using sys_page_map.</span>
<span class="hljs-comment">// If the block is not in the block cache or is not dirty, does</span>
<span class="hljs-comment">// nothing.</span>
<span class="hljs-comment">// Hint: Use va_is_mapped, va_is_dirty, and ide_write.</span>
<span class="hljs-comment">// Hint: Use the PTE_SYSCALL constant when calling sys_page_map.</span>
<span class="hljs-comment">// Hint: Don't forget to round addr down.</span>
<span class="hljs-function"><span class="hljs-keyword">void</span>
<span class="hljs-title">flush_block</span><span class="hljs-params">(<span class="hljs-keyword">void</span> *addr)</span>
</span>{
<span class="hljs-keyword">uint32_t</span> blockno = ((<span class="hljs-keyword">uint32_t</span>)addr - DISKMAP) / BLKSIZE;
<span class="hljs-keyword">if</span> (addr < (<span class="hljs-keyword">void</span>*)DISKMAP || addr >= (<span class="hljs-keyword">void</span>*)(DISKMAP + DISKSIZE))
panic(<span class="hljs-string">"flush_block of bad va %08x"</span>, addr);
<span class="hljs-comment">// LAB 5: Your code here.</span>
addr = (<span class="hljs-keyword">void</span> *)ROUNDDOWN(addr, PGSIZE);
<span class="hljs-keyword">if</span> (va_is_mapped(addr) && va_is_dirty(addr)) {
ide_write(blockno*BLKSECTS, addr , BLKSECTS);
<span class="hljs-keyword">int</span> r;
<span class="hljs-comment">// Clear the dirty bit for the disk block page since we just read the</span>
<span class="hljs-comment">// block from disk </span>
<span class="hljs-comment">//下面的语句就是为了清空脏位</span>
<span class="hljs-keyword">if</span> ((r = sys_page_map(<span class="hljs-number">0</span>, addr, <span class="hljs-number">0</span>, addr, uvpt[PGNUM(addr)] & PTE_SYSCALL)) < <span class="hljs-number">0</span>)
panic(<span class="hljs-string">"in flush_block, sys_page_map: %e"</span>, r);
}
<span class="hljs-comment">//panic("flush_block not implemented");</span>
}
</code></pre>
<h4 id="the-block-bitmap">The Block Bitmap</h4>
<p>我们可以使用bitmap来记录硬盘块的使用情况。每一位都能记录一个块是否被使用。bitmap大小为4096Bytes=4096<em>8bits,那么一共管理$4096 </em> 8 * 4KB = 128MB$反正目前是够用的。</p>
<h4 id="exercise-3">exercise 3</h4>
<blockquote>
<p>使用free_block为模板,来实现<code>fs/fs.c</code>中的<code>alloc_block</code>函数。</p>
<p>我们需要找到第一个没有使用的硬盘块,将其标记被使用,并且返回序号</p>
<p>注意当我们改变了bitmap时,应该将其立刻写回硬盘中,以此来保证文件系统的一致性。</p>
</blockquote>
<pre><code class="lang-c"><span class="hljs-comment">// Search the bitmap for a free block and allocate it. When you</span>
<span class="hljs-comment">// allocate a block, immediately flush the changed bitmap block</span>
<span class="hljs-comment">// to disk.</span>
<span class="hljs-comment">//</span>
<span class="hljs-comment">// Return block number allocated on success,</span>
<span class="hljs-comment">// -E_NO_DISK if we are out of blocks.</span>
<span class="hljs-comment">//</span>
<span class="hljs-comment">// Hint: use free_block as an example for manipulating the bitmap.</span>
<span class="hljs-keyword">uint32_t</span> *bitmap; <span class="hljs-comment">// bitmap blocks mapped in memory</span>
<span class="hljs-function"><span class="hljs-keyword">int</span>
<span class="hljs-title">alloc_block</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span>
</span>{
<span class="hljs-comment">// The bitmap consists of one or more blocks. A single bitmap block</span>
<span class="hljs-comment">// contains the in-use bits for BLKBITSIZE blocks. There are</span>
<span class="hljs-comment">// super->s_nblocks blocks in the disk altogether.</span>
<span class="hljs-comment">// LAB 5: Your code here.</span>
<span class="hljs-keyword">size_t</span> i;
<span class="hljs-comment">//bitmap 1表示是空闲的,0表示的是占用的</span>
<span class="hljs-keyword">for</span>(i=<span class="hljs-number">1</span>; i < super->s_nblocks; i++) {
<span class="hljs-keyword">if</span> (block_is_free(i)) {
bitmap[i/<span class="hljs-number">32</span>] &= ~(<span class="hljs-number">1</span><<(i%<span class="hljs-number">32</span>));
flush_block(&bitmap[i/<span class="hljs-number">32</span>]);<span class="hljs-comment">//将bitmap在硬盘中刷新</span>
<span class="hljs-keyword">return</span> i;
}
}
<span class="hljs-comment">//panic("alloc_block not implemented");</span>
<span class="hljs-keyword">return</span> -E_NO_DISK;
}
</code></pre>
<h4 id="file-operations">File Operations</h4>
<p>熟读<code>fs/fs.c</code>中的代码,有较为熟悉的了解。</p>
<h4 id="exercise-4">exercise 4</h4>
<blockquote>
<p>实现<code>file_block_walk</code>和<code>file_get_block</code>。</p>
</blockquote>
<p>file_block_walk就是不断递归,寻找绝对路径中的文件夹和文件,而file_get_block就是获得文件块中具体的块号。</p>
<p>下面是寻找某个文件过程的示意图:</p>
<p><img src="lab5-File system, Spawn and Shell/filename.png" alt=""></p>
<pre><code class="lang-c"><span class="hljs-comment">// Find the disk block number slot for the 'filebno'th block in file 'f'.</span>
<span class="hljs-comment">// Set '*ppdiskbno' to point to that slot.</span>
<span class="hljs-comment">// The slot will be one of the f->f_direct[] entries,</span>
<span class="hljs-comment">// or an entry in the indirect block.</span>
<span class="hljs-comment">// When 'alloc' is set, this function will allocate an indirect block</span>
<span class="hljs-comment">// if necessary.</span>
<span class="hljs-comment">//</span>
<span class="hljs-comment">// Returns:</span>
<span class="hljs-comment">// 0 on success (but note that *ppdiskbno might equal 0).</span>
<span class="hljs-comment">// -E_NOT_FOUND if the function needed to allocate an indirect block, but</span>
<span class="hljs-comment">// alloc was 0.</span>
<span class="hljs-comment">// -E_NO_DISK if there's no space on the disk for an indirect block.</span>
<span class="hljs-comment">// -E_INVAL if filebno is out of range (it's >= NDIRECT + NINDIRECT).</span>
<span class="hljs-comment">//</span>
<span class="hljs-comment">// Analogy: This is like pgdir_walk for files.</span>
<span class="hljs-comment">// Hint: Don't forget to clear any block you allocate.</span>
<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span>
<span class="hljs-title">file_block_walk</span><span class="hljs-params">(<span class="hljs-keyword">struct</span> File *f, uint32_t filebno, uint32_t **ppdiskbno, <span class="hljs-keyword">bool</span> alloc)</span>
</span>{
<span class="hljs-keyword">int</span> r;
<span class="hljs-keyword">if</span> (filebno >= NDIRECT + NINDIRECT)
<span class="hljs-keyword">return</span> -E_INVAL;
<span class="hljs-keyword">if</span> (filebno < NDIRECT) {
<span class="hljs-keyword">if</span> (ppdiskbno)
*ppdiskbno = f->f_direct + filebno;
<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
<span class="hljs-keyword">if</span> (!alloc && !f->f_indirect)
<span class="hljs-keyword">return</span> -E_NOT_FOUND;
<span class="hljs-comment">//间接寻找</span>
<span class="hljs-keyword">if</span> (!f->f_indirect) {
<span class="hljs-keyword">if</span> ((r = alloc_block()) < <span class="hljs-number">0</span>)
<span class="hljs-keyword">return</span> -E_NO_DISK;
f->f_indirect = r;
<span class="hljs-built_in">memset</span>(diskaddr(r), <span class="hljs-number">0</span>, BLKSIZE);
flush_block(diskaddr(r));
}
<span class="hljs-comment">//这里保存的是硬盘块号,有点不理解</span>
<span class="hljs-keyword">if</span> (ppdiskbno)
*ppdiskbno = (<span class="hljs-keyword">uint32_t</span>*)(diskaddr(f->f_indirect)) + filebno - NDIRECT;
<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<pre><code class="lang-c"><span class="hljs-comment">// Set *blk to the address in memory where the filebno'th</span>
<span class="hljs-comment">// block of file 'f' would be mapped.</span>
<span class="hljs-comment">//</span>
<span class="hljs-comment">// Returns 0 on success, < 0 on error. Errors are:</span>
<span class="hljs-comment">// -E_NO_DISK if a block needed to be allocated but the disk is full.</span>
<span class="hljs-comment">// -E_INVAL if filebno is out of range.</span>
<span class="hljs-comment">//</span>
<span class="hljs-comment">// Hint: Use file_block_walk and alloc_block.</span>
<span class="hljs-function"><span class="hljs-keyword">int</span>
<span class="hljs-title">file_get_block</span><span class="hljs-params">(<span class="hljs-keyword">struct</span> File *f, uint32_t filebno, <span class="hljs-keyword">char</span> **blk)</span>
</span>{
<span class="hljs-comment">// LAB 5: Your code here.</span>
<span class="hljs-keyword">int</span> r;
<span class="hljs-keyword">uint32_t</span> *ppdiskbno;
<span class="hljs-keyword">if</span> ((r = file_block_walk(f, filebno, &ppdiskbno, <span class="hljs-number">1</span>)) < <span class="hljs-number">0</span>)
<span class="hljs-keyword">return</span> r;
<span class="hljs-keyword">if</span> (*ppdiskbno == <span class="hljs-number">0</span>) {
<span class="hljs-keyword">if</span> ((r = alloc_block()) < <span class="hljs-number">0</span>)
<span class="hljs-keyword">return</span> -E_NO_DISK;
*ppdiskbno = r;
<span class="hljs-built_in">memset</span>(diskaddr(r), <span class="hljs-number">0</span>, BLKSIZE);
flush_block(diskaddr(r));
}
*blk = diskaddr(*ppdiskbno);
<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<p><code>file_block_walk</code> and <code>file_get_block</code>是file system的马力。<code>file_read</code>和<code>file_write</code>正是基于上面的两个函数实现调用的。</p>
<h4 id="the-file-system-interface">The file system interface</h4>
<p>JOS将文件功能单独的独立出来一个文件服务进程,并且其他的进程没有权限调用相关的文件操作函数(由于eflags寄存器的限制)。因此,如果其他进程想要对文件进行操作,那么必须和文件系统进程进行通信,通信的结构如下:</p>
<pre><code class="lang-c"> Regular env FS env
+---------------+ +---------------+
| read | | file_read |
| (lib/fd.c) | | (fs/fs.c) |
...|.......|.......|...|.......^.......|...............
| v | | | | RPC mechanism
| devfile_read | | serve_read |
| (lib/file.c) | | (fs/serv.c) |
| | | | ^ |
| v | | | |
| fsipc | | serve |
| (lib/file.c) | | (fs/serv.c) |
| | | | ^ |
| v | | | |
| ipc_send | | ipc_recv |
| | | | ^ |
+-------|-------+ +-------|-------+
| |
+-------------------+
</code></pre>
<h4 id="exercise-5">exercise 5</h4>
<blockquote>
<p>实现/fs/serv.c中的serve_read函数</p>
</blockquote>
<pre><code class="lang-c"><span class="hljs-comment">// Read at most ipc->read.req_n bytes from the current seek position</span>
<span class="hljs-comment">// in ipc->read.req_fileid. Return the bytes read from the file to</span>
<span class="hljs-comment">// the caller in ipc->readRet, then update the seek position. Returns</span>
<span class="hljs-comment">// the number of bytes successfully read, or < 0 on error.</span>
<span class="hljs-function"><span class="hljs-keyword">int</span>
<span class="hljs-title">serve_read</span><span class="hljs-params">(envid_t envid, <span class="hljs-keyword">union</span> Fsipc *ipc)</span>
</span>{
<span class="hljs-keyword">struct</span> Fsreq_read *req = &ipc->read;
<span class="hljs-keyword">struct</span> Fsret_read *ret = &ipc->readRet;
<span class="hljs-keyword">if</span> (debug)
cprintf(<span class="hljs-string">"serve_read %08x %08x %08x\n"</span>, envid, req->req_fileid, req->req_n);
<span class="hljs-comment">// Lab 5: Your code here:</span>
<span class="hljs-keyword">int</span> r;
<span class="hljs-keyword">struct</span> OpenFile *of;
<span class="hljs-keyword">if</span> ( (r = openfile_lookup(envid, req->req_fileid, &of) )< <span class="hljs-number">0</span>)
<span class="hljs-keyword">return</span> r;
<span class="hljs-keyword">if</span> ( (r = file_read(of->o_file, ret->ret_buf, req->req_n, of->o_fd->fd_offset))< <span class="hljs-number">0</span>)
<span class="hljs-keyword">return</span> r;
<span class="hljs-comment">// then update the seek position.</span>
of->o_fd->fd_offset += r;
<span class="hljs-keyword">return</span> r;
}
</code></pre>
<h4 id="exercise-6">exercise 6</h4>
<blockquote>
<p>实现<code>fs/serv.c</code>中的<code>serve_write</code>函数,实现<code>lib/file.c</code>中的<code>devfile_write</code>函数。</p>
</blockquote>
<pre><code class="lang-c"><span class="hljs-comment">// Write req->req_n bytes from req->req_buf to req_fileid, starting at</span>
<span class="hljs-comment">// the current seek position, and update the seek position</span>
<span class="hljs-comment">// accordingly. Extend the file if necessary. Returns the number of</span>
<span class="hljs-comment">// bytes written, or < 0 on error.</span>
<span class="hljs-function"><span class="hljs-keyword">int</span>
<span class="hljs-title">serve_write</span><span class="hljs-params">(envid_t envid, <span class="hljs-keyword">struct</span> Fsreq_write *req)</span>
</span>{
<span class="hljs-keyword">if</span> (debug)
cprintf(<span class="hljs-string">"serve_write %08x %08x %08x\n"</span>, envid, req->req_fileid, req->req_n);
<span class="hljs-comment">// LAB 5: Your code here.</span>
<span class="hljs-keyword">int</span> r;
<span class="hljs-keyword">struct</span> OpenFile *of;
<span class="hljs-keyword">int</span> reqn;
<span class="hljs-keyword">if</span> ( (r = openfile_lookup(envid, req->req_fileid, &of)) < <span class="hljs-number">0</span>)
<span class="hljs-keyword">return</span> r;
reqn = req->req_n > PGSIZE? PGSIZE:req->req_n;
<span class="hljs-keyword">if</span> ( (r = file_write(of->o_file, req->req_buf, reqn, of->o_fd->fd_offset)) < <span class="hljs-number">0</span>)
<span class="hljs-keyword">return</span> r;
of->o_fd->fd_offset += r;
<span class="hljs-keyword">return</span> r;
<span class="hljs-comment">//panic("serve_write not implemented");</span>
}
</code></pre>
<p><code>devfile_write</code>函数:</p>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">static</span> ssize_t
<span class="hljs-title">devfile_write</span><span class="hljs-params">(<span class="hljs-keyword">struct</span> Fd *fd, <span class="hljs-keyword">const</span> <span class="hljs-keyword">void</span> *buf, size_t n)</span>
</span>{
<span class="hljs-comment">// Make an FSREQ_WRITE request to the file system server. Be</span>
<span class="hljs-comment">// careful: fsipcbuf.write.req_buf is only so large, but</span>
<span class="hljs-comment">// remember that write is always allowed to write *fewer*</span>
<span class="hljs-comment">// bytes than requested.</span>
<span class="hljs-comment">// LAB 5: Your code here</span>
<span class="hljs-keyword">int</span> r;
<span class="hljs-keyword">if</span> (n > <span class="hljs-keyword">sizeof</span>(fsipcbuf.write.req_buf))
n = <span class="hljs-keyword">sizeof</span>(fsipcbuf.write.req_buf);
fsipcbuf.write.req_fileid = fd->fd_file.id;
fsipcbuf.write.req_n = n;
memmove(fsipcbuf.write.req_buf, buf, n);
<span class="hljs-keyword">if</span> ((r = fsipc(FSREQ_WRITE, <span class="hljs-literal">NULL</span>)) < <span class="hljs-number">0</span>)
<span class="hljs-keyword">return</span> r;
<span class="hljs-keyword">return</span> r;
<span class="hljs-comment">//panic("devfile_write not implemented");</span>
}
</code></pre>
<h3 id="spawning-processes">Spawning Processes</h3>
<p>spawn = fork + exec</p>
<h4 id="exercise-7">exercise 7</h4>
<blockquote>
<p>实现kern/syscall.c中的<code>sys_env_set_trapframe</code>。</p>
</blockquote>
<pre><code class="lang-c"><span class="hljs-comment">// Set envid's trap frame to 'tf'.</span>
<span class="hljs-comment">// tf is modified to make sure that user environments always run at code</span>
<span class="hljs-comment">// protection level 3 (CPL 3), interrupts enabled, and IOPL of 0.</span>
<span class="hljs-comment">//</span>
<span class="hljs-comment">// Returns 0 on success, < 0 on error. Errors are:</span>
<span class="hljs-comment">// -E_BAD_ENV if environment envid doesn't currently exist,</span>
<span class="hljs-comment">// or the caller doesn't have permission to change envid.</span>
<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span>
<span class="hljs-title">sys_env_set_trapframe</span><span class="hljs-params">(envid_t envid, <span class="hljs-keyword">struct</span> Trapframe *tf)</span>
</span>{
<span class="hljs-comment">// LAB 5: Your code here.</span>
<span class="hljs-comment">// Remember to check whether the user has supplied us with a good</span>
<span class="hljs-comment">// address!</span>
<span class="hljs-keyword">struct</span> Env *env;
<span class="hljs-keyword">int</span> r;
<span class="hljs-keyword">if</span> ( (r = envid2env(envid, &env, <span class="hljs-number">1</span>)) < <span class="hljs-number">0</span>)
<span class="hljs-keyword">return</span> r;
<span class="hljs-comment">// 什么时候会出现没有权限访问的问题?</span>
user_mem_assert(env, tf, <span class="hljs-keyword">sizeof</span>(<span class="hljs-keyword">struct</span> Trapframe), PTE_U);
<span class="hljs-comment">// 直接整个结构体也是可以赋值的</span>
env->env_tf = *tf;
env->env_tf.tf_cs |= <span class="hljs-number">0x3</span>;
env->env_tf.tf_eflags &= (~FL_IOPL_MASK);
env->env_tf.tf_eflags |= FL_IF;
<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
<span class="hljs-comment">//panic("sys_env_set_trapframe not implemented");</span>
}
</code></pre>
<h4 id="sharing-library-state-across-fork-and-spawn">Sharing library state across fork and spawn</h4>
<p>分享的部分其实就是为了能够进行内存的共享,从而能够进行内容的互换与通信。</p>
<p>之前所有做的父进程与子进程之间内存都是共享读的,一旦某一个进程改变了其中的内容,那么父进程和子进程分享读的内容就分道扬镳了。</p>
<p>为了能够实现页的共享,JOS做了下面的设计与规定:</p>
<p>新增符号位<code>PTE_SHARE</code>,使得有该标记的页能够被共享。</p>
<h4 id="exercise-8">exercise 8</h4>
<blockquote>
<p>更改<code>lib/fork.c</code>中<code>duppage</code>函数的实现,如果页有<code>PTE_SHARE</code>标记位,那么直接进行copy。</p>
<p>同理,实现<code>lib/spawn.c</code>中的<code>copy_shared_pages</code>函数,它会将目前进程中所有的页表遍历一遍,然后copy那么标有<code>PTE_SHARE</code>的页。</p>
</blockquote>
<pre><code class="lang-c"><span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span>
<span class="hljs-title">duppage</span><span class="hljs-params">(envid_t envid, <span class="hljs-keyword">unsigned</span> pn)</span>
</span>{
<span class="hljs-keyword">int</span> r;
<span class="hljs-comment">// LAB 4: Your code here.</span>
<span class="hljs-keyword">int</span> ret;
<span class="hljs-keyword">void</span> *addr = (<span class="hljs-keyword">void</span> *)(pn * PGSIZE);
<span class="hljs-comment">// 新增的分支判断</span>
<span class="hljs-keyword">if</span> (uvpt[pn] & PTE_SHARE) {
<span class="hljs-keyword">if</span>((ret = sys_page_map(<span class="hljs-number">0</span>, addr, envid, addr, uvpt[pn] & PTE_SYSCALL)) <<span class="hljs-number">0</span> )
<span class="hljs-keyword">return</span> ret;
}
<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>((uvpt[pn] & PTE_W) || (uvpt[pn] & PTE_COW)){
<span class="hljs-keyword">if</span>(sys_page_map(<span class="hljs-number">0</span>, addr, envid, addr, PTE_U | PTE_COW | PTE_P) < <span class="hljs-number">0</span>)
panic(<span class="hljs-string">"duppage: parent->child sys_page_map failed."</span>);
<span class="hljs-keyword">if</span>(sys_page_map(<span class="hljs-number">0</span>, addr, <span class="hljs-number">0</span>, addr, PTE_U | PTE_COW | PTE_P) < <span class="hljs-number">0</span>)
panic(<span class="hljs-string">"duppage: self sys_page_map failed."</span>);
} <span class="hljs-keyword">else</span> {
<span class="hljs-keyword">if</span>(sys_page_map(<span class="hljs-number">0</span>, addr, envid, addr, PTE_P | PTE_U) < <span class="hljs-number">0</span>)
panic(<span class="hljs-string">"duppage: single sys_page_map failed."</span>);
}
<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<pre><code class="lang-c"><span class="hljs-comment">// Copy the mappings for shared pages into the child address space.</span>
<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span>
<span class="hljs-title">copy_shared_pages</span><span class="hljs-params">(envid_t child)</span>
</span>{
<span class="hljs-comment">// LAB 5: Your code here.</span>
<span class="hljs-keyword">size_t</span> pn;
<span class="hljs-keyword">int</span> r;
<span class="hljs-keyword">struct</span> Env *e;
<span class="hljs-keyword">for</span> (pn = PGNUM(UTEXT); pn < PGNUM(USTACKTOP); ++pn) {
<span class="hljs-keyword">if</span> ( (uvpd[pn >> <span class="hljs-number">10</span>] & PTE_P) && (uvpt[pn] & PTE_P) ) {
<span class="hljs-keyword">if</span> (uvpt[pn] & PTE_SHARE) {
<span class="hljs-keyword">if</span> ( (r = sys_page_map(thisenv->env_id, (<span class="hljs-keyword">void</span> *)(pn*PGSIZE), child, (<span class="hljs-keyword">void</span> *)(pn*PGSIZE), uvpt[pn] & PTE_SYSCALL )) < <span class="hljs-number">0</span>)
<span class="hljs-keyword">return</span> r;
}
}
}
<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
}
</code></pre>
<h4 id="pipe的本质">pipe的本质</h4>
<p>在JOS中,pipe本质上就是一段父进程和子进程共享的一段内存。很多的示意图会将管道画成一个队列的形式,其实并不正确,下面通过pipe的初始化和使用,对pipe的原理进行说明。</p>
<p>一般父进程和子进程进行通信,假设子进程读,父进程写,那么一般的套路为:</p>
<pre><code class="lang-c"><span class="hljs-keyword">char</span> *msg = <span class="hljs-string">"Now is the time for all good men to come to the aid of their party."</span>;
<span class="hljs-keyword">char</span> buf[<span class="hljs-number">100</span>];
<span class="hljs-keyword">int</span> p[<span class="hljs-number">2</span>];
pipe(p);
<span class="hljs-keyword">int</span> pid = fork();
<span class="hljs-keyword">if</span>(pid == <span class="hljs-number">0</span>){
<span class="hljs-comment">//子进程程序</span>
close(p[<span class="hljs-number">1</span>]);
i = readn(p[<span class="hljs-number">0</span>], buf, <span class="hljs-keyword">sizeof</span> buf<span class="hljs-number">-1</span>);
<span class="hljs-built_in">exit</span>();
}
<span class="hljs-keyword">else</span>{
<span class="hljs-comment">//父进程程序</span>
close(p[<span class="hljs-number">0</span>]);
i = write(p[<span class="hljs-number">1</span>], msg, <span class="hljs-built_in">strlen</span>(msg));
close(p[<span class="hljs-number">1</span>]);
}
wait(pid);
</code></pre>
<p>pipe读写的过程:写和读操作都是在<strong>同一个内存块</strong>的。</p>
<pre><code class="lang-c"><span class="hljs-keyword">if</span> ((r = sys_page_map(<span class="hljs-number">0</span>, va, <span class="hljs-number">0</span>, fd2data(fd1), PTE_P|PTE_W|PTE_U|PTE_SHARE)) < <span class="hljs-number">0</span>)
</code></pre>
<p>该语句表示的就是两个fd指向的是同一个虚拟的页面。</p>
<p>close(p[i])实际上是减少该内存页的引用次数。</p>
<p>读是在一个轮询的状态,因此当一个进程完成了写操作,那么就应该立刻close(p[1]),从而能够减少该共享页的引用次数。而读进程一旦知道了所有的写操作都完成后,那么就会结束这个读的操作。如果不及时的关闭写,那么读进程就会进入死循环(写进程是正常结束的)。</p>
<p>同样的,如果写进程写满了pipe buffer,并且检测到没有读管道,那么会立刻停止写的操作。</p>
<p><img src="lab5-File system, Spawn and Shell/fs.png" alt=""></p>
<p>上图是整个文件系统大概的工作流程,fd实际上是dev(即硬盘)、管道和console的抽象。在lab6中也是socket的抽象。</p>
<p>我们特意简化其中的一些要素。</p>
<p>下面是整个pipe工作的原理图:</p>
<p><img src="lab5-File system, Spawn and Shell/pipe.png" alt=""></p>
<p>fd0(读操作),fd1(写操作)都指向了同样的一块虚拟地址空间,这个空间就是pipe。其中<code>p_rpos</code>是读指针,<code>p_wpos</code>是写指针,它们共同的数据区域为<code>p_buf</code>。</p>
<p>当某个进程写完了,应该及时的关闭管道,这样才能够及时的通知读进程,告诉它读完就可以结束了。</p>
<pre><code class="lang-c">ret = pageref(fd) == pageref(p);
</code></pre>
<p>这个语句中,当写进程在写的时候,<code>pageref(fd) < pageref(p)</code>,一旦close(fd[i]),相关的pageref(p)就会减少。注意p只有一个,而fd有两个fd0和fd1。</p>
<p>知道了上面的原理,我们修改上面的代码:</p>
<pre><code class="lang-c">
<span class="hljs-keyword">if</span>(pid == <span class="hljs-number">0</span>){
<span class="hljs-comment">//子进程程序</span>
close(p[<span class="hljs-number">1</span>]);
i = readn(p[<span class="hljs-number">0</span>], buf, <span class="hljs-keyword">sizeof</span> buf<span class="hljs-number">-1</span>);
<span class="hljs-built_in">exit</span>();
}
<span class="hljs-keyword">else</span>{
<span class="hljs-comment">//父进程程序</span>
<span class="hljs-comment">//close(p[0]); //仅仅把这个注释了</span>
i = write(p[<span class="hljs-number">1</span>], msg, <span class="hljs-built_in">strlen</span>(msg));
close(p[<span class="hljs-number">1</span>]);
}
wait(pid);
</code></pre>
<p>这样也是对的。</p>
<p>一开始pipe()+fork(),使得pageref(p)=4, pageref(fd0)=2, pageref(fd1)=2。</p>
<p>我们只要保证写进程写完后pageref(fd1) = 0就能保证程序的正确的运行,而不会使得读进程陷入死循环。</p>
<h3 id="the-keyboard-interface">The keyboard interface</h3>
<p>这一部分的实现和在monitor中的输入不太一样,这一部分是在用户态的程序进行输入的接受。</p>
<h4 id="exercise-9">exercise 9</h4>
<blockquote>
<p>In your <code>kern/trap.c</code>, call <code>kbd_intr</code> to handle trap <code>IRQ_OFFSET+IRQ_KBD</code> and <code>serial_intr</code> to handle trap <code>IRQ_OFFSET+IRQ_SERIAL</code>.</p>
</blockquote>
<pre><code class="lang-c"><span class="hljs-comment">// Handle keyboard and serial interrupts.</span>
<span class="hljs-comment">// LAB 5: Your code here.</span>
<span class="hljs-keyword">if</span> (tf->tf_trapno == IRQ_OFFSET + IRQ_KBD) {
kbd_intr();
<span class="hljs-keyword">return</span>;
}
<span class="hljs-keyword">if</span> (tf->tf_trapno == IRQ_OFFSET + IRQ_SERIAL) {
serial_intr();
<span class="hljs-keyword">return</span>;
}
</code></pre>
<h3 id="the-shell">The Shell</h3>
<p>运行<code>make run-icode</code>或者运行<code>make run-icode-nox</code>,使得能够通过键盘输入运行简单的应用程序。</p>
<h4 id="exercise-10">exercise 10</h4>
<blockquote>
<p>进行相关的实现,使得该程序支持输入的重定向,支持<code>sh <script</code>操作。</p>
</blockquote>
<p>解析读入<code><</code>后面的文件,然后将该文件作为运行程序的输入即可。</p>
<pre><code class="lang-c"><span class="hljs-keyword">case</span> <span class="hljs-string">'<'</span>: <span class="hljs-comment">// Input redirection</span>
<span class="hljs-comment">// Grab the filename from the argument list</span>
<span class="hljs-keyword">if</span> (gettoken(<span class="hljs-number">0</span>, &t) != <span class="hljs-string">'w'</span>) {
cprintf(<span class="hljs-string">"syntax error: < not followed by word\n"</span>);
<span class="hljs-built_in">exit</span>();
}
<span class="hljs-comment">// Open 't' for reading as file descriptor 0</span>
<span class="hljs-comment">// (which environments use as standard input).</span>
<span class="hljs-comment">// We can't open a file onto a particular descriptor,</span>
<span class="hljs-comment">// so open the file as 'fd',</span>
<span class="hljs-comment">// then check whether 'fd' is 0.</span>
<span class="hljs-comment">// If not, dup 'fd' onto file descriptor 0,</span>
<span class="hljs-comment">// then close the original 'fd'.</span>
<span class="hljs-comment">// LAB 5: Your code here.</span>
<span class="hljs-keyword">if</span> ( (fd = open(t, O_RDONLY) )< <span class="hljs-number">0</span> ) {
<span class="hljs-built_in">fprintf</span>(<span class="hljs-number">2</span>,<span class="hljs-string">"file %s is no exist\n"</span>, t);
<span class="hljs-built_in">exit</span>();
}
<span class="hljs-keyword">if</span> (fd != <span class="hljs-number">0</span>) {
dup(fd, <span class="hljs-number">0</span>);
close(fd);
}
<span class="hljs-keyword">break</span>;
<span class="hljs-comment">//panic("< redirection not implemented");</span>
</code></pre>
<p>最后的结果:</p>
<p><img src="lab5-File system, Spawn and Shell/result.png" alt=""></p>
</section>
</div>
<div class="search-results">
<div class="has-results">
<h1 class="search-results-title"><span class='search-results-count'></span> results matching "<span class='search-query'></span>"</h1>
<ul class="search-results-list"></ul>
</div>
<div class="no-results">
<h1 class="search-results-title">No results matching "<span class='search-query'></span>"</h1>
</div>
</div>
</div>
</div>
</div>
</div>
<a href="lab4-Preemptive Multitasking.html" class="navigation navigation-prev " aria-label="Previous page: Lab4: Preemptive Multitasking">
<i class="fa fa-angle-left"></i>
</a>
<a href="lab6-Network Driver.html" class="navigation navigation-next " aria-label="Next page: Lab6: Network Driver">
<i class="fa fa-angle-right"></i>
</a>
</div>
<script>
var gitbook = gitbook || [];
gitbook.push(function() {
gitbook.page.hasChanged({"page":{"title":"Lab5: File system, Spawn and Shell","level":"1.4.5","depth":2,"next":{"title":"Lab6: Network Driver","level":"1.4.6","depth":2,"path":"lab6-Network Driver.md","ref":"./lab6-Network Driver.md","articles":[]},"previous":{"title":"Lab4: Preemptive Multitasking","level":"1.4.4","depth":2,"path":"lab4-Preemptive Multitasking.md","ref":"./lab4-Preemptive Multitasking.md","articles":[]},"dir":"ltr"},"config":{"gitbook":"*","theme":"default","variables":{},"plugins":["callouts@git+https://github.com/Simran-B/gitbook-plugin-callouts.git","intopic-toc","theme-comscore","-lunr","-search","search-pro","github","splitter","-sharing","mathjax-pro"],"pluginsConfig":{"callouts":{"showTypeInHeader":true},"github":{"url":"https://github.com/KnowledgeHive/ddia"},"intopic-toc":{"isCollapsed":false,"isScrollspyActive":true,"label":{"de":"导航","en":"导航","ch":"导航"},"maxDepth":6,"mode":"nested","selector":".markdown-section h1, .markdown-section h2, .markdown-section h3, .markdown-section h4, .markdown-section h5, .markdown-section h6","visible":true},"splitter":{},"search-pro":{},"fontsettings":{"theme":"white","family":"sans","size":2},"highlight":{},"theme-comscore":{},"mathjax-pro":{"forceSVG":false,"version":"2.7.7"},"theme-default":{"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"showLevel":false}},"structure":{"langs":"LANGS.md","readme":"README.md","glossary":"GLOSSARY.md","summary":"SUMMARY.md"},"pdf":{"pageNumbers":true,"fontSize":12,"fontFamily":"Arial","paperSize":"a4","chapterMark":"pagebreak","pageBreaksBefore":"/","margin":{"right":62,"left":62,"top":56,"bottom":56}},"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"}},"file":{"path":"lab5-File system, Spawn and Shell.md","mtime":"2021-02-19T16:35:01.847Z","type":"markdown"},"gitbook":{"version":"3.2.3","time":"2021-02-21T03:30:06.713Z"},"basePath":".","book":{"language":""}});
});
</script>
</div>
<script src="gitbook/gitbook.js"></script>
<script src="gitbook/theme.js"></script>
<script src="gitbook/gitbook-plugin-intopic-toc/anchor.min.js"></script>
<script src="gitbook/gitbook-plugin-intopic-toc/gumshoe.polyfills.min.js"></script>
<script src="gitbook/gitbook-plugin-intopic-toc/plugin.js"></script>
<script src="gitbook/gitbook-plugin-search-pro/jquery.mark.min.js"></script>
<script src="gitbook/gitbook-plugin-search-pro/search.js"></script>
<script src="gitbook/gitbook-plugin-github/plugin.js"></script>