common.h 17 KB

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