Advertisement
MichaelPetch

SO79315836 - kernel.asm

Dec 29th, 2024 (edited)
54
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 25.35 KB | None | 0 0
  1. KERNEL_OFS EQU 0x8000 ; Origin point (VMA) of the kernel
  2. ; Offset form base of memory where kernel starts
  3. VIDEO_TEXT_ADDR EQU 0xb8000
  4. ; Hard code beginning of text video memory
  5. ATTR_WHITE_ON_MAGENTA EQU 0x57 ; White on magenta attribl
  6. EFLAGS_IF_BIT EQU 9 ; Interrupt Flag (IF) bit = 9
  7.  
  8. org KERNEL_OFS ; Set origin point (VMA) of kernel
  9.  
  10. ; PIC constants
  11. PIC1 EQU 0x20 ; IO base address for master PIC
  12. PIC2 EQU 0xA0 ; IO base address for slave PIC
  13. PIC1_COMMAND EQU PIC1
  14. PIC1_DATA EQU (PIC1+1)
  15. PIC2_COMMAND EQU PIC2
  16. PIC2_DATA EQU (PIC2+1)
  17.  
  18. ICW1_ICW4 EQU 0x01 ; Indicates that ICW4 will be present
  19. ICW1_SINGLE EQU 0x02 ; Single (cascade) mode
  20. ICW1_INTERVAL4 EQU 0x04 ; Call address interval 4 (8)
  21. ICW1_LEVEL EQU 0x08 ; Level triggered (edge) mode
  22. ICW1_INIT EQU 0x10 ; Initialization - required!
  23.  
  24. ICW4_8086 EQU 0x01 ; 8086/88 (MCS-80/85) mode
  25. ICW4_AUTO EQU 0x02 ; Auto (normal) EOI
  26. ICW4_BUF_SLAVE EQU 0x08 ; Buffered mode/slave
  27. ICW4_BUF_MASTER EQU 0x0C ; Buffered mode/master
  28. ICW4_SFNM EQU 0x10 ; Special fully nested (not)
  29.  
  30. PIC1_BASE EQU 0x20
  31. PIC2_BASE EQU 0x28
  32.  
  33. PIC_EOI EQU 0x20
  34.  
  35. bits 16
  36.  
  37. ; Kernel Entry point
  38. ; Upon entry these have all been set:
  39. ; Direction Flag (DF) = 0
  40. ; DS=ES=GS=FS=0x0000
  41. ; SS:SP = 0x0000:0x7c00
  42.  
  43. kernel_start:
  44. mov si, not386_err ; Default error message to no 386 processor
  45. call check_386 ; Is this a 32-bit processor?
  46. jz .error ; If not print error and stop
  47. mov si, noa20_err ; Default error message to A20 enable error
  48. call a20_enable ; Enable A20 line
  49. jz .error ; If the A20 line isn't enabled then print error and stop
  50. jmp switch_protmode_32 ; Switch to 32-bit protected mode and
  51. ; and continue at label 'protmode32_entry'
  52. .error:
  53. call print_string_16 ; Print error message
  54. .end:
  55. cli ; Disable interrupts
  56. .endloop:
  57. hlt ; Halt CPU
  58. jmp .endloop ; Loop in case we get an NMI (non-maskable interrupt)
  59.  
  60. ; Function: print_string_16
  61. ; Display a string to the console on display page 0
  62. ;
  63. ; Inputs: SI = Offset of address to print
  64. ; Clobbers: AX, BX, SI
  65.  
  66. print_string_16:
  67. mov ah, 0x0e ; BIOS tty Print
  68. xor bx, bx ; Set display page to 0 (BL)
  69. jmp .getch
  70. .repeat:
  71. int 0x10 ; print character
  72. .getch:
  73. lodsb ; Get character from string
  74. test al,al ; Have we reached end of string?
  75. jnz .repeat ; if not process next character
  76. .end:
  77. ret
  78.  
  79. ; Function: wait_8042_cmd
  80. ; Wait until the Input Buffer Full bit in the keyboard controller's
  81. ; status register becomes 0. After calls to this function it is
  82. ; safe to send a command on Port 0x64
  83. ;
  84. ; Inputs: None
  85. ; Clobbers: AX
  86. ; Returns: None
  87.  
  88. KBC_STATUS_IBF_BIT EQU 1
  89. wait_8042_cmd:
  90. in al, 0x64 ; Read keyboard controller status register
  91. test al, 1 << KBC_STATUS_IBF_BIT
  92. ; Is bit 1 (Input Buffer Full) set?
  93. jnz wait_8042_cmd ; If it is then controller is busy and we
  94. ; can't send command byte, try again
  95. ret ; Otherwise buffer is clear and ready to send a command
  96.  
  97. ; Function: wait_8042_data
  98. ; Wait until the Output Buffer Empty (OBE) bit in the keyboard controller's
  99. ; status register becomes 0. After a call to this function there is
  100. ; data available to be read on port 0x60.
  101. ;
  102. ; Inputs: None
  103. ; Clobbers: AX
  104. ; Returns: None
  105.  
  106. KBC_STATUS_OBE_BIT EQU 0
  107. wait_8042_data:
  108. in al, 0x64 ; Read keyboard controller status register
  109. test al, 1 << KBC_STATUS_OBE_BIT
  110. ; Is bit 0 (Output Buffer Empty) set?
  111. jz wait_8042_data ; If not then no data waiting to be read, try again
  112. ret ; Otherwise data is ready to be read
  113.  
  114. ; Function: a20_kbd_enable
  115. ; Enable the A20 line via the keyboard controller
  116. ;
  117. ; Inputs: None
  118. ; Clobbers: AX, CX
  119. ; Returns: None
  120.  
  121. a20_kbd_enable:
  122. pushf
  123. cli ; Disable interrupts
  124.  
  125. call wait_8042_cmd ; When controller ready for command
  126. mov al, 0xad ; Send command 0xad (disable keyboard).
  127. out 0x64, al
  128.  
  129. call wait_8042_cmd ; When controller ready for command
  130. mov al, 0xd0 ; Send command 0xd0 (read output port)
  131. out 0x64, al
  132.  
  133. call wait_8042_data ; Wait until controller has data
  134. in al, 0x60 ; Read data from keyboard
  135. mov cx, ax ; CX = copy of byte read
  136.  
  137. call wait_8042_cmd ; Wait until controller is ready for a command
  138. mov al, 0xd1
  139. out 0x64, al ; Send command 0xd1 (write output port)
  140.  
  141. call wait_8042_cmd ; Wait until controller is ready for a command
  142. mov ax, cx
  143. or al, 1 << 1 ; Write value back with bit 1 set
  144. out 0x60, al
  145.  
  146. call wait_8042_cmd ; Wait until controller is ready for a command
  147. mov al, 0xae
  148. out 0x64, al ; Write command 0xae (enable keyboard)
  149.  
  150. call wait_8042_cmd ; Wait until controller is ready for command
  151. popf ; Restore flags including interrupt flag
  152. ret
  153.  
  154. ; Function: a20_fast_enable
  155. ; Enable the A20 line via System Control Port A
  156. ;
  157. ; Inputs: None
  158. ; Clobbers: AX
  159. ; Returns: None
  160.  
  161. a20_fast_enable:
  162. in al, 0x92 ; Read System Control Port A
  163. test al, 1 << 1
  164. jnz .finished ; If bit 1 is set then A20 already enabled
  165. or al, 1 << 1 ; Set bit 1
  166. and al, ~(1 << 0) ; Clear bit 0 to avoid issuing a reset
  167. out 0x92, al ; Send Enabled A20 and disabled Reset to control port
  168. .finished:
  169. ret
  170.  
  171. ; Function: a20_bios_enable
  172. ; Enable the A20 line via the BIOS function Int 15h/AH=2401
  173. ;
  174. ; Inputs: None
  175. ; Clobbers: AX
  176. ; Returns: None
  177.  
  178. a20_bios_enable:
  179. mov ax, 0x2401 ; Int 15h/AH=2401 enables A20 on BIOS with this feature
  180. int 0x15
  181. ret
  182.  
  183. ; Function: a20_check
  184. ; Determine if the A20 line is enabled or disabled
  185. ;
  186. ; Inputs: None
  187. ; Clobbers: AX, CX, ES
  188. ; Returns: ZF=1 if A20 enabled, ZF=0 if disabled
  189.  
  190. a20_check:
  191. pushf ; Save flags so Interrupt Flag (IF) can be restored
  192. push ds ; Save volatile registers
  193. push si
  194. push di
  195.  
  196. cli ; Disable interrupts
  197. xor ax, ax
  198. mov ds, ax
  199. mov si, 0x600 ; 0x0000:0x0600 (0x00600) address we will test
  200.  
  201. mov ax, 0xffff
  202. mov es, ax
  203. mov di, 0x610 ; 0xffff:0x0610 (0x00600) address we will test
  204. ; The physical address pointed to depends on whether
  205. ; memory wraps or not. If it wraps then A20 is disabled
  206.  
  207. mov cl, [si] ; Save byte at 0x0000:0x0600
  208. mov ch, [es:di] ; Save byte at 0xffff:0x0610
  209.  
  210. mov byte [si], 0xaa ; Write 0xaa to 0x0000:0x0600
  211. mov byte [es:di], 0x55 ; Write 0x55 to 0xffff:0x0610
  212.  
  213. xor ax, ax ; Set return value 0
  214. cmp byte [si], 0x55 ; If 0x0000:0x0600 is 0x55 and not 0xaa
  215. je .disabled ; then memory wrapped because A20 is disabled
  216.  
  217. dec ax ; A20 Disable, set AX to -1
  218. .disabled:
  219. ; Cleanup by restoring original bytes in memory. This must be in reverse
  220. ; order from the order they were originally saved
  221. mov [es:di], ch ; Restore data saved data to 0xffff:0x0610
  222. mov [si], cl ; Restore data saved data to 0x0000:0x0600
  223.  
  224. pop di ; Restore non-volatile registers
  225. pop si
  226. pop ds
  227. popf ; Restore Flags (including IF)
  228. test al, al ; Return ZF=1 if A20 enabled, ZF=0 if disabled
  229. ret
  230.  
  231. ; Function: a20_enable
  232. ; Enable the A20 line
  233. ;
  234. ; Inputs: None
  235. ; Clobbers: AX, BX, CX, DX
  236. ; Returns: ZF=0 if A20 not enabled, ZF=1 if A20 enabled
  237.  
  238. a20_enable:
  239. call a20_check ; Is A20 already enabled?
  240. jnz .a20_on ; If so then we're done ZF=1
  241.  
  242. call a20_bios_enable ; Try enabling A20 via BIOS
  243. call a20_check ; Is A20 now enabled?
  244. jnz .a20_on ; If so then we're done ZF=1
  245.  
  246. call a20_kbd_enable ; Try enabling A20 via keyboard controller
  247. call a20_check ; Is A20 now enabled?
  248. jnz .a20_on ; If so then we're done ZF=1
  249.  
  250. call a20_fast_enable ; Try enabling A20 via fast method
  251. call a20_check ; Is A20 now enabled?
  252. jnz .a20_on ; If so then we're done ZF=1
  253. .a20_err:
  254. xor ax, ax ; If A20 disabled then return with ZF=0
  255. .a20_on:
  256. ret
  257.  
  258. ; Function: check_386
  259. ; Check if this processor is at least a 386
  260. ;
  261. ; Inputs: None
  262. ; Clobbers: AX
  263. ; Returns: ZF=0 if Processor earlier than a 386, ZF=1 if processor is 386+
  264.  
  265. check_386:
  266. xor ax, ax ; Zero EFLAGS
  267. push ax
  268. popf ; Push zeroed flags
  269. pushf
  270. pop ax ; Get the currently set flags
  271. and ax, 0xf000 ; if high 4 bits of FLAGS are not set then
  272. cmp ax, 0xf000 ; CPU is an 8086/8088/80186/80188
  273. je .error ; and exit with ZF = 0
  274. mov ax, 0xf000 ; Set the high 4 bits of FLAGS to 1
  275. push ax
  276. popf ; Update the FLAGS register
  277. pushf ; Get newly set FLAGS into AX
  278. pop ax
  279. and ax, 0xf000 ; if none of the high 4 bits are set then
  280. jnz .noerror ; CPU is an 80286. Return success ZF = 1
  281. ; otherwise CPU is a 386+
  282. .error:
  283. xor ax, ax ; Set ZF = 0 (Earlier than a 386)
  284. .noerror:
  285. ret
  286.  
  287. ; Load the GDT and fix up each entry by swapping the high 8 bits of
  288. ; the base with the access byte. The GDT entries created by MAKE_GDT_DESC
  289. ; can't be used directly since the base is encoded in such a way that
  290. ; operations other than + or - aren't performed on it..
  291. load_gdt:
  292. mov cx, NUMGDTENTRIES
  293. mov si, gdt.start
  294. .fixentry:
  295. mov al, [si + 5] ; Get high 8 bits of the base
  296. mov bl, [si + 7] ; Get the Access byte
  297. mov [si + 5], bl ; Save the swapped values back
  298. mov [si + 7], al
  299. add si, 8 ; Advance to next entry
  300. loop .fixentry ; Repeat until all entries processed
  301.  
  302. lgdt [gdt.gdtr] ; Load the GDT record
  303. ret
  304.  
  305. ; Load the IDT and fix up each entry by swapping the high 16 bits of
  306. ; the handler offset with the selector value. The IDT entries created
  307. ; by MAKE_IDT_DESC can't be used directly since the offset of the
  308. ; handler is encoded in such a way that operations other than + or -
  309. ; aren't performed on it.
  310. load_idt:
  311. mov cx, NUMIDTENTRIES
  312. mov si, idt.start
  313. .fixentry:
  314. mov ax, [si + 2] ; Get upper 16 bits of handler's offset
  315. mov bx, [si + 6] ; Get the selector value
  316. mov [si + 2], bx ; Save the swapped values back
  317. mov [si + 6], ax
  318. add si, 8 ; Advance to next entry
  319. loop .fixentry ; Repeat until all entries processed
  320.  
  321. lidt [idt.idtr] ; Load the IDT record
  322. ret
  323.  
  324. ; Function: switch_protmode_32
  325. ; Switch processor to 32-bit protected
  326. ; - Enable Interrupts (IF=1)
  327. ; - Paging not enabled
  328. ; - Disable interrupts on the Master and Slave PICs
  329. ; - Flush any pending external interrupts
  330. ; - Jump to 32-bit protected mode at label `protmode32_entry`
  331. ;
  332. ; Clobbers: N/A
  333. ; Returns: Jumps to label 'protmode32_entry', doesn't return
  334.  
  335. switch_protmode_32:
  336. push 1<<EFLAGS_IF_BIT | 1<<1
  337. ; Reset the EFLAG bits to 0 except IF=1 and reserved bit 1
  338. popf ; This put EFLAGS in a known state
  339.  
  340. ; Disable IRQs on the Master and Slave PICs
  341. mov al, 0xFF ; Bits that are 1 disable interrupts, 0 = enable
  342. out PIC2_DATA, al ; Disable all interrupts on Slave PIC
  343. out PIC1_DATA, al ; Disable all interrupts on Master PIC
  344.  
  345. ; Flush any pending IRQs
  346. ; Do a loop to allow pending interrupts to be processed.
  347. ; Execute enough instructions to process all 16 interrupts.
  348. mov ecx, 8
  349. .irqflush:
  350. dec ecx
  351. jnz .irqflush
  352.  
  353. call load_idt ; Load IDT and perform fixups
  354. call load_gdt ; Load GDT and perform fixups
  355.  
  356. ; Enter 32-bit protected mode without paging enabled
  357. movzx esp, sp ; Zero extend SP to ESP
  358. mov eax, cr0 ; Get current CR0
  359. or eax, 0x00000001 ; Enable protected mode bit
  360. mov cr0, eax ; Update CR0
  361. jmp CODE32_PL0_SEL:protmode32_entry
  362. ; Start executing code in 32-bit protected mode
  363. ; Also flushes the instruction prefetch queue
  364.  
  365. noa20_err db "A20 line couldn't be enabled", 10, 13, 0
  366. not386_err db "Processor is not a 386+", 10, 13, 0
  367.  
  368. ; Macro to build an initial GDT descriptor entry
  369. ; 4 parameters: base, limit, access, flags
  370. ;
  371. ; The generated descriptor entry will need to be fixed up at runtime
  372. ; before interrupts are enabled
  373. ;
  374. %macro MAKE_GDT_DESC 4
  375. dw (%2 & 0xffff)
  376. dd %1
  377. db ((%4 & 0x0f) << 4) | ((%2 >> 16) & 0x0f)
  378. db (%3 & 0xff)
  379. %endmacro
  380.  
  381. ; Macro to build an initial IDT descriptor entry
  382. ; 3 parameters: offset, selector, access
  383. ;
  384. ; The generated descriptor entry will need to be fixed up at runtime
  385. ; before interrupts are enabled
  386. ;
  387. %macro MAKE_IDT_DESC 3
  388. dd %1
  389. db 0
  390. db (%3 & 0xFF)
  391. dw (%2 & 0xFFFF)
  392. %endmacro
  393.  
  394. ; GDT structure
  395. align 8
  396. gdt:
  397. .start:
  398. .null: MAKE_GDT_DESC 0, 0, 0, 0
  399. ; Null descriptor
  400. .code32_pl0: MAKE_GDT_DESC 0, 0x000FFFFF, 10011011b, 1100b
  401. ; 32-bit code, PL0, acc=1, r/x, gran=page
  402. ; Lim=0xffffffff
  403. .data32_pl0: MAKE_GDT_DESC 0, 0x000FFFFF, 10010011b, 1100b
  404. ; 32-bit data, PL0, acc=1, r/w, gran=page
  405. ; Lim=0xffffffff
  406. .code32_pl3: MAKE_GDT_DESC 0, 0x000FFFFF, 11111011b, 1100b
  407. ; 32-bit code, PL3, acc=1, r/x, gran=page
  408. ; Lim=0xffffffff
  409. .data32_pl3: MAKE_GDT_DESC 0, 0x000FFFFF, 11110011b, 1100b
  410. ; 32-bit data, PL3, acc=1, r/w, gran=page
  411. .tss32: MAKE_GDT_DESC tss_entry, TSS_SIZE-1, 10001001b, 0000b
  412. ; 32-bit TSS, gran=byte, available, IOPL=0
  413. .end:
  414. NUMGDTENTRIES equ ((gdt.end - gdt.start) / 8)
  415.  
  416. ; GDT record
  417. align 4
  418. dw 0 ; Padding align dd GDT in gdtr on 4 byte boundary
  419. .gdtr:
  420. dw .end - .start - 1 ; limit (Size of GDT - 1)
  421. dd .start ; base of GDT
  422.  
  423. NULL_SEL_RPL0 EQU 0
  424. NULL_SEL_RPL1 EQU 1
  425. NULL_SEL_RPL2 EQU 2
  426. NULL_SEL_RPL3 EQU 3
  427. CODE32_PL0_SEL EQU gdt.code32_pl0 - gdt.start
  428. DATA32_PL0_SEL EQU gdt.data32_pl0 - gdt.start
  429. CODE32_PL3_SEL EQU gdt.code32_pl3 - gdt.start
  430. DATA32_PL3_SEL EQU gdt.data32_pl3 - gdt.start
  431. TSS32_SEL EQU gdt.tss32 - gdt.start
  432.  
  433. align 16
  434. ; Create an IDT which handles exceptions
  435. idt:
  436. .start:
  437. MAKE_IDT_DESC exc_def_noerror, CODE32_PL0_SEL, 10001110b
  438. MAKE_IDT_DESC exc_def_noerror, CODE32_PL0_SEL, 10001110b
  439. MAKE_IDT_DESC exc_def_noerror, CODE32_PL0_SEL, 10001110b
  440. MAKE_IDT_DESC exc_def_noerror, CODE32_PL0_SEL, 10001110b
  441. MAKE_IDT_DESC exc_def_noerror, CODE32_PL0_SEL, 10001110b
  442. MAKE_IDT_DESC exc_def_noerror, CODE32_PL0_SEL, 10001110b
  443. ; Set undefined instruction exception to test an exception in ring 3
  444. ; MAKE_IDT_DESC exc_def_noerror, CODE32_PL0_SEL, 10001110b
  445. MAKE_IDT_DESC exc_ud2, CODE32_PL0_SEL, 10001110b
  446. MAKE_IDT_DESC exc_def_noerror, CODE32_PL0_SEL, 10001110b
  447. MAKE_IDT_DESC exc_def_error, CODE32_PL0_SEL, 10001110b
  448. MAKE_IDT_DESC exc_def_noerror, CODE32_PL0_SEL, 10001110b
  449. MAKE_IDT_DESC exc_def_error, CODE32_PL0_SEL, 10001110b
  450. MAKE_IDT_DESC exc_def_error, CODE32_PL0_SEL, 10001110b
  451. MAKE_IDT_DESC exc_def_error, CODE32_PL0_SEL, 10001110b
  452. MAKE_IDT_DESC exc_def_error, CODE32_PL0_SEL, 10001110b
  453. MAKE_IDT_DESC exc_def_error, CODE32_PL0_SEL, 10001110b
  454. MAKE_IDT_DESC exc_def_noerror, CODE32_PL0_SEL, 10001110b
  455.  
  456. MAKE_IDT_DESC exc_def_noerror, CODE32_PL0_SEL, 10001110b
  457. MAKE_IDT_DESC exc_def_error, CODE32_PL0_SEL, 10001110b
  458. MAKE_IDT_DESC exc_def_noerror, CODE32_PL0_SEL, 10001110b
  459. MAKE_IDT_DESC exc_def_noerror, CODE32_PL0_SEL, 10001110b
  460. MAKE_IDT_DESC exc_def_noerror, CODE32_PL0_SEL, 10001110b
  461. MAKE_IDT_DESC exc_def_error, CODE32_PL0_SEL, 10001110b
  462. MAKE_IDT_DESC exc_def_noerror, CODE32_PL0_SEL, 10001110b
  463. MAKE_IDT_DESC exc_def_noerror, CODE32_PL0_SEL, 10001110b
  464. MAKE_IDT_DESC exc_def_noerror, CODE32_PL0_SEL, 10001110b
  465. MAKE_IDT_DESC exc_def_noerror, CODE32_PL0_SEL, 10001110b
  466. MAKE_IDT_DESC exc_def_noerror, CODE32_PL0_SEL, 10001110b
  467. MAKE_IDT_DESC exc_def_noerror, CODE32_PL0_SEL, 10001110b
  468. MAKE_IDT_DESC exc_def_noerror, CODE32_PL0_SEL, 10001110b
  469. MAKE_IDT_DESC exc_def_error, CODE32_PL0_SEL, 10001110b
  470. MAKE_IDT_DESC exc_def_error, CODE32_PL0_SEL, 10001110b
  471. MAKE_IDT_DESC exc_def_noerror, CODE32_PL0_SEL, 10001110b
  472.  
  473. MAKE_IDT_DESC irq_def_master, CODE32_PL0_SEL, 10001110b ; IRQ0
  474. ; Set a keyboard handler for testing interrupts
  475. ; MAKE_IDT_DESC irq_def_master, CODE32_PL0_SEL, 10001110b ; IRQ1
  476. MAKE_IDT_DESC irq_keyboard, CODE32_PL0_SEL, 10001110b ; IRQ1
  477. MAKE_IDT_DESC irq_def_master, CODE32_PL0_SEL, 10001110b ; IRQ2
  478. MAKE_IDT_DESC irq_def_master, CODE32_PL0_SEL, 10001110b ; IRQ3
  479. MAKE_IDT_DESC irq_def_master, CODE32_PL0_SEL, 10001110b ; IRQ4
  480. MAKE_IDT_DESC irq_def_master, CODE32_PL0_SEL, 10001110b ; IRQ5
  481. MAKE_IDT_DESC irq_def_master, CODE32_PL0_SEL, 10001110b ; IRQ6
  482. MAKE_IDT_DESC irq_def_master, CODE32_PL0_SEL, 10001110b ; IRQ7
  483. MAKE_IDT_DESC irq_def_slave, CODE32_PL0_SEL, 10001110b ; IRQ8
  484. MAKE_IDT_DESC irq_def_slave, CODE32_PL0_SEL, 10001110b ; IRQ9
  485. MAKE_IDT_DESC irq_def_slave, CODE32_PL0_SEL, 10001110b ; IRQ10
  486. MAKE_IDT_DESC irq_def_slave, CODE32_PL0_SEL, 10001110b ; IRQ11
  487. MAKE_IDT_DESC irq_def_slave, CODE32_PL0_SEL, 10001110b ; IRQ12
  488. MAKE_IDT_DESC irq_def_slave, CODE32_PL0_SEL, 10001110b ; IRQ13
  489. MAKE_IDT_DESC irq_def_slave, CODE32_PL0_SEL, 10001110b ; IRQ14
  490. MAKE_IDT_DESC irq_def_slave, CODE32_PL0_SEL, 10001110b ; IRQ15
  491. .end:
  492. NUMIDTENTRIES equ ((idt.end - idt.start) / 8)
  493.  
  494. align 4
  495. .idtr:
  496. dw .end - .start - 1 ; limit (Size of IDT - 1)
  497. dd .start ; base of IDT
  498.  
  499. TSS_IO_BITMAP_SIZE EQU 0
  500. align 4
  501. tss_entry:
  502. .back_link: dd 0
  503. .esp0: dd 0x90000 ; Kernel stack pointer used on ring transitions
  504. .ss0: dd 0x10 ; Kernel stack segment used on ring transitions
  505. .esp1: dd 0
  506. .ss1: dd 0
  507. .esp2: dd 0
  508. .ss2: dd 0
  509. .cr3: dd 0
  510. .eip: dd 0
  511. .eflags: dd 0
  512. .eax: dd 0
  513. .ecx: dd 0
  514. .edx: dd 0
  515. .ebx: dd 0
  516. .esp: dd 0
  517. .ebp: dd 0
  518. .esi: dd 0
  519. .edi: dd 0
  520. .es: dd 0
  521. .cs: dd 0
  522. .ss: dd 0
  523. .ds: dd 0
  524. .fs: dd 0
  525. .gs: dd 0
  526. .ldt: dd 0
  527. .trap: dw 0
  528. .iomap_base:dw TSS_SIZE ; IOPB offset
  529. ;.cetssp: dd 0 ; Need this if CET is enabled
  530.  
  531. ; Insert any kernel defined task instance data here
  532. ; ...
  533.  
  534. ; If using VME (Virtual Mode extensions) there need to be an additional 32 bytes
  535. ; available immediately preceding iomap. If using VME uncomment next 2 lines
  536. ;.vmeintmap: ; If VME enabled uncomment this line and the next
  537. ;TIMES 32 db 0 ; 32*8 bits = 256 bits (one bit for each interrupt)
  538.  
  539. .iomap:
  540. TIMES TSS_IO_BITMAP_SIZE db 0x0
  541. ; IO bitmap (IOPB) size 8192 (8*8192=65536) representing
  542. ; all ports. An IO bitmap size of 0 would fault all IO
  543. ; port access if IOPL < CPL (CPL=3 with v8086)
  544. %if TSS_IO_BITMAP_SIZE > 0
  545. .iomap_pad: db 0xff ; Padding byte that has to be filled with 0xff
  546. ; To deal with issues on some CPUs when using an IOPB
  547. %endif
  548. TSS_SIZE EQU $-tss_entry
  549.  
  550.  
  551. BITS 32
  552.  
  553. ; Entry point for 32-bit mode
  554. ; Upon entry these have all been set:
  555. ; - CPU is running at Current Privilege Level (CPL) = 0 aka kernel mode
  556. ; - Interrupts are enabled (IF=1)
  557. ; - Direction Flag clear (DF=0)
  558.  
  559. protmode32_entry:
  560. mov eax, DATA32_PL3_SEL | 3 ; Set DS/ES/FS/GS/SS to a privilege level 3 data selector
  561. mov ds, eax
  562. mov es, eax
  563. mov fs, eax
  564. mov gs, eax
  565. mov eax, DATA32_PL0_SEL | 0 ; Set DS/ES/FS/GS/SS to a privilege level 0 data selector
  566. mov ss, eax
  567.  
  568. ; Load the TSS to allow for interrupts/exceptions while in User Mode (Ring3)
  569. mov eax, TSS32_SEL
  570. ltr ax
  571.  
  572. ; Remap Master PIC to 0x20, and Slave PIC to 0x28
  573. ; For testing disable all interrupts except keyboard
  574.  
  575. mov al, ICW1_INIT | ICW1_ICW4
  576. out PIC1_COMMAND, al
  577. out PIC2_COMMAND, al
  578.  
  579. ; ICW2
  580. mov al, PIC1_BASE ; Remap master PIC to 0x20
  581. out PIC1_DATA, al
  582. mov al, PIC2_BASE ; Remap slave PIC to 0x28
  583. out PIC2_DATA, al
  584.  
  585. ; ICW3
  586. mov al, 4
  587. out PIC1_DATA, al
  588. mov al, 2
  589. out PIC2_DATA, al
  590.  
  591. ; ICW4
  592. mov al, ICW4_8086
  593. out PIC1_DATA, al
  594. out PIC2_DATA, al
  595.  
  596. mov al, 0xFF ; Bits that are 1 disable interrupts, 0 = enable
  597. out PIC2_DATA, al ; Disable all interrupts on Slave PIC
  598. mov al, 0xFD ; Bits that are 1 disable interrupts, 0 = enable
  599. out PIC1_DATA, al ; Disable all interrupts on Master PIC except IRQ1
  600.  
  601. ; Change to ring 3 (user mode)
  602. mov eax, esp ; Save current ESP and use it as stack pointer in ring 3
  603. push DATA32_PL3_SEL | 3 ; User mode SS = 32 data segment with a DPL of 3, RPL=3
  604. push eax ; User mode ESP
  605. push 1<<EFLAGS_IF_BIT | 1<<1
  606. ; Reset all EFLAG bits to 0 except IF=1 and reserved bit 1
  607. push CODE32_PL3_SEL | 3 ; User mode CS = 32 code segment with a DPL of 3, RPL=3
  608. push .usermode ; User mode EIP - enter ring 3 at label '.usermode'
  609. iret ; Use IRET to perform ring transition from CPL 0 to CPL 3
  610.  
  611. .usermode:
  612. ; Write the letters "PM" (protected mode) to upper left hand corner of display
  613. ; starting at text video memory address 0xb8000 using white on magenta attribute
  614. mov dword [VIDEO_TEXT_ADDR], (ATTR_WHITE_ON_MAGENTA << 8 | 'M') << 16 | \
  615. (ATTR_WHITE_ON_MAGENTA << 8 | 'P')
  616.  
  617. ud2 ; Cause a #UD exception to test interrupts
  618. jmp $ ; Can't use HLT in Ring 3
  619.  
  620. ; Undefined instruction exception for testing an exception
  621. exc_ud2:
  622. mov esi, .ud2str
  623. mov edi, VIDEO_TEXT_ADDR+80*2
  624. mov ah, ATTR_WHITE_ON_MAGENTA
  625. call print_string
  626.  
  627. ; Skip the UD2 instruction that caused the fault
  628. add dword [esp], 2
  629. iret
  630. .ud2str: db "#UD exception", 0
  631.  
  632. ; Default IRQ handler for IRQs >= 8
  633. irq_def_slave:
  634. ; Send EOI to slave and then master PIC for IRQs >= 8
  635. mov al, PIC_EOI
  636. out PIC2_COMMAND, al
  637. out PIC1_COMMAND, al
  638. iret
  639.  
  640. ; Default IRQ handler for IRQs < 8
  641. irq_def_master:
  642. ; Send EOI to master PIC for IRQs < 8
  643. mov al, PIC_EOI
  644. out PIC1_COMMAND, al
  645. iret
  646.  
  647. ; Test keyboard handler
  648. irq_keyboard:
  649. ; Read scancode from port 0x60 and throw it away
  650. ; You'd normally process the key, but this is just for testing
  651. in al, 0x60
  652. mov al, PIC_EOI
  653. out PIC1_COMMAND, al
  654. iret
  655.  
  656. ; Default exception without an error code pushed by CPU
  657. exc_def_noerror:
  658. ; Do nothing and return
  659. iret
  660.  
  661. ; Default exception with an error code pushed by CPU
  662. exc_def_error:
  663. ; Remove error code automatically pushed by CPU to stack
  664. add esp, 4
  665. iret
  666.  
  667.  
  668. ; Function: print_string (32-bit protected mode)
  669. ; Print a string directly to video memory
  670. ;
  671. ; Inputs: ESI = Offset of address to print
  672. ; EDI = Video memory address to write to
  673. ; AH = Attribute to use when writing a character
  674. ;
  675. ; Clobbers: EAX, ESI, EDI
  676.  
  677. print_string:
  678. jmp .getch
  679. .repeat:
  680. stosw ; Print character with attribute
  681. .getch:
  682. lodsb ; Get character from string
  683. test al,al ; Have we reached end of string?
  684. jnz .repeat ; if not process next character
  685. .end:
  686. ret
  687.  
  688. kernel_end:
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement