~ubuntu-branches/ubuntu/oneiric/seabios/oneiric

« back to all changes in this revision

Viewing changes to .pc/0026-Rename-check_time-to-check_tsc.patch/src/cdrom.c

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn, Serge Hallyn, Dustin Kirkland
  • Date: 2011-02-14 14:38:50 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20110214143850-cmzexufi3dlrt7ga
Tags: 0.6.1.2-0ubuntu1
[ Serge Hallyn ]
* upstream merge
  - updated debian/watch
  - remove all patches as they are applied upstream
  - removed debian-changes-0.6.0-0ubuntu2 - I'm not certain about this one,
    so it may re-introduce a regression

[ Dustin Kirkland ]
* debian/rules: fix lintian warnings, install changelog, make binary build
  arch indep
* debian/control: update standards version

Show diffs side-by-side

added added

removed removed

Lines of Context:
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 "disk.h" // cdrom_13
9
 
#include "util.h" // memset
10
 
#include "bregs.h" // struct bregs
11
 
#include "biosvar.h" // GET_EBDA
12
 
#include "ata.h" // ATA_CMD_REQUEST_SENSE
13
 
#include "blockcmd.h" // CDB_CMD_REQUEST_SENSE
14
 
 
15
 
 
16
 
/****************************************************************
17
 
 * CD emulation
18
 
 ****************************************************************/
19
 
 
20
 
static int
21
 
cdemu_read(struct disk_op_s *op)
22
 
{
23
 
    u16 ebda_seg = get_ebda_seg();
24
 
    struct drive_s *drive_g;
25
 
    drive_g = GLOBALFLAT2GLOBAL(GET_EBDA2(ebda_seg, cdemu.emulated_drive_gf));
26
 
    struct disk_op_s dop;
27
 
    dop.drive_g = drive_g;
28
 
    dop.command = op->command;
29
 
    dop.lba = GET_EBDA2(ebda_seg, cdemu.ilba) + op->lba / 4;
30
 
 
31
 
    int count = op->count;
32
 
    op->count = 0;
33
 
    u8 *cdbuf_far = (void*)offsetof(struct extended_bios_data_area_s, cdemu_buf);
34
 
 
35
 
    if (op->lba & 3) {
36
 
        // Partial read of first block.
37
 
        dop.count = 1;
38
 
        dop.buf_fl = MAKE_FLATPTR(ebda_seg, cdbuf_far);
39
 
        int ret = process_op(&dop);
40
 
        if (ret)
41
 
            return ret;
42
 
        u8 thiscount = 4 - (op->lba & 3);
43
 
        if (thiscount > count)
44
 
            thiscount = count;
45
 
        count -= thiscount;
46
 
        memcpy_far(FLATPTR_TO_SEG(op->buf_fl)
47
 
                   , (void*)FLATPTR_TO_OFFSET(op->buf_fl)
48
 
                   , ebda_seg, cdbuf_far + (op->lba & 3) * 512
49
 
                   , thiscount * 512);
50
 
        op->buf_fl += thiscount * 512;
51
 
        op->count += thiscount;
52
 
        dop.lba++;
53
 
    }
54
 
 
55
 
    if (count > 3) {
56
 
        // Read n number of regular blocks.
57
 
        dop.count = count / 4;
58
 
        dop.buf_fl = op->buf_fl;
59
 
        int ret = process_op(&dop);
60
 
        op->count += dop.count * 4;
61
 
        if (ret)
62
 
            return ret;
63
 
        u8 thiscount = count & ~3;
64
 
        count &= 3;
65
 
        op->buf_fl += thiscount * 512;
66
 
        dop.lba += thiscount / 4;
67
 
    }
68
 
 
69
 
    if (count) {
70
 
        // Partial read on last block.
71
 
        dop.count = 1;
72
 
        dop.buf_fl = MAKE_FLATPTR(ebda_seg, cdbuf_far);
73
 
        int ret = process_op(&dop);
74
 
        if (ret)
75
 
            return ret;
76
 
        u8 thiscount = count;
77
 
        memcpy_far(FLATPTR_TO_SEG(op->buf_fl)
78
 
                   , (void*)FLATPTR_TO_OFFSET(op->buf_fl)
79
 
                   , ebda_seg, cdbuf_far, thiscount * 512);
80
 
        op->count += thiscount;
81
 
    }
82
 
 
83
 
    return DISK_RET_SUCCESS;
84
 
}
85
 
 
86
 
int
87
 
process_cdemu_op(struct disk_op_s *op)
88
 
{
89
 
    if (!CONFIG_CDROM_EMU)
90
 
        return 0;
91
 
 
92
 
    switch (op->command) {
93
 
    case CMD_READ:
94
 
        return cdemu_read(op);
95
 
    case CMD_WRITE:
96
 
    case CMD_FORMAT:
97
 
        return DISK_RET_EWRITEPROTECT;
98
 
    case CMD_VERIFY:
99
 
    case CMD_RESET:
100
 
    case CMD_SEEK:
101
 
    case CMD_ISREADY:
102
 
        return DISK_RET_SUCCESS;
103
 
    default:
104
 
        op->count = 0;
105
 
        return DISK_RET_EPARAM;
106
 
    }
107
 
}
108
 
 
109
 
struct drive_s *cdemu_drive_gf VAR16VISIBLE;
110
 
 
111
 
void
112
 
cdemu_setup(void)
113
 
{
114
 
    if (!CONFIG_CDROM_EMU)
115
 
        return;
116
 
 
117
 
    struct drive_s *drive_g = malloc_fseg(sizeof(*drive_g));
118
 
    if (! drive_g) {
119
 
        warn_noalloc();
120
 
        cdemu_drive_gf = NULL;
121
 
        return;
122
 
    }
123
 
    memset(drive_g, 0, sizeof(*drive_g));
124
 
    cdemu_drive_gf = drive_g;
125
 
    drive_g->type = DTYPE_CDEMU;
126
 
    drive_g->blksize = DISK_SECTOR_SIZE;
127
 
    drive_g->sectors = (u64)-1;
128
 
}
129
 
 
130
 
struct eltorito_s {
131
 
    u8 size;
132
 
    u8 media;
133
 
    u8 emulated_drive;
134
 
    u8 controller_index;
135
 
    u32 ilba;
136
 
    u16 device_spec;
137
 
    u16 buffer_segment;
138
 
    u16 load_segment;
139
 
    u16 sector_count;
140
 
    u8 cylinders;
141
 
    u8 sectors;
142
 
    u8 heads;
143
 
};
144
 
 
145
 
#define SET_INT13ET(regs,var,val)                                      \
146
 
    SET_FARVAR((regs)->ds, ((struct eltorito_s*)((regs)->si+0))->var, (val))
147
 
 
148
 
// ElTorito - Terminate disk emu
149
 
void
150
 
cdemu_134b(struct bregs *regs)
151
 
{
152
 
    // FIXME ElTorito Hardcoded
153
 
    u16 ebda_seg = get_ebda_seg();
154
 
    SET_INT13ET(regs, size, 0x13);
155
 
    SET_INT13ET(regs, media, GET_EBDA2(ebda_seg, cdemu.media));
156
 
    SET_INT13ET(regs, emulated_drive
157
 
                , GET_EBDA2(ebda_seg, cdemu.emulated_extdrive));
158
 
    struct drive_s *drive_gf = GET_EBDA2(ebda_seg, cdemu.emulated_drive_gf);
159
 
    u8 cntl_id = 0;
160
 
    if (drive_gf)
161
 
        cntl_id = GET_GLOBALFLAT(drive_gf->cntl_id);
162
 
    SET_INT13ET(regs, controller_index, cntl_id / 2);
163
 
    SET_INT13ET(regs, device_spec, cntl_id % 2);
164
 
    SET_INT13ET(regs, ilba, GET_EBDA2(ebda_seg, cdemu.ilba));
165
 
    SET_INT13ET(regs, buffer_segment, GET_EBDA2(ebda_seg, cdemu.buffer_segment));
166
 
    SET_INT13ET(regs, load_segment, GET_EBDA2(ebda_seg, cdemu.load_segment));
167
 
    SET_INT13ET(regs, sector_count, GET_EBDA2(ebda_seg, cdemu.sector_count));
168
 
    SET_INT13ET(regs, cylinders, GET_EBDA2(ebda_seg, cdemu.lchs.cylinders));
169
 
    SET_INT13ET(regs, sectors, GET_EBDA2(ebda_seg, cdemu.lchs.spt));
170
 
    SET_INT13ET(regs, heads, GET_EBDA2(ebda_seg, cdemu.lchs.heads));
171
 
 
172
 
    // If we have to terminate emulation
173
 
    if (regs->al == 0x00) {
174
 
        // FIXME ElTorito Various. Should be handled accordingly to spec
175
 
        SET_EBDA2(ebda_seg, cdemu.active, 0x00); // bye bye
176
 
 
177
 
        // XXX - update floppy/hd count.
178
 
    }
179
 
 
180
 
    disk_ret(regs, DISK_RET_SUCCESS);
181
 
}
182
 
 
183
 
 
184
 
/****************************************************************
185
 
 * CD booting
186
 
 ****************************************************************/
187
 
 
188
 
static int
189
 
atapi_is_ready(struct disk_op_s *op)
190
 
{
191
 
    dprintf(6, "atapi_is_ready (drive=%p)\n", op->drive_g);
192
 
 
193
 
    /* Retry READ CAPACITY for 5 seconds unless MEDIUM NOT PRESENT is
194
 
     * reported by the device.  If the device reports "IN PROGRESS",
195
 
     * 30 seconds is added. */
196
 
    struct cdbres_read_capacity info;
197
 
    int in_progress = 0;
198
 
    u64 end = calc_future_tsc(5000);
199
 
    for (;;) {
200
 
        if (check_time(end)) {
201
 
            dprintf(1, "read capacity failed\n");
202
 
            return -1;
203
 
        }
204
 
 
205
 
        int ret = cdb_read_capacity(op, &info);
206
 
        if (!ret)
207
 
            // Success
208
 
            break;
209
 
 
210
 
        struct cdbres_request_sense sense;
211
 
        ret = cdb_get_sense(op, &sense);
212
 
        if (ret)
213
 
            // Error - retry.
214
 
            continue;
215
 
 
216
 
        // Sense succeeded.
217
 
        if (sense.asc == 0x3a) { /* MEDIUM NOT PRESENT */
218
 
            dprintf(1, "Device reports MEDIUM NOT PRESENT\n");
219
 
            return -1;
220
 
        }
221
 
 
222
 
        if (sense.asc == 0x04 && sense.ascq == 0x01 && !in_progress) {
223
 
            /* IN PROGRESS OF BECOMING READY */
224
 
            printf("Waiting for device to detect medium... ");
225
 
            /* Allow 30 seconds more */
226
 
            end = calc_future_tsc(30000);
227
 
            in_progress = 1;
228
 
        }
229
 
    }
230
 
 
231
 
    u32 blksize = ntohl(info.blksize), sectors = ntohl(info.sectors);
232
 
    if (blksize != GET_GLOBAL(op->drive_g->blksize)) {
233
 
        printf("Unsupported sector size %u\n", blksize);
234
 
        return -1;
235
 
    }
236
 
 
237
 
    dprintf(6, "sectors=%u\n", sectors);
238
 
    printf("%dMB medium detected\n", sectors>>(20-11));
239
 
    return 0;
240
 
}
241
 
 
242
 
int
243
 
cdrom_boot(int cdid)
244
 
{
245
 
    struct disk_op_s dop;
246
 
    memset(&dop, 0, sizeof(dop));
247
 
    dop.drive_g = getDrive(EXTTYPE_CD, cdid);
248
 
    if (!dop.drive_g)
249
 
        return 1;
250
 
 
251
 
    int ret = atapi_is_ready(&dop);
252
 
    if (ret)
253
 
        dprintf(1, "atapi_is_ready returned %d\n", ret);
254
 
 
255
 
    // Read the Boot Record Volume Descriptor
256
 
    u8 buffer[2048];
257
 
    dop.lba = 0x11;
258
 
    dop.count = 1;
259
 
    dop.buf_fl = MAKE_FLATPTR(GET_SEG(SS), buffer);
260
 
    ret = cdb_read(&dop);
261
 
    if (ret)
262
 
        return 3;
263
 
 
264
 
    // Validity checks
265
 
    if (buffer[0])
266
 
        return 4;
267
 
    if (strcmp((char*)&buffer[1], "CD001\001EL TORITO SPECIFICATION") != 0)
268
 
        return 5;
269
 
 
270
 
    // ok, now we calculate the Boot catalog address
271
 
    u32 lba = *(u32*)&buffer[0x47];
272
 
 
273
 
    // And we read the Boot Catalog
274
 
    dop.lba = lba;
275
 
    dop.count = 1;
276
 
    ret = cdb_read(&dop);
277
 
    if (ret)
278
 
        return 7;
279
 
 
280
 
    // Validation entry
281
 
    if (buffer[0x00] != 0x01)
282
 
        return 8;   // Header
283
 
    if (buffer[0x01] != 0x00)
284
 
        return 9;   // Platform
285
 
    if (buffer[0x1E] != 0x55)
286
 
        return 10;  // key 1
287
 
    if (buffer[0x1F] != 0xAA)
288
 
        return 10;  // key 2
289
 
 
290
 
    // Initial/Default Entry
291
 
    if (buffer[0x20] != 0x88)
292
 
        return 11; // Bootable
293
 
 
294
 
    u16 ebda_seg = get_ebda_seg();
295
 
    u8 media = buffer[0x21];
296
 
    SET_EBDA2(ebda_seg, cdemu.media, media);
297
 
 
298
 
    SET_EBDA2(ebda_seg, cdemu.emulated_drive_gf, dop.drive_g);
299
 
 
300
 
    u16 boot_segment = *(u16*)&buffer[0x22];
301
 
    if (!boot_segment)
302
 
        boot_segment = 0x07C0;
303
 
    SET_EBDA2(ebda_seg, cdemu.load_segment, boot_segment);
304
 
    SET_EBDA2(ebda_seg, cdemu.buffer_segment, 0x0000);
305
 
 
306
 
    u16 nbsectors = *(u16*)&buffer[0x26];
307
 
    SET_EBDA2(ebda_seg, cdemu.sector_count, nbsectors);
308
 
 
309
 
    lba = *(u32*)&buffer[0x28];
310
 
    SET_EBDA2(ebda_seg, cdemu.ilba, lba);
311
 
 
312
 
    // And we read the image in memory
313
 
    dop.lba = lba;
314
 
    dop.count = DIV_ROUND_UP(nbsectors, 4);
315
 
    dop.buf_fl = MAKE_FLATPTR(boot_segment, 0);
316
 
    ret = cdb_read(&dop);
317
 
    if (ret)
318
 
        return 12;
319
 
 
320
 
    if (media == 0) {
321
 
        // No emulation requested - return success.
322
 
        SET_EBDA2(ebda_seg, cdemu.emulated_extdrive, EXTSTART_CD + cdid);
323
 
        return 0;
324
 
    }
325
 
 
326
 
    // Emulation of a floppy/harddisk requested
327
 
    if (! CONFIG_CDROM_EMU || !cdemu_drive_gf)
328
 
        return 13;
329
 
 
330
 
    // Set emulated drive id and increase bios installed hardware
331
 
    // number of devices
332
 
    if (media < 4) {
333
 
        // Floppy emulation
334
 
        SET_EBDA2(ebda_seg, cdemu.emulated_extdrive, 0x00);
335
 
        // XXX - get and set actual floppy count.
336
 
        SETBITS_BDA(equipment_list_flags, 0x41);
337
 
 
338
 
        switch (media) {
339
 
        case 0x01:  // 1.2M floppy
340
 
            SET_EBDA2(ebda_seg, cdemu.lchs.spt, 15);
341
 
            SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
342
 
            SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
343
 
            break;
344
 
        case 0x02:  // 1.44M floppy
345
 
            SET_EBDA2(ebda_seg, cdemu.lchs.spt, 18);
346
 
            SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
347
 
            SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
348
 
            break;
349
 
        case 0x03:  // 2.88M floppy
350
 
            SET_EBDA2(ebda_seg, cdemu.lchs.spt, 36);
351
 
            SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
352
 
            SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
353
 
            break;
354
 
        }
355
 
    } else {
356
 
        // Harddrive emulation
357
 
        SET_EBDA2(ebda_seg, cdemu.emulated_extdrive, 0x80);
358
 
        SET_BDA(hdcount, GET_BDA(hdcount) + 1);
359
 
 
360
 
        // Peak at partition table to get chs.
361
 
        struct mbr_s *mbr = (void*)0;
362
 
        u8 sptcyl = GET_FARVAR(boot_segment, mbr->partitions[0].last.sptcyl);
363
 
        u8 cyllow = GET_FARVAR(boot_segment, mbr->partitions[0].last.cyllow);
364
 
        u8 heads = GET_FARVAR(boot_segment, mbr->partitions[0].last.heads);
365
 
 
366
 
        SET_EBDA2(ebda_seg, cdemu.lchs.spt, sptcyl & 0x3f);
367
 
        SET_EBDA2(ebda_seg, cdemu.lchs.cylinders
368
 
                  , ((sptcyl<<2)&0x300) + cyllow + 1);
369
 
        SET_EBDA2(ebda_seg, cdemu.lchs.heads, heads + 1);
370
 
    }
371
 
 
372
 
    // everything is ok, so from now on, the emulation is active
373
 
    SET_EBDA2(ebda_seg, cdemu.active, 0x01);
374
 
    dprintf(6, "cdemu media=%d\n", media);
375
 
 
376
 
    return 0;
377
 
}