-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathc18_core.lst
1219 lines (1219 loc) · 89 KB
/
c18_core.lst
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
1 ;代码清单18-1
2 ;文件名:c18_core.asm
3 ;文件说明:保护模式微型核心程序
4 ;创建日期:2021-01-19
5
6 ;以下常量定义部分。内核的大部分内容都应当固定
7 core_code_seg_sel equ 0x38 ;内核代码段选择子
8 core_data_seg_sel equ 0x30 ;内核数据段选择子
9 sys_routine_seg_sel equ 0x28 ;系统公共例程代码段的选择子
10 video_ram_seg_sel equ 0x20 ;视频显示缓冲区的段选择子
11 core_stack_seg_sel equ 0x18 ;内核堆栈段选择子
12 mem_0_4_gb_seg_sel equ 0x08 ;整个0-4GB内存的段的选择子
13 idt_linear_address equ 0x1F000 ;中断描述符表的线性地址
14
15 ;-------------------------------------------------------------------------------
16 ;以下是系统核心的头部,用于加载核心程序
17 00000000 [00000000] core_length dd core_end ;核心程序总长度#00
18
19 00000004 [00000000] sys_routine_seg dd section.sys_routine.start
20 ;系统公用例程段位置#04
21
22 00000008 [00000000] core_data_seg dd section.core_data.start
23 ;核心数据段位置#08
24
25 0000000C [00000000] core_code_seg dd section.core_code.start
26 ;核心代码段位置#0c
27
28
29 00000010 [BA030000] core_entry dd start ;核心代码段入口点#10
30 00000014 3800 dw core_code_seg_sel
31
32 ;===============================================================================
33 [bits 32]
34 ;===============================================================================
35 SECTION sys_routine vstart=0 ;系统公共例程代码段
36 ;-------------------------------------------------------------------------------
37 ;字符串显示例程
38 put_string: ;显示0终止的字符串并移动光标
39 ;输入:DS:EBX=串地址
40 00000000 51 push ecx
41
42 00000001 FA cli
43
44 .getc:
45 00000002 8A0B mov cl,[ebx]
46 00000004 08C9 or cl,cl
47 00000006 7408 jz .exit
48 00000008 E806000000 call put_char
49 0000000D 43 inc ebx
50 0000000E EBF2 jmp .getc
51
52 .exit:
53 00000010 FB sti
54
55 00000011 59 pop ecx
56 00000012 CB retf ;段间返回
57
58 ;-------------------------------------------------------------------------------
59 put_char: ;在当前光标处显示一个字符,并推进
60 ;光标。仅用于段内调用
61 ;输入:CL=字符ASCII码
62 00000013 60 pushad
63
64 ;以下取当前光标位置
65 00000014 66BAD403 mov dx,0x3d4
66 00000018 B00E mov al,0x0e
67 0000001A EE out dx,al
68 0000001B 6642 inc dx ;0x3d5
69 0000001D EC in al,dx ;高字
70 0000001E 88C4 mov ah,al
71
72 00000020 664A dec dx ;0x3d4
73 00000022 B00F mov al,0x0f
74 00000024 EE out dx,al
75 00000025 6642 inc dx ;0x3d5
76 00000027 EC in al,dx ;低字
77 00000028 6689C3 mov bx,ax ;BX=代表光标位置的16位数
78
79 0000002B 80F90D cmp cl,0x0d ;回车符?
80 0000002E 750E jnz .put_0a
81 00000030 6689D8 mov ax,bx
82 00000033 B350 mov bl,80
83 00000035 F6F3 div bl
84 00000037 F6E3 mul bl
85 00000039 6689C3 mov bx,ax
86 0000003C EB65 jmp .set_cursor
87
88 .put_0a:
89 0000003E 80F90A cmp cl,0x0a ;换行符?
90 00000041 7506 jnz .put_other
91 00000043 6683C350 add bx,80
92 00000047 EB15 jmp .roll_screen
93
94 .put_other: ;正常显示字符
95 00000049 06 push es
96 0000004A B820000000 mov eax,video_ram_seg_sel ;0xb8000段的选择子
97 0000004F 8EC0 mov es,eax
98 00000051 66D1E3 shl bx,1
99 00000054 2667880F mov [es:bx],cl
100 00000058 07 pop es
101
102 ;以下将光标位置推进一个字符
103 00000059 66D1EB shr bx,1
104 0000005C 6643 inc bx
105
106 .roll_screen:
107 0000005E 6681FBD007 cmp bx,2000 ;光标超出屏幕?滚屏
108 00000063 7C3E jl .set_cursor
109
110 00000065 6653 push bx ;为了修改原书程序的逻辑问题,新增
111 00000067 1E push ds
112 00000068 06 push es
113 00000069 B820000000 mov eax,video_ram_seg_sel
114 0000006E 8ED8 mov ds,eax
115 00000070 8EC0 mov es,eax
116 00000072 FC cld
117 00000073 BEA0000000 mov esi,0xa0 ;小心!32位模式下movsb/w/d
118 00000078 BF00000000 mov edi,0x00 ;使用的是esi/edi/ecx
119 0000007D B980070000 mov ecx,1920
120 00000082 F366A5 rep movsw
121 00000085 66BB000F mov bx,3840 ;清除屏幕最底一行
122 00000089 B950000000 mov ecx,80 ;32位程序应该使用ECX
123 .cls:
124 0000008E 266667C7072007 mov word[es:bx],0x0720
125 00000095 6683C302 add bx,2
126 00000099 E2F3 loop .cls
127
128 0000009B 07 pop es
129 0000009C 1F pop ds
130
131 ;mov bx,1920 ;为了修改原书程序的逻辑问题,删除
132 0000009D 665B pop bx ;为了修改原书程序的逻辑问题,新增
133 0000009F 6683EB50 sub bx,80 ;为了修改原书程序的逻辑问题,新增
134
135 .set_cursor:
136 000000A3 66BAD403 mov dx,0x3d4
137 000000A7 B00E mov al,0x0e
138 000000A9 EE out dx,al
139 000000AA 6642 inc dx ;0x3d5
140 000000AC 88F8 mov al,bh
141 000000AE EE out dx,al
142 000000AF 664A dec dx ;0x3d4
143 000000B1 B00F mov al,0x0f
144 000000B3 EE out dx,al
145 000000B4 6642 inc dx ;0x3d5
146 000000B6 88D8 mov al,bl
147 000000B8 EE out dx,al
148
149 000000B9 61 popad
150 000000BA C3 ret
151
152 ;-------------------------------------------------------------------------------
153 read_hard_disk_0: ;从硬盘读取一个逻辑扇区
154 ;EAX=逻辑扇区号
155 ;DS:EBX=目标缓冲区地址
156 ;返回:EBX=EBX+512
157 000000BB 50 push eax
158 000000BC 51 push ecx
159 000000BD 52 push edx
160
161 000000BE 50 push eax
162
163 000000BF 66BAF201 mov dx,0x1f2
164 000000C3 B001 mov al,1
165 000000C5 EE out dx,al ;读取的扇区数
166
167 000000C6 6642 inc dx ;0x1f3
168 000000C8 58 pop eax
169 000000C9 EE out dx,al ;LBA地址7~0
170
171 000000CA 6642 inc dx ;0x1f4
172 000000CC B108 mov cl,8
173 000000CE D3E8 shr eax,cl
174 000000D0 EE out dx,al ;LBA地址15~8
175
176 000000D1 6642 inc dx ;0x1f5
177 000000D3 D3E8 shr eax,cl
178 000000D5 EE out dx,al ;LBA地址23~16
179
180 000000D6 6642 inc dx ;0x1f6
181 000000D8 D3E8 shr eax,cl
182 000000DA 0CE0 or al,0xe0 ;第一硬盘 LBA地址27~24
183 000000DC EE out dx,al
184
185 000000DD 6642 inc dx ;0x1f7
186 000000DF B020 mov al,0x20 ;读命令
187 000000E1 EE out dx,al
188
189 .waits:
190 000000E2 EC in al,dx
191 000000E3 2488 and al,0x88
192 000000E5 3C08 cmp al,0x08
193 000000E7 75F9 jnz .waits ;不忙,且硬盘已准备好数据传输
194
195 000000E9 B900010000 mov ecx,256 ;总共要读取的字数
196 000000EE 66BAF001 mov dx,0x1f0
197 .readw:
198 000000F2 66ED in ax,dx
199 000000F4 668903 mov [ebx],ax
200 000000F7 83C302 add ebx,2
201 000000FA E2F6 loop .readw
202
203 000000FC 5A pop edx
204 000000FD 59 pop ecx
205 000000FE 58 pop eax
206
207 000000FF CB retf ;段间返回
208
209 ;-------------------------------------------------------------------------------
210 ;汇编语言程序是极难一次成功,而且调试非常困难。这个例程可以提供帮助
211 put_hex_dword: ;在当前光标处以十六进制形式显示
212 ;一个双字并推进光标
213 ;输入:EDX=要转换并显示的数字
214 ;输出:无
215 00000100 60 pushad
216 00000101 1E push ds
217
218 00000102 66B83000 mov ax,core_data_seg_sel ;切换到核心数据段
219 00000106 8ED8 mov ds,ax
220
221 00000108 BB[1B060000] mov ebx,bin_hex ;指向核心数据段内的转换表
222 0000010D B908000000 mov ecx,8
223 .xlt:
224 00000112 C1C204 rol edx,4
225 00000115 89D0 mov eax,edx
226 00000117 83E00F and eax,0x0000000f
227 0000011A D7 xlat
228
229 0000011B 51 push ecx
230 0000011C 88C1 mov cl,al
231 0000011E E8F0FEFFFF call put_char
232 00000123 59 pop ecx
233
234 00000124 E2EC loop .xlt
235
236 00000126 1F pop ds
237 00000127 61 popad
238 00000128 CB retf
239
240 ;-------------------------------------------------------------------------------
241 allocate_memory: ;分配内存
242 ;输入:ECX=希望分配的字节数
243 ;输出:ECX=起始线性地址
244 00000129 1E push ds
245 0000012A 50 push eax
246 0000012B 53 push ebx
247
248 0000012C B830000000 mov eax,core_data_seg_sel
249 00000131 8ED8 mov ds,eax
250
251 00000133 A1[0C000000] mov eax,[ram_alloc]
252 00000138 01C8 add eax,ecx ;下一次分配时的起始地址
253
254 ;这里应当有检测可用内存数量的指令
255
256 0000013A 8B0D[0C000000] mov ecx,[ram_alloc] ;返回分配的起始地址
257
258 00000140 89C3 mov ebx,eax
259 00000142 83E3FC and ebx,0xfffffffc
260 00000145 83C304 add ebx,4 ;强制对齐
261 00000148 A903000000 test eax,0x00000003 ;下次分配的起始地址最好是4字节对齐
262 0000014D 0F45C3 cmovnz eax,ebx ;如果没有对齐,则强制对齐
263 00000150 A3[0C000000] mov [ram_alloc],eax ;下次从该地址分配内存
264 ;cmovcc指令可以避免控制转移
265 00000155 5B pop ebx
266 00000156 58 pop eax
267 00000157 1F pop ds
268
269 00000158 CB retf
270
271 ;-------------------------------------------------------------------------------
272 set_up_gdt_descriptor: ;在GDT内安装一个新的描述符
273 ;输入:EDX:EAX=描述符
274 ;输出:CX=描述符的选择子
275 00000159 50 push eax
276 0000015A 53 push ebx
277 0000015B 52 push edx
278
279 0000015C 1E push ds
280 0000015D 06 push es
281
282 0000015E BB30000000 mov ebx,core_data_seg_sel ;切换到核心数据段
283 00000163 8EDB mov ds,ebx
284
285 00000165 0F0105[00000000] sgdt [pgdt] ;以便开始处理GDT
286
287 0000016C BB08000000 mov ebx,mem_0_4_gb_seg_sel
288 00000171 8EC3 mov es,ebx
289
290 00000173 0FB71D[00000000] movzx ebx,word [pgdt] ;GDT界限
291 0000017A 6643 inc bx ;GDT总字节数,也是下一个描述符偏移
292 0000017C 031D[02000000] add ebx,[pgdt+2] ;下一个描述符的线性地址
293
294 00000182 268903 mov [es:ebx],eax
295 00000185 26895304 mov [es:ebx+4],edx
296
297 00000189 668305[00000000]08 add word [pgdt],8 ;增加一个描述符的大小
298
299 00000191 0F0115[00000000] lgdt [pgdt] ;对GDT的更改生效
300
301 00000198 66A1[00000000] mov ax,[pgdt] ;得到GDT界限值
302 0000019E 6631D2 xor dx,dx
303 000001A1 66BB0800 mov bx,8
304 000001A5 66F7F3 div bx ;除以8,去掉余数
305 000001A8 6689C1 mov cx,ax
306 000001AB 66C1E103 shl cx,3 ;将索引号移到正确位置
307
308 000001AF 07 pop es
309 000001B0 1F pop ds
310
311 000001B1 5A pop edx
312 000001B2 5B pop ebx
313 000001B3 58 pop eax
314
315 000001B4 CB retf
316 ;-------------------------------------------------------------------------------
317 make_seg_descriptor: ;构造存储器和系统的段描述符
318 ;输入:EAX=线性基地址
319 ; EBX=段界限
320 ; ECX=属性。各属性位都在原始
321 ; 位置,无关的位清零
322 ;返回:EDX:EAX=描述符
323 000001B5 89C2 mov edx,eax
324 000001B7 C1E010 shl eax,16
325 000001BA 6609D8 or ax,bx ;描述符前32位(EAX)构造完毕
326
327 000001BD 81E20000FFFF and edx,0xffff0000 ;清除基地址中无关的位
328 000001C3 C1C208 rol edx,8
329 000001C6 0FCA bswap edx ;装配基址的31~24和23~16 (80486+)
330
331 000001C8 6631DB xor bx,bx
332 000001CB 09DA or edx,ebx ;装配段界限的高4位
333
334 000001CD 09CA or edx,ecx ;装配属性
335
336 000001CF CB retf
337
338 ;-------------------------------------------------------------------------------
339 make_gate_descriptor: ;构造门的描述符(调用门等)
340 ;输入:EAX=门代码在段内偏移地址
341 ; BX=门代码所在段的选择子
342 ; CX=段类型及属性等(各属
343 ; 性位都在原始位置)
344 ;返回:EDX:EAX=完整的描述符
345 000001D0 53 push ebx
346 000001D1 51 push ecx
347
348 000001D2 89C2 mov edx,eax
349 000001D4 81E20000FFFF and edx,0xffff0000 ;得到偏移地址高16位
350 000001DA 6609CA or dx,cx ;组装属性部分到EDX
351
352 000001DD 25FFFF0000 and eax,0x0000ffff ;得到偏移地址低16位
353 000001E2 C1E310 shl ebx,16
354 000001E5 09D8 or eax,ebx ;组装段选择子部分
355
356 000001E7 59 pop ecx
357 000001E8 5B pop ebx
358
359 000001E9 CB retf
360
361 ;-------------------------------------------------------------------------------
362 initiate_task_switch: ;主动发起任务切换
363 ;输入:无
364 ;输出:无。
365 000001EA 60 pushad
366 000001EB 1E push ds
367 000001EC 06 push es
368
369 000001ED B830000000 mov eax,core_data_seg_sel
370 000001F2 8EC0 mov es,eax
371
372 000001F4 B808000000 mov eax,mem_0_4_gb_seg_sel
373 000001F9 8ED8 mov ds,eax
374
375 000001FB 26A1[2B0E0000] mov eax,[es:tcb_chain]
376 00000201 83F800 cmp eax,0
377 00000204 7446 jz .return
378
379 ;搜索状态为忙(当前任务)的节点
380 .b0:
381 00000206 66837804FF cmp word [eax+0x04],0xffff
382 0000020B 0F44F0 cmove esi,eax ;找到忙的节点,ESI=节点的线性地址
383 0000020E 7404 jz .b1
384 00000210 8B00 mov eax,[eax]
385 00000212 EBF2 jmp .b0
386
387 ;从当前节点继续搜索就绪任务的节点
388 .b1:
389 00000214 8B18 mov ebx,[eax]
390 00000216 09DB or ebx,ebx
391 00000218 740E jz .b2 ;到链表尾部也未发现就绪节点,从头找
392 0000021A 66837B0400 cmp word [ebx+0x04],0x0000
393 0000021F 0F44FB cmove edi,ebx ;已找到就绪节点,EDI=节点的线性地址
394 00000222 741D jz .b3
395 00000224 89D8 mov eax,ebx
396 00000226 EBEC jmp .b1
397
398 .b2:
399 00000228 268B1D[2B0E0000] mov ebx,[es:tcb_chain] ;EBX=链表首节点线性地址
400 .b20:
401 0000022F 66837B0400 cmp word [ebx+0x04],0x0000
402 00000234 0F44FB cmove edi,ebx ;已找到就绪节点,EDI=节点的线性地址
403 00000237 7408 jz .b3
404 00000239 8B1B mov ebx,[ebx]
405 0000023B 09DB or ebx,ebx
406 0000023D 740D jz .return ;链表中已经不存在就绪任务,返回
407 0000023F EBEE jmp .b20
408
409 ;就绪任务的节点已经找到,准备切换到该任务
410 .b3:
411 00000241 66F75604 not word [esi+0x04] ;将忙状态的节点改为就绪状态的节点
412 00000245 66F75704 not word [edi+0x04] ;将就绪状态的节点改为忙状态的节点
413 00000249 FF6F14 jmp far [edi+0x14] ;任务切换
414
415 .return:
416 0000024C 07 pop es
417 0000024D 1F pop ds
418 0000024E 61 popad
419
420 0000024F CB retf
421
422 ;-------------------------------------------------------------------------------
423 terminate_current_task: ;终止当前任务
424 ;注意,执行此例程时,当前任务仍在
425 ;运行中。此例程其实也是当前任务的
426 ;一部分
427 00000250 B830000000 mov eax,core_data_seg_sel
428 00000255 8EC0 mov es,eax
429
430 00000257 B808000000 mov eax,mem_0_4_gb_seg_sel
431 0000025C 8ED8 mov ds,eax
432
433 0000025E 26A1[2B0E0000] mov eax,[es:tcb_chain]
434 ;EAX=首节点的线性地址
435 ;搜索状态为忙(当前任务)的节点
436 .s0:
437 00000264 66837804FF cmp word [eax+0x04],0xffff
438 00000269 7404 jz .s1 ;找到忙的节点,EAX=节点的线性地址
439 0000026B 8B00 mov eax,[eax]
440 0000026D EBF5 jmp .s0
441
442 ;将状态为忙的节点改成终止状态
443 .s1:
444 0000026F 66C740043333 mov word [eax+0x04],0x3333
445
446 ;搜索就绪状态的任务
447 00000275 268B1D[2B0E0000] mov ebx,[es:tcb_chain] ;EBX=链表首节点线性地址
448 .s2:
449 0000027C 66837B0400 cmp word [ebx+0x04],0x0000
450 00000281 7404 jz .s3 ;已找到就绪节点,EBX=节点的线性地址
451 00000283 8B1B mov ebx,[ebx]
452 00000285 EBF5 jmp .s2
453
454 ;就绪任务的节点已经找到,准备切换到该任务
455 .s3:
456 00000287 66F75304 not word [ebx+0x04] ;将就绪状态的节点改为忙状态的节点
457 0000028B FF6B14 jmp far [ebx+0x14] ;任务切换
458
459 ;-------------------------------------------------------------------------------
460 general_interrupt_handler: ;通用的中断处理过程
461 0000028E 50 push eax
462
463 0000028F B020 mov al,0x20 ;中断结束命令EOI
464 00000291 E6A0 out 0xa0,al ;向从片发送
465 00000293 E620 out 0x20,al ;向主片发送
466
467 00000295 58 pop eax
468
469 00000296 CF iretd
470
471 ;-------------------------------------------------------------------------------
472 general_exception_handler: ;通用的异常处理过程
473 00000297 BB[F7050000] mov ebx,excep_msg
474 0000029C 9A[00000000]2800 call sys_routine_seg_sel:put_string
475
476 000002A3 F4 hlt
477
478 ;-------------------------------------------------------------------------------
479 rtm_0x70_interrupt_handle: ;实时时钟中断处理过程
480
481 000002A4 60 pushad
482
483 000002A5 B020 mov al,0x20 ;中断结束命令EOI
484 000002A7 E6A0 out 0xa0,al ;向8259A从片发送
485 000002A9 E620 out 0x20,al ;向8259A主片发送
486
487 000002AB B00C mov al,0x0c ;寄存器C的索引。且开放NMI
488 000002AD E670 out 0x70,al
489 000002AF E471 in al,0x71 ;读一下RTC的寄存器C,否则只发生一次中断
490 ;此处不考虑闹钟和周期性中断的情况
491 ;请求任务调度
492 000002B1 9A[EA010000]2800 call sys_routine_seg_sel:initiate_task_switch
493
494 000002B8 61 popad
495
496 000002B9 CF iretd
497
498 ;-------------------------------------------------------------------------------
499 do_task_clean: ;清理已经终止的任务并回收资源
500
501 ;搜索TCB链表,找到状态为终止的节点
502 ;将节点从链表中拆除
503 ;回收任务占用的各种资源(可以从它的TCB中找到)
504
505 000002BA CB retf
506
507 sys_routine_end:
508
509 ;===============================================================================
510 SECTION core_data vstart=0 ;系统核心的数据段
511 ;-------------------------------------------------------------------------------
512 00000000 0000 pgdt dw 0 ;用于设置和修改GDT
513 00000002 00000000 dd 0
514
515 00000006 0000 pidt dw 0
516 00000008 00000000 dd 0
517
518 0000000C 00001000 ram_alloc dd 0x00100000 ;下次分配内存时的起始地址
519
520 ;符号地址检索表
521 salt:
522 00000010 405072696E74537472- salt_1 db '@PrintString'
522 00000019 696E67
523 0000001C 00<rep F4h> times 256-($-salt_1) db 0
524 00000110 [00000000] dd put_string
525 00000114 2800 dw sys_routine_seg_sel
526
527 00000116 40526561644469736B- salt_2 db '@ReadDiskData'
527 0000011F 44617461
528 00000123 00<rep F3h> times 256-($-salt_2) db 0
529 00000216 [BB000000] dd read_hard_disk_0
530 0000021A 2800 dw sys_routine_seg_sel
531
532 0000021C 405072696E7444776F- salt_3 db '@PrintDwordAsHexString'
532 00000225 726441734865785374-
532 0000022E 72696E67
533 00000232 00<rep EAh> times 256-($-salt_3) db 0
534 0000031C [00010000] dd put_hex_dword
535 00000320 2800 dw sys_routine_seg_sel
536
537 00000322 405465726D696E6174- salt_4 db '@TerminateProgram'
537 0000032B 6550726F6772616D
538 00000333 00<rep EFh> times 256-($-salt_4) db 0
539 00000422 [50020000] dd terminate_current_task
540 00000426 2800 dw sys_routine_seg_sel
541
542 00000428 40496E69745461736B- salt_5 db '@InitTaskSwitch'
542 00000431 537769746368
543 00000437 00<rep F1h> times 256-($-salt_5) db 0
544 00000528 [EA010000] dd initiate_task_switch
545 0000052C 2800 dw sys_routine_seg_sel
546
547 salt_item_len equ $-salt_5
548 salt_items equ ($-salt)/salt_item_len
549
550 0000052E 2020496620796F7520- message_0 db ' If you seen this message,it means we are now '
550 00000537 7365656E2074686973-
550 00000540 206D6573736167652C-
550 00000549 6974206D65616E7320-
550 00000552 776520617265206E6F-
550 0000055B 7720
551 0000055D 696E2070726F746563- db 'in protected mode, and the IDT is mounted.'
551 00000566 746564206D6F64652C-
551 0000056F 20616E642074686520-
551 00000578 494454206973206D6F-
551 00000581 756E7465642E
552 00000587 0D0A00 db 0x0d,0x0a,0
553
554 0000058A 0D0A202000 cpu_brnd0 db 0x0d,0x0a,' ',0
555 0000058F 00<rep 34h> cpu_brand times 52 db 0
556 000005C3 0D0A0D0A00 cpu_brnd1 db 0x0d,0x0a,0x0d,0x0a,0
557
558 000005C8 202053797374656D20- message_1 db ' System wide CALL-GATE mounted and test OK.'
558 000005D1 776964652043414C4C-
558 000005DA 2D47415445206D6F75-
558 000005E3 6E74656420616E6420-
558 000005EC 74657374204F4B2E
559 000005F4 0D0A00 db 0x0d,0x0a,0
560
561 000005F7 2A2A2A2A2A2A2A2A45- excep_msg db '********Exception encounted********',0
561 00000600 7863657074696F6E20-
561 00000609 656E636F756E746564-
561 00000612 2A2A2A2A2A2A2A2A00
562
563 0000061B 303132333435363738- bin_hex db '0123456789ABCDEF'
563 00000624 39414243444546
564 ;put_hex_dword子过程用的查找表
565
566 0000062B 00<rep 800h> core_buf times 2048 db 0 ;内核用的缓冲区
567
568 ;任务控制块链
569 00000E2B 00000000 tcb_chain dd 0
570
571 00000E2F 436F7265207461736B- core_msg1 db 'Core task created.',0x0d,0x0a,0
571 00000E38 20637265617465642E-
571 00000E41 0D0A00
572
573 00000E44 5B434F524520544153- core_msg2 db '[CORE TASK]: I am working!',0x0d,0x0a,0
573 00000E4D 4B5D3A204920616D20-
573 00000E56 776F726B696E67210D-
573 00000E5F 0A00
574
575 core_data_end:
576
577 ;===============================================================================
578 SECTION core_code vstart=0
579 ;-------------------------------------------------------------------------------
580 fill_descriptor_in_ldt: ;在LDT内安装一个新的描述符
581 ;输入:EDX:EAX=描述符
582 ; EBX=TCB基地址
583 ;输出:CX=描述符的选择子
584 00000000 50 push eax
585 00000001 52 push edx
586 00000002 57 push edi
587 00000003 1E push ds
588
589 00000004 B908000000 mov ecx,mem_0_4_gb_seg_sel
590 00000009 8ED9 mov ds,ecx
591
592 0000000B 8B7B0C mov edi,[ebx+0x0c] ;获得LDT基地址
593
594 0000000E 31C9 xor ecx,ecx
595 00000010 668B4B0A mov cx,[ebx+0x0a] ;获得LDT界限
596 00000014 6641 inc cx ;LDT的总字节数,即新描述符偏移地址
597
598 00000016 89040F mov [edi+ecx+0x00],eax
599 00000019 89540F04 mov [edi+ecx+0x04],edx ;安装描述符
600
601 0000001D 6683C108 add cx,8
602 00000021 6649 dec cx ;得到新的LDT界限值
603
604 00000023 66894B0A mov [ebx+0x0a],cx ;更新LDT界限值到TCB
605
606 00000027 6689C8 mov ax,cx
607 0000002A 6631D2 xor dx,dx
608 0000002D 66B90800 mov cx,8
609 00000031 66F7F1 div cx
610
611 00000034 6689C1 mov cx,ax
612 00000037 66C1E103 shl cx,3 ;左移3位,并且
613 0000003B 6683C904 or cx,0000_0000_0000_0100B ;使TI位=1,指向LDT,最后使RPL=00
614
615 0000003F 1F pop ds
616 00000040 5F pop edi
617 00000041 5A pop edx
618 00000042 58 pop eax
619
620 00000043 C3 ret
621
622 ;-------------------------------------------------------------------------------
623 load_relocate_program: ;加载并重定位用户程序
624 ;输入: PUSH 逻辑扇区号
625 ; PUSH 任务控制块基地址
626 ;输出:无
627 00000044 60 pushad
628
629 00000045 1E push ds
630 00000046 06 push es
631
632 00000047 89E5 mov ebp,esp ;为访问通过堆栈传递的参数做准备
633
634 00000049 B908000000 mov ecx,mem_0_4_gb_seg_sel
635 0000004E 8EC1 mov es,ecx
636
637 00000050 8B752C mov esi,[ebp+11*4] ;从堆栈中取得TCB的基地址
638
639 ;以下申请创建LDT所需要的内存
640 00000053 B9A0000000 mov ecx,160 ;允许安装20个LDT描述符
641 00000058 9A[29010000]2800 call sys_routine_seg_sel:allocate_memory
642 0000005F 26894E0C mov [es:esi+0x0c],ecx ;登记LDT基地址到TCB中
643 00000063 2666C7460AFFFF mov word [es:esi+0x0a],0xffff ;登记LDT初始的界限到TCB中
644
645 ;以下开始加载用户程序
646 0000006A B830000000 mov eax,core_data_seg_sel
647 0000006F 8ED8 mov ds,eax ;切换DS到内核数据段
648
649 00000071 8B4530 mov eax,[ebp+12*4] ;从堆栈中取出用户程序起始扇区号
650 00000074 BB[2B060000] mov ebx,core_buf ;读取程序头部数据
651 00000079 9A[BB000000]2800 call sys_routine_seg_sel:read_hard_disk_0
652
653 ;以下判断整个程序有多大
654 00000080 A1[2B060000] mov eax,[core_buf] ;程序尺寸
655 00000085 89C3 mov ebx,eax
656 00000087 81E300FEFFFF and ebx,0xfffffe00 ;使之512字节对齐(能被512整除的数低
657 0000008D 81C300020000 add ebx,512 ;9位都为0
658 00000093 A9FF010000 test eax,0x000001ff ;程序的大小正好是512的倍数吗?
659 00000098 0F45C3 cmovnz eax,ebx ;不是。使用凑整的结果
660
661 0000009B 89C1 mov ecx,eax ;实际需要申请的内存数量
662 0000009D 9A[29010000]2800 call sys_routine_seg_sel:allocate_memory
663 000000A4 26894E06 mov [es:esi+0x06],ecx ;登记程序加载基地址到TCB中
664
665 000000A8 89CB mov ebx,ecx ;ebx -> 申请到的内存首地址
666 000000AA 31D2 xor edx,edx
667 000000AC B900020000 mov ecx,512
668 000000B1 F7F1 div ecx
669 000000B3 89C1 mov ecx,eax ;总扇区数
670
671 000000B5 B808000000 mov eax,mem_0_4_gb_seg_sel ;切换DS到0-4GB的段
672 000000BA 8ED8 mov ds,eax
673
674 000000BC 8B4530 mov eax,[ebp+12*4] ;起始扇区号
675 .b1:
676 000000BF 9A[BB000000]2800 call sys_routine_seg_sel:read_hard_disk_0
677 000000C6 40 inc eax
678 000000C7 E2F6 loop .b1 ;循环读,直到读完整个用户程序
679
680 000000C9 268B7E06 mov edi,[es:esi+0x06] ;获得程序加载基地址
681
682 ;建立程序头部段描述符
683 000000CD 89F8 mov eax,edi ;程序头部起始线性地址
684 000000CF 8B5F04 mov ebx,[edi+0x04] ;段长度
685 000000D2 4B dec ebx ;段界限
686 000000D3 B900F24000 mov ecx,0x0040f200 ;字节粒度的数据段描述符,特权级3
687 000000D8 9A[B5010000]2800 call sys_routine_seg_sel:make_seg_descriptor
688
689 ;安装头部段描述符到LDT中
690 000000DF 89F3 mov ebx,esi ;TCB的基地址
691 000000E1 E81AFFFFFF call fill_descriptor_in_ldt
692
693 000000E6 6683C903 or cx,0000_0000_0000_0011B ;设置选择子的特权级为3
694 000000EA 2666894E44 mov [es:esi+0x44],cx ;登记程序头部段选择子到TCB
695 000000EF 66894F04 mov [edi+0x04],cx ;和头部内
696
697 ;建立程序代码段描述符
698 000000F3 89F8 mov eax,edi
699 000000F5 03470C add eax,[edi+0x0c] ;代码起始线性地址
700 000000F8 8B5F10 mov ebx,[edi+0x10] ;段长度
701 000000FB 4B dec ebx ;段界限
702 000000FC B900F84000 mov ecx,0x0040f800 ;字节粒度的代码段描述符,特权级3
703 00000101 9A[B5010000]2800 call sys_routine_seg_sel:make_seg_descriptor
704 00000108 89F3 mov ebx,esi ;TCB的基地址
705 0000010A E8F1FEFFFF call fill_descriptor_in_ldt
706 0000010F 6683C903 or cx,0000_0000_0000_0011B ;设置选择子的特权级为3
707 00000113 66894F0C mov [edi+0x0c],cx ;登记代码段选择子到头部
708
709 ;建立程序数据段描述符
710 00000117 89F8 mov eax,edi
711 00000119 034714 add eax,[edi+0x14] ;数据段起始线性地址
712 0000011C 8B5F18 mov ebx,[edi+0x18] ;段长度
713 0000011F 4B dec ebx ;段界限
714 00000120 B900F24000 mov ecx,0x0040f200 ;字节粒度的数据段描述符,特权级3
715 00000125 9A[B5010000]2800 call sys_routine_seg_sel:make_seg_descriptor
716 0000012C 89F3 mov ebx,esi ;TCB的基地址
717 0000012E E8CDFEFFFF call fill_descriptor_in_ldt
718 00000133 6683C903 or cx,0000_0000_0000_0011B ;设置选择子的特权级为3
719 00000137 66894F14 mov [edi+0x14],cx ;登记数据段选择子到头部
720
721 ;建立程序堆栈段描述符
722 0000013B 89F8 mov eax,edi
723 0000013D 03471C add eax,[edi+0x1c] ;数据段起始线性地址
724 00000140 8B5F20 mov ebx,[edi+0x20] ;段长度
725 00000143 4B dec ebx ;段界限
726 00000144 B900F24000 mov ecx,0x0040f200 ;字节粒度的堆栈段描述符,特权级3
727 00000149 9A[B5010000]2800 call sys_routine_seg_sel:make_seg_descriptor
728 00000150 89F3 mov ebx,esi ;TCB的基地址
729 00000152 E8A9FEFFFF call fill_descriptor_in_ldt
730 00000157 6683C903 or cx,0000_0000_0000_0011B ;设置选择子的特权级为3
731 0000015B 66894F1C mov [edi+0x1c],cx ;登记堆栈段选择子到头部
732
733 ;重定位SALT
734 0000015F B808000000 mov eax,mem_0_4_gb_seg_sel ;这里和前一章不同,头部段描述符
735 00000164 8EC0 mov es,eax ;已安装,但还没有生效,故只能通
736 ;过4GB段访问用户程序头部
737 00000166 B830000000 mov eax,core_data_seg_sel
738 0000016B 8ED8 mov ds,eax
739
740 0000016D FC cld
741
742 0000016E 268B4F24 mov ecx,[es:edi+0x24] ;U-SALT条目数(通过访问4GB段取得)
743 00000172 83C728 add edi,0x28 ;U-SALT在4GB段内的偏移
744 .b2:
745 00000175 51 push ecx
746 00000176 57 push edi
747
748 00000177 B905000000 mov ecx,salt_items
749 0000017C BE[10000000] mov esi,salt
750 .b3:
751 00000181 57 push edi
752 00000182 56 push esi
753 00000183 51 push ecx
754
755 00000184 B940000000 mov ecx,64 ;检索表中,每条目的比较次数
756 00000189 F3A7 repe cmpsd ;每次比较4字节
757 0000018B 7519 jnz .b4
758 0000018D 8B06 mov eax,[esi] ;若匹配,则esi恰好指向其后的地址
759 0000018F 26898700FFFFFF mov [es:edi-256],eax ;将字符串改写成偏移地址
760 00000196 668B4604 mov ax,[esi+4]
761 0000019A 6683C803 or ax,0000000000000011B ;以用户程序自己的特权级使用调用门
762 ;故RPL=3
763 0000019E 2666898704FFFFFF mov [es:edi-252],ax ;回填调用门选择子
764 .b4:
765
766 000001A6 59 pop ecx
767 000001A7 5E pop esi
768 000001A8 81C606010000 add esi,salt_item_len
769 000001AE 5F pop edi ;从头比较
770 000001AF E2D0 loop .b3
771
772 000001B1 5F pop edi
773 000001B2 81C700010000 add edi,256
774 000001B8 59 pop ecx
775 000001B9 E2BA loop .b2
776
777 000001BB 8B752C mov esi,[ebp+11*4] ;从堆栈中取得TCB的基地址
778
779 ;创建0特权级栈
780 000001BE B900000000 mov ecx,0 ;以4KB为单位的栈段界限值
781 000001C3 26894E1A mov [es:esi+0x1a],ecx ;登记0特权级栈界限到TCB
782 000001C7 41 inc ecx
783 000001C8 C1E10C shl ecx,12 ;乘以4096,得到段大小
784 000001CB 51 push ecx
785 000001CC 9A[29010000]2800 call sys_routine_seg_sel:allocate_memory
786 000001D3 26894E1E mov [es:esi+0x1e],ecx ;登记0特权级栈基地址到TCB
787 000001D7 89C8 mov eax,ecx
788 000001D9 268B5E1A mov ebx,[es:esi+0x1a] ;段长度(界限)
789 000001DD B90092C000 mov ecx,0x00c09200 ;4KB粒度,读写,特权级0
790 000001E2 9A[B5010000]2800 call sys_routine_seg_sel:make_seg_descriptor
791 000001E9 89F3 mov ebx,esi ;TCB的基地址
792 000001EB E810FEFFFF call fill_descriptor_in_ldt
793 ;or cx,0000_0000_0000_0000 ;设置选择子的特权级为0
794 000001F0 2666894E22 mov [es:esi+0x22],cx ;登记0特权级堆栈选择子到TCB
795 000001F5 268F4624 pop dword [es:esi+0x24] ;登记0特权级堆栈初始ESP到TCB
796
797 ;创建1特权级堆栈
798 000001F9 B900000000 mov ecx,0
799 000001FE 26894E28 mov [es:esi+0x28],ecx ;登记1特权级堆栈尺寸到TCB
800 00000202 41 inc ecx
801 00000203 C1E10C shl ecx,12 ;乘以4096,得到段大小
802 00000206 51 push ecx
803 00000207 9A[29010000]2800 call sys_routine_seg_sel:allocate_memory
804 0000020E 26894E2C mov [es:esi+0x2c],ecx ;登记1特权级堆栈基地址到TCB
805 00000212 89C8 mov eax,ecx
806 00000214 268B5E28 mov ebx,[es:esi+0x28] ;段长度(界限)
807 00000218 B900B2C000 mov ecx,0x00c0b200 ;4KB粒度,读写,特权级1
808 0000021D 9A[B5010000]2800 call sys_routine_seg_sel:make_seg_descriptor
809 00000224 89F3 mov ebx,esi ;TCB的基地址
810 00000226 E8D5FDFFFF call fill_descriptor_in_ldt
811 0000022B 6683C901 or cx,0000_0000_0000_0001 ;设置选择子的特权级为1
812 0000022F 2666894E30 mov [es:esi+0x30],cx ;登记1特权级堆栈选择子到TCB
813 00000234 268F4632 pop dword [es:esi+0x32] ;登记1特权级堆栈初始ESP到TCB
814
815 ;创建2特权级堆栈
816 00000238 B900000000 mov ecx,0
817 0000023D 26894E36 mov [es:esi+0x36],ecx ;登记2特权级堆栈尺寸到TCB
818 00000241 41 inc ecx
819 00000242 C1E10C shl ecx,12 ;乘以4096,得到段大小
820 00000245 51 push ecx
821 00000246 9A[29010000]2800 call sys_routine_seg_sel:allocate_memory
822 0000024D 26894E3A mov [es:esi+0x3a],ecx ;登记2特权级堆栈基地址到TCB
823 00000251 89C8 mov eax,ecx
824 00000253 268B5E36 mov ebx,[es:esi+0x36] ;段长度(界限)
825 00000257 B900D2C000 mov ecx,0x00c0d200 ;4KB粒度,读写,特权级2
826 0000025C 9A[B5010000]2800 call sys_routine_seg_sel:make_seg_descriptor
827 00000263 89F3 mov ebx,esi ;TCB的基地址
828 00000265 E896FDFFFF call fill_descriptor_in_ldt
829 0000026A 6683C90A or cx,0000_0000_0000_0010 ;设置选择子的特权级为2
830 0000026E 2666894E3E mov [es:esi+0x3e],cx ;登记2特权级堆栈选择子到TCB
831 00000273 268F4640 pop dword [es:esi+0x40] ;登记2特权级堆栈初始ESP到TCB
832
833 ;在GDT中登记LDT描述符
834 00000277 268B460C mov eax,[es:esi+0x0c] ;LDT的起始线性地址
835 0000027B 260FB75E0A movzx ebx,word [es:esi+0x0a] ;LDT段界限
836 00000280 B900820000 mov ecx,0x00008200 ;LDT描述符,特权级0
837 00000285 9A[B5010000]2800 call sys_routine_seg_sel:make_seg_descriptor
838 0000028C 9A[59010000]2800 call sys_routine_seg_sel:set_up_gdt_descriptor
839 00000293 2666894E10 mov [es:esi+0x10],cx ;登记LDT选择子到TCB中
840
841 ;创建用户程序的TSS
842 00000298 B968000000 mov ecx,104 ;tss的基本尺寸
843 0000029D 2666894E12 mov [es:esi+0x12],cx
844 000002A2 2666FF4E12 dec word [es:esi+0x12] ;登记TSS界限值到TCB
845 000002A7 9A[29010000]2800 call sys_routine_seg_sel:allocate_memory
846 000002AE 26894E14 mov [es:esi+0x14],ecx ;登记TSS基地址到TCB
847
848 ;登记基本的TSS表格内容
849 000002B2 2666C7010000 mov word [es:ecx+0],0 ;反向链=0
850
851 000002B8 268B5624 mov edx,[es:esi+0x24] ;登记0特权级堆栈初始ESP
852 000002BC 26895104 mov [es:ecx+4],edx ;到TSS中
853
854 000002C0 26668B5622 mov dx,[es:esi+0x22] ;登记0特权级堆栈段选择子
855 000002C5 2666895108 mov [es:ecx+8],dx ;到TSS中
856
857 000002CA 268B5632 mov edx,[es:esi+0x32] ;登记1特权级堆栈初始ESP
858 000002CE 2689510C mov [es:ecx+12],edx ;到TSS中
859
860 000002D2 26668B5630 mov dx,[es:esi+0x30] ;登记1特权级堆栈段选择子
861 000002D7 2666895110 mov [es:ecx+16],dx ;到TSS中
862
863 000002DC 268B5640 mov edx,[es:esi+0x40] ;登记2特权级堆栈初始ESP
864 000002E0 26895114 mov [es:ecx+20],edx ;到TSS中
865
866 000002E4 26668B563E mov dx,[es:esi+0x3e] ;登记2特权级堆栈段选择子
867 000002E9 2666895118 mov [es:ecx+24],dx ;到TSS中
868
869 000002EE 26668B5610 mov dx,[es:esi+0x10] ;登记任务的LDT选择子
870 000002F3 2666895160 mov [es:ecx+96],dx ;到TSS中
871
872 000002F8 26668B5612 mov dx,[es:esi+0x12] ;登记任务的I/O位图偏移
873 000002FD 2666895166 mov [es:ecx+102],dx ;到TSS中
874
875 00000302 2666C741640000 mov word [es:ecx+100],0 ;T=0
876
877 00000309 26C7411C00000000 mov dword [es:ecx+28],0 ;登记CR3(PDBR)
878
879 ;访问用户程序头部,获取数据填充TSS
880 00000311 8B5D2C mov ebx,[ebp+11*4] ;从堆栈中取得TCB的基地址
881 00000314 268B7B06 mov edi,[es:ebx+0x06] ;用户程序加载的基地址
882
883 00000318 268B5708 mov edx,[es:edi+0x08] ;登记程序入口点(EIP)
884 0000031C 26895120 mov [es:ecx+32],edx ;到TSS
885
886 00000320 26668B570C mov dx,[es:edi+0x0c] ;登记程序代码段(CS)选择子
887 00000325 266689514C mov [es:ecx+76],dx ;到TSS中
888
889 0000032A 26668B571C mov dx,[es:edi+0x1c] ;登记程序堆栈段(SS)选择子
890 0000032F 2666895150 mov [es:ecx+80],dx ;到TSS中
891
892 00000334 26668B5704 mov dx,[es:edi+0x04] ;登记程序数据段(DS)选择子
893 00000339 2666895154 mov word [es:ecx+84],dx ;到TSS中。注意,它指向程序头部段
894
895 0000033E 2666C741480000 mov word [es:ecx+72],0 ;TSS中的ES=0
896
897 00000345 2666C741580000 mov word [es:ecx+88],0 ;TSS中的FS=0
898
899 0000034C 2666C7415C0000 mov word [es:ecx+92],0 ;TSS中的GS=0
900
901 00000353 9C pushfd
902 00000354 268F4124 pop dword [es:ecx+36] ;EFLAGS
903
904 ;在GDT中登记TSS描述符
905 00000358 268B4614 mov eax,[es:esi+0x14] ;TSS的起始线性地址
906 0000035C 260FB75E12 movzx ebx,word [es:esi+0x12] ;段长度(界限)
907 00000361 B900890000 mov ecx,0x00008900 ;TSS描述符,特权级0
908 00000366 9A[B5010000]2800 call sys_routine_seg_sel:make_seg_descriptor
909 0000036D 9A[59010000]2800 call sys_routine_seg_sel:set_up_gdt_descriptor
910 00000374 2666894E18 mov [es:esi+0x18],cx ;登记TSS选择子到TCB
911
912 00000379 07 pop es ;恢复到调用此过程前的es段
913 0000037A 1F pop ds ;恢复到调用此过程前的ds段
914
915 0000037B 61 popad
916
917 0000037C C20800 ret 8 ;丢弃调用本过程前压入的参数
918
919 ;-------------------------------------------------------------------------------
920 append_to_tcb_link: ;在TCB链上追加任务控制块
921 ;输入:ECX=TCB线性基地址
922 0000037F 50 push eax
923 00000380 52 push edx
924 00000381 1E push ds
925 00000382 06 push es
926
927 00000383 B830000000 mov eax,core_data_seg_sel ;令DS指向内核数据段
928 00000388 8ED8 mov ds,eax
929 0000038A B808000000 mov eax,mem_0_4_gb_seg_sel ;令ES指向0..4GB段
930 0000038F 8EC0 mov es,eax
931
932 00000391 26C70100000000 mov dword [es: ecx+0x00],0 ;当前TCB指针域清零,以指示这是最
933 ;后一个TCB
934
935 00000398 A1[2B0E0000] mov eax,[tcb_chain] ;TCB表头指针
936 0000039D 09C0 or eax,eax ;链表为空?
937 0000039F 740E jz .notcb
938
939 .searc:
940 000003A1 89C2 mov edx,eax
941 000003A3 268B02 mov eax,[es: edx+0x00]
942 000003A6 09C0 or eax,eax
943 000003A8 75F7 jnz .searc
944
945 000003AA 26890A mov [es: edx+0x00],ecx
946 000003AD EB06 jmp .retpc
947
948 .notcb:
949 000003AF 890D[2B0E0000] mov [tcb_chain],ecx ;若为空表,直接令表头指针指向TCB
950
951 .retpc:
952 000003B5 07 pop es
953 000003B6 1F pop ds
954 000003B7 5A pop edx
955 000003B8 58 pop eax
956
957 000003B9 C3 ret
958
959 ;-------------------------------------------------------------------------------
960 start:
961 000003BA B930000000 mov ecx,core_data_seg_sel ;令DS指向核心数据段
962 000003BF 8ED9 mov ds,ecx
963
964 000003C1 B908000000 mov ecx,mem_0_4_gb_seg_sel ;令ES指向4GB数据段
965 000003C6 8EC1 mov es,ecx
966
967 ;创建中断描述符表IDT
968 ;注意!在此期间,不得开放中断,也不得调用put_string例程!
969
970 ;前20个向量是处理器异常使用的
971 000003C8 B8[97020000] mov eax,general_exception_handler ;门代码在段内偏移地址
972 000003CD 66BB2800 mov bx,sys_routine_seg_sel ;门代码所在段的选择子