kernel.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /*
  2. * example/kernel.c
  3. * https://gitlab.com/bztsrc/simpleboot
  4. *
  5. * Copyright (C) 2023 bzt (bztsrc@gitlab), MIT license
  6. * Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc.
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to
  10. * deal in the Software without restriction, including without limitation the
  11. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  12. * sell copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in
  16. * all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY
  21. * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
  23. * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  24. *
  25. * @brief An example Multiboot2 compliant kernel for the Simpleboot loader
  26. * https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html
  27. *
  28. * This is a very minimal "kernel" that just dumps the MBI to the serial console.
  29. * The main function is 99.9% identical to the one in the Multiboot2 spec (that's
  30. * why the identation is so ugly).
  31. */
  32. #include <simpleboot.h>
  33. void printf(char *fmt, ...);
  34. void dumpacpi(uint64_t addr);
  35. /*****************************************
  36. * kernel entry point *
  37. *****************************************/
  38. void _start(uint32_t magic, uintptr_t addr)
  39. {
  40. multiboot_tag_t *tag, *last;
  41. multiboot_mmap_entry_t *mmap;
  42. multiboot_tag_framebuffer_t *tagfb;
  43. unsigned int size;
  44. /* if everything else fails, this always works */
  45. /*
  46. __asm__ __volatile__("":"=a"(magic),"=b"(addr)::);
  47. */
  48. /* since this might run on multiple cores, do some locking to avoid messing up each other's output */
  49. while(*((volatile uint8_t*)0x558)) {}; *((volatile uint8_t*)0x558) = 1;
  50. /* Am I booted by a Multiboot-compliant boot loader? */
  51. if (magic != MULTIBOOT2_BOOTLOADER_MAGIC) {
  52. printf ("Invalid magic number: 0x%x\n", (unsigned) magic);
  53. goto halt;
  54. }
  55. if (addr & 7) {
  56. printf ("Unaligned MBI: 0x%x\n", addr);
  57. goto halt;
  58. }
  59. /* Dump the MBI tags that we've received */
  60. size = ((multiboot_info_t*)addr)->total_size;
  61. printf ("\nAnnounced MBI size 0x%x\n", size);
  62. for (tag = (multiboot_tag_t *) (addr + 8), last = (multiboot_tag_t *) (addr + size);
  63. tag < last && tag->type != MULTIBOOT_TAG_TYPE_END;
  64. tag = (multiboot_tag_t *) ((uint8_t *) tag + ((tag->size + 7) & ~7)))
  65. {
  66. printf ("Tag 0x%x, Size 0x%x\n", tag->type, tag->size);
  67. switch (tag->type) {
  68. case MULTIBOOT_TAG_TYPE_CMDLINE:
  69. printf ("Command line = %s\n",
  70. ((multiboot_tag_cmdline_t *) tag)->string);
  71. break;
  72. case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME:
  73. printf ("Boot loader name = %s\n",
  74. ((multiboot_tag_loader_t *) tag)->string);
  75. break;
  76. case MULTIBOOT_TAG_TYPE_MODULE:
  77. printf ("Module at 0x%x-0x%x. Command line %s\n",
  78. ((multiboot_tag_module_t *) tag)->mod_start,
  79. ((multiboot_tag_module_t *) tag)->mod_end,
  80. ((multiboot_tag_module_t *) tag)->string);
  81. break;
  82. case MULTIBOOT_TAG_TYPE_MMAP:
  83. {
  84. printf ("mmap\n");
  85. for (mmap = ((multiboot_tag_mmap_t *) tag)->entries;
  86. (uint8_t *) mmap < (uint8_t *) tag + tag->size;
  87. mmap = (multiboot_mmap_entry_t *) ((uintptr_t) mmap
  88. + ((multiboot_tag_mmap_t *) tag)->entry_size))
  89. printf (" base_addr = 0x%8x%8x,"
  90. " length = 0x%8x%8x, type = 0x%x %s, res = 0x%x\n",
  91. (unsigned) (mmap->base_addr >> 32),
  92. (unsigned) (mmap->base_addr & 0xffffffff),
  93. (unsigned) (mmap->length >> 32),
  94. (unsigned) (mmap->length & 0xffffffff),
  95. (unsigned) mmap->type,
  96. mmap->type == MULTIBOOT_MEMORY_AVAILABLE ? "free" : (
  97. mmap->type == MULTIBOOT_MEMORY_ACPI_RECLAIMABLE ? "ACPI" : (
  98. mmap->type == MULTIBOOT_MEMORY_NVS ? "ACPI NVS" : "used")),
  99. (unsigned) mmap->reserved);
  100. }
  101. break;
  102. case MULTIBOOT_TAG_TYPE_FRAMEBUFFER:
  103. {
  104. tagfb = (multiboot_tag_framebuffer_t *) tag;
  105. printf ("framebuffer\n");
  106. printf (" address 0x%8x%8x pitch %d\n",
  107. (unsigned) (tagfb->framebuffer_addr >> 32),
  108. (unsigned) (tagfb->framebuffer_addr & 0xffffffff),
  109. tagfb->framebuffer_pitch);
  110. printf (" width %d height %d depth %d bpp\n",
  111. tagfb->framebuffer_width,
  112. tagfb->framebuffer_height,
  113. tagfb->framebuffer_bpp);
  114. printf (" red channel: at %d, %d bits\n",
  115. tagfb->framebuffer_red_field_position,
  116. tagfb->framebuffer_red_mask_size);
  117. printf (" green channel: at %d, %d bits\n",
  118. tagfb->framebuffer_green_field_position,
  119. tagfb->framebuffer_green_mask_size);
  120. printf (" blue channel: at %d, %d bits\n",
  121. tagfb->framebuffer_blue_field_position,
  122. tagfb->framebuffer_blue_mask_size);
  123. break;
  124. }
  125. case MULTIBOOT_TAG_TYPE_EFI64:
  126. printf ("EFI system table 0x%x\n",
  127. ((multiboot_tag_efi64_t *) tag)->pointer);
  128. break;
  129. case MULTIBOOT_TAG_TYPE_EFI64_IH:
  130. printf ("EFI image handle 0x%x\n",
  131. ((multiboot_tag_efi64_t *) tag)->pointer);
  132. break;
  133. case MULTIBOOT_TAG_TYPE_SMBIOS:
  134. printf ("SMBIOS table major %d minor %d\n",
  135. ((multiboot_tag_smbios_t *) tag)->major,
  136. ((multiboot_tag_smbios_t *) tag)->minor);
  137. break;
  138. case MULTIBOOT_TAG_TYPE_ACPI_OLD:
  139. printf ("ACPI table (1.0, old RSDP)");
  140. dumpacpi ((uint64_t)*((uint32_t*)&((multiboot_tag_old_acpi_t *) tag)->rsdp[16]));
  141. break;
  142. case MULTIBOOT_TAG_TYPE_ACPI_NEW:
  143. printf ("ACPI table (2.0, new RSDP)");
  144. dumpacpi (*((uint64_t*)&((multiboot_tag_new_acpi_t *) tag)->rsdp[24]));
  145. break;
  146. /* additional, not in the original Multiboot2 spec */
  147. case MULTIBOOT_TAG_TYPE_EDID:
  148. printf ("EDID info\n");
  149. printf (" manufacturer ID %02x%02x\n",
  150. ((multiboot_tag_edid_t *) tag)->edid[8], ((multiboot_tag_edid_t *) tag)->edid[9]);
  151. printf (" EDID ID %02x%02x Version %d Rev %d\n",
  152. ((multiboot_tag_edid_t *) tag)->edid[10], ((multiboot_tag_edid_t *) tag)->edid[11],
  153. ((multiboot_tag_edid_t *) tag)->edid[18], ((multiboot_tag_edid_t *) tag)->edid[19]);
  154. printf (" monitor type %02x size %d cm x %d cm\n",
  155. ((multiboot_tag_edid_t *) tag)->edid[20], ((multiboot_tag_edid_t *) tag)->edid[21],
  156. ((multiboot_tag_edid_t *) tag)->edid[22]);
  157. break;
  158. case MULTIBOOT_TAG_TYPE_SMP:
  159. printf ("SMP supported\n");
  160. printf (" %d core(s)\n", ((multiboot_tag_smp_t*) tag)->numcores);
  161. printf (" %d running\n", ((multiboot_tag_smp_t*) tag)->running);
  162. printf (" %02x bsp id\n", ((multiboot_tag_smp_t*) tag)->bspid);
  163. break;
  164. default:
  165. printf ("---unknown MBI tag, this shouldn't happen with Simpleboot/Easyboot!---\n");
  166. goto halt;
  167. }
  168. }
  169. tag = (multiboot_tag_t *) ((uint8_t *) tag + ((tag->size + 7) & ~7));
  170. printf ("Total MBI size 0x%x %s\n", (uintptr_t)tag - addr, ((uintptr_t)tag - addr) == size ? "OK" : "ERR");
  171. /* there's nowhere to return to, halt machine */
  172. halt:
  173. *((volatile uint8_t*)0x558) = 0;
  174. #ifdef __aarch64__
  175. __asm__ __volatile__("1: wfe; b 1b");
  176. #else
  177. __asm__ __volatile__("1: cli; hlt; jmp 1b");
  178. #endif
  179. }
  180. /**
  181. * Display (extremely minimal) formated message on serial
  182. */
  183. void printf(char *fmt, ...)
  184. {
  185. __builtin_va_list args;
  186. int arg, len, sign, i;
  187. unsigned int uarg;
  188. char *p, tmpstr[19], n;
  189. #ifdef __aarch64__
  190. #define mmio_base 0x3F000000
  191. #define UART0_DR ((volatile uint32_t*)(mmio_base+0x00201000))
  192. #define UART0_FR ((volatile uint32_t*)(mmio_base+0x00201018))
  193. #define PUTC(c) do{do{ __asm__ __volatile__("nop");} while(*UART0_FR&0x20); *UART0_DR=c;}while(0)
  194. #else
  195. static char serinit = 0;
  196. #define PUTC(c) __asm__ __volatile__( \
  197. "xorl %%ebx, %%ebx; movb %0, %%bl;" \
  198. "movl $10000,%%ecx;" \
  199. "1:inb %%dx, %%al;pause;" \
  200. "cmpb $0xff,%%al;je 2f;" \
  201. "dec %%ecx;jz 2f;" \
  202. "andb $0x20,%%al;jz 1b;" \
  203. "subb $5,%%dl;movb %%bl, %%al;outb %%al, %%dx;2:" \
  204. ::"a"(c),"d"(0x3fd): "rbx", "rcx");
  205. /* initialize serial port */
  206. if(!serinit) {
  207. serinit = 1;
  208. __asm__ __volatile__(
  209. "movl %0, %%edx;"
  210. "xorb %%al, %%al;outb %%al, %%dx;" /* IER int off */
  211. "movb $0x80, %%al;addb $2,%%dl;outb %%al, %%dx;" /* LCR set divisor mode */
  212. "movb $1, %%al;subb $3,%%dl;outb %%al, %%dx;" /* DLL divisor lo 115200 */
  213. "xorb %%al, %%al;incb %%dl;outb %%al, %%dx;" /* DLH divisor hi */
  214. "incb %%dl;outb %%al, %%dx;" /* FCR fifo off */
  215. "movb $0x43, %%al;incb %%dl;outb %%al, %%dx;" /* LCR 8N1, break on */
  216. "movb $0x8, %%al;incb %%dl;outb %%al, %%dx;" /* MCR Aux out 2 */
  217. "xorb %%al, %%al;subb $4,%%dl;inb %%dx, %%al" /* clear receiver/transmitter */
  218. : : "a"(0x3f9): "rdx");
  219. }
  220. #endif
  221. /* parse format and print */
  222. __builtin_va_start(args, fmt);
  223. arg = 0;
  224. while(*fmt) {
  225. if(*fmt == '%') {
  226. fmt++;
  227. if(*fmt == '%') goto put;
  228. len=0; while(*fmt >= '0' && *fmt <= '9') { len *= 10; len += *fmt - '0'; fmt++; }
  229. if(*fmt == 'c') { arg = __builtin_va_arg(args, int); PUTC((uint8_t)arg); fmt++; continue; } else
  230. if(*fmt == 'd') {
  231. arg = __builtin_va_arg(args, int);
  232. sign = 0; if((int)arg < 0) { arg = -arg; sign++; }
  233. i = 18; tmpstr[i] = 0;
  234. do { tmpstr[--i] = '0' + (arg % 10); arg /= 10; } while(arg != 0 && i > 0);
  235. if(sign) tmpstr[--i] = '-';
  236. if(len > 0 && len < 18) { while(i > 18 - len) tmpstr[--i] = ' '; }
  237. p = &tmpstr[i];
  238. goto putstring;
  239. } else
  240. if(*fmt == 'x') {
  241. uarg = __builtin_va_arg(args, unsigned int);
  242. i = 16; tmpstr[i] = 0;
  243. do { n = uarg & 0xf; tmpstr[--i] = n + (n > 9 ? 0x37 : 0x30); uarg >>= 4; } while(uarg != 0 && i > 0);
  244. if(len > 0 && len <= 16) { while(i > 16 - len) tmpstr[--i] = '0'; }
  245. p = &tmpstr[i];
  246. goto putstring;
  247. } else
  248. if(*fmt == 's') {
  249. p = __builtin_va_arg(args, char*);
  250. putstring: if(p == (void*)0) p = "(null)";
  251. while(*p) PUTC(*p++);
  252. }
  253. } else {
  254. put: PUTC(*fmt);
  255. }
  256. fmt++;
  257. }
  258. __builtin_va_end(args);
  259. }
  260. typedef struct {
  261. char magic[4];
  262. uint32_t size;
  263. uint8_t rev;
  264. uint8_t chksum;
  265. char OEM[6];
  266. char OEMtableid[8];
  267. uint32_t OEMrev;
  268. uint32_t creatid;
  269. uint32_t creatrev;
  270. } __attribute__((packed)) sdt_hdr_t;
  271. typedef struct {
  272. char magic[4];
  273. uint32_t size;
  274. uint8_t rev;
  275. uint8_t chksum;
  276. uint8_t res0[30];
  277. uint32_t dsdt;
  278. uint8_t reserved[96];
  279. uint64_t x_dsdt;
  280. } __attribute__((packed)) fadt_t;
  281. /**
  282. * Dump ACPI tables
  283. */
  284. void dumpacpi(uint64_t addr)
  285. {
  286. uint8_t *ptr, *end, *p;
  287. sdt_hdr_t *hdr = (sdt_hdr_t*)addr, *tbl = 0;
  288. /* print root table, either RSDT or XSDT */
  289. printf(" 0x%08x%08x %c%c%c%c size %d\n",
  290. addr >> 32, addr & 0xffffffff,
  291. hdr->magic[0], hdr->magic[1], hdr->magic[2], hdr->magic[3],
  292. hdr->size);
  293. /* iterate on tables */
  294. if(hdr->magic[1] == 'S' && hdr->magic[2] == 'D' && hdr->magic[3] == 'T')
  295. for(ptr = (uint8_t*)(addr + sizeof(sdt_hdr_t)), end = (uint8_t*)(addr + hdr->size);
  296. ptr < end; ptr += hdr->magic[0] == 'X' ? 8 : 4) {
  297. /* with RSDT we have 32-bit addresses, but with XSDT 64-bit */
  298. tbl = (hdr->magic[0] == 'X' ?
  299. (sdt_hdr_t*)((uintptr_t)*((uint64_t*)ptr)) :
  300. (sdt_hdr_t*)((uintptr_t)*((uint32_t*)ptr)));
  301. printf(" 0x%08x%08x %c%c%c%c size %d",
  302. (uint64_t)tbl >> 32, (uint64_t)tbl & 0xffffffff,
  303. tbl->magic[0], tbl->magic[1], tbl->magic[2], tbl->magic[3],
  304. tbl->size);
  305. /* if it's FADT, print the DSDT in it too. There's a 32-bit address and a 64-bit address for it as well */
  306. if(tbl->magic[0] == 'F' && tbl->magic[1] == 'A' && tbl->magic[2] == 'C' && tbl->magic[3] == 'P') {
  307. p = tbl->rev >= 2 && tbl->size > 148 ? (uint8_t*)(uintptr_t)((fadt_t*)tbl)->x_dsdt :
  308. (uint8_t*)(uintptr_t)((fadt_t*)tbl)->dsdt;
  309. /* it is possible that the DSDT data is actually GUDT or DTB encoded (loader's feature, not in ACPI) */
  310. if(p[0] == 0xD0 && p[1] == 0x0D && p[2] == 0xFE && p[3] == 0xED)
  311. printf(" (DTB ");
  312. else
  313. printf(" (%c%c%c%c ", p[0], p[1], p[2], p[3]);
  314. /* print out address */
  315. if(tbl->rev >= 2 && tbl->size > 148)
  316. printf("0x%08x%08x)", ((fadt_t*)tbl)->x_dsdt >> 32, ((fadt_t*)tbl)->x_dsdt & 0xffffffff);
  317. else
  318. printf("0x%08x)", p);
  319. }
  320. printf("\n");
  321. }
  322. }