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