printk.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959
  1. //
  2. // Created by longjin on 2022/1/22.
  3. //
  4. #include "printk.h"
  5. #include "kprint.h"
  6. #include <driver/multiboot2/multiboot2.h>
  7. #include <mm/mm.h>
  8. #include <process/spinlock.h>
  9. #include <driver/uart/uart.h>
  10. #include <driver/video/video.h>
  11. #include "math.h"
  12. struct printk_screen_info pos;
  13. extern ul VBE_FB_phys_addr; // 由bootloader传来的帧缓存区的物理地址
  14. static spinlock_t printk_lock;
  15. static bool sw_show_scroll_animation = false; // 显示换行动画的开关
  16. /**
  17. * @brief Set the printk pos object
  18. *
  19. * @param x 列坐标
  20. * @param y 行坐标
  21. */
  22. static int set_printk_pos(const int x, const int y);
  23. /**
  24. * @brief 在屏幕上指定位置打印字符
  25. *
  26. * @param fb 帧缓存线性地址
  27. * @param Xsize 行分辨率
  28. * @param x 左上角列像素点位置
  29. * @param y 左上角行像素点位置
  30. * @param FRcolor 字体颜色
  31. * @param BKcolor 背景颜色
  32. * @param font 字符的bitmap
  33. */
  34. static void putchar(uint *fb, int Xsize, int x, int y, unsigned int FRcolor, unsigned int BKcolor, unsigned char font);
  35. static uint *get_pos_VBE_FB_addr();
  36. /**
  37. * @brief 清屏
  38. *
  39. */
  40. static int cls();
  41. /**
  42. * @brief 滚动窗口(尚不支持向下滚动)
  43. *
  44. * @param direction 方向,向上滑动为true,否则为false
  45. * @param pixels 要滑动的像素数量
  46. * @param animation 是否包含滑动动画
  47. */
  48. static int scroll(bool direction, int pixels, bool animation);
  49. /**
  50. * @brief 将数字按照指定的要求转换成对应的字符串(2~36进制)
  51. *
  52. * @param str 要返回的字符串
  53. * @param num 要打印的数值
  54. * @param base 基数
  55. * @param field_width 区域宽度
  56. * @param precision 精度
  57. * @param flags 标志位
  58. */
  59. static char *write_num(char *str, ul num, int base, int field_width, int precision, int flags);
  60. static char *write_float_point_num(char *str, double num, int field_width, int precision, int flags);
  61. static int calculate_max_charNum(int len, int size)
  62. {
  63. /**
  64. * @brief 计算屏幕上能有多少行
  65. * @param len 屏幕长/宽
  66. * @param size 字符长/宽
  67. */
  68. return len / size - 1;
  69. }
  70. int printk_init(const int char_size_x, const int char_size_y)
  71. {
  72. struct multiboot_tag_framebuffer_info_t info;
  73. int reserved;
  74. multiboot2_iter(multiboot2_get_Framebuffer_info, &info, &reserved);
  75. pos.width = info.framebuffer_width;
  76. pos.height = info.framebuffer_height;
  77. pos.char_size_x = char_size_x;
  78. pos.char_size_y = char_size_y;
  79. pos.max_x = calculate_max_charNum(pos.width, char_size_x);
  80. pos.max_y = calculate_max_charNum(pos.height, char_size_y);
  81. VBE_FB_phys_addr = (ul)info.framebuffer_addr;
  82. pos.FB_address = (uint *)0xffff800003000000;
  83. pos.FB_length = 1UL * pos.width * pos.height;
  84. // 初始化自旋锁
  85. spin_init(&printk_lock);
  86. // ======== 临时的将物理地址填写到0x0000000003000000处 之后会在mm内将帧缓存区重新映射=====
  87. ul global_CR3 = (ul)get_CR3();
  88. ul fb_virt_addr = (ul)pos.FB_address;
  89. ul fb_phys_addr = VBE_FB_phys_addr;
  90. // 计算帧缓冲区的线性地址对应的pml4页表项的地址
  91. ul *tmp = phys_2_virt((ul *)((ul)global_CR3 & (~0xfffUL)) + ((fb_virt_addr >> PAGE_GDT_SHIFT) & 0x1ff));
  92. tmp = phys_2_virt((ul *)(*tmp & (~0xfffUL)) + ((fb_virt_addr >> PAGE_1G_SHIFT) & 0x1ff));
  93. ul *tmp1;
  94. // 初始化2M物理页
  95. for (ul i = 0; i < (pos.FB_length << 2); i += PAGE_2M_SIZE)
  96. {
  97. // 计算当前2M物理页对应的pdt的页表项的物理地址
  98. tmp1 = phys_2_virt((ul *)(*tmp & (~0xfffUL)) + (((fb_virt_addr + i) >> PAGE_2M_SHIFT) & 0x1ff));
  99. // 页面写穿,禁止缓存
  100. set_pdt(tmp1, mk_pdt((ul)fb_phys_addr + i, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD));
  101. }
  102. flush_tlb();
  103. pos.x = 0;
  104. pos.y = 0;
  105. cls();
  106. kdebug("width=%d\theight=%d", pos.width, pos.height);
  107. // 由于此时系统并未启用双缓冲,因此关闭滚动动画
  108. printk_disable_animation();
  109. return 0;
  110. }
  111. static int set_printk_pos(const int x, const int y)
  112. {
  113. // 指定的坐标不在屏幕范围内
  114. if (!((x >= 0 && x <= pos.max_x) && (y >= 0 && y <= pos.max_y)))
  115. return EPOS_OVERFLOW;
  116. pos.x = x;
  117. pos.y = y;
  118. return 0;
  119. }
  120. static int skip_and_atoi(const char **s)
  121. {
  122. /**
  123. * @brief 获取连续的一段字符对应整数的值
  124. * @param:**s 指向 指向字符串的指针 的指针
  125. */
  126. int ans = 0;
  127. while (is_digit(**s))
  128. {
  129. ans = ans * 10 + (**s) - '0';
  130. ++(*s);
  131. }
  132. return ans;
  133. }
  134. static void auto_newline()
  135. {
  136. /**
  137. * @brief 超过每行最大字符数,自动换行
  138. *
  139. */
  140. if (pos.x > pos.max_x)
  141. {
  142. #ifdef DEBUG
  143. uart_send(COM1, '\r');
  144. uart_send(COM1, '\n');
  145. #endif
  146. pos.x = 0;
  147. ++pos.y;
  148. }
  149. if (pos.y > pos.max_y)
  150. {
  151. #ifdef DEBUG
  152. uart_send(COM1, '\r');
  153. uart_send(COM1, '\n');
  154. #endif
  155. pos.y = pos.max_y;
  156. int lines_to_scroll = 1;
  157. scroll(true, lines_to_scroll * pos.char_size_y, sw_show_scroll_animation);
  158. pos.y -= (lines_to_scroll - 1);
  159. }
  160. }
  161. int vsprintf(char *buf, const char *fmt, va_list args)
  162. {
  163. /**
  164. * 将字符串按照fmt和args中的内容进行格式化,然后保存到buf中
  165. * @param buf 结果缓冲区
  166. * @param fmt 格式化字符串
  167. * @param args 内容
  168. * @return 最终字符串的长度
  169. */
  170. char *str, *s;
  171. str = buf;
  172. int flags; // 用来存储格式信息的bitmap
  173. int field_width; //区域宽度
  174. int precision; //精度
  175. int qualifier; //数据显示的类型
  176. int len;
  177. //开始解析字符串
  178. for (; *fmt; ++fmt)
  179. {
  180. //内容不涉及到格式化,直接输出
  181. if (*fmt != '%')
  182. {
  183. *str = *fmt;
  184. ++str;
  185. continue;
  186. }
  187. //开始格式化字符串
  188. //清空标志位和field宽度
  189. field_width = flags = 0;
  190. bool flag_tmp = true;
  191. bool flag_break = false;
  192. ++fmt;
  193. while (flag_tmp)
  194. {
  195. switch (*fmt)
  196. {
  197. case '\0':
  198. //结束解析
  199. flag_break = true;
  200. flag_tmp = false;
  201. break;
  202. case '-':
  203. // 左对齐
  204. flags |= LEFT;
  205. ++fmt;
  206. break;
  207. case '+':
  208. //在正数前面显示加号
  209. flags |= PLUS;
  210. ++fmt;
  211. break;
  212. case ' ':
  213. flags |= SPACE;
  214. ++fmt;
  215. break;
  216. case '#':
  217. //在八进制数前面显示 '0o',在十六进制数前面显示 '0x' 或 '0X'
  218. flags |= SPECIAL;
  219. ++fmt;
  220. break;
  221. case '0':
  222. //显示的数字之前填充‘0’来取代空格
  223. flags |= PAD_ZERO;
  224. ++fmt;
  225. break;
  226. default:
  227. flag_tmp = false;
  228. break;
  229. }
  230. }
  231. if (flag_break)
  232. break;
  233. //获取区域宽度
  234. field_width = -1;
  235. if (*fmt == '*')
  236. {
  237. field_width = va_arg(args, int);
  238. ++fmt;
  239. }
  240. else if (is_digit(*fmt))
  241. {
  242. field_width = skip_and_atoi(&fmt);
  243. if (field_width < 0)
  244. {
  245. field_width = -field_width;
  246. flags |= LEFT;
  247. }
  248. }
  249. //获取小数精度
  250. precision = -1;
  251. if (*fmt == '.')
  252. {
  253. ++fmt;
  254. if (*fmt == '*')
  255. {
  256. precision = va_arg(args, int);
  257. ++fmt;
  258. }
  259. else if is_digit (*fmt)
  260. {
  261. precision = skip_and_atoi(&fmt);
  262. }
  263. }
  264. //获取要显示的数据的类型
  265. if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'Z')
  266. {
  267. qualifier = *fmt;
  268. ++fmt;
  269. }
  270. //为了支持lld
  271. if (qualifier == 'l' && *fmt == 'l', *(fmt + 1) == 'd')
  272. ++fmt;
  273. //转化成字符串
  274. long long *ip;
  275. switch (*fmt)
  276. {
  277. //输出 %
  278. case '%':
  279. *str++ = '%';
  280. break;
  281. // 显示一个字符
  282. case 'c':
  283. //靠右对齐
  284. if (!(flags & LEFT))
  285. {
  286. while (--field_width > 0)
  287. {
  288. *str = ' ';
  289. ++str;
  290. }
  291. }
  292. *str++ = (unsigned char)va_arg(args, int);
  293. while (--field_width > 0)
  294. {
  295. *str = ' ';
  296. ++str;
  297. }
  298. break;
  299. //显示一个字符串
  300. case 's':
  301. s = va_arg(args, char *);
  302. if (!s)
  303. s = '\0';
  304. len = strlen(s);
  305. if (precision < 0)
  306. {
  307. //未指定精度
  308. precision = len;
  309. }
  310. else if (len > precision)
  311. {
  312. len = precision;
  313. }
  314. //靠右对齐
  315. if (!(flags & LEFT))
  316. while (len < field_width--)
  317. {
  318. *str = ' ';
  319. ++str;
  320. }
  321. for (int i = 0; i < len; i++)
  322. {
  323. *str = *s;
  324. ++s;
  325. ++str;
  326. }
  327. while (len < field_width--)
  328. {
  329. *str = ' ';
  330. ++str;
  331. }
  332. break;
  333. //以八进制显示字符串
  334. case 'o':
  335. flags |= SMALL;
  336. case 'O':
  337. flags |= SPECIAL;
  338. if (qualifier == 'l')
  339. str = write_num(str, va_arg(args, long long), 8, field_width, precision, flags);
  340. else
  341. str = write_num(str, va_arg(args, int), 8, field_width, precision, flags);
  342. break;
  343. //打印指针指向的地址
  344. case 'p':
  345. if (field_width == 0)
  346. {
  347. field_width = 2 * sizeof(void *);
  348. flags |= PAD_ZERO;
  349. }
  350. str = write_num(str, (unsigned long)va_arg(args, void *), 16, field_width, precision, flags);
  351. break;
  352. //打印十六进制
  353. case 'x':
  354. flags |= SMALL;
  355. case 'X':
  356. // flags |= SPECIAL;
  357. if (qualifier == 'l')
  358. str = write_num(str, va_arg(args, ll), 16, field_width, precision, flags);
  359. else
  360. str = write_num(str, va_arg(args, int), 16, field_width, precision, flags);
  361. break;
  362. //打印十进制有符号整数
  363. case 'i':
  364. case 'd':
  365. flags |= SIGN;
  366. if (qualifier == 'l')
  367. str = write_num(str, va_arg(args, long long), 10, field_width, precision, flags);
  368. else
  369. str = write_num(str, va_arg(args, int), 10, field_width, precision, flags);
  370. break;
  371. //打印十进制无符号整数
  372. case 'u':
  373. if (qualifier == 'l')
  374. str = write_num(str, va_arg(args, unsigned long long), 10, field_width, precision, flags);
  375. else
  376. str = write_num(str, va_arg(args, unsigned int), 10, field_width, precision, flags);
  377. break;
  378. //输出有效字符数量到*ip对应的变量
  379. case 'n':
  380. if (qualifier == 'l')
  381. ip = va_arg(args, long long *);
  382. else
  383. ip = (ll *)va_arg(args, int *);
  384. *ip = str - buf;
  385. break;
  386. case 'f':
  387. // 默认精度为3
  388. // printk("1111\n");
  389. // va_arg(args, double);
  390. // printk("222\n");
  391. if (precision < 0)
  392. precision = 3;
  393. str = write_float_point_num(str, va_arg(args, double), field_width, precision, flags);
  394. break;
  395. //对于不识别的控制符,直接输出
  396. default:
  397. *str++ = '%';
  398. if (*fmt)
  399. *str++ = *fmt;
  400. else
  401. --fmt;
  402. break;
  403. }
  404. }
  405. *str = '\0';
  406. //返回缓冲区已有字符串的长度。
  407. return str - buf;
  408. }
  409. static char *write_num(char *str, ul num, int base, int field_width, int precision, int flags)
  410. {
  411. /**
  412. * @brief 将数字按照指定的要求转换成对应的字符串
  413. *
  414. * @param str 要返回的字符串
  415. * @param num 要打印的数值
  416. * @param base 基数
  417. * @param field_width 区域宽度
  418. * @param precision 精度
  419. * @param flags 标志位
  420. */
  421. // 首先判断是否支持该进制
  422. if (base < 2 || base > 36)
  423. return 0;
  424. char pad, sign, tmp_num[100];
  425. const char *digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  426. // 显示小写字母
  427. if (flags & SMALL)
  428. digits = "0123456789abcdefghijklmnopqrstuvwxyz";
  429. if (flags & LEFT)
  430. flags &= ~PAD_ZERO;
  431. // 设置填充元素
  432. pad = (flags & PAD_ZERO) ? '0' : ' ';
  433. sign = 0;
  434. if (flags & SIGN)
  435. {
  436. int64_t signed_num = (int64_t)num;
  437. if (signed_num < 0)
  438. {
  439. sign = '-';
  440. num = -signed_num;
  441. }
  442. else
  443. num = signed_num;
  444. }
  445. else
  446. {
  447. // 设置符号
  448. sign = (flags & PLUS) ? '+' : ((flags & SPACE) ? ' ' : 0);
  449. }
  450. // sign占用了一个宽度
  451. if (sign)
  452. --field_width;
  453. if (flags & SPECIAL)
  454. if (base == 16) // 0x占用2个位置
  455. field_width -= 2;
  456. else if (base == 8) // O占用一个位置
  457. --field_width;
  458. int js_num = 0; // 临时数字字符串tmp_num的长度
  459. if (num == 0)
  460. tmp_num[js_num++] = '0';
  461. else
  462. {
  463. num = ABS(num);
  464. //进制转换
  465. while (num > 0)
  466. {
  467. tmp_num[js_num++] = digits[num % base]; // 注意这里,输出的数字,是小端对齐的。低位存低位
  468. num /= base;
  469. }
  470. }
  471. if (js_num > precision)
  472. precision = js_num;
  473. field_width -= precision;
  474. // 靠右对齐
  475. if (!(flags & (LEFT + PAD_ZERO)))
  476. while (field_width-- > 0)
  477. *str++ = ' ';
  478. if (sign)
  479. *str++ = sign;
  480. if (flags & SPECIAL)
  481. if (base == 16)
  482. {
  483. *str++ = '0';
  484. *str++ = digits[33];
  485. }
  486. else if (base == 8)
  487. *str++ = digits[24]; //注意这里是英文字母O或者o
  488. if (!(flags & LEFT))
  489. while (field_width-- > 0)
  490. *str++ = pad;
  491. while (js_num < precision)
  492. {
  493. --precision;
  494. *str++ = '0';
  495. }
  496. while (js_num-- > 0)
  497. *str++ = tmp_num[js_num];
  498. while (field_width-- > 0)
  499. *str++ = ' ';
  500. return str;
  501. }
  502. static char *write_float_point_num(char *str, double num, int field_width, int precision, int flags)
  503. {
  504. /**
  505. * @brief 将浮点数按照指定的要求转换成对应的字符串
  506. *
  507. * @param str 要返回的字符串
  508. * @param num 要打印的数值
  509. * @param field_width 区域宽度
  510. * @param precision 精度
  511. * @param flags 标志位
  512. */
  513. char pad, sign, tmp_num_z[100], tmp_num_d[350];
  514. const char *digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  515. // 显示小写字母
  516. if (flags & SMALL)
  517. digits = "0123456789abcdefghijklmnopqrstuvwxyz";
  518. // 设置填充元素
  519. pad = (flags & PAD_ZERO) ? '0' : ' ';
  520. sign = 0;
  521. if (flags & SIGN && num < 0)
  522. {
  523. sign = '-';
  524. num = -num;
  525. }
  526. else
  527. {
  528. // 设置符号
  529. sign = (flags & PLUS) ? '+' : ((flags & SPACE) ? ' ' : 0);
  530. }
  531. // sign占用了一个宽度
  532. if (sign)
  533. --field_width;
  534. int js_num_z = 0, js_num_d = 0; // 临时数字字符串tmp_num_z tmp_num_d的长度
  535. uint64_t num_z = (uint64_t)(num); // 获取整数部分
  536. uint64_t num_decimal = (uint64_t)(round(1.0 * (num - num_z) * pow(10, precision))); // 获取小数部分
  537. if (num == 0 || num_z == 0)
  538. tmp_num_z[js_num_z++] = '0';
  539. else
  540. {
  541. //存储整数部分
  542. while (num_z > 0)
  543. {
  544. tmp_num_z[js_num_z++] = digits[num_z % 10]; // 注意这里,输出的数字,是小端对齐的。低位存低位
  545. num_z /= 10;
  546. }
  547. }
  548. while (num_decimal > 0)
  549. {
  550. tmp_num_d[js_num_d++] = digits[num_decimal % 10];
  551. num_decimal /= 10;
  552. }
  553. field_width -= (precision + 1 + js_num_z);
  554. // 靠右对齐
  555. if (!(flags & LEFT))
  556. while (field_width-- > 0)
  557. *str++ = pad;
  558. if (sign)
  559. *str++ = sign;
  560. // 输出整数部分
  561. // while (js_num_z-- > 0)
  562. // *str++ = tmp_num_z[js_num_z];
  563. while (js_num_z > 0)
  564. {
  565. *str++ = tmp_num_z[js_num_z - 1];
  566. --js_num_z;
  567. }
  568. *str++ = '.';
  569. // 输出小数部分
  570. int total_dec_count = js_num_d;
  571. for (int i = 0; i < precision && js_num_d-- > 0; ++i)
  572. *str++ = tmp_num_d[js_num_d];
  573. while (total_dec_count < precision)
  574. {
  575. ++total_dec_count;
  576. *str++ = '0';
  577. }
  578. while (field_width-- > 0)
  579. *str++ = ' ';
  580. return str;
  581. }
  582. static void putchar(uint *fb, int Xsize, int x, int y, unsigned int FRcolor, unsigned int BKcolor, unsigned char font)
  583. {
  584. /**
  585. * @brief 在屏幕上指定位置打印字符
  586. *
  587. * @param fb 帧缓存线性地址
  588. * @param Xsize 行分辨率
  589. * @param x 左上角列像素点位置
  590. * @param y 左上角行像素点位置
  591. * @param FRcolor 字体颜色
  592. * @param BKcolor 背景颜色
  593. * @param font 字符的bitmap
  594. */
  595. //#if DEBUG
  596. uart_send(COM1, font);
  597. //#endif
  598. unsigned char *font_ptr = font_ascii[font];
  599. unsigned int *addr;
  600. int testbit; // 用来测试某位是背景还是字体本身
  601. for (int i = 0; i < pos.char_size_y; ++i)
  602. {
  603. // 计算出帧缓冲区的地址
  604. addr = fb + Xsize * (y + i) + x;
  605. testbit = (1 << (pos.char_size_x + 1));
  606. for (int j = 0; j < pos.char_size_x; ++j)
  607. {
  608. //从左往右逐个测试相应位
  609. testbit >>= 1;
  610. if (*font_ptr & testbit)
  611. *addr = FRcolor; // 字,显示前景色
  612. else
  613. *addr = BKcolor; // 背景色
  614. ++addr;
  615. }
  616. ++font_ptr;
  617. }
  618. }
  619. /**
  620. * @brief 格式化打印字符串
  621. *
  622. * @param FRcolor 前景色
  623. * @param BKcolor 背景色
  624. * @param ... 格式化字符串
  625. */
  626. int printk_color(unsigned int FRcolor, unsigned int BKcolor, const char *fmt, ...)
  627. {
  628. uint64_t rflags = 0; // 加锁后rflags存储到这里
  629. spin_lock_irqsave(&printk_lock, rflags);
  630. va_list args;
  631. va_start(args, fmt);
  632. char buf[4096]; // vsprintf()的缓冲区
  633. int len = vsprintf(buf, fmt, args);
  634. va_end(args);
  635. unsigned char current;
  636. int i; // 总共输出的字符数
  637. for (i = 0; i < len; ++i)
  638. {
  639. current = *(buf + i);
  640. //输出换行
  641. if (current == '\n')
  642. {
  643. pos.x = 0;
  644. ++pos.y;
  645. auto_newline();
  646. }
  647. else if (current == '\t') // 输出制表符
  648. {
  649. int space_to_print = 8 - pos.x % 8;
  650. while (space_to_print--)
  651. {
  652. putchar(pos.FB_address, pos.width, pos.x * pos.char_size_x, pos.y * pos.char_size_y, FRcolor, BKcolor, ' ');
  653. ++pos.x;
  654. auto_newline();
  655. }
  656. }
  657. else if (current == '\b') // 退格
  658. {
  659. --pos.x;
  660. if (pos.x < 0)
  661. {
  662. --pos.y;
  663. if (pos.y <= 0)
  664. pos.x = pos.y = 0;
  665. else
  666. pos.x = pos.max_x;
  667. }
  668. putchar(pos.FB_address, pos.width, pos.x * pos.char_size_x, pos.y * pos.char_size_y, FRcolor, BKcolor, ' ');
  669. auto_newline();
  670. }
  671. else
  672. {
  673. putchar(pos.FB_address, pos.width, pos.x * pos.char_size_x, pos.y * pos.char_size_y, FRcolor, BKcolor, current);
  674. ++pos.x;
  675. auto_newline();
  676. }
  677. }
  678. spin_unlock_irqrestore(&printk_lock, rflags);
  679. return i;
  680. }
  681. int do_scroll(bool direction, int pixels)
  682. {
  683. if (direction == true) // 向上滚动
  684. {
  685. pixels = pixels;
  686. if (pixels > pos.height)
  687. return EPOS_OVERFLOW;
  688. // 无需滚动
  689. if (pixels == 0)
  690. return 0;
  691. unsigned int src = pixels * pos.width;
  692. unsigned int count = pos.FB_length - src;
  693. memcpy(pos.FB_address, (pos.FB_address + src), sizeof(unsigned int) * (pos.FB_length - src));
  694. memset(pos.FB_address + (pos.FB_length - src), 0, sizeof(unsigned int) * (src));
  695. return 0;
  696. }
  697. else
  698. return EUNSUPPORTED;
  699. return 0;
  700. }
  701. /**
  702. * @brief 滚动窗口(尚不支持向下滚动)
  703. *
  704. * @param direction 方向,向上滑动为true,否则为false
  705. * @param pixels 要滑动的像素数量
  706. * @param animation 是否包含滑动动画
  707. */
  708. static int scroll(bool direction, int pixels, bool animation)
  709. {
  710. // 暂时不支持反方向滚动
  711. if (direction == false)
  712. return EUNSUPPORTED;
  713. // 为了保证打印字符正确,需要对pixel按照字体高度对齐
  714. int md = pixels % pos.char_size_y;
  715. if (md)
  716. pixels = pixels + pos.char_size_y - md;
  717. if (animation == false)
  718. return do_scroll(direction, pixels);
  719. else
  720. {
  721. int steps;
  722. if (pixels > 10)
  723. steps = 5;
  724. else
  725. steps = pixels % 10;
  726. int half_steps = steps / 2;
  727. // 计算加速度
  728. double accelerate = 0.5 * pixels / (half_steps * half_steps);
  729. int current_pixels = 0;
  730. double delta_x;
  731. int trace[13] = {0};
  732. int js_trace = 0;
  733. // 加速阶段
  734. for (int i = 1; i <= half_steps; ++i)
  735. {
  736. trace[js_trace] = (int)(accelerate * i + 0.5);
  737. current_pixels += trace[js_trace];
  738. do_scroll(direction, trace[js_trace]);
  739. ++js_trace;
  740. }
  741. // 强制使得位置位于1/2*pixels
  742. if (current_pixels < pixels / 2)
  743. {
  744. delta_x = pixels / 2 - current_pixels;
  745. current_pixels += delta_x;
  746. do_scroll(direction, delta_x);
  747. }
  748. // 减速阶段,是加速阶段的重放
  749. for (int i = js_trace - 1; i >= 0; --i)
  750. {
  751. current_pixels += trace[i];
  752. do_scroll(direction, trace[i]);
  753. }
  754. if (current_pixels > pixels)
  755. kerror("During scrolling: scrolled pixels over bound!");
  756. // 强制使得位置位于pixels
  757. if (current_pixels < pixels)
  758. {
  759. delta_x = pixels - current_pixels;
  760. current_pixels += delta_x;
  761. do_scroll(direction, delta_x);
  762. }
  763. }
  764. return 0;
  765. }
  766. /**
  767. * @brief 清屏
  768. *
  769. */
  770. static int cls()
  771. {
  772. memset(pos.FB_address, BLACK, pos.FB_length * sizeof(unsigned int));
  773. pos.x = 0;
  774. pos.y = 0;
  775. return 0;
  776. }
  777. /**
  778. * @brief 获取VBE帧缓冲区长度
  779. */
  780. ul get_VBE_FB_length()
  781. {
  782. return pos.FB_length;
  783. }
  784. /**
  785. * @brief 设置pos变量中的VBE帧缓存区的线性地址
  786. * @param virt_addr VBE帧缓存区线性地址
  787. */
  788. void set_pos_VBE_FB_addr(uint *virt_addr)
  789. {
  790. pos.FB_address = (uint *)virt_addr;
  791. }
  792. static uint *get_pos_VBE_FB_addr()
  793. {
  794. return pos.FB_address;
  795. }
  796. /**
  797. * @brief 使能滚动动画
  798. *
  799. */
  800. void printk_enable_animation()
  801. {
  802. sw_show_scroll_animation = true;
  803. }
  804. /**
  805. * @brief 禁用滚动动画
  806. *
  807. */
  808. void printk_disable_animation()
  809. {
  810. sw_show_scroll_animation = false;
  811. }
  812. int sprintk(char *buf, const char *fmt, ...)
  813. {
  814. int count = 0;
  815. va_list args;
  816. va_start(args, fmt);
  817. count = vsprintf(buf, fmt, args);
  818. va_end(args);
  819. return count;
  820. }