^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* -*- linux-c -*- ------------------------------------------------------- *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 1991, 1992 Linus Torvalds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright 2007 rPath, Inc. - All Rights Reserved
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright 2009 Intel Corporation; author H. Peter Anvin
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * ----------------------------------------------------------------------- */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Get EDD BIOS disk information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "boot.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/edd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "string.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * Read the MBR (first sector) from a specific device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static int read_mbr(u8 devno, void *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct biosregs ireg, oreg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) initregs(&ireg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) ireg.ax = 0x0201; /* Legacy Read, one sector */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) ireg.cx = 0x0001; /* Sector 0-0-1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) ireg.dl = devno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) ireg.bx = (size_t)buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) intcall(0x13, &ireg, &oreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) return -(oreg.eflags & X86_EFLAGS_CF); /* 0 or -1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static u32 read_mbr_sig(u8 devno, struct edd_info *ei, u32 *mbrsig)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) int sector_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) char *mbrbuf_ptr, *mbrbuf_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) u32 buf_base, mbr_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) extern char _end[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) u16 mbr_magic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) sector_size = ei->params.bytes_per_sector;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) if (!sector_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) sector_size = 512; /* Best available guess */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) /* Produce a naturally aligned buffer on the heap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) buf_base = (ds() << 4) + (u32)&_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) mbr_base = (buf_base+sector_size-1) & ~(sector_size-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) mbrbuf_ptr = _end + (mbr_base-buf_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) mbrbuf_end = mbrbuf_ptr + sector_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) /* Make sure we actually have space on the heap... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (!(boot_params.hdr.loadflags & CAN_USE_HEAP))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (mbrbuf_end > (char *)(size_t)boot_params.hdr.heap_end_ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) memset(mbrbuf_ptr, 0, sector_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (read_mbr(devno, mbrbuf_ptr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) *mbrsig = *(u32 *)&mbrbuf_ptr[EDD_MBR_SIG_OFFSET];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) mbr_magic = *(u16 *)&mbrbuf_ptr[510];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) /* check for valid MBR magic */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return mbr_magic == 0xAA55 ? 0 : -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static int get_edd_info(u8 devno, struct edd_info *ei)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) struct biosregs ireg, oreg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) memset(ei, 0, sizeof(*ei));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) /* Check Extensions Present */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) initregs(&ireg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) ireg.ah = 0x41;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) ireg.bx = EDDMAGIC1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) ireg.dl = devno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) intcall(0x13, &ireg, &oreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (oreg.eflags & X86_EFLAGS_CF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) return -1; /* No extended information */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (oreg.bx != EDDMAGIC2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) ei->device = devno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) ei->version = oreg.ah; /* EDD version number */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) ei->interface_support = oreg.cx; /* EDD functionality subsets */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) /* Extended Get Device Parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) ei->params.length = sizeof(ei->params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) ireg.ah = 0x48;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) ireg.si = (size_t)&ei->params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) intcall(0x13, &ireg, &oreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) /* Get legacy CHS parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) /* Ralf Brown recommends setting ES:DI to 0:0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) ireg.ah = 0x08;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) ireg.es = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) intcall(0x13, &ireg, &oreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (!(oreg.eflags & X86_EFLAGS_CF)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) ei->legacy_max_cylinder = oreg.ch + ((oreg.cl & 0xc0) << 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) ei->legacy_max_head = oreg.dh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) ei->legacy_sectors_per_track = oreg.cl & 0x3f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) void query_edd(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) char eddarg[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) int do_mbr = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) #ifdef CONFIG_EDD_OFF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) int do_edd = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) int do_edd = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) int be_quiet;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) int devno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) struct edd_info ei, *edp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) u32 *mbrptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) if (cmdline_find_option("edd", eddarg, sizeof(eddarg)) > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (!strcmp(eddarg, "skipmbr") || !strcmp(eddarg, "skip")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) do_edd = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) do_mbr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) else if (!strcmp(eddarg, "off"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) do_edd = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) else if (!strcmp(eddarg, "on"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) do_edd = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) be_quiet = cmdline_find_option_bool("quiet");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) edp = boot_params.eddbuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) mbrptr = boot_params.edd_mbr_sig_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (!do_edd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) /* Bugs in OnBoard or AddOnCards Bios may hang the EDD probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) * so give a hint if this happens.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (!be_quiet)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) printf("Probing EDD (edd=off to disable)... ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) for (devno = 0x80; devno < 0x80+EDD_MBR_SIG_MAX; devno++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) * Scan the BIOS-supported hard disks and query EDD
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) * information...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) if (!get_edd_info(devno, &ei)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) && boot_params.eddbuf_entries < EDDMAXNR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) memcpy(edp, &ei, sizeof(ei));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) edp++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) boot_params.eddbuf_entries++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) if (do_mbr && !read_mbr_sig(devno, &ei, mbrptr++))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) boot_params.edd_mbr_sig_buf_entries = devno-0x80+1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) if (!be_quiet)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) printf("ok\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) #endif