]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/grub-2.04/grub-core/disk/i386/pc/biosdisk.c
1.0.07 release
[Ventoy.git] / GRUB2 / grub-2.04 / grub-core / disk / i386 / pc / biosdisk.c
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
4 *
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <grub/machine/biosdisk.h>
20 #include <grub/machine/kernel.h>
21 #include <grub/machine/memory.h>
22 #include <grub/machine/int.h>
23 #include <grub/disk.h>
24 #include <grub/dl.h>
25 #include <grub/mm.h>
26 #include <grub/types.h>
27 #include <grub/misc.h>
28 #include <grub/err.h>
29 #include <grub/term.h>
30 #include <grub/i18n.h>
31
32 GRUB_MOD_LICENSE ("GPLv3+");
33
34 static int cd_drive = 0;
35 static int grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap);
36
37 static int grub_biosdisk_get_num_floppies (void)
38 {
39 struct grub_bios_int_registers regs;
40 int drive;
41
42 /* reset the disk system first */
43 regs.eax = 0;
44 regs.edx = 0;
45 regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
46
47 grub_bios_interrupt (0x13, &regs);
48
49 for (drive = 0; drive < 2; drive++)
50 {
51 regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT | GRUB_CPU_INT_FLAGS_CARRY;
52 regs.edx = drive;
53
54 /* call GET DISK TYPE */
55 regs.eax = 0x1500;
56 grub_bios_interrupt (0x13, &regs);
57 if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY)
58 break;
59
60 /* check if this drive exists */
61 if (!(regs.eax & 0x300))
62 break;
63 }
64
65 return drive;
66 }
67
68 /*
69 * Call IBM/MS INT13 Extensions (int 13 %ah=AH) for DRIVE. DAP
70 * is passed for disk address packet. If an error occurs, return
71 * non-zero, otherwise zero.
72 */
73
74 static int
75 grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap)
76 {
77 struct grub_bios_int_registers regs;
78 regs.eax = ah << 8;
79 /* compute the address of disk_address_packet */
80 regs.ds = (((grub_addr_t) dap) & 0xffff0000) >> 4;
81 regs.esi = (((grub_addr_t) dap) & 0xffff);
82 regs.edx = drive;
83 regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
84
85 grub_bios_interrupt (0x13, &regs);
86 return (regs.eax >> 8) & 0xff;
87 }
88
89 /*
90 * Call standard and old INT13 (int 13 %ah=AH) for DRIVE. Read/write
91 * NSEC sectors from COFF/HOFF/SOFF into SEGMENT. If an error occurs,
92 * return non-zero, otherwise zero.
93 */
94 static int
95 grub_biosdisk_rw_standard (int ah, int drive, int coff, int hoff,
96 int soff, int nsec, int segment)
97 {
98 int ret, i;
99
100 /* Try 3 times. */
101 for (i = 0; i < 3; i++)
102 {
103 struct grub_bios_int_registers regs;
104
105 /* set up CHS information */
106 /* set %ch to low eight bits of cylinder */
107 regs.ecx = (coff << 8) & 0xff00;
108 /* set bits 6-7 of %cl to high two bits of cylinder */
109 regs.ecx |= (coff >> 2) & 0xc0;
110 /* set bits 0-5 of %cl to sector */
111 regs.ecx |= soff & 0x3f;
112
113 /* set %dh to head and %dl to drive */
114 regs.edx = (drive & 0xff) | ((hoff << 8) & 0xff00);
115 /* set %ah to AH */
116 regs.eax = (ah << 8) & 0xff00;
117 /* set %al to NSEC */
118 regs.eax |= nsec & 0xff;
119
120 regs.ebx = 0;
121 regs.es = segment;
122
123 regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
124
125 grub_bios_interrupt (0x13, &regs);
126 /* check if successful */
127 if (!(regs.flags & GRUB_CPU_INT_FLAGS_CARRY))
128 return 0;
129
130 /* save return value */
131 ret = regs.eax >> 8;
132
133 /* if fail, reset the disk system */
134 regs.eax = 0;
135 regs.edx = (drive & 0xff);
136 regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
137 grub_bios_interrupt (0x13, &regs);
138 }
139 return ret;
140 }
141
142 /*
143 * Check if LBA is supported for DRIVE. If it is supported, then return
144 * the major version of extensions, otherwise zero.
145 */
146 static int
147 grub_biosdisk_check_int13_extensions (int drive)
148 {
149 struct grub_bios_int_registers regs;
150
151 regs.edx = drive & 0xff;
152 regs.eax = 0x4100;
153 regs.ebx = 0x55aa;
154 regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
155 grub_bios_interrupt (0x13, &regs);
156
157 if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY)
158 return 0;
159
160 if ((regs.ebx & 0xffff) != 0xaa55)
161 return 0;
162
163 /* check if AH=0x42 is supported */
164 if (!(regs.ecx & 1))
165 return 0;
166
167 return (regs.eax >> 8) & 0xff;
168 }
169
170 /*
171 * Return the geometry of DRIVE in CYLINDERS, HEADS and SECTORS. If an
172 * error occurs, then return non-zero, otherwise zero.
173 */
174 static int
175 grub_biosdisk_get_diskinfo_standard (int drive,
176 unsigned long *cylinders,
177 unsigned long *heads,
178 unsigned long *sectors)
179 {
180 struct grub_bios_int_registers regs;
181
182 regs.eax = 0x0800;
183 regs.edx = drive & 0xff;
184
185 regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
186 grub_bios_interrupt (0x13, &regs);
187
188 /* Check if unsuccessful. Ignore return value if carry isn't set to
189 workaround some buggy BIOSes. */
190 if ((regs.flags & GRUB_CPU_INT_FLAGS_CARRY) && ((regs.eax & 0xff00) != 0))
191 return (regs.eax & 0xff00) >> 8;
192
193 /* bogus BIOSes may not return an error number */
194 /* 0 sectors means no disk */
195 if (!(regs.ecx & 0x3f))
196 /* XXX 0x60 is one of the unused error numbers */
197 return 0x60;
198
199 /* the number of heads is counted from zero */
200 *heads = ((regs.edx >> 8) & 0xff) + 1;
201 *cylinders = (((regs.ecx >> 8) & 0xff) | ((regs.ecx << 2) & 0x0300)) + 1;
202 *sectors = regs.ecx & 0x3f;
203 return 0;
204 }
205
206 static int
207 grub_biosdisk_get_diskinfo_real (int drive, void *drp, grub_uint16_t ax)
208 {
209 struct grub_bios_int_registers regs;
210
211 regs.eax = ax;
212
213 /* compute the address of drive parameters */
214 regs.esi = ((grub_addr_t) drp) & 0xf;
215 regs.ds = ((grub_addr_t) drp) >> 4;
216 regs.edx = drive & 0xff;
217
218 regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
219 grub_bios_interrupt (0x13, &regs);
220
221 /* Check if unsuccessful. Ignore return value if carry isn't set to
222 workaround some buggy BIOSes. */
223 if ((regs.flags & GRUB_CPU_INT_FLAGS_CARRY) && ((regs.eax & 0xff00) != 0))
224 return (regs.eax & 0xff00) >> 8;
225
226 return 0;
227 }
228
229 /*
230 * Return the cdrom information of DRIVE in CDRP. If an error occurs,
231 * then return non-zero, otherwise zero.
232 */
233 static int
234 grub_biosdisk_get_cdinfo_int13_extensions (int drive, void *cdrp)
235 {
236 return grub_biosdisk_get_diskinfo_real (drive, cdrp, 0x4b01);
237 }
238
239 /*
240 * Return the geometry of DRIVE in a drive parameters, DRP. If an error
241 * occurs, then return non-zero, otherwise zero.
242 */
243 static int
244 grub_biosdisk_get_diskinfo_int13_extensions (int drive, void *drp)
245 {
246 return grub_biosdisk_get_diskinfo_real (drive, drp, 0x4800);
247 }
248
249 static int
250 grub_biosdisk_get_drive (const char *name)
251 {
252 unsigned long drive;
253
254 if (name[0] == 'c' && name[1] == 'd' && name[2] == 0 && cd_drive)
255 return cd_drive;
256
257 if ((name[0] != 'f' && name[0] != 'h') || name[1] != 'd')
258 goto fail;
259
260 drive = grub_strtoul (name + 2, 0, 10);
261 if (grub_errno != GRUB_ERR_NONE)
262 goto fail;
263
264 if (name[0] == 'h')
265 drive += 0x80;
266
267 return (int) drive ;
268
269 fail:
270 grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a biosdisk");
271 return -1;
272 }
273
274 static int
275 grub_biosdisk_call_hook (grub_disk_dev_iterate_hook_t hook, void *hook_data,
276 int drive)
277 {
278 char name[10];
279
280 if (cd_drive && drive == cd_drive)
281 return hook ("cd", hook_data);
282
283 grub_snprintf (name, sizeof (name),
284 (drive & 0x80) ? "hd%d" : "fd%d", drive & (~0x80));
285 return hook (name, hook_data);
286 }
287
288 static int
289 grub_biosdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
290 grub_disk_pull_t pull)
291 {
292 int num_floppies;
293 int drive;
294
295 /* For hard disks, attempt to read the MBR. */
296 switch (pull)
297 {
298 case GRUB_DISK_PULL_NONE:
299 for (drive = 0x80; drive < 0x90; drive++)
300 {
301 if (grub_biosdisk_rw_standard (0x02, drive, 0, 0, 1, 1,
302 GRUB_MEMORY_MACHINE_SCRATCH_SEG) != 0)
303 {
304 grub_dprintf ("disk", "Read error when probing drive 0x%2x\n", drive);
305 break;
306 }
307
308 if (grub_biosdisk_call_hook (hook, hook_data, drive))
309 return 1;
310 }
311 return 0;
312
313 case GRUB_DISK_PULL_REMOVABLE:
314 if (cd_drive)
315 {
316 if (grub_biosdisk_call_hook (hook, hook_data, cd_drive))
317 return 1;
318 }
319
320 /* For floppy disks, we can get the number safely. */
321 num_floppies = grub_biosdisk_get_num_floppies ();
322 for (drive = 0; drive < num_floppies; drive++)
323 if (grub_biosdisk_call_hook (hook, hook_data, drive))
324 return 1;
325 return 0;
326 default:
327 return 0;
328 }
329 return 0;
330 }
331
332 #pragma pack(1)
333 typedef struct ventoy_part_table
334 {
335 grub_uint8_t Active; // 0x00 0x80
336
337 grub_uint8_t StartHead;
338 grub_uint16_t StartSector : 6;
339 grub_uint16_t StartCylinder : 10;
340
341 grub_uint8_t FsFlag;
342
343 grub_uint8_t EndHead;
344 grub_uint16_t EndSector : 6;
345 grub_uint16_t EndCylinder : 10;
346
347 grub_uint32_t StartSectorId;
348 grub_uint32_t SectorCount;
349 }ventoy_part_table;
350
351 typedef struct ventoy_mbr_head
352 {
353 grub_uint8_t BootCode[446];
354 ventoy_part_table PartTbl[4];
355 grub_uint8_t Byte55;
356 grub_uint8_t ByteAA;
357 }ventoy_mbr_head;
358 #pragma pack()
359
360 static grub_err_t
361 grub_biosdisk_rw (int cmd, grub_disk_t disk,
362 grub_disk_addr_t sector, grub_size_t size,
363 unsigned segment);
364
365 static int ventoy_is_mbr_match(ventoy_mbr_head *head)
366 {
367 grub_uint32_t PartStartSector;
368
369 if (head->Byte55 != 0x55 || head->ByteAA != 0xAA) {
370 return 0;
371 }
372
373 if (head->PartTbl[2].SectorCount > 0 || head->PartTbl[3].SectorCount > 0) {
374 return 0;
375 }
376
377 if (head->PartTbl[0].FsFlag != 0x07 || head->PartTbl[0].StartSectorId != 2048) {
378 return 0;
379 }
380
381 if (head->PartTbl[1].Active != 0x80 || head->PartTbl[1].FsFlag != 0xEF) {
382 return 0;
383 }
384
385 PartStartSector = head->PartTbl[0].StartSectorId + head->PartTbl[0].SectorCount;
386
387 if (head->PartTbl[1].StartSectorId != PartStartSector || head->PartTbl[1].SectorCount != 65536) {
388 return 0;
389 }
390
391 return 1;
392 }
393
394 static grub_err_t
395 grub_biosdisk_open (const char *name, grub_disk_t disk)
396 {
397 grub_uint64_t total_sectors = 0;
398 int drive;
399 struct grub_biosdisk_data *data;
400
401 drive = grub_biosdisk_get_drive (name);
402 if (drive < 0)
403 return grub_errno;
404
405 disk->id = drive;
406
407 data = (struct grub_biosdisk_data *) grub_zalloc (sizeof (*data));
408 if (! data)
409 return grub_errno;
410
411 data->drive = drive;
412
413 if ((cd_drive) && (drive == cd_drive))
414 {
415 data->flags = GRUB_BIOSDISK_FLAG_LBA | GRUB_BIOSDISK_FLAG_CDROM;
416 data->sectors = 8;
417 disk->log_sector_size = 11;
418 /* TODO: get the correct size. */
419 total_sectors = GRUB_DISK_SIZE_UNKNOWN;
420 }
421 else
422 {
423 /* HDD */
424 int version;
425
426 disk->log_sector_size = 9;
427
428 version = grub_biosdisk_check_int13_extensions (drive);
429 if (version)
430 {
431 struct grub_biosdisk_drp *drp
432 = (struct grub_biosdisk_drp *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
433
434 /* Clear out the DRP. */
435 grub_memset (drp, 0, sizeof (*drp));
436 drp->size = sizeof (*drp);
437 if (! grub_biosdisk_get_diskinfo_int13_extensions (drive, drp))
438 {
439 data->flags = GRUB_BIOSDISK_FLAG_LBA;
440
441 if (drp->total_sectors)
442 total_sectors = drp->total_sectors;
443 else
444 /* Some buggy BIOSes doesn't return the total sectors
445 correctly but returns zero. So if it is zero, compute
446 it by C/H/S returned by the LBA BIOS call. */
447 total_sectors = ((grub_uint64_t) drp->cylinders)
448 * drp->heads * drp->sectors;
449 if (drp->bytes_per_sector
450 && !(drp->bytes_per_sector & (drp->bytes_per_sector - 1))
451 && drp->bytes_per_sector >= 512
452 && drp->bytes_per_sector <= 16384)
453 {
454 for (disk->log_sector_size = 0;
455 (1 << disk->log_sector_size) < drp->bytes_per_sector;
456 disk->log_sector_size++);
457 }
458 }
459 }
460 }
461
462 if (! (data->flags & GRUB_BIOSDISK_FLAG_CDROM))
463 {
464 if (grub_biosdisk_get_diskinfo_standard (drive,
465 &data->cylinders,
466 &data->heads,
467 &data->sectors) != 0)
468 {
469 if (total_sectors && (data->flags & GRUB_BIOSDISK_FLAG_LBA))
470 {
471 data->sectors = 63;
472 data->heads = 255;
473 data->cylinders
474 = grub_divmod64 (total_sectors
475 + data->heads * data->sectors - 1,
476 data->heads * data->sectors, 0);
477 }
478 else
479 {
480 grub_free (data);
481 return grub_error (GRUB_ERR_BAD_DEVICE, "%s cannot get C/H/S values", disk->name);
482 }
483 }
484
485 if (data->sectors == 0)
486 data->sectors = 63;
487 if (data->heads == 0)
488 data->heads = 255;
489
490 if (! total_sectors)
491 total_sectors = ((grub_uint64_t) data->cylinders)
492 * data->heads * data->sectors;
493 }
494
495 disk->total_sectors = total_sectors;
496 /* Limit the max to 0x7f because of Phoenix EDD. */
497 disk->max_agglomerate = 0x7f >> GRUB_DISK_CACHE_BITS;
498 COMPILE_TIME_ASSERT ((0x7f >> GRUB_DISK_CACHE_BITS
499 << (GRUB_DISK_SECTOR_BITS + GRUB_DISK_CACHE_BITS))
500 + sizeof (struct grub_biosdisk_dap)
501 < GRUB_MEMORY_MACHINE_SCRATCH_SIZE);
502
503 disk->data = data;
504
505 //fixup some buggy bios
506 if (total_sectors > (16434495 - 2097152) && total_sectors < (16434495 + 2097152) &&
507 (data->flags & GRUB_BIOSDISK_FLAG_LBA) > 0 && (data->flags & GRUB_BIOSDISK_FLAG_CDROM) == 0) {
508 if (grub_biosdisk_rw(0, disk, 0, 1, GRUB_MEMORY_MACHINE_SCRATCH_SEG) == 0) {
509 ventoy_mbr_head *mbr = (ventoy_mbr_head *)GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
510 if (ventoy_is_mbr_match(mbr)) {
511 total_sectors = mbr->PartTbl[1].StartSectorId + mbr->PartTbl[1].SectorCount + 1;
512 if (disk->total_sectors < total_sectors) {
513 disk->total_sectors = total_sectors;
514 }
515 }
516 }
517 }
518
519 return GRUB_ERR_NONE;
520 }
521
522 static void
523 grub_biosdisk_close (grub_disk_t disk)
524 {
525 grub_free (disk->data);
526 }
527
528 /* For readability. */
529 #define GRUB_BIOSDISK_READ 0
530 #define GRUB_BIOSDISK_WRITE 1
531
532 #define GRUB_BIOSDISK_CDROM_RETRY_COUNT 3
533
534 static grub_err_t
535 grub_biosdisk_rw (int cmd, grub_disk_t disk,
536 grub_disk_addr_t sector, grub_size_t size,
537 unsigned segment)
538 {
539 struct grub_biosdisk_data *data = disk->data;
540
541 /* VirtualBox fails with sectors above 2T on CDs.
542 Since even BD-ROMS are never that big anyway, return error. */
543 if ((data->flags & GRUB_BIOSDISK_FLAG_CDROM)
544 && (sector >> 32))
545 return grub_error (GRUB_ERR_OUT_OF_RANGE,
546 N_("attempt to read or write outside of disk `%s'"),
547 disk->name);
548
549 if (data->flags & GRUB_BIOSDISK_FLAG_LBA)
550 {
551 struct grub_biosdisk_dap *dap;
552
553 dap = (struct grub_biosdisk_dap *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR
554 + (data->sectors
555 << disk->log_sector_size));
556 dap->length = sizeof (*dap);
557 dap->reserved = 0;
558 dap->blocks = size;
559 dap->buffer = segment << 16; /* The format SEGMENT:ADDRESS. */
560 dap->block = sector;
561
562 if (data->flags & GRUB_BIOSDISK_FLAG_CDROM)
563 {
564 int i;
565
566 if (cmd)
567 return grub_error (GRUB_ERR_WRITE_ERROR, N_("cannot write to CD-ROM"));
568
569 for (i = 0; i < GRUB_BIOSDISK_CDROM_RETRY_COUNT; i++)
570 if (! grub_biosdisk_rw_int13_extensions (0x42, data->drive, dap))
571 break;
572
573 if (i == GRUB_BIOSDISK_CDROM_RETRY_COUNT)
574 return grub_error (GRUB_ERR_READ_ERROR, N_("failure reading sector 0x%llx "
575 "from `%s'"),
576 (unsigned long long) sector,
577 disk->name);
578 }
579 else
580 if (grub_biosdisk_rw_int13_extensions (cmd + 0x42, data->drive, dap))
581 {
582 /* Fall back to the CHS mode. */
583 data->flags &= ~GRUB_BIOSDISK_FLAG_LBA;
584 disk->total_sectors = data->cylinders * data->heads * data->sectors;
585 return grub_biosdisk_rw (cmd, disk, sector, size, segment);
586 }
587 }
588 else
589 {
590 unsigned coff, hoff, soff;
591 unsigned head;
592
593 /* It is impossible to reach over 8064 MiB (a bit less than LBA24) with
594 the traditional CHS access. */
595 if (sector >
596 1024 /* cylinders */ *
597 256 /* heads */ *
598 63 /* spt */)
599 return grub_error (GRUB_ERR_OUT_OF_RANGE,
600 N_("attempt to read or write outside of disk `%s'"),
601 disk->name);
602
603 soff = ((grub_uint32_t) sector) % data->sectors + 1;
604 head = ((grub_uint32_t) sector) / data->sectors;
605 hoff = head % data->heads;
606 coff = head / data->heads;
607
608 if (coff >= data->cylinders)
609 return grub_error (GRUB_ERR_OUT_OF_RANGE,
610 N_("attempt to read or write outside of disk `%s'"),
611 disk->name);
612
613 if (grub_biosdisk_rw_standard (cmd + 0x02, data->drive,
614 coff, hoff, soff, size, segment))
615 {
616 switch (cmd)
617 {
618 case GRUB_BIOSDISK_READ:
619 return grub_error (GRUB_ERR_READ_ERROR, N_("failure reading sector 0x%llx "
620 "from `%s'"),
621 (unsigned long long) sector,
622 disk->name);
623 case GRUB_BIOSDISK_WRITE:
624 return grub_error (GRUB_ERR_WRITE_ERROR, N_("failure writing sector 0x%llx "
625 "to `%s'"),
626 (unsigned long long) sector,
627 disk->name);
628 }
629 }
630 }
631
632 return GRUB_ERR_NONE;
633 }
634
635 /* Return the number of sectors which can be read safely at a time. */
636 static grub_size_t
637 get_safe_sectors (grub_disk_t disk, grub_disk_addr_t sector)
638 {
639 grub_size_t size;
640 grub_uint64_t offset;
641 struct grub_biosdisk_data *data = disk->data;
642 grub_uint32_t sectors = data->sectors;
643
644 /* OFFSET = SECTOR % SECTORS */
645 grub_divmod64 (sector, sectors, &offset);
646
647 size = sectors - offset;
648
649 return size;
650 }
651
652 static grub_err_t
653 grub_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
654 grub_size_t size, char *buf)
655 {
656 while (size)
657 {
658 grub_size_t len;
659
660 len = get_safe_sectors (disk, sector);
661
662 if (len > size)
663 len = size;
664
665 if (grub_biosdisk_rw (GRUB_BIOSDISK_READ, disk, sector, len,
666 GRUB_MEMORY_MACHINE_SCRATCH_SEG))
667 return grub_errno;
668
669 grub_memcpy (buf, (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR,
670 len << disk->log_sector_size);
671
672 buf += len << disk->log_sector_size;
673 sector += len;
674 size -= len;
675 }
676
677 return grub_errno;
678 }
679
680 static grub_err_t
681 grub_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector,
682 grub_size_t size, const char *buf)
683 {
684 struct grub_biosdisk_data *data = disk->data;
685
686 if (data->flags & GRUB_BIOSDISK_FLAG_CDROM)
687 return grub_error (GRUB_ERR_IO, N_("cannot write to CD-ROM"));
688
689 while (size)
690 {
691 grub_size_t len;
692
693 len = get_safe_sectors (disk, sector);
694 if (len > size)
695 len = size;
696
697 grub_memcpy ((void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR, buf,
698 len << disk->log_sector_size);
699
700 if (grub_biosdisk_rw (GRUB_BIOSDISK_WRITE, disk, sector, len,
701 GRUB_MEMORY_MACHINE_SCRATCH_SEG))
702 return grub_errno;
703
704 buf += len << disk->log_sector_size;
705 sector += len;
706 size -= len;
707 }
708
709 return grub_errno;
710 }
711
712 static struct grub_disk_dev grub_biosdisk_dev =
713 {
714 .name = "biosdisk",
715 .id = GRUB_DISK_DEVICE_BIOSDISK_ID,
716 .disk_iterate = grub_biosdisk_iterate,
717 .disk_open = grub_biosdisk_open,
718 .disk_close = grub_biosdisk_close,
719 .disk_read = grub_biosdisk_read,
720 .disk_write = grub_biosdisk_write,
721 .next = 0
722 };
723
724 static void
725 grub_disk_biosdisk_fini (void)
726 {
727 grub_disk_dev_unregister (&grub_biosdisk_dev);
728 }
729
730 GRUB_MOD_INIT(biosdisk)
731 {
732 struct grub_biosdisk_cdrp *cdrp
733 = (struct grub_biosdisk_cdrp *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
734 grub_uint8_t boot_drive;
735
736 if (grub_disk_firmware_is_tainted)
737 {
738 grub_puts_ (N_("Native disk drivers are in use. "
739 "Refusing to use firmware disk interface."));
740 return;
741 }
742 grub_disk_firmware_fini = grub_disk_biosdisk_fini;
743
744 grub_memset (cdrp, 0, sizeof (*cdrp));
745 cdrp->size = sizeof (*cdrp);
746 cdrp->media_type = 0xFF;
747 boot_drive = (grub_boot_device >> 24);
748 if ((! grub_biosdisk_get_cdinfo_int13_extensions (boot_drive, cdrp))
749 && ((cdrp->media_type & GRUB_BIOSDISK_CDTYPE_MASK)
750 == GRUB_BIOSDISK_CDTYPE_NO_EMUL))
751 cd_drive = cdrp->drive_no;
752 /* Since diskboot.S rejects devices over 0x90 it must be a CD booted with
753 cdboot.S
754 */
755 if (boot_drive >= 0x90)
756 cd_drive = boot_drive;
757
758 grub_disk_dev_register (&grub_biosdisk_dev);
759 }
760
761 GRUB_MOD_FINI(biosdisk)
762 {
763 grub_disk_biosdisk_fini ();
764 }