1 // Disk setup and access
3 // Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2002 MandrakeSoft S.A.
6 // This file may be distributed under the terms of the GNU LGPLv3 license.
8 #include "disk.h" // struct ata_s
9 #include "biosvar.h" // GET_GLOBAL
10 #include "cmos.h" // inb_cmos
11 #include "util.h" // dprintf
13 struct drives_s Drives VAR16_32;
16 /****************************************************************
17 * Disk geometry translation
18 ****************************************************************/
21 get_translation(int driveid)
23 u8 type = GET_GLOBAL(Drives.drives[driveid].type);
24 if (! CONFIG_COREBOOT && type == DTYPE_ATA) {
25 // Emulators pass in the translation info via nvram.
26 u8 ataid = GET_GLOBAL(Drives.drives[driveid].cntl_id);
27 u8 channel = ataid / 2;
28 u8 translation = inb_cmos(CMOS_BIOS_DISKTRANSFLAG + channel/2);
29 translation >>= 2 * (ataid % 4);
34 // On COREBOOT, use a heuristic to determine translation type.
35 u16 heads = GET_GLOBAL(Drives.drives[driveid].pchs.heads);
36 u16 cylinders = GET_GLOBAL(Drives.drives[driveid].pchs.cylinders);
37 u16 spt = GET_GLOBAL(Drives.drives[driveid].pchs.spt);
39 if (cylinders <= 1024 && heads <= 16 && spt <= 63)
40 return TRANSLATION_NONE;
41 if (cylinders * heads <= 131072)
42 return TRANSLATION_LARGE;
43 return TRANSLATION_LBA;
47 setup_translation(int driveid)
49 u8 translation = get_translation(driveid);
50 SET_GLOBAL(Drives.drives[driveid].translation, translation);
52 u8 ataid = GET_GLOBAL(Drives.drives[driveid].cntl_id);
53 u8 channel = ataid / 2;
55 u16 heads = GET_GLOBAL(Drives.drives[driveid].pchs.heads);
56 u16 cylinders = GET_GLOBAL(Drives.drives[driveid].pchs.cylinders);
57 u16 spt = GET_GLOBAL(Drives.drives[driveid].pchs.spt);
58 u64 sectors = GET_GLOBAL(Drives.drives[driveid].sectors);
60 dprintf(1, "ata%d-%d: PCHS=%u/%d/%d translation="
61 , channel, slave, cylinders, heads, spt);
62 switch (translation) {
63 case TRANSLATION_NONE:
69 if (sectors > 63*255*1024) {
74 u32 sect = (u32)sectors / 63;
86 cylinders = sect / heads;
88 case TRANSLATION_RECHS:
90 // Take care not to overflow
95 cylinders = (u16)((u32)(cylinders)*16/15);
97 // then go through the large bitshift process
98 case TRANSLATION_LARGE:
99 if (translation == TRANSLATION_LARGE)
101 while (cylinders > 1024) {
105 // If we max out the head count
111 // clip to 1024 cylinders in lchs
112 if (cylinders > 1024)
114 dprintf(1, " LCHS=%d/%d/%d\n", cylinders, heads, spt);
116 SET_GLOBAL(Drives.drives[driveid].lchs.heads, heads);
117 SET_GLOBAL(Drives.drives[driveid].lchs.cylinders, cylinders);
118 SET_GLOBAL(Drives.drives[driveid].lchs.spt, spt);
122 /****************************************************************
124 ****************************************************************/
126 // Fill in Fixed Disk Parameter Table (located in ebda).
128 fill_fdpt(int driveid)
133 u16 nlc = GET_GLOBAL(Drives.drives[driveid].lchs.cylinders);
134 u16 nlh = GET_GLOBAL(Drives.drives[driveid].lchs.heads);
135 u16 nlspt = GET_GLOBAL(Drives.drives[driveid].lchs.spt);
137 u16 npc = GET_GLOBAL(Drives.drives[driveid].pchs.cylinders);
138 u16 nph = GET_GLOBAL(Drives.drives[driveid].pchs.heads);
139 u16 npspt = GET_GLOBAL(Drives.drives[driveid].pchs.spt);
141 struct fdpt_s *fdpt = &get_ebda_ptr()->fdpt[driveid];
142 fdpt->precompensation = 0xffff;
143 fdpt->drive_control_byte = 0xc0 | ((nph > 8) << 3);
144 fdpt->landing_zone = npc;
145 fdpt->cylinders = nlc;
147 fdpt->sectors = nlspt;
149 if (nlc == npc && nlh == nph && nlspt == npspt)
150 // no logical CHS mapping used, just physical CHS
151 // use Standard Fixed Disk Parameter Table (FDPT)
154 // complies with Phoenix style Translated Fixed Disk Parameter
156 fdpt->phys_cylinders = npc;
157 fdpt->phys_heads = nph;
158 fdpt->phys_sectors = npspt;
159 fdpt->a0h_signature = 0xa0;
161 // Checksum structure.
162 fdpt->checksum -= checksum(fdpt, sizeof(*fdpt));
165 SET_IVT(0x41, get_ebda_seg()
166 , offsetof(struct extended_bios_data_area_s, fdpt[0]));
168 SET_IVT(0x46, get_ebda_seg()
169 , offsetof(struct extended_bios_data_area_s, fdpt[1]));
172 // Map a drive (that was registered via add_bcv_hd)
174 map_hd_drive(int driveid)
177 u8 hdcount = GET_BDA(hdcount);
178 if (hdcount >= ARRAY_SIZE(Drives.idmap[0]))
180 dprintf(3, "Mapping hd driveid %d to %d\n", driveid, hdcount);
181 SET_GLOBAL(Drives.idmap[EXTTYPE_HD][hdcount], driveid);
182 SET_BDA(hdcount, hdcount + 1);
184 // Fill "fdpt" structure.
190 map_cd_drive(int driveid)
193 u8 cdcount = GET_GLOBAL(Drives.cdcount);
194 if (cdcount >= ARRAY_SIZE(Drives.idmap[0]))
196 dprintf(3, "Mapping cd driveid %d to %d\n", driveid, cdcount);
197 SET_GLOBAL(Drives.idmap[EXTTYPE_CD][cdcount], driveid);
198 SET_GLOBAL(Drives.cdcount, cdcount+1);
203 map_floppy_drive(int driveid)
206 u8 floppycount = GET_GLOBAL(Drives.floppycount);
207 if (floppycount >= ARRAY_SIZE(Drives.idmap[0]))
209 dprintf(3, "Mapping floppy driveid %d to %d\n", driveid, floppycount);
210 SET_GLOBAL(Drives.idmap[EXTTYPE_FLOPPY][floppycount], driveid);
212 SET_GLOBAL(Drives.floppycount, floppycount);
214 // Update equipment word bits for floppy
215 if (floppycount == 1) {
216 // 1 drive, ready for boot
217 SETBITS_BDA(equipment_list_flags, 0x01);
218 SET_BDA(floppy_harddisk_info, 0x07);
220 // 2 drives, ready for boot
221 SETBITS_BDA(equipment_list_flags, 0x41);
222 SET_BDA(floppy_harddisk_info, 0x77);
227 /****************************************************************
229 ****************************************************************/
234 memset(&Drives, 0, sizeof(Drives));
235 memset(&Drives.idmap, 0xff, sizeof(Drives.idmap));