mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-24 02:05:01 +00:00
Don't use FDT to report it on ARM. This fixes ARM reporting the wrong thing for RO-normal. BUG=none TEST=none Change-Id: Id3a1bd2a1d2502e1d9493ab362be5a58fa88d70e Reviewed-on: http://gerrit.chromium.org/gerrit/4213 Reviewed-by: Olof Johansson <olofj@chromium.org> Reviewed-by: Simon Glass <sjg@chromium.org> Tested-by: Randall Spangler <rspangler@chromium.org>
354 lines
8.6 KiB
C
354 lines
8.6 KiB
C
/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <linux/fs.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/param.h>
|
|
#include <sys/ioctl.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <netinet/in.h>
|
|
|
|
#include "vboot_common.h"
|
|
#include "vboot_nvstorage.h"
|
|
#include "host_common.h"
|
|
#include "crossystem_arch.h"
|
|
|
|
/* Base name for FDT files */
|
|
#define FDT_BASE_PATH "/proc/device-tree/firmware/chromeos"
|
|
/* Device for NVCTX write */
|
|
#define NVCTX_PATH "/dev/mmcblk%d"
|
|
/* Errors */
|
|
#define E_FAIL -1
|
|
#define E_FILEOP -2
|
|
#define E_MEM -3
|
|
/* Common constants */
|
|
#define FNAME_SIZE 80
|
|
#define SECTOR_SIZE 512
|
|
#define MAX_NMMCBLK 9
|
|
|
|
static int FindEmmcDev(void) {
|
|
int mmcblk;
|
|
char filename[FNAME_SIZE];
|
|
for (mmcblk = 0; mmcblk < MAX_NMMCBLK; mmcblk++) {
|
|
/* Get first non-removable mmc block device */
|
|
snprintf(filename, sizeof(filename), "/sys/block/mmcblk%d/removable",
|
|
mmcblk);
|
|
if (ReadFileInt(filename) == 0)
|
|
return mmcblk;
|
|
}
|
|
/* eMMC not found */
|
|
return E_FAIL;
|
|
}
|
|
|
|
static int ReadFdtValue(const char *property, int *value) {
|
|
char filename[FNAME_SIZE];
|
|
FILE *file;
|
|
int data = 0;
|
|
|
|
snprintf(filename, sizeof(filename), FDT_BASE_PATH "/%s", property);
|
|
file = fopen(filename, "rb");
|
|
if (!file) {
|
|
fprintf(stderr, "Unable to open FDT property %s\n", property);
|
|
return E_FILEOP;
|
|
}
|
|
|
|
fread(&data, 1, sizeof(data), file);
|
|
fclose(file);
|
|
|
|
if (value)
|
|
*value = ntohl(data); /* FDT is network byte order */
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ReadFdtBool(const char *property) {
|
|
char filename[FNAME_SIZE];
|
|
struct stat tmp;
|
|
int err;
|
|
|
|
snprintf(filename, sizeof(filename), FDT_BASE_PATH "/%s", property);
|
|
err = stat(filename, &tmp);
|
|
|
|
if (err == 0)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ReadFdtInt(const char *property) {
|
|
int value;
|
|
if (ReadFdtValue(property, &value))
|
|
return E_FAIL;
|
|
return value;
|
|
}
|
|
|
|
static int ReadFdtBlock(const char *property, void **block, size_t *size) {
|
|
char filename[FNAME_SIZE];
|
|
FILE *file;
|
|
size_t property_size;
|
|
char *data;
|
|
|
|
if (!block)
|
|
return E_FAIL;
|
|
|
|
snprintf(filename, sizeof(filename), FDT_BASE_PATH "/%s", property);
|
|
file = fopen(filename, "rb");
|
|
if (!file) {
|
|
fprintf(stderr, "Unable to open FDT property %s\n", property);
|
|
return E_FILEOP;
|
|
}
|
|
|
|
fseek(file, 0, SEEK_END);
|
|
property_size = ftell(file);
|
|
rewind(file);
|
|
|
|
data = malloc(property_size +1);
|
|
if (!data) {
|
|
fclose(file);
|
|
return E_MEM;
|
|
}
|
|
data[property_size] = 0;
|
|
|
|
if (1 != fread(data, property_size, 1, file)) {
|
|
fprintf(stderr, "Unable to read from property %s\n", property);
|
|
fclose(file);
|
|
free(data);
|
|
return E_FILEOP;
|
|
}
|
|
|
|
fclose(file);
|
|
*block = data;
|
|
if (size)
|
|
*size = property_size;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static char * ReadFdtString(const char *property) {
|
|
void *str = NULL;
|
|
/* Do not need property size */
|
|
ReadFdtBlock(property, &str, 0);
|
|
return (char *)str;
|
|
}
|
|
|
|
static int VbGetGpioStatus(unsigned gpio_number) {
|
|
char const *gpio_name_format = "/sys/class/gpio/gpio%d/value";
|
|
char gpio_name[FNAME_SIZE];
|
|
|
|
snprintf(gpio_name, sizeof(gpio_name), gpio_name_format, gpio_number);
|
|
return ReadFileInt(gpio_name);
|
|
}
|
|
|
|
static int VbGetVarGpio(const char* name) {
|
|
int polarity, gpio_num;
|
|
void *pp = NULL;
|
|
int *prop;
|
|
size_t proplen = 0;
|
|
int ret = 0;
|
|
|
|
/* TODO: This should at some point in the future use the phandle
|
|
* to find the gpio chip and thus the base number. Assume 0 now,
|
|
* which isn't 100% future-proof (i.e. if one of the switches gets
|
|
* moved to an offchip gpio controller.
|
|
*/
|
|
|
|
ret = ReadFdtBlock(name, &pp, &proplen);
|
|
if (ret || !pp || proplen != 12) {
|
|
ret = 2;
|
|
goto out;
|
|
}
|
|
prop = pp;
|
|
gpio_num = ntohl(prop[1]);
|
|
polarity = ntohl(prop[2]);
|
|
|
|
ret = VbGetGpioStatus(gpio_num) ^ polarity ^ 1;
|
|
out:
|
|
if (pp)
|
|
free(pp);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int VbReadNvStorage(VbNvContext* vnc) {
|
|
int nvctx_fd = -1;
|
|
uint8_t sector[SECTOR_SIZE];
|
|
int rv = -1;
|
|
char nvctx_path[FNAME_SIZE];
|
|
int emmc_dev;
|
|
int lba = ReadFdtInt("nonvolatile-context-lba");
|
|
int offset = ReadFdtInt("nonvolatile-context-offset");
|
|
int size = ReadFdtInt("nonvolatile-context-size");
|
|
|
|
emmc_dev = FindEmmcDev();
|
|
if (emmc_dev < 0)
|
|
return E_FAIL;
|
|
snprintf(nvctx_path, sizeof(nvctx_path), NVCTX_PATH, emmc_dev);
|
|
|
|
if (size != sizeof(vnc->raw) || (size + offset > SECTOR_SIZE))
|
|
return E_FAIL;
|
|
|
|
nvctx_fd = open(nvctx_path, O_RDONLY);
|
|
if (nvctx_fd == -1) {
|
|
fprintf(stderr, "%s: failed to open %s\n", __FUNCTION__, nvctx_path);
|
|
goto out;
|
|
}
|
|
lseek(nvctx_fd, lba * SECTOR_SIZE, SEEK_SET);
|
|
|
|
rv = read(nvctx_fd, sector, SECTOR_SIZE);
|
|
if (size <= 0) {
|
|
fprintf(stderr, "%s: failed to read nvctx from device %s\n",
|
|
__FUNCTION__, nvctx_path);
|
|
goto out;
|
|
}
|
|
Memcpy(vnc->raw, sector+offset, size);
|
|
rv = 0;
|
|
|
|
out:
|
|
if (nvctx_fd > 0)
|
|
close(nvctx_fd);
|
|
|
|
return rv;
|
|
}
|
|
|
|
int VbWriteNvStorage(VbNvContext* vnc) {
|
|
int nvctx_fd = -1;
|
|
uint8_t sector[SECTOR_SIZE];
|
|
int rv = -1;
|
|
char nvctx_path[FNAME_SIZE];
|
|
int emmc_dev;
|
|
int lba = ReadFdtInt("nonvolatile-context-lba");
|
|
int offset = ReadFdtInt("nonvolatile-context-offset");
|
|
int size = ReadFdtInt("nonvolatile-context-size");
|
|
|
|
emmc_dev = FindEmmcDev();
|
|
if (emmc_dev < 0)
|
|
return E_FAIL;
|
|
snprintf(nvctx_path, sizeof(nvctx_path), NVCTX_PATH, emmc_dev);
|
|
|
|
if (size != sizeof(vnc->raw) || (size + offset > SECTOR_SIZE))
|
|
return E_FAIL;
|
|
|
|
do {
|
|
nvctx_fd = open(nvctx_path, O_RDWR);
|
|
if (nvctx_fd == -1) {
|
|
fprintf(stderr, "%s: failed to open %s\n", __FUNCTION__, nvctx_path);
|
|
break;
|
|
}
|
|
lseek(nvctx_fd, lba * SECTOR_SIZE, SEEK_SET);
|
|
rv = read(nvctx_fd, sector, SECTOR_SIZE);
|
|
if (rv <= 0) {
|
|
fprintf(stderr, "%s: failed to read nvctx from device %s\n",
|
|
__FUNCTION__, nvctx_path);
|
|
break;
|
|
}
|
|
Memcpy(sector+offset, vnc->raw, size);
|
|
lseek(nvctx_fd, lba * SECTOR_SIZE, SEEK_SET);
|
|
rv = write(nvctx_fd, sector, SECTOR_SIZE);
|
|
if (rv <= 0) {
|
|
fprintf(stderr, "%s: failed to write nvctx to device %s\n",
|
|
__FUNCTION__, nvctx_path);
|
|
break;
|
|
}
|
|
/* Must flush buffer cache here to make sure it goes to disk */
|
|
rv = ioctl(nvctx_fd, BLKFLSBUF, 0);
|
|
if (rv < 0) {
|
|
fprintf(stderr, "%s: failed to flush nvctx to device %s\n",
|
|
__FUNCTION__, nvctx_path);
|
|
break;
|
|
}
|
|
rv = 0;
|
|
} while (0);
|
|
|
|
if (nvctx_fd > 0)
|
|
close(nvctx_fd);
|
|
|
|
return rv;
|
|
}
|
|
|
|
VbSharedDataHeader *VbSharedDataRead(void) {
|
|
void *block = NULL;
|
|
size_t size = 0;
|
|
if (ReadFdtBlock("vboot-shared-data", &block, &size))
|
|
return NULL;
|
|
return (VbSharedDataHeader *)block;
|
|
}
|
|
|
|
static int VbGetRecoveryReason(void) {
|
|
return ReadFdtInt("recovery-reason");
|
|
}
|
|
|
|
int VbGetArchPropertyInt(const char* name) {
|
|
if (!strcasecmp(name, "recovery_reason"))
|
|
return VbGetRecoveryReason();
|
|
else if (!strcasecmp(name, "fmap_base"))
|
|
return ReadFdtInt("fmap-offset");
|
|
else if (!strcasecmp(name, "devsw_boot"))
|
|
return ReadFdtBool("boot-developer-switch");
|
|
else if (!strcasecmp(name, "recoverysw_boot"))
|
|
return ReadFdtBool("boot-recovery-switch");
|
|
else if (!strcasecmp(name, "wpsw_boot"))
|
|
return ReadFdtBool("boot-write-protect-switch");
|
|
else if (!strcasecmp(name, "devsw_cur"))
|
|
return VbGetVarGpio("developer-switch");
|
|
else if (!strcasecmp(name, "recoverysw_cur"))
|
|
return VbGetVarGpio("recovery-switch");
|
|
else if (!strcasecmp(name, "wpsw_cur"))
|
|
return VbGetVarGpio("write-protect-switch");
|
|
else if (!strcasecmp(name, "recoverysw_ec_boot"))
|
|
return 0;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
const char* VbGetArchPropertyString(const char* name, char* dest, int size) {
|
|
char *str = NULL;
|
|
char *rv = NULL;
|
|
char *prop = NULL;
|
|
|
|
if (!strcasecmp(name,"arch"))
|
|
return StrCopy(dest, "arm", size);
|
|
|
|
/* Properties from fdt */
|
|
if (!strcasecmp(name, "ro_fwid"))
|
|
prop = "readonly-firmware-version";
|
|
else if (!strcasecmp(name, "hwid"))
|
|
prop = "hardware-id";
|
|
else if (!strcasecmp(name, "fwid"))
|
|
prop = "firmware-version";
|
|
else if (!strcasecmp(name, "mainfw_type"))
|
|
prop = "firmware-type";
|
|
else if (!strcasecmp(name, "ecfw_act"))
|
|
prop = "active-ec-firmware";
|
|
|
|
if (prop)
|
|
str = ReadFdtString(prop);
|
|
|
|
if (str) {
|
|
rv = StrCopy(dest, str, size);
|
|
free(str);
|
|
return rv;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int VbSetArchPropertyInt(const char* name, int value) {
|
|
/* All is handled in arch independent fashion */
|
|
return -1;
|
|
}
|
|
|
|
int VbSetArchPropertyString(const char* name, const char* value) {
|
|
/* All is handled in arch independent fashion */
|
|
return -1;
|
|
}
|
|
|
|
int VbArchInit(void)
|
|
{
|
|
return 0;
|
|
}
|