linux.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /*
  2. * example/linux.c
  3. * https://gitlab.com/bztsrc/simpleboot
  4. *
  5. * Copyright (C) 2023 bzt (bztsrc@gitlab), MIT license
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy
  8. * of this software and associated documentation files (the "Software"), to
  9. * deal in the Software without restriction, including without limitation the
  10. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  11. * sell copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in
  15. * all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY
  20. * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  21. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
  22. * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23. *
  24. * @brief An example Linux/x86 Boot Protocol compliant kernel for the Simpleboot loader
  25. * https://www.kernel.org/doc/html/latest/arch/x86/boot.html
  26. *
  27. * This is a very minimal "kernel" that just dumps the boot_params to the serial console.
  28. */
  29. #include <simpleboot.h>
  30. /* get the Linux structs */
  31. #include "../src/loader.h"
  32. void printf(char *fmt, ...);
  33. /***************************************************************************
  34. * Linux has no concept of a header with an entry point field, so we must *
  35. * keep fixed positions: setup_header must be at 0x1f1 and _start at 0x600 *
  36. ***************************************************************************/
  37. uint8_t __attribute__((section(".text"))) __attribute__ ((aligned (1)))
  38. padding1[0x1f1] = { 0 };
  39. linux_boot_t __attribute__((section(".text"))) __attribute__ ((aligned (1))) setup_header = {
  40. .setup_sects = 1,
  41. .boot_flag = 0xAA55,
  42. .jump = 0x6AEB,
  43. .header = 0x53726448, /* "HdrS" */
  44. .version = 0x20c,
  45. .pref_address = 0x100000,
  46. .init_size = 4900-1024
  47. };
  48. uint8_t __attribute__((section(".text"))) __attribute__ ((aligned (1)))
  49. padding2[0x600 - 0x1f1 - sizeof(setup_header)] = { 0 };
  50. /*****************************************
  51. * kernel entry point *
  52. *****************************************/
  53. void _start(uint32_t dummy, linux_boot_params_t *bp)
  54. {
  55. uint32_t i;
  56. printf("\r\nstruct boot_params at %x\r\n{\r\n", bp);
  57. printf(".screen_info.lfb_width %d\r\n", bp->lfb_width);
  58. printf(".screen_info.lfb_height %d\r\n", bp->lfb_height);
  59. printf(".screen_info.lfb_depth %d\r\n", bp->lfb_depth);
  60. printf(".screen_info.lfb_base %x\r\n", bp->lfb_base);
  61. printf(".screen_info.lfb_size %d\r\n", bp->lfb_size);
  62. printf(".screen_info.lfb_linelength %d\r\n", bp->lfb_linelength);
  63. printf(".screen_info.red_size %d\r\n", bp->red_size);
  64. printf(".screen_info.red_pos %d\r\n", bp->red_pos);
  65. printf(".screen_info.green_size %d\r\n", bp->green_size);
  66. printf(".screen_info.green_pos %d\r\n", bp->green_pos);
  67. printf(".screen_info.blue_size %d\r\n", bp->blue_size);
  68. printf(".screen_info.blue_pos %d\r\n", bp->blue_pos);
  69. printf(".acpi_rsdp_addr %x\r\n", bp->acpi_rsdp_addr);
  70. printf(".e820_entries %d\r\n", bp->e820_entries);
  71. for(i = 0; i < bp->e820_entries && i < E820_MAX_ENTRIES_ZEROPAGE; i++)
  72. printf(".e820_table[%d] = { .base %012x .size %d .type %x }\r\n", i,
  73. bp->e820_table[i].addr, bp->e820_table[i].size, bp->e820_table[i].type);
  74. printf(".hdr.setup_sects %d\r\n", bp->hdr.setup_sects);
  75. printf(".hdr.version %04x\r\n", bp->hdr.version);
  76. printf(".hdr.type_of_loader %d\r\n", bp->hdr.type_of_loader);
  77. printf(".hdr.loadflags %x\r\n", bp->hdr.loadflags);
  78. printf(".hdr.code32_start %x\r\n", bp->hdr.code32_start);
  79. printf(".hdr.ramdisk_image %x\r\n", bp->hdr.ramdisk_image);
  80. printf(".hdr.ramdisk_size %d\r\n", bp->hdr.ramdisk_size);
  81. printf(".hdr.cmd_line_ptr %x '%s'\r\n", bp->hdr.cmd_line_ptr, (char*)(uintptr_t)bp->hdr.cmd_line_ptr);
  82. printf(".hdr.pref_address %x\r\n", (uint32_t)bp->hdr.pref_address);
  83. printf(".hdr.init_size %d\r\n", bp->hdr.init_size);
  84. printf("}\r\n\r\n");
  85. /* there's nowhere to return to, halt machine */
  86. __asm__ __volatile__("1: cli; hlt; jmp 1b");
  87. }
  88. /**
  89. * Display (extremely minimal) formated message on serial
  90. */
  91. void printf(char *fmt, ...)
  92. {
  93. __builtin_va_list args;
  94. int64_t arg;
  95. int len, sign, i;
  96. char *p, tmpstr[19], n;
  97. static char serinit = 0;
  98. #define PUTC(c) __asm__ __volatile__( \
  99. "xorl %%ebx, %%ebx; movb %0, %%bl;" \
  100. "movl $10000,%%ecx;" \
  101. "1:inb %%dx, %%al;pause;" \
  102. "cmpb $0xff,%%al;je 2f;" \
  103. "dec %%ecx;jz 2f;" \
  104. "andb $0x20,%%al;jz 1b;" \
  105. "subb $5,%%dl;movb %%bl, %%al;outb %%al, %%dx;2:" \
  106. ::"a"(c),"d"(0x3fd): "rbx", "rcx");
  107. /* initialize serial port */
  108. if(!serinit) {
  109. serinit = 1;
  110. __asm__ __volatile__(
  111. "movl %0, %%edx;"
  112. "xorb %%al, %%al;outb %%al, %%dx;" /* IER int off */
  113. "movb $0x80, %%al;addb $2,%%dl;outb %%al, %%dx;" /* LCR set divisor mode */
  114. "movb $1, %%al;subb $3,%%dl;outb %%al, %%dx;" /* DLL divisor lo 115200 */
  115. "xorb %%al, %%al;incb %%dl;outb %%al, %%dx;" /* DLH divisor hi */
  116. "incb %%dl;outb %%al, %%dx;" /* FCR fifo off */
  117. "movb $0x43, %%al;incb %%dl;outb %%al, %%dx;" /* LCR 8N1, break on */
  118. "movb $0x8, %%al;incb %%dl;outb %%al, %%dx;" /* MCR Aux out 2 */
  119. "xorb %%al, %%al;subb $4,%%dl;inb %%dx, %%al" /* clear receiver/transmitter */
  120. : : "a"(0x3f9): "rdx");
  121. }
  122. /* parse format and print */
  123. __builtin_va_start(args, fmt);
  124. arg = 0;
  125. while(*fmt) {
  126. if(*fmt == '%') {
  127. fmt++;
  128. if(*fmt == '%') goto put;
  129. len=0; while(*fmt >= '0' && *fmt <= '9') { len *= 10; len += *fmt - '0'; fmt++; }
  130. if(*fmt == 'd') {
  131. arg = __builtin_va_arg(args, int64_t);
  132. sign = 0; if((int)arg < 0) { arg = -arg; sign++; }
  133. i = 18; tmpstr[i] = 0;
  134. do { tmpstr[--i] = '0' + (arg % 10); arg /= 10; } while(arg != 0 && i > 0);
  135. if(sign) tmpstr[--i] = '-';
  136. if(len > 0 && len < 18) { while(i > 18 - len) tmpstr[--i] = ' '; }
  137. p = &tmpstr[i];
  138. goto putstring;
  139. } else
  140. if(*fmt == 'x') {
  141. arg = __builtin_va_arg(args, int64_t);
  142. i = 16; tmpstr[i] = 0;
  143. do { n = arg & 0xf; tmpstr[--i] = n + (n > 9 ? 0x37 : 0x30); arg >>= 4; } while(arg != 0 && i > 0);
  144. if(len > 0 && len <= 16) { while(i > 16 - len) tmpstr[--i] = '0'; }
  145. p = &tmpstr[i];
  146. goto putstring;
  147. } else
  148. if(*fmt == 's') {
  149. p = __builtin_va_arg(args, char*);
  150. putstring: if(p == (void*)0) p = "(null)";
  151. while(*p) PUTC(*p++);
  152. }
  153. } else {
  154. put: PUTC(*fmt);
  155. }
  156. fmt++;
  157. }
  158. __builtin_va_end(args);
  159. }