kernel.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. #if !defined(__cplusplus)
  2. #include <stdbool.h> /* C doesn't have booleans by default. */
  3. #endif
  4. #include <stddef.h>
  5. #include <stdint.h>
  6. /* Check if the compiler thinks we are targeting the wrong operating system. */
  7. #if defined(__linux__)
  8. /* TODO how does this check for a cross compiler? It was failing. */
  9. /*#error "You are not using a cross-compiler, you will most certainly run into trouble"*/
  10. #endif
  11. /* This tutorial will only work for the 32-bit ix86 targets. */
  12. #if !defined(__i386__)
  13. #error "This tutorial needs to be compiled with a ix86-elf compiler"
  14. #endif
  15. /* Hardware text mode color constants. */
  16. enum vga_color {
  17. COLOR_BLACK = 0,
  18. COLOR_BLUE = 1,
  19. COLOR_GREEN = 2,
  20. COLOR_CYAN = 3,
  21. COLOR_RED = 4,
  22. COLOR_MAGENTA = 5,
  23. COLOR_BROWN = 6,
  24. COLOR_LIGHT_GREY = 7,
  25. COLOR_DARK_GREY = 8,
  26. COLOR_LIGHT_BLUE = 9,
  27. COLOR_LIGHT_GREEN = 10,
  28. COLOR_LIGHT_CYAN = 11,
  29. COLOR_LIGHT_RED = 12,
  30. COLOR_LIGHT_MAGENTA = 13,
  31. COLOR_LIGHT_BROWN = 14,
  32. COLOR_WHITE = 15,
  33. };
  34. uint8_t make_color(enum vga_color fg, enum vga_color bg) {
  35. return fg | bg << 4;
  36. }
  37. uint16_t make_vgaentry(char c, uint8_t color) {
  38. uint16_t c16 = c;
  39. uint16_t color16 = color;
  40. return c16 | color16 << 8;
  41. }
  42. size_t strlen(const char* str) {
  43. size_t ret = 0;
  44. while ( str[ret] != 0 )
  45. ret++;
  46. return ret;
  47. }
  48. static const size_t VGA_WIDTH = 80;
  49. static const size_t VGA_HEIGHT = 25;
  50. size_t terminal_row;
  51. size_t terminal_column;
  52. uint8_t terminal_color;
  53. uint16_t* terminal_buffer;
  54. void terminal_initialize() {
  55. terminal_row = 0;
  56. terminal_column = 0;
  57. terminal_color = make_color(COLOR_LIGHT_GREY, COLOR_BLACK);
  58. terminal_buffer = (uint16_t*) 0xB8000;
  59. for (size_t y = 0; y < VGA_HEIGHT; y++) {
  60. for (size_t x = 0; x < VGA_WIDTH; x++) {
  61. const size_t index = y * VGA_WIDTH + x;
  62. terminal_buffer[index] = make_vgaentry(' ', terminal_color);
  63. }
  64. }
  65. }
  66. void terminal_setcolor(uint8_t color) {
  67. terminal_color = color;
  68. }
  69. void terminal_putentryat(char c, uint8_t color, size_t x, size_t y) {
  70. const size_t index = y * VGA_WIDTH + x;
  71. terminal_buffer[index] = make_vgaentry(c, color);
  72. }
  73. void terminal_putchar(char c) {
  74. terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
  75. if (++terminal_column == VGA_WIDTH) {
  76. terminal_column = 0;
  77. if (++terminal_row == VGA_HEIGHT) {
  78. terminal_row = 0;
  79. }
  80. }
  81. }
  82. void terminal_writestring(const char* data) {
  83. size_t datalen = strlen(data);
  84. for (size_t i = 0; i < datalen; i++)
  85. terminal_putchar(data[i]);
  86. }
  87. #if defined(__cplusplus)
  88. extern "C" /* Use C linkage for kernel_main. */
  89. #endif
  90. void kernel_main() {
  91. /* Initialize terminal interface */
  92. terminal_initialize();
  93. /* Since there is no support for newlines in terminal_putchar
  94. * yet, '\n' would produce some weird VGA specific character instead.
  95. * This is normal.
  96. */
  97. terminal_writestring("hello world");
  98. }