diff --git a/arch/sparc32/boot.h b/arch/sparc32/boot.h
index 73d8451..fa701e5 100644
--- a/arch/sparc32/boot.h
+++ b/arch/sparc32/boot.h
@@ -13,9 +13,6 @@ int linux_load(struct sys_info *info, const char *file, const char *cmdline);
extern struct context *__context;
unsigned int start_elf(unsigned long entry_point, unsigned long param);
-// romvec.c
-void *init_openprom(void);
-
// boot.c
extern const char *bootpath;
extern void boot(void);
@@ -45,10 +42,3 @@ extern struct linux_mlist_v0 *ptavail;
void ob_init_mmu(void);
void init_mmu_swift(void);
-char *obp_dumb_mmap(char *va, int which_io, unsigned int pa,
- unsigned int size);
-void obp_dumb_munmap(__attribute__((unused)) char *va,
- __attribute__((unused)) unsigned int size);
-char *obp_dumb_memalloc(char *va, unsigned int size);
-void obp_dumb_memfree(__attribute__((unused))char *va,
- __attribute__((unused))unsigned sz);
diff --git a/arch/sparc32/build.xml b/arch/sparc32/build.xml
index d2eadce..222dfb7 100644
--- a/arch/sparc32/build.xml
+++ b/arch/sparc32/build.xml
@@ -16,6 +16,7 @@
+
diff --git a/arch/sparc32/call-romvec.S b/arch/sparc32/call-romvec.S
new file mode 100644
index 0000000..1e8f754
--- /dev/null
+++ b/arch/sparc32/call-romvec.S
@@ -0,0 +1,92 @@
+#include "psr.h"
+#include "asm/asi.h"
+
+ .text
+ .align 4
+
+#define STACKFRAME_SZ 0x60
+
+/* These are just handy. */
+#define _SV save %sp, -STACKFRAME_SZ, %sp
+#define _RS restore
+
+#define FLUSH_ALL_KERNEL_WINDOWS \
+ _SV; _SV; _SV; _SV; _SV; _SV; _SV; \
+ _RS; _RS; _RS; _RS; _RS; _RS; _RS;
+
+/* Macro for romvec handlers */
+#define ROMVEC_HANDLER(type) \
+ \
+ .globl type##_handler; \
+ \
+type##_handler: \
+ \
+ FLUSH_ALL_KERNEL_WINDOWS; \
+ \
+ save %sp, -STACKFRAME_SZ - 0x20, %sp; \
+ \
+ st %g1, [ %sp + STACKFRAME_SZ + 0x0]; \
+ st %g2, [ %sp + STACKFRAME_SZ + 0x4]; \
+ st %g3, [ %sp + STACKFRAME_SZ + 0x8]; \
+ st %g4, [ %sp + STACKFRAME_SZ + 0xc]; \
+ st %g5, [ %sp + STACKFRAME_SZ + 0x10]; \
+ st %g6, [ %sp + STACKFRAME_SZ + 0x14]; \
+ st %g7, [ %sp + STACKFRAME_SZ + 0x18]; \
+ \
+ mov %i0, %o0; \
+ mov %i1, %o1; \
+ mov %i2, %o2; \
+ mov %i3, %o3; \
+ mov %i4, %o4; \
+ mov %i5, %o5; \
+ \
+ call type; \
+ nop; \
+ \
+ mov %o0, %i0; \
+ \
+ ld [ %sp + STACKFRAME_SZ + 0x0], %g1; \
+ ld [ %sp + STACKFRAME_SZ + 0x4], %g2; \
+ ld [ %sp + STACKFRAME_SZ + 0x8], %g3; \
+ ld [ %sp + STACKFRAME_SZ + 0xc], %g4; \
+ ld [ %sp + STACKFRAME_SZ + 0x10], %g5; \
+ ld [ %sp + STACKFRAME_SZ + 0x14], %g6; \
+ ld [ %sp + STACKFRAME_SZ + 0x18], %g7; \
+ \
+ ret; \
+ restore; \
+
+
+/* Generate handlers which are proxy functions to the
+ real C functions that correctly save the globals
+ and stack */
+ROMVEC_HANDLER(obp_devopen)
+ROMVEC_HANDLER(obp_devclose)
+ROMVEC_HANDLER(obp_rdblkdev)
+ROMVEC_HANDLER(obp_nbgetchar)
+ROMVEC_HANDLER(obp_nbputchar)
+ROMVEC_HANDLER(obp_putstr)
+ROMVEC_HANDLER(obp_printf)
+ROMVEC_HANDLER(obp_reboot)
+ROMVEC_HANDLER(obp_abort)
+ROMVEC_HANDLER(obp_halt)
+ROMVEC_HANDLER(obp_fortheval_v2)
+ROMVEC_HANDLER(obp_inst2pkg)
+ROMVEC_HANDLER(obp_dumb_memalloc)
+ROMVEC_HANDLER(obp_dumb_memfree)
+ROMVEC_HANDLER(obp_dumb_mmap)
+ROMVEC_HANDLER(obp_dumb_munmap)
+ROMVEC_HANDLER(obp_devread)
+ROMVEC_HANDLER(obp_devwrite)
+ROMVEC_HANDLER(obp_devseek)
+ROMVEC_HANDLER(obp_cpustart)
+ROMVEC_HANDLER(obp_cpustop)
+ROMVEC_HANDLER(obp_cpuidle)
+ROMVEC_HANDLER(obp_cpuresume)
+ROMVEC_HANDLER(obp_nextnode)
+ROMVEC_HANDLER(obp_child)
+ROMVEC_HANDLER(obp_proplen)
+ROMVEC_HANDLER(obp_getprop)
+ROMVEC_HANDLER(obp_setprop)
+ROMVEC_HANDLER(obp_nextprop)
+
diff --git a/arch/sparc32/context.c b/arch/sparc32/context.c
index 8a34a16..d4d8530 100644
--- a/arch/sparc32/context.c
+++ b/arch/sparc32/context.c
@@ -11,7 +11,7 @@
#include "openbios.h"
#define MAIN_STACK_SIZE 16384
-#define IMAGE_STACK_SIZE 4096
+#define IMAGE_STACK_SIZE 4096*2
#define debug printk
diff --git a/arch/sparc32/lib.c b/arch/sparc32/lib.c
index 720fe43..9f4f0ac 100644
--- a/arch/sparc32/lib.c
+++ b/arch/sparc32/lib.c
@@ -15,6 +15,7 @@
#include "openprom.h"
#include "libopenbios/sys_info.h"
#include "boot.h"
+#include "romvec.h"
#define NCTX_SWIFT 0x100
#define LOWMEMSZ 32 * 1024 * 1024
diff --git a/arch/sparc32/openbios.c b/arch/sparc32/openbios.c
index 22c04c3..e368d6c 100644
--- a/arch/sparc32/openbios.c
+++ b/arch/sparc32/openbios.c
@@ -20,6 +20,7 @@
#include "libopenbios/sys_info.h"
#include "openbios.h"
#include "boot.h"
+#include "romvec.h"
#include "openprom.h"
#include "packages/video.h"
#define NO_QEMU_PROTOS
diff --git a/arch/sparc32/romvec.c b/arch/sparc32/romvec.c
index f6e0ca6..e915731 100644
--- a/arch/sparc32/romvec.c
+++ b/arch/sparc32/romvec.c
@@ -7,12 +7,15 @@
* Public License version 2 or later
*/
+#include
+
#include "openprom.h"
#include "config.h"
#include "libopenbios/bindings.h"
#include "drivers/drivers.h"
#include "libopenbios/sys_info.h"
#include "boot.h"
+#include "romvec.h"
#ifdef CONFIG_DEBUG_OBP
#define DPRINTF(fmt, args...) \
@@ -25,15 +28,6 @@ char obp_stdin, obp_stdout;
static int obp_fd_stdin, obp_fd_stdout;
const char *obp_stdin_path, *obp_stdout_path;
-static int obp_nextnode(int node);
-static int obp_child(int node);
-static int obp_proplen(int node, const char *name);
-static int obp_getprop(int node, const char *name, char *val);
-static int obp_setprop(int node, const char *name, char *val, int len);
-static const char *obp_nextprop(int node, const char *name);
-static int obp_devread(int dev_desc, char *buf, int nbytes);
-static int obp_devseek(int dev_desc, int hi, int lo);
-
struct linux_arguments_v0 obp_arg;
const char *bootpath;
static const struct linux_arguments_v0 * const obp_argp = &obp_arg;
@@ -47,7 +41,7 @@ static void doublewalk(__attribute__((unused)) unsigned int ptab1,
{
}
-static int obp_nextnode(int node)
+int obp_nextnode(int node)
{
int peer;
@@ -59,7 +53,7 @@ static int obp_nextnode(int node)
return peer;
}
-static int obp_child(int node)
+int obp_child(int node)
{
int child;
@@ -71,7 +65,7 @@ static int obp_child(int node)
return child;
}
-static int obp_proplen(int node, const char *name)
+int obp_proplen(int node, const char *name)
{
int notfound;
@@ -115,7 +109,7 @@ static int looks_like_string(const char *str, int len)
}
#endif
-static int obp_getprop(int node, const char *name, char *value)
+int obp_getprop(int node, const char *name, char *value)
{
int notfound, found;
int len;
@@ -178,7 +172,7 @@ static int obp_getprop(int node, const char *name, char *value)
}
}
-static const char *obp_nextprop(int node, const char *name)
+const char *obp_nextprop(int node, const char *name)
{
int found;
@@ -208,7 +202,7 @@ static const char *obp_nextprop(int node, const char *name)
}
}
-static int obp_setprop(__attribute__((unused)) int node,
+int obp_setprop(__attribute__((unused)) int node,
__attribute__((unused)) const char *name,
__attribute__((unused)) char *value,
__attribute__((unused)) int len)
@@ -219,28 +213,44 @@ static int obp_setprop(__attribute__((unused)) int node,
}
static const struct linux_nodeops nodeops0 = {
- obp_nextnode, /* int (*no_nextnode)(int node); */
- obp_child, /* int (*no_child)(int node); */
- obp_proplen, /* int (*no_proplen)(int node, char *name); */
- obp_getprop, /* int (*no_getprop)(int node,char *name,char *val); */
- obp_setprop, /* int (*no_setprop)(int node, char *name,
- char *val, int len); */
- obp_nextprop /* char * (*no_nextprop)(int node, char *name); */
+ obp_nextnode_handler, /* int (*no_nextnode)(int node); */
+ obp_child_handler, /* int (*no_child)(int node); */
+ obp_proplen_handler, /* int (*no_proplen)(int node, char *name); */
+ obp_getprop_handler, /* int (*no_getprop)(int node,char *name,char *val); */
+ obp_setprop_handler, /* int (*no_setprop)(int node, char *name,
+ char *val, int len); */
+ obp_nextprop_handler /* char * (*no_nextprop)(int node, char *name); */
};
-static int obp_nbgetchar(void)
+int obp_nbgetchar(void)
{
return getchar();
}
-static int obp_nbputchar(int ch)
+int obp_nbputchar(int ch)
{
putchar(ch);
return 0;
}
-static void obp_reboot(char *str)
+void obp_putstr(char *str, int len)
+{
+ PUSH(pointer2cell(str));
+ PUSH(len);
+ fword("type");
+}
+
+void obp_printf(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ printk(fmt, ap);
+ va_end(ap);
+}
+
+void obp_reboot(char *str)
{
printk("rebooting (%s)\n", str);
*reset_reg = 1;
@@ -248,7 +258,7 @@ static void obp_reboot(char *str)
for (;;) {}
}
-static void obp_abort(void)
+void obp_abort(void)
{
printk("abort, power off\n");
*power_reg = 1;
@@ -256,7 +266,7 @@ static void obp_abort(void)
for (;;) {}
}
-static void obp_halt(void)
+void obp_halt(void)
{
printk("halt, power off\n");
*power_reg = 1;
@@ -264,7 +274,7 @@ static void obp_halt(void)
for (;;) {}
}
-static int obp_devopen(char *str)
+int obp_devopen(char *str)
{
int ret;
@@ -276,7 +286,7 @@ static int obp_devopen(char *str)
return ret;
}
-static int obp_devclose(int dev_desc)
+int obp_devclose(int dev_desc)
{
int ret = 1;
@@ -288,7 +298,7 @@ static int obp_devclose(int dev_desc)
return ret;
}
-static int obp_rdblkdev(int dev_desc, int num_blks, int offset, char *buf)
+int obp_rdblkdev(int dev_desc, int num_blks, int offset, char *buf)
{
int ret, hi, lo, bs;
@@ -305,7 +315,7 @@ static int obp_rdblkdev(int dev_desc, int num_blks, int offset, char *buf)
return ret;
}
-static int obp_devread(int dev_desc, char *buf, int nbytes)
+int obp_devread(int dev_desc, char *buf, int nbytes)
{
int ret;
@@ -321,7 +331,7 @@ static int obp_devread(int dev_desc, char *buf, int nbytes)
return ret;
}
-static int obp_devwrite(int dev_desc, char *buf, int nbytes)
+int obp_devwrite(int dev_desc, char *buf, int nbytes)
{
#ifdef CONFIG_DEBUG_OBP_DEVWRITE /* disabled, makes too much noise */
int ret;
@@ -342,7 +352,7 @@ static int obp_devwrite(int dev_desc, char *buf, int nbytes)
return nbytes;
}
-static int obp_devseek(int dev_desc, int hi, int lo)
+int obp_devseek(int dev_desc, int hi, int lo)
{
int ret;
@@ -358,7 +368,7 @@ static int obp_devseek(int dev_desc, int hi, int lo)
return ret;
}
-static int obp_inst2pkg(int dev_desc)
+int obp_inst2pkg(int dev_desc)
{
int ret;
@@ -371,7 +381,7 @@ static int obp_inst2pkg(int dev_desc)
return ret;
}
-static int obp_cpustart(__attribute__((unused))unsigned int whichcpu,
+int obp_cpustart(__attribute__((unused))unsigned int whichcpu,
__attribute__((unused))int ctxtbl_ptr,
__attribute__((unused))int thiscontext,
__attribute__((unused))char *prog_counter)
@@ -391,28 +401,28 @@ static int obp_cpustart(__attribute__((unused))unsigned int whichcpu,
thiscontext, cpu);
}
-static int obp_cpustop(__attribute__((unused)) unsigned int whichcpu)
+int obp_cpustop(__attribute__((unused)) unsigned int whichcpu)
{
DPRINTF("obp_cpustop: cpu %d\n", whichcpu);
return 0;
}
-static int obp_cpuidle(__attribute__((unused)) unsigned int whichcpu)
+int obp_cpuidle(__attribute__((unused)) unsigned int whichcpu)
{
DPRINTF("obp_cpuidle: cpu %d\n", whichcpu);
return 0;
}
-static int obp_cpuresume(__attribute__((unused)) unsigned int whichcpu)
+int obp_cpuresume(__attribute__((unused)) unsigned int whichcpu)
{
DPRINTF("obp_cpuresume: cpu %d\n", whichcpu);
return 0;
}
-static void obp_fortheval_v2(char *str, int arg0, int arg1, int arg2, int arg3, int arg4)
+void obp_fortheval_v2(char *str, int arg0, int arg1, int arg2, int arg3, int arg4)
{
int pusharg = 0;
@@ -454,6 +464,10 @@ static void obp_fortheval_v2(char *str, int arg0, int arg1, int arg2, int arg3,
void *
init_openprom(void)
{
+ /* Setup the openprom vector. Note that all functions should be invoked
+ via their handler (see call-romvec.S) which acts as a proxy to save
+ the globals and setup the stack correctly */
+
// Linux wants a R/W romvec table
romvec0.pv_magic_cookie = LINUX_OPPROM_MAGIC;
romvec0.pv_romvers = 3;
@@ -464,32 +478,33 @@ init_openprom(void)
romvec0.pv_v0mem.v0_available = &ptavail;
romvec0.pv_nodeops = &nodeops0;
romvec0.pv_bootstr = (void *)doublewalk;
- romvec0.pv_v0devops.v0_devopen = &obp_devopen;
- romvec0.pv_v0devops.v0_devclose = &obp_devclose;
- romvec0.pv_v0devops.v0_rdblkdev = &obp_rdblkdev;
+ romvec0.pv_v0devops.v0_devopen = &obp_devopen_handler;
+ romvec0.pv_v0devops.v0_devclose = &obp_devclose_handler;
+ romvec0.pv_v0devops.v0_rdblkdev = &obp_rdblkdev_handler;
romvec0.pv_stdin = &obp_stdin;
romvec0.pv_stdout = &obp_stdout;
- romvec0.pv_getchar = obp_nbgetchar;
- romvec0.pv_putchar = (void (*)(int))obp_nbputchar;
- romvec0.pv_nbgetchar = obp_nbgetchar;
- romvec0.pv_nbputchar = obp_nbputchar;
- romvec0.pv_reboot = obp_reboot;
- romvec0.pv_printf = (void (*)(const char *fmt, ...))printk;
- romvec0.pv_abort = obp_abort;
- romvec0.pv_halt = obp_halt;
+ romvec0.pv_getchar = obp_nbgetchar_handler;
+ romvec0.pv_putchar = (void (*)(int))obp_nbputchar_handler;
+ romvec0.pv_nbgetchar = obp_nbgetchar_handler;
+ romvec0.pv_nbputchar = obp_nbputchar_handler;
+ romvec0.pv_putstr = obp_putstr_handler;
+ romvec0.pv_reboot = obp_reboot_handler;
+ romvec0.pv_printf = obp_printf_handler;
+ romvec0.pv_abort = obp_abort_handler;
+ romvec0.pv_halt = obp_halt_handler;
romvec0.pv_synchook = &sync_hook;
romvec0.pv_v0bootargs = &obp_argp;
- romvec0.pv_fortheval.v2_eval = obp_fortheval_v2;
- romvec0.pv_v2devops.v2_inst2pkg = obp_inst2pkg;
- romvec0.pv_v2devops.v2_dumb_mem_alloc = obp_dumb_memalloc;
- romvec0.pv_v2devops.v2_dumb_mem_free = obp_dumb_memfree;
- romvec0.pv_v2devops.v2_dumb_mmap = obp_dumb_mmap;
- romvec0.pv_v2devops.v2_dumb_munmap = obp_dumb_munmap;
- romvec0.pv_v2devops.v2_dev_open = obp_devopen;
- romvec0.pv_v2devops.v2_dev_close = (void (*)(int))obp_devclose;
- romvec0.pv_v2devops.v2_dev_read = obp_devread;
- romvec0.pv_v2devops.v2_dev_write = obp_devwrite;
- romvec0.pv_v2devops.v2_dev_seek = obp_devseek;
+ romvec0.pv_fortheval.v2_eval = obp_fortheval_v2_handler;
+ romvec0.pv_v2devops.v2_inst2pkg = obp_inst2pkg_handler;
+ romvec0.pv_v2devops.v2_dumb_mem_alloc = obp_dumb_memalloc_handler;
+ romvec0.pv_v2devops.v2_dumb_mem_free = obp_dumb_memfree_handler;
+ romvec0.pv_v2devops.v2_dumb_mmap = obp_dumb_mmap_handler;
+ romvec0.pv_v2devops.v2_dumb_munmap = obp_dumb_munmap_handler;
+ romvec0.pv_v2devops.v2_dev_open = obp_devopen_handler;
+ romvec0.pv_v2devops.v2_dev_close = (void (*)(int))obp_devclose_handler;
+ romvec0.pv_v2devops.v2_dev_read = obp_devread_handler;
+ romvec0.pv_v2devops.v2_dev_write = obp_devwrite_handler;
+ romvec0.pv_v2devops.v2_dev_seek = obp_devseek_handler;
romvec0.pv_v2bootargs.bootpath = &bootpath;
@@ -504,10 +519,10 @@ init_openprom(void)
fword("open-dev");
obp_fd_stdout = POP();
- romvec0.v3_cpustart = obp_cpustart;
- romvec0.v3_cpustop = obp_cpustop;
- romvec0.v3_cpuidle = obp_cpuidle;
- romvec0.v3_cpuresume = obp_cpuresume;
+ romvec0.v3_cpustart = obp_cpustart_handler;
+ romvec0.v3_cpustop = obp_cpustop_handler;
+ romvec0.v3_cpuidle = obp_cpuidle_handler;
+ romvec0.v3_cpuresume = obp_cpuresume_handler;
return &romvec0;
}
diff --git a/arch/sparc32/romvec.h b/arch/sparc32/romvec.h
new file mode 100644
index 0000000..d5103d1
--- /dev/null
+++ b/arch/sparc32/romvec.h
@@ -0,0 +1,76 @@
+/*
+ * romvec main C function and handler declarations
+ */
+
+void *init_openprom(void);
+
+int obp_devopen(char *str);
+int obp_devopen_handler(char *str);
+int obp_devclose(int dev_desc);
+int obp_devclose_handler(int dev_desc);
+int obp_rdblkdev(int dev_desc, int num_blks, int offset, char *buf);
+int obp_rdblkdev_handler(int dev_desc, int num_blks, int offset, char *buf);
+int obp_nbgetchar(void);
+int obp_nbgetchar_handler(void);
+int obp_nbputchar(int ch);
+int obp_nbputchar_handler(int ch);
+void obp_putstr(char *str, int len);
+void obp_putstr_handler(char *str, int len);
+void obp_printf(__const__ char *fmt, ...);
+void obp_printf_handler(__const__ char *fmt, ...);
+void obp_reboot(char *str);
+void obp_reboot_handler(char *str);
+void obp_abort(void);
+void obp_abort_handler(void);
+void obp_halt(void);
+void obp_halt_handler(void);
+void obp_fortheval_v2(char *str, int arg0, int arg1, int arg2, int arg3, int arg4);
+void obp_fortheval_v2_handler(char *str, int arg0, int arg1, int arg2, int arg3, int arg4);
+int obp_inst2pkg(int dev_desc);
+int obp_inst2pkg_handler(int dev_desc);
+char *obp_dumb_memalloc(char *va, unsigned int size);
+char *obp_dumb_memalloc_handler(char *va, unsigned int size);
+void obp_dumb_memfree(__attribute__((unused))char *va, __attribute__((unused))unsigned sz);
+void obp_dumb_memfree_handler(__attribute__((unused))char *va, __attribute__((unused))unsigned sz);
+char *obp_dumb_mmap(char *va, int which_io, unsigned int pa, unsigned int size);
+char *obp_dumb_mmap_handler(char *va, int which_io, unsigned int pa, unsigned int size);
+void obp_dumb_munmap(__attribute__((unused)) char *va, __attribute__((unused)) unsigned int size);
+void obp_dumb_munmap_handler(__attribute__((unused)) char *va, __attribute__((unused)) unsigned int size);
+int obp_devread(int dev_desc, char *buf, int nbytes);
+int obp_devread_handler(int dev_desc, char *buf, int nbytes);
+int obp_devwrite(int dev_desc, char *buf, int nbytes);
+int obp_devwrite_handler(int dev_desc, char *buf, int nbytes);
+int obp_devseek(int dev_desc, int hi, int lo);
+int obp_devseek_handler(int dev_desc, int hi, int lo);
+int obp_cpustart(__attribute__((unused))unsigned int whichcpu,
+ __attribute__((unused))int ctxtbl_ptr,
+ __attribute__((unused))int thiscontext,
+ __attribute__((unused))char *prog_counter);
+int obp_cpustart_handler(__attribute__((unused))unsigned int whichcpu,
+ __attribute__((unused))int ctxtbl_ptr,
+ __attribute__((unused))int thiscontext,
+ __attribute__((unused))char *prog_counter);
+int obp_cpustop(__attribute__((unused)) unsigned int whichcpu);
+int obp_cpustop_handler(__attribute__((unused)) unsigned int whichcpu);
+int obp_cpuidle(__attribute__((unused)) unsigned int whichcpu);
+int obp_cpuidle_handler(__attribute__((unused)) unsigned int whichcpu);
+int obp_cpuresume(__attribute__((unused)) unsigned int whichcpu);
+int obp_cpuresume_handler(__attribute__((unused)) unsigned int whichcpu);
+int obp_nextnode(int node);
+int obp_nextnode_handler(int node);
+int obp_child(int node);
+int obp_child_handler(int node);
+int obp_proplen(int node, const char *name);
+int obp_proplen_handler(int node, const char *name);
+int obp_getprop(int node, const char *name, char *value);
+int obp_getprop_handler(int node, const char *name, char *value);
+int obp_setprop(__attribute__((unused)) int node,
+ __attribute__((unused)) const char *name,
+ __attribute__((unused)) char *value,
+ __attribute__((unused)) int len);
+int obp_setprop_handler(__attribute__((unused)) int node,
+ __attribute__((unused)) const char *name,
+ __attribute__((unused)) char *value,
+ __attribute__((unused)) int len);
+const char *obp_nextprop(int node, const char *name);
+const char *obp_nextprop_handler(int node, const char *name);