common.h 18 KB

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