summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2018-05-16 09:42:22 -0600
committerAlexander Graf <agraf@suse.de>2018-06-03 15:27:21 +0200
commit30eef21fa041635fb8327ef9001d78cb187c359f (patch)
tree0945455a7afbc64b4636329b50ac62d58db979cb
parent0864c565a274ddbc23dda667d71524e7efbbef8f (diff)
sandbox: Add a setjmp() implementation
Add an implementation of setjmp() and longjmp() which rely on the underlying host C library. Since we cannot know how large the jump buffer needs to be, pick something that should be suitable and check it at runtime. At present we need access to the underlying struct as well. Signed-off-by: Simon Glass <sjg@chromium.org> Signed-off-by: Alexander Graf <agraf@suse.de>
-rw-r--r--arch/sandbox/cpu/cpu.c13
-rw-r--r--arch/sandbox/cpu/os.c23
-rw-r--r--arch/sandbox/include/asm/setjmp.h30
-rw-r--r--include/os.h21
4 files changed, 87 insertions, 0 deletions
diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c
index d4ad020012..cde0b055a6 100644
--- a/arch/sandbox/cpu/cpu.c
+++ b/arch/sandbox/cpu/cpu.c
@@ -9,6 +9,7 @@
#include <linux/libfdt.h>
#include <os.h>
#include <asm/io.h>
+#include <asm/setjmp.h>
#include <asm/state.h>
#include <dm/root.h>
@@ -164,3 +165,15 @@ ulong timer_get_boot_us(void)
return (count - base_count) / 1000;
}
+
+int setjmp(jmp_buf jmp)
+{
+ return os_setjmp((ulong *)jmp, sizeof(*jmp));
+}
+
+void longjmp(jmp_buf jmp, int ret)
+{
+ os_longjmp((ulong *)jmp, ret);
+ while (1)
+ ;
+}
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c
index d76d0211a2..5839932b00 100644
--- a/arch/sandbox/cpu/os.c
+++ b/arch/sandbox/cpu/os.c
@@ -7,6 +7,7 @@
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
+#include <setjmp.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
@@ -628,3 +629,25 @@ void os_localtime(struct rtc_time *rt)
rt->tm_yday = tm->tm_yday;
rt->tm_isdst = tm->tm_isdst;
}
+
+int os_setjmp(ulong *jmp, int size)
+{
+ jmp_buf dummy;
+
+ /*
+ * We cannot rely on the struct name that jmp_buf uses, so use a
+ * local variable here
+ */
+ if (size < sizeof(dummy)) {
+ printf("setjmp: jmpbuf is too small (%d bytes, need %d)\n",
+ size, sizeof(jmp_buf));
+ return -ENOSPC;
+ }
+
+ return setjmp((struct __jmp_buf_tag *)jmp);
+}
+
+void os_longjmp(ulong *jmp, int ret)
+{
+ longjmp((struct __jmp_buf_tag *)jmp, ret);
+}
diff --git a/arch/sandbox/include/asm/setjmp.h b/arch/sandbox/include/asm/setjmp.h
new file mode 100644
index 0000000000..0fb1a11f23
--- /dev/null
+++ b/arch/sandbox/include/asm/setjmp.h
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) 2018 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#ifndef _SETJMP_H_
+#define _SETJMP_H_
+
+struct jmp_buf_data {
+ /*
+ * We're not sure how long this should be:
+ *
+ * amd64: 200 bytes
+ * arm64: 392 bytes
+ * armhf: 392 bytes
+ *
+ * So allow space for all of those, plus some extra.
+ * We don't need to worry about 16-byte alignment, since this does not
+ * run on Windows.
+ */
+ ulong data[128];
+};
+
+typedef struct jmp_buf_data jmp_buf[1];
+
+int setjmp(jmp_buf jmp);
+__noreturn void longjmp(jmp_buf jmp, int ret);
+
+#endif /* _SETJMP_H_ */
diff --git a/include/os.h b/include/os.h
index 64e89a06c9..c8e0f52d30 100644
--- a/include/os.h
+++ b/include/os.h
@@ -330,4 +330,25 @@ int os_spl_to_uboot(const char *fname);
*/
void os_localtime(struct rtc_time *rt);
+/**
+ * os_setjmp() - Call setjmp()
+ *
+ * Call the host system's setjmp() function.
+ *
+ * @jmp: Buffer to store current execution state
+ * @size: Size of buffer
+ * @return normal setjmp() value if OK, -ENOSPC if @size is too small
+ */
+int os_setjmp(ulong *jmp, int size);
+
+/**
+ * os_longjmp() - Call longjmp()
+ *
+ * Call the host system's longjmp() function.
+ *
+ * @jmp: Buffer where previous execution state was stored
+ * @ret: Value to pass to longjmp()
+ */
+void os_longjmp(ulong *jmp, int ret);
+
#endif