已阅读5页,还剩13页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Linux0.00深度剖析2010-08-07 14:43361人阅读评论(1)收藏举报最近在学习Linux内核,这0.00据说当年使还是学生的linus异常兴奋,只是满屏幕的AABBBBAAA而已。本人只是写下学习笔记,以备日后复习之用。:c-sharpview plaincopy1. 01!boot.s程序2. 3. 02!首先利用BIOS中断把内核代码(head代码)加载到内存0x10000处,然后移动到内存0处。4. 5. 03!最后进入保护模式,并跳转到内存0(head代码)开始处继续运行。6. 7. 04BOOTSEG=0x07c0!引导扇区(本程序)被BIOS加载到内存0x7c00处。8. 9. 05SYSSEG=0x1000!内核(head)先加载到0x10000处,然后移动到0x0处。10. 11. 06SYSLEN=17!内核占用的最大磁盘扇区数。12. 13. 07entrystart14. 15. 08start:16. 17. 09jmpigo,#BOOTSEG!段间跳转至0x7c0:go处。当本程序刚运行时所有段寄存器值18. 19. 10go:movax,cs!均为0。该跳转语句会把CS寄存器加载为0x7c0(原为0)。20. 21. 11movds,ax!让DS和SS都指向0x7c0段。22. 23. 12movss,ax24. 25. 13movsp,#0x400!设置临时栈指针。其值需大于程序末端并有一定空间即可。26. 27. 1428. 29. 15!加载内核代码到内存0x10000开始处。30. 31. 16load_system:32. 33. 17movdx,#0x0000!利用BIOS中断int0x13功能2从启动盘读取head代码。34. 35. 18movcx,#0x0002!DH-磁头号;DL-驱动器号;CH-10位磁道号低8位;36. 37. 19movax,#SYSSEG!CL-位7、6是磁道号高2位,位50起始扇区号(从1计)。38. 39. 20moves,ax!ES:BX-读入缓冲区位置(0x1000:0x0000)。40. 41. 21xorbx,bx!AH-读扇区功能号;AL-需读的扇区数(17)。42. 43. 22movax,#0x200+SYSLEN44. 45. 23int0x1346. 47. 24jncok_load!若没有发生错误则跳转继续运行,否则死循环。48. 49. 25die:jmpdie50. 51. 2652. 53. 27!把内核代码移动到内存0开始处。共移动8KB(内核长度不超过8KB)。54. 55. 28ok_load:56. 57. 29cli!关中断。58. 59. 30movax,#SYSSEG!移动开始位置DS:SI=0x1000:0;目的位置ES:DI=0:0。60. 61. 31movds,ax62. 63. 32xorax,ax64. 65. 33moves,ax66. 67. 34movcx,#0x1000!设置共移动4K次,每次移动一个字(word)。68. 69. 35subsi,si70. 71. 36subdi,di72. 73. 37repmovw!执行重复移动指令。74. 75. 38!加载IDT和GDT基地址寄存器IDTR和GDTR。76. 77. 39movax,#BOOTSEG78. 79. 40movds,ax!让DS重新指向0x7c0段。80. 81. 41lidtidt_48!加载IDTR。6字节操作数:2字节表长度,4字节线性基地址。82. 83. 42lgdtgdt_48!加载GDTR。6字节操作数:2字节表长度,4字节线性基地址。84. 85. 4386. 87. 44!设置控制寄存器CR0(即机器状态字),进入保护模式。段选择符值8对应GDT表中第2个段描述符。88. 89. 45movax,#0x0001!在CR0中设置保护模式标志PE(位0)。90. 91. 46lmswax!然后跳转至段选择符值指定的段中,偏移0处。92. 93. 47jmpi0,8!注意此时段值已是段选择符。该段的线性基地址是0。94. 95. 4896. 97. 49!下面是全局描述符表GDT的内容。其中包含3个段描述符。第1个不用,另2个是代码和数据段描述符。98. 99. 50gdt:.word0,0,0,0!段描述符0,不用。每个描述符项占8字节。100. 101. 51102. 103. 52.word0x07FF!段描述符1。8Mb-段限长值=2047(2048*4096=8MB)。104. 105. 53.word0x0000!段基地址=0x00000。106. 107. 54.word0x9A00!是代码段,可读/执行。108. 109. 55.word0x00C0!段属性颗粒度=4KB,80386。110. 111. 56112. 113. 57.word0x07FF!段描述符2。8Mb-段限长值=2047(2048*4096=8MB)。114. 115. 58.word0x0000!段基地址=0x00000。116. 117. 59.word0x9200!是数据段,可读写。118. 119. 60.word0x00C0!段属性颗粒度=4KB,80386。120. 121. 61!下面分别是LIDT和LGDT指令的6字节操作数。122. 123. 62idt_48:.word0!IDT表长度是0。124. 125. 63.word0,0!IDT表的线性基地址也是0。126. 127. 64gdt_48:.word0x7ff!GDT表长度是2KB,可容纳256个描述符项。128. 129. 65.word0x7c00+gdt,0!GDT表的线性基地址在0x7c0段的偏移gdt处。130. 131. 66.org510132. 133. 67.word0xAA55!引导扇区有效标志。必须处于引导扇区最后2字节处。134. 135. !多任务内核程序head.s136. !在进入保护模式后,head.s程序重新建立和设置IDT、GDT表的主要原因是为了让程序在结构上比较清晰,也为了与137. !后面Linux0.12内核源代码中这两个表的设置方式保持一致。当然,就本程序来说我们完全可以直接使用boot.s中138. !设置的IDT和GDT表位置,填入适当的描述符项即可。139. 140. 01#head.s包含32位保护模式初始化设置代码、时钟中断代码、系统调用中断代码和两个任务的代码。141. 142. 02#在初始化完成之后程序移动到任务0开始执行,并在时钟中断控制下进行任务0和1之间的切换操作。143. 144. 03LATCH=11930#定时器初始计数值,即每隔10ms发送一次中断请求。145. 146. 04SCRN_SEL=0x18#屏幕显示内存段选择符。147. 148. 05TSS0_SEL=0x20#任务0的TSS段选择符。149. 150. 06LDT0_SEL=0x28#任务0的LDT段选择符。151. 152. 07TSS1_SEL=0X30#任务1的TSS段选择符。153. 154. 08LDT1_SEL=0x38#任务1的LDT段选择符。155. 156. 09.text157. 158. 10startup_32:159. 160. 11#首先加载数据段寄存器DS、堆栈段寄存器SS和堆栈指针ESP。所有段的线性基地址都是0。161. 162. 12movl$0x10,%eax#0x10是GDT中数据段选择符。163. 164. 13mov%ax,%ds165. 166. 14lssinit_stack,%esp167. 168. 15#在新的位置重新设置IDT和GDT表。169. 170. 16callsetup_idt#设置IDT。先把256个中断门都填默认处理过程的描述符。171. 172. 17callsetup_gdt#设置GDT。173. 174. 18movl$0x10,%eax#在改变了GDT之后重新加载所有段寄存器。175. 176. 19mov%ax,%ds177. 178. 20mov%ax,%es179. 180. 21mov%ax,%fs181. 182. 22mov%ax,%gs183. 184. 23lssinit_stack,%esp185. 186. 24#设置8253定时芯片。把计数器通道0设置成每隔10ms向中断控制器发送一个中断请求信号。187. 188. 25movb$0x36,%al#控制字:设置通道0工作在方式3、计数初值采用二进制。189. 190. 26movl$0x43,%edx#8253芯片控制字寄存器写端口。191. 192. 27outb%al,%dx193. 194. 28movl$LATCH,%eax#初始计数值设置为LATCH(1193180/100),即频率100Hz。195. 196. 29movl$0x40,%edx#通道0的端口。197. 198. 30outb%al,%dx#分两次把初始计数值写入通道0。199. 200. 31movb%ah,%al201. 202. 32outb%al,%dx203. 204. 33#在IDT表第8和第128(0x80)项处分别设置定时中断门描述符和系统调用陷阱门描述符。205. 206. 34movl$0x00080000,%eax#中断程序属内核,即EAX高字是内核代码段选择符0x0008。207. 208. 35movw$timer_interrupt,%ax#设置定时中断门描述符。取定时中断处理程序地址。209. 210. 36movw$0x8E00,%dx#中断门类型是14(屏蔽中断),特权级0或硬件使用。211. 212. 37movl$0x08,%ecx#开机时BIOS设置的时钟中断向量号8。这里直接使用它。213. 214. 38leaidt(,%ecx,8),%esi#把IDT描述符0x08地址放入ESI中,然后设置该描述符。215. 216. 39movl%eax,(%esi)217. 218. 40movl%edx,4(%esi)219. 220. 41movw$system_interrupt,%ax#设置系统调用陷阱门描述符。取系统调用处理程序地址。221. 222. 42movw$0xef00,%dx#陷阱门类型是15,特权级3的程序可执行。223. 224. 43movl$0x80,%ecx#系统调用向量号是0x80。225. 226. 44leaidt(,%ecx,8),%esi#把IDT描述符项0x80地址放入ESI中,然后设置该描述符。227. 228. 45movl%eax,(%esi)229. 230. 46movl%edx,4(%esi)231. 232. 47#好了,现在我们为移动到任务0(任务A)中执行来操作堆栈内容,在堆栈中人工建立中断返回时的场景。233. 234. 48pushfl#复位标志寄存器EFLAGS中的嵌套任务标志。235. 236. 49andl$0xffffbfff,(%esp)237. 238. 50popfl239. 240. 51movl$TSS0_SEL,%eax#把任务0的TSS段选择符加载到任务寄存器TR。241. 242. 52ltr%ax243. 244. 53movl$LDT0_SEL,%eax#把任务0的LDT段选择符加载到局部描述符表寄存器LDTR。245. 246. 54lldt%ax#TR和LDTR只需人工加载一次,以后CPU会自动处理。247. 248. 55movl$0,current#把当前任务号0保存在current变量中。249. 250. 56sti#现在开启中断,并在栈中营造中断返回时的场景。251. 252. 57pushl$0x17#把任务0当前局部空间数据段(堆栈段)选择符入栈。253. 254. 58pushl$init_stack#把堆栈指针入栈(也可以直接把ESP入栈)。255. 256. 59pushfl#把标志寄存器值入栈。257. 258. 60pushl$0x0f#把当前局部空间代码段选择符入栈。259. 260. 61pushl$task0#把代码指针入栈。261. 262. 62iret#执行中断返回指令,从而切换到特权级3的任务0中执行。263. 264. 63265. 266. 64#以下是设置GDT和IDT中描述符项的子程序。267. 268. 65setup_gdt:#使用6字节操作数lgdt_opcode设置GDT表位置和长度。269. 270. 66lgdtlgdt_opcode271. 272. 67ret273. 274. #这段代码暂时设置IDT表中所有256个中断门描述符都为同一个默认值,均使用默认的中断处理过程275. 276. #ignore_int。设置的具体方法是:首先在eax和edx寄存器对中分别设置好默认中断门描述符的03277. 278. #字节和47字节的内容,然后利用该寄存器对循环往IDT表中填充默认中断门描述符内容。279. 280. 68setup_idt:#把所有256个中断门描述符设置为使用默认处理过程。281. 282. 69leaignore_int,%edx#设置方法与设置定时中断门描述符的方法一样。283. 284. 70movl$0x00080000,%eax#选择符为0x0008。285. 286. 71movw%dx,%ax287. 288. 72movw$0x8E00,%dx#中断门类型,特权级为0。289. 290. 73leaidt,%edi291. 292. 74mov$256,%ecx#循环设置所有256个门描述符项。293. 294. 75rp_idt:movl%eax,(%edi)295. 296. 76movl%edx,4(%edi)297. 298. 77addl$8,%edi299. 300. 78dec%ecx301. 302. 79jnerp_idt303. 304. 80lidtlidt_opcode#最后用6字节操作数加载IDTR寄存器。305. 306. 81ret307. 308. 82309. 310. 83#显示字符子程序。取当前光标位置并把AL中的字符显示在屏幕上。整屏可显示8025个字符。311. 312. 84write_char:313. 314. 85push%gs#首先保存要用到的寄存器,EAX由调用者负责保存。315. 316. 86pushl%ebx317. 318. 87mov$SCRN_SEL,%ebx#然后让GS指向显示内存段(0xb8000)。319. 320. 88mov%bx,%gs321. 322. 89movlscr_loc,%bx#再从变量scr_loc中取目前字符显示位置值。323. 324. 90shl$1,%ebx#因为在屏幕上每个字符还有一个属性字节,因此字符325. 326. 91movb%al,%gs:(%ebx)#实际显示位置对应的显示内存偏移地址要乘2。327. 328. 92shr$1,%ebx#把字符放到显示内存后把位置值除2加1,此时位置值对329. 330. 93incl%ebx#应下一个显示位置。如果该位置大于2000,则复位成0。331. 332. 94cmpl$2000,%ebx333. 334. 95jb1f335. 336. 96movl$0,%ebx337. 338. 971:movl%ebx,scr_loc#最后把这个位置值保存起来(scr_loc),339. 340. 98popl%ebx#并弹出保存的寄存器内容,返回。341. 342. 99pop%gs343. 344. 100ret345. 346. 101347. 348. 102#以下是3个中断处理程序:默认中断、定时中断和系统调用中断。349. 350. 103#ignore_int是默认的中断处理程序,若系统产生了其他中断,则会在屏幕上显示一个字符“C”。351. 352. 104.align2353. 354. 105ignore_int:355. 356. 106push%ds357. 358. 107pushl%eax359. 360. 108movl$0x10,%eax#首先让DS指向内核数据段,因为中断程序属于内核。361. 362. 109mov%ax,%ds363. 364. 110movl$67,%eax#在AL中存放字符“C”的代码,调用显示程序显示在屏幕上。365. 366. 111callwrite_char367. 368. 112popl%eax369. 370. 113pop%ds371. 372. 114iret373. 374. 115375. 376. 116#这是定时中断处理程序。其中主要执行任务切换操作。377. 378. 117.align2379. 380. 118timer_interrupt:381. 382. 119push%ds383. 384. 120pushl%eax385. 386. 121movl$0x10,%eax#首先让DS指向内核数据段。387. 388. 122mov%ax,%ds389. 390. 123movb$0x20,%al#然后立刻允许其他硬件中断,即向8259A发送EOI命令。391. 392. 124outb%al,$0x20393. 394. 125movl$1,%eax#接着判断当前任务,若是任务1则去执行任务0,或反之。395. 396. 126cmpl%eax,current397. 398. 127je1f399. 400. 128movl%eax,current#若当前任务是0,则把1存入current,并跳转到任务1401. 402. 129ljmp$TSS1_SEL,$0#去执行。注意跳转的偏移值无用,但需要写上。403. 404. 130jmp2f405. 406. 1311:movl$0,current#若当前任务是1,则把0存入current,并跳转到任务0407. 408. 132ljmp$TSS0_SEL,$0#去执行。409. 410. 1332:popl%eax411. 412. 134pop%ds413. 414. 135iret415. 416. 136417. 418. 137#系统调用中断int0x80处理程序。该示例只有一个显示字符功能。419. 420. 138.align2421. 422. 139system_interrupt:423. 424. 140push%ds425. 426. 141pushl%edx427. 428. 142pushl%ecx429. 430. 143pushl%ebx431. 432. 144pushl%eax433. 434. 145movl$0x10,%edx#首先让DS指向内核数据段。435. 436. 146mov%dx,%ds437. 438. 147callwrite_char#然后调用显示字符子程序write_char,显示AL中的字符。439. 440. 148popl%eax441. 442. 149popl%ebx443. 444. 150popl%ecx445. 446. 151popl%edx447. 448. 152pop%ds449. 450. 153iret451. 452. 154453. 454. 155/*/455. 456. 156current:.long0#当前任务号(0或1)。457. 458. 157scr_loc:.long0#屏幕当前显示位置。按从左上角到右下角顺序显示。459. 460. 158461. 462. 159.align2463. 464. 160lidt_opcode:465. 466. 161.word256*8-1#加载IDTR寄存器的6字节操作数:表长度和基地址。467. 468. 162.longidt469. 470. 163lgdt_opcode:471. 472. 164.word(end_gdt-gdt)-1#加载GDTR寄存器的6字节操作数:表长度和基地址。473. 474. 165.longgdt475. 476. 166477. 478. 167.align3479. 480. 168idt:.fill256,8,0#IDT空间。共256个门描述符,每个8字节,占用2KB。481. 482. 169483. 484. 170gdt:.quad0x0000000000000000#GDT表。第1个描述符不用。485. 486. 171.quad0x00c09a00000007ff#第2个是内核代码段描述符。其选择符是0x08。487. 488. 172.quad0x00c09200000007ff#第3个是内核数据段描述符。其选择符是0x10。489. 490. 173.quad0x00c0920b80000002#第4个是显示内存段描述符。其选择符是0x18。491. 492. 174.word0x68,tss0,0xe900,0x0#第5个是TSS0段的描述符。其选择符是0x20493. 494. 175.word0x40,ldt0,0xe200,0x0#第6个是LDT0段的描述符。其选择符是0x28495. 496. 176.word0x68,tss1,0xe900,0x0#第7个是TSS1段的描述符。其选择符是0x30497. 498. 177.word0x40,ldt1,0xe200,0x0#第8个是LDT1段的描述符。其选择符是0x38499. 500. 178end_gdt:501. 502. 179.fill128,4,0#初始内核堆栈空间。503. 504. 180init_stack:#刚进入保护模式时用于加载SS:ESP堆栈指针值。505. 506. 181.longinit_stack#堆栈段偏移位置。507. 508. 182.word0x10#堆栈段同内核数据段。509. 510. 183511. 512. 184#下面是任务0的LDT表段中的局部段描述符。513. 514. 185.align3515. 516. 186ldt0:.quad0x0000000000000000#第1个描述符,不用。517. 518. 187.quad0x00c0fa00000003ff#第2个局部代码段描述符,对应选择符是0x0f。519. 520. 188.quad0x00c0f200000003ff#第3个局部数据段描述符,对应选择符是0x17。521. 522. 189#下面是任务0的TSS段的内容。注意其中标号等字段在任务切换时不会改变。523. 524. 190tss0:.long0/*backlink*/525. 526. 191.longkrn_stk0,0x10/*esp0,ss0*/527. 528. 192.long0,0,0,0,0/*esp1,ss1,esp2,ss2,cr3*/529. 530. 193.long0,0,0,0,0/*eip,eflags,eax,ecx,edx*/531. 532. 194.long0,0,0,0,0/*ebxesp,ebp,esi,edi*/533. 534. 195.long0,0,0,0,0,0/*es,cs,ss,ds,fs,gs*/535. 536. 196.longLDT0_SEL,0x8000000/*ldt,tracebitmap*/537. 538. 197539. 540. 198.fill128,4,0#这是任务0的内核栈空间。541. 542. 199krn_stk0:543. 544. 200545. 546. 201#下面是任务1的LDT表段内容和TSS段内容。547. 548. 202.align3549. 550. 203ldt1:.quad0x0000000000000000#第1个描述符,不用。551. 552. 204.quad0x00c0fa00000003ff#选择符是0x0f,基地址=0x00000。553. 554. 205.quad0x00c0f200000003ff#选择符是0x17,基地址=0x00000。555. 556. 206557. 558. 207tss1:.long0/*backlink*/559. 560. 208.longkrn_stk1,0x10/*esp0,ss0*/561. 562. 209.long0,0,0,0,0/*esp1,ss1,esp2,ss2,cr3*/563. 564. 210.longtask1,0x200/*eip,eflags*/565. 566. 211.long0,0,0,0/*eax,ecx,edx,ebx*/567. 568. 212.longusr_stk1,0,0,0/*esp,ebp,esi,edi*/569. 570. 213.long0x17,0x0f,0x17,0x17,0x17,0x17/*es,cs,ss,ds,fs,gs*/571. 572. 214.longLDT1_SEL,0x8000000/*ldt,tracebitmap*/573. 574. 215575. 576. 216.fill128,4,0#这是任务1的内核栈空间。其用户栈直接使用初始栈空间。577. 578. 217krn_stk1:579. 580. 218581. 582. 824#下面是任务0和任务1的程序,它们分别循环显示字符“A”和“B”。583. 584. 220task0:585. 586. 221movl$0x17,%eax#首先让DS指向任务的局部数据段。587. 588. 222movw%ax,%ds#因为任务没有使用局部数据,所以这两句可省略。589. 590. 223movl$65,%al#把需要显示的字符“A”放入AL寄存器中。591. 592. 224int$0x80#执行系统调用,显示字符。593. 594. 225movl$0xfff,%ecx#执行循环,起延时作用。595. 596. 2261:loop1b597. 598. 227jmptask0#跳转到任务代码开始处继续显示字符。599
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 古今“兴”说略论
- 南昌绿色生态发展存在的问题及解决对策
- 不锈钢控制棒离子渗氮外观色差改善技术研究
- 职称评审鉴定评语
- 工程合同应该咋写好一点(3篇)
- 标准毕业论文格式
- 博士论文格式要求
- 物流运输管理系统 本科开题报告
- 毕业论文写作标准格式
- 论文后记怎么写
- 商场客服服务礼仪培训
- 2025年专升本物理学热力学与统计物理试卷(含答案)
- 企业品牌形象策划与宣传材料制作模板
- 26.1.2 反比例函数的图象和性质(第1课时 图象和性质)(教学设计)数学人教版九年级下册
- 浙江省杭州市滨和中学2024-2025学年九年级上学期期中教学质量检测英语试题(含答案)
- 82-2式手榴弹教学课件
- 安徽省合肥八中2026届高一化学第一学期期中质量检测试题含解析
- 河南省体育彩票管理中心聘用人员招聘笔试真题2024
- 人力资源岗位岗前培训试题及答案
- 解决学习问题的做法
- 2025年国家义务教育质量监测小学德育模拟测评估考试题库及答案
评论
0/150
提交评论