timer.c 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. #include "timer.h"
  2. #include "../lib/kernel/io.h"
  3. #include "../lib/kernel/print.h"
  4. #include "../thread/thread.h"
  5. #include "../kernel/debug.h"
  6. #include "../kernel/interrupt.h"
  7. /**
  8. * 8253定时器初始化 计数器的工作频率均是 1.19318MHz
  9. * 通过控制字指定使用计数器 0,工作方式 2,
  10. * 然后写入初始值 1193180/ 中断信号的频率=计数器的初始值
  11. * 设置 中断信号的频率=100Hz
  12. */
  13. #define IRQ0_FREQUENCY 100
  14. #define INPUT_FREQUENCY 1193180
  15. #define COUNTER0_VALUE INPUT_FREQUENCY / IRQ0_FREQUENCY
  16. #define COUNTER0_PORT 0x40
  17. #define COUNTER0_NO 0
  18. #define COUNTER_MODE 2
  19. #define READ_WRITE_LATCH 3
  20. #define PIT_CONTROL_PORT 0x43
  21. uint32_t ticks; // ticks 是内核自中断开启以来总共的嘀嗒数
  22. /// @brief 时钟中断处理函数
  23. static void intr_timer_handler(void)
  24. {
  25. struct task_struct *cur_thread = running_thread();
  26. ASSERT(cur_thread->stack_magic == 0x19940625); // 检查栈是否溢出
  27. cur_thread->elapsed_ticks++; // 记录此线程占用的 CPU 时间嘀嗒数
  28. ticks++; // 内核态的嘀嗒数
  29. if (cur_thread->ticks == 0)
  30. { // 若进程时间片用完就开始调度新的进程上 CPU
  31. schedule();
  32. }
  33. else
  34. {
  35. cur_thread->ticks--; // 将当前进程的时间片-1
  36. }
  37. }
  38. /// @brief 设置计数器
  39. /// @param counter_port 操作的计数器端口
  40. /// @param counter_no 计数器编号
  41. /// @param rwl 读写锁属性
  42. /// @param counter_mode 模式
  43. /// @param counter_value 初始化值
  44. static void frequency_set(uint8_t counter_port, uint8_t counter_no, uint8_t rwl, uint8_t counter_mode, uint16_t counter_value)
  45. {
  46. // 先往控制字寄存器端口写入控制字
  47. outb(PIT_CONTROL_PORT, (uint8_t)(counter_no << 6 | rwl << 4 | counter_mode << 1));
  48. // 先写入计数器的低8位
  49. outb(counter_port, (uint8_t)counter_value);
  50. // 再写入计数器的高8位
  51. outb(counter_port, (uint8_t)counter_value >> 8);
  52. }
  53. /* 初始化 PIT 8235 */
  54. void timer_init(void)
  55. {
  56. put_str("timer_init start\n");
  57. // 设置计数器 0,工作方式 2,初始值 1193180/100=11931,即每 10ms 发送一次时钟中断
  58. frequency_set(COUNTER0_PORT, COUNTER0_NO, READ_WRITE_LATCH, COUNTER_MODE, COUNTER0_VALUE);
  59. register_handler(0x20, intr_timer_handler);
  60. put_str("timer_init done\n");
  61. }