| /* |
| * This file is part of the coreboot project. |
| * |
| * Copyright 2012-2015 Google Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; version 2 of the License. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| */ |
| |
| #include <arch/early_variables.h> |
| #include <boot_device.h> |
| #include <console/console.h> |
| #include <fmap.h> |
| #include <commonlib/fmap_serialized.h> |
| #include <stddef.h> |
| #include <string.h> |
| |
| #include "fmap_config.h" |
| |
| /* |
| * See http://code.google.com/p/flashmap/ for more information on FMAP. |
| */ |
| |
| static int fmap_print_once CAR_GLOBAL; |
| |
| int find_fmap_directory(struct region_device *fmrd) |
| { |
| const struct region_device *boot; |
| struct fmap *fmap; |
| size_t fmap_size; |
| size_t offset = FMAP_OFFSET; |
| |
| boot_device_init(); |
| boot = boot_device_ro(); |
| |
| if (boot == NULL) |
| return -1; |
| |
| fmap_size = sizeof(struct fmap); |
| |
| fmap = rdev_mmap(boot, offset, fmap_size); |
| |
| if (fmap == NULL) |
| return -1; |
| |
| if (memcmp(fmap->signature, FMAP_SIGNATURE, sizeof(fmap->signature))) { |
| printk(BIOS_DEBUG, "No FMAP found at %zx offset.\n", offset); |
| rdev_munmap(boot, fmap); |
| return -1; |
| } |
| |
| if (!car_get_var(fmap_print_once)) { |
| printk(BIOS_DEBUG, "FMAP: Found \"%s\" version %d.%d at %zx.\n", |
| fmap->name, fmap->ver_major, fmap->ver_minor, offset); |
| printk(BIOS_DEBUG, "FMAP: base = %llx size = %x #areas = %d\n", |
| (long long)fmap->base, fmap->size, fmap->nareas); |
| car_set_var(fmap_print_once, 1); |
| } |
| |
| fmap_size += fmap->nareas * sizeof(struct fmap_area); |
| |
| rdev_munmap(boot, fmap); |
| |
| return rdev_chain(fmrd, boot, offset, fmap_size); |
| } |
| |
| int fmap_locate_area_as_rdev(const char *name, struct region_device *area) |
| { |
| struct region ar; |
| |
| if (fmap_locate_area(name, &ar)) |
| return -1; |
| |
| return boot_device_ro_subregion(&ar, area); |
| } |
| |
| int fmap_locate_area_as_rdev_rw(const char *name, struct region_device *area) |
| { |
| struct region ar; |
| |
| if (fmap_locate_area(name, &ar)) |
| return -1; |
| |
| return boot_device_rw_subregion(&ar, area); |
| } |
| |
| int fmap_locate_area(const char *name, struct region *ar) |
| { |
| struct region_device fmrd; |
| size_t offset; |
| |
| if (find_fmap_directory(&fmrd)) |
| return -1; |
| |
| /* Start reading the areas just after fmap header. */ |
| offset = sizeof(struct fmap); |
| |
| while (1) { |
| struct fmap_area *area; |
| |
| area = rdev_mmap(&fmrd, offset, sizeof(*area)); |
| |
| if (area == NULL) |
| return -1; |
| |
| if (strcmp((const char *)area->name, name)) { |
| rdev_munmap(&fmrd, area); |
| offset += sizeof(struct fmap_area); |
| continue; |
| } |
| |
| printk(BIOS_DEBUG, "FMAP: area %s found @ %x (%d bytes)\n", |
| name, area->offset, area->size); |
| |
| ar->offset = area->offset; |
| ar->size = area->size; |
| |
| rdev_munmap(&fmrd, area); |
| |
| return 0; |
| } |
| |
| printk(BIOS_DEBUG, "FMAP: area %s not found\n", name); |
| |
| return -1; |
| } |
| |
| int fmap_find_region_name(const struct region * const ar, |
| char name[FMAP_STRLEN]) |
| { |
| struct region_device fmrd; |
| size_t offset; |
| |
| if (find_fmap_directory(&fmrd)) |
| return -1; |
| |
| /* Start reading the areas just after fmap header. */ |
| offset = sizeof(struct fmap); |
| |
| while (1) { |
| struct fmap_area *area; |
| |
| area = rdev_mmap(&fmrd, offset, sizeof(*area)); |
| |
| if (area == NULL) |
| return -1; |
| |
| if ((ar->offset != area->offset) || |
| (ar->size != area->size)) { |
| rdev_munmap(&fmrd, area); |
| offset += sizeof(struct fmap_area); |
| continue; |
| } |
| |
| printk(BIOS_DEBUG, "FMAP: area (%zx, %zx) found, named %s\n", |
| ar->offset, ar->size, area->name); |
| |
| memcpy(name, area->name, FMAP_STRLEN); |
| |
| rdev_munmap(&fmrd, area); |
| |
| return 0; |
| } |
| |
| printk(BIOS_DEBUG, "FMAP: area (%zx, %zx) not found\n", |
| ar->offset, ar->size); |
| |
| return -1; |
| } |