From 0ad10f26c94a86a0c9c3970e53f9a9f6a744055d Mon Sep 17 00:00:00 2001 From: "Nikunj A. Dadhania" Date: Tue, 16 Oct 2012 11:49:51 +0530 Subject: SLOF: Support PAPR NVRAM RTAS calls BenH still need to ACK this though. From: Nikunj A. Dadhania * Determines size of the flash using device tree. * Provides nvram access functions for RTAS_NVRAM * Allocates temporary buffer of nvram in SLOF code and use that in C. (sbrk not available) * NVRAM_LENGTH is used at various places, make sure it is well guarded and also use dynamically determined size once an RTAS-NVRAM is found. * Use NVRAM_LENGTH as a variable in case of RTAS_NVRAM, not very elegant though Signed-off-by: Nikunj A. Dadhania -- Changelog from v1: * #define cleanups suggested by Thomas/Benh * Fix makefile which missed passing $FLAG for building llfw * renamed vio-nvram.fs as rtas-nvram.fs --- board-qemu/config | 2 +- board-qemu/include/southbridge.h | 1 - board-qemu/llfw/Makefile | 2 +- board-qemu/slof/Makefile | 1 + board-qemu/slof/qemu-bootlist.fs | 14 ++++--- board-qemu/slof/rtas-nvram.fs | 48 ++++++++++++++++++++++ board-qemu/slof/tree.fs | 3 ++ lib/libbases/libbases.code | 2 +- lib/libbootmsg/bootmsg_lvl.S | 5 ++- lib/libhvcall/libhvcall.h | 14 +++++++ lib/libnvram/libnvram.code | 10 ++++- lib/libnvram/libnvram.in | 1 + lib/libnvram/nvram.c | 88 ++++++++++++++++++++++++++++++++++++---- lib/libnvram/nvram.h | 3 ++ llfw/nvramlog.S | 5 +-- slof/fs/logging.fs | 6 +-- 16 files changed, 179 insertions(+), 26 deletions(-) create mode 100644 board-qemu/slof/rtas-nvram.fs diff --git a/board-qemu/config b/board-qemu/config index 63976a0..a381f19 100644 --- a/board-qemu/config +++ b/board-qemu/config @@ -1,6 +1,6 @@ BOARD=qemu TARG=ppc64 -export FLAG="-DDISABLE_NVRAM" +export FLAG=-DRTAS_NVRAM export CPUARCH=ppcp7 export CPUARCHDEF=-DCPU_PPCP7 #export SNK_BIOSEMU_APPS=1 diff --git a/board-qemu/include/southbridge.h b/board-qemu/include/southbridge.h index 3ca4e04..1cdb422 100644 --- a/board-qemu/include/southbridge.h +++ b/board-qemu/include/southbridge.h @@ -13,7 +13,6 @@ /* Not used */ #define SB_NVRAM_adr 0 #define SB_FLASH_adr 0 -#define NVRAM_LENGTH 0x10000 #define FLASH_LENGTH 0 #define SB_MAILBOX_adr 0 diff --git a/board-qemu/llfw/Makefile b/board-qemu/llfw/Makefile index e40472c..89f17f8 100644 --- a/board-qemu/llfw/Makefile +++ b/board-qemu/llfw/Makefile @@ -14,7 +14,7 @@ include ../../make.rules CPPFLAGS = -I$(INCLBRDDIR) -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH) \ -I$(LIBCMNDIR)/libc/include -CFLAGS += -fno-builtin $(CPPFLAGS) -O2 -msoft-float $(MAMBO) +CFLAGS += -fno-builtin $(FLAG) $(CPPFLAGS) -O2 -msoft-float $(MAMBO) CFLAGS += $(BOOT) $(IOCONF) -Wa,-mregnames $(RELEASE) $(CPUARCHDEF) -Wall ASFLAGS = $(BOOT) $(IOCONF) $(RELEASE)$(CPUARCHDEF) -Wa,-mregnames LDFLAGS1 = -nostdlib -e__start -Tstage2.lds -N -Ttext=0x100 diff --git a/board-qemu/slof/Makefile b/board-qemu/slof/Makefile index 07d4916..036ad61 100644 --- a/board-qemu/slof/Makefile +++ b/board-qemu/slof/Makefile @@ -63,6 +63,7 @@ VIO_FFS_FILES = \ $(SLOFBRDDIR)/vio-vscsi.fs \ $(SLOFBRDDIR)/vio-vscsi-device.fs \ $(SLOFBRDDIR)/vio-veth.fs \ + $(SLOFBRDDIR)/rtas-nvram.fs \ $(SLOFBRDDIR)/virtio-net.fs \ $(SLOFBRDDIR)/virtio-block.fs \ $(SLOFBRDDIR)/virtio-fs.fs diff --git a/board-qemu/slof/qemu-bootlist.fs b/board-qemu/slof/qemu-bootlist.fs index 6b52b97..0a1aaf3 100644 --- a/board-qemu/slof/qemu-bootlist.fs +++ b/board-qemu/slof/qemu-bootlist.fs @@ -16,11 +16,15 @@ defer add-boot-device : qemu-read-bootlist ( -- ) 0 0 set-boot-device - \ check nvram - " boot-device" evaluate swap drop 0 <> IF EXIT THEN - - \ check qemu boot list - " qemu,boot-device" get-chosen not IF EXIT THEN + " qemu,boot-device" get-chosen not IF + \ No boot list set from qemu, so check nvram + " boot-device" evaluate swap drop 0= IF + \ Not set in nvram too, set default disk/cdrom alias + " disk" add-boot-device + " cdrom" add-boot-device + THEN + EXIT + THEN 0 ?DO dup i + c@ CASE diff --git a/board-qemu/slof/rtas-nvram.fs b/board-qemu/slof/rtas-nvram.fs new file mode 100644 index 0000000..fdebfb2 --- /dev/null +++ b/board-qemu/slof/rtas-nvram.fs @@ -0,0 +1,48 @@ +\ ***************************************************************************** +\ * Copyright (c) 2012 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 +\ ****************************************************************************/ + +." Populating " pwd cr + +0 VALUE my-nvram-fetch +0 VALUE my-nvram-store +0 VALUE my-nvram-size +0 VALUE nvram-addr + +: open true ; +: close ; + +: write ( adr len -- actual ) + nip +; + +: read ( adr len -- actual ) + nip +; + +: setup-alias + " nvram" find-alias 0= IF + " nvram" get-node node>path set-alias + ELSE + drop + THEN +; + +" #bytes" get-node get-package-property 0= IF + decode-int to my-nvram-size 2drop + " nvram-fetch" rtas-get-token to my-nvram-fetch + " nvram-store" rtas-get-token to my-nvram-store + my-nvram-size to nvram-size + nvram-size alloc-mem to nvram-addr + my-nvram-fetch my-nvram-store nvram-size nvram-addr internal-nvram-init +THEN + +setup-alias diff --git a/board-qemu/slof/tree.fs b/board-qemu/slof/tree.fs index 533fc95..d00f5af 100644 --- a/board-qemu/slof/tree.fs +++ b/board-qemu/slof/tree.fs @@ -80,6 +80,9 @@ include fbuffer.fs 2dup " IBM,l-lan" strequal IF " vio-veth.fs" included THEN + 2dup " qemu,spapr-nvram" strequal IF + " rtas-nvram.fs" included + THEN 2drop THEN peer diff --git a/lib/libbases/libbases.code b/lib/libbases/libbases.code index 7dc941d..45312e2 100644 --- a/lib/libbases/libbases.code +++ b/lib/libbases/libbases.code @@ -20,7 +20,7 @@ MIRP // : get-nvram-size ( -- size ) PRIM(get_X2d_nvram_X2d_size) PUSH; - TOS.u = NVRAM_LENGTH; + TOS.u = get_nvram_size(); MIRP // : get-flash-base ( -- base ) diff --git a/lib/libbootmsg/bootmsg_lvl.S b/lib/libbootmsg/bootmsg_lvl.S index 65cf0c3..2e4c135 100644 --- a/lib/libbootmsg/bootmsg_lvl.S +++ b/lib/libbootmsg/bootmsg_lvl.S @@ -158,7 +158,8 @@ ENTRY(bootmsg_setlevel) andi. r3, r3, 0x7F add r6,r3,r6 // address | stb r4,0(r6) // store level |_ stwbrx r4,r3,r6 -#ifndef DISABLE_NVRAM + +#if !defined(DISABLE_NVRAM) && !defined(RTAS_NVRAM) LOAD64(r6, SB_NVRAM_FWONLY_adr + 8 ) add r6,r6,r3 stb r4,0(r6) @@ -167,7 +168,7 @@ ENTRY(bootmsg_setlevel) blr ENTRY(bootmsg_nvupdate) -#ifndef DISABLE_NVRAM +#if !defined(DISABLE_NVRAM) && !defined(RTAS_NVRAM) mflr r10 LOAD64(r3, SB_NVRAM_FWONLY_adr) lwz r4, 0(r3) diff --git a/lib/libhvcall/libhvcall.h b/lib/libhvcall/libhvcall.h index 302e2a3..6e418ba 100644 --- a/lib/libhvcall/libhvcall.h +++ b/lib/libhvcall/libhvcall.h @@ -70,6 +70,20 @@ static inline long h_add_logical_lan_buffer(unsigned long unit_address, return hv_generic(H_ADD_LOGICAL_LAN_BUFFER, unit_address, buffer); } +#define HV_RTAS_MAX_ARGRET 5 + +struct hv_rtas_call { + uint32_t token; + uint32_t nargs; + uint32_t nrets; + uint32_t argret[HV_RTAS_MAX_ARGRET]; +}; + +static inline unsigned long h_rtas(struct hv_rtas_call *rtas_buf) +{ + return hv_generic(KVMPPC_H_RTAS, (unsigned long)rtas_buf); +} + extern unsigned long hv_logical_ci_load(unsigned long size, unsigned long addr); extern unsigned long hv_logical_ci_store(unsigned long size, unsigned long addr, unsigned long value); diff --git a/lib/libnvram/libnvram.code b/lib/libnvram/libnvram.code index f1fd414..723941d 100644 --- a/lib/libnvram/libnvram.code +++ b/lib/libnvram/libnvram.code @@ -276,4 +276,12 @@ PRIM(delete_X2d_nvram_X2d_partition) 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/lib/libnvram/libnvram.in b/lib/libnvram/libnvram.in index 33ab3bc..bbb20a8 100644 --- a/lib/libnvram/libnvram.in +++ b/lib/libnvram/libnvram.in @@ -39,3 +39,4 @@ cod(internal-add-env) cod(internal-del-env) cod(internal-set-env) +cod(internal-nvram-init) diff --git a/lib/libnvram/nvram.c b/lib/libnvram/nvram.c index 048ec0f..2cb83dc 100644 --- a/lib/libnvram/nvram.c +++ b/lib/libnvram/nvram.c @@ -12,6 +12,7 @@ #include "cache.h" #include "nvram.h" +#include "../libhvcall/libhvcall.h" #include #include @@ -20,9 +21,38 @@ #include #include +#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; + + printf("\nNVRAM: size=%d, fetch=%x, store=%x\n", + NVRAM_LENGTH, fetch_token, store_token); +#endif +} + void asm_cout(long Character,long UART,long NVRAM); @@ -48,6 +78,46 @@ static volatile uint8_t nvram[NVRAM_LENGTH]; /* FAKE */ *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; @@ -83,12 +153,7 @@ nvram_access(uint16_t, 16, word) nvram_access(uint32_t, 32, dword) nvram_access(uint64_t, 64, qword) -/* - * This is extremely ugly, but still better than implementing - * another sbrk() around it. - */ -static char nvram_buffer[NVRAM_LENGTH]; -static uint8_t nvram_buffer_locked=0x00; + /** * This function is a minimal abstraction for our temporary @@ -184,7 +249,7 @@ static char * get_partition_name(int offset) for (i=0; i<12; i++) name[i]=nvram_read_byte(offset+4+i); - // DEBUG("name: \"%s\"\n", name); + DEBUG("name: \"%s\"\n", name); return name; } @@ -217,7 +282,7 @@ static int calc_used_nvram_space(void) } len=get_partition_len(walk); - // DEBUG("... part len=%x, %x\n", len, len*16); + DEBUG("... part len=%x, %x\n", len, len*16); if(!len) { /* If there's a partition type but no len, bail out. @@ -546,6 +611,13 @@ void reset_nvram(void) 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/lib/libnvram/nvram.h b/lib/libnvram/nvram.h index 1324809..fa6bdd4 100644 --- a/lib/libnvram/nvram.h +++ b/lib/libnvram/nvram.h @@ -60,6 +60,9 @@ 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); diff --git a/llfw/nvramlog.S b/llfw/nvramlog.S index be6bfd8..eb14c95 100644 --- a/llfw/nvramlog.S +++ b/llfw/nvramlog.S @@ -14,8 +14,7 @@ #include #include - -#if !defined(DISABLE_NVRAM) +#if !defined(DISABLE_NVRAM) && !defined(RTAS_NVRAM) // detect overflow: if(a