continue2.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /* This file is part of asmc, a bootstrapping OS with minimal seed
  2. Copyright (C) 2019 Giovanni Mascellani <gio@debian.org>
  3. https://gitlab.com/giomasce/asmc
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <https://www.gnu.org/licenses/>. */
  14. #include <stdint.h>
  15. #include <assert.h>
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <asmc_api.h>
  19. struct gdt_entry {
  20. unsigned int limit_low : 16;
  21. unsigned int base_low : 24;
  22. // Access byte
  23. unsigned int accessed : 1;
  24. unsigned int read_write : 1; // Readable for code, writable for data
  25. unsigned int conforming : 1; // Conforming for code, expand down for data
  26. unsigned int code : 1; // 1 for code, 0 for data
  27. unsigned int type : 1; // 1 for code/data, 0 for system segments (like TSS)
  28. unsigned int DPL : 2; //priviledge level
  29. unsigned int present : 1;
  30. // Flags
  31. unsigned int limit_high : 4;
  32. unsigned int always_0 : 2;
  33. unsigned int size : 1; // 1 for 32 bits, 0 for 16 bits
  34. unsigned int gran : 1; // 1 for 4k page addressing, 0 for byte addressing
  35. unsigned int base_high : 8;
  36. } __attribute__((packed));
  37. struct gdt_desc {
  38. uint16_t size;
  39. struct gdt_entry *offset;
  40. } __attribute__((packed));
  41. void reload_gdt(struct gdt_entry *gdt, int entry_num) {
  42. struct gdt_desc desc;
  43. desc.size = entry_num * 8 - 1;
  44. desc.offset = gdt;
  45. asm volatile("lgdt %0 \n\t"
  46. "push $0x10 \n\t"
  47. "push $reload_cs \n\t"
  48. // TCC does not know retf
  49. ".byte 0xcb \n\t"
  50. "reload_cs: \n\t"
  51. "mov $0x18, %%ax \n\t"
  52. // TCC generates a 0x66 prefix that does not look like right
  53. /*"mov %%ax, %%ds \n\t"
  54. "mov %%ax, %%es \n\t"
  55. "mov %%ax, %%fs \n\t"
  56. "mov %%ax, %%gs \n\t"
  57. "mov %%ax, %%ss \n\t"*/
  58. ".byte 0x8e, 0xd8 \n\t"
  59. ".byte 0x8e, 0xc0 \n\t"
  60. ".byte 0x8e, 0xe0 \n\t"
  61. ".byte 0x8e, 0xe8 \n\t"
  62. ".byte 0x8e, 0xd0 \n\t"
  63. : : "m" (desc));
  64. printf("Still alive after reloading code and data segments!\n");
  65. }
  66. // Load GDT, code and data segments according to Linux Boot Protocol
  67. void load_linux_gdt() {
  68. assert(sizeof(struct gdt_desc) == 6);
  69. assert(sizeof(struct gdt_entry) == 8);
  70. // Random address, hoping that it does not bother anybody
  71. struct gdt_entry *gdt = (struct gdt_entry*) 0x800;
  72. memset(gdt, 0, sizeof(gdt[0]) * 4);
  73. // 0x10: code segment
  74. gdt[2].limit_low = 0xffff;
  75. gdt[2].base_low = 0x000000;
  76. gdt[2].accessed = 0;
  77. gdt[2].read_write = 1;
  78. gdt[2].conforming = 0;
  79. gdt[2].code = 1;
  80. gdt[2].type = 1;
  81. gdt[2].DPL = 0;
  82. gdt[2].present = 1;
  83. gdt[2].limit_high = 0xf;
  84. gdt[2].size = 1;
  85. gdt[2].gran = 1;
  86. gdt[2].base_high = 0x00;
  87. // 0x18: data segment
  88. gdt[3].limit_low = 0xffff;
  89. gdt[3].base_low = 0x000000;
  90. gdt[3].accessed = 0;
  91. gdt[3].read_write = 1;
  92. gdt[3].conforming = 0;
  93. gdt[3].code = 0;
  94. gdt[3].type = 1;
  95. gdt[3].DPL = 0;
  96. gdt[3].present = 1;
  97. gdt[3].limit_high = 0xf;
  98. gdt[3].size = 1;
  99. gdt[3].gran = 1;
  100. gdt[3].base_high = 0x00;
  101. reload_gdt(gdt, 4);
  102. }
  103. // Prepare GDT to re-enter real mode
  104. void prepare_real_mode_gdt() {
  105. assert(sizeof(struct gdt_desc) == 6);
  106. assert(sizeof(struct gdt_entry) == 8);
  107. // Random address, hoping that it does not bother anybody
  108. struct gdt_entry *gdt = (struct gdt_entry*) 0x800;
  109. memset(gdt, 0, sizeof(gdt[0]) * 4);
  110. // 0x10: code segment
  111. gdt[2].limit_low = 0xffff;
  112. gdt[2].base_low = 0x000000;
  113. gdt[2].accessed = 0;
  114. gdt[2].read_write = 1;
  115. gdt[2].conforming = 0;
  116. gdt[2].code = 1;
  117. gdt[2].type = 1;
  118. gdt[2].DPL = 0;
  119. gdt[2].present = 1;
  120. gdt[2].limit_high = 0x0;
  121. gdt[2].size = 0;
  122. gdt[2].gran = 0;
  123. gdt[2].base_high = 0x00;
  124. // 0x18: data segment
  125. gdt[3].limit_low = 0xffff;
  126. gdt[3].base_low = 0x000000;
  127. gdt[3].accessed = 0;
  128. gdt[3].read_write = 1;
  129. gdt[3].conforming = 0;
  130. gdt[3].code = 0;
  131. gdt[3].type = 1;
  132. gdt[3].DPL = 0;
  133. gdt[3].present = 1;
  134. gdt[3].limit_high = 0x0;
  135. gdt[3].size = 0;
  136. gdt[3].gran = 0;
  137. gdt[3].base_high = 0x00;
  138. }
  139. void prepare_setup_header(void *zero_page, void *initrd, size_t initrd_size) {
  140. char *czp = (char*) zero_page;
  141. *((uint16_t*)(czp+0x1fa)) = 0xffff;
  142. *((uint8_t*)(czp+0x210)) = 0xff;
  143. *((uint8_t*)(czp+0x211)) = 0x81;
  144. *((void**)(czp+0x218)) = initrd;
  145. *((uint32_t*)(czp+0x21c)) = initrd_size;
  146. *((uint16_t*)(czp+0x224)) = 0xde00;
  147. *((void**)(czp+0x228)) = (void*) 0x1e000;
  148. }
  149. void prepare_boot_params(void *zero_page, void *initrd, size_t initrd_size) {
  150. prepare_setup_header(zero_page, initrd, initrd_size);
  151. }
  152. #define SECT_SIZE 512
  153. void load_linux32() {
  154. download_file("http://10.0.2.2:8080/bzImage", "/ram/cont/bzImage");
  155. download_file("http://10.0.2.2:8080/initrd.img", "/ram/cont/initrd.img");
  156. printf("Loading Linux kernel\n");
  157. FILE *fin = fopen("/ram/cont/bzImage", "rb");
  158. void *real_mode = malloc(SECT_SIZE);
  159. size_t res = fread(real_mode, SECT_SIZE, 1, fin);
  160. assert(res == 1);
  161. uint8_t setup_sects = *((uint8_t*)(((char*)real_mode)+0x1f1));
  162. setup_sects = setup_sects == 0 ? 4 : setup_sects;
  163. size_t real_mode_size = SECT_SIZE * (1 + setup_sects);
  164. printf("Real mode code/data is 0x%x bytes long\n", real_mode_size);
  165. real_mode = realloc(real_mode, real_mode_size);
  166. res = fread(((char*)real_mode) + SECT_SIZE, SECT_SIZE, setup_sects, fin);
  167. assert(res == setup_sects);
  168. assert(*((uint16_t*)(((char*)real_mode)+0x1fe)) == 0xaa55);
  169. assert(*((uint32_t*)(((char*)real_mode)+0x202)) == 0x53726448);
  170. size_t prot_mode_size;
  171. void *prot_mode = read_whole_file(fin, &prot_mode_size);
  172. printf("Protected mode code/data is 0x%x bytes long\n", prot_mode_size);
  173. fclose(fin);
  174. fin = fopen("/ram/cont/initrd.img", "rb");
  175. size_t initrd_size;
  176. void *initrd = read_whole_file(fin, &initrd_size);
  177. printf("Initrd is 0x%x bytes long\n", initrd_size);
  178. fclose(fin);
  179. // Align initrd
  180. initrd = realloc(initrd, initrd_size + 4096);
  181. void *initrd_aligned = (void*)(((((unsigned long)initrd)-1) | (4096-1)) + 1);
  182. memmove(initrd_aligned, initrd, initrd_size);
  183. printf("Initrd initially allocated at 0x%x, then moved at 0x%x\n", initrd, initrd_aligned);
  184. prepare_boot_params(real_mode, initrd_aligned, initrd_size);
  185. load_linux_gdt();
  186. char *cmdline = "verbose earlyprintk nokaslr console=uart8250,io,0x3f8,115200n8";
  187. // Here we really smash our operating system!
  188. memset((void*) 0x10000, 0, 0x10000);
  189. memcpy((void*) 0x10000, real_mode, real_mode_size);
  190. memcpy((void*) 0x1e000, cmdline, strlen(cmdline));
  191. //memcpy((void*) 0x100000, prot_mode, prot_mode_size);
  192. asm volatile("mov $0x100000, %%edi \n\t"
  193. "cld \n\t"
  194. "rep movsb \n\t"
  195. "mov $0x10000, %%esi \n\t"
  196. "xor %%eax, %%eax \n\t"
  197. "mov %%eax, %%ebp \n\t"
  198. "mov %%eax, %%edi \n\t"
  199. "mov %%eax, %%ebx \n\t"
  200. "mov %%eax, %%ecx \n\t"
  201. "mov %%eax, %%edx \n\t"
  202. "mov $0xe000, %%esp \n\t"
  203. "push $0x100000 \n\t"
  204. "ret \n\t"
  205. : : "S" (prot_mode), "c" (prot_mode_size));
  206. free(initrd);
  207. free(real_mode);
  208. free(prot_mode);
  209. }
  210. void load_linux() {
  211. download_file("http://10.0.2.2:8080/bzImage", "/ram/cont/bzImage");
  212. download_file("http://10.0.2.2:8080/realmode.bin", "/ram/cont/realmode.bin");
  213. printf("Loading Linux kernel\n");
  214. FILE *fin = fopen("/ram/cont/bzImage", "rb");
  215. void *real_mode = malloc(SECT_SIZE);
  216. size_t res = fread(real_mode, SECT_SIZE, 1, fin);
  217. assert(res == 1);
  218. uint8_t setup_sects = *((uint8_t*)(((char*)real_mode)+0x1f1));
  219. setup_sects = setup_sects == 0 ? 4 : setup_sects;
  220. size_t real_mode_size = SECT_SIZE * (1 + setup_sects);
  221. printf("Real mode code/data is 0x%x bytes long\n", real_mode_size);
  222. real_mode = realloc(real_mode, real_mode_size);
  223. res = fread(((char*)real_mode) + SECT_SIZE, SECT_SIZE, setup_sects, fin);
  224. assert(res == setup_sects);
  225. assert(*((uint16_t*)(((char*)real_mode)+0x1fe)) == 0xaa55);
  226. assert(*((uint32_t*)(((char*)real_mode)+0x202)) == 0x53726448);
  227. size_t prot_mode_size;
  228. void *prot_mode = read_whole_file(fin, &prot_mode_size);
  229. printf("Protected mode code/data is 0x%x bytes long\n", prot_mode_size);
  230. fclose(fin);
  231. prepare_setup_header(real_mode, 0, 0);
  232. //load_linux_gdt();
  233. fin = fopen("/ram/cont/realmode.bin", "rb");
  234. size_t trampoline_size;
  235. void *trampoline = read_whole_file(fin, &trampoline_size);
  236. printf("Trampoline is 0x%x bytes long\n", trampoline_size);
  237. fclose(fin);
  238. prepare_real_mode_gdt();
  239. char *cmdline = "verbose";
  240. // Here we really smash our operating system!
  241. memset((void*) 0x10000, 0, 0x10000);
  242. memcpy((void*) 0x500, trampoline, trampoline_size);
  243. memcpy((void*) 0x10000, real_mode, real_mode_size);
  244. memcpy((void*) 0x1e000, cmdline, strlen(cmdline));
  245. memcpy((void*) 0x100000, prot_mode, prot_mode_size);
  246. ((void (*)()) 0x500)();
  247. free(trampoline);
  248. free(real_mode);
  249. free(prot_mode);
  250. }
  251. void load_mlb() {
  252. download_file("http://10.0.2.2:8080/realmode2", "/ram/cont/realmode.bin");
  253. download_file("http://10.0.2.2:8080/example", "/ram/cont/bootloader");
  254. FILE *fin = fopen("/ram/cont/realmode.bin", "rb");
  255. size_t trampoline_size;
  256. void *trampoline = read_whole_file(fin, &trampoline_size);
  257. printf("Trampoline is 0x%x bytes long\n", trampoline_size);
  258. fclose(fin);
  259. prepare_real_mode_gdt();
  260. fin = fopen("/ram/cont/bootloader", "rb");
  261. size_t bootloader_size;
  262. void *bootloader = read_whole_file(fin, &bootloader_size);
  263. printf("Bootloader is 0x%x bytes long\n", bootloader_size);
  264. fclose(fin);
  265. prepare_real_mode_gdt();
  266. memset((void*) 0x10000, 0, 0x10000);
  267. memcpy((void*) 0x500, trampoline, trampoline_size);
  268. memcpy((void*) 0x7c00, bootloader, bootloader_size);
  269. ((void (*)()) 0x500)();
  270. }
  271. int main(int argc, char *argv[]) {
  272. printf("Hello world from continue2.c!\n");
  273. //load_linux32();
  274. //load_linux();
  275. //load_mlb();
  276. return 0;
  277. }