kernel.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  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. void dumpuuid(uint8_t *uuid);
  36. /*****************************************
  37. * kernel entry point *
  38. *****************************************/
  39. void _start(uint32_t magic, uintptr_t addr)
  40. {
  41. multiboot_tag_t *tag, *last;
  42. multiboot_mmap_entry_t *mmap;
  43. multiboot_tag_framebuffer_t *tagfb;
  44. unsigned int size;
  45. /* if everything else fails, this always works */
  46. /*
  47. __asm__ __volatile__("":"=a"(magic),"=b"(addr)::);
  48. */
  49. /* since this might run on multiple cores, do some locking to avoid messing up each other's output */
  50. while(*((volatile uint8_t*)0x558)) {}; *((volatile uint8_t*)0x558) = 1;
  51. /* Am I booted by a Multiboot-compliant boot loader? */
  52. if (magic != MULTIBOOT2_BOOTLOADER_MAGIC) {
  53. printf ("Invalid magic number: 0x%x\n", (unsigned) magic);
  54. goto halt;
  55. }
  56. if (addr & 7) {
  57. printf ("Unaligned MBI: 0x%x\n", addr);
  58. goto halt;
  59. }
  60. /* Dump the MBI tags that we've received */
  61. size = ((multiboot_info_t*)addr)->total_size;
  62. printf ("\nAnnounced MBI size 0x%x\n", size);
  63. for (tag = (multiboot_tag_t *) (addr + 8), last = (multiboot_tag_t *) (addr + size);
  64. tag < last && tag->type != MULTIBOOT_TAG_TYPE_END;
  65. tag = (multiboot_tag_t *) ((uint8_t *) tag + ((tag->size + 7) & ~7)))
  66. {
  67. printf ("Tag 0x%x, Size 0x%x\n", tag->type, tag->size);
  68. switch (tag->type) {
  69. case MULTIBOOT_TAG_TYPE_CMDLINE:
  70. printf ("Command line = %s\n",
  71. ((multiboot_tag_cmdline_t *) tag)->string);
  72. break;
  73. case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME:
  74. printf ("Boot loader name = %s\n",
  75. ((multiboot_tag_loader_t *) tag)->string);
  76. break;
  77. case MULTIBOOT_TAG_TYPE_MODULE:
  78. printf ("Module at 0x%x-0x%x. Command line %s\n",
  79. ((multiboot_tag_module_t *) tag)->mod_start,
  80. ((multiboot_tag_module_t *) tag)->mod_end,
  81. ((multiboot_tag_module_t *) tag)->string);
  82. break;
  83. case MULTIBOOT_TAG_TYPE_MMAP:
  84. {
  85. printf ("mmap\n");
  86. for (mmap = ((multiboot_tag_mmap_t *) tag)->entries;
  87. (uint8_t *) mmap < (uint8_t *) tag + tag->size;
  88. mmap = (multiboot_mmap_entry_t *) ((uintptr_t) mmap
  89. + ((multiboot_tag_mmap_t *) tag)->entry_size))
  90. printf (" base_addr = 0x%8x%8x,"
  91. " length = 0x%8x%8x, type = 0x%x %s, res = 0x%x\n",
  92. (unsigned) (mmap->base_addr >> 32),
  93. (unsigned) (mmap->base_addr & 0xffffffff),
  94. (unsigned) (mmap->length >> 32),
  95. (unsigned) (mmap->length & 0xffffffff),
  96. (unsigned) mmap->type,
  97. mmap->type == MULTIBOOT_MEMORY_AVAILABLE ? "free" : (
  98. mmap->type == MULTIBOOT_MEMORY_ACPI_RECLAIMABLE ? "ACPI" : (
  99. mmap->type == MULTIBOOT_MEMORY_NVS ? "ACPI NVS" : "used")),
  100. (unsigned) mmap->reserved);
  101. }
  102. break;
  103. case MULTIBOOT_TAG_TYPE_FRAMEBUFFER:
  104. {
  105. tagfb = (multiboot_tag_framebuffer_t *) tag;
  106. printf ("framebuffer\n");
  107. printf (" address 0x%8x%8x pitch %d\n",
  108. (unsigned) (tagfb->framebuffer_addr >> 32),
  109. (unsigned) (tagfb->framebuffer_addr & 0xffffffff),
  110. tagfb->framebuffer_pitch);
  111. printf (" width %d height %d depth %d bpp\n",
  112. tagfb->framebuffer_width,
  113. tagfb->framebuffer_height,
  114. tagfb->framebuffer_bpp);
  115. printf (" red channel: at %d, %d bits\n",
  116. tagfb->framebuffer_red_field_position,
  117. tagfb->framebuffer_red_mask_size);
  118. printf (" green channel: at %d, %d bits\n",
  119. tagfb->framebuffer_green_field_position,
  120. tagfb->framebuffer_green_mask_size);
  121. printf (" blue channel: at %d, %d bits\n",
  122. tagfb->framebuffer_blue_field_position,
  123. tagfb->framebuffer_blue_mask_size);
  124. break;
  125. }
  126. case MULTIBOOT_TAG_TYPE_EFI64:
  127. printf ("EFI system table 0x%x\n",
  128. ((multiboot_tag_efi64_t *) tag)->pointer);
  129. break;
  130. case MULTIBOOT_TAG_TYPE_EFI64_IH:
  131. printf ("EFI image handle 0x%x\n",
  132. ((multiboot_tag_efi64_t *) tag)->pointer);
  133. break;
  134. case MULTIBOOT_TAG_TYPE_SMBIOS:
  135. printf ("SMBIOS table major %d minor %d\n",
  136. ((multiboot_tag_smbios_t *) tag)->major,
  137. ((multiboot_tag_smbios_t *) tag)->minor);
  138. break;
  139. case MULTIBOOT_TAG_TYPE_ACPI_OLD:
  140. printf ("ACPI table (1.0, old RSDP)");
  141. dumpacpi ((uint64_t)*((uint32_t*)&((multiboot_tag_old_acpi_t *) tag)->rsdp[16]));
  142. break;
  143. case MULTIBOOT_TAG_TYPE_ACPI_NEW:
  144. printf ("ACPI table (2.0, new RSDP)");
  145. dumpacpi (*((uint64_t*)&((multiboot_tag_new_acpi_t *) tag)->rsdp[24]));
  146. break;
  147. /* additional, not in the original Multiboot2 spec */
  148. case MULTIBOOT_TAG_TYPE_EDID:
  149. printf ("EDID info\n");
  150. printf (" manufacturer ID %02x%02x\n",
  151. ((multiboot_tag_edid_t *) tag)->edid[8], ((multiboot_tag_edid_t *) tag)->edid[9]);
  152. printf (" EDID ID %02x%02x Version %d Rev %d\n",
  153. ((multiboot_tag_edid_t *) tag)->edid[10], ((multiboot_tag_edid_t *) tag)->edid[11],
  154. ((multiboot_tag_edid_t *) tag)->edid[18], ((multiboot_tag_edid_t *) tag)->edid[19]);
  155. printf (" monitor type %02x size %d cm x %d cm\n",
  156. ((multiboot_tag_edid_t *) tag)->edid[20], ((multiboot_tag_edid_t *) tag)->edid[21],
  157. ((multiboot_tag_edid_t *) tag)->edid[22]);
  158. break;
  159. case MULTIBOOT_TAG_TYPE_SMP:
  160. printf ("SMP supported\n");
  161. printf (" %d core(s)\n", ((multiboot_tag_smp_t*) tag)->numcores);
  162. printf (" %d running\n", ((multiboot_tag_smp_t*) tag)->running);
  163. printf (" %02x bsp id\n", ((multiboot_tag_smp_t*) tag)->bspid);
  164. break;
  165. case MULTIBOOT_TAG_TYPE_PARTUUID:
  166. printf ("Partition UUIDs\n");
  167. printf (" boot "); dumpuuid(((multiboot_tag_partuuid_t*) tag)->bootuuid);
  168. if(tag->size >= 40) {
  169. printf (" root "); dumpuuid(((multiboot_tag_partuuid_t*) tag)->rootuuid);
  170. }
  171. break;
  172. default:
  173. printf ("---unknown MBI tag, this shouldn't happen with Simpleboot/Easyboot!---\n");
  174. goto halt;
  175. }
  176. }
  177. tag = (multiboot_tag_t *) ((uint8_t *) tag + ((tag->size + 7) & ~7));
  178. printf ("Total MBI size 0x%x %s\n", (uintptr_t)tag - addr, ((uintptr_t)tag - addr) == size ? "OK" : "ERR");
  179. /* there's nowhere to return to, halt machine */
  180. halt:
  181. *((volatile uint8_t*)0x558) = 0;
  182. #ifdef __aarch64__
  183. __asm__ __volatile__("1: wfe; b 1b");
  184. #else
  185. __asm__ __volatile__("1: cli; hlt; jmp 1b");
  186. #endif
  187. }
  188. /**
  189. * Display (extremely minimal) formated message on serial
  190. */
  191. void printf(char *fmt, ...)
  192. {
  193. __builtin_va_list args;
  194. int arg, len, sign, i;
  195. unsigned int uarg;
  196. char *p, tmpstr[19], n;
  197. /* macro to put a character on serial console */
  198. #ifdef __aarch64__
  199. #define mmio_base 0x3F000000
  200. #define UART0_DR ((volatile uint32_t*)(mmio_base+0x00201000))
  201. #define UART0_FR ((volatile uint32_t*)(mmio_base+0x00201018))
  202. #define PUTC(c) do{do{ __asm__ __volatile__("nop");} while(*UART0_FR&0x20); *UART0_DR=c;}while(0)
  203. #else
  204. #define PUTC(c) __asm__ __volatile__( \
  205. "xorl %%ebx, %%ebx; movb %0, %%bl;" \
  206. "movl $10000,%%ecx;" \
  207. "1:inb %%dx, %%al;pause;" \
  208. "cmpb $0xff,%%al;je 2f;" \
  209. "dec %%ecx;jz 2f;" \
  210. "andb $0x20,%%al;jz 1b;" \
  211. "subb $5,%%dl;movb %%bl, %%al;outb %%al, %%dx;2:" \
  212. ::"a"(c),"d"(0x3fd): "rbx", "rcx");
  213. #endif
  214. /* parse format and print */
  215. __builtin_va_start(args, fmt);
  216. arg = 0;
  217. while(*fmt) {
  218. if(*fmt == '%') {
  219. fmt++;
  220. if(*fmt == '%') goto put;
  221. len=0; while(*fmt >= '0' && *fmt <= '9') { len *= 10; len += *fmt - '0'; fmt++; }
  222. if(*fmt == 'c') { arg = __builtin_va_arg(args, int); PUTC((uint8_t)arg); fmt++; continue; } else
  223. if(*fmt == 'd') {
  224. arg = __builtin_va_arg(args, int);
  225. sign = 0; if((int)arg < 0) { arg = -arg; sign++; }
  226. i = 18; tmpstr[i] = 0;
  227. do { tmpstr[--i] = '0' + (arg % 10); arg /= 10; } while(arg != 0 && i > 0);
  228. if(sign) tmpstr[--i] = '-';
  229. if(len > 0 && len < 18) { while(i > 18 - len) tmpstr[--i] = ' '; }
  230. p = &tmpstr[i];
  231. goto putstring;
  232. } else
  233. if(*fmt == 'x') {
  234. uarg = __builtin_va_arg(args, unsigned int);
  235. i = 16; tmpstr[i] = 0;
  236. do { n = uarg & 0xf; tmpstr[--i] = n + (n > 9 ? 0x37 : 0x30); uarg >>= 4; } while(uarg != 0 && i > 0);
  237. if(len > 0 && len <= 16) { while(i > 16 - len) tmpstr[--i] = '0'; }
  238. p = &tmpstr[i];
  239. goto putstring;
  240. } else
  241. if(*fmt == 's') {
  242. p = __builtin_va_arg(args, char*);
  243. putstring: if(p == (void*)0) p = "(null)";
  244. while(*p) PUTC(*p++);
  245. }
  246. } else {
  247. put: PUTC(*fmt);
  248. }
  249. fmt++;
  250. }
  251. __builtin_va_end(args);
  252. }
  253. /**
  254. * Print a binary UUID in human readable form
  255. */
  256. void dumpuuid(uint8_t *uuid)
  257. {
  258. printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x\n",
  259. uuid[3], uuid[2], uuid[1], uuid[0],
  260. uuid[5], uuid[4],
  261. uuid[7], uuid[6],
  262. uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
  263. }
  264. typedef struct {
  265. char magic[4];
  266. uint32_t size;
  267. uint8_t rev;
  268. uint8_t chksum;
  269. char OEM[6];
  270. char OEMtableid[8];
  271. uint32_t OEMrev;
  272. uint32_t creatid;
  273. uint32_t creatrev;
  274. } __attribute__((packed)) sdt_hdr_t;
  275. typedef struct {
  276. char magic[4];
  277. uint32_t size;
  278. uint8_t rev;
  279. uint8_t chksum;
  280. uint8_t res0[30];
  281. uint32_t dsdt;
  282. uint8_t reserved[96];
  283. uint64_t x_dsdt;
  284. } __attribute__((packed)) fadt_t;
  285. /**
  286. * Dump ACPI tables
  287. */
  288. void dumpacpi(uint64_t addr)
  289. {
  290. uint8_t *ptr, *end, *p;
  291. sdt_hdr_t *hdr = (sdt_hdr_t*)addr, *tbl = 0;
  292. /* print root table, either RSDT or XSDT */
  293. printf(" 0x%08x%08x %c%c%c%c size %d\n",
  294. addr >> 32, addr & 0xffffffff,
  295. hdr->magic[0], hdr->magic[1], hdr->magic[2], hdr->magic[3],
  296. hdr->size);
  297. /* iterate on tables */
  298. if(hdr->magic[1] == 'S' && hdr->magic[2] == 'D' && hdr->magic[3] == 'T')
  299. for(ptr = (uint8_t*)(addr + sizeof(sdt_hdr_t)), end = (uint8_t*)(addr + hdr->size);
  300. ptr < end; ptr += hdr->magic[0] == 'X' ? 8 : 4) {
  301. /* with RSDT we have 32-bit addresses, but with XSDT 64-bit */
  302. tbl = (hdr->magic[0] == 'X' ?
  303. (sdt_hdr_t*)((uintptr_t)*((uint64_t*)ptr)) :
  304. (sdt_hdr_t*)((uintptr_t)*((uint32_t*)ptr)));
  305. printf(" 0x%08x%08x %c%c%c%c size %d",
  306. (uint64_t)tbl >> 32, (uint64_t)tbl & 0xffffffff,
  307. tbl->magic[0], tbl->magic[1], tbl->magic[2], tbl->magic[3],
  308. tbl->size);
  309. /* 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 */
  310. if(tbl->magic[0] == 'F' && tbl->magic[1] == 'A' && tbl->magic[2] == 'C' && tbl->magic[3] == 'P') {
  311. p = tbl->rev >= 2 && tbl->size > 148 ? (uint8_t*)(uintptr_t)((fadt_t*)tbl)->x_dsdt :
  312. (uint8_t*)(uintptr_t)((fadt_t*)tbl)->dsdt;
  313. /* it is possible that the DSDT data is actually GUDT or DTB encoded (loader's feature, not in ACPI) */
  314. if(p[0] == 0xD0 && p[1] == 0x0D && p[2] == 0xFE && p[3] == 0xED)
  315. printf(" (DTB ");
  316. else
  317. printf(" (%c%c%c%c ", p[0], p[1], p[2], p[3]);
  318. /* print out address */
  319. if(tbl->rev >= 2 && tbl->size > 148)
  320. printf("0x%08x%08x)", ((fadt_t*)tbl)->x_dsdt >> 32, ((fadt_t*)tbl)->x_dsdt & 0xffffffff);
  321. else
  322. printf("0x%08x)", p);
  323. }
  324. printf("\n");
  325. }
  326. }