From 6768cf54c2ee0f5a5be3eb30cece3beeaad661eb Mon Sep 17 00:00:00 2001 From: kevans Date: Sun, 21 Apr 2019 04:35:49 +0000 Subject: [PATCH] MFC r343911, r344238-r344241, r344247, r344254-r344255, r344260, r344268, r344335, r344839, r345066, r345330 r343911: Allow reading the UEFI variable size When loading bigger variables form UEFI it is necessary to know their size beforehand, so that an appropriate amount of memory can be allocated. The easiest way to do this is to try to read the variable with buffer size equal 0, expecting EFI_BUFFER_TOO_SMALL error to be returned. Allow such possible approach in efi_getenv routine. Extracted from a bigger patch as suggested by imp. r344238: Restore loader(8)'s ability for lsdev to show partitions within a bsd slice. I'm pretty sure this used to work at one time, perhaps long ago. It has been failing recently because if you call disk_open() with dev->d_partition set to -1 when d_slice refers to a bsd slice, it assumes you want it to open the first partition within that slice. When you then pass that open dev instance to ptable_open(), it tries to read the start of the 'a' partition and decides there is no recognizable partition type there. This restores the old functionality by resetting d_offset to the start of the raw slice after disk_open() returns. For good measure, d_partition is also set back to -1, although that doesn't currently affect anything. I would have preferred to make disk_open() avoid such rude assumptions and if you ask for partition -1 you get the raw slice. But the commit history shows that someone already did that once (r239058), and had to revert it (r239232), so I didn't even try to go down that road. r344239: Use a couple local variables to avoid repetitive long expressions that cause line-wrapping. r344240: Make lsdev -v output line up in neat columns by using a fixed width for the size field and a tab between the partition type and the size. Changes this disk devices: disk0 (MMC) disk0s1: DOS/Windows 49MB disk0s2: FreeBSD 14GB disk0s2a: FreeBSD UFS 14GB disk0s2b: Unknown 2048KB disk0s2d: FreeBSD UFS 2040KB to this disk devices: disk0 (MMC) disk0s1: DOS/Windows 49MB disk0s2: FreeBSD 14GB disk0s2a: FreeBSD UFS 14GB disk0s2b: Unknown 2048KB disk0s2d: FreeBSD UFS 2040KB r344241: Garbage collection no-longer-used constant. r344247: Make uboot_devdesc properly alias disk_devdesc, so that parsing the u-boot loaderdev variable works correctly. The uboot_devdesc struct is variously cast back and forth between uboot_devdesc and disk_devdesc as pointers are handed off through various opaque interfaces. uboot_devdesc attempted to mimic the layout of disk_devdesc by having a devdesc struct, followed by a union of some device-specific stuff that included a struct that contains the same fields as a disk_devdesc. However, one of those fields inside the struct is 64-bit which causes the entire union to be 64-bit aligned -- 32 bits of padding is added between the struct devdesc and the union, so the whole mess ends up NOT properly mimicking a disk_devdesc after all. (In disk_devdesc there is also 32 bits of padding, but it shows up immediately before the d_offset field, rather than before the whole collection of d_* fields.) This fixes the problem by using an anonymous union to overlay the devdesc field uboot network devices need with the disk_devdesc that uboot storage devices need. This is a different solution than the one contributed with the PR (so if anything goes wrong, the blame goes to me), but 95% of the credit for this fix goes to Pawel Worach and Manuel Stuhn who analyzed the problem and proposed a fix. r344254: Use DEV_TYP_NONE instead of -1 to indicate no device was specified. DEV_TYP_NONE has a value of zero, which makes more sense since the device type is a bunch of bits describing the device, crammed into an int. r344255: Fix more places to use DEV_TYP_NONE instead of -1 to indicate 'no device'. r344260: Allow the u-boot loaderdev env var to be formatted in the "usual" loader(8) way: device[s|p]. E.g., disk0s2a or disk3p12. The code first tries to parse the variable in this format using the standard disk_parsedev(). If that fails, it falls back to parsing the legacy format that has been supported by ubldr for years. In addition to 'disk', all the valid uboot device names can also be used: mmc, sata, usb, ide, scsi. The 'disk' device serves as an alias for all those types and will match the Nth storage-type device found (where N is the unit number). r344268: loader: ptable_close() should check its argument If the passed in table is NULL, just return. r344335: Fix the handling of legacy-format devices in the u-boot loaderdev variable. When I added support for the standard loader(8) disk0s2a: type formats, the parsing of legacy format was broken because it also contains a colon, but it comes before the slice and partition. That would cause disk_parsedev() to return success with the slice and partition set to wildcard values. This change examines the string first, and if it contains spaces, dots, or a colon at any position other than the end, it must be a legacy-format string and we don't even try to use disk_parsedev() on it. r344839: Add retry loop around GetMemoryMap call to fix fragmentation bug The call to BS->AllocatePages can cause the memory map to become framented, causing BS->GetMemoryMap to return EFI_BUFFER_TOO_SMALL more than once. For example this can happen on the MinnowBoard Turbot, causing the boot to stop with an error. Avoid this by calling GetMemoryMap in a loop. r345066: stand: Improve some debugging experience Some of these files using _DEBUG defined a DEBUG() macro to serve as a debug-printf. -DDEBUG is useful to enable some debugging output across multiple ELF/common parts, so switch the DEBUG-as-printf macros over to something more like DPRINTF that is more commonly used for this kind of thing and less likely to conflict. userboot/elf64_freebsd debugging also assumed %llx for uint64; use PRIx64 instead. r345330: loader: fix loading of kernels with . in path The loader indended to search the kernel file name (only) for . but instead searched the entire path, so paths like "boot/test.elfv2/kernel" would not work. PR: 233097 --- stand/common/bcache.c | 10 +- stand/common/disk.c | 49 +++++---- stand/common/interp_forth.c | 8 +- stand/common/load_elf.c | 18 ++-- stand/common/part.c | 73 +++++++------ stand/efi/libefi/efienv.c | 2 +- stand/efi/loader/bootinfo.c | 136 ++++++++++++++---------- stand/efi/loader/copy.c | 33 ++++-- stand/uboot/common/main.c | 63 ++++++++--- stand/uboot/lib/libuboot.h | 14 +-- stand/userboot/userboot/elf64_freebsd.c | 5 +- 11 files changed, 238 insertions(+), 173 deletions(-) diff --git a/stand/common/bcache.c b/stand/common/bcache.c index 5affaf5f0fd..82d8b4ed438 100644 --- a/stand/common/bcache.c +++ b/stand/common/bcache.c @@ -44,9 +44,9 @@ __FBSDID("$FreeBSD$"); /* #define BCACHE_DEBUG */ #ifdef BCACHE_DEBUG -# define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) +# define DPRINTF(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) #else -# define DEBUG(fmt, args...) +# define DPRINTF(fmt, args...) #endif struct bcachectl @@ -369,7 +369,7 @@ bcache_strategy(void *devdata, int rw, daddr_t blk, size_t size, /* bypass large requests, or when the cache is inactive */ if (bc == NULL || ((size * 2 / bcache_blksize) > bcache_nblks)) { - DEBUG("bypass %zu from %qu", size / bcache_blksize, blk); + DPRINTF("bypass %zu from %qu", size / bcache_blksize, blk); bcache_bypasses++; rw &= F_MASK; return (dd->dv_strategy(dd->dv_devdata, rw, blk, size, buf, rsize)); @@ -444,7 +444,7 @@ bcache_insert(struct bcache *bc, daddr_t blkno) cand = BHASH(bc, blkno); - DEBUG("insert blk %llu -> %u # %d", blkno, cand, bcache_bcount); + DPRINTF("insert blk %llu -> %u # %d", blkno, cand, bcache_bcount); bc->bcache_ctl[cand].bc_blkno = blkno; bc->bcache_ctl[cand].bc_count = bcache_bcount++; } @@ -461,7 +461,7 @@ bcache_invalidate(struct bcache *bc, daddr_t blkno) if (bc->bcache_ctl[i].bc_blkno == blkno) { bc->bcache_ctl[i].bc_count = -1; bc->bcache_ctl[i].bc_blkno = -1; - DEBUG("invalidate blk %llu", blkno); + DPRINTF("invalidate blk %llu", blkno); } } diff --git a/stand/common/disk.c b/stand/common/disk.c index ec714b24d85..fb0ec980581 100644 --- a/stand/common/disk.c +++ b/stand/common/disk.c @@ -38,9 +38,9 @@ __FBSDID("$FreeBSD$"); #include "disk.h" #ifdef DISK_DEBUG -# define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) +# define DPRINTF(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) #else -# define DEBUG(fmt, args...) +# define DPRINTF(fmt, args...) #endif struct open_disk { @@ -75,7 +75,7 @@ display_size(uint64_t size, u_int sectorsize) size /= 1024; unit = 'M'; } - sprintf(buf, "%ld%cB", (long)size, unit); + sprintf(buf, "%4ld%cB", (long)size, unit); return (buf); } @@ -102,7 +102,6 @@ ptblread(void *d, void *buf, size_t blocks, uint64_t offset) blocks * od->sectorsize, (char *)buf, NULL)); } -#define PWIDTH 35 static int ptable_print(void *arg, const char *pname, const struct ptable_entry *part) { @@ -112,16 +111,16 @@ ptable_print(void *arg, const char *pname, const struct ptable_entry *part) struct ptable *table; char line[80]; int res; + u_int sectsize; + uint64_t partsize; pa = (struct print_args *)arg; od = (struct open_disk *)pa->dev->dd.d_opendata; - sprintf(line, " %s%s: %s", pa->prefix, pname, - parttype2str(part->type)); - if (pa->verbose) - sprintf(line, "%-*s%s", PWIDTH, line, - display_size(part->end - part->start + 1, - od->sectorsize)); - strcat(line, "\n"); + sectsize = od->sectorsize; + partsize = part->end - part->start + 1; + sprintf(line, " %s%s: %s\t%s\n", pa->prefix, pname, + parttype2str(part->type), + pa->verbose ? display_size(partsize, sectsize) : ""); if (pager_output(line)) return 1; res = 0; @@ -131,10 +130,15 @@ ptable_print(void *arg, const char *pname, const struct ptable_entry *part) dev.dd.d_unit = pa->dev->dd.d_unit; dev.d_slice = part->index; dev.d_partition = -1; - if (disk_open(&dev, part->end - part->start + 1, - od->sectorsize) == 0) { - table = ptable_open(&dev, part->end - part->start + 1, - od->sectorsize, ptblread); + if (disk_open(&dev, partsize, sectsize) == 0) { + /* + * disk_open() for partition -1 on a bsd slice assumes + * you want the first bsd partition. Reset things so + * that we're looking at the start of the raw slice. + */ + dev.d_partition = -1; + dev.d_offset = part->start; + table = ptable_open(&dev, partsize, sectsize, ptblread); if (table != NULL) { sprintf(line, " %s%s", pa->prefix, pname); bsd.dev = pa->dev; @@ -149,7 +153,6 @@ ptable_print(void *arg, const char *pname, const struct ptable_entry *part) return (res); } -#undef PWIDTH int disk_print(struct disk_devdesc *dev, char *prefix, int verbose) @@ -228,7 +231,7 @@ disk_open(struct disk_devdesc *dev, uint64_t mediasize, u_int sectorsize) rc = 0; od = (struct open_disk *)malloc(sizeof(struct open_disk)); if (od == NULL) { - DEBUG("no memory"); + DPRINTF("no memory"); return (ENOMEM); } dev->dd.d_opendata = od; @@ -249,14 +252,14 @@ disk_open(struct disk_devdesc *dev, uint64_t mediasize, u_int sectorsize) slice = dev->d_slice; partition = dev->d_partition; - DEBUG("%s unit %d, slice %d, partition %d => %p", + DPRINTF("%s unit %d, slice %d, partition %d => %p", disk_fmtdev(dev), dev->dd.d_unit, dev->d_slice, dev->d_partition, od); /* Determine disk layout. */ od->table = ptable_open(&partdev, mediasize / sectorsize, sectorsize, ptblread); if (od->table == NULL) { - DEBUG("Can't read partition table"); + DPRINTF("Can't read partition table"); rc = ENXIO; goto out; } @@ -312,7 +315,7 @@ disk_open(struct disk_devdesc *dev, uint64_t mediasize, u_int sectorsize) table = ptable_open(dev, part.end - part.start + 1, od->sectorsize, ptblread); if (table == NULL) { - DEBUG("Can't read BSD label"); + DPRINTF("Can't read BSD label"); rc = ENXIO; goto out; } @@ -340,12 +343,12 @@ disk_open(struct disk_devdesc *dev, uint64_t mediasize, u_int sectorsize) if (od->table != NULL) ptable_close(od->table); free(od); - DEBUG("%s could not open", disk_fmtdev(dev)); + DPRINTF("%s could not open", disk_fmtdev(dev)); } else { /* Save the slice and partition number to the dev */ dev->d_slice = slice; dev->d_partition = partition; - DEBUG("%s offset %lld => %p", disk_fmtdev(dev), + DPRINTF("%s offset %lld => %p", disk_fmtdev(dev), (long long)dev->d_offset, od); } return (rc); @@ -357,7 +360,7 @@ disk_close(struct disk_devdesc *dev) struct open_disk *od; od = (struct open_disk *)dev->dd.d_opendata; - DEBUG("%s closed => %p", disk_fmtdev(dev), od); + DPRINTF("%s closed => %p", disk_fmtdev(dev), od); ptable_close(od->table); free(od); return (0); diff --git a/stand/common/interp_forth.c b/stand/common/interp_forth.c index 19d66cdf3f4..198ffd5b5f4 100644 --- a/stand/common/interp_forth.c +++ b/stand/common/interp_forth.c @@ -39,9 +39,9 @@ INTERP_DEFINE("4th"); /* #define BFORTH_DEBUG */ #ifdef BFORTH_DEBUG -#define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) +#define DPRINTF(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) #else -#define DEBUG(fmt, args...) +#define DPRINTF(fmt, args...) #endif /* @@ -128,7 +128,7 @@ bf_command(FICL_VM *vm) vmUpdateTib(vm, tail + len); } } - DEBUG("cmd '%s'", line); + DPRINTF("cmd '%s'", line); command_errmsg = command_errbuf; command_errbuf[0] = 0; @@ -305,7 +305,7 @@ bf_run(const char *line) */ result = ficlExec(bf_vm, __DECONST(char *, line)); - DEBUG("ficlExec '%s' = %d", line, result); + DPRINTF("ficlExec '%s' = %d", line, result); switch (result) { case VM_OUTOFTEXT: case VM_ABORTQ: diff --git a/stand/common/load_elf.c b/stand/common/load_elf.c index 695eec68a01..97fdac95ec1 100644 --- a/stand/common/load_elf.c +++ b/stand/common/load_elf.c @@ -862,14 +862,16 @@ fake_modname(const char *name) sp++; else sp = name; - ep = strrchr(name, '.'); - if (ep) { - if (ep == name) { - sp = invalid_name; - ep = invalid_name + sizeof(invalid_name) - 1; - } - } else - ep = name + strlen(name); + + ep = strrchr(sp, '.'); + if (ep == NULL) { + ep = sp + strlen(sp); + } + if (ep == sp) { + sp = invalid_name; + ep = invalid_name + sizeof(invalid_name) - 1; + } + len = ep - sp; fp = malloc(len + 1); if (fp == NULL) diff --git a/stand/common/part.c b/stand/common/part.c index da0934d74f0..43e2e70f32e 100644 --- a/stand/common/part.c +++ b/stand/common/part.c @@ -44,9 +44,9 @@ __FBSDID("$FreeBSD$"); #include #ifdef PART_DEBUG -#define DEBUG(fmt, args...) printf("%s: " fmt "\n", __func__, ## args) +#define DPRINTF(fmt, args...) printf("%s: " fmt "\n", __func__, ## args) #else -#define DEBUG(fmt, args...) +#define DPRINTF(fmt, args...) #endif #ifdef LOADER_GPT_SUPPORT @@ -155,34 +155,34 @@ gpt_checkhdr(struct gpt_hdr *hdr, uint64_t lba_self, uint64_t lba_last, uint32_t sz, crc; if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)) != 0) { - DEBUG("no GPT signature"); + DPRINTF("no GPT signature"); return (NULL); } sz = le32toh(hdr->hdr_size); if (sz < 92 || sz > sectorsize) { - DEBUG("invalid GPT header size: %d", sz); + DPRINTF("invalid GPT header size: %d", sz); return (NULL); } crc = le32toh(hdr->hdr_crc_self); hdr->hdr_crc_self = 0; if (crc32(hdr, sz) != crc) { - DEBUG("GPT header's CRC doesn't match"); + DPRINTF("GPT header's CRC doesn't match"); return (NULL); } hdr->hdr_crc_self = crc; hdr->hdr_revision = le32toh(hdr->hdr_revision); if (hdr->hdr_revision < GPT_HDR_REVISION) { - DEBUG("unsupported GPT revision %d", hdr->hdr_revision); + DPRINTF("unsupported GPT revision %d", hdr->hdr_revision); return (NULL); } hdr->hdr_lba_self = le64toh(hdr->hdr_lba_self); if (hdr->hdr_lba_self != lba_self) { - DEBUG("self LBA doesn't match"); + DPRINTF("self LBA doesn't match"); return (NULL); } hdr->hdr_lba_alt = le64toh(hdr->hdr_lba_alt); if (hdr->hdr_lba_alt == hdr->hdr_lba_self) { - DEBUG("invalid alternate LBA"); + DPRINTF("invalid alternate LBA"); return (NULL); } hdr->hdr_entries = le32toh(hdr->hdr_entries); @@ -190,7 +190,7 @@ gpt_checkhdr(struct gpt_hdr *hdr, uint64_t lba_self, uint64_t lba_last, if (hdr->hdr_entries == 0 || hdr->hdr_entsz < sizeof(struct gpt_ent) || sectorsize % hdr->hdr_entsz != 0) { - DEBUG("invalid entry size or number of entries"); + DPRINTF("invalid entry size or number of entries"); return (NULL); } hdr->hdr_lba_start = le64toh(hdr->hdr_lba_start); @@ -214,7 +214,7 @@ gpt_checktbl(const struct gpt_hdr *hdr, uint8_t *tbl, size_t size, /* Check CRC only when buffer size is enough for table. */ if (hdr->hdr_crc_table != crc32(tbl, hdr->hdr_entries * hdr->hdr_entsz)) { - DEBUG("GPT table's CRC doesn't match"); + DPRINTF("GPT table's CRC doesn't match"); return (-1); } } @@ -310,7 +310,7 @@ ptable_gptread(struct ptable *table, void *dev, diskread_t dread) table->type = PTABLE_NONE; goto out; } - DEBUG("GPT detected"); + DPRINTF("GPT detected"); size = MIN(hdr.hdr_entries * hdr.hdr_entsz, MAXTBLSZ * table->sectorsize); @@ -346,7 +346,7 @@ ptable_gptread(struct ptable *table, void *dev, diskread_t dread) entry->flags = le64toh(ent->ent_attr); memcpy(&entry->type.gpt, &ent->ent_type, sizeof(uuid_t)); STAILQ_INSERT_TAIL(&table->entries, entry, entry); - DEBUG("new GPT partition added"); + DPRINTF("new GPT partition added"); } out: free(buf); @@ -402,7 +402,7 @@ ptable_ebrread(struct ptable *table, void *dev, diskread_t dread) buf = malloc(table->sectorsize); if (buf == NULL) return (table); - DEBUG("EBR detected"); + DPRINTF("EBR detected"); for (i = 0; i < MAXEBRENTRIES; i++) { #if 0 /* Some BIOSes return an incorrect number of sectors */ if (offset >= table->sectors) @@ -430,7 +430,7 @@ ptable_ebrread(struct ptable *table, void *dev, diskread_t dread) entry->flags = dp[0].dp_flag; entry->type.mbr = dp[0].dp_typ; STAILQ_INSERT_TAIL(&table->entries, entry, entry); - DEBUG("new EBR partition added"); + DPRINTF("new EBR partition added"); if (dp[1].dp_typ == 0) break; offset = e1->part.start + le32toh(dp[1].dp_start); @@ -470,14 +470,14 @@ ptable_bsdread(struct ptable *table, void *dev, diskread_t dread) int i; if (table->sectorsize < sizeof(struct disklabel)) { - DEBUG("Too small sectorsize"); + DPRINTF("Too small sectorsize"); return (table); } buf = malloc(table->sectorsize); if (buf == NULL) return (table); if (dread(dev, buf, 1, 1) != 0) { - DEBUG("read failed"); + DPRINTF("read failed"); ptable_close(table); table = NULL; goto out; @@ -487,15 +487,15 @@ ptable_bsdread(struct ptable *table, void *dev, diskread_t dread) le32toh(dl->d_magic2) != DISKMAGIC) goto out; if (le32toh(dl->d_secsize) != table->sectorsize) { - DEBUG("unsupported sector size"); + DPRINTF("unsupported sector size"); goto out; } dl->d_npartitions = le16toh(dl->d_npartitions); if (dl->d_npartitions > 20 || dl->d_npartitions < 8) { - DEBUG("invalid number of partitions"); + DPRINTF("invalid number of partitions"); goto out; } - DEBUG("BSD detected"); + DPRINTF("BSD detected"); part = &dl->d_partitions[0]; raw_offset = le32toh(part[RAW_PART].p_offset); for (i = 0; i < dl->d_npartitions; i++, part++) { @@ -513,7 +513,7 @@ ptable_bsdread(struct ptable *table, void *dev, diskread_t dread) entry->part.index = i; /* starts from zero */ entry->type.bsd = part->p_fstype; STAILQ_INSERT_TAIL(&table->entries, entry, entry); - DEBUG("new BSD partition added"); + DPRINTF("new BSD partition added"); } table->type = PTABLE_BSD; out: @@ -556,7 +556,7 @@ ptable_vtoc8read(struct ptable *table, void *dev, diskread_t dread) if (buf == NULL) return (table); if (dread(dev, buf, 1, 0) != 0) { - DEBUG("read failed"); + DPRINTF("read failed"); ptable_close(table); table = NULL; goto out; @@ -566,20 +566,20 @@ ptable_vtoc8read(struct ptable *table, void *dev, diskread_t dread) for (i = sum = 0; i < sizeof(struct vtoc8); i += sizeof(sum)) sum ^= be16dec(buf + i); if (sum != 0) { - DEBUG("incorrect checksum"); + DPRINTF("incorrect checksum"); goto out; } if (be16toh(dl->nparts) != VTOC8_NPARTS) { - DEBUG("invalid number of entries"); + DPRINTF("invalid number of entries"); goto out; } sectors = be16toh(dl->nsecs); heads = be16toh(dl->nheads); if (sectors * heads == 0) { - DEBUG("invalid geometry"); + DPRINTF("invalid geometry"); goto out; } - DEBUG("VTOC8 detected"); + DPRINTF("VTOC8 detected"); for (i = 0; i < VTOC8_NPARTS; i++) { dl->part[i].tag = be16toh(dl->part[i].tag); if (i == VTOC_RAW_PART || @@ -595,7 +595,7 @@ ptable_vtoc8read(struct ptable *table, void *dev, diskread_t dread) entry->part.index = i; /* starts from zero */ entry->type.vtoc8 = dl->part[i].tag; STAILQ_INSERT_TAIL(&table->entries, entry, entry); - DEBUG("new VTOC8 partition added"); + DPRINTF("new VTOC8 partition added"); } table->type = PTABLE_VTOC8; out: @@ -619,7 +619,7 @@ ptable_iso9660read(struct ptable *table, void *dev, diskread_t dread) return (table); if (dread(dev, buf, 1, cdb2devb(16)) != 0) { - DEBUG("read failed"); + DPRINTF("read failed"); ptable_close(table); table = NULL; goto out; @@ -663,7 +663,7 @@ ptable_open(void *dev, uint64_t sectors, uint16_t sectorsize, return (NULL); /* First, read the MBR. */ if (dread(dev, buf, 1, DOSBBSECTOR) != 0) { - DEBUG("read failed"); + DPRINTF("read failed"); goto out; } @@ -703,7 +703,7 @@ ptable_open(void *dev, uint64_t sectors, uint16_t sectorsize, /* Check the MBR magic. */ if (buf[DOSMAGICOFFSET] != 0x55 || buf[DOSMAGICOFFSET + 1] != 0xaa) { - DEBUG("magic sequence not found"); + DPRINTF("magic sequence not found"); #if defined(LOADER_GPT_SUPPORT) /* There is no PMBR, check that we have backup GPT */ table->type = PTABLE_GPT; @@ -715,13 +715,13 @@ ptable_open(void *dev, uint64_t sectors, uint16_t sectorsize, dp = (struct dos_partition *)(buf + DOSPARTOFF); for (i = 0, count = 0; i < NDOSPART; i++) { if (dp[i].dp_flag != 0 && dp[i].dp_flag != 0x80) { - DEBUG("invalid partition flag %x", dp[i].dp_flag); + DPRINTF("invalid partition flag %x", dp[i].dp_flag); goto out; } #ifdef LOADER_GPT_SUPPORT if (dp[i].dp_typ == DOSPTYP_PMBR) { table->type = PTABLE_GPT; - DEBUG("PMBR detected"); + DPRINTF("PMBR detected"); } #endif if (dp[i].dp_typ != 0) @@ -731,9 +731,9 @@ ptable_open(void *dev, uint64_t sectors, uint16_t sectorsize, if (table->type == PTABLE_GPT && count > 1) { if (dp[1].dp_typ != DOSPTYP_HFS) { table->type = PTABLE_NONE; - DEBUG("Incorrect PMBR, ignore it"); + DPRINTF("Incorrect PMBR, ignore it"); } else { - DEBUG("Bootcamp detected"); + DPRINTF("Bootcamp detected"); } } #ifdef LOADER_GPT_SUPPORT @@ -744,7 +744,7 @@ ptable_open(void *dev, uint64_t sectors, uint16_t sectorsize, #endif #ifdef LOADER_MBR_SUPPORT /* Read MBR. */ - DEBUG("MBR detected"); + DPRINTF("MBR detected"); table->type = PTABLE_MBR; for (i = has_ext = 0; i < NDOSPART; i++) { if (dp[i].dp_typ == 0) @@ -770,7 +770,7 @@ ptable_open(void *dev, uint64_t sectors, uint16_t sectorsize, entry->flags = dp[i].dp_flag; entry->type.mbr = dp[i].dp_typ; STAILQ_INSERT_TAIL(&table->entries, entry, entry); - DEBUG("new MBR partition added"); + DPRINTF("new MBR partition added"); } if (has_ext) { table = ptable_ebrread(table, dev, dread); @@ -788,6 +788,9 @@ ptable_close(struct ptable *table) { struct pentry *entry; + if (table == NULL) + return; + while (!STAILQ_EMPTY(&table->entries)) { entry = STAILQ_FIRST(&table->entries); STAILQ_REMOVE_HEAD(&table->entries, entry); diff --git a/stand/efi/libefi/efienv.c b/stand/efi/libefi/efienv.c index 1ee6beeb518..2f063b0a51f 100644 --- a/stand/efi/libefi/efienv.c +++ b/stand/efi/libefi/efienv.c @@ -49,7 +49,7 @@ efi_getenv(EFI_GUID *g, const char *v, void *data, size_t *len) return (EFI_OUT_OF_RESOURCES); dl = *len; rv = RS->GetVariable(uv, g, &attr, &dl, data); - if (rv == EFI_SUCCESS) + if (rv == EFI_SUCCESS || rv == EFI_BUFFER_TOO_SMALL) *len = dl; free(uv); return (rv); diff --git a/stand/efi/loader/bootinfo.c b/stand/efi/loader/bootinfo.c index af0896a4606..b1df11acd53 100644 --- a/stand/efi/loader/bootinfo.c +++ b/stand/efi/loader/bootinfo.c @@ -287,12 +287,12 @@ static int bi_load_efi_data(struct preloaded_file *kfp) { EFI_MEMORY_DESCRIPTOR *mm; - EFI_PHYSICAL_ADDRESS addr; + EFI_PHYSICAL_ADDRESS addr = 0; EFI_STATUS status; const char *efi_novmap; size_t efisz; UINTN efi_mapkey; - UINTN mmsz, pages, retry, sz; + UINTN dsz, pages, retry, sz; UINT32 mmver; struct efi_map_header *efihdr; bool do_vmap; @@ -323,76 +323,94 @@ bi_load_efi_data(struct preloaded_file *kfp) efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf; /* - * Assgin size of EFI_MEMORY_DESCRIPTOR to keep compatible with + * Assign size of EFI_MEMORY_DESCRIPTOR to keep compatible with * u-boot which doesn't fill this value when buffer for memory * descriptors is too small (eg. 0 to obtain memory map size) */ - mmsz = sizeof(EFI_MEMORY_DESCRIPTOR); + dsz = sizeof(EFI_MEMORY_DESCRIPTOR); /* - * It is possible that the first call to ExitBootServices may change - * the map key. Fetch a new map key and retry ExitBootServices in that - * case. + * Allocate enough pages to hold the bootinfo block and the + * memory map EFI will return to us. The memory map has an + * unknown size, so we have to determine that first. Note that + * the AllocatePages call can itself modify the memory map, so + * we have to take that into account as well. The changes to + * the memory map are caused by splitting a range of free + * memory into two, so that one is marked as being loader + * data. + */ + + sz = 0; + + /* + * Matthew Garrett has observed at least one system changing the + * memory map when calling ExitBootServices, causing it to return an + * error, probably because callbacks are allocating memory. + * So we need to retry calling it at least once. */ for (retry = 2; retry > 0; retry--) { - /* - * Allocate enough pages to hold the bootinfo block and the - * memory map EFI will return to us. The memory map has an - * unknown size, so we have to determine that first. Note that - * the AllocatePages call can itself modify the memory map, so - * we have to take that into account as well. The changes to - * the memory map are caused by splitting a range of free - * memory into two (AFAICT), so that one is marked as being - * loader data. - */ - sz = 0; - BS->GetMemoryMap(&sz, NULL, &efi_mapkey, &mmsz, &mmver); - sz += mmsz; - sz = (sz + 0xf) & ~0xf; - pages = EFI_SIZE_TO_PAGES(sz + efisz); - status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, - pages, &addr); - if (EFI_ERROR(status)) { - printf("%s: AllocatePages error %lu\n", __func__, - EFI_ERROR_CODE(status)); - return (ENOMEM); - } + for (;;) { + status = BS->GetMemoryMap(&sz, mm, &efi_mapkey, &dsz, &mmver); + if (!EFI_ERROR(status)) + break; + + if (status != EFI_BUFFER_TOO_SMALL) { + printf("%s: GetMemoryMap error %lu\n", __func__, + EFI_ERROR_CODE(status)); + return (EINVAL); + } + + if (addr != 0) + BS->FreePages(addr, pages); + + /* Add 10 descriptors to the size to allow for + * fragmentation caused by calling AllocatePages */ + sz += (10 * dsz); + pages = EFI_SIZE_TO_PAGES(sz + efisz); + status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, + pages, &addr); + if (EFI_ERROR(status)) { + printf("%s: AllocatePages error %lu\n", __func__, + EFI_ERROR_CODE(status)); + return (ENOMEM); + } - /* - * Read the memory map and stash it after bootinfo. Align the - * memory map on a 16-byte boundary (the bootinfo block is page - * aligned). - */ - efihdr = (struct efi_map_header *)(uintptr_t)addr; - mm = (void *)((uint8_t *)efihdr + efisz); - sz = (EFI_PAGE_SIZE * pages) - efisz; - - status = BS->GetMemoryMap(&sz, mm, &efi_mapkey, &mmsz, &mmver); - if (EFI_ERROR(status)) { - printf("%s: GetMemoryMap error %lu\n", __func__, - EFI_ERROR_CODE(status)); - return (EINVAL); - } - status = BS->ExitBootServices(IH, efi_mapkey); - if (EFI_ERROR(status) == 0) { /* - * This may be disabled by setting efi_disable_vmap in - * loader.conf(5). By default we will setup the virtual - * map entries. + * Read the memory map and stash it after bootinfo. Align the + * memory map on a 16-byte boundary (the bootinfo block is page + * aligned). */ - if (do_vmap) - efi_do_vmap(mm, sz, mmsz, mmver); - efihdr->memory_size = sz; - efihdr->descriptor_size = mmsz; - efihdr->descriptor_version = mmver; - file_addmetadata(kfp, MODINFOMD_EFI_MAP, efisz + sz, - efihdr); - return (0); + efihdr = (struct efi_map_header *)(uintptr_t)addr; + mm = (void *)((uint8_t *)efihdr + efisz); + sz = (EFI_PAGE_SIZE * pages) - efisz; } + + status = BS->ExitBootServices(IH, efi_mapkey); + if (!EFI_ERROR(status)) + break; + } + + if (retry == 0) { BS->FreePages(addr, pages); + printf("ExitBootServices error %lu\n", EFI_ERROR_CODE(status)); + return (EINVAL); } - printf("ExitBootServices error %lu\n", EFI_ERROR_CODE(status)); - return (EINVAL); + + /* + * This may be disabled by setting efi_disable_vmap in + * loader.conf(5). By default we will setup the virtual + * map entries. + */ + + if (do_vmap) + efi_do_vmap(mm, sz, dsz, mmver); + efihdr->memory_size = sz; + efihdr->descriptor_size = dsz; + efihdr->descriptor_version = mmver; + file_addmetadata(kfp, MODINFOMD_EFI_MAP, efisz + sz, + efihdr); + + return (0); } /* diff --git a/stand/efi/loader/copy.c b/stand/efi/loader/copy.c index 293626c95c9..a19b048c9be 100644 --- a/stand/efi/loader/copy.c +++ b/stand/efi/loader/copy.c @@ -95,7 +95,7 @@ static void efi_verify_staging_size(unsigned long *nr_pages) { UINTN sz; - EFI_MEMORY_DESCRIPTOR *map, *p; + EFI_MEMORY_DESCRIPTOR *map = NULL, *p; EFI_PHYSICAL_ADDRESS start, end; UINTN key, dsz; UINT32 dver; @@ -104,17 +104,28 @@ efi_verify_staging_size(unsigned long *nr_pages) unsigned long available_pages = 0; sz = 0; - status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver); - if (status != EFI_BUFFER_TOO_SMALL) { - printf("Can't determine memory map size\n"); - return; - } - map = malloc(sz); - status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver); - if (EFI_ERROR(status)) { - printf("Can't read memory map\n"); - goto out; + for (;;) { + status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver); + if (!EFI_ERROR(status)) + break; + + if (status != EFI_BUFFER_TOO_SMALL) { + printf("Can't read memory map: %lu\n", + EFI_ERROR_CODE(status)); + goto out; + } + + free(map); + + /* Allocate 10 descriptors more than the size reported, + * to allow for any fragmentation caused by calling + * malloc */ + map = malloc(sz + (10 * dsz)); + if (map == NULL) { + printf("Unable to allocate memory\n"); + goto out; + } } ndesc = sz / dsz; diff --git a/stand/uboot/common/main.c b/stand/uboot/common/main.c index c7ca501c7a4..ae8a6570a5b 100644 --- a/stand/uboot/common/main.c +++ b/stand/uboot/common/main.c @@ -156,7 +156,7 @@ get_device_type(const char *devstr, int *devtype) printf("Unknown device type '%s'\n", devstr); } - *devtype = -1; + *devtype = DEV_TYP_NONE; return (NULL); } @@ -182,6 +182,14 @@ device_typename(int type) * The returned values for slice and partition are interpreted by * disk_open(). * + * The device string can be a standard loader(8) disk specifier: + * + * disks disk0s1 + * disks disk1s2a + * diskp disk0p4 + * + * or one of the following formats: + * * Valid device strings: For device types: * * DEV_TYP_STOR, DEV_TYP_NET @@ -198,11 +206,12 @@ device_typename(int type) static void get_load_device(int *type, int *unit, int *slice, int *partition) { + struct disk_devdesc dev; char *devstr; const char *p; char *endp; - *type = -1; + *type = DEV_TYP_NONE; *unit = -1; *slice = 0; *partition = -1; @@ -216,18 +225,38 @@ get_load_device(int *type, int *unit, int *slice, int *partition) p = get_device_type(devstr, type); + /* + * If type is DEV_TYP_STOR we have a disk-like device. If the remainder + * of the string contains spaces, dots, or a colon in any location other + * than the last char, it's legacy format. Otherwise it might be + * standard loader(8) format (e.g., disk0s2a or mmc1p12), so try to + * parse the remainder of the string as such, and if it works, return + * those results. Otherwise we'll fall through to the code that parses + * the legacy format. + */ + if (*type & DEV_TYP_STOR) { + size_t len = strlen(p); + if (strcspn(p, " .") == len && strcspn(p, ":") >= len - 1 && + disk_parsedev(&dev, p, NULL) == 0) { + *unit = dev.dd.d_unit; + *slice = dev.d_slice; + *partition = dev.d_partition; + return; + } + } + /* Ignore optional spaces after the device name. */ while (*p == ' ') p++; /* Unknown device name, or a known name without unit number. */ - if ((*type == -1) || (*p == '\0')) { + if ((*type == DEV_TYP_NONE) || (*p == '\0')) { return; } /* Malformed unit number. */ if (!isdigit(*p)) { - *type = -1; + *type = DEV_TYP_NONE; return; } @@ -242,7 +271,7 @@ get_load_device(int *type, int *unit, int *slice, int *partition) /* Device string is malformed beyond unit number. */ if (*p != ':') { - *type = -1; + *type = DEV_TYP_NONE; *unit = -1; return; } @@ -255,7 +284,7 @@ get_load_device(int *type, int *unit, int *slice, int *partition) /* Only DEV_TYP_STOR devices can have a slice specification. */ if (!(*type & DEV_TYP_STOR)) { - *type = -1; + *type = DEV_TYP_NONE; *unit = -1; return; } @@ -264,7 +293,7 @@ get_load_device(int *type, int *unit, int *slice, int *partition) /* Malformed slice number. */ if (p == endp) { - *type = -1; + *type = DEV_TYP_NONE; *unit = -1; *slice = 0; return; @@ -278,7 +307,7 @@ get_load_device(int *type, int *unit, int *slice, int *partition) /* Device string is malformed beyond slice number. */ if (*p != '.') { - *type = -1; + *type = DEV_TYP_NONE; *unit = -1; *slice = 0; return; @@ -298,7 +327,7 @@ get_load_device(int *type, int *unit, int *slice, int *partition) return; /* Junk beyond partition number. */ - *type = -1; + *type = DEV_TYP_NONE; *unit = -1; *slice = 0; *partition = -1; @@ -310,13 +339,13 @@ print_disk_probe_info() char slice[32]; char partition[32]; - if (currdev.d_disk.slice > 0) - sprintf(slice, "%d", currdev.d_disk.slice); + if (currdev.d_disk.d_slice > 0) + sprintf(slice, "%d", currdev.d_disk.d_slice); else strcpy(slice, ""); - if (currdev.d_disk.partition >= 0) - sprintf(partition, "%d", currdev.d_disk.partition); + if (currdev.d_disk.d_partition >= 0) + sprintf(partition, "%d", currdev.d_disk.d_partition); else strcpy(partition, ""); @@ -332,8 +361,8 @@ probe_disks(int devidx, int load_type, int load_unit, int load_slice, int open_result, unit; struct open_file f; - currdev.d_disk.slice = load_slice; - currdev.d_disk.partition = load_partition; + currdev.d_disk.d_slice = load_slice; + currdev.d_disk.d_partition = load_partition; f.f_devdata = &currdev; open_result = -1; @@ -467,14 +496,14 @@ main(int argc, char **argv) currdev.dd.d_dev = devsw[i]; currdev.dd.d_unit = 0; - if ((load_type == -1 || (load_type & DEV_TYP_STOR)) && + if ((load_type == DEV_TYP_NONE || (load_type & DEV_TYP_STOR)) && strcmp(devsw[i]->dv_name, "disk") == 0) { if (probe_disks(i, load_type, load_unit, load_slice, load_partition) == 0) break; } - if ((load_type == -1 || (load_type & DEV_TYP_NET)) && + if ((load_type == DEV_TYP_NONE || (load_type & DEV_TYP_NET)) && strcmp(devsw[i]->dv_name, "net") == 0) break; } diff --git a/stand/uboot/lib/libuboot.h b/stand/uboot/lib/libuboot.h index 8b81486b1fa..59438e711a6 100644 --- a/stand/uboot/lib/libuboot.h +++ b/stand/uboot/lib/libuboot.h @@ -27,19 +27,15 @@ * $FreeBSD$ */ +#include + struct uboot_devdesc { - struct devdesc dd; /* Must be first. */ union { - struct { - int slice; - int partition; - off_t offset; - } disk; - } d_kind; + struct devdesc dd; + struct disk_devdesc d_disk; + }; }; -#define d_disk d_kind.disk - /* * Default network packet alignment in memory. On arm arches packets must be * aligned to cacheline boundaries. diff --git a/stand/userboot/userboot/elf64_freebsd.c b/stand/userboot/userboot/elf64_freebsd.c index 0dd90fabeb4..8268b7da5d0 100644 --- a/stand/userboot/userboot/elf64_freebsd.c +++ b/stand/userboot/userboot/elf64_freebsd.c @@ -31,6 +31,9 @@ __FBSDID("$FreeBSD$"); #include #include #include +#ifdef DEBUG +#include +#endif #include #include #include @@ -136,7 +139,7 @@ elf64_exec(struct preloaded_file *fp) } #ifdef DEBUG - printf("Start @ %#llx ...\n", ehdr->e_entry); + printf("Start @ %#"PRIx64" ...\n", ehdr->e_entry); #endif dev_cleanup(); -- 2.45.0