common.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  1. /* I really want this for the local labels.
  2. *
  3. * The major downside is that every register passed as argument requires `<>`:
  4. * http://stackoverflow.com/questions/19776992/gas-altmacro-macro-with-a-percent-sign-in-a-default-parameter-fails-with-oper/
  5. */
  6. .altmacro
  7. /* Helpers */
  8. .macro DBG
  9. mov %ax, 0x9000
  10. .endm
  11. /* Push registers ax, bx, cx and dx. Lightweight `pusha`. */
  12. .macro PUSH_ADX
  13. push %ax
  14. push %bx
  15. push %cx
  16. push %dx
  17. .endm
  18. /* Pop registers dx, cx, bx, ax. Inverse order from PUSH_ADX,
  19. * so this cancels that one.
  20. */
  21. .macro POP_DAX
  22. pop %dx
  23. pop %cx
  24. pop %bx
  25. pop %ax
  26. .endm
  27. .macro PUSH_EADX
  28. push %eax
  29. push %ebx
  30. push %ecx
  31. push %edx
  32. .endm
  33. .macro POP_EDAX
  34. pop %edx
  35. pop %ecx
  36. pop %ebx
  37. pop %eax
  38. .endm
  39. /* Convert the low nibble of a r8 reg to ASCII of 8-bit in-place.
  40. * reg: r8 to be converted
  41. * Output: stored in reg itself. Letters are uppercase.
  42. */
  43. .macro HEX_NIBBLE reg
  44. LOCAL letter, end
  45. cmp $10, \reg
  46. jae letter
  47. add $'0, \reg
  48. jmp end
  49. letter:
  50. /* 0x37 == 'A' - 10 */
  51. add $0x37, \reg
  52. end:
  53. .endm
  54. /* Convert a byte to hex ASCII value.
  55. * c: r/m8 byte to be converted
  56. * Output: two ASCII characters, is stored in `ah:al`
  57. * http://stackoverflow.com/questions/3853730/printing-hexadecimal-digits-with-assembly
  58. */
  59. .macro HEX c
  60. mov \c, %al
  61. mov \c, %ah
  62. shr $4, %al
  63. HEX_NIBBLE <%al>
  64. and $0x0F, %ah
  65. HEX_NIBBLE <%ah>
  66. .endm
  67. /* Structural. */
  68. /* Setup a sane initial state.
  69. *
  70. * Should be the first thing in every file.
  71. *
  72. * Discussion of what is needed exactly: http://stackoverflow.com/a/32509555/895245
  73. */
  74. .macro BEGIN
  75. LOCAL after_locals
  76. .code16
  77. cli
  78. /* Set %cs to 0. TODO Is that really needed? */
  79. ljmp $0, $1f
  80. 1:
  81. xor %ax, %ax
  82. /* We must zero %ds for any data access. */
  83. mov %ax, %ds
  84. /* TODO is it really need to clear all those segment registers, e.g. for BIOS calls? */
  85. mov %ax, %es
  86. mov %ax, %fs
  87. mov %ax, %gs
  88. /* TODO What to move into BP and SP?
  89. * http://stackoverflow.com/questions/10598802/which-value-should-be-used-for-sp-for-booting-process
  90. */
  91. mov %ax, %bp
  92. /* Automatically disables interrupts until the end of the next instruction. */
  93. mov %ax, %ss
  94. /* We should set SP because BIOS calls may depend on that. TODO confirm. */
  95. mov %bp, %sp
  96. /* Store the initial dl to load stage 2 later on. */
  97. mov %dl, initial_dl
  98. jmp after_locals
  99. initial_dl: .byte 0
  100. after_locals:
  101. .endm
  102. /* Load stage2 from disk to memory, and jump to it.
  103. *
  104. * To be used when the program does not fit in the 512 bytes.
  105. *
  106. * Sample usage:
  107. *
  108. * ....
  109. * STAGE2
  110. * Stage 2 code here.
  111. * ....
  112. */
  113. .macro STAGE2
  114. /* Defined in the linker script. */
  115. mov $__stage2_nsectors, %al
  116. mov $0x02, %ah
  117. mov $1f, %bx
  118. mov $0x0002, %cx
  119. mov $0x00, %dh
  120. mov initial_dl, %dl
  121. int $0x13
  122. jmp 1f
  123. .section .stage2
  124. 1:
  125. .endm
  126. /* Enter protected mode. Use the simplest GDT possible. */
  127. .macro PROTECTED_MODE
  128. /* Must come before they are used. */
  129. .equ CODE_SEG, 8
  130. .equ DATA_SEG, gdt_data - gdt_start
  131. /* Tell the processor where our Global Descriptor Table is in memory. */
  132. lgdt gdt_descriptor
  133. /* Set PE (Protection Enable) bit in CR0 (Control Register 0),
  134. * effectively entering protected mode.
  135. */
  136. mov %cr0, %eax
  137. orl $0x1, %eax
  138. mov %eax, %cr0
  139. ljmp $CODE_SEG, $protected_mode
  140. /* Our GDT contains:
  141. *
  142. * * a null entry to fill the unusable entry 0:
  143. * http://stackoverflow.com/questions/33198282/why-have-the-first-segment-descriptor-of-the-global-descriptor-table-contain-onl
  144. * * a code and data. Both are necessary, because:
  145. * +
  146. * --
  147. * ** it is impossible to write to the code segment
  148. * ** it is impossible execute the data segment
  149. * --
  150. * +
  151. * Both start at 0 and span the entire memory,
  152. * allowing us to access anything without problems.
  153. *
  154. * A real OS might have 2 extra segments: user data and code.
  155. *
  156. * This is the case for the Linux kernel.
  157. *
  158. * This is better than modifying the privilege bit of the GDT
  159. * as we'd have to reload it several times, losing cache.
  160. */
  161. gdt_start:
  162. gdt_null:
  163. .long 0x0
  164. .long 0x0
  165. gdt_code:
  166. .word 0xffff
  167. .word 0x0
  168. .byte 0x0
  169. .byte 0b10011010
  170. .byte 0b11001111
  171. .byte 0x0
  172. gdt_data:
  173. .word 0xffff
  174. .word 0x0
  175. .byte 0x0
  176. .byte 0b10010010
  177. .byte 0b11001111
  178. .byte 0x0
  179. gdt_end:
  180. gdt_descriptor:
  181. .word gdt_end - gdt_start
  182. .long gdt_start
  183. vga_current_line:
  184. .long 0
  185. .code32
  186. protected_mode:
  187. /* Setup the other segments.
  188. * Those movs are mandatory because they update the descriptor cache:
  189. * http://wiki.osdev.org/Descriptor_Cache
  190. */
  191. mov $DATA_SEG, %ax
  192. mov %ax, %ds
  193. mov %ax, %es
  194. mov %ax, %fs
  195. mov %ax, %gs
  196. mov %ax, %ss
  197. /* TODO detect the last memory address available properly.
  198. * It depends on how much RAM we have.
  199. */
  200. mov $0X7000, %ebp
  201. mov %ebp, %esp
  202. .endm
  203. /* Setup a single page directory, which give us 2^10 * 2^12 == 4MiB
  204. * of identity memory starting at address 0.
  205. * The currently executing code is inside that range, or else we'd jump somewhere and die.
  206. */
  207. .equ page_directory, __end_align_4k
  208. .equ page_table, __end_align_4k + 0x1000
  209. .macro SETUP_PAGING_4M
  210. LOCAL page_setup_start page_setup_end
  211. PUSH_EADX
  212. /* Page directory steup. */
  213. /* Set the top 20 address bits. */
  214. mov $page_table, %eax
  215. /* Zero out the 4 low flag bits of the second byte (top 20 are address). */
  216. and $0xF000, %ax
  217. mov %eax, page_directory
  218. /* Set flags for the first byte. */
  219. mov $0b00100111, %al
  220. mov %al, page_directory
  221. /* Page table setup. */
  222. mov $0, %eax
  223. mov $page_table, %ebx
  224. page_setup_start:
  225. cmp $0x400, %eax
  226. je page_setup_end
  227. /* Top 20 address bits. */
  228. mov %eax, %edx
  229. shl $12, %edx
  230. /* Set flag bits 0-7. We only set to 1:
  231. * * bit 0: Page present
  232. * * bit 1: Page is writable.
  233. * Might work without this as the permission also depends on CR0.WP.
  234. */
  235. mov $0b00000011, %dl
  236. /* Zero flag bits 8-11 */
  237. and $0xF0, %dh
  238. mov %edx, (%ebx)
  239. inc %eax
  240. add $4, %ebx
  241. jmp page_setup_start
  242. page_setup_end:
  243. POP_EDAX
  244. .endm
  245. /* * Turn paging on.
  246. * Registers are not saved because memory will be all messed up.
  247. *
  248. * ## cr3
  249. *
  250. * The cr3 register does have a format, it is not simply the address of the page directory:
  251. *
  252. * * 20 top bits: 4KiB address. Since those are the only address bits,
  253. * this implies that the page directory must be aligned to 4Kib.
  254. * * bits 3 and 4: TODO some function I don't understand yet
  255. * * all others: ignored
  256. *
  257. * Many tutorials simply ignore bits 3 and 4, and do a direct address mov to `cr3`.
  258. *
  259. * This sets the 20 top address bits to their correct value, and puts trash in bits 3 and 4,
  260. * but it generally works.
  261. */
  262. .macro PAGING_ON
  263. /* Tell the CPU where the page directory is. */
  264. mov $page_directory, %eax
  265. mov %eax, %cr3
  266. /* Turn paging on. */
  267. mov %cr0, %eax
  268. or $0x80000000, %eax
  269. mov %eax, %cr0
  270. .endm
  271. /* Turn paging off. */
  272. .macro PAGING_OFF
  273. mov %cr0, %eax
  274. and $0x7FFFFFFF, %eax
  275. mov %eax, %cr0
  276. .endm
  277. /* IDT */
  278. .macro IDT_START
  279. idt_start:
  280. .endm
  281. .macro IDT_END
  282. idt_end:
  283. /* Exact same structure as gdt_descriptor. */
  284. idt_descriptor:
  285. .word idt_end - idt_start
  286. .long idt_start
  287. .endm
  288. .macro IDT_ENTRY
  289. /* Low handler address.
  290. * It is impossible to write:
  291. * .word (handler & 0x0000FFFF)
  292. * as we would like:
  293. * http://stackoverflow.com/questions/18495765/invalid-operands-for-binary-and
  294. * because this address has to be split up into two.
  295. * So this must be done at runtime.
  296. * Why this design choice from Intel?! Weird.
  297. */
  298. .word 0
  299. /* Segment selector: byte offset into the GDT. */
  300. .word CODE_SEG
  301. /* Reserved 0. */
  302. .byte 0
  303. /* Flags. Format:
  304. * 1 bit: present. If 0 and this happens, triple fault.
  305. * 2 bits: ring level we will be called from.
  306. * 5 bits: fixed to 0xE.
  307. */
  308. .byte 0x8E
  309. /* High word of base. */
  310. .word 0
  311. .endm
  312. /* Skip n IDT entries, usually to set the Nth one next. */
  313. .macro IDT_SKIP n=1
  314. .skip n * 8
  315. .endm
  316. /* * index: r/m/imm32 Index of the entry to setup.
  317. * * handler: r/m/imm32 Address of the handler function.
  318. */
  319. .macro IDT_SETUP_ENTRY index, handler
  320. push %eax
  321. push %edx
  322. mov \index, %eax
  323. mov \handler, %edx
  324. mov %dx, idt_start(,%eax, 8)
  325. shr $16, %edx
  326. mov %dx, (idt_start + 6)(,%eax, 8)
  327. pop %edx
  328. pop %eax
  329. .endm
  330. /* Shamelessly copied from James Molloy's tutorial. */
  331. .macro ISR_NOERRCODE i
  332. isr\()\i:
  333. cli
  334. /* Push a dummy 0 for interrupts that don't push any code.
  335. * http://stackoverflow.com/questions/10581224/why-does-iret-from-a-page-fault-handler-generate-interrupt-13-general-protectio/33398064#33398064
  336. */
  337. push $0
  338. push $\i
  339. jmp interrupt_handler_stub
  340. .endm
  341. .macro ISR_ERRCODE i
  342. isr\()\i:
  343. cli
  344. push $\i
  345. jmp interrupt_handler_stub
  346. .endm
  347. /* Protected mode PIT number after remapping it. */
  348. #define PIT_ISR_NUMBER $0x20
  349. /* Entries and handlers.
  350. * 48 = 32 processor built-ins + 16 PIC interrupts.
  351. * In addition to including this, you should also call
  352. * * call IDT_SETUP_48_ISRS to setup the handler addreses.
  353. * * define an `interrupt_handler(uint32 number, uint32 error)` function
  354. */
  355. .macro IDT_48_ENTRIES
  356. /* IDT. */
  357. IDT_START
  358. .rept 48
  359. IDT_ENTRY
  360. .endr
  361. IDT_END
  362. /* ISRs */
  363. .irp i, 0, 1, 2, 3, 4, 5, 6, 7
  364. ISR_NOERRCODE \i
  365. .endr
  366. ISR_ERRCODE 8
  367. ISR_NOERRCODE 9
  368. .irp i, 10, 11, 12, 13, 14
  369. ISR_ERRCODE \i
  370. .endr
  371. .irp i, 15, 16, 17, 18, 19, \
  372. 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, \
  373. 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, \
  374. 40, 41, 42, 43, 44, 45, 46, 47, 48
  375. ISR_NOERRCODE \i
  376. .endr
  377. /* Factor out things which we will want to do in every handler. */
  378. interrupt_handler_stub:
  379. cli
  380. call interrupt_handler
  381. /* If we are a PIC interrupt (>=32), do an EOI. */
  382. cmp PIT_ISR_NUMBER, (%esp)
  383. jb interrupt_handler_stub.noeoi
  384. PIC_EOI
  385. interrupt_handler_stub.noeoi:
  386. add $8, %esp
  387. sti
  388. iret
  389. .endm
  390. .macro IDT_SETUP_48_ISRS
  391. .irp i, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, \
  392. 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, \
  393. 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, \
  394. 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, \
  395. 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, \
  396. 40, 41, 42, 43, 44, 45, 46, 47, 48
  397. IDT_SETUP_ENTRY $\i, $isr\()\i
  398. .endr
  399. lidt idt_descriptor
  400. .endm
  401. /* BIOS */
  402. .macro CURSOR_POSITION x=$0, y=$0
  403. PUSH_ADX
  404. mov $0x02, %ah
  405. mov $0x00, %bh
  406. mov \x, %dh
  407. mov \y, %dl
  408. int $0x10
  409. POP_DAX
  410. .endm
  411. /* Clear the screen, move to position 0, 0. */
  412. .macro CLEAR
  413. PUSH_ADX
  414. mov $0x0600, %ax
  415. mov $0x7, %bh
  416. mov $0x0, %cx
  417. mov $0x184f, %dx
  418. int $0x10
  419. CURSOR_POSITION
  420. POP_DAX
  421. .endm
  422. /* Print a 8 bit ASCII value at current cursor position.
  423. *
  424. * * `c`: r/m/imm8 ASCII value to be printed.
  425. *
  426. * Usage:
  427. *
  428. * ....
  429. * PUTC $'a
  430. * ....
  431. *
  432. * prints `a` to the screen.
  433. */
  434. .macro PUTC c=$0x20
  435. push %ax
  436. mov \c, %al
  437. mov $0x0E, %ah
  438. int $0x10
  439. pop %ax
  440. .endm
  441. /* Print a byte as two hexadecimal digits.
  442. *
  443. * * reg: 1 byte register.
  444. */
  445. .macro PRINT_HEX reg=<%al>
  446. push %ax
  447. HEX <\reg>
  448. PUTC <%al>
  449. PUTC <%ah>
  450. pop %ax
  451. .endm
  452. /* Print a 16-bit number
  453. *
  454. * * in: r/m/imm16
  455. */
  456. .macro PRINT_WORD_HEX in=<%ax>
  457. push %ax
  458. mov \in, %ax
  459. PRINT_HEX <%ah>
  460. PRINT_HEX <%al>
  461. pop %ax
  462. .endm
  463. .macro PRINT_NEWLINE
  464. PUTC $'\n
  465. PUTC $'\r
  466. .endm
  467. /* Print a null terminated string.
  468. *
  469. * Use as:
  470. *
  471. * ....
  472. * PRINT_STRING $s
  473. * hlt
  474. * s:
  475. * .asciz "string"
  476. * ....
  477. */
  478. .macro PRINT_STRING s
  479. LOCAL end, loop
  480. mov s, %si
  481. mov $0x0e, %ah
  482. cld
  483. loop:
  484. lodsb
  485. or %al, %al
  486. jz end
  487. int $0x10
  488. jmp loop
  489. end:
  490. .endm
  491. /* Dump memory:
  492. *
  493. * * s: starting address
  494. * * n: number of bytes to dump
  495. */
  496. .macro PRINT_BYTES s, n=$16
  497. LOCAL end, loop, no_newline
  498. PUSH_ADX
  499. push %di
  500. mov s, %si
  501. mov \n, %cx
  502. mov $0, %di
  503. cld
  504. loop:
  505. cmp $0, %cx
  506. je end
  507. dec %cx
  508. lodsb
  509. PRINT_HEX
  510. PUTC
  511. /* Print a newline for every 8 bytes. */
  512. mov $0, %dx
  513. mov %di, %ax
  514. mov $8, %bx
  515. div %bx
  516. cmp $7, %dx
  517. jne no_newline
  518. PRINT_NEWLINE
  519. no_newline:
  520. inc %di
  521. jmp loop
  522. end:
  523. pop %di
  524. POP_DAX
  525. .endm
  526. /* VGA */
  527. /* Print a NULL terminated string to position 0 in VGA.
  528. *
  529. * s: 32-bit register or memory containing the address of the string to print.
  530. *
  531. * Clobbers: none.
  532. *
  533. * Uses and updates vga_current_line to decide the current line.
  534. * Loops around the to the top.
  535. */
  536. .macro VGA_PRINT_STRING s
  537. LOCAL loop, end
  538. PUSH_EADX
  539. mov \s, %ecx
  540. mov vga_current_line, %eax
  541. mov $0, %edx
  542. /* Number of horizontal lines. */
  543. mov $25, %ebx
  544. div %ebx
  545. mov %edx, %eax
  546. /* 160 == 80 * 2 == line width * bytes per character on screen */
  547. mov $160, %edx
  548. mul %edx
  549. /* 0xb8000 == magic video memory address which shows on the screen. */
  550. lea 0xb8000(%eax), %edx
  551. /* White on black. */
  552. mov $0x0f, %ah
  553. loop:
  554. mov (%ecx), %al
  555. cmp $0, %al
  556. je end
  557. mov %ax, (%edx)
  558. add $1, %ecx
  559. add $2, %edx
  560. jmp loop
  561. end:
  562. incl vga_current_line
  563. POP_EDAX
  564. .endm
  565. /* Print a 32-bit r/m/immm in hex.
  566. *
  567. * Sample usage:
  568. *
  569. * ....
  570. * mov $12345678, %eax
  571. * VGA_PRINT_HEX_4 <%eax>
  572. * ....
  573. *
  574. * Expected output on screen:
  575. *
  576. * ....
  577. * 12345678
  578. * ....
  579. */
  580. .macro VGA_PRINT_HEX_4 in=<%eax>
  581. LOCAL loop
  582. PUSH_EADX
  583. /* Null terminator. */
  584. mov \in, %ecx
  585. /* Write ASCII representation to memory. */
  586. push $0
  587. mov $2, %ebx
  588. loop:
  589. HEX <%cl>
  590. mov %ax, %dx
  591. shl $16, %edx
  592. HEX <%ch>
  593. mov %ax, %dx
  594. push %edx
  595. shr $16, %ecx
  596. dec %ebx
  597. cmp $0, %ebx
  598. jne loop
  599. /* Print it. */
  600. mov %esp, %edx
  601. VGA_PRINT_STRING <%edx>
  602. /* Restore the stack. We have pushed 3 * 4 bytes. */
  603. add $12, %esp
  604. POP_EDAX
  605. .endm
  606. /* Dump memory.
  607. *
  608. * * s: starting address
  609. * * n: number of bytes to dump
  610. *
  611. * TODO implement. This is just a stub.
  612. */
  613. .macro VGA_PRINT_BYTES s, n=$16
  614. LOCAL end, loop, no_newline
  615. PUSH_ADX
  616. push %edi
  617. mov s, %esi
  618. mov \n, %ecx
  619. mov $0, %edi
  620. cld
  621. loop:
  622. cmp $0, %ecx
  623. je end
  624. dec %ecx
  625. lodsb
  626. PRINT_HEX
  627. PUTC
  628. /* Print a newline for every 8 bytes. */
  629. mov $0, %edx
  630. mov %di, %eax
  631. mov $8, %ebx
  632. div %ebx
  633. cmp $7, %edx
  634. jne no_newline
  635. /*VGA_PRINT_NEWLINE*/
  636. no_newline:
  637. inc %edi
  638. jmp loop
  639. end:
  640. pop %di
  641. POP_DAX
  642. .endm
  643. /* IO ports. */
  644. .macro OUTB value, port
  645. push %ax
  646. mov \value, %al
  647. out %al, \port
  648. pop %ax
  649. .endm
  650. #define PORT_PIC_MASTER_CMD $0x20
  651. #define PORT_PIC_MASTER_DATA $0x21
  652. #define PORT_PIT_CHANNEL0 $0x40
  653. #define PORT_PIT_MODE $0x43
  654. #define PORT_PIC_SLAVE_CMD $0xA0
  655. #define PORT_PIC_SLAVE_DATA $0xA1
  656. /* PIC */
  657. #define PIC_CMD_RESET $0x20
  658. #define PIC_ICR_ADDRESS $0xFEE00300
  659. /* EOI End Of Interrupt: PIC it will not fire again unless we reset it. */
  660. .macro PIC_EOI
  661. OUTB PIC_CMD_RESET, PORT_PIC_MASTER_CMD
  662. .endm
  663. .macro REMAP_PIC_32
  664. /* Remap the PIC interrupts to start at 32.
  665. * TODO understand.
  666. */
  667. OUTB $0x11, PORT_PIC_MASTER_CMD
  668. OUTB $0x11, PORT_PIC_SLAVE_CMD
  669. OUTB $0x20, PORT_PIC_MASTER_DATA
  670. OUTB $0x28, PORT_PIC_SLAVE_DATA
  671. OUTB $0x04, PORT_PIC_MASTER_DATA
  672. OUTB $0x02, PORT_PIC_SLAVE_DATA
  673. OUTB $0x01, PORT_PIC_MASTER_DATA
  674. OUTB $0x01, PORT_PIC_SLAVE_DATA
  675. OUTB $0x00, PORT_PIC_MASTER_DATA
  676. OUTB $0x00, PORT_PIC_SLAVE_DATA
  677. .endm
  678. /* PIT */
  679. #define PIT_FREQ 0x1234DD
  680. /* Set the minimum possible PIT frequency = 0x1234DD / 0xFFFF =~ 18.2 Hz
  681. * This is a human friendly frequency: you can see individual events,
  682. * but you don't have to wait much for each one.
  683. */
  684. .macro PIT_SET_MIN_FREQ
  685. push %eax
  686. mov $0xFF, %al
  687. out %al, PORT_PIT_CHANNEL0
  688. out %al, PORT_PIT_CHANNEL0
  689. pop %eax
  690. .endm
  691. /* We have to split the 2 ax bytes,
  692. * as we can only communicate one byte at a time here.
  693. * - freq: 16 bit compile time constant desired frequency.
  694. * Range: 19 - 0x1234DD.
  695. */
  696. .macro PIT_SET_FREQ freq
  697. push %eax
  698. mov $(PIT_FREQ / \freq), %ax
  699. out %al, PORT_PIT_CHANNEL0
  700. mov %ah, %al
  701. out %al, PORT_PIT_CHANNEL0
  702. pop %eax
  703. .endm
  704. /* Sleep for `ticks` ticks of the PIT at current frequency.
  705. * PIT_SLEEP_HANDLER_UPDATE must be placed in the PIT handler for this to work.
  706. * Currently only one can be used at a given time.
  707. */
  708. .macro PIT_SLEEP_TICKS ticks
  709. LOCAL loop
  710. movb $1, pit_sleep_ticks_locked
  711. movl \ticks, pit_sleep_ticks_count
  712. jmp loop
  713. loop:
  714. cmpb $0, pit_sleep_ticks_locked
  715. jne loop
  716. .endm
  717. /* Must be placed in the PIT handler for PIT_SLEEP_TICKS to work. */
  718. .macro PIT_SLEEP_TICKS_HANDLER_UPDATE
  719. LOCAL dont_unlock
  720. decl pit_sleep_ticks_count
  721. cmpl $0, pit_sleep_ticks_count
  722. jne dont_unlock
  723. movb $0, pit_sleep_ticks_locked
  724. dont_unlock:
  725. .endm
  726. .macro PIT_SLEEP_TICKS_GLOBALS
  727. pit_sleep_ticks_count:
  728. .long 0
  729. pit_sleep_ticks_locked:
  730. .byte 0
  731. .endm
  732. /* Define the properties of the wave:
  733. *
  734. * * Channel: 0
  735. * * access mode: lobyte/hibyte
  736. * * operating mode: rate generator
  737. * * BCD/binary: binary
  738. */
  739. .macro PIT_GENERATE_FREQUENCY
  740. OUTB $0b00110100, PORT_PIT_MODE
  741. .endm
  742. /* IVT */
  743. #define IVT_PIT 8
  744. #define IVT_HANDLER_SIZE 4
  745. #define IVT_CODE_OFFSET 2
  746. /* Setup interrupt handler 8: this is where the PIC maps IRQ 0 to. */
  747. .macro IVT_PIT_SETUP
  748. movw $handler, IVT_PIT * IVT_HANDLER_SIZE
  749. mov %cs, IVT_PIT * IVT_HANDLER_SIZE + IVT_CODE_OFFSET
  750. .endm