]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - IPXE/ipxe_mod_code/ipxe-3fe683e/src/arch/x86/core/ventoy_vdisk.c
d3ccb2b43d0d96e009d736b35b4a9700f63fd957
[Ventoy.git] / IPXE / ipxe_mod_code / ipxe-3fe683e / src / arch / x86 / core / ventoy_vdisk.c
1
2 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
3
4 #include <stdint.h>
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <limits.h>
8 #include <byteswap.h>
9 #include <errno.h>
10 #include <assert.h>
11 #include <ipxe/blockdev.h>
12 #include <ipxe/io.h>
13 #include <ipxe/acpi.h>
14 #include <ipxe/sanboot.h>
15 #include <ipxe/device.h>
16 #include <ipxe/pci.h>
17 #include <ipxe/eltorito.h>
18 #include <ipxe/timer.h>
19 #include <ipxe/umalloc.h>
20 #include <realmode.h>
21 #include <bios.h>
22 #include <biosint.h>
23 #include <bootsector.h>
24 #include <int13.h>
25 #include <ventoy.h>
26
27 int g_debug = 0;
28 char *g_cmdline_copy;
29 void *g_initrd_addr;
30 size_t g_initrd_len;
31 ventoy_chain_head *g_chain;
32 ventoy_img_chunk *g_chunk;
33 uint32_t g_img_chunk_num;
34 ventoy_img_chunk *g_cur_chunk;
35 uint32_t g_disk_sector_size;
36 uint8_t *g_os_param_reserved;
37
38
39 ventoy_override_chunk *g_override_chunk;
40 uint32_t g_override_chunk_num;
41
42 ventoy_virt_chunk *g_virt_chunk;
43 uint32_t g_virt_chunk_num;
44
45 ventoy_sector_flag g_sector_flag[128];
46
47 #define VENTOY_ISO9660_SECTOR_OVERFLOW 2097152
48
49 int g_fixup_iso9660_secover_enable = 0;
50 int g_fixup_iso9660_secover_start = 0;
51 uint64 g_fixup_iso9660_secover_1st_secs = 0;
52 uint64 g_fixup_iso9660_secover_cur_secs = 0;
53 uint64 g_fixup_iso9660_secover_tot_secs = 0;
54
55 static struct int13_disk_address __bss16 ( ventoy_address );
56 #define ventoy_address __use_data16 ( ventoy_address )
57
58 static uint64_t ventoy_remap_lba(uint64_t lba, uint32_t *count)
59 {
60 uint32_t i;
61 uint32_t max_sectors;
62 ventoy_img_chunk *cur;
63
64 if ((NULL == g_cur_chunk) || ((lba) < g_cur_chunk->img_start_sector) || ((lba) > g_cur_chunk->img_end_sector))
65 {
66 g_cur_chunk = NULL;
67 for (i = 0; i < g_img_chunk_num; i++)
68 {
69 cur = g_chunk + i;
70 if (lba >= cur->img_start_sector && lba <= cur->img_end_sector)
71 {
72 g_cur_chunk = cur;
73 break;
74 }
75 }
76 }
77
78 if (g_cur_chunk)
79 {
80 max_sectors = g_cur_chunk->img_end_sector - lba + 1;
81 if (*count > max_sectors)
82 {
83 *count = max_sectors;
84 }
85
86 if (512 == g_disk_sector_size)
87 {
88 return g_cur_chunk->disk_start_sector + ((lba - g_cur_chunk->img_start_sector) << 2);
89 }
90 return g_cur_chunk->disk_start_sector + (lba - g_cur_chunk->img_start_sector) * 2048 / g_disk_sector_size;
91 }
92 return lba;
93 }
94
95 static int ventoy_vdisk_read_real(uint64_t lba, unsigned int count, unsigned long buffer)
96 {
97 uint32_t i = 0;
98 uint32_t left = 0;
99 uint32_t readcount = 0;
100 uint32_t tmpcount = 0;
101 uint16_t status = 0;
102 uint64_t curlba = 0;
103 uint64_t maplba = 0;
104 uint64_t start = 0;
105 uint64_t end = 0;
106 uint64_t override_start = 0;
107 uint64_t override_end = 0;
108 unsigned long phyaddr;
109 unsigned long databuffer = buffer;
110 uint8_t *override_data;
111
112 curlba = lba;
113 left = count;
114
115 while (left > 0)
116 {
117 readcount = left;
118 maplba = ventoy_remap_lba(curlba, &readcount);
119
120 if (g_disk_sector_size == 512)
121 {
122 tmpcount = (readcount << 2);
123 }
124 else
125 {
126 tmpcount = (readcount * 2048) / g_disk_sector_size;
127 }
128
129 phyaddr = user_to_phys(buffer, 0);
130
131 while (tmpcount > 0)
132 {
133 /* Use INT 13, 42 to read the data from real disk */
134 ventoy_address.lba = maplba;
135 ventoy_address.buffer.segment = (uint16_t)(phyaddr >> 4);
136 ventoy_address.buffer.offset = (uint16_t)(phyaddr & 0x0F);
137
138 if (tmpcount >= 64) /* max sectors per transmit */
139 {
140 ventoy_address.count = 64;
141 tmpcount -= 64;
142 maplba += 64;
143 phyaddr += 32768;
144 }
145 else
146 {
147 ventoy_address.count = tmpcount;
148 tmpcount = 0;
149 }
150
151 __asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
152 "sti\n\t"
153 "int $0x13\n\t"
154 "sti\n\t" /* BIOS bugs */
155 "jc 1f\n\t"
156 "xorw %%ax, %%ax\n\t"
157 "\n1:\n\t" )
158 : "=a" ( status )
159 : "a" ( 0x4200 ), "d" ( VENTOY_BIOS_FAKE_DRIVE ),
160 "S" ( __from_data16 ( &ventoy_address ) ) );
161 }
162
163 curlba += readcount;
164 left -= readcount;
165 buffer += (readcount * 2048);
166 }
167
168 start = lba * 2048;
169 if (start > g_chain->real_img_size_in_bytes)
170 {
171 goto end;
172 }
173
174 end = start + count * 2048;
175 for (i = 0; i < g_override_chunk_num; i++)
176 {
177 override_data = g_override_chunk[i].override_data;
178 override_start = g_override_chunk[i].img_offset;
179 override_end = override_start + g_override_chunk[i].override_size;
180
181 if (end <= override_start || start >= override_end)
182 {
183 continue;
184 }
185
186 if (start <= override_start)
187 {
188 if (end <= override_end)
189 {
190 memcpy((char *)databuffer + override_start - start, override_data, end - override_start);
191 }
192 else
193 {
194 memcpy((char *)databuffer + override_start - start, override_data, override_end - override_start);
195 }
196 }
197 else
198 {
199 if (end <= override_end)
200 {
201 memcpy((char *)databuffer, override_data + start - override_start, end - start);
202 }
203 else
204 {
205 memcpy((char *)databuffer, override_data + start - override_start, override_end - start);
206 }
207 }
208
209 if (g_fixup_iso9660_secover_enable && (!g_fixup_iso9660_secover_start) &&
210 g_override_chunk[i].override_size == sizeof(ventoy_iso9660_override))
211 {
212 ventoy_iso9660_override *dirent = (ventoy_iso9660_override *)override_data;
213 if (dirent->first_sector >= VENTOY_ISO9660_SECTOR_OVERFLOW)
214 {
215 g_fixup_iso9660_secover_start = 1;
216 g_fixup_iso9660_secover_cur_secs = 0;
217 }
218 }
219 }
220
221 end:
222
223 return 0;
224 }
225
226 uint64_t ventoy_fixup_iso9660_sector(uint64_t Lba, uint32_t secNum)
227 {
228 uint32_t i = 0;
229
230 if (g_fixup_iso9660_secover_cur_secs > 0)
231 {
232 Lba += VENTOY_ISO9660_SECTOR_OVERFLOW;
233 g_fixup_iso9660_secover_cur_secs += secNum;
234 if (g_fixup_iso9660_secover_cur_secs >= g_fixup_iso9660_secover_tot_secs)
235 {
236 g_fixup_iso9660_secover_start = 0;
237 goto end;
238 }
239 }
240 else
241 {
242 ventoy_iso9660_override *dirent;
243 ventoy_override_chunk *pOverride;
244
245 for (i = 0, pOverride = g_override_chunk; i < g_override_chunk_num; i++, pOverride++)
246 {
247 dirent = (ventoy_iso9660_override *)pOverride->override_data;
248 if (Lba == dirent->first_sector)
249 {
250 g_fixup_iso9660_secover_start = 0;
251 goto end;
252 }
253 }
254
255 if (g_fixup_iso9660_secover_start)
256 {
257 for (i = 0, pOverride = g_override_chunk; i < g_override_chunk_num; i++, pOverride++)
258 {
259 dirent = (ventoy_iso9660_override *)pOverride->override_data;
260 if (Lba + VENTOY_ISO9660_SECTOR_OVERFLOW == dirent->first_sector)
261 {
262 g_fixup_iso9660_secover_tot_secs = (dirent->size + 2047) / 2048;
263 g_fixup_iso9660_secover_cur_secs = secNum;
264 if (g_fixup_iso9660_secover_cur_secs >= g_fixup_iso9660_secover_tot_secs)
265 {
266 g_fixup_iso9660_secover_start = 0;
267 }
268 Lba += VENTOY_ISO9660_SECTOR_OVERFLOW;
269 goto end;
270 }
271 }
272 }
273 }
274
275 end:
276 return Lba;
277 }
278
279 int ventoy_vdisk_read(struct san_device *sandev, uint64_t lba, unsigned int count, unsigned long buffer)
280 {
281 uint32_t i, j;
282 uint64_t curlba;
283 uint64_t lastlba = 0;
284 uint32_t lbacount = 0;
285 unsigned long lastbuffer;
286 uint64_t readend;
287 ventoy_virt_chunk *node;
288 ventoy_sector_flag *cur_flag;
289 ventoy_sector_flag *sector_flag = g_sector_flag;
290 struct i386_all_regs *ix86;
291
292 if (INT13_EXTENDED_READ != sandev->int13_command)
293 {
294 DBGC(sandev, "invalid cmd %u\n", sandev->int13_command);
295 return 0;
296 }
297
298 ix86 = (struct i386_all_regs *)sandev->x86_regptr;
299
300 /* Workaround for SSTR PE loader error */
301 if (g_fixup_iso9660_secover_start)
302 {
303 lba = ventoy_fixup_iso9660_sector(lba, count);
304 }
305
306 readend = (lba + count) * 2048;
307 if (readend <= g_chain->real_img_size_in_bytes)
308 {
309 ventoy_vdisk_read_real(lba, count, buffer);
310 ix86->regs.dl = sandev->drive;
311 return 0;
312 }
313
314 if (count > sizeof(g_sector_flag))
315 {
316 sector_flag = (ventoy_sector_flag *)malloc(count * sizeof(ventoy_sector_flag));
317 }
318
319 for (curlba = lba, cur_flag = sector_flag, j = 0; j < count; j++, curlba++, cur_flag++)
320 {
321 cur_flag->flag = 0;
322 for (node = g_virt_chunk, i = 0; i < g_virt_chunk_num; i++, node++)
323 {
324 if (curlba >= node->mem_sector_start && curlba < node->mem_sector_end)
325 {
326 memcpy((void *)(buffer + j * 2048),
327 (char *)g_virt_chunk + node->mem_sector_offset + (curlba - node->mem_sector_start) * 2048,
328 2048);
329 cur_flag->flag = 1;
330 break;
331 }
332 else if (curlba >= node->remap_sector_start && curlba < node->remap_sector_end)
333 {
334 cur_flag->remap_lba = node->org_sector_start + curlba - node->remap_sector_start;
335 cur_flag->flag = 2;
336 break;
337 }
338 }
339 }
340
341 for (curlba = lba, cur_flag = sector_flag, j = 0; j < count; j++, curlba++, cur_flag++)
342 {
343 if (cur_flag->flag == 2)
344 {
345 if (lastlba == 0)
346 {
347 lastbuffer = buffer + j * 2048;
348 lastlba = cur_flag->remap_lba;
349 lbacount = 1;
350 }
351 else if (lastlba + lbacount == cur_flag->remap_lba)
352 {
353 lbacount++;
354 }
355 else
356 {
357 ventoy_vdisk_read_real(lastlba, lbacount, lastbuffer);
358 lastbuffer = buffer + j * 2048;
359 lastlba = cur_flag->remap_lba;
360 lbacount = 1;
361 }
362 }
363 }
364
365 if (lbacount > 0)
366 {
367 ventoy_vdisk_read_real(lastlba, lbacount, lastbuffer);
368 }
369
370 if (sector_flag != g_sector_flag)
371 {
372 free(sector_flag);
373 }
374
375 ix86->regs.dl = sandev->drive;
376 return 0;
377 }
378
379 static void ventoy_dump_img_chunk(ventoy_chain_head *chain)
380 {
381 uint32_t i;
382 ventoy_img_chunk *chunk;
383
384 chunk = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset);
385
386 printf("##################### ventoy_dump_img_chunk #######################\n");
387
388 for (i = 0; i < chain->img_chunk_num; i++)
389 {
390 printf("%2u: [ %u - %u ] <==> [ %llu - %llu ]\n",
391 i, chunk[i].img_start_sector, chunk[i].img_end_sector,
392 chunk[i].disk_start_sector, chunk[i].disk_end_sector);
393 }
394
395 ventoy_debug_pause();
396 }
397
398 static void ventoy_dump_override_chunk(ventoy_chain_head *chain)
399 {
400 uint32_t i;
401 ventoy_override_chunk *chunk;
402
403 chunk = (ventoy_override_chunk *)((char *)chain + chain->override_chunk_offset);
404
405 printf("##################### ventoy_dump_override_chunk #######################\n");
406
407 for (i = 0; i < g_override_chunk_num; i++)
408 {
409 printf("%2u: [ %llu, %u ]\n", i, chunk[i].img_offset, chunk[i].override_size);
410 }
411
412 ventoy_debug_pause();
413 }
414
415 static void ventoy_dump_virt_chunk(ventoy_chain_head *chain)
416 {
417 uint32_t i;
418 ventoy_virt_chunk *node;
419
420 printf("##################### ventoy_dump_virt_chunk #######################\n");
421 printf("virt_chunk_offset=%u\n", chain->virt_chunk_offset);
422 printf("virt_chunk_num=%u\n", chain->virt_chunk_num);
423
424 node = (ventoy_virt_chunk *)((char *)chain + chain->virt_chunk_offset);
425 for (i = 0; i < chain->virt_chunk_num; i++, node++)
426 {
427 printf("%2u: mem:[ %u, %u, %u ] remap:[ %u, %u, %u ]\n", i,
428 node->mem_sector_start,
429 node->mem_sector_end,
430 node->mem_sector_offset,
431 node->remap_sector_start,
432 node->remap_sector_end,
433 node->org_sector_start);
434 }
435
436 ventoy_debug_pause();
437 }
438
439 static void ventoy_dump_chain(ventoy_chain_head *chain)
440 {
441 uint32_t i = 0;
442 uint8_t chksum = 0;
443 uint8_t *guid;
444 uint8_t *vtoy_reserve;
445
446 guid = chain->os_param.vtoy_disk_guid;
447 for (i = 0; i < sizeof(ventoy_os_param); i++)
448 {
449 chksum += *((uint8_t *)(&(chain->os_param)) + i);
450 }
451
452 vtoy_reserve = (uint8_t *)(chain->os_param.vtoy_reserved);
453
454 printf("##################### ventoy_dump_chain #######################\n");
455
456 printf("os_param will be save at %p\n", ventoy_get_runtime_addr());
457
458 printf("os_param->chksum=0x%x (%s)\n", chain->os_param.chksum, chksum ? "FAILED" : "SUCCESS");
459 printf("os_param->vtoy_disk_guid=%02x%02x%02x%02x\n", guid[0], guid[1], guid[2], guid[3]);
460 printf("os_param->vtoy_disk_size=%llu\n", chain->os_param.vtoy_disk_size);
461 printf("os_param->vtoy_disk_part_id=%u\n", chain->os_param.vtoy_disk_part_id);
462 printf("os_param->vtoy_disk_part_type=%u\n", chain->os_param.vtoy_disk_part_type);
463 printf("os_param->vtoy_img_path=<%s>\n", chain->os_param.vtoy_img_path);
464 printf("os_param->vtoy_img_size=<%llu>\n", chain->os_param.vtoy_img_size);
465 printf("os_param->vtoy_reserve[0]=<%u>\n", vtoy_reserve[0]);
466 printf("os_param->vtoy_reserve[1]=<%u>\n", vtoy_reserve[1]);
467 printf("os_param->vtoy_reserve[2]=<%u>\n", vtoy_reserve[2]);
468 printf("os_param->vtoy_reserve[3]=<%u>\n", vtoy_reserve[3]);
469 printf("os_param->vtoy_img_location_addr=<0x%llx>\n", chain->os_param.vtoy_img_location_addr);
470 printf("os_param->vtoy_img_location_len=<%u>\n", chain->os_param.vtoy_img_location_len);
471 ventoy_debug_pause();
472
473 printf("chain->disk_drive=0x%x\n", chain->disk_drive);
474 printf("chain->drive_map=0x%x\n", chain->drive_map);
475 printf("chain->disk_sector_size=%u\n", chain->disk_sector_size);
476 printf("chain->real_img_size_in_bytes=%llu\n", chain->real_img_size_in_bytes);
477 printf("chain->virt_img_size_in_bytes=%llu\n", chain->virt_img_size_in_bytes);
478 printf("chain->boot_catalog=%u\n", chain->boot_catalog);
479 printf("chain->img_chunk_offset=%u\n", chain->img_chunk_offset);
480 printf("chain->img_chunk_num=%u\n", chain->img_chunk_num);
481 printf("chain->override_chunk_offset=%u\n", chain->override_chunk_offset);
482 printf("chain->override_chunk_num=%u\n", chain->override_chunk_num);
483 printf("chain->virt_chunk_offset=%u\n", chain->virt_chunk_offset);
484 printf("chain->virt_chunk_num=%u\n", chain->virt_chunk_num);
485 ventoy_debug_pause();
486
487 ventoy_dump_img_chunk(chain);
488 ventoy_dump_override_chunk(chain);
489 ventoy_dump_virt_chunk(chain);
490 }
491
492 static int ventoy_update_image_location(ventoy_os_param *param)
493 {
494 uint8_t chksum = 0;
495 unsigned int i;
496 unsigned int length;
497 userptr_t address = 0;
498 ventoy_image_location *location = NULL;
499 ventoy_image_disk_region *region = NULL;
500 ventoy_img_chunk *chunk = g_chunk;
501
502 length = sizeof(ventoy_image_location) + (g_img_chunk_num - 1) * sizeof(ventoy_image_disk_region);
503
504 address = umalloc(length + 4096 * 2);
505 if (!address)
506 {
507 return 0;
508 }
509
510 if (address % 4096)
511 {
512 address += 4096 - (address % 4096);
513 }
514
515 param->chksum = 0;
516 param->vtoy_img_location_addr = user_to_phys(address, 0);
517 param->vtoy_img_location_len = length;
518
519 /* update check sum */
520 for (i = 0; i < sizeof(ventoy_os_param); i++)
521 {
522 chksum += *((uint8_t *)param + i);
523 }
524 param->chksum = (chksum == 0) ? 0 : (uint8_t)(0x100 - chksum);
525
526 location = (ventoy_image_location *)(unsigned long)(address);
527 if (NULL == location)
528 {
529 return 0;
530 }
531
532 memcpy(&location->guid, &param->guid, sizeof(ventoy_guid));
533 location->image_sector_size = 2048;
534 location->disk_sector_size = g_chain->disk_sector_size;
535 location->region_count = g_img_chunk_num;
536
537 region = location->regions;
538
539 for (i = 0; i < g_img_chunk_num; i++)
540 {
541 region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1;
542 region->image_start_sector = chunk->img_start_sector;
543 region->disk_start_sector = chunk->disk_start_sector;
544 region++;
545 chunk++;
546 }
547
548 return 0;
549 }
550
551 int ventoy_boot_vdisk(void *data)
552 {
553 uint8_t chksum = 0;
554 unsigned int i;
555 unsigned int drive;
556
557 (void)data;
558
559 ventoy_address.bufsize = offsetof ( typeof ( ventoy_address ), buffer_phys );
560
561 if (strstr(g_cmdline_copy, "debug"))
562 {
563 g_debug = 1;
564 printf("### ventoy chain boot begin... ###\n");
565 ventoy_debug_pause();
566 }
567
568 g_chain = (ventoy_chain_head *)g_initrd_addr;
569 g_chunk = (ventoy_img_chunk *)((char *)g_chain + g_chain->img_chunk_offset);
570 g_img_chunk_num = g_chain->img_chunk_num;
571 g_disk_sector_size = g_chain->disk_sector_size;
572 g_cur_chunk = g_chunk;
573
574 g_os_param_reserved = (uint8_t *)(g_chain->os_param.vtoy_reserved);
575
576 /* Workaround for Windows & ISO9660 */
577 if (g_os_param_reserved[2] == 1 && g_os_param_reserved[3] == 0)
578 {
579 g_fixup_iso9660_secover_enable = 1;
580 }
581
582 g_override_chunk = (ventoy_override_chunk *)((char *)g_chain + g_chain->override_chunk_offset);
583 g_override_chunk_num = g_chain->override_chunk_num;
584
585 g_virt_chunk = (ventoy_virt_chunk *)((char *)g_chain + g_chain->virt_chunk_offset);
586 g_virt_chunk_num = g_chain->virt_chunk_num;
587
588 if (g_debug)
589 {
590 for (i = 0; i < sizeof(ventoy_os_param); i++)
591 {
592 chksum += *((uint8_t *)(&(g_chain->os_param)) + i);
593 }
594 printf("os param checksum: 0x%x %s\n", g_chain->os_param.chksum, chksum ? "FAILED" : "SUCCESS");
595 }
596
597 ventoy_update_image_location(&(g_chain->os_param));
598
599 if (g_debug)
600 {
601 ventoy_dump_chain(g_chain);
602 }
603
604 drive = ventoy_int13_hook(g_chain);
605
606 if (g_debug)
607 {
608 printf("### ventoy chain boot before boot image ... ###\n");
609 ventoy_debug_pause();
610 }
611
612 ventoy_int13_boot(drive, &(g_chain->os_param), g_cmdline_copy);
613
614 if (g_debug)
615 {
616 printf("!!!!!!!!!! ventoy boot failed !!!!!!!!!!\n");
617 ventoy_debug_pause();
618 }
619
620 return 0;
621 }
622