These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / seabios / src / cdrom.c
1 // Support for booting from cdroms (the "El Torito" spec).
2 //
3 // Copyright (C) 2008,2009  Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2002  MandrakeSoft S.A.
5 //
6 // This file may be distributed under the terms of the GNU LGPLv3 license.
7
8 #include "biosvar.h" // GET_GLOBAL
9 #include "block.h" // struct drive_s
10 #include "bregs.h" // struct bregs
11 #include "hw/ata.h" // ATA_CMD_REQUEST_SENSE
12 #include "hw/blockcmd.h" // CDB_CMD_REQUEST_SENSE
13 #include "malloc.h" // free
14 #include "output.h" // dprintf
15 #include "std/disk.h" // DISK_RET_SUCCESS
16 #include "string.h" // memset
17 #include "util.h" // cdrom_prepboot
18 #include "tcgbios.h" // tpm_*
19
20
21 /****************************************************************
22  * CD emulation
23  ****************************************************************/
24
25 struct eltorito_s CDEmu VARLOW = { .size=sizeof(CDEmu) };
26 struct drive_s *emulated_drive_gf VARLOW;
27 struct drive_s *cdemu_drive_gf VARFSEG;
28
29 static int
30 cdemu_read(struct disk_op_s *op)
31 {
32     struct drive_s *drive_gf = GET_LOW(emulated_drive_gf);
33     struct disk_op_s dop;
34     dop.drive_gf = drive_gf;
35     dop.command = op->command;
36     dop.lba = GET_LOW(CDEmu.ilba) + op->lba / 4;
37
38     int count = op->count;
39     op->count = 0;
40     u8 *cdbuf_fl = GET_GLOBAL(bounce_buf_fl);
41
42     if (op->lba & 3) {
43         // Partial read of first block.
44         dop.count = 1;
45         dop.buf_fl = cdbuf_fl;
46         int ret = process_op(&dop);
47         if (ret)
48             return ret;
49         u8 thiscount = 4 - (op->lba & 3);
50         if (thiscount > count)
51             thiscount = count;
52         count -= thiscount;
53         memcpy_fl(op->buf_fl, cdbuf_fl + (op->lba & 3) * 512, thiscount * 512);
54         op->buf_fl += thiscount * 512;
55         op->count += thiscount;
56         dop.lba++;
57     }
58
59     if (count > 3) {
60         // Read n number of regular blocks.
61         dop.count = count / 4;
62         dop.buf_fl = op->buf_fl;
63         int ret = process_op(&dop);
64         op->count += dop.count * 4;
65         if (ret)
66             return ret;
67         u8 thiscount = count & ~3;
68         count &= 3;
69         op->buf_fl += thiscount * 512;
70         dop.lba += thiscount / 4;
71     }
72
73     if (count) {
74         // Partial read on last block.
75         dop.count = 1;
76         dop.buf_fl = cdbuf_fl;
77         int ret = process_op(&dop);
78         if (ret)
79             return ret;
80         u8 thiscount = count;
81         memcpy_fl(op->buf_fl, cdbuf_fl, thiscount * 512);
82         op->count += thiscount;
83     }
84
85     return DISK_RET_SUCCESS;
86 }
87
88 int
89 cdemu_process_op(struct disk_op_s *op)
90 {
91     if (!CONFIG_CDROM_EMU)
92         return 0;
93
94     switch (op->command) {
95     case CMD_READ:
96         return cdemu_read(op);
97     case CMD_WRITE:
98     case CMD_FORMAT:
99         return DISK_RET_EWRITEPROTECT;
100     default:
101         return default_process_op(op);
102     }
103 }
104
105 void
106 cdrom_prepboot(void)
107 {
108     if (!CONFIG_CDROM_EMU)
109         return;
110     if (!CDCount)
111         return;
112     if (create_bounce_buf() < 0)
113         return;
114
115     struct drive_s *drive = malloc_fseg(sizeof(*drive));
116     if (!drive) {
117         warn_noalloc();
118         return;
119     }
120     cdemu_drive_gf = drive;
121     memset(drive, 0, sizeof(*drive));
122     drive->type = DTYPE_CDEMU;
123     drive->blksize = DISK_SECTOR_SIZE;
124     drive->sectors = (u64)-1;
125 }
126
127
128 /****************************************************************
129  * CD booting
130  ****************************************************************/
131
132 int
133 cdrom_boot(struct drive_s *drive)
134 {
135     ASSERT32FLAT();
136     struct disk_op_s dop;
137     int cdid = getDriveId(EXTTYPE_CD, drive);
138     memset(&dop, 0, sizeof(dop));
139     dop.drive_gf = drive;
140     if (!dop.drive_gf || cdid < 0)
141         return 1;
142
143     int ret = scsi_is_ready(&dop);
144     if (ret)
145         dprintf(1, "scsi_is_ready returned %d\n", ret);
146
147     // Read the Boot Record Volume Descriptor
148     u8 buffer[CDROM_SECTOR_SIZE];
149     dop.command = CMD_READ;
150     dop.lba = 0x11;
151     dop.count = 1;
152     dop.buf_fl = buffer;
153     ret = process_op(&dop);
154     if (ret)
155         return 3;
156
157     // Validity checks
158     if (buffer[0])
159         return 4;
160     if (strcmp((char*)&buffer[1], "CD001\001EL TORITO SPECIFICATION") != 0)
161         return 5;
162
163     // ok, now we calculate the Boot catalog address
164     u32 lba = *(u32*)&buffer[0x47];
165
166     // And we read the Boot Catalog
167     dop.lba = lba;
168     dop.count = 1;
169     ret = process_op(&dop);
170     if (ret)
171         return 7;
172
173     // Validation entry
174     if (buffer[0x00] != 0x01)
175         return 8;   // Header
176     if (buffer[0x01] != 0x00)
177         return 9;   // Platform
178     if (buffer[0x1E] != 0x55)
179         return 10;  // key 1
180     if (buffer[0x1F] != 0xAA)
181         return 10;  // key 2
182
183     // Initial/Default Entry
184     if (buffer[0x20] != 0x88)
185         return 11; // Bootable
186
187     /* measure 2048 bytes (one sector) */
188     tpm_add_cdrom_catalog(MAKE_FLATPTR(GET_SEG(SS), buffer), sizeof(buffer));
189
190     // Fill in el-torito cdrom emulation fields.
191     emulated_drive_gf = drive;
192     u8 media = buffer[0x21];
193
194     u16 boot_segment = *(u16*)&buffer[0x22];
195     if (!boot_segment)
196         boot_segment = 0x07C0;
197     CDEmu.load_segment = boot_segment;
198     CDEmu.buffer_segment = 0x0000;
199
200     u16 nbsectors = *(u16*)&buffer[0x26];
201     CDEmu.sector_count = nbsectors;
202
203     lba = *(u32*)&buffer[0x28];
204     CDEmu.ilba = lba;
205
206     CDEmu.controller_index = drive->cntl_id / 2;
207     CDEmu.device_spec = drive->cntl_id % 2;
208
209     // And we read the image in memory
210     nbsectors = DIV_ROUND_UP(nbsectors, 4);
211     dop.lba = lba;
212     dop.buf_fl = MAKE_FLATPTR(boot_segment, 0);
213     while (nbsectors) {
214         int count = nbsectors;
215         if (count > 64*1024/CDROM_SECTOR_SIZE)
216             count = 64*1024/CDROM_SECTOR_SIZE;
217         dop.count = count;
218         ret = process_op(&dop);
219         if (ret)
220             return 12;
221         nbsectors -= count;
222         dop.lba += count;
223         dop.buf_fl += count*CDROM_SECTOR_SIZE;
224     }
225
226     if (media == 0) {
227         // No emulation requested - return success.
228         CDEmu.emulated_drive = EXTSTART_CD + cdid;
229         return 0;
230     }
231
232     // Emulation of a floppy/harddisk requested
233     if (! CONFIG_CDROM_EMU || !cdemu_drive_gf)
234         return 13;
235
236     // Set emulated drive id and increase bios installed hardware
237     // number of devices
238     if (media < 4) {
239         // Floppy emulation
240         CDEmu.emulated_drive = 0x00;
241         // XXX - get and set actual floppy count.
242         set_equipment_flags(0x41, 0x41);
243
244         switch (media) {
245         case 0x01:  // 1.2M floppy
246             CDEmu.chs.sptcyl = 15;
247             CDEmu.chs.cyllow = 79;
248             CDEmu.chs.heads = 1;
249             break;
250         case 0x02:  // 1.44M floppy
251             CDEmu.chs.sptcyl = 18;
252             CDEmu.chs.cyllow = 79;
253             CDEmu.chs.heads = 1;
254             break;
255         case 0x03:  // 2.88M floppy
256             CDEmu.chs.sptcyl = 36;
257             CDEmu.chs.cyllow = 79;
258             CDEmu.chs.heads = 1;
259             break;
260         }
261     } else {
262         // Harddrive emulation
263         CDEmu.emulated_drive = 0x80;
264         SET_BDA(hdcount, GET_BDA(hdcount) + 1);
265
266         // Peak at partition table to get chs.
267         struct mbr_s *mbr = MAKE_FLATPTR(boot_segment, 0);
268         CDEmu.chs = mbr->partitions[0].last;
269     }
270
271     // everything is ok, so from now on, the emulation is active
272     CDEmu.media = media;
273     dprintf(6, "cdemu media=%d\n", media);
274
275     return 0;
276 }