0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include "boot.h"
0015 #include <linux/edd.h>
0016 #include "string.h"
0017
0018 #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
0019
0020
0021
0022
0023 static int read_mbr(u8 devno, void *buf)
0024 {
0025 struct biosregs ireg, oreg;
0026
0027 initregs(&ireg);
0028 ireg.ax = 0x0201;
0029 ireg.cx = 0x0001;
0030 ireg.dl = devno;
0031 ireg.bx = (size_t)buf;
0032
0033 intcall(0x13, &ireg, &oreg);
0034
0035 return -(oreg.eflags & X86_EFLAGS_CF);
0036 }
0037
0038 static u32 read_mbr_sig(u8 devno, struct edd_info *ei, u32 *mbrsig)
0039 {
0040 int sector_size;
0041 char *mbrbuf_ptr, *mbrbuf_end;
0042 u32 buf_base, mbr_base;
0043 extern char _end[];
0044 u16 mbr_magic;
0045
0046 sector_size = ei->params.bytes_per_sector;
0047 if (!sector_size)
0048 sector_size = 512;
0049
0050
0051 buf_base = (ds() << 4) + (u32)&_end;
0052 mbr_base = (buf_base+sector_size-1) & ~(sector_size-1);
0053 mbrbuf_ptr = _end + (mbr_base-buf_base);
0054 mbrbuf_end = mbrbuf_ptr + sector_size;
0055
0056
0057 if (!(boot_params.hdr.loadflags & CAN_USE_HEAP))
0058 return -1;
0059 if (mbrbuf_end > (char *)(size_t)boot_params.hdr.heap_end_ptr)
0060 return -1;
0061
0062 memset(mbrbuf_ptr, 0, sector_size);
0063 if (read_mbr(devno, mbrbuf_ptr))
0064 return -1;
0065
0066 *mbrsig = *(u32 *)&mbrbuf_ptr[EDD_MBR_SIG_OFFSET];
0067 mbr_magic = *(u16 *)&mbrbuf_ptr[510];
0068
0069
0070 return mbr_magic == 0xAA55 ? 0 : -1;
0071 }
0072
0073 static int get_edd_info(u8 devno, struct edd_info *ei)
0074 {
0075 struct biosregs ireg, oreg;
0076
0077 memset(ei, 0, sizeof(*ei));
0078
0079
0080
0081 initregs(&ireg);
0082 ireg.ah = 0x41;
0083 ireg.bx = EDDMAGIC1;
0084 ireg.dl = devno;
0085 intcall(0x13, &ireg, &oreg);
0086
0087 if (oreg.eflags & X86_EFLAGS_CF)
0088 return -1;
0089
0090 if (oreg.bx != EDDMAGIC2)
0091 return -1;
0092
0093 ei->device = devno;
0094 ei->version = oreg.ah;
0095 ei->interface_support = oreg.cx;
0096
0097
0098
0099 ei->params.length = sizeof(ei->params);
0100 ireg.ah = 0x48;
0101 ireg.si = (size_t)&ei->params;
0102 intcall(0x13, &ireg, &oreg);
0103
0104
0105
0106
0107 ireg.ah = 0x08;
0108 ireg.es = 0;
0109 intcall(0x13, &ireg, &oreg);
0110
0111 if (!(oreg.eflags & X86_EFLAGS_CF)) {
0112 ei->legacy_max_cylinder = oreg.ch + ((oreg.cl & 0xc0) << 2);
0113 ei->legacy_max_head = oreg.dh;
0114 ei->legacy_sectors_per_track = oreg.cl & 0x3f;
0115 }
0116
0117 return 0;
0118 }
0119
0120 void query_edd(void)
0121 {
0122 char eddarg[8];
0123 int do_mbr = 1;
0124 #ifdef CONFIG_EDD_OFF
0125 int do_edd = 0;
0126 #else
0127 int do_edd = 1;
0128 #endif
0129 int be_quiet;
0130 int devno;
0131 struct edd_info ei, *edp;
0132 u32 *mbrptr;
0133
0134 if (cmdline_find_option("edd", eddarg, sizeof(eddarg)) > 0) {
0135 if (!strcmp(eddarg, "skipmbr") || !strcmp(eddarg, "skip")) {
0136 do_edd = 1;
0137 do_mbr = 0;
0138 }
0139 else if (!strcmp(eddarg, "off"))
0140 do_edd = 0;
0141 else if (!strcmp(eddarg, "on"))
0142 do_edd = 1;
0143 }
0144
0145 be_quiet = cmdline_find_option_bool("quiet");
0146
0147 edp = boot_params.eddbuf;
0148 mbrptr = boot_params.edd_mbr_sig_buffer;
0149
0150 if (!do_edd)
0151 return;
0152
0153
0154
0155
0156
0157 if (!be_quiet)
0158 printf("Probing EDD (edd=off to disable)... ");
0159
0160 for (devno = 0x80; devno < 0x80+EDD_MBR_SIG_MAX; devno++) {
0161
0162
0163
0164
0165 if (!get_edd_info(devno, &ei)
0166 && boot_params.eddbuf_entries < EDDMAXNR) {
0167 memcpy(edp, &ei, sizeof(ei));
0168 edp++;
0169 boot_params.eddbuf_entries++;
0170 }
0171
0172 if (do_mbr && !read_mbr_sig(devno, &ei, mbrptr++))
0173 boot_params.edd_mbr_sig_buf_entries = devno-0x80+1;
0174 }
0175
0176 if (!be_quiet)
0177 printf("ok\n");
0178 }
0179
0180 #endif