printk.c 23 KB

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