mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-17 05:17:04 +00:00
Introduce arm fdt support in crossystem utility
This CL builds upon recent changes in u-boot and kernel. (see issue ids: 15744, 16665) - Remove /sys/kernel/debug/chromeos_arm share memory mechanism - Load properties from /proc/device-tree/crossystem/* - Write NVCXT to /dev/mmcblk0:lba[0] BUG=chromium-os:17300 TEST=manual Run crossystem on device console. Check current values of gpio switches. All other values are exported from FDT directly. Change-Id: Ib8db4a4aeb6dc36308ad8882403cb2f5978a5c70 Signed-off-by: Rong Chang <rongchang@chromium.org> Reviewed-on: http://gerrit.chromium.org/gerrit/3676 Reviewed-by: Tom Wai-Hong Tam <waihong@chromium.org>
This commit is contained in:
@@ -6,235 +6,281 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
#include "vboot_common.h"
|
#include "vboot_common.h"
|
||||||
#include "vboot_nvstorage.h"
|
#include "vboot_nvstorage.h"
|
||||||
#include "host_common.h"
|
#include "host_common.h"
|
||||||
#include "crossystem_arch.h"
|
#include "crossystem_arch.h"
|
||||||
|
|
||||||
#define offsetof(struct_name, field) ((int) &(((struct_name*)0)->field))
|
/* Base name for FDT files */
|
||||||
|
#define FDT_BASE_PATH "/proc/device-tree/firmware/chromeos"
|
||||||
|
/* Device for NVCTX write */
|
||||||
|
#define NVCTX_PATH "/dev/mmcblk%d"
|
||||||
|
/* BINF */
|
||||||
|
#define BINF_MAINFW_ACT 1
|
||||||
|
#define BINF_ECFW_ACT 2
|
||||||
|
#define BINF_MAINFW_TYPE 3
|
||||||
|
#define BINF_RECOVERY_REASON 4
|
||||||
|
/* 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
|
||||||
|
|
||||||
/* This is used to keep u-boot and kernel in sync */
|
static int FindEmmcDev(void) {
|
||||||
#define SHARED_MEM_VERSION 1
|
int mmcblk;
|
||||||
#define SHARED_MEM_SIGNATURE "CHROMEOS"
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct {
|
static int ReadFdtValue(const char *property, int *value) {
|
||||||
const char *signal_name;
|
char filename[FNAME_SIZE];
|
||||||
unsigned gpio_number;
|
FILE *file;
|
||||||
uint8_t needs_inversion;
|
int data = 0;
|
||||||
} GpioMap;
|
|
||||||
|
|
||||||
static const GpioMap vb_gpio_map_kaen[] = {
|
snprintf(filename, sizeof(filename), FDT_BASE_PATH "/%s", property);
|
||||||
{"recoverysw_cur", 56, 1},
|
file = fopen(filename, "rb");
|
||||||
{"devsw_cur", 168},
|
if (!file) {
|
||||||
{"wpsw_cur", 59, 1},
|
fprintf(stderr, "Unable to open FDT property %s\n", property);
|
||||||
};
|
return E_FILEOP;
|
||||||
|
}
|
||||||
|
|
||||||
/* This is map is for kaen, function to gpio number mapping */
|
fread(&data, 1, sizeof(data), file);
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
/*
|
if (value)
|
||||||
* This structure has been copied from u-boot-next
|
*value = ntohl(data); /* FDT is network byte order */
|
||||||
* files/lib/chromeos/os_storage.c. Keep it in sync until a better interface
|
|
||||||
* is implemented.
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
uint32_t total_size;
|
|
||||||
uint8_t signature[10];
|
|
||||||
uint16_t version;
|
|
||||||
uint64_t nvcxt_lba;
|
|
||||||
uint16_t vbnv[2];
|
|
||||||
uint8_t nvcxt_cache[VBNV_BLOCK_SIZE];
|
|
||||||
uint8_t write_protect_sw;
|
|
||||||
uint8_t recovery_sw;
|
|
||||||
uint8_t developer_sw;
|
|
||||||
uint8_t binf[5];
|
|
||||||
uint32_t chsw;
|
|
||||||
uint8_t hwid[256];
|
|
||||||
uint8_t fwid[256];
|
|
||||||
uint8_t frid[256];
|
|
||||||
uint32_t fmap_base;
|
|
||||||
uint8_t shared_data_body[VB_SHARED_DATA_REC_SIZE];
|
|
||||||
} __attribute__((packed)) VbSharedMem;
|
|
||||||
|
|
||||||
typedef struct {
|
return 0;
|
||||||
const char *cs_field_name;
|
}
|
||||||
const void *cs_value;
|
|
||||||
} VbVarInfo;
|
|
||||||
|
|
||||||
static VbSharedMem shared_memory;
|
static int ReadFdtInt(const char *property) {
|
||||||
static const char *blob_name = "/sys/kernel/debug/chromeos_arm";
|
int value;
|
||||||
static VbVarInfo vb_cs_map[] = {
|
if (ReadFdtValue(property, &value))
|
||||||
{"hwid", &shared_memory.hwid},
|
return E_FAIL;
|
||||||
{"fwid", &shared_memory.fwid},
|
return value;
|
||||||
{"ro_fwid", &shared_memory.frid},
|
}
|
||||||
{"devsw_boot", &shared_memory.developer_sw},
|
|
||||||
{"recoverysw_boot", &shared_memory.recovery_sw},
|
static int ReadFdtBlock(const char *property, void **block, size_t *size) {
|
||||||
{"wpsw_boot", &shared_memory.write_protect_sw},
|
char filename[FNAME_SIZE];
|
||||||
{"recovery_reason", &shared_memory.binf[4]},
|
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) {
|
static int VbGetGpioStatus(unsigned gpio_number) {
|
||||||
char const *gpio_name_format = "/sys/class/gpio/gpio%d/value";
|
char const *gpio_name_format = "/sys/class/gpio/gpio%d/value";
|
||||||
char gpio_name [80];
|
char gpio_name[FNAME_SIZE];
|
||||||
char gpio_value[3]; /* gpio value file contains the value and the CR */
|
|
||||||
FILE *gpio_file;
|
|
||||||
int rv = -1, size;
|
|
||||||
|
|
||||||
snprintf(gpio_name, sizeof(gpio_name), gpio_name_format, gpio_number);
|
snprintf(gpio_name, sizeof(gpio_name), gpio_name_format, gpio_number);
|
||||||
gpio_file = fopen(gpio_name, "r");
|
return ReadFileInt(gpio_name);
|
||||||
if (!gpio_file) {
|
|
||||||
fprintf(stderr, "%s: failed to open %s\n", __FUNCTION__, gpio_name);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
size = fread(&gpio_value, 1, sizeof(gpio_value), gpio_file);
|
|
||||||
if ((size == 2) && (gpio_value[1] == 0xa)) {
|
|
||||||
rv = gpio_value[0] - '0'; /* we expect 0 or 1 only */
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "%s: failed to read %s, got %d\n",
|
|
||||||
__FUNCTION__, gpio_name, size);
|
|
||||||
}
|
|
||||||
fclose(gpio_file);
|
|
||||||
return rv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int VbGetVarGpio(const char* name) {
|
static int VbGetVarGpio(const char* name) {
|
||||||
int i;
|
int polarity, gpio_num;
|
||||||
const GpioMap* pmap;
|
char prop_polarity[FNAME_SIZE];
|
||||||
|
char prop_gpio_num[FNAME_SIZE];
|
||||||
|
|
||||||
for (i = 0, pmap = vb_gpio_map_kaen;
|
snprintf(prop_polarity, sizeof(prop_polarity), "polarity_%s", name);
|
||||||
i < ARRAY_SIZE(vb_gpio_map_kaen);
|
snprintf(prop_gpio_num, sizeof(prop_gpio_num), "gpio_port_%s", name);
|
||||||
i++, pmap++) {
|
|
||||||
if (!strcmp(name, pmap->signal_name))
|
|
||||||
return VbGetGpioStatus(pmap->gpio_number) ^ pmap->needs_inversion;
|
|
||||||
}
|
|
||||||
return 2; /* means not found */
|
|
||||||
}
|
|
||||||
|
|
||||||
static int VbReadSharedMemory(void) {
|
polarity = ReadFdtInt(prop_polarity);
|
||||||
FILE *data_file = NULL;
|
gpio_num = ReadFdtInt(prop_gpio_num);
|
||||||
int rv = -1;
|
|
||||||
int size;
|
|
||||||
|
|
||||||
do {
|
if (polarity == -1 || gpio_num == -1)
|
||||||
data_file = fopen(blob_name, "rb");
|
return 2;
|
||||||
if (!data_file) {
|
|
||||||
fprintf(stderr, "%s: failed to open %s\n", __FUNCTION__, blob_name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
size = fread(&shared_memory, 1, sizeof(shared_memory), data_file);
|
|
||||||
if ((size != sizeof(shared_memory)) || (size != shared_memory.total_size)) {
|
|
||||||
fprintf(stderr, "%s: failed to read shared memory: got %d bytes, "
|
|
||||||
"expected %lu, should have been %d\n",
|
|
||||||
__FUNCTION__,
|
|
||||||
size,
|
|
||||||
(unsigned long)sizeof(shared_memory),
|
|
||||||
shared_memory.total_size);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp((const char*)shared_memory.signature, SHARED_MEM_SIGNATURE)) {
|
return VbGetGpioStatus(gpio_num) ^ polarity ^ 1;
|
||||||
fprintf(stderr, "%s: signature verification failed\n", __FUNCTION__);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shared_memory.version != SHARED_MEM_VERSION) {
|
|
||||||
fprintf(stderr, "%s: version mismatch: %d != %d\n",
|
|
||||||
__FUNCTION__, shared_memory.version, SHARED_MEM_VERSION);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
rv = 0;
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
if (data_file)
|
|
||||||
fclose(data_file);
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieve the address of an entity in the shared memory based on the entity
|
|
||||||
* name, as described in vb_cs_map table.
|
|
||||||
*
|
|
||||||
* Return NULL if the entity name is not found in the table.
|
|
||||||
*/
|
|
||||||
static const void* VbGetVarAuto(const char* name) {
|
|
||||||
int i;
|
|
||||||
VbVarInfo *pi;
|
|
||||||
|
|
||||||
for (i = 0, pi = vb_cs_map; i < ARRAY_SIZE(vb_cs_map); i++, pi++) {
|
|
||||||
if (strcmp(pi->cs_field_name, name)) continue;
|
|
||||||
return pi->cs_value;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int VbReadNvStorage(VbNvContext* vnc) {
|
int VbReadNvStorage(VbNvContext* vnc) {
|
||||||
Memcpy(vnc->raw, shared_memory.nvcxt_cache, sizeof(vnc->raw));
|
void *nvcxt_cache;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
if (ReadFdtBlock("nvcxt_cache", &nvcxt_cache, &size))
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
Memcpy(vnc->raw, nvcxt_cache, MIN(sizeof(vnc->raw), size));
|
||||||
|
free(nvcxt_cache);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int VbWriteNvStorage(VbNvContext* vnc) {
|
int VbWriteNvStorage(VbNvContext* vnc) {
|
||||||
FILE *data_file = NULL;
|
int nvctx_fd = -1;
|
||||||
|
uint8_t sector[SECTOR_SIZE];
|
||||||
int rv = -1;
|
int rv = -1;
|
||||||
int size;
|
ssize_t size;
|
||||||
|
char nvctx_path[FNAME_SIZE];
|
||||||
|
int emmc_dev;
|
||||||
|
|
||||||
|
emmc_dev = FindEmmcDev();
|
||||||
|
if (emmc_dev < 0)
|
||||||
|
return E_FAIL;
|
||||||
|
snprintf(nvctx_path, sizeof(nvctx_path), NVCTX_PATH, emmc_dev);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
data_file = fopen(blob_name, "w");
|
nvctx_fd = open(nvctx_path, O_RDWR);
|
||||||
if (!data_file) {
|
if (nvctx_fd == -1) {
|
||||||
fprintf(stderr, "%s: failed to open %s\n", __FUNCTION__, blob_name);
|
fprintf(stderr, "%s: failed to open %s\n", __FUNCTION__, nvctx_path);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
size = fwrite(vnc->raw, 1, sizeof(vnc->raw), data_file);
|
size = read(nvctx_fd, sector, SECTOR_SIZE);
|
||||||
if (size != sizeof(vnc->raw)) {
|
if (size <= 0) {
|
||||||
fprintf(stderr, "%s: failed to write shared memory (%d)\n",
|
fprintf(stderr, "%s: failed to read nvctx from device %s\n",
|
||||||
__FUNCTION__, size);
|
__FUNCTION__, nvctx_path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
size = MIN(sizeof(vnc->raw), SECTOR_SIZE);
|
||||||
|
Memcpy(sector, vnc->raw, size);
|
||||||
|
lseek(nvctx_fd, 0, SEEK_SET);
|
||||||
|
size = write(nvctx_fd, sector, SECTOR_SIZE);
|
||||||
|
if (size <= 0) {
|
||||||
|
fprintf(stderr, "%s: failed to write nvctx to device %s\n",
|
||||||
|
__FUNCTION__, nvctx_path);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
rv = 0;
|
rv = 0;
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
if (data_file)
|
if (nvctx_fd > 0)
|
||||||
fclose(data_file);
|
close(nvctx_fd);
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
VbSharedDataHeader *VbSharedDataRead(void) {
|
VbSharedDataHeader *VbSharedDataRead(void) {
|
||||||
/* don't need this malloc/copy, but have to do it to comply with the
|
void *block = NULL;
|
||||||
* wrapper.
|
size_t size = 0;
|
||||||
*/
|
if (ReadFdtBlock("vbshared_data", &block, &size))
|
||||||
VbSharedDataHeader *p = malloc(sizeof(*p));
|
return NULL;
|
||||||
Memcpy(p, shared_memory.shared_data_body, sizeof(*p));
|
return (VbSharedDataHeader *)block;
|
||||||
return p;
|
}
|
||||||
|
|
||||||
|
static int VbGetRecoveryReason(void) {
|
||||||
|
int value;
|
||||||
|
size_t size;
|
||||||
|
uint8_t *binf;
|
||||||
|
if (ReadFdtBlock("binf", (void **)&binf, &size))
|
||||||
|
return -1;
|
||||||
|
value = binf[BINF_RECOVERY_REASON];
|
||||||
|
free(binf);
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
int VbGetArchPropertyInt(const char* name) {
|
int VbGetArchPropertyInt(const char* name) {
|
||||||
|
if (!strcasecmp(name, "recovery_reason")) {
|
||||||
const uint8_t *value;
|
return VbGetRecoveryReason();
|
||||||
int rv;
|
} else if (!strcasecmp(name, "fmap_base")) {
|
||||||
|
return ReadFdtInt("fmap_base");
|
||||||
value = VbGetVarAuto(name);
|
} else if (!strcasecmp(name, "devsw_boot")) {
|
||||||
|
return ReadFdtInt("developer_sw");
|
||||||
if (value) return (int) *value;
|
} else if (!strcasecmp(name, "recoverysw_boot")) {
|
||||||
|
return ReadFdtInt("recovery_sw");
|
||||||
rv = VbGetVarGpio(name);
|
} else if (!strcasecmp(name, "wpsw_boot")) {
|
||||||
if (rv <= 1) return rv;
|
return ReadFdtInt("write_protect_sw");
|
||||||
|
} else if (!strcasecmp(name, "devsw_cur")) {
|
||||||
if (!strcasecmp(name,"fmap_base")) {
|
return VbGetVarGpio("developer_sw");
|
||||||
return shared_memory.fmap_base;
|
} else if (!strcasecmp(name, "recoverysw_cur")) {
|
||||||
}
|
return VbGetVarGpio("recovery_sw");
|
||||||
|
} else if (!strcasecmp(name, "wpsw_cur")) {
|
||||||
return -1;
|
return VbGetVarGpio("write_protect_sw");
|
||||||
|
} else if (!strcasecmp(name, "recoverysw_ec_boot")) {
|
||||||
|
return 0;
|
||||||
|
} else
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* VbGetArchPropertyString(const char* name, char* dest, int size) {
|
const char* VbGetArchPropertyString(const char* name, char* dest, int size) {
|
||||||
const char* value = VbGetVarAuto(name);
|
char *str = NULL;
|
||||||
if (value) return StrCopy(dest, value, size);
|
char *rv = NULL;
|
||||||
|
size_t block_size;
|
||||||
|
uint8_t *binf, mainfw_act, mainfw_type, ecfw_act;
|
||||||
|
|
||||||
|
/* Properties from fdt */
|
||||||
|
if (!strcasecmp(name, "ro_fwid")) {
|
||||||
|
str = ReadFdtString("frid");
|
||||||
|
} else if (!strcasecmp(name, "hwid")) {
|
||||||
|
str = ReadFdtString("hwid");
|
||||||
|
} else if (!strcasecmp(name, "fwid")) {
|
||||||
|
str = ReadFdtString("fwid");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str) {
|
||||||
|
rv = StrCopy(dest, str, size);
|
||||||
|
free(str);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Other properties */
|
||||||
|
if (ReadFdtBlock("binf", (void**)&binf, &block_size))
|
||||||
|
return NULL;
|
||||||
|
mainfw_act = binf[BINF_MAINFW_ACT];
|
||||||
|
ecfw_act = binf[BINF_ECFW_ACT];
|
||||||
|
mainfw_type = binf[BINF_MAINFW_TYPE];
|
||||||
|
free(binf);
|
||||||
|
|
||||||
if (!strcasecmp(name,"arch")) {
|
if (!strcasecmp(name,"arch")) {
|
||||||
return StrCopy(dest, "arm", size);
|
return StrCopy(dest, "arm", size);
|
||||||
} else if (!strcasecmp(name,"mainfw_act")) {
|
} else if (!strcasecmp(name,"mainfw_act")) {
|
||||||
switch(shared_memory.binf[1]) {
|
switch(mainfw_act) {
|
||||||
case 0:
|
case 0:
|
||||||
return StrCopy(dest, "recovery", size);
|
return StrCopy(dest, "recovery", size);
|
||||||
case 1:
|
case 1:
|
||||||
@@ -245,7 +291,7 @@ const char* VbGetArchPropertyString(const char* name, char* dest, int size) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
} else if (!strcasecmp(name,"mainfw_type")) {
|
} else if (!strcasecmp(name,"mainfw_type")) {
|
||||||
switch(shared_memory.binf[3]) {
|
switch(mainfw_type) {
|
||||||
case BINF3_RECOVERY:
|
case BINF3_RECOVERY:
|
||||||
return StrCopy(dest, "recovery", size);
|
return StrCopy(dest, "recovery", size);
|
||||||
case BINF3_NORMAL:
|
case BINF3_NORMAL:
|
||||||
@@ -256,7 +302,7 @@ const char* VbGetArchPropertyString(const char* name, char* dest, int size) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
} else if (!strcasecmp(name,"ecfw_act")) {
|
} else if (!strcasecmp(name,"ecfw_act")) {
|
||||||
switch(shared_memory.binf[2]) {
|
switch(ecfw_act) {
|
||||||
case 0:
|
case 0:
|
||||||
return StrCopy(dest, "RO", size);
|
return StrCopy(dest, "RO", size);
|
||||||
case 1:
|
case 1:
|
||||||
@@ -280,5 +326,5 @@ int VbSetArchPropertyString(const char* name, const char* value) {
|
|||||||
|
|
||||||
int VbArchInit(void)
|
int VbArchInit(void)
|
||||||
{
|
{
|
||||||
return VbReadSharedMemory();
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user