diff options
Diffstat (limited to 'roms/SLOF/lib/libnvram')
| -rw-r--r-- | roms/SLOF/lib/libnvram/Makefile | 53 | ||||
| -rw-r--r-- | roms/SLOF/lib/libnvram/envvar.c | 243 | ||||
| -rw-r--r-- | roms/SLOF/lib/libnvram/libnvram.code | 287 | ||||
| -rw-r--r-- | roms/SLOF/lib/libnvram/libnvram.in | 42 | ||||
| -rw-r--r-- | roms/SLOF/lib/libnvram/nvram.c | 623 | ||||
| -rw-r--r-- | roms/SLOF/lib/libnvram/nvram.h | 73 | 
6 files changed, 1321 insertions, 0 deletions
| diff --git a/roms/SLOF/lib/libnvram/Makefile b/roms/SLOF/lib/libnvram/Makefile new file mode 100644 index 00000000..d4e9a617 --- /dev/null +++ b/roms/SLOF/lib/libnvram/Makefile @@ -0,0 +1,53 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# *     IBM Corporation - initial implementation +# ****************************************************************************/ + +SRCS = nvram.c envvar.c + +TOPCMNDIR ?= ../.. + +include $(TOPCMNDIR)/make.rules + +ASFLAGS = $(FLAG) $(RELEASE) $(CPUARCHDEF) -Wa,-mregnames +CPPFLAGS = -I../libc/include $(CPUARCHDEF) $(FLAG) \ +	   -I$(INCLBRDDIR) -I$(INCLCMNDIR)/$(CPUARCH) -I. -I../../include +LDFLAGS = -nostdlib + +TARGET = ../libnvram.a + +all: $(TARGET) + +OBJS = $(SRCS:%.c=%.o) + +$(TARGET): $(OBJS) +	$(AR) -rc $@ $(OBJS) +	$(RANLIB) $@ + + +clean: +	$(RM) $(TARGET) $(OBJS) + +distclean: clean +	$(RM) Makefile.dep + + +# Rules for creating the dependency file: +depend: +	$(RM) Makefile.dep +	$(MAKE) Makefile.dep + +Makefile.dep: Makefile +	$(CC) -MM $(CPPFLAGS) $(CFLAGS) $(SRCS) > Makefile.dep + + +# Include dependency file if available: +-include Makefile.dep + diff --git a/roms/SLOF/lib/libnvram/envvar.c b/roms/SLOF/lib/libnvram/envvar.c new file mode 100644 index 00000000..87aaf27a --- /dev/null +++ b/roms/SLOF/lib/libnvram/envvar.c @@ -0,0 +1,243 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + *     IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdint.h> +#include "../libc/include/stdio.h" +#include "../libc/include/string.h" +#include "../libc/include/stdlib.h" +#include "nvram.h" + +/* returns the offset of the first byte after the searched envvar */ +static int get_past_env_pos(partition_t part, char *envvar) +{ +	int offset, len; +	static char temp[256]; +	uint8_t data; + +	offset=part.addr; + +	memset(temp, 0, 256); + +	do { +		len=0; +		while((data=nvram_read_byte(offset++)) && len < 256) { +			temp[len++]=data; +		} +		if (!strncmp(envvar, temp, strlen(envvar))) { +			return offset; +		} +	} while (len); + +	return -1; +} + +/** + * @param partition name of the envvar partition + * @param envvar name of the environment variable + * @return pointer to temporary string containing the value of envvar + */ + +char *get_env(partition_t part, char *envvar) +{ +	static char temp[256+1]; +	int len, offset; +	uint8_t data; + +	DEBUG("get_env %s... ", envvar); +	if(!part.addr) { +		/* ERROR: No environment variable partition */ +		DEBUG("invalid partition.\n"); +		return NULL; +	} + +	offset=part.addr; + +	do { +		len=0; +		while((data=nvram_read_byte(offset++)) && len < 256) { +			temp[len++]=data; +		} +		temp[len]=0; + +		if (!strncmp(envvar, temp, strlen(envvar))) { +			int pos=0; +			while (temp[pos]!='=' && pos < len) pos++; +			// DEBUG("value='%s'\n", temp+pos+1);  +			return temp+pos+1; +		} +	} while (len); + +	DEBUG("not found\n"); +	return NULL; +} + +static int find_last_envvar(partition_t part) +{ +	uint8_t last, current; +	int offset; + +	offset=part.addr; + +	last=nvram_read_byte(part.addr); + +	for (offset=part.addr; offset<(int)(part.addr+part.len); offset++) { +		current=nvram_read_byte(offset); +		if(!last && !current) +			return offset; + +		last=current; +	} + +	return -1; +} + +int add_env(partition_t part, char *envvar, char *value) +{ +	int freespace, last, len, offset; +	unsigned int i; + +	/* Find offset where we can write */ +	last = find_last_envvar(part); + +	/* How much space do we have left? */ +	freespace = part.addr+part.len-last; + +	/* how long is the entry we want to write? */ +	len = strlen(envvar) + strlen(value) + 2; + +	if(freespace<len) { +		// TODO try to increase partition size +		return -1; +	} + +	offset=last; + +	for(i=0; i<strlen(envvar); i++) +		nvram_write_byte(offset++, envvar[i]); + +	nvram_write_byte(offset++, '='); + +	for(i=0; i<strlen(value); i++) +		nvram_write_byte(offset++, value[i]); + +	return 0; +} + +int del_env(partition_t part, char *envvar) +{ +	int last, current, pos, i; +	char *buffer; + +	if(!part.addr) +		return -1; + +	last=find_last_envvar(part); +	current = pos = get_past_env_pos(part, envvar); +	 +	// TODO is this really required? +	/* go back to non-0 value */ +	current--; + +	while (nvram_read_byte(current)) +		current--; + +	// TODO is this required? +	current++; + +	buffer=get_nvram_buffer(last-pos); + +	for (i=0; i<last-pos; i++) +		buffer[i]=nvram_read_byte(i+pos); + +	for (i=0; i<last-pos; i++) +		nvram_write_byte(i+current, buffer[i]); + +	free_nvram_buffer(buffer); + +	erase_nvram(last, current+last-pos); + +	return 0; +} + +int set_env(partition_t part, char *envvar, char *value) +{ +	char *oldvalue, *buffer; +	int last, current, buffersize, i; + +	DEBUG("set_env %lx[%lx]: %s=%s\n", part.addr, part.len, envvar, value); + +	if(!part.addr) +		return -1; + +	/* Check whether the environment variable exists already */ +	oldvalue = get_env(part, envvar); + +	if(oldvalue==NULL) +		return add_env(part, envvar, value); + + +	/* The value did not change. So we succeeded! */ +	if(!strncmp(oldvalue, value, strlen(value)+1)) +		return 0; + +	/* we need to overwrite environment variables, back them up first */ + +	// DEBUG("overwriting existing environment variable\n"); + +	/* allocate a buffer */ +	last=find_last_envvar(part); +	current=get_past_env_pos(part, envvar); +	buffersize = last - current; +	buffer=get_nvram_buffer(buffersize); +	if(!buffer) +		return -1; + +	for (i=0; i<buffersize; i++) { +		buffer[i] = nvram_read_byte(current+i); +	} + +	/* walk back until the = */ +	while (nvram_read_byte(current)!='=') { +		current--; +	} + +	/* Start at envvar= */ +	current++; + +	/* Write the new value */ +	for(i=0; i<(int)strlen(value); i++) { +		nvram_write_byte(current++, value[i]); +	} +	 +	/* Write end of string marker */ +	nvram_write_byte(current++, 0); + +	/* Copy back the buffer */ +	for (i=0; i<buffersize; i++) { +		nvram_write_byte(current++, buffer[i]); +	} + +	free_nvram_buffer(buffer); + +	/* If the new environment variable content is shorter than the old one, +	 * we need to erase the rest of the bytes  +	 */ + +	if (current<last) { +		for(i=current; i<last; i++) { +			nvram_write_byte(i, 0); +		} +	} + +	return 0; /* success */ +} + diff --git a/roms/SLOF/lib/libnvram/libnvram.code b/roms/SLOF/lib/libnvram/libnvram.code new file mode 100644 index 00000000..723941d3 --- /dev/null +++ b/roms/SLOF/lib/libnvram/libnvram.code @@ -0,0 +1,287 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + *     IBM Corporation - initial implementation + *****************************************************************************/ +#include <nvram.h> + +#define STRING_INIT(str)	\ +	char str[255];		\ +	char * str##_address;	\ +	int  str##_length; + +#define STRING_FROM_STACK(str)				\ +	str##_length = TOS.u; POP;				\ +	str##_address = TOS.a; POP;			\ +	memcpy(str, str##_address, str##_length);	\ +	memset(str + str##_length, 0, 255 - str##_length); + +PRIM(nvram_X2d_c_X40) +	unsigned int offset = TOS.u; +	TOS.u=nvram_read_byte(offset); +MIRP + +PRIM(nvram_X2d_w_X40) +	unsigned int offset = TOS.u; +	TOS.u=nvram_read_word(offset); +MIRP + +PRIM(nvram_X2d_l_X40) +	unsigned int offset = TOS.u; +	TOS.u=nvram_read_dword(offset); +MIRP + +PRIM(nvram_X2d_x_X40) +	unsigned int offset = TOS.u; +	TOS.u=nvram_read_qword(offset); +MIRP + +PRIM(nvram_X2d_c_X21) +	nvram_write_byte(TOS.u, NOS.u); +	POP; POP; +MIRP + +PRIM(nvram_X2d_w_X21) +	nvram_write_word(TOS.u, NOS.u); +	POP; POP; +MIRP + +PRIM(nvram_X2d_l_X21) +	nvram_write_dword(TOS.u, NOS.u); +	POP; POP; +MIRP + +PRIM(nvram_X2d_x_X21) +	nvram_write_qword(TOS.u, NOS.u); +	POP; POP; +MIRP + +/* get-nvram-partition ( type -- addr len FAILED? ) */ +PRIM(get_X2d_nvram_X2d_partition) +	partition_t partition; +	unsigned int ptype = TOS.u; +	partition = get_partition(ptype, NULL); +	if(partition.len && partition.len != -1) { +		TOS.u = partition.addr; +		PUSH; +		TOS.u = partition.len; +		PUSH; +		TOS.u = 0; // FALSE +	} else { +		TOS.u = -1; // TRUE +	} +MIRP + +/* get-named-nvram-partition ( name.addr name.len -- addr len FAILED? ) */ +PRIM(get_X2d_named_X2d_nvram_X2d_partition) +	STRING_INIT(name) +	partition_t partition; + +	STRING_FROM_STACK(name) +	partition = get_partition(-1, name); + +	if(partition.len && partition.len != -1) { +		PUSH; +		TOS.u = partition.addr; +		PUSH; +		TOS.u = partition.len; +		PUSH; +		TOS.u = 0; // FALSE +	} else { +		PUSH; +		TOS.u = -1; // TRUE +	} +MIRP + + + +/* new-nvram-partition ( type name.addr name.len len -- part.offs part.len FALSE | TRUE) */ +PRIM(new_X2d_nvram_X2d_partition) +	int type, len, i, slen; +	char name[12], *addr; +	partition_t partition; + +	len = TOS.u; POP; +	slen = TOS.u; POP; +	addr = (char *)TOS.u; POP; +	type = TOS.u; POP; + +	for (i=0; i<12; i++) { +		if(slen>i) +			name[i]=addr[i]; +		else +			name[i]=0; +	} + +	partition=new_nvram_partition(type, name, len); + +	if(!partition.len) { +		PUSH; TOS.u = -1; // TRUE +	} else { +		PUSH; TOS.u = partition.addr; +		PUSH; TOS.u = partition.len; +		PUSH; TOS.u = 0; // FALSE +	} +MIRP + +/* inrease-nvram-partition ( part.offs part.len new-len -- FALSE | TRUE ) */ +PRIM(increase_X2d_nvram_X2d_partition) +	int len, ret; +	partition_t partition; + +	// FIXME +	partition.addr = TOS.u; POP; +	partition.len  = TOS.u; POP; +	len = TOS.u; POP; + +	ret=increase_nvram_partition_size(partition, len); + +	PUSH; + +	if(!ret)  +		TOS.u=-1; // TRUE +	else +		TOS.u=0; // FALSE + +MIRP + +PRIM(internal_X2d_reset_X2d_nvram) +	reset_nvram(); +MIRP + +PRIM(wipe_X2d_nvram) +	wipe_nvram(); +MIRP + +PRIM(nvram_X2d_debug) +	nvram_debug(); +MIRP + +// ( part.start part.len name.addr name.len -- var.addr var.len TRUE | false ) +PRIM(internal_X2d_get_X2d_env) +	STRING_INIT(name) +	partition_t part; +	char *val; + +	STRING_FROM_STACK(name) +	part.len = TOS.u; POP; +	part.addr = TOS.u; POP; + +	val=get_env(part, name); +	if(val) { +		PUSH; TOS.a = val; +		PUSH; TOS.u = strlen(val); +		PUSH; TOS.u = -1; // TRUE +	} else { +		PUSH; TOS.u = 0; // FALSE +	} +MIRP + +// ( part.start part.len name.addr name.len val.addr val.len -- FALSE|TRUE) +PRIM(internal_X2d_add_X2d_env) +	STRING_INIT(name) +	STRING_INIT(value) +	partition_t part; +	int ret; + +	STRING_FROM_STACK(value) +	STRING_FROM_STACK(name) +	part.len = TOS.u; POP; +	part.addr = TOS.u; POP; + +	ret=add_env(part, name, value); +	if(ret) { +		PUSH; TOS.u = -1; // TRUE +	} else { +		PUSH; TOS.u = 0; // FALSE +	} +MIRP + +// ( part.addr part.len name.addr name.len -- FALSE|TRUE) +PRIM(internal_X2d_del_X2d_env) +	STRING_INIT(name) +	partition_t part; +	int ret; + +	STRING_FROM_STACK(name); +	part.len = TOS.u; POP; +	part.addr = TOS.u; POP; + +	ret=del_env(part, name); +	if(ret) { +		PUSH; TOS.u = -1; // TRUE +	} else { +		PUSH; TOS.u = 0; // FALSE +	} + +MIRP + +// internal-set-env ( part.addr part.len name.addr name.len val.addr val.len -- FALSE|TRUE) +PRIM(internal_X2d_set_X2d_env) +	STRING_INIT(name) +	STRING_INIT(value) +	partition_t part; +	int ret; + +	STRING_FROM_STACK(value) +	STRING_FROM_STACK(name) +	part.len = TOS.u; POP; +	part.addr = TOS.u; POP; + +	ret=set_env(part, name, value); +	if(ret) { +		PUSH; TOS.u = -1; // TRUE +	} else { +		PUSH; TOS.u = 0; // FALSE +	} +MIRP + +// ( part.addr part.len -- FALSE|TRUE) +PRIM(erase_X2d_nvram_X2d_partition) +	partition_t part; +	int ret; + +	part.len = TOS.u; POP; +	part.addr = TOS.u; POP; + +	ret=clear_nvram_partition(part); +	if(ret) { +		PUSH; TOS.u = -1; // TRUE +	} else { +		PUSH; TOS.u = 0; // FALSE +	} + +MIRP + +// ( part.addr part.len -- FALSE|TRUE) +PRIM(delete_X2d_nvram_X2d_partition) +	partition_t part; +	int ret; + +	part.len = TOS.u; POP; +	part.addr = TOS.u; POP; + +	ret=delete_nvram_partition(part); +	if(ret) { +		PUSH; TOS.u = -1; // TRUE +	} else { +		PUSH; TOS.u = 0; // FALSE +	} + +MIRP + +// ( fetch_token store_token size nvram-addr -- ) +PRIM(internal_X2d_nvram_X2d_init) +	void *nvram_addr = TOS.a; POP; +	uint32_t nvram_size = TOS.u; POP; +	uint32_t store_token = TOS.u; POP; +	long fetch_token = TOS.u; POP; + +	nvram_init(fetch_token, store_token, nvram_size, nvram_addr); +MIRP diff --git a/roms/SLOF/lib/libnvram/libnvram.in b/roms/SLOF/lib/libnvram/libnvram.in new file mode 100644 index 00000000..bbb20a88 --- /dev/null +++ b/roms/SLOF/lib/libnvram/libnvram.in @@ -0,0 +1,42 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + *     IBM Corporation - initial implementation + *****************************************************************************/ + +/* NVRAM access primitives */ +cod(nvram-c@) +cod(nvram-c!) +cod(nvram-w@) +cod(nvram-w!) +cod(nvram-l@) +cod(nvram-l!) +cod(nvram-x@) +cod(nvram-x!) + +/* Generic NVRAM helpers */ +cod(internal-reset-nvram) +cod(nvram-debug) +cod(wipe-nvram) + +/* NVRAM Partition Handling */ +cod(get-nvram-partition) +cod(get-named-nvram-partition) +cod(new-nvram-partition) +cod(increase-nvram-partition) +cod(erase-nvram-partition) +cod(delete-nvram-partition) + +/* NVRAM environment access words */ +cod(internal-get-env) +cod(internal-add-env) +cod(internal-del-env) +cod(internal-set-env) + +cod(internal-nvram-init) diff --git a/roms/SLOF/lib/libnvram/nvram.c b/roms/SLOF/lib/libnvram/nvram.c new file mode 100644 index 00000000..5c113766 --- /dev/null +++ b/roms/SLOF/lib/libnvram/nvram.c @@ -0,0 +1,623 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + *     IBM Corporation - initial implementation + *****************************************************************************/ + +#include "cache.h" +#include "nvram.h" +#include "../libhvcall/libhvcall.h" + +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <southbridge.h> +#include <nvramlog.h> +#include <byteorder.h> + +#ifdef RTAS_NVRAM +static uint32_t fetch_token; +static uint32_t store_token; +static uint32_t NVRAM_LENGTH; +static char *nvram_buffer; /* use buffer allocated by SLOF code */ +#else +#ifndef NVRAM_LENGTH +#define NVRAM_LENGTH	0x10000 +#endif +/* + * This is extremely ugly, but still better than implementing  + * another sbrk() around it. + */ +static char nvram_buffer[NVRAM_LENGTH]; +#endif + +static uint8_t nvram_buffer_locked=0x00; + +void nvram_init(uint32_t _fetch_token, uint32_t _store_token,  +		long _nvram_length, void* nvram_addr) +{ +#ifdef RTAS_NVRAM +	fetch_token = _fetch_token; +	store_token = _store_token; +	NVRAM_LENGTH = _nvram_length; +	nvram_buffer = nvram_addr; + +	DEBUG("\nNVRAM: size=%d, fetch=%x, store=%x\n", +		NVRAM_LENGTH, fetch_token, store_token); +#endif +} + + +void asm_cout(long Character,long UART,long NVRAM); + +#if defined(DISABLE_NVRAM) + +static volatile uint8_t nvram[NVRAM_LENGTH]; /* FAKE */ + +#define nvram_access(type,size,name) 				\ +	type nvram_read_##name(unsigned int offset)		\ +	{							\ +		type *pos;					\ +		if (offset > (NVRAM_LENGTH - sizeof(type)))	\ +			return 0;				\ +		pos = (type *)(nvram+offset);			\ +		return *pos;					\ +	}							\ +	void nvram_write_##name(unsigned int offset, type data)	\ +	{							\ +		type *pos;					\ +		if (offset > (NVRAM_LENGTH - sizeof(type)))	\ +			return;					\ +		pos = (type *)(nvram+offset);			\ +		*pos = data;					\ +	} + +#elif defined(RTAS_NVRAM) + +static inline void nvram_fetch(unsigned int offset, void *buf, unsigned int len) +{ + 	struct hv_rtas_call rtas = { +		.token = fetch_token, +		.nargs = 3, +		.nrets = 2, +		.argret = { offset, (uint32_t)(unsigned long)buf, len }, +	}; +	h_rtas(&rtas); +} + +static inline void nvram_store(unsigned int offset, void *buf, unsigned int len) +{ +	struct hv_rtas_call rtas = { +		.token = store_token, +		.nargs = 3, +		.nrets = 2, +		.argret = { offset, (uint32_t)(unsigned long)buf, len }, +	}; +	h_rtas(&rtas); +} + +#define nvram_access(type,size,name) 				\ +	type nvram_read_##name(unsigned int offset)		\ +	{							\ +		type val;					\ +		if (offset > (NVRAM_LENGTH - sizeof(type)))	\ +			return 0;				\ +		nvram_fetch(offset, &val, size / 8);		\ +		return val;					\ +	}							\ +	void nvram_write_##name(unsigned int offset, type data)	\ +	{							\ +		if (offset > (NVRAM_LENGTH - sizeof(type)))	\ +			return;					\ +		nvram_store(offset, &data, size / 8);		\ +	} + +#else	/* DISABLE_NVRAM */ + +static volatile uint8_t *nvram = (volatile uint8_t *)SB_NVRAM_adr; + +#define nvram_access(type,size,name) 				\ +	type nvram_read_##name(unsigned int offset)		\ +	{							\ +		type *pos;					\ +		if (offset > (NVRAM_LENGTH - sizeof(type)))	\ +			return 0;				\ +		pos = (type *)(nvram+offset);			\ +		return ci_read_##size(pos);			\ +	}							\ +	void nvram_write_##name(unsigned int offset, type data)	\ +	{							\ +		type *pos;					\ +		if (offset > (NVRAM_LENGTH - sizeof(type)))	\ +			return;					\ +		pos = (type *)(nvram+offset);			\ +		ci_write_##size(pos, data);			\ +	} + +#endif + +/* + * producer for nvram access functions. Since these functions are + * basically all the same except for the used data types, produce  + * them via the nvram_access macro to keep the code from bloating. + */ + +nvram_access(uint8_t,   8, byte) +nvram_access(uint16_t, 16, word) +nvram_access(uint32_t, 32, dword) +nvram_access(uint64_t, 64, qword) + + + +/** + * This function is a minimal abstraction for our temporary + * buffer. It should have been malloced, but since there is no + * usable malloc, we go this route. + * + * @return pointer to temporary buffer + */ + +char *get_nvram_buffer(int len) +{ +	if(len>NVRAM_LENGTH) +		return NULL; + +	if(nvram_buffer_locked) +		return NULL; + +	nvram_buffer_locked = 0xff; + +	return nvram_buffer; +} + +/** + * @param buffer pointer to the allocated buffer. This + * is unused, but nice in case we ever get a real malloc + */ + +void free_nvram_buffer(char *buffer __attribute__((unused))) +{ +	nvram_buffer_locked = 0x00; +} + +/** + * @param fmt format string, like in printf + * @param ... variable number of arguments + */ + +int nvramlog_printf(const char* fmt, ...) +{ +	char buff[256]; +	int count, i; +	va_list ap; + +	va_start(ap, fmt); +	count = vsprintf(buff, fmt, ap); +	va_end(ap); + +	for (i=0; i<count; i++) +		asm_cout(buff[i], 0, 1); + +	return count; +} + +/** + * @param offset start offset of the partition header + */ + +static uint8_t get_partition_type(int offset) +{ +	return nvram_read_byte(offset); +} + +/** + * @param offset start offset of the partition header + */ + +static uint8_t get_partition_header_checksum(int offset) +{ +	return nvram_read_byte(offset+1); +} + +/** + * @param offset start offset of the partition header + */ + +static uint16_t get_partition_len(int offset) +{ +	return nvram_read_word(offset+2); +} + +/** + * @param offset start offset of the partition header + * @return static char array containing the partition name + * + * NOTE: If the partition name needs to be non-temporary, strdup  + * and use the copy instead. + */ + +static char * get_partition_name(int offset) +{ +	static char name[12]; +	int i; +	for (i=0; i<12; i++) +		name[i]=nvram_read_byte(offset+4+i); + +	DEBUG("name: \"%s\"\n", name); +	return name; +} + +static uint8_t calc_partition_header_checksum(int offset) +{ +	uint16_t plainsum; +	uint8_t checksum; +	int i; + +	plainsum = nvram_read_byte(offset); + +	for (i=2; i<PARTITION_HEADER_SIZE; i++) +		plainsum+=nvram_read_byte(offset+i); + +	checksum=(plainsum>>8)+(plainsum&0xff); + +	return checksum; +} + +static int calc_used_nvram_space(void) +{ +	int walk, len; + +	for (walk=0; walk<NVRAM_LENGTH;) { +		if(nvram_read_byte(walk) == 0  +		   || get_partition_header_checksum(walk) !=  +				calc_partition_header_checksum(walk)) { +			/* If there's no valid entry, bail out */ +			break; +		} + +		len=get_partition_len(walk); +		DEBUG("... part len=%x, %x\n", len, len*16); + +		if(!len) { +			/* If there's a partition type but no len, bail out. +			 * Don't bail out if type is 0. This can be used to +			 * find the offset of the first free byte. +			 */ +			break; +		} + +		walk += len * 16; +	} +	DEBUG("used nvram space: %d\n", walk); + +	return walk; +} + +/** + * + * @param type partition type. Set this to the partition type you are looking + *             for. If there are several partitions with the same type, only + *             the first partition with that type will be found. + *             Set to -1 to ignore. Set to 0 to find free unpartitioned space. + * + * @param name partition name. Set this to the name of the partition you are + *             looking for. If there are several partitions with the same name, + *             only the first partition with that name will be found. + *             Set to NULL to ignore. + * + * To disambiguate the partitions you should have a unique name if you plan to + * have several partitions of the same type. + * + */ + +partition_t get_partition(unsigned int type, char *name) +{ +	partition_t ret={0,-1}; +	int walk, len; + +	DEBUG("get_partition(%i, '%s')\n", type, name); + +	for (walk=0; walk<NVRAM_LENGTH;) { +		// DEBUG("get_partition: walk=%x\n", walk); +		if(get_partition_header_checksum(walk) !=  +				calc_partition_header_checksum(walk)) { +			/* If there's no valid entry, bail out */ +			break; +		} + +		len=get_partition_len(walk); +		if(type && !len) { +			/* If there's a partition type but no len, bail out. +			 * Don't bail out if type is 0. This can be used to +			 * find the offset of the first free byte. +			 */ +			break; +		} + +		/* Check if either type or name or both do not match. */ +		if ( (type!=(unsigned int)-1 && type != get_partition_type(walk)) || +			(name && strncmp(get_partition_name(walk), name, 12)) ) { +			/* We hit another partition. Continue +			 * at the end of this partition +			 */ +			walk += len*16; +			continue; +		} + +		ret.addr=walk+PARTITION_HEADER_SIZE; +		ret.len=(len*16)-PARTITION_HEADER_SIZE; +		break; +	} + +	return ret; +} + +void erase_nvram(int offset, int len) +{ +	int i; + +	for (i=offset; i<offset+len; i++) +		nvram_write_byte(i, 0); +} + +void wipe_nvram(void) +{ +	erase_nvram(0, NVRAM_LENGTH); +} + +/** + * @param partition   partition structure pointing to the partition to wipe. + * @param header_only if header_only is != 0 only the partition header is + *                    nulled out, not the whole partition. + */ + +int wipe_partition(partition_t partition, int header_only) +{ +	int pstart, len; + +	pstart=partition.addr-PARTITION_HEADER_SIZE; +	 +	len=PARTITION_HEADER_SIZE; + +	if(!header_only) +		len += partition.len; + +	erase_nvram(pstart, len); + +	return 0; +} + + +static partition_t create_nvram_partition(int type, const char *name, int len) +{ +	partition_t ret = { 0, 0 }; +	int offset, plen; +	unsigned int i; + +	plen = ALIGN(len+PARTITION_HEADER_SIZE, 16); + +	DEBUG("Creating partition type=%x, name=%s, len=%d plen=%d\n", +			type, name, len, plen); + +	offset = calc_used_nvram_space(); + +	if (NVRAM_LENGTH-(calc_used_nvram_space())<plen) { +		DEBUG("Not enough free space.\n"); +		return ret; +	} + +	DEBUG("Writing header."); + +	nvram_write_byte(offset, type); +	nvram_write_word(offset+2, plen/16); + +	for (i=0; i<strlen(name); i++) +		nvram_write_byte(offset+4+i, name[i]); + +	nvram_write_byte(offset+1, calc_partition_header_checksum(offset)); + +	ret.addr = offset+PARTITION_HEADER_SIZE; +	ret.len = len; + +	DEBUG("partition created: addr=%lx len=%lx\n", ret.addr, ret.len); + +	return ret; +} + +static int create_free_partition(void) +{ +	int free_space; +	partition_t free_part; + +	free_space = NVRAM_LENGTH - calc_used_nvram_space() - PARTITION_HEADER_SIZE; +	free_part = create_nvram_partition(0x7f, "free space", free_space); + +	return (free_part.addr != 0); +} + +partition_t new_nvram_partition(int type, char *name, int len) +{ +	partition_t free_part, new_part = { 0, 0 }; + +	/* NOTE: Assume all free space is consumed by the "free space" +	 * partition. This means a partition can not be increased in the middle +	 * of reset_nvram, which is obviously not a big loss. +	 */ + +	free_part=get_partition(0x7f, NULL); +	if( free_part.len && free_part.len != -1) +		wipe_partition(free_part, 1); + +	new_part = create_nvram_partition(type, name, len); + +	if(new_part.len != len) { +		new_part.len = 0; +		new_part.addr = 0; +	} + +	create_free_partition(); + +	return new_part; +} + +/** + * @param partition   partition structure pointing to the partition to wipe. + */ + +int delete_nvram_partition(partition_t partition) +{ +	int i; +	partition_t free_part; + +	if(!partition.len || partition.len == -1) +		return 0; + +	for (i=partition.addr+partition.len; i< NVRAM_LENGTH; i++)  +		nvram_write_byte(i - partition.len - PARTITION_HEADER_SIZE, nvram_read_byte(i)); + +	erase_nvram(NVRAM_LENGTH-partition.len-PARTITION_HEADER_SIZE,  +			partition.len-PARTITION_HEADER_SIZE); + +	free_part=get_partition(0x7f, NULL); +	wipe_partition(free_part, 0); +	create_free_partition(); + +	return 1; +} + +int clear_nvram_partition(partition_t part) +{ +	if(!part.addr) +		return 0; + +	erase_nvram(part.addr, part.len); + +	return 1; +} + + +int increase_nvram_partition_size(partition_t partition, int newsize) +{ +	partition_t free_part; +	int free_offset, end_offset, i; + +	/* We don't support shrinking partitions (yet) */ +	if (newsize < partition.len) { +		return 0; +	} + +	/* NOTE: Assume all free space is consumed by the "free space" +	 * partition. This means a partition can not be increased in the middle +	 * of reset_nvram, which is obviously not a big loss. +	 */ + +	free_part=get_partition(0x7f, NULL); + +	// FIXME: It could be 16 byte more. Also handle empty "free" partition. +	if (free_part.len == -1 || free_part.len < newsize - partition.len ) { +		return 0; +	} +	 +	free_offset=free_part.addr - PARTITION_HEADER_SIZE; // first unused byte +	end_offset=partition.addr + partition.len; // last used byte of partition + 1 + +	if(free_offset > end_offset) { +		int j, bufferlen; +		char *overlap_buffer; + +		bufferlen=free_offset - end_offset; + +		overlap_buffer=get_nvram_buffer(bufferlen); +		if(!overlap_buffer) { +			return 0; +		} + +		for (i=end_offset, j=0; i<free_offset; i++, j++) +			overlap_buffer[j]=nvram_read_byte(i); + +		/* Only wipe the header. The free space partition is empty per +		 * definition +		 */ + +		wipe_partition(free_part, 1); + +		for (i=partition.addr+newsize, j=0; i<(int)(partition.addr+newsize+bufferlen); i++, j++) +			nvram_write_byte(i, overlap_buffer[j]); + +		free_nvram_buffer(overlap_buffer); +	} else { +		/* Only wipe the header. */ +		wipe_partition(free_part, 1); +	} + +	/* Clear the new partition space */ +	erase_nvram(partition.addr+partition.len, newsize-partition.len); + +	nvram_write_word(partition.addr - 16 + 2, newsize); + +	create_free_partition(); + +	return 1; +} + +static void init_cpulog_partition(partition_t cpulog) +{ +	unsigned int offset=cpulog.addr; + +	/* see board-xxx/include/nvramlog.h for information */ +	nvram_write_word(offset+0, 0x40);  // offset +	nvram_write_word(offset+2, 0x00);  // flags +	nvram_write_dword(offset+4, 0x01); // pointer + +} + +void reset_nvram(void) +{ +	partition_t cpulog0, cpulog1; +	struct { +		uint32_t prefix; +		uint64_t name; +	} __attribute__((packed)) header; + +	DEBUG("Erasing NVRAM\n"); +	erase_nvram(0, NVRAM_LENGTH); + +	DEBUG("Creating CPU log partitions\n"); +	header.prefix = be32_to_cpu(LLFW_LOG_BE0_NAME_PREFIX); +	header.name   = be64_to_cpu(LLFW_LOG_BE0_NAME); +	cpulog0=create_nvram_partition(LLFW_LOG_BE0_SIGNATURE, (char *)&header,  +			(LLFW_LOG_BE0_LENGTH*16)-PARTITION_HEADER_SIZE); + +	header.prefix = be32_to_cpu(LLFW_LOG_BE1_NAME_PREFIX); +	header.name   = be64_to_cpu(LLFW_LOG_BE1_NAME); +	cpulog1=create_nvram_partition(LLFW_LOG_BE1_SIGNATURE, (char *)&header,  +			(LLFW_LOG_BE1_LENGTH*16)-PARTITION_HEADER_SIZE); + +	DEBUG("Initializing CPU log partitions\n"); +	init_cpulog_partition(cpulog0); +	init_cpulog_partition(cpulog1); + +	nvramlog_printf("Creating common NVRAM partition\r\n"); +	create_nvram_partition(0x70, "common", 0x01000-PARTITION_HEADER_SIZE); + +	create_free_partition(); +} + +void nvram_debug(void) +{ +#ifndef RTAS_NVRAM +	printf("\nNVRAM_BASE: %p\n", nvram); +	printf("NVRAM_LEN: 0x%x\n", NVRAM_LENGTH); +#endif +} + +unsigned int get_nvram_size(void) +{ +	return NVRAM_LENGTH; +} diff --git a/roms/SLOF/lib/libnvram/nvram.h b/roms/SLOF/lib/libnvram/nvram.h new file mode 100644 index 00000000..fa6bdd42 --- /dev/null +++ b/roms/SLOF/lib/libnvram/nvram.h @@ -0,0 +1,73 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + *     IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef __NVRAM_H +#define __NVRAM_H 1 + +/* data structures */ + +typedef struct { +	unsigned long addr; +	long len; +} partition_t; + +/* macros */ + +#define DEBUG(x...) +// #define DEBUG(x...) printf(x); + +#ifndef ALIGN +#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) +#endif + +#define NULL ((void *)0) + +#define PARTITION_HEADER_SIZE 16 + + +/* exported functions */ + +#define nvram_access_proto(type,name)			\ +	type nvram_read_##name(unsigned int offset);		\ +	void nvram_write_##name(unsigned int offset, type data); + +nvram_access_proto(uint8_t,  byte) +nvram_access_proto(uint16_t, word) +nvram_access_proto(uint32_t, dword) +nvram_access_proto(uint64_t, qword) + +/* nvram.c */ + +char *get_nvram_buffer(int len); +void free_nvram_buffer(char *buffer); +int nvramlog_printf(const char* fmt, ...); +partition_t get_partition(unsigned int type, char *name); +void erase_nvram(int offset, int len); +int wipe_partition(partition_t partition, int header_only); +partition_t new_nvram_partition(int type, char *name, int len); +int increase_nvram_partition_size(partition_t partition, int newsize); +int clear_nvram_partition(partition_t part); +int delete_nvram_partition(partition_t part); +void reset_nvram(void); +void wipe_nvram(void); +void nvram_debug(void); +void nvram_init(uint32_t store_token, uint32_t fetch_token, +		long nv_size, void* nvram_addr); +unsigned int get_nvram_size(void); + +/* envvar.c */ +char *get_env(partition_t part, char *envvar); +int add_env(partition_t part, char *envvar, char *value); +int del_env(partition_t part, char *envvar); +int set_env(partition_t part, char *envvar, char *value); + +#endif | 
