All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH ARM v4 00/12] mini-os: initial ARM support
@ 2014-06-18 15:08 Thomas Leonard
  2014-06-18 15:08 ` [PATCH ARM v4 01/12] mini-os: build fixes Thomas Leonard
                   ` (11 more replies)
  0 siblings, 12 replies; 41+ messages in thread
From: Thomas Leonard @ 2014-06-18 15:08 UTC (permalink / raw)
  To: xen-devel
  Cc: Thomas Leonard, Dave.Scott, anil, stefano.stabellini, samuel.thibault

This series is based on Karim's ARM support commits, further broken up into
smaller patches.

The comments from last time should be addressed too, plus a few other things:

- the series is rebased onto the patches that Ian already applied
- removing the "link" make target broke stubdom, so I brought that back
- the x86 stack address printk is back, and I moved all the other x86 printks
  to after the "WARN: don't do printk before here" line
- the TODOs in arm/os.h have been implemented (mainly using GCC intrinsics)
- added clrex to the IRQ handler return in case these get interrupted
- added an explicit -march=armv7-a to cope with other compiler defaults
- the zImage header now works with the XSA-95 fix to "xl create"
- added fixes for unbinding ports (also useful on x86)
- configued ARM not to fault on unaligned word accessess (useful for lwIP)
- fixed the off_t type to match POSIX (maybe Mini-OS shouldn't be defining it
  in the first place, but since it is, it should do it correctly).
- there are also some new patches adding support for using the FDT to
  initialise the MM, GIC and grant tables.

This patch roll is also available here:

  https://github.com/talex5/xen/commits/sent-Jun-18

Please include Karim in any reply as I am not the author of much of this code.

Karim Raslan (3):
  mini-os: switched initial C entry point to arch_init
  mini-os: initial ARM support
  mini-os: import libfdt

Thomas Leonard (9):
  mini-os: build fixes
  mini-os: fixed shutdown thread
  mini-os: fixed format string error in unbind_evtchn
  mini-os: use unbind_evtchn in unbind_all_ports
  mini-os: made off_t type signed
  mini-os: arm: show registers, stack and exception vector on fault
  mini-os: get RAM base and size from the FDT
  mini-os: get GIC addresses from FDT
  mini-os: added ARM grant table initialisation

 extras/mini-os/ARM-TODO.txt                      |   10 +
 extras/mini-os/COPYING                           |   27 +
 extras/mini-os/Config.mk                         |    2 +
 extras/mini-os/Makefile                          |   48 +-
 extras/mini-os/arch/arm/Makefile                 |   32 +
 extras/mini-os/arch/arm/arch.mk                  |    7 +
 extras/mini-os/arch/arm/arm32.S                  |  222 ++++
 extras/mini-os/arch/arm/events.c                 |   30 +
 extras/mini-os/arch/arm/hypercalls32.S           |   88 ++
 extras/mini-os/arch/arm/minios-arm32.lds         |   75 ++
 extras/mini-os/arch/arm/mm.c                     |  162 +++
 extras/mini-os/arch/arm/panic.c                  |   99 ++
 extras/mini-os/arch/arm/sched.c                  |   37 +
 extras/mini-os/arch/arm/setup.c                  |  112 ++
 extras/mini-os/arch/arm/time.c                   |  202 +++
 extras/mini-os/arch/x86/events.c                 |    4 +
 extras/mini-os/arch/x86/mm.c                     |   13 +
 extras/mini-os/arch/x86/setup.c                  |   44 +-
 extras/mini-os/arch/x86/x86_32.S                 |    2 +-
 extras/mini-os/arch/x86/x86_64.S                 |    2 +-
 extras/mini-os/drivers/gic.c                     |  217 ++++
 extras/mini-os/events.c                          |   39 +-
 extras/mini-os/gnttab.c                          |   11 +-
 extras/mini-os/hypervisor.c                      |   12 +-
 extras/mini-os/include/arm/arch_endian.h         |    7 +
 extras/mini-os/include/arm/arch_limits.h         |    9 +
 extras/mini-os/include/arm/arch_mm.h             |   37 +
 extras/mini-os/include/arm/arch_sched.h          |   22 +
 extras/mini-os/include/arm/arch_spinlock.h       |   49 +
 extras/mini-os/include/arm/arm32/arch_wordsize.h |    1 +
 extras/mini-os/include/arm/hypercall-arm32.h     |  173 +++
 extras/mini-os/include/arm/os.h                  |  232 ++++
 extras/mini-os/include/arm/traps.h               |   20 +
 extras/mini-os/include/events.h                  |    4 +
 extras/mini-os/include/fdt.h                     |   60 +
 extras/mini-os/include/gic.h                     |    1 +
 extras/mini-os/include/gnttab.h                  |    1 +
 extras/mini-os/include/hypervisor.h              |    4 +
 extras/mini-os/include/kernel.h                  |    6 +-
 extras/mini-os/include/lib.h                     |    4 +-
 extras/mini-os/include/libfdt.h                  | 1478 ++++++++++++++++++++++
 extras/mini-os/include/libfdt_env.h              |   37 +
 extras/mini-os/include/mm.h                      |    2 +
 extras/mini-os/include/types.h                   |   14 +-
 extras/mini-os/include/x86/os.h                  |    2 -
 extras/mini-os/kernel.c                          |   55 +-
 extras/mini-os/lib/fdt/fdt.c                     |  222 ++++
 extras/mini-os/lib/fdt/fdt_empty_tree.c          |   84 ++
 extras/mini-os/lib/fdt/fdt_ro.c                  |  574 +++++++++
 extras/mini-os/lib/fdt/fdt_rw.c                  |  492 +++++++
 extras/mini-os/lib/fdt/fdt_strerror.c            |   96 ++
 extras/mini-os/lib/fdt/fdt_sw.c                  |  256 ++++
 extras/mini-os/lib/fdt/fdt_wip.c                 |  118 ++
 extras/mini-os/lib/fdt/libfdt_internal.h         |   95 ++
 extras/mini-os/lib/memmove.c                     |   45 +
 extras/mini-os/lib/string.c                      |   12 +
 extras/mini-os/main.c                            |    2 +-
 extras/mini-os/mm.c                              |    4 +-
 extras/mini-os/sched.c                           |   29 +-
 59 files changed, 5632 insertions(+), 112 deletions(-)
 create mode 100644 extras/mini-os/ARM-TODO.txt
 create mode 100755 extras/mini-os/arch/arm/Makefile
 create mode 100644 extras/mini-os/arch/arm/arch.mk
 create mode 100644 extras/mini-os/arch/arm/arm32.S
 create mode 100644 extras/mini-os/arch/arm/events.c
 create mode 100644 extras/mini-os/arch/arm/hypercalls32.S
 create mode 100755 extras/mini-os/arch/arm/minios-arm32.lds
 create mode 100644 extras/mini-os/arch/arm/mm.c
 create mode 100644 extras/mini-os/arch/arm/panic.c
 create mode 100644 extras/mini-os/arch/arm/sched.c
 create mode 100644 extras/mini-os/arch/arm/setup.c
 create mode 100644 extras/mini-os/arch/arm/time.c
 create mode 100644 extras/mini-os/drivers/gic.c
 create mode 100644 extras/mini-os/include/arm/arch_endian.h
 create mode 100644 extras/mini-os/include/arm/arch_limits.h
 create mode 100644 extras/mini-os/include/arm/arch_mm.h
 create mode 100644 extras/mini-os/include/arm/arch_sched.h
 create mode 100755 extras/mini-os/include/arm/arch_spinlock.h
 create mode 100644 extras/mini-os/include/arm/arm32/arch_wordsize.h
 create mode 100644 extras/mini-os/include/arm/hypercall-arm32.h
 create mode 100644 extras/mini-os/include/arm/os.h
 create mode 100644 extras/mini-os/include/arm/traps.h
 create mode 100644 extras/mini-os/include/fdt.h
 create mode 100644 extras/mini-os/include/gic.h
 create mode 100644 extras/mini-os/include/libfdt.h
 create mode 100644 extras/mini-os/include/libfdt_env.h
 create mode 100644 extras/mini-os/lib/fdt/fdt.c
 create mode 100644 extras/mini-os/lib/fdt/fdt_empty_tree.c
 create mode 100644 extras/mini-os/lib/fdt/fdt_ro.c
 create mode 100644 extras/mini-os/lib/fdt/fdt_rw.c
 create mode 100644 extras/mini-os/lib/fdt/fdt_strerror.c
 create mode 100644 extras/mini-os/lib/fdt/fdt_sw.c
 create mode 100644 extras/mini-os/lib/fdt/fdt_wip.c
 create mode 100644 extras/mini-os/lib/fdt/libfdt_internal.h
 create mode 100644 extras/mini-os/lib/memmove.c

-- 
2.0.0

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH ARM v4 01/12] mini-os: build fixes
  2014-06-18 15:08 [PATCH ARM v4 00/12] mini-os: initial ARM support Thomas Leonard
@ 2014-06-18 15:08 ` Thomas Leonard
  2014-06-18 16:26   ` Ian Campbell
  2014-06-18 17:41   ` Samuel Thibault
  2014-06-18 15:08 ` [PATCH ARM v4 02/12] mini-os: fixed shutdown thread Thomas Leonard
                   ` (10 subsequent siblings)
  11 siblings, 2 replies; 41+ messages in thread
From: Thomas Leonard @ 2014-06-18 15:08 UTC (permalink / raw)
  To: xen-devel
  Cc: Thomas Leonard, Dave.Scott, anil, stefano.stabellini, samuel.thibault

Make .o rules depend on the includes. Before, only the final link step
depended on setting up the includes directory, making parallel builds
unreliable.

Make symlinks use explicit make rules instead of using a phony target.
Avoids unnecessary rebuilds.

[talex5@gmail.com: bring back "make links", for stubdom]
Signed-off-by: Thomas Leonard <talex5@gmail.com>
---
 extras/mini-os/Makefile | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/extras/mini-os/Makefile b/extras/mini-os/Makefile
index 50d038b..6d6537e 100644
--- a/extras/mini-os/Makefile
+++ b/extras/mini-os/Makefile
@@ -50,6 +50,11 @@ flags-$(CONFIG_XENBUS) += -DCONFIG_XENBUS
 
 DEF_CFLAGS += $(flags-y)
 
+# Symlinks and headers that must be created before building the C files
+GENERATED_HEADERS := include/list.h $(ARCH_LINKS) include/mini-os include/xen include/$(TARGET_ARCH_FAM)/mini-os
+
+EXTRA_DEPS += $(GENERATED_HEADERS)
+
 # Include common mini-os makerules.
 include minios.mk
 
@@ -124,11 +129,18 @@ include/list.h: $(XEN_ROOT)/tools/include/xen-external/bsd-sys-queue-h-seddery $
 	perl $^ --prefix=minios  >$@.new
 	$(call move-if-changed,$@.new,$@)
 
+# Used by stubdom's Makefile
 .PHONY: links
-links: include/list.h $(ARCH_LINKS)
-	[ -e include/xen ] || ln -sf ../../../xen/include/public include/xen
-	[ -e include/mini-os ] || ln -sf . include/mini-os
-	[ -e include/$(TARGET_ARCH_FAM)/mini-os ] || ln -sf . include/$(TARGET_ARCH_FAM)/mini-os
+links: $(GENERATED_HEADERS)
+
+include/xen:
+	ln -sf ../../../xen/include/public $@
+
+include/mini-os:
+	ln -sf . $@
+
+include/$(TARGET_ARCH_FAM)/mini-os:
+	ln -sf . $@
 
 .PHONY: arch_lib
 arch_lib:
@@ -174,7 +186,7 @@ ifneq ($(APP_OBJS),)
 APP_O=$(OBJ_DIR)/$(TARGET)_app.o 
 endif
 
-$(OBJ_DIR)/$(TARGET): links include/list.h $(OBJS) $(APP_O) arch_lib
+$(OBJ_DIR)/$(TARGET): $(OBJS) $(APP_O) arch_lib
 	$(LD) -r $(LDFLAGS) $(HEAD_OBJ) $(APP_O) $(OBJS) $(LDARCHLIB) $(LDLIBS) -o $@.o
 	$(OBJCOPY) -w -G $(GLOBAL_PREFIX)* -G _start $@.o $@.o
 	$(LD) $(LDFLAGS) $(LDFLAGS_FINAL) $@.o $(EXTRA_OBJS) -o $@
@@ -212,4 +224,3 @@ tags:
 .PHONY: TAGS
 TAGS:
 	$(all_sources) | xargs etags
-
-- 
2.0.0

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH ARM v4 02/12] mini-os: fixed shutdown thread
  2014-06-18 15:08 [PATCH ARM v4 00/12] mini-os: initial ARM support Thomas Leonard
  2014-06-18 15:08 ` [PATCH ARM v4 01/12] mini-os: build fixes Thomas Leonard
@ 2014-06-18 15:08 ` Thomas Leonard
  2014-06-18 15:08 ` [PATCH ARM v4 03/12] mini-os: fixed format string error in unbind_evtchn Thomas Leonard
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 41+ messages in thread
From: Thomas Leonard @ 2014-06-18 15:08 UTC (permalink / raw)
  To: xen-devel
  Cc: Thomas Leonard, Dave.Scott, anil, stefano.stabellini, samuel.thibault

Before, it read "" and started a shutdown immediately. Now, it waits for
a non-empty value and then actually shuts down.

Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
[talex5@gmail.com: avoid declaration-after-statement in kernel.c]
Signed-off-by: Thomas Leonard <talex5@gmail.com>
---
 extras/mini-os/kernel.c | 10 +++++++---
 extras/mini-os/main.c   |  2 +-
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/extras/mini-os/kernel.c b/extras/mini-os/kernel.c
index ea409f4..c7410db 100644
--- a/extras/mini-os/kernel.c
+++ b/extras/mini-os/kernel.c
@@ -68,7 +68,9 @@ void setup_xen_features(void)
 /* This should be overridden by the application we are linked against. */
 __attribute__((weak)) void app_shutdown(unsigned reason)
 {
+    struct sched_shutdown sched_shutdown = { .reason = reason };
     printk("Shutdown requested: %d\n", reason);
+    HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown);
 }
 
 static void shutdown_thread(void *p)
@@ -76,12 +78,14 @@ static void shutdown_thread(void *p)
     const char *path = "control/shutdown";
     const char *token = path;
     xenbus_event_queue events = NULL;
-    char *shutdown, *err;
+    char *shutdown = NULL, *err;
     unsigned int shutdown_reason;
     xenbus_watch_path_token(XBT_NIL, path, token, &events);
-    while ((err = xenbus_read(XBT_NIL, path, &shutdown)) != NULL)
+    while ((err = xenbus_read(XBT_NIL, path, &shutdown)) != NULL || !strcmp(shutdown, ""))
     {
         free(err);
+        free(shutdown);
+        shutdown = NULL;
         xenbus_wait_for_watch(&events);
     }
     err = xenbus_unwatch_path_token(XBT_NIL, path, token);
@@ -106,7 +110,7 @@ static void shutdown_thread(void *p)
 /* This should be overridden by the application we are linked against. */
 __attribute__((weak)) int app_main(start_info_t *si)
 {
-    printk("Dummy main: start_info=%p\n", si);
+    printk("kernel.c: dummy main: start_info=%p\n", si);
     return 0;
 }
 
diff --git a/extras/mini-os/main.c b/extras/mini-os/main.c
index 73eb6fb..aec0586 100644
--- a/extras/mini-os/main.c
+++ b/extras/mini-os/main.c
@@ -185,7 +185,7 @@ void _exit(int ret)
 
 int app_main(start_info_t *si)
 {
-    printk("Dummy main: start_info=%p\n", si);
+    printk("main.c: dummy main: start_info=%p\n", si);
     main_thread = create_thread("main", call_main, si);
     return 0;
 }
-- 
2.0.0

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH ARM v4 03/12] mini-os: fixed format string error in unbind_evtchn
  2014-06-18 15:08 [PATCH ARM v4 00/12] mini-os: initial ARM support Thomas Leonard
  2014-06-18 15:08 ` [PATCH ARM v4 01/12] mini-os: build fixes Thomas Leonard
  2014-06-18 15:08 ` [PATCH ARM v4 02/12] mini-os: fixed shutdown thread Thomas Leonard
@ 2014-06-18 15:08 ` Thomas Leonard
  2014-06-18 16:28   ` Ian Campbell
  2014-06-18 17:42   ` Samuel Thibault
  2014-06-18 15:08 ` [PATCH ARM v4 04/12] mini-os: use unbind_evtchn in unbind_all_ports Thomas Leonard
                   ` (8 subsequent siblings)
  11 siblings, 2 replies; 41+ messages in thread
From: Thomas Leonard @ 2014-06-18 15:08 UTC (permalink / raw)
  To: xen-devel
  Cc: Thomas Leonard, Dave.Scott, anil, stefano.stabellini, samuel.thibault

Would crash if HYPERVISOR_event_channel_op returned an error code.
The other changes in this commit are just fixing indentation.

Signed-off-by: Thomas Leonard <talex5@gmail.com>
---
 extras/mini-os/events.c | 25 ++++++++++++-------------
 1 file changed, 12 insertions(+), 13 deletions(-)

diff --git a/extras/mini-os/events.c b/extras/mini-os/events.c
index d60630b..f708cb4 100644
--- a/extras/mini-os/events.c
+++ b/extras/mini-os/events.c
@@ -109,24 +109,23 @@ evtchn_port_t bind_evtchn(evtchn_port_t port, evtchn_handler_t handler,
 
 void unbind_evtchn(evtchn_port_t port )
 {
-	struct evtchn_close close;
+    struct evtchn_close close;
     int rc;
 
-	if ( ev_actions[port].handler == default_handler )
-		printk("WARN: No handler for port %d when unbinding\n", port);
-	mask_evtchn(port);
-	clear_evtchn(port);
+    if ( ev_actions[port].handler == default_handler )
+        printk("WARN: No handler for port %d when unbinding\n", port);
+    mask_evtchn(port);
+    clear_evtchn(port);
 
-	ev_actions[port].handler = default_handler;
-	wmb();
-	ev_actions[port].data = NULL;
-	clear_bit(port, bound_ports);
+    ev_actions[port].handler = default_handler;
+    wmb();
+    ev_actions[port].data = NULL;
+    clear_bit(port, bound_ports);
 
-	close.port = port;
-	rc = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
+    close.port = port;
+    rc = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
     if ( rc )
-        printk("WARN: close_port %s failed rc=%d. ignored\n", port, rc);
-        
+        printk("WARN: close_port %d failed rc=%d. ignored\n", port, rc);
 }
 
 evtchn_port_t bind_virq(uint32_t virq, evtchn_handler_t handler, void *data)
-- 
2.0.0

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH ARM v4 04/12] mini-os: use unbind_evtchn in unbind_all_ports
  2014-06-18 15:08 [PATCH ARM v4 00/12] mini-os: initial ARM support Thomas Leonard
                   ` (2 preceding siblings ...)
  2014-06-18 15:08 ` [PATCH ARM v4 03/12] mini-os: fixed format string error in unbind_evtchn Thomas Leonard
@ 2014-06-18 15:08 ` Thomas Leonard
  2014-06-18 16:30   ` Ian Campbell
  2014-06-18 17:44   ` Samuel Thibault
  2014-06-18 15:08 ` [PATCH ARM v4 05/12] mini-os: made off_t type signed Thomas Leonard
                   ` (7 subsequent siblings)
  11 siblings, 2 replies; 41+ messages in thread
From: Thomas Leonard @ 2014-06-18 15:08 UTC (permalink / raw)
  To: xen-devel
  Cc: Thomas Leonard, Dave.Scott, anil, stefano.stabellini, samuel.thibault

This marks the channel as closed, in case someone tries to use it again.

Signed-off-by: Thomas Leonard <talex5@gmail.com>
---
 extras/mini-os/events.c | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/extras/mini-os/events.c b/extras/mini-os/events.c
index f708cb4..3c92d82 100644
--- a/extras/mini-os/events.c
+++ b/extras/mini-os/events.c
@@ -43,7 +43,6 @@ void unbind_all_ports(void)
     int cpu = 0;
     shared_info_t *s = HYPERVISOR_shared_info;
     vcpu_info_t   *vcpu_info = &s->vcpu_info[cpu];
-    int rc;
 
     for ( i = 0; i < NR_EVS; i++ )
     {
@@ -53,14 +52,8 @@ void unbind_all_ports(void)
 
         if ( test_and_clear_bit(i, bound_ports) )
         {
-            struct evtchn_close close;
             printk("port %d still bound!\n", i);
-            mask_evtchn(i);
-            close.port = i;
-            rc = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
-            if ( rc )
-                printk("WARN: close_port %s failed rc=%d. ignored\n", i, rc);
-            clear_evtchn(i);
+	    unbind_evtchn(i);
         }
     }
     vcpu_info->evtchn_upcall_pending = 0;
-- 
2.0.0

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH ARM v4 05/12] mini-os: made off_t type signed
  2014-06-18 15:08 [PATCH ARM v4 00/12] mini-os: initial ARM support Thomas Leonard
                   ` (3 preceding siblings ...)
  2014-06-18 15:08 ` [PATCH ARM v4 04/12] mini-os: use unbind_evtchn in unbind_all_ports Thomas Leonard
@ 2014-06-18 15:08 ` Thomas Leonard
  2014-06-18 16:31   ` Ian Campbell
  2014-06-18 17:44   ` Samuel Thibault
  2014-06-18 15:08 ` [PATCH ARM v4 06/12] mini-os: switched initial C entry point to arch_init Thomas Leonard
                   ` (6 subsequent siblings)
  11 siblings, 2 replies; 41+ messages in thread
From: Thomas Leonard @ 2014-06-18 15:08 UTC (permalink / raw)
  To: xen-devel
  Cc: Thomas Leonard, Dave.Scott, anil, stefano.stabellini, samuel.thibault

POSIX requires this.

Signed-off-by: Thomas Leonard <talex5@gmail.com>
---
 extras/mini-os/include/types.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/extras/mini-os/include/types.h b/extras/mini-os/include/types.h
index 6640ede..de356e8 100644
--- a/extras/mini-os/include/types.h
+++ b/extras/mini-os/include/types.h
@@ -73,7 +73,7 @@ typedef unsigned long uint64_t;
 #endif
 typedef uint64_t uintmax_t;
 typedef  int64_t intmax_t;
-typedef uint64_t off_t;
+typedef  int64_t off_t;
 #endif
 
 typedef intptr_t            ptrdiff_t;
-- 
2.0.0

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH ARM v4 06/12] mini-os: switched initial C entry point to arch_init
  2014-06-18 15:08 [PATCH ARM v4 00/12] mini-os: initial ARM support Thomas Leonard
                   ` (4 preceding siblings ...)
  2014-06-18 15:08 ` [PATCH ARM v4 05/12] mini-os: made off_t type signed Thomas Leonard
@ 2014-06-18 15:08 ` Thomas Leonard
  2014-06-18 15:08 ` [PATCH ARM v4 07/12] mini-os: initial ARM support Thomas Leonard
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 41+ messages in thread
From: Thomas Leonard @ 2014-06-18 15:08 UTC (permalink / raw)
  To: xen-devel
  Cc: Thomas Leonard, Dave.Scott, anil, stefano.stabellini, samuel.thibault

From: Karim Raslan <karim.allah.ahmed@gmail.com>

Signed-off-by: Karim Allah Ahmed <karim.allah.ahmed@gmail.com>
[talex5@gmail.com: separated from big ARM commit]
[talex5@gmail.com: restored comment, moved prototypes to headers]
Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
[talex5@gmail.com: restored stack address printk on x86]
[talex5@gmail.com: moved first printk's after start_info setup on x86]
Signed-off-by: Thomas Leonard <talex5@gmail.com>
---
 extras/mini-os/arch/x86/setup.c  | 44 ++++++++++++++++++++++++++++++++--------
 extras/mini-os/arch/x86/x86_32.S |  2 +-
 extras/mini-os/arch/x86/x86_64.S |  2 +-
 extras/mini-os/include/kernel.h  |  6 ++++--
 extras/mini-os/include/x86/os.h  |  2 --
 extras/mini-os/kernel.c          | 37 ++++-----------------------------
 6 files changed, 46 insertions(+), 47 deletions(-)

diff --git a/extras/mini-os/arch/x86/setup.c b/extras/mini-os/arch/x86/setup.c
index 54046d3..5e87dd1 100644
--- a/extras/mini-os/arch/x86/setup.c
+++ b/extras/mini-os/arch/x86/setup.c
@@ -28,6 +28,8 @@
 
 #include <mini-os/os.h>
 #include <mini-os/lib.h> /* for printk, memcpy */
+#include <mini-os/kernel.h>
+#include <xen/xen.h>
 
 /*
  * Shared page for communicating with the hypervisor.
@@ -87,20 +89,45 @@ static inline void sse_init(void) {
 #define sse_init()
 #endif
 
+
+/*
+ * INITIAL C ENTRY POINT.
+ */
 void
 arch_init(start_info_t *si)
 {
+	static char hello[] = "Bootstrapping...\n";
+
+	(void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(hello), hello);
+
+	trap_init();
+
 	/*Initialize floating point unit */
-        fpu_init();
+	fpu_init();
 
-        /* Initialize SSE */
-        sse_init();
+	/* Initialize SSE */
+	sse_init();
 
 	/* Copy the start_info struct to a globally-accessible area. */
 	/* WARN: don't do printk before here, it uses information from
 	   shared_info. Use xprintk instead. */
 	memcpy(&start_info, si, sizeof(*si));
 
+	/* print out some useful information  */
+	printk("Xen Minimal OS!\n");
+	printk("  start_info: %p(VA)\n", si);
+	printk("    nr_pages: 0x%lx\n", si->nr_pages);
+	printk("  shared_inf: 0x%08lx(MA)\n", si->shared_info);
+	printk("     pt_base: %p(VA)\n", (void *)si->pt_base);
+	printk("nr_pt_frames: 0x%lx\n", si->nr_pt_frames);
+	printk("    mfn_list: %p(VA)\n", (void *)si->mfn_list);
+	printk("   mod_start: 0x%lx(VA)\n", si->mod_start);
+	printk("     mod_len: %lu\n", si->mod_len);
+	printk("       flags: 0x%x\n", (unsigned int)si->flags);
+	printk("    cmd_line: %s\n",
+			si->cmd_line ? (const char *)si->cmd_line : "NULL");
+	printk("       stack: %p-%p\n", stack, stack + sizeof(stack));
+
 	/* set up minimal memory infos */
 	phys_to_machine_mapping = (unsigned long *)start_info.mfn_list;
 
@@ -118,12 +145,15 @@ arch_init(start_info_t *si)
 		(unsigned long)failsafe_callback, 0);
 #endif
 
-
+	start_kernel();
 }
 
 void
 arch_fini(void)
 {
+	/* Reset traps */
+	trap_fini();
+
 #ifdef __i386__
 	HYPERVISOR_set_callbacks(0, 0, 0, 0);
 #else
@@ -132,9 +162,7 @@ arch_fini(void)
 }
 
 void
-arch_print_info(void)
+arch_do_exit(void)
 {
-	printk("  stack:      %p-%p\n", stack, stack + sizeof(stack));
+	stack_walk();
 }
-
-
diff --git a/extras/mini-os/arch/x86/x86_32.S b/extras/mini-os/arch/x86/x86_32.S
index fb3e30a..b9aa392 100644
--- a/extras/mini-os/arch/x86/x86_32.S
+++ b/extras/mini-os/arch/x86/x86_32.S
@@ -20,7 +20,7 @@ _start:
         lss stack_start,%esp
         andl $(~(__STACK_SIZE-1)), %esp
         push %esi 
-        call start_kernel
+        call arch_init
 
 stack_start:
 	.long stack+(2*__STACK_SIZE), __KERNEL_SS
diff --git a/extras/mini-os/arch/x86/x86_64.S b/extras/mini-os/arch/x86/x86_64.S
index f022eb3..df3469e 100644
--- a/extras/mini-os/arch/x86/x86_64.S
+++ b/extras/mini-os/arch/x86/x86_64.S
@@ -21,7 +21,7 @@ _start:
         movq stack_start(%rip),%rsp
         andq $(~(__STACK_SIZE-1)), %rsp
         movq %rsi,%rdi
-        call start_kernel
+        call arch_init
 
 stack_start:
         .quad stack+(2*__STACK_SIZE)
diff --git a/extras/mini-os/include/kernel.h b/extras/mini-os/include/kernel.h
index b36f172..13e3274 100644
--- a/extras/mini-os/include/kernel.h
+++ b/extras/mini-os/include/kernel.h
@@ -1,7 +1,9 @@
 #ifndef _KERNEL_H_
 #define _KERNEL_H_
 
-extern void do_exit(void) __attribute__((noreturn));
-extern void stop_kernel(void);
+void start_kernel(void);
+void do_exit(void) __attribute__((noreturn));
+void arch_do_exit(void);
+void stop_kernel(void);
 
 #endif /* _KERNEL_H_ */
diff --git a/extras/mini-os/include/x86/os.h b/extras/mini-os/include/x86/os.h
index f193865..73b8297 100644
--- a/extras/mini-os/include/x86/os.h
+++ b/extras/mini-os/include/x86/os.h
@@ -64,8 +64,6 @@ extern shared_info_t *HYPERVISOR_shared_info;
 void trap_init(void);
 void trap_fini(void);
 
-void arch_init(start_info_t *si);
-void arch_print_info(void);
 void arch_fini(void);
 
 
diff --git a/extras/mini-os/kernel.c b/extras/mini-os/kernel.c
index c7410db..9a30550 100644
--- a/extras/mini-os/kernel.c
+++ b/extras/mini-os/kernel.c
@@ -28,6 +28,7 @@
  */
 
 #include <mini-os/os.h>
+#include <mini-os/kernel.h>
 #include <mini-os/hypervisor.h>
 #include <mini-os/mm.h>
 #include <mini-os/events.h>
@@ -114,41 +115,14 @@ __attribute__((weak)) int app_main(start_info_t *si)
     return 0;
 }
 
-/*
- * INITIAL C ENTRY POINT.
- */
-void start_kernel(start_info_t *si)
+void start_kernel(void)
 {
-    static char hello[] = "Bootstrapping...\n";
-
-    (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(hello), hello);
-
-    arch_init(si);
-
-    trap_init();
-
-    /* print out some useful information  */
-    printk("Xen Minimal OS!\n");
-    printk("  start_info: %p(VA)\n", si);
-    printk("    nr_pages: 0x%lx\n", si->nr_pages);
-    printk("  shared_inf: 0x%08lx(MA)\n", si->shared_info);
-    printk("     pt_base: %p(VA)\n", (void *)si->pt_base); 
-    printk("nr_pt_frames: 0x%lx\n", si->nr_pt_frames);
-    printk("    mfn_list: %p(VA)\n", (void *)si->mfn_list); 
-    printk("   mod_start: 0x%lx(VA)\n", si->mod_start);
-    printk("     mod_len: %lu\n", si->mod_len); 
-    printk("       flags: 0x%x\n", (unsigned int)si->flags);
-    printk("    cmd_line: %s\n",  
-           si->cmd_line ? (const char *)si->cmd_line : "NULL");
-
     /* Set up events. */
     init_events();
-    
+
     /* ENABLE EVENT DELIVERY. This is disabled at start of day. */
     __sti();
 
-    arch_print_info();
-
     setup_xen_features();
 
     /* Init memory management. */
@@ -201,9 +175,6 @@ void stop_kernel(void)
     /* Reset events. */
     fini_events();
 
-    /* Reset traps */
-    trap_fini();
-
     /* Reset arch details */
     arch_fini();
 }
@@ -218,7 +189,7 @@ void stop_kernel(void)
 void do_exit(void)
 {
     printk("Do_exit called!\n");
-    stack_walk();
+    arch_do_exit();
     for( ;; )
     {
         struct sched_shutdown sched_shutdown = { .reason = SHUTDOWN_crash };
-- 
2.0.0

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH ARM v4 07/12] mini-os: initial ARM support
  2014-06-18 15:08 [PATCH ARM v4 00/12] mini-os: initial ARM support Thomas Leonard
                   ` (5 preceding siblings ...)
  2014-06-18 15:08 ` [PATCH ARM v4 06/12] mini-os: switched initial C entry point to arch_init Thomas Leonard
@ 2014-06-18 15:08 ` Thomas Leonard
  2014-06-18 17:48   ` Samuel Thibault
  2014-06-18 22:40   ` Julien Grall
  2014-06-18 15:08 ` [PATCH ARM v4 08/12] mini-os: arm: show registers, stack and exception vector on fault Thomas Leonard
                   ` (4 subsequent siblings)
  11 siblings, 2 replies; 41+ messages in thread
From: Thomas Leonard @ 2014-06-18 15:08 UTC (permalink / raw)
  To: xen-devel
  Cc: Thomas Leonard, Dave.Scott, anil, stefano.stabellini, samuel.thibault

From: Karim Raslan <karim.allah.ahmed@gmail.com>

On ARM, Mini-OS will boot and display some output on the console.
Tested with:

make XEN_TARGET_ARCH=arm32 CROSS_COMPILE=arm-linux-gnueabihf- \
	CONFIG_TEST=y CONFIG_START_NETWORK=n CONFIG_BLKFRONT=n \
	CONFIG_NETFRONT=n CONFIG_FBFRONT=n CONFIG_KBDFRONT=n \
	CONFIG_CONSFRONT=n CONFIG_XC=n -j4

Signed-off-by: Karim Allah Ahmed <karim.allah.ahmed@gmail.com>
[talex5@gmail.com: made x86_64 support work again]
[talex5@gmail.com: split into multiple patches]
[talex5@gmail.com: re-enabled force_evtchn_callback]
[talex5@gmail.com: enable regular console]
[talex5@gmail.com: fixed initialisation code:
- Configure write-back caching in page table. This is needed for
  reliable hypercalls to Xen (thanks to Julien Grall).
- Use "client mode" for access control (domains are deprecated,
  according to ARM Cortex-A Series Programmer’s Guide version 4.0,
  section 9.6.4).
- Enable more SCTLR features (icache, branch prediction)]
[talex5@gmail.com: use Virtual Count register for monotonic time]
[talex5@gmail.com: fixed HYPERVISOR_shutdown]
[talex5@gmail.com: get xenstore details from hypervisor]
[talex5@gmail.com: use GCC implementation of division]
[talex5@gmail.com: include hypervisor.h from os.h, as on x86]
[talex5@gmail.com: cleaned up interrupt handlers and threading]
[talex5@gmail.com: call exit_thread when a thread returns]
[talex5@gmail.com: implemented block_domain for ARM]
[talex5@gmail.com: fixed hang when enabling interrupts]
[talex5@gmail.com: added -march=armv7-a to flags]
[talex5@gmail.com: implemented bitops for ARM]
[talex5@gmail.com: CLREX after handling IRQs]
[talex5@gmail.com: unbind debug port at shutdown]
[talex5@gmail.com: allow unaligned accesses]
[talex5@gmail.com: added arch_endian.h for ARM]
[talex5@gmail.com: fix zImage header for XSA-95]
Signed-off-by: Thomas Leonard <talex5@gmail.com>
---
 extras/mini-os/ARM-TODO.txt                      |  12 ++
 extras/mini-os/Config.mk                         |   2 +
 extras/mini-os/Makefile                          |  14 ++
 extras/mini-os/arch/arm/Makefile                 |  32 ++++
 extras/mini-os/arch/arm/arch.mk                  |   7 +
 extras/mini-os/arch/arm/arm32.S                  | 155 +++++++++++++++
 extras/mini-os/arch/arm/events.c                 |  30 +++
 extras/mini-os/arch/arm/hypercalls32.S           |  88 +++++++++
 extras/mini-os/arch/arm/minios-arm32.lds         |  75 ++++++++
 extras/mini-os/arch/arm/mm.c                     |  44 +++++
 extras/mini-os/arch/arm/sched.c                  |  37 ++++
 extras/mini-os/arch/arm/setup.c                  | 102 ++++++++++
 extras/mini-os/arch/arm/time.c                   | 202 ++++++++++++++++++++
 extras/mini-os/arch/x86/events.c                 |   4 +
 extras/mini-os/drivers/gic.c                     | 187 ++++++++++++++++++
 extras/mini-os/events.c                          |   5 +-
 extras/mini-os/hypervisor.c                      |  12 +-
 extras/mini-os/include/arm/arch_endian.h         |   7 +
 extras/mini-os/include/arm/arch_limits.h         |   9 +
 extras/mini-os/include/arm/arch_mm.h             |  37 ++++
 extras/mini-os/include/arm/arch_sched.h          |  22 +++
 extras/mini-os/include/arm/arch_spinlock.h       |  49 +++++
 extras/mini-os/include/arm/arm32/arch_wordsize.h |   1 +
 extras/mini-os/include/arm/hypercall-arm32.h     | 173 +++++++++++++++++
 extras/mini-os/include/arm/os.h                  | 230 +++++++++++++++++++++++
 extras/mini-os/include/arm/traps.h               |  20 ++
 extras/mini-os/include/events.h                  |   4 +
 extras/mini-os/include/gic.h                     |   1 +
 extras/mini-os/include/hypervisor.h              |   4 +
 extras/mini-os/include/mm.h                      |   2 +
 extras/mini-os/include/types.h                   |  12 +-
 extras/mini-os/kernel.c                          |   8 +
 extras/mini-os/sched.c                           |  29 +--
 33 files changed, 1595 insertions(+), 21 deletions(-)
 create mode 100644 extras/mini-os/ARM-TODO.txt
 create mode 100755 extras/mini-os/arch/arm/Makefile
 create mode 100644 extras/mini-os/arch/arm/arch.mk
 create mode 100644 extras/mini-os/arch/arm/arm32.S
 create mode 100644 extras/mini-os/arch/arm/events.c
 create mode 100644 extras/mini-os/arch/arm/hypercalls32.S
 create mode 100755 extras/mini-os/arch/arm/minios-arm32.lds
 create mode 100644 extras/mini-os/arch/arm/mm.c
 create mode 100644 extras/mini-os/arch/arm/sched.c
 create mode 100644 extras/mini-os/arch/arm/setup.c
 create mode 100644 extras/mini-os/arch/arm/time.c
 create mode 100644 extras/mini-os/drivers/gic.c
 create mode 100644 extras/mini-os/include/arm/arch_endian.h
 create mode 100644 extras/mini-os/include/arm/arch_limits.h
 create mode 100644 extras/mini-os/include/arm/arch_mm.h
 create mode 100644 extras/mini-os/include/arm/arch_sched.h
 create mode 100755 extras/mini-os/include/arm/arch_spinlock.h
 create mode 100644 extras/mini-os/include/arm/arm32/arch_wordsize.h
 create mode 100644 extras/mini-os/include/arm/hypercall-arm32.h
 create mode 100644 extras/mini-os/include/arm/os.h
 create mode 100644 extras/mini-os/include/arm/traps.h
 create mode 100644 extras/mini-os/include/gic.h

diff --git a/extras/mini-os/ARM-TODO.txt b/extras/mini-os/ARM-TODO.txt
new file mode 100644
index 0000000..3d9be10
--- /dev/null
+++ b/extras/mini-os/ARM-TODO.txt
@@ -0,0 +1,12 @@
+* support abort exception handling ( and others )
+* scheduling!
+* gic request_irq implementation, currently all IRQs all hardcoded in gic irq handler.
+* use device tree instead of the currently hardcoded values
+* Add virtual memory support and make vstart = 0 ( use 4k descriptors instead of 1M descriptors )
+* sched
+* fini_gnttab
+* bind_*
+* add multiple cpu support (?)
+* map_frames
+* make sure that wallclock is functioning properly
+* evtchn_get_peercontext
diff --git a/extras/mini-os/Config.mk b/extras/mini-os/Config.mk
index d61877b..4ecde54 100644
--- a/extras/mini-os/Config.mk
+++ b/extras/mini-os/Config.mk
@@ -12,6 +12,8 @@ export XEN_INTERFACE_VERSION
 # If not x86 then use $(XEN_TARGET_ARCH)
 ifeq ($(findstring x86_,$(XEN_TARGET_ARCH)),x86_)
 TARGET_ARCH_FAM = x86
+else ifeq ($(findstring arm,$(XEN_TARGET_ARCH)),arm)
+TARGET_ARCH_FAM = arm
 else
 TARGET_ARCH_FAM = $(XEN_TARGET_ARCH)
 endif
diff --git a/extras/mini-os/Makefile b/extras/mini-os/Makefile
index 6d6537e..535ca68 100644
--- a/extras/mini-os/Makefile
+++ b/extras/mini-os/Makefile
@@ -77,6 +77,14 @@ TARGET := mini-os
 # Subdirectories common to mini-os
 SUBDIRS := lib xenbus console
 
+ifeq ($(XEN_TARGET_ARCH),arm32)
+# ARM drivers
+src-y += drivers/gic.c
+
+# Need libgcc.a for division helpers
+LDLIBS += `$(CC) -print-libgcc-file-name`
+endif
+
 src-$(CONFIG_BLKFRONT) += blkfront.c
 src-$(CONFIG_TPMFRONT) += tpmfront.c
 src-$(CONFIG_TPM_TIS) += tpm_tis.c
@@ -97,7 +105,9 @@ src-y += sched.c
 src-$(CONFIG_TEST) += test.c
 
 src-y += lib/ctype.c
+ifneq ($(XEN_TARGET_ARCH),arm32)
 src-y += lib/math.c
+endif
 src-y += lib/printf.c
 src-y += lib/stack_chk_fail.c
 src-y += lib/string.c
@@ -190,7 +200,11 @@ $(OBJ_DIR)/$(TARGET): $(OBJS) $(APP_O) arch_lib
 	$(LD) -r $(LDFLAGS) $(HEAD_OBJ) $(APP_O) $(OBJS) $(LDARCHLIB) $(LDLIBS) -o $@.o
 	$(OBJCOPY) -w -G $(GLOBAL_PREFIX)* -G _start $@.o $@.o
 	$(LD) $(LDFLAGS) $(LDFLAGS_FINAL) $@.o $(EXTRA_OBJS) -o $@
+ifeq ($(XEN_TARGET_ARCH),arm32)
+	$(OBJCOPY) -O binary $@ $@.img
+else
 	gzip -f -9 -c $@ >$@.gz
+endif
 
 .PHONY: clean arch_clean
 
diff --git a/extras/mini-os/arch/arm/Makefile b/extras/mini-os/arch/arm/Makefile
new file mode 100755
index 0000000..8b78651
--- /dev/null
+++ b/extras/mini-os/arch/arm/Makefile
@@ -0,0 +1,32 @@
+#
+# ARM architecture specific makefiles.
+#
+
+XEN_ROOT = $(CURDIR)/../../../..
+include $(XEN_ROOT)/Config.mk
+include ../../Config.mk
+
+# include arch.mk has to be before minios.mk!
+
+include arch.mk
+include ../../minios.mk
+
+# Sources here are all *.c (without $(XEN_TARGET_ARCH).S)
+# This is handled in $(HEAD_ARCH_OBJ)
+ARCH_SRCS := $(wildcard *.c)
+
+# The objects built from the sources.
+ARCH_OBJS := $(patsubst %.c,$(OBJ_DIR)/%.o,$(ARCH_SRCS))
+
+ARCH_OBJS += hypercalls32.o
+
+all: $(OBJ_DIR)/$(ARCH_LIB)
+
+# $(HEAD_ARCH_OBJ) is only built here, needed on linking
+# in ../../Makefile.
+$(OBJ_DIR)/$(ARCH_LIB): $(ARCH_OBJS) $(OBJ_DIR)/$(HEAD_ARCH_OBJ)
+	$(AR) rv $(OBJ_DIR)/$(ARCH_LIB) $(ARCH_OBJS)
+
+clean:
+	rm -f $(OBJ_DIR)/$(ARCH_LIB) $(ARCH_OBJS) $(OBJ_DIR)/$(HEAD_ARCH_OBJ)
+
diff --git a/extras/mini-os/arch/arm/arch.mk b/extras/mini-os/arch/arm/arch.mk
new file mode 100644
index 0000000..ab20d99
--- /dev/null
+++ b/extras/mini-os/arch/arm/arch.mk
@@ -0,0 +1,7 @@
+ifeq ($(XEN_TARGET_ARCH),arm32)
+DEF_ASFLAGS += -march=armv7-a
+ARCH_CFLAGS  := -march=armv7-a -marm -fms-extensions -D__arm__ -DXEN_HAVE_PV_GUEST_ENTRY #-DCPU_EXCLUSIVE_LDST
+EXTRA_INC += $(TARGET_ARCH_FAM)/$(XEN_TARGET_ARCH)
+EXTRA_SRC += arch/$(EXTRA_INC)
+endif
+
diff --git a/extras/mini-os/arch/arm/arm32.S b/extras/mini-os/arch/arm/arm32.S
new file mode 100644
index 0000000..4f953ec
--- /dev/null
+++ b/extras/mini-os/arch/arm/arm32.S
@@ -0,0 +1,155 @@
+#define PHYS_START (0x80008000)
+
+.section .text
+
+.globl _start
+_start:
+	@ zImage header
+.rept   8
+        mov     r0, r0
+.endr
+        b       reset
+        .word   0x016f2818      @ Magic numbers to help the loader
+        .word   0		@ zImage start address
+        .word   _edata - _start @ zImage end address (excludes bss section)
+	@ end of zImage header
+
+@ Called at boot time. Sets up MMU, exception vectors and stack, and then calls C setup() function.
+@ => r2 -> DTB
+@ <= never returns
+reset:
+	@ Fill in the top-level translation table (at page_dir).
+	@ Populate the whole pagedir with 1MB section descriptors.
+	@ TEX[2:0] C B = 001 1 1 (outer and inner write-back, write-allocate)
+	ldr	r0, =(0x2 +  		/* Section entry */ \
+		      0xc +  		/* C B */ \
+		      (3 << 10) + 	/* Read/write */ \
+		      (1 << 12) +	/* TEX */ \
+		      (1 << 16) +	/* Sharable */ \
+		      (1<<19))		/* Non-secure */
+	ldr	r1, =page_dir
+	add	r3, r1, #4*4*1024	@ Limit (4 GB address space, 4 byte entries)
+
+1:
+	str	r0, [r1],#4		@ write the section entry
+	add	r0, r0, #1 << 20 	@ next physical page
+	cmp	r1, r3
+	bne	1b
+
+	@ Tell the system where our new table is located.
+	ldr	r3, =page_dir
+	mcr	p15, 0, r3, c2, c0, 0	@ set ttbr0
+
+	@ Set access permission for domains
+	@ Domains are deprecated, but we have to configure them anyway.
+	@ We mark every page as being domain 0 and set domain 0 to "client mode"
+	@ (client mode = use access flags in page table).
+	mov	r0, #1			@ 1 = client
+	mcr	p15, 0, r0, c3, c0, 0	@ DACR
+
+	@ Invalidate TLB
+	mcr	p15, 0, r1, c8, c7, 0	@ TLBIALL
+
+	@ Enable MMU / SCTLR
+	mrc	p15, 0, r1, c1, c0, 0	@ SCTLR
+	orr	r1, r1, #0x5		@ (dcache, MMU)
+	orr	r1, r1, #3 << 11	@ (icache, branch prediction)
+	mcr	p15, 0, r1, c1, c0, 0	@ SCTLR
+	isb
+
+	@ Set VBAR -> exception_vector_table
+	@ SCTLR.V = 0
+	adr	r0, exception_vector_table
+	mcr	p15, 0, r0, c12, c0, 0
+
+	@ Initialise 16 KB stack
+	ldr	sp, =stack_end
+
+	mov	r0, r2			@ C wants the DTB pointer in r0
+	b	arch_init
+
+.pushsection .data
+.align	14
+page_dir:
+	.fill (4*1024), 4, 0x0
+
+.align 12
+.globl shared_info_page
+shared_info_page:
+	.fill (1024), 4, 0x0
+
+.align 3
+.globl stack
+stack:
+	.fill (4*1024), 4, 0x0
+stack_end:
+
+.align 3
+irqstack:
+	.fill (1024), 4, 0x0
+irqstack_end:
+.popsection
+
+@ exception base address
+.align 5
+.globl exception_vector_table
+@ Note: remember to call CLREX if returning from an exception:
+@ "The architecture enables the local monitor to treat any exclusive store as
+@  matching a previous LDREX address. For this reason, use of the CLREX
+@  instruction to clear an existing tag is required on context switches."
+@ -- ARM Cortex-A Series Programmer’s Guide (Version: 4.0)
+exception_vector_table:
+	b	. @ reset
+	b	. @ undefined instruction
+	b	. @ supervisor call
+	b	. @ prefetch call
+	b	. @ prefetch abort
+	b	. @ data abort
+	b	irq_handler @ irq
+	.word 0xe7f000f0    @ abort on FIQ
+
+irq_handler:
+	ldr	sp, =irqstack_end
+	push	{r0 - r12, r14}
+
+	ldr	r0, IRQ_handler
+	cmp	r0, #0
+	.word	0x07f000f0    @ undeq - panic if no handler
+	blx	r0
+
+	@ Return from IRQ
+	pop	{r0 - r12, r14}
+	clrex
+	subs	pc, lr, #4
+
+.globl IRQ_handler
+IRQ_handler:
+	.long	0x0
+
+
+.globl __arch_switch_threads
+@ => r0 = prev->sp
+@    r1 = next->sp
+@ <= returns to next thread's saved return address
+__arch_switch_threads:
+	stmia	r0, {sp, lr}	@ Store current sp and ip to prev's struct thread
+	str	fp, [sp, #-4]	@ Store fp on the old stack
+
+	ldmia	r1, {sp, lr}	@ Load new sp, ip from next's struct thread
+	ldr	fp, [sp, #-4]	@ Restore fp from the stack
+
+	mov	pc, lr
+
+@ This is called if you try to divide by zero. For now, we make a supervisor call,
+@ which will make us halt.
+.globl raise
+raise:
+	svc	0
+
+.globl arm_start_thread
+arm_start_thread:
+	pop	{r0, r1}
+	@ r0 = user data
+	@ r1 -> thread's main function
+	ldr	lr, =exit_thread
+	bx	r1
diff --git a/extras/mini-os/arch/arm/events.c b/extras/mini-os/arch/arm/events.c
new file mode 100644
index 0000000..517e763
--- /dev/null
+++ b/extras/mini-os/arch/arm/events.c
@@ -0,0 +1,30 @@
+#include <mini-os/os.h>
+#include <mini-os/events.h>
+#include <mini-os/hypervisor.h>
+
+static void virq_debug(evtchn_port_t port, struct pt_regs *regs, void *params)
+{
+    printk("Received a virq_debug event\n");
+}
+
+evtchn_port_t debug_port = -1;
+void arch_init_events(void)
+{
+    debug_port = bind_virq(VIRQ_DEBUG, (evtchn_handler_t)virq_debug, 0);
+    if(debug_port == -1)
+        BUG();
+    unmask_evtchn(debug_port);
+}
+
+void arch_unbind_ports(void)
+{
+    if(debug_port != -1)
+    {
+        mask_evtchn(debug_port);
+        unbind_evtchn(debug_port);
+    }
+}
+
+void arch_fini_events(void)
+{
+}
diff --git a/extras/mini-os/arch/arm/hypercalls32.S b/extras/mini-os/arch/arm/hypercalls32.S
new file mode 100644
index 0000000..e2f21c4
--- /dev/null
+++ b/extras/mini-os/arch/arm/hypercalls32.S
@@ -0,0 +1,88 @@
+#define __HYPERVISOR_set_trap_table        0
+#define __HYPERVISOR_mmu_update            1
+#define __HYPERVISOR_set_gdt               2
+#define __HYPERVISOR_stack_switch          3
+#define __HYPERVISOR_set_callbacks         4
+#define __HYPERVISOR_fpu_taskswitch        5
+#define __HYPERVISOR_sched_op_compat       6 /* compat since 0x00030101 */
+#define __HYPERVISOR_platform_op           7
+#define __HYPERVISOR_set_debugreg          8
+#define __HYPERVISOR_get_debugreg          9
+#define __HYPERVISOR_update_descriptor    10
+#define __HYPERVISOR_memory_op            12
+#define __HYPERVISOR_multicall            13
+#define __HYPERVISOR_update_va_mapping    14
+#define __HYPERVISOR_set_timer_op         15
+#define __HYPERVISOR_event_channel_op_compat 16 /* compat since 0x00030202 */
+#define __HYPERVISOR_xen_version          17
+#define __HYPERVISOR_console_io           18
+#define __HYPERVISOR_physdev_op_compat    19 /* compat since 0x00030202 */
+#define __HYPERVISOR_grant_table_op       20
+#define __HYPERVISOR_vm_assist            21
+#define __HYPERVISOR_update_va_mapping_otherdomain 22
+#define __HYPERVISOR_iret                 23 /* x86 only */
+#define __HYPERVISOR_vcpu_op              24
+#define __HYPERVISOR_set_segment_base     25 /* x86/64 only */
+#define __HYPERVISOR_mmuext_op            26
+#define __HYPERVISOR_xsm_op               27
+#define __HYPERVISOR_nmi_op               28
+#define __HYPERVISOR_sched_op             29
+#define __HYPERVISOR_callback_op          30
+#define __HYPERVISOR_xenoprof_op          31
+#define __HYPERVISOR_event_channel_op     32
+#define __HYPERVISOR_physdev_op           33
+#define __HYPERVISOR_hvm_op               34
+#define __HYPERVISOR_sysctl               35
+#define __HYPERVISOR_domctl               36
+#define __HYPERVISOR_kexec_op             37
+#define __HYPERVISOR_tmem_op              38
+#define __HYPERVISOR_xc_reserved_op       39 /* reserved for XenClient */
+
+
+
+#define __HVC(imm16) .long ((0xE1400070 | (((imm16) & 0xFFF0) << 4) | ((imm16) & 0x000F)) & 0xFFFFFFFF)
+
+#define XEN_IMM 0xEA1
+
+#define HYPERCALL_SIMPLE(hypercall)		\
+.globl HYPERVISOR_##hypercall;			\
+.align 4,0x90;					\
+HYPERVISOR_##hypercall:				\
+        mov r12, #__HYPERVISOR_##hypercall;	\
+        __HVC(XEN_IMM);				\
+        mov pc, lr;
+
+#define _hypercall0 HYPERCALL_SIMPLE
+#define _hypercall1 HYPERCALL_SIMPLE
+#define _hypercall2 HYPERCALL_SIMPLE
+#define _hypercall3 HYPERCALL_SIMPLE
+#define _hypercall4 HYPERCALL_SIMPLE
+
+_hypercall1(set_trap_table);
+_hypercall4(mmu_update);
+_hypercall4(mmuext_op);
+_hypercall2(set_gdt);
+_hypercall2(stack_switch);
+_hypercall3(set_callbacks);
+_hypercall1(fpu_taskswitch);
+_hypercall2(sched_op);
+_hypercall1(set_timer_op);
+_hypercall2(set_debugreg);
+_hypercall1(get_debugreg);
+_hypercall2(update_descriptor);
+_hypercall2(memory_op);
+_hypercall2(multicall);
+_hypercall3(update_va_mapping);
+_hypercall2(event_channel_op);
+_hypercall2(xen_version);
+_hypercall3(console_io);
+_hypercall1(physdev_op);
+_hypercall3(grant_table_op);
+_hypercall4(update_va_mapping_otherdomain);
+_hypercall2(vm_assist);
+_hypercall3(vcpu_op);
+_hypercall2(set_segment_base);
+_hypercall2(nmi_op);
+_hypercall1(sysctl);
+_hypercall1(domctl);
+_hypercall2(hvm_op);
diff --git a/extras/mini-os/arch/arm/minios-arm32.lds b/extras/mini-os/arch/arm/minios-arm32.lds
new file mode 100755
index 0000000..0d58395
--- /dev/null
+++ b/extras/mini-os/arch/arm/minios-arm32.lds
@@ -0,0 +1,75 @@
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+  . = 0x80008000;
+  _text = .;			/* Text and read-only data */
+  .text : {
+	*(.text)
+	*(.gnu.warning)
+	} = 0x9090
+
+  _etext = .;			/* End of text section */
+
+  .rodata : { *(.rodata) *(.rodata.*) }
+  . = ALIGN(4096);
+  _erodata = .;
+
+  /* newlib initialization functions */
+  . = ALIGN(32 / 8);
+  PROVIDE (__preinit_array_start = .);
+  .preinit_array     : { *(.preinit_array) }
+  PROVIDE (__preinit_array_end = .);
+  PROVIDE (__init_array_start = .);
+  .init_array     : { *(.init_array) }
+  PROVIDE (__init_array_end = .);
+  PROVIDE (__fini_array_start = .);
+  .fini_array     : { *(.fini_array) }
+  PROVIDE (__fini_array_end = .);
+
+  .ctors : {
+        __CTOR_LIST__ = .;
+        *(.ctors)
+	CONSTRUCTORS
+        LONG(0)
+        __CTOR_END__ = .;
+        }
+
+  .dtors : {
+        __DTOR_LIST__ = .;
+        *(.dtors)
+        LONG(0)
+        __DTOR_END__ = .;
+        }
+
+  .data : {			/* Data */
+	*(.data)
+	}
+
+  _edata = .;			/* End of data section */
+
+  /* Nothing after here is included in the zImage's size */
+
+  __bss_start = .;		/* BSS */
+  .bss : {
+	*(.bss)
+        *(.app.bss)
+	}
+  _end = . ;
+
+  /* Sections to be discarded */
+  /DISCARD/ : {
+	*(.text.exit)
+	*(.data.exit)
+	*(.exitcall.exit)
+	}
+
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+}
diff --git a/extras/mini-os/arch/arm/mm.c b/extras/mini-os/arch/arm/mm.c
new file mode 100644
index 0000000..bb6aa0e
--- /dev/null
+++ b/extras/mini-os/arch/arm/mm.c
@@ -0,0 +1,44 @@
+#include <console.h>
+#include <arch_mm.h>
+
+#define PHYS_START (0x80008000 + (1000 * 4 * 1024))
+#define PHYS_SIZE (40*1024*1024)
+
+static void build_pagetable(unsigned long *start_pfn, unsigned long *max_pfn)
+{
+    // FIXME Create small pages descriptors here instead of the 1M superpages created earlier.
+    return;
+}
+
+unsigned long allocate_ondemand(unsigned long n, unsigned long alignment)
+{
+    // FIXME
+    BUG();
+}
+
+void arch_init_mm(unsigned long* start_pfn_p, unsigned long* max_pfn_p)
+{
+    printk("    _text: %p(VA)\n", &_text);
+    printk("    _etext: %p(VA)\n", &_etext);
+    printk("    _erodata: %p(VA)\n", &_erodata);
+    printk("    _edata: %p(VA)\n", &_edata);
+    printk("    stack start: %p(VA)\n", stack);
+    printk("    _end: %p(VA)\n", &_end);
+
+    // FIXME Get from dt!
+    *start_pfn_p = (((unsigned long)&_end) >> PAGE_SHIFT) + 1000;
+    *max_pfn_p = ((unsigned long)&_end + PHYS_SIZE) >> PAGE_SHIFT;
+
+    printk("    start_pfn: %lx\n", *start_pfn_p);
+    printk("    max_pfn: %lx\n", *max_pfn_p);
+
+    build_pagetable(start_pfn_p, max_pfn_p);
+}
+
+void arch_init_p2m(unsigned long max_pfn)
+{
+}
+
+void arch_init_demand_mapping_area(unsigned long cur_pfn)
+{
+}
diff --git a/extras/mini-os/arch/arm/sched.c b/extras/mini-os/arch/arm/sched.c
new file mode 100644
index 0000000..1306c1b
--- /dev/null
+++ b/extras/mini-os/arch/arm/sched.c
@@ -0,0 +1,37 @@
+#include <mini-os/sched.h>
+#include <mini-os/xmalloc.h>
+
+void arm_start_thread(void);
+
+/* Architecture specific setup of thread creation */
+struct thread* arch_create_thread(char *name, void (*function)(void *),
+                                  void *data)
+{
+    struct thread *thread;
+
+    thread = xmalloc(struct thread);
+    /* We can't use lazy allocation here since the trap handler runs on the stack */
+    thread->stack = (char *)alloc_pages(STACK_SIZE_PAGE_ORDER);
+    thread->name = name;
+    printk("Thread \"%s\": pointer: 0x%lx, stack: 0x%lx\n", name, thread,
+            thread->stack);
+
+    /* Save pointer to the thread on the stack, used by current macro */
+    *((unsigned long *)thread->stack) = (unsigned long)thread;
+
+    /* Push the details to pass to arm_start_thread onto the stack */
+    int *sp = (int *) (thread->stack + STACK_SIZE);
+    *(--sp) = (int) function;
+    *(--sp) = (int) data;
+    thread->sp = (unsigned long) sp;
+
+    thread->ip = (unsigned long) arm_start_thread;
+
+    return thread;
+}
+
+void run_idle_thread(void)
+{
+    __asm__ __volatile__ ("mov sp, %0; mov pc, %1"::"r"(idle_thread->sp), "r"(idle_thread->ip));
+    /* Never arrive here! */
+}
diff --git a/extras/mini-os/arch/arm/setup.c b/extras/mini-os/arch/arm/setup.c
new file mode 100644
index 0000000..3499b37
--- /dev/null
+++ b/extras/mini-os/arch/arm/setup.c
@@ -0,0 +1,102 @@
+#include <mini-os/os.h>
+#include <mini-os/kernel.h>
+#include <xen/xen.h>
+#include <xen/memory.h>
+#include <xen/hvm/params.h>
+#include <arch_mm.h>
+
+/*
+ * This structure contains start-of-day info, such as pagetable base pointer,
+ * address of the shared_info structure, and things like that.
+ * On x86, the hypervisor passes it to us. On ARM, we fill it in ourselves.
+ */
+union start_info_union start_info_union;
+
+/*
+ * Shared page for communicating with the hypervisor.
+ * Events flags go here, for example.
+ */
+shared_info_t *HYPERVISOR_shared_info;
+
+extern char shared_info_page[PAGE_SIZE];
+
+static int hvm_get_parameter(int idx, uint64_t *value)
+{
+    struct xen_hvm_param xhv;
+    int ret;
+
+    xhv.domid = DOMID_SELF;
+    xhv.index = idx;
+    ret = HYPERVISOR_hvm_op(HVMOP_get_param, &xhv);
+    if (ret < 0) {
+        BUG();
+    }
+    *value = xhv.value;
+    return ret;
+}
+
+static void get_console(void)
+{
+    uint64_t v = -1;
+
+    hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v);
+    start_info.console.domU.evtchn = v;
+
+    hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v);
+    start_info.console.domU.mfn = v;
+
+    printk("Console is on port %d\n", start_info.console.domU.evtchn);
+    printk("Console ring is at mfn %x\n", start_info.console.domU.mfn);
+}
+
+void get_xenbus(void)
+{
+    uint64_t value;
+
+    if (hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &value))
+	BUG();
+
+    start_info.store_evtchn = (int)value;
+
+    if(hvm_get_parameter(HVM_PARAM_STORE_PFN, &value))
+	BUG();
+    start_info.store_mfn = (unsigned long)value;
+}
+
+/*
+ * INITIAL C ENTRY POINT.
+ */
+void arch_init(void *dtb_pointer)
+{
+    struct xen_add_to_physmap xatp;
+
+    memset(&__bss_start, 0, &_end - &__bss_start);
+
+    printk("dtb_pointer : %x\n", dtb_pointer);
+
+    /* Map shared_info page */
+    xatp.domid = DOMID_SELF;
+    xatp.idx = 0;
+    xatp.space = XENMAPSPACE_shared_info;
+    xatp.gpfn = virt_to_pfn(shared_info_page);
+    if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp) != 0)
+        BUG();
+    HYPERVISOR_shared_info = (struct shared_info *)shared_info_page;
+
+    /* Fill in start_info */
+    get_console();
+    get_xenbus();
+
+    start_kernel();
+}
+
+void
+arch_fini(void)
+{
+
+}
+
+void
+arch_do_exit(void)
+{
+}
diff --git a/extras/mini-os/arch/arm/time.c b/extras/mini-os/arch/arm/time.c
new file mode 100644
index 0000000..7c0cce5
--- /dev/null
+++ b/extras/mini-os/arch/arm/time.c
@@ -0,0 +1,202 @@
+#include <mini-os/os.h>
+#include <mini-os/hypervisor.h>
+#include <mini-os/events.h>
+#include <mini-os/traps.h>
+#include <mini-os/types.h>
+#include <mini-os/time.h>
+#include <mini-os/lib.h>
+
+//#define VTIMER_DEBUG
+#ifdef VTIMER_DEBUG
+#define DEBUG(_f, _a...) \
+    printk("MINI_OS(file=vtimer.c, line=%d) " _f , __LINE__, ## _a)
+#else
+#define DEBUG(_f, _a...)    ((void)0)
+#endif
+
+/************************************************************************
+ * Time functions
+ *************************************************************************/
+
+static uint64_t cntvct_at_init;
+static uint32_t counter_freq;
+
+/* Compute with 96 bit intermediate result: (a*b)/c */
+uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
+{
+    union {
+        uint64_t ll;
+        struct {
+            uint32_t low, high;
+        } l;
+    } u, res;
+    uint64_t rl, rh;
+
+    u.ll = a;
+    rl = (uint64_t)u.l.low * (uint64_t)b;
+    rh = (uint64_t)u.l.high * (uint64_t)b;
+    rh += (rl >> 32);
+    res.l.high = rh / c;
+    res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
+    return res.ll;
+}
+
+static inline s_time_t ticks_to_ns(uint64_t ticks)
+{
+    return muldiv64(ticks, SECONDS(1), counter_freq);
+}
+
+static inline uint64_t ns_to_ticks(s_time_t ns)
+{
+    return muldiv64(ns, counter_freq, SECONDS(1));
+}
+
+/* These are peridically updated in shared_info, and then copied here. */
+struct shadow_time_info {
+    uint64_t tsc_timestamp;     /* TSC at last update of time vals.  */
+    uint64_t system_timestamp;  /* Time, in nanosecs, since boot.    */
+    uint32_t tsc_to_nsec_mul;
+    uint32_t tsc_to_usec_mul;
+    int tsc_shift;
+    uint32_t version;
+};
+static struct timespec shadow_ts;
+static uint32_t shadow_ts_version;
+
+static struct shadow_time_info shadow;
+
+static void get_time_values_from_xen(void)
+{
+    struct vcpu_time_info    *src = &HYPERVISOR_shared_info->vcpu_info[0].time;
+
+     do {
+        shadow.version = src->version;
+        rmb();
+        shadow.tsc_timestamp     = src->tsc_timestamp;
+        shadow.system_timestamp  = src->system_time;
+        shadow.tsc_to_nsec_mul   = src->tsc_to_system_mul;
+        shadow.tsc_shift         = src->tsc_shift;
+        rmb();
+    }
+    while ((src->version & 1) | (shadow.version ^ src->version));
+
+    shadow.tsc_to_usec_mul = shadow.tsc_to_nsec_mul / 1000;
+}
+
+static inline uint64_t read_virtual_count(void)
+{
+    uint32_t c_lo, c_hi;
+    __asm__ __volatile__("isb;mrrc p15, 1, %0, %1, c14":"=r"(c_lo), "=r"(c_hi));
+    return (((uint64_t) c_hi) << 32) + c_lo;
+}
+
+/* monotonic_clock(): returns # of nanoseconds passed since time_init()
+ *        Note: This function is required to return accurate
+ *        time even in the absence of multiple timer ticks.
+ */
+uint64_t monotonic_clock(void)
+{
+    s_time_t time = ticks_to_ns(read_virtual_count() - cntvct_at_init);
+    //printk("monotonic_clock: %llu (%llu)\n", time, NSEC_TO_SEC(time));
+    return time;
+}
+
+static void update_wallclock(void)
+{
+    shared_info_t *s = HYPERVISOR_shared_info;
+
+    do {
+        shadow_ts_version = s->wc_version;
+        rmb();
+        shadow_ts.tv_sec  = s->wc_sec;
+        shadow_ts.tv_nsec = s->wc_nsec;
+        rmb();
+    }
+    while ((s->wc_version & 1) | (shadow_ts_version ^ s->wc_version));
+}
+
+
+int gettimeofday(struct timeval *tv, void *tz)
+{
+    uint64_t nsec = monotonic_clock();
+    nsec += shadow_ts.tv_nsec;
+
+    tv->tv_sec = shadow_ts.tv_sec;
+    tv->tv_sec += NSEC_TO_SEC(nsec);
+    tv->tv_usec = NSEC_TO_USEC(nsec % 1000000000UL);
+
+    return 0;
+}
+
+void set_vtimer_compare(uint64_t value) {
+    uint32_t x, y;
+
+    DEBUG("New CompareValue : %llx\n", value);
+    x = 0xFFFFFFFFULL & value;
+    y = (value >> 32) & 0xFFFFFFFF;
+
+    __asm__ __volatile__("mcrr p15, 3, %0, %1, c14\n"
+            "isb"::"r"(x), "r"(y));
+
+    __asm__ __volatile__("mov %0, #0x1\n"
+            "mcr p15, 0, %0, c14, c3, 1\n" /* Enable timer and unmask the output signal */
+            "isb":"=r"(x));
+}
+
+void unset_vtimer_compare(void) {
+    uint32_t x;
+
+    __asm__ __volatile__("mov %0, #0x2\n"
+            "mcr p15, 0, %0, c14, c3, 1\n" /* Disable timer and mask the output signal */
+            "isb":"=r"(x));
+}
+
+void block_domain(s_time_t until)
+{
+    uint64_t until_count = ns_to_ticks(until) + cntvct_at_init;
+    ASSERT(irqs_disabled());
+    if (read_virtual_count() < until_count)
+    {
+        set_vtimer_compare(until_count);
+        //char buf[] = "sleep\n"; (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(buf), buf);
+        __asm__ __volatile__("wfi");
+        //char wake[] = "wake\n"; (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(wake), wake);
+        unset_vtimer_compare();
+
+        /* Give the IRQ handler a chance to handle whatever woke us up. */
+        local_irq_enable();
+        local_irq_disable();
+    }
+}
+
+void timer_handler(evtchn_port_t port, struct pt_regs *regs, void *ign)
+{
+    DEBUG("Timer kick\n");
+    get_time_values_from_xen();
+    update_wallclock();
+}
+
+evtchn_port_t timer_port = -1;
+
+void init_time(void)
+{
+    printk("Initialising timer interface\n");
+
+    __asm__ __volatile__("mrc p15, 0, %0, c14, c0, 0":"=r"(counter_freq));
+    cntvct_at_init = read_virtual_count();
+    printk("Virtual Count register is %llx, freq = %d Hz\n", cntvct_at_init, counter_freq);
+
+    timer_port = bind_virq(VIRQ_TIMER, (evtchn_handler_t)timer_handler, 0);
+    if (timer_port == -1)
+        BUG();
+    unmask_evtchn(timer_port);
+}
+
+void fini_time(void)
+{
+    if (timer_port != -1)
+    {
+        mask_evtchn(timer_port);
+        unbind_evtchn(timer_port);
+    }
+}
diff --git a/extras/mini-os/arch/x86/events.c b/extras/mini-os/arch/x86/events.c
index e420a98..5198cf3 100644
--- a/extras/mini-os/arch/x86/events.c
+++ b/extras/mini-os/arch/x86/events.c
@@ -23,6 +23,10 @@ void arch_init_events(void)
 #endif
 }
 
+void arch_unbind_ports(void)
+{
+}
+
 void arch_fini_events(void)
 {
 #if defined(__x86_64__)
diff --git a/extras/mini-os/drivers/gic.c b/extras/mini-os/drivers/gic.c
new file mode 100644
index 0000000..3141830
--- /dev/null
+++ b/extras/mini-os/drivers/gic.c
@@ -0,0 +1,187 @@
+// ARM GIC implementation
+
+#include <mini-os/os.h>
+#include <mini-os/hypervisor.h>
+
+//#define VGIC_DEBUG
+#ifdef VGIC_DEBUG
+#define DEBUG(_f, _a...) \
+    DEBUG("MINI_OS(file=vgic.c, line=%d) " _f , __LINE__, ## _a)
+#else
+#define DEBUG(_f, _a...)    ((void)0)
+#endif
+
+extern void (*IRQ_handler)(void);
+
+struct gic {
+    volatile char *gicd_base;
+    volatile char *gicc_base;
+};
+
+static struct gic gic;
+
+// Distributor Interface
+#define GICD_CTLR        0x0
+#define GICD_ISENABLER    0x100
+#define GICD_PRIORITY    0x400
+#define GICD_ITARGETSR    0x800
+#define GICD_ICFGR        0xC00
+
+// CPU Interface
+#define GICC_CTLR    0x0
+#define GICC_PMR    0x4
+#define GICC_IAR    0xc
+#define GICC_EOIR    0x10
+#define GICC_HPPIR    0x18
+
+#define gicd(gic, offset) ((gic)->gicd_base + (offset))
+#define gicc(gic, offset) ((gic)->gicc_base + (offset))
+
+#define REG(addr) ((uint32_t *)(addr))
+
+static inline uint32_t REG_READ32(volatile uint32_t *addr)
+{
+    uint32_t value;
+    __asm__ __volatile__("ldr %0, [%1]":"=&r"(value):"r"(addr));
+    rmb();
+    return value;
+}
+
+static inline void REG_WRITE32(volatile uint32_t *addr, unsigned int value)
+{
+    __asm__ __volatile__("str %0, [%1]"::"r"(value), "r"(addr));
+    wmb();
+}
+
+static void gic_set_priority(struct gic *gic, unsigned char irq_number, unsigned char priority)
+{
+    uint32_t value;
+    value = REG_READ32(REG(gicd(gic, GICD_PRIORITY)) + irq_number);
+    value &= ~(0xff << (8 * (irq_number & 0x3))); // set priority to '0'
+    value |= priority << (8 * (irq_number & 0x3)); // add our priority
+    REG_WRITE32(REG(gicd(gic, GICD_PRIORITY)) + irq_number, value);
+}
+
+static void gic_route_interrupt(struct gic *gic, unsigned char irq_number, unsigned char cpu_set)
+{
+    uint32_t value;
+    value = REG_READ32(REG(gicd(gic, GICD_ITARGETSR)) + irq_number);
+    value &= ~(0xff << (8 * (irq_number & 0x3))); // set priority to '0'
+    value |= cpu_set << (8 * (irq_number & 0x3)); // add our priority
+    REG_WRITE32(REG(gicd(gic, GICD_ITARGETSR)) + irq_number, value);
+}
+
+/* When accessing the GIC registers, we can't use LDREX/STREX because it's not regular memory. */
+static __inline__ void clear_bit_non_atomic(int nr, volatile void *base)
+{
+    uint32_t *tmp = (uint32_t *)base;
+    tmp[nr >> 5] &= (unsigned long)~(1 << (nr & 0x1f));
+}
+
+static __inline__ void set_bit_non_atomic(int nr, volatile void *base)
+{
+    uint32_t *tmp = (uint32_t *)base;
+    tmp[nr >> 5] |= (1 << (nr & 0x1f));
+}
+
+/* Note: not thread safe (but we only support one CPU for now anyway) */
+static void gic_enable_interrupt(struct gic *gic, unsigned char irq_number,
+        unsigned char cpu_set, unsigned char level_sensitive, unsigned char ppi)
+{
+    void *set_enable_reg;
+    void *cfg_reg;
+
+    // set priority
+    gic_set_priority(gic, irq_number, 0x0);
+
+    // set target cpus for this interrupt
+    gic_route_interrupt(gic, irq_number, cpu_set);
+
+    // set level/edge triggered
+    cfg_reg = (void *)gicd(gic, GICD_ICFGR);
+    level_sensitive ? clear_bit_non_atomic((irq_number * 2) + 1, cfg_reg) : set_bit_non_atomic((irq_number * 2) + 1, cfg_reg);
+    if(ppi)
+        clear_bit_non_atomic((irq_number * 2), cfg_reg);
+
+    wmb();
+
+    // enable forwarding interrupt from distributor to cpu interface
+    set_enable_reg = (void *)gicd(gic, GICD_ISENABLER);
+    set_bit_non_atomic(irq_number, set_enable_reg);
+    wmb();
+}
+
+static void gic_enable_interrupts(struct gic *gic)
+{
+    // Global enable forwarding interrupts from distributor to cpu interface
+    REG_WRITE32(REG(gicd(gic, GICD_CTLR)), 0x00000001);
+
+    // Global enable signalling of interrupt from the cpu interface
+    REG_WRITE32(REG(gicc(gic, GICC_CTLR)), 0x00000001);
+}
+
+static void gic_disable_interrupts(struct gic *gic)
+{
+    // Global disable signalling of interrupt from the cpu interface
+    REG_WRITE32(REG(gicc(gic, GICC_CTLR)), 0x00000000);
+
+    // Global disable forwarding interrupts from distributor to cpu interface
+    REG_WRITE32(REG(gicd(gic, GICD_CTLR)), 0x00000000);
+}
+
+static void gic_cpu_set_priority(struct gic *gic, char priority)
+{
+    REG_WRITE32(REG(gicc(gic, GICC_PMR)), priority & 0x000000FF);
+}
+
+static unsigned long gic_readiar(struct gic *gic) {
+    return REG_READ32(REG(gicc(gic, GICC_IAR))) & 0x000003FF; // Interrupt ID
+}
+
+static void gic_eoir(struct gic *gic, uint32_t irq) {
+    REG_WRITE32(REG(gicc(gic, GICC_EOIR)), irq & 0x000003FF);
+}
+
+//FIXME Get event_irq from dt
+#define EVENTS_IRQ 31
+#define VIRTUALTIMER_IRQ 27
+
+static void gic_handler(void) {
+    unsigned int irq = gic_readiar(&gic);
+
+    DEBUG("IRQ received : %i\n", irq);
+    switch(irq) {
+    case EVENTS_IRQ:
+        do_hypervisor_callback(NULL);
+        break;
+    case VIRTUALTIMER_IRQ:
+        timer_handler(0, NULL, 0);
+        break;
+    default:
+        DEBUG("Unhandled irq\n");
+        break;
+    }
+
+    DEBUG("EIRQ\n");
+
+    gic_eoir(&gic, irq);
+}
+
+void gic_init(void) {
+    // FIXME Get from dt!
+    gic.gicd_base = (char *)0x2c001000ULL;
+    gic.gicc_base = (char *)0x2c002000ULL;
+    wmb();
+
+    IRQ_handler = gic_handler;
+
+    gic_disable_interrupts(&gic);
+    gic_cpu_set_priority(&gic, 0xff);
+
+    /* Must call gic_enable_interrupts before enabling individual interrupts, otherwise our IRQ handler
+     * gets called endlessly with spurious interrupts. */
+    gic_enable_interrupts(&gic);
+
+    gic_enable_interrupt(&gic, EVENTS_IRQ /* interrupt number */, 0x1 /*cpu_set*/, 1 /*level_sensitive*/, 0 /* ppi */);
+    gic_enable_interrupt(&gic, VIRTUALTIMER_IRQ /* interrupt number */, 0x1 /*cpu_set*/, 1 /*level_sensitive*/, 1 /* ppi */);
+}
diff --git a/extras/mini-os/events.c b/extras/mini-os/events.c
index 3c92d82..780c74a 100644
--- a/extras/mini-os/events.c
+++ b/extras/mini-os/events.c
@@ -179,6 +179,7 @@ void init_events(void)
 void fini_events(void)
 {
     /* Dealloc all events */
+    arch_unbind_ports();
     unbind_all_ports();
     arch_fini_events();
 }
@@ -238,7 +239,8 @@ int evtchn_bind_interdomain(domid_t pal, evtchn_port_t remote_port,
 
 int evtchn_get_peercontext(evtchn_port_t local_port, char *ctx, int size)
 {
-    int rc;
+    int rc = 0;
+#ifndef __arm__			/* TODO */
     uint32_t sid;
     struct xen_flask_op op;
     op.cmd = FLASK_GET_PEER_SID;
@@ -253,6 +255,7 @@ int evtchn_get_peercontext(evtchn_port_t local_port, char *ctx, int size)
     op.u.sid_context.size = size;
     set_xen_guest_handle(op.u.sid_context.context, ctx);
     rc = _hypercall1(int, xsm_op, &op);
+#endif
     return rc;
 }
 
diff --git a/extras/mini-os/hypervisor.c b/extras/mini-os/hypervisor.c
index b4688a0..1b61d9b 100644
--- a/extras/mini-os/hypervisor.c
+++ b/extras/mini-os/hypervisor.c
@@ -64,7 +64,7 @@ void do_hypervisor_callback(struct pt_regs *regs)
             l2 &= ~(1UL << l2i);
 
             port = (l1i * (sizeof(unsigned long) * 8)) + l2i;
-			do_event(port, regs);
+            do_event(port, regs);
         }
     }
 
@@ -73,18 +73,26 @@ void do_hypervisor_callback(struct pt_regs *regs)
 
 void force_evtchn_callback(void)
 {
+#ifdef XEN_HAVE_PV_UPCALL_MASK
     int save;
+#endif
     vcpu_info_t *vcpu;
     vcpu = &HYPERVISOR_shared_info->vcpu_info[smp_processor_id()];
+#ifdef XEN_HAVE_PV_UPCALL_MASK
     save = vcpu->evtchn_upcall_mask;
+#endif
 
     while (vcpu->evtchn_upcall_pending) {
+#ifdef XEN_HAVE_PV_UPCALL_MASK
         vcpu->evtchn_upcall_mask = 1;
+#endif
         barrier();
         do_hypervisor_callback(NULL);
         barrier();
+#ifdef XEN_HAVE_PV_UPCALL_MASK
         vcpu->evtchn_upcall_mask = save;
         barrier();
+#endif
     };
 }
 
@@ -110,7 +118,9 @@ inline void unmask_evtchn(uint32_t port)
               &vcpu_info->evtchn_pending_sel) )
     {
         vcpu_info->evtchn_upcall_pending = 1;
+#ifdef XEN_HAVE_PV_UPCALL_MASK
         if ( !vcpu_info->evtchn_upcall_mask )
+#endif
             force_evtchn_callback();
     }
 }
diff --git a/extras/mini-os/include/arm/arch_endian.h b/extras/mini-os/include/arm/arch_endian.h
new file mode 100644
index 0000000..0771683
--- /dev/null
+++ b/extras/mini-os/include/arm/arch_endian.h
@@ -0,0 +1,7 @@
+#ifndef	ARCH_ENDIAN_H
+#error "Do not include arch_endian by itself, include endian.h"
+#else
+
+#define __BYTE_ORDER __LITTLE_ENDIAN
+
+#endif
diff --git a/extras/mini-os/include/arm/arch_limits.h b/extras/mini-os/include/arm/arch_limits.h
new file mode 100644
index 0000000..bae99e1
--- /dev/null
+++ b/extras/mini-os/include/arm/arch_limits.h
@@ -0,0 +1,9 @@
+#ifndef __ARCH_LIMITS_H__
+#define __ARCH_LIMITS_H__
+
+#include <mm.h>
+
+#define __STACK_SIZE_PAGE_ORDER  2
+#define __STACK_SIZE (4 * PAGE_SIZE)
+
+#endif
diff --git a/extras/mini-os/include/arm/arch_mm.h b/extras/mini-os/include/arm/arch_mm.h
new file mode 100644
index 0000000..be14ada
--- /dev/null
+++ b/extras/mini-os/include/arm/arch_mm.h
@@ -0,0 +1,37 @@
+#ifndef _ARCH_MM_H_
+#define _ARCH_MM_H_
+
+extern char _text, _etext, _erodata, _edata, _end, __bss_start;
+extern char stack[];
+
+#define PAGE_SHIFT        12
+#define PAGE_SIZE        (1 << PAGE_SHIFT)
+#define PAGE_MASK       (~(PAGE_SIZE-1))
+
+#define L1_PAGETABLE_SHIFT      12
+
+#if 0
+#define VIRT_START                 ((unsigned long)&_text)
+#else
+#define VIRT_START                 ((unsigned long)0)
+#endif
+
+#define to_phys(x)                 ((unsigned long)(x)-VIRT_START)
+#define to_virt(x)                 ((void *)((unsigned long)(x)+VIRT_START))
+
+#define PFN_UP(x)    (((x) + PAGE_SIZE-1) >> L1_PAGETABLE_SHIFT)
+#define PFN_DOWN(x)    ((x) >> L1_PAGETABLE_SHIFT)
+#define PFN_PHYS(x)    ((uint64_t)(x) << L1_PAGETABLE_SHIFT)
+#define PHYS_PFN(x)    ((x) >> L1_PAGETABLE_SHIFT)
+
+#define virt_to_pfn(_virt)         (PFN_DOWN(to_phys(_virt)))
+#define virt_to_mfn(_virt)         (PFN_DOWN(to_phys(_virt)))
+#define mach_to_virt(_mach)        (_mach)
+#define virt_to_mach(_virt)        (_virt)
+#define mfn_to_virt(_mfn)          (to_virt(PFN_PHYS(_mfn)))
+#define pfn_to_virt(_pfn)          (to_virt(PFN_PHYS(_pfn)))
+
+// FIXME
+#define map_frames(f, n) (NULL)
+
+#endif
diff --git a/extras/mini-os/include/arm/arch_sched.h b/extras/mini-os/include/arm/arch_sched.h
new file mode 100644
index 0000000..e2307ed
--- /dev/null
+++ b/extras/mini-os/include/arm/arch_sched.h
@@ -0,0 +1,22 @@
+
+#ifndef __ARCH_SCHED_H__
+#define __ARCH_SCHED_H__
+
+#include "arch_limits.h"
+
+static inline struct thread* get_current(void)
+{
+   struct thread **current;
+   unsigned long sp;
+   __asm__ __volatile__ ("mov %0, sp":"=r"(sp));
+    current = (void *)(unsigned long)(sp & ~(__STACK_SIZE-1));
+    return *current;
+}
+
+
+extern void __arch_switch_threads(unsigned long *prevctx, unsigned long *nextctx);
+
+#define arch_switch_threads(prev,next) __arch_switch_threads(&(prev)->sp, &(next)->sp)
+
+
+#endif /* __ARCH_SCHED_H__ */
diff --git a/extras/mini-os/include/arm/arch_spinlock.h b/extras/mini-os/include/arm/arch_spinlock.h
new file mode 100755
index 0000000..d57f150
--- /dev/null
+++ b/extras/mini-os/include/arm/arch_spinlock.h
@@ -0,0 +1,49 @@
+
+
+#ifndef __ARCH_ASM_SPINLOCK_H
+#define __ARCH_ASM_SPINLOCK_H
+
+#include "os.h"
+
+
+#define ARCH_SPIN_LOCK_UNLOCKED { 1 }
+
+/*
+ * Simple spin lock operations.  There are two variants, one clears IRQ's
+ * on the local processor, one does not.
+ *
+ * We make no fairness assumptions. They have a cost.
+ */
+
+#define arch_spin_is_locked(x)    (*(volatile signed char *)(&(x)->slock) <= 0)
+#define arch_spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x))
+
+/*
+ * This works. Despite all the confusion.
+ * (except on PPro SMP or if we are using OOSTORE)
+ * (PPro errata 66, 92)
+ */
+
+static inline void _raw_spin_unlock(spinlock_t *lock)
+{
+    xchg(&lock->slock, 1);
+}
+
+static inline int _raw_spin_trylock(spinlock_t *lock)
+{
+    return xchg(&lock->slock, 0) != 0 ? 1 : 0;
+}
+
+static inline void _raw_spin_lock(spinlock_t *lock)
+{
+    volatile int was_locked;
+    do {
+        was_locked = xchg(&lock->slock, 0) == 0 ? 1 : 0;
+    } while(was_locked);
+}
+
+static inline void _raw_spin_lock_flags (spinlock_t *lock, unsigned long flags)
+{
+}
+
+#endif
diff --git a/extras/mini-os/include/arm/arm32/arch_wordsize.h b/extras/mini-os/include/arm/arm32/arch_wordsize.h
new file mode 100644
index 0000000..b47eee9
--- /dev/null
+++ b/extras/mini-os/include/arm/arm32/arch_wordsize.h
@@ -0,0 +1 @@
+#define __WORDSIZE 32
diff --git a/extras/mini-os/include/arm/hypercall-arm32.h b/extras/mini-os/include/arm/hypercall-arm32.h
new file mode 100644
index 0000000..0fc1c03
--- /dev/null
+++ b/extras/mini-os/include/arm/hypercall-arm32.h
@@ -0,0 +1,173 @@
+/******************************************************************************
+ * hypercall-arm32.h
+ * 
+ * Copied from XenLinux.
+ * 
+ * Copyright (c) 2002-2004, K A Fraser
+ * 
+ * 64-bit updates:
+ *   Benjamin Liu <benjamin.liu@intel.com>
+ *   Jun Nakajima <jun.nakajima@intel.com>
+ * 
+ * This file may be distributed separately from the Linux kernel, or
+ * incorporated into other software packages, subject to the following license:
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __HYPERCALL_ARM_H__
+#define __HYPERCALL_ARM_H__
+
+#include <xen/xen.h>
+#include <xen/sched.h>
+#include <mini-os/mm.h>
+
+inline int
+HYPERVISOR_mmu_update(
+    mmu_update_t *req, int count, int *success_count, domid_t domid);
+
+inline int
+HYPERVISOR_mmuext_op(
+    struct mmuext_op *op, int count, int *success_count, domid_t domid);
+
+inline int
+HYPERVISOR_set_gdt(
+    unsigned long *frame_list, int entries);
+
+inline int
+HYPERVISOR_stack_switch(
+    unsigned long ss, unsigned long esp);
+
+inline int
+HYPERVISOR_set_callbacks(
+    unsigned long event_address, unsigned long failsafe_address, 
+    unsigned long syscall_address);
+
+inline int
+HYPERVISOR_fpu_taskswitch(
+    int set);
+
+inline int
+HYPERVISOR_sched_op(
+    int cmd, void *arg);
+
+static inline int
+HYPERVISOR_shutdown(
+    unsigned int reason)
+{
+    struct sched_shutdown shutdown = { .reason = reason };
+	HYPERVISOR_sched_op(SCHEDOP_shutdown, &shutdown);
+}
+
+inline long
+HYPERVISOR_set_timer_op(
+    uint64_t timeout);
+
+inline int
+HYPERVISOR_set_debugreg(
+    int reg, unsigned long value);
+
+inline unsigned long
+HYPERVISOR_get_debugreg(
+    int reg);
+
+inline int
+HYPERVISOR_update_descriptor(
+    unsigned long ma, unsigned long word);
+
+inline int
+HYPERVISOR_memory_op(
+    unsigned int cmd, void *arg);
+
+inline int
+HYPERVISOR_multicall(
+    void *call_list, int nr_calls);
+
+inline int
+HYPERVISOR_update_va_mapping(
+    unsigned long va, pte_t new_val, unsigned long flags);
+
+inline int
+HYPERVISOR_event_channel_op(
+       int cmd, void *op);
+
+inline int
+HYPERVISOR_xen_version(
+    int cmd, void *arg);
+
+inline int
+HYPERVISOR_console_io(
+    int cmd, int count, char *str);
+
+inline int
+HYPERVISOR_physdev_op(
+    void *physdev_op);
+
+inline int
+HYPERVISOR_grant_table_op(
+    unsigned int cmd, void *uop, unsigned int count);
+
+inline int
+HYPERVISOR_update_va_mapping_otherdomain(
+    unsigned long va, pte_t new_val, unsigned long flags, domid_t domid);
+
+inline int
+HYPERVISOR_vm_assist(
+    unsigned int cmd, unsigned int type);
+
+inline int
+HYPERVISOR_vcpu_op(
+    int cmd, int vcpuid, void *extra_args);
+
+inline int
+HYPERVISOR_set_segment_base(
+    int reg, unsigned long value);
+
+inline int
+HYPERVISOR_suspend(
+    unsigned long srec);
+
+inline int
+HYPERVISOR_nmi_op(
+    unsigned long op,
+    unsigned long arg);
+
+inline int
+HYPERVISOR_sysctl(
+    unsigned long op);
+
+inline int
+HYPERVISOR_domctl(
+    unsigned long op);
+
+inline int
+HYPERVISOR_hvm_op(
+    unsigned long op, void *arg);
+
+#endif /* __HYPERCALL_X86_64_H__ */
+
+/*
+ * Local variables:
+ *  c-file-style: "linux"
+ *  indent-tabs-mode: t
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/extras/mini-os/include/arm/os.h b/extras/mini-os/include/arm/os.h
new file mode 100644
index 0000000..21e9276
--- /dev/null
+++ b/extras/mini-os/include/arm/os.h
@@ -0,0 +1,230 @@
+#ifndef _OS_H_
+#define _OS_H_
+
+#ifndef __ASSEMBLY__
+
+#include <mini-os/hypervisor.h>
+#include <mini-os/types.h>
+#include <xen/xen.h>
+
+void arch_fini(void);
+void timer_handler(evtchn_port_t port, struct pt_regs *regs, void *ign);
+
+#define BUG() while(1){}
+
+#define smp_processor_id() 0
+
+#define barrier() __asm__ __volatile__("": : :"memory")
+
+extern shared_info_t *HYPERVISOR_shared_info;
+
+// disable interrupts
+static inline __cli(void) {
+    int x;
+    __asm__ __volatile__("mrs %0, cpsr;cpsid i":"=r"(x)::"memory");
+}
+
+// enable interrupts
+static inline __sti(void) {
+    int x;
+    __asm__ __volatile__("mrs %0, cpsr\n"
+                        "bic %0, %0, #0x80\n"
+                        "msr cpsr_c, %0"
+                        :"=r"(x)::"memory");
+}
+
+static inline int irqs_disabled() {
+    int x;
+    __asm__ __volatile__("mrs %0, cpsr\n":"=r"(x)::"memory");
+    return (x & 0x80);
+}
+
+#define local_irq_save(x) { \
+    __asm__ __volatile__("mrs %0, cpsr;cpsid i; and %0, %0, #0x80":"=r"(x)::"memory");    \
+}
+
+#define local_irq_restore(x) {    \
+    __asm__ __volatile__("msr cpsr_c, %0"::"r"(x):"memory");    \
+}
+
+#define local_save_flags(x)    { \
+    __asm__ __volatile__("mrs %0, cpsr; and %0, %0, 0x80":"=r"(x)::"memory");    \
+}
+
+#define local_irq_disable()    __cli()
+#define local_irq_enable() __sti()
+
+#if defined(__arm__)
+#define mb() __asm__("dmb");
+#define rmb() __asm__("dmb");
+#define wmb() __asm__("dmb");
+#elif defined(__aarch64__)
+#define mb()
+#define rmb()
+#define wmb()
+#else
+#error undefined architecture
+#endif
+
+#define unlikely(x)  __builtin_expect((x),0)
+#define likely(x)  __builtin_expect((x),1)
+
+/************************** arm *******************************/
+#ifdef __INSIDE_MINIOS__
+#if defined (__arm__)
+#define xchg(ptr,v) __atomic_exchange_n(ptr, v, __ATOMIC_SEQ_CST)
+
+/**
+ * test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to clear
+ * @addr: Address to count from
+ *
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ *
+ * This operation is atomic.
+ * If you need a memory barrier, use synch_test_and_clear_bit instead.
+ */
+static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
+{
+    uint8_t *byte = ((uint8_t *)addr) + (nr >> 3);
+    uint8_t bit = 1 << (nr & 7);
+    uint8_t orig;
+
+    orig = __atomic_fetch_and(byte, ~bit, __ATOMIC_RELAXED);
+
+    return (orig & bit) != 0;
+}
+
+/**
+ * Atomically set a bit and return the old value.
+ * Similar to test_and_clear_bit.
+ */
+static __inline__ int test_and_set_bit(int nr, volatile void *base)
+{
+    uint8_t *byte = ((uint8_t *)base) + (nr >> 3);
+    uint8_t bit = 1 << (nr & 7);
+    uint8_t orig;
+
+    orig = __atomic_fetch_or(byte, bit, __ATOMIC_RELAXED);
+
+    return (orig & bit) != 0;
+}
+
+/**
+ * Test whether a bit is set. */
+static __inline__ int test_bit(int nr, const volatile unsigned long *addr)
+{
+    const uint8_t *ptr = (const uint8_t *) addr;
+    return ((1 << (nr & 7)) & (ptr[nr >> 3])) != 0;
+}
+
+/**
+ * Atomically set a bit in memory (like test_and_set_bit but discards result).
+ */
+static __inline__ void set_bit(int nr, volatile unsigned long *addr)
+{
+    test_and_set_bit(nr, addr);
+}
+
+/**
+ * Atomically clear a bit in memory (like test_and_clear_bit but discards result).
+ */
+static __inline__ void clear_bit(int nr, volatile unsigned long *addr)
+{
+    test_and_clear_bit(nr, addr);
+}
+
+/**
+ * __ffs - find first (lowest) set bit in word.
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static __inline__ unsigned long __ffs(unsigned long word)
+{
+    int clz;
+
+    /* xxxxx10000 = word
+     * xxxxx01111 = word - 1
+     * 0000011111 = word ^ (word - 1)
+     *      4     = 31 - clz(word ^ (word - 1))
+     */
+
+    __asm__ (
+        "sub r0, %[word], #1\n"
+        "eor r0, r0, %[word]\n"
+        "clz %[clz], r0\n":
+        /* Outputs: */
+        [clz] "=r"(clz):
+        /* Inputs: */
+        [word] "r"(word):
+        /* Clobbers: */
+        "r0");
+
+    return 31 - clz;
+}
+
+#else /* ifdef __arm__ */
+#error "Unsupported architecture"
+#endif
+#endif /* ifdef __INSIDE_MINIOS */
+
+/********************* common arm32 and arm64  ****************************/
+
+/* If *ptr == old, then store new there (and return new).
+ * Otherwise, return the old value.
+ * Atomic. */
+#define synch_cmpxchg(ptr, old, new) \
+({ __typeof__(*ptr) stored = old; \
+   __atomic_compare_exchange_n(ptr, &stored, new, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? new : old; \
+})
+
+/* As test_and_clear_bit, but using __ATOMIC_SEQ_CST */
+static __inline__ int synch_test_and_clear_bit(int nr, volatile void *addr)
+{
+    uint8_t *byte = ((uint8_t *)addr) + (nr >> 3);
+    uint8_t bit = 1 << (nr & 7);
+    uint8_t orig;
+
+    orig = __atomic_fetch_and(byte, ~bit, __ATOMIC_SEQ_CST);
+
+    return (orig & bit) != 0;
+}
+
+/* As test_and_set_bit, but using __ATOMIC_SEQ_CST */
+static __inline__ int synch_test_and_set_bit(int nr, volatile void *base)
+{
+    uint8_t *byte = ((uint8_t *)base) + (nr >> 3);
+    uint8_t bit = 1 << (nr & 7);
+    uint8_t orig;
+
+    orig = __atomic_fetch_or(byte, bit, __ATOMIC_SEQ_CST);
+
+    return (orig & bit) != 0;
+}
+
+/* As set_bit, but using __ATOMIC_SEQ_CST */
+static __inline__ void synch_set_bit(int nr, volatile void *addr)
+{
+    synch_test_and_set_bit(nr, addr);
+}
+
+/* As clear_bit, but using __ATOMIC_SEQ_CST */
+static __inline__ void synch_clear_bit(int nr, volatile void *addr)
+{
+    synch_test_and_clear_bit(nr, addr);
+}
+
+/* As test_bit, but with a following memory barrier. */
+static __inline__ int synch_test_bit(int nr, volatile void *addr)
+{
+    int result;
+    result = test_bit(nr, addr);
+    barrier();
+    return result;
+}
+
+#endif /* not assembly */
+
+#endif
diff --git a/extras/mini-os/include/arm/traps.h b/extras/mini-os/include/arm/traps.h
new file mode 100644
index 0000000..704df22
--- /dev/null
+++ b/extras/mini-os/include/arm/traps.h
@@ -0,0 +1,20 @@
+#ifndef _TRAPS_H_
+#define _TRAPS_H_
+
+struct pt_regs {
+    unsigned long r0;
+    unsigned long r1;
+    unsigned long r2;
+    unsigned long r3;
+    unsigned long r4;
+    unsigned long r5;
+    unsigned long r6;
+    unsigned long r7;
+    unsigned long r8;
+    unsigned long r9;
+    unsigned long r10;
+    unsigned long r11;
+    unsigned long r12;
+};
+
+#endif
diff --git a/extras/mini-os/include/events.h b/extras/mini-os/include/events.h
index 0452d21..f571b06 100644
--- a/extras/mini-os/include/events.h
+++ b/extras/mini-os/include/events.h
@@ -26,6 +26,10 @@ typedef void (*evtchn_handler_t)(evtchn_port_t, struct pt_regs *, void *);
 
 /* prototypes */
 void arch_init_events(void);
+
+/* Called by fini_events. Close any arch-specific ports (e.g. debug ports) */
+void arch_unbind_ports(void);
+
 void arch_fini_events(void);
 
 int do_event(evtchn_port_t port, struct pt_regs *regs);
diff --git a/extras/mini-os/include/gic.h b/extras/mini-os/include/gic.h
new file mode 100644
index 0000000..cead2e5
--- /dev/null
+++ b/extras/mini-os/include/gic.h
@@ -0,0 +1 @@
+void gic_init(void);
diff --git a/extras/mini-os/include/hypervisor.h b/extras/mini-os/include/hypervisor.h
index a62cb78..052f4f8 100644
--- a/extras/mini-os/include/hypervisor.h
+++ b/extras/mini-os/include/hypervisor.h
@@ -18,6 +18,10 @@
 #include <hypercall-x86_32.h>
 #elif defined(__x86_64__)
 #include <hypercall-x86_64.h>
+#elif defined(__arm__)
+#include <hypercall-arm32.h>
+#elif defined(__aarch64__)
+#include <hypercall-arm64.h>
 #else
 #error "Unsupported architecture"
 #endif
diff --git a/extras/mini-os/include/mm.h b/extras/mini-os/include/mm.h
index a94cd6d..644c7de 100644
--- a/extras/mini-os/include/mm.h
+++ b/extras/mini-os/include/mm.h
@@ -29,6 +29,8 @@
 #include <xen/arch-x86_32.h>
 #elif defined(__x86_64__)
 #include <xen/arch-x86_64.h>
+#elif defined(__arm__) || defined(__aarch64__)
+#include <xen/arch-arm.h>
 #else
 #error "Unsupported architecture"
 #endif
diff --git a/extras/mini-os/include/types.h b/extras/mini-os/include/types.h
index de356e8..f79ff8c 100644
--- a/extras/mini-os/include/types.h
+++ b/extras/mini-os/include/types.h
@@ -27,7 +27,7 @@ typedef unsigned char       u_char;
 typedef unsigned int        u_int;
 typedef unsigned long       u_long;
 #endif
-#ifdef __i386__
+#if defined(__i386__) || defined(__arm__)
 typedef long long           quad_t;
 typedef unsigned long long  u_quad_t;
 
@@ -40,7 +40,7 @@ typedef unsigned long       u_quad_t;
 typedef struct { unsigned long pte; } pte_t;
 #endif /* __i386__ || __x86_64__ */
 
-#ifdef __x86_64__
+#if defined(__x86_64__) || defined(__aarch64__)
 #define __pte(x) ((pte_t) { (x) } )
 #else
 #define __pte(x) ({ unsigned long long _x = (x);        \
@@ -51,10 +51,10 @@ typedef struct { unsigned long pte; } pte_t;
 #include <limits.h>
 #include <stdint.h>
 #else
-#ifdef __i386__
+#if defined(__i386__) || defined(__arm__)
 typedef unsigned int        uintptr_t;
 typedef int                 intptr_t;
-#elif defined(__x86_64__)
+#elif defined(__x86_64__) || defined(__aarch64__)
 typedef unsigned long       uintptr_t;
 typedef long                intptr_t;
 #endif /* __i386__ || __x86_64__ */
@@ -64,10 +64,10 @@ typedef unsigned short uint16_t;
 typedef   signed short int16_t;
 typedef unsigned int uint32_t;
 typedef   signed int int32_t;
-#ifdef __i386__
+#if defined(__i386__) || defined(__arm__)
 typedef   signed long long int64_t;
 typedef unsigned long long uint64_t;
-#elif defined(__x86_64__)
+#elif defined(__x86_64__) || defined(__aarch64__)
 typedef   signed long int64_t;
 typedef unsigned long uint64_t;
 #endif
diff --git a/extras/mini-os/kernel.c b/extras/mini-os/kernel.c
index 9a30550..7b2b8fc 100644
--- a/extras/mini-os/kernel.c
+++ b/extras/mini-os/kernel.c
@@ -47,6 +47,10 @@
 #include <xen/features.h>
 #include <xen/version.h>
 
+#ifdef __arm__
+#include <mini-os/gic.h>
+#endif
+
 uint8_t xen_features[XENFEAT_NR_SUBMAPS * 32];
 
 void setup_xen_features(void)
@@ -147,6 +151,10 @@ void start_kernel(void)
     create_thread("shutdown", shutdown_thread, NULL);
 #endif
 
+#ifdef __arm__
+    gic_init();
+#endif
+
     /* Call (possibly overridden) app_main() */
     app_main(&start_info);
 
diff --git a/extras/mini-os/sched.c b/extras/mini-os/sched.c
index 174945e..b99d7dc 100644
--- a/extras/mini-os/sched.c
+++ b/extras/mini-os/sched.c
@@ -145,6 +145,9 @@ struct thread* create_thread(char *name, void (*function)(void *), void *data)
     unsigned long flags;
     /* Call architecture specific setup. */
     thread = arch_create_thread(name, function, data);
+    if(!thread)
+        BUG(); //For now, FIXME should just return NULL
+
     /* Not runable, not exited, not sleeping */
     thread->flags = 0;
     thread->wakeup_time = 0LL;
@@ -165,28 +168,28 @@ struct _reent *__getreent(void)
     struct _reent *_reent;
 
     if (!threads_started)
-	_reent = _impure_ptr;
+        _reent = _impure_ptr;
     else if (in_callback)
-	_reent = &callback_reent;
+        _reent = &callback_reent;
     else
-	_reent = &get_current()->reent;
+        _reent = &get_current()->reent;
 
 #ifndef NDEBUG
 #if defined(__x86_64__) || defined(__x86__)
     {
 #ifdef __x86_64__
-	register unsigned long sp asm ("rsp");
+        register unsigned long sp asm ("rsp");
 #else
-	register unsigned long sp asm ("esp");
+        register unsigned long sp asm ("esp");
 #endif
-	if ((sp & (STACK_SIZE-1)) < STACK_SIZE / 16) {
-	    static int overflowing;
-	    if (!overflowing) {
-		overflowing = 1;
-		printk("stack overflow\n");
-		BUG();
-	    }
-	}
+        if ((sp & (STACK_SIZE-1)) < STACK_SIZE / 16) {
+            static int overflowing;
+            if (!overflowing) {
+                overflowing = 1;
+                printk("stack overflow\n");
+                BUG();
+            }
+        }
     }
 #endif
 #else
-- 
2.0.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH ARM v4 08/12] mini-os: arm: show registers, stack and exception vector on fault
  2014-06-18 15:08 [PATCH ARM v4 00/12] mini-os: initial ARM support Thomas Leonard
                   ` (6 preceding siblings ...)
  2014-06-18 15:08 ` [PATCH ARM v4 07/12] mini-os: initial ARM support Thomas Leonard
@ 2014-06-18 15:08 ` Thomas Leonard
  2014-06-18 15:08 ` [PATCH ARM v4 09/12] mini-os: import libfdt Thomas Leonard
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 41+ messages in thread
From: Thomas Leonard @ 2014-06-18 15:08 UTC (permalink / raw)
  To: xen-devel
  Cc: Thomas Leonard, Dave.Scott, anil, stefano.stabellini, samuel.thibault

Signed-off-by: Thomas Leonard <talex5@gmail.com>
---
 extras/mini-os/ARM-TODO.txt          |  1 -
 extras/mini-os/arch/arm/arm32.S      | 81 ++++++++++++++++++++++++++---
 extras/mini-os/arch/arm/panic.c      | 99 ++++++++++++++++++++++++++++++++++++
 extras/mini-os/include/arm/arch_mm.h |  2 +-
 extras/mini-os/include/arm/os.h      |  2 +-
 5 files changed, 175 insertions(+), 10 deletions(-)
 create mode 100644 extras/mini-os/arch/arm/panic.c

diff --git a/extras/mini-os/ARM-TODO.txt b/extras/mini-os/ARM-TODO.txt
index 3d9be10..8f4f1da 100644
--- a/extras/mini-os/ARM-TODO.txt
+++ b/extras/mini-os/ARM-TODO.txt
@@ -1,4 +1,3 @@
-* support abort exception handling ( and others )
 * scheduling!
 * gic request_irq implementation, currently all IRQs all hardcoded in gic irq handler.
 * use device tree instead of the currently hardcoded values
diff --git a/extras/mini-os/arch/arm/arm32.S b/extras/mini-os/arch/arm/arm32.S
index 4f953ec..29fba72 100644
--- a/extras/mini-os/arch/arm/arm32.S
+++ b/extras/mini-os/arch/arm/arm32.S
@@ -80,16 +80,83 @@ shared_info_page:
 
 .align 3
 .globl stack
+.globl stack_end
 stack:
 	.fill (4*1024), 4, 0x0
 stack_end:
 
 .align 3
+.globl irqstack
+.globl irqstack_end
 irqstack:
 	.fill (1024), 4, 0x0
 irqstack_end:
+
+fault_dump:
+	.fill 18, 4, 0x0		@ On fault, we save the registers + CPSR + handler address
+
 .popsection
 
+fault:
+	cpsid	aif			@ Disable interrupts
+
+	ldr	r13, =fault_dump
+	stmia	r13, {r0-r12}		@ Dump the non-banked registers directly (well, unless from FIQ mode)
+	str	r14, [r13, #15 << 2]	@ Our r14 is the faulting r15
+	mov	r0, r13
+
+	@ Save the caller's CPSR (our SPSR) too.
+	mrs	r1, SPSR
+	str	r1, [r13, #16 << 2]
+
+	@ Switch to the mode we came from to get r13 and r14.
+	@ If coming from user mode, use System mode instead so we're still
+	@ privileged.
+	and	r1, r1, #0x1f		@ r1 = SPSR mode
+	cmp	r1, #0x10		@ If from User mode
+	moveq	r1, #0x1f		@ Then use System mode instead
+
+	mrs	r3, CPSR		@ r3 = our CPSR
+	bic	r2, r3, #0x1f
+	orr	r2, r2, r1
+	msr	CPSR, r2		@ Change to mode r1
+
+	@ Save old mode's r13, r14
+	str	r13, [r0, #13 << 2]
+	str	r14, [r0, #14 << 2]
+
+	msr	CPSR, r3		@ Back to fault mode
+
+	ldr	r1, [r0, #17 << 2]
+	sub	r1, r1, #12		@ Fix to point at start of handler
+	str	r1, [r0, #17 << 2]
+
+	@ Call C code to format the register dump.
+	@ Clobbers the stack, but we're not going to return anyway.
+	ldr	r13, =stack_end
+	bl	dump_registers
+1:
+	wfi
+	b	1b
+
+@ We want to store a unique value to identify this handler, without corrupting
+@ any of the registers. So, we store r15 (which will point just after the branch).
+@ Later, we subtract 12 so the user gets pointed at the start of the exception
+@ handler.
+#define FAULT(name)			\
+.globl fault_##name;			\
+fault_##name:				\
+	ldr	r13, =fault_dump;	\
+	str	r15, [r13, #17 << 2];	\
+	b	fault
+
+FAULT(reset)
+FAULT(undefined_instruction)
+FAULT(svc)
+FAULT(prefetch_call)
+FAULT(prefetch_abort)
+FAULT(data_abort)
+
 @ exception base address
 .align 5
 .globl exception_vector_table
@@ -99,13 +166,13 @@ irqstack_end:
 @  instruction to clear an existing tag is required on context switches."
 @ -- ARM Cortex-A Series Programmer’s Guide (Version: 4.0)
 exception_vector_table:
-	b	. @ reset
-	b	. @ undefined instruction
-	b	. @ supervisor call
-	b	. @ prefetch call
-	b	. @ prefetch abort
-	b	. @ data abort
-	b	irq_handler @ irq
+	b	fault_reset
+	b	fault_undefined_instruction
+	b	fault_svc
+	b	fault_prefetch_call
+	b	fault_prefetch_abort
+	b	fault_data_abort
+	b	irq_handler @ IRQ
 	.word 0xe7f000f0    @ abort on FIQ
 
 irq_handler:
diff --git a/extras/mini-os/arch/arm/panic.c b/extras/mini-os/arch/arm/panic.c
new file mode 100644
index 0000000..12735d6
--- /dev/null
+++ b/extras/mini-os/arch/arm/panic.c
@@ -0,0 +1,99 @@
+/******************************************************************************
+ * panic.c
+ *
+ * Displays a register dump and stack trace for debugging.
+ *
+ * Copyright (c) 2014, Thomas Leonard
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <mini-os/os.h>
+#include <arch_mm.h>
+
+extern int stack[];
+extern int stack_end[];
+extern int irqstack[];
+extern int irqstack_end[];
+
+typedef void handler(void);
+
+extern handler fault_reset;
+extern handler fault_undefined_instruction;
+extern handler fault_svc;
+extern handler fault_prefetch_call;
+extern handler fault_prefetch_abort;
+extern handler fault_data_abort;
+
+void dump_registers(int *saved_registers) {
+    static int in_dump = 0;
+    int *sp, *stack_top, *x;
+    char *fault_name;
+    void *fault_handler;
+    int i;
+
+    if (in_dump)
+    {
+        printk("Crash while in dump_registers! Not generating a second report.\n");
+        return;
+    }
+
+    in_dump = 1;
+
+    fault_handler = (handler *) saved_registers[17];
+    if (fault_handler == fault_reset)
+        fault_name = "reset";
+    else if (fault_handler == fault_undefined_instruction)
+        fault_name = "undefined_instruction";
+    else if (fault_handler == fault_svc)
+        fault_name = "svc";
+    else if (fault_handler == fault_prefetch_call)
+        fault_name = "prefetch_call";
+    else if (fault_handler == fault_prefetch_abort)
+        fault_name = "prefetch_abort";
+    else if (fault_handler == fault_data_abort)
+        fault_name = "data_abort";
+    else
+        fault_name = "unknown fault type!";
+
+    printk("Fault handler at %x called (%s)\n", fault_handler, fault_name);
+
+    for (i = 0; i < 16; i++) {
+        printk("r%d = %x\n", i, saved_registers[i]);
+    }
+    printk("CPSR = %x\n", saved_registers[16]);
+
+    printk("Stack dump (innermost last)\n");
+    sp = (int *) saved_registers[13];
+
+    if (sp >= stack && sp <= stack_end)
+        stack_top = stack_end;                          /* The small boot stack */
+    else if (sp >= irqstack && sp <= irqstack_end)
+        stack_top = irqstack_end;                       /* The small IRQ stack */
+    else
+        stack_top = (int *) ((((unsigned long) sp) | (__STACK_SIZE-1)) + 1);        /* A normal thread stack */
+
+    for (x = stack_top - 1; x >= sp; x--)
+    {
+        printk("  [%8p] %8x\n", x, *x);
+    }
+    printk("End of stack\n");
+
+    in_dump = 0;
+}
diff --git a/extras/mini-os/include/arm/arch_mm.h b/extras/mini-os/include/arm/arch_mm.h
index be14ada..e943a9b 100644
--- a/extras/mini-os/include/arm/arch_mm.h
+++ b/extras/mini-os/include/arm/arch_mm.h
@@ -2,7 +2,7 @@
 #define _ARCH_MM_H_
 
 extern char _text, _etext, _erodata, _edata, _end, __bss_start;
-extern char stack[];
+extern int stack[];
 
 #define PAGE_SHIFT        12
 #define PAGE_SIZE        (1 << PAGE_SHIFT)
diff --git a/extras/mini-os/include/arm/os.h b/extras/mini-os/include/arm/os.h
index 21e9276..8d76089 100644
--- a/extras/mini-os/include/arm/os.h
+++ b/extras/mini-os/include/arm/os.h
@@ -10,7 +10,7 @@
 void arch_fini(void);
 void timer_handler(evtchn_port_t port, struct pt_regs *regs, void *ign);
 
-#define BUG() while(1){}
+#define BUG() while(1){asm volatile (".word 0xe7f000f0\n");} /* Undefined instruction; will call our fault handler. */
 
 #define smp_processor_id() 0
 
-- 
2.0.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH ARM v4 09/12] mini-os: import libfdt
  2014-06-18 15:08 [PATCH ARM v4 00/12] mini-os: initial ARM support Thomas Leonard
                   ` (7 preceding siblings ...)
  2014-06-18 15:08 ` [PATCH ARM v4 08/12] mini-os: arm: show registers, stack and exception vector on fault Thomas Leonard
@ 2014-06-18 15:08 ` Thomas Leonard
  2014-06-18 18:02   ` Samuel Thibault
  2014-06-18 15:08 ` [PATCH ARM v4 10/12] mini-os: get RAM base and size from the FDT Thomas Leonard
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 41+ messages in thread
From: Thomas Leonard @ 2014-06-18 15:08 UTC (permalink / raw)
  To: xen-devel
  Cc: Thomas Leonard, Dave.Scott, anil, stefano.stabellini, samuel.thibault

From: Karim Raslan <karim.allah.ahmed@gmail.com>

Looks like this is revision v1.3.0-47-gbe60268 from
http://git.jdl.com/gitweb/?p=dtc.git

The memmove implementation is from FreeBSD's
contrib/ldns/compat/memmove.c

Signed-off-by: Karim Allah Ahmed <karim.allah.ahmed@gmail.com>
[talex5@gmail.com: split out FDT support into a separate patch]
[talex5@gmail.com: fixed "make clean" for FDT]
[talex5@gmail.com: replaced GPL memmove with BSD one]
Signed-off-by: Thomas Leonard <talex5@gmail.com>
---
 extras/mini-os/COPYING                   |   27 +
 extras/mini-os/Makefile                  |   11 +
 extras/mini-os/include/fdt.h             |   60 ++
 extras/mini-os/include/lib.h             |    4 +-
 extras/mini-os/include/libfdt.h          | 1478 ++++++++++++++++++++++++++++++
 extras/mini-os/include/libfdt_env.h      |   37 +
 extras/mini-os/lib/fdt/fdt.c             |  222 +++++
 extras/mini-os/lib/fdt/fdt_empty_tree.c  |   84 ++
 extras/mini-os/lib/fdt/fdt_ro.c          |  574 ++++++++++++
 extras/mini-os/lib/fdt/fdt_rw.c          |  492 ++++++++++
 extras/mini-os/lib/fdt/fdt_strerror.c    |   96 ++
 extras/mini-os/lib/fdt/fdt_sw.c          |  256 ++++++
 extras/mini-os/lib/fdt/fdt_wip.c         |  118 +++
 extras/mini-os/lib/fdt/libfdt_internal.h |   95 ++
 extras/mini-os/lib/memmove.c             |   45 +
 extras/mini-os/lib/string.c              |   12 +
 16 files changed, 3610 insertions(+), 1 deletion(-)
 create mode 100644 extras/mini-os/include/fdt.h
 create mode 100644 extras/mini-os/include/libfdt.h
 create mode 100644 extras/mini-os/include/libfdt_env.h
 create mode 100644 extras/mini-os/lib/fdt/fdt.c
 create mode 100644 extras/mini-os/lib/fdt/fdt_empty_tree.c
 create mode 100644 extras/mini-os/lib/fdt/fdt_ro.c
 create mode 100644 extras/mini-os/lib/fdt/fdt_rw.c
 create mode 100644 extras/mini-os/lib/fdt/fdt_strerror.c
 create mode 100644 extras/mini-os/lib/fdt/fdt_sw.c
 create mode 100644 extras/mini-os/lib/fdt/fdt_wip.c
 create mode 100644 extras/mini-os/lib/fdt/libfdt_internal.h
 create mode 100644 extras/mini-os/lib/memmove.c

diff --git a/extras/mini-os/COPYING b/extras/mini-os/COPYING
index 1d9df6c..b676bb6 100644
--- a/extras/mini-os/COPYING
+++ b/extras/mini-os/COPYING
@@ -34,3 +34,30 @@ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 SUCH DAMAGE.
 
+
+Copyright (c) 2005,2006, NLnetLabs
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of NLnetLabs nor the names of its
+      contributors may be used to endorse or promote products derived from this
+      software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/extras/mini-os/Makefile b/extras/mini-os/Makefile
index 535ca68..a16e64f 100644
--- a/extras/mini-os/Makefile
+++ b/extras/mini-os/Makefile
@@ -83,6 +83,16 @@ src-y += drivers/gic.c
 
 # Need libgcc.a for division helpers
 LDLIBS += `$(CC) -print-libgcc-file-name`
+
+# Device tree support
+SUBDIRS += lib/fdt
+src-y += lib/fdt/fdt.c
+src-y += lib/fdt/fdt_empty_tree.c
+src-y += lib/fdt/fdt_ro.c
+src-y += lib/fdt/fdt_rw.c
+src-y += lib/fdt/fdt_strerror.c
+src-y += lib/fdt/fdt_sw.c
+src-y += lib/fdt/fdt_wip.c
 endif
 
 src-$(CONFIG_BLKFRONT) += blkfront.c
@@ -111,6 +121,7 @@ endif
 src-y += lib/printf.c
 src-y += lib/stack_chk_fail.c
 src-y += lib/string.c
+src-y += lib/memmove.c
 src-y += lib/sys.c
 src-y += lib/xmalloc.c
 src-$(CONFIG_XENBUS) += lib/xs.c
diff --git a/extras/mini-os/include/fdt.h b/extras/mini-os/include/fdt.h
new file mode 100644
index 0000000..48ccfd9
--- /dev/null
+++ b/extras/mini-os/include/fdt.h
@@ -0,0 +1,60 @@
+#ifndef _FDT_H
+#define _FDT_H
+
+#ifndef __ASSEMBLY__
+
+struct fdt_header {
+	uint32_t magic;			 /* magic word FDT_MAGIC */
+	uint32_t totalsize;		 /* total size of DT block */
+	uint32_t off_dt_struct;		 /* offset to structure */
+	uint32_t off_dt_strings;	 /* offset to strings */
+	uint32_t off_mem_rsvmap;	 /* offset to memory reserve map */
+	uint32_t version;		 /* format version */
+	uint32_t last_comp_version;	 /* last compatible version */
+
+	/* version 2 fields below */
+	uint32_t boot_cpuid_phys;	 /* Which physical CPU id we're
+					    booting on */
+	/* version 3 fields below */
+	uint32_t size_dt_strings;	 /* size of the strings block */
+
+	/* version 17 fields below */
+	uint32_t size_dt_struct;	 /* size of the structure block */
+};
+
+struct fdt_reserve_entry {
+	uint64_t address;
+	uint64_t size;
+};
+
+struct fdt_node_header {
+	uint32_t tag;
+	char name[0];
+};
+
+struct fdt_property {
+	uint32_t tag;
+	uint32_t len;
+	uint32_t nameoff;
+	char data[0];
+};
+
+#endif /* !__ASSEMBLY */
+
+#define FDT_MAGIC	0xd00dfeed	/* 4: version, 4: total size */
+#define FDT_TAGSIZE	sizeof(uint32_t)
+
+#define FDT_BEGIN_NODE	0x1		/* Start node: full name */
+#define FDT_END_NODE	0x2		/* End node */
+#define FDT_PROP	0x3		/* Property: name off,
+					   size, content */
+#define FDT_NOP		0x4		/* nop */
+#define FDT_END		0x9
+
+#define FDT_V1_SIZE	(7*sizeof(uint32_t))
+#define FDT_V2_SIZE	(FDT_V1_SIZE + sizeof(uint32_t))
+#define FDT_V3_SIZE	(FDT_V2_SIZE + sizeof(uint32_t))
+#define FDT_V16_SIZE	FDT_V3_SIZE
+#define FDT_V17_SIZE	(FDT_V16_SIZE + sizeof(uint32_t))
+
+#endif /* _FDT_H */
diff --git a/extras/mini-os/include/lib.h b/extras/mini-os/include/lib.h
index 670c14f..171f2df 100644
--- a/extras/mini-os/include/lib.h
+++ b/extras/mini-os/include/lib.h
@@ -86,6 +86,7 @@ char	*strncpy(char * __restrict, const char * __restrict, size_t);
 
 char	*strstr(const char *, const char *);
 
+void *memmove(void * dest,const void *src,size_t count);
 void *memset(void *, int, size_t);
 
 char *strchr(const char *p, int ch);
@@ -95,7 +96,8 @@ char *strrchr(const char *p, int ch);
  *	@(#)systm.h	8.7 (Berkeley) 3/29/95
  * $FreeBSD$
  */
-void	*memcpy(void *to, const void *from, size_t len);
+void *memcpy(void *to, const void *from, size_t len);
+void *memchr(const void *s, int c, size_t n);
 
 size_t strnlen(const char *, size_t);
 #endif
diff --git a/extras/mini-os/include/libfdt.h b/extras/mini-os/include/libfdt.h
new file mode 100644
index 0000000..73f4975
--- /dev/null
+++ b/extras/mini-os/include/libfdt.h
@@ -0,0 +1,1478 @@
+#ifndef _LIBFDT_H
+#define _LIBFDT_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <libfdt_env.h>
+#include <fdt.h>
+
+#define FDT_FIRST_SUPPORTED_VERSION	0x10
+#define FDT_LAST_SUPPORTED_VERSION	0x11
+
+/* Error codes: informative error codes */
+#define FDT_ERR_NOTFOUND	1
+	/* FDT_ERR_NOTFOUND: The requested node or property does not exist */
+#define FDT_ERR_EXISTS		2
+	/* FDT_ERR_EXISTS: Attemped to create a node or property which
+	 * already exists */
+#define FDT_ERR_NOSPACE		3
+	/* FDT_ERR_NOSPACE: Operation needed to expand the device
+	 * tree, but its buffer did not have sufficient space to
+	 * contain the expanded tree. Use fdt_open_into() to move the
+	 * device tree to a buffer with more space. */
+
+/* Error codes: codes for bad parameters */
+#define FDT_ERR_BADOFFSET	4
+	/* FDT_ERR_BADOFFSET: Function was passed a structure block
+	 * offset which is out-of-bounds, or which points to an
+	 * unsuitable part of the structure for the operation. */
+#define FDT_ERR_BADPATH		5
+	/* FDT_ERR_BADPATH: Function was passed a badly formatted path
+	 * (e.g. missing a leading / for a function which requires an
+	 * absolute path) */
+#define FDT_ERR_BADPHANDLE	6
+	/* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle
+	 * value.  phandle values of 0 and -1 are not permitted. */
+#define FDT_ERR_BADSTATE	7
+	/* FDT_ERR_BADSTATE: Function was passed an incomplete device
+	 * tree created by the sequential-write functions, which is
+	 * not sufficiently complete for the requested operation. */
+
+/* Error codes: codes for bad device tree blobs */
+#define FDT_ERR_TRUNCATED	8
+	/* FDT_ERR_TRUNCATED: Structure block of the given device tree
+	 * ends without an FDT_END tag. */
+#define FDT_ERR_BADMAGIC	9
+	/* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
+	 * device tree at all - it is missing the flattened device
+	 * tree magic number. */
+#define FDT_ERR_BADVERSION	10
+	/* FDT_ERR_BADVERSION: Given device tree has a version which
+	 * can't be handled by the requested operation.  For
+	 * read-write functions, this may mean that fdt_open_into() is
+	 * required to convert the tree to the expected version. */
+#define FDT_ERR_BADSTRUCTURE	11
+	/* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt
+	 * structure block or other serious error (e.g. misnested
+	 * nodes, or subnodes preceding properties). */
+#define FDT_ERR_BADLAYOUT	12
+	/* FDT_ERR_BADLAYOUT: For read-write functions, the given
+	 * device tree has it's sub-blocks in an order that the
+	 * function can't handle (memory reserve map, then structure,
+	 * then strings).  Use fdt_open_into() to reorganize the tree
+	 * into a form suitable for the read-write operations. */
+
+/* "Can't happen" error indicating a bug in libfdt */
+#define FDT_ERR_INTERNAL	13
+	/* FDT_ERR_INTERNAL: libfdt has failed an internal assertion.
+	 * Should never be returned, if it is, it indicates a bug in
+	 * libfdt itself. */
+
+#define FDT_ERR_MAX		13
+
+/**********************************************************************/
+/* Low-level functions (you probably don't need these)                */
+/**********************************************************************/
+
+const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen);
+static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
+{
+	return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen);
+}
+
+uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
+
+/**********************************************************************/
+/* Traversal functions                                                */
+/**********************************************************************/
+
+int fdt_next_node(const void *fdt, int offset, int *depth);
+
+/**********************************************************************/
+/* General functions                                                  */
+/**********************************************************************/
+
+#define fdt_get_header(fdt, field) \
+	(fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
+#define fdt_magic(fdt) 			(fdt_get_header(fdt, magic))
+#define fdt_totalsize(fdt)		(fdt_get_header(fdt, totalsize))
+#define fdt_off_dt_struct(fdt)		(fdt_get_header(fdt, off_dt_struct))
+#define fdt_off_dt_strings(fdt)		(fdt_get_header(fdt, off_dt_strings))
+#define fdt_off_mem_rsvmap(fdt)		(fdt_get_header(fdt, off_mem_rsvmap))
+#define fdt_version(fdt)		(fdt_get_header(fdt, version))
+#define fdt_last_comp_version(fdt) 	(fdt_get_header(fdt, last_comp_version))
+#define fdt_boot_cpuid_phys(fdt) 	(fdt_get_header(fdt, boot_cpuid_phys))
+#define fdt_size_dt_strings(fdt) 	(fdt_get_header(fdt, size_dt_strings))
+#define fdt_size_dt_struct(fdt)		(fdt_get_header(fdt, size_dt_struct))
+
+#define __fdt_set_hdr(name) \
+	static inline void fdt_set_##name(void *fdt, uint32_t val) \
+	{ \
+		struct fdt_header *fdth = (struct fdt_header*)fdt; \
+		fdth->name = cpu_to_fdt32(val); \
+	}
+__fdt_set_hdr(magic);
+__fdt_set_hdr(totalsize);
+__fdt_set_hdr(off_dt_struct);
+__fdt_set_hdr(off_dt_strings);
+__fdt_set_hdr(off_mem_rsvmap);
+__fdt_set_hdr(version);
+__fdt_set_hdr(last_comp_version);
+__fdt_set_hdr(boot_cpuid_phys);
+__fdt_set_hdr(size_dt_strings);
+__fdt_set_hdr(size_dt_struct);
+#undef __fdt_set_hdr
+
+/**
+ * fdt_check_header - sanity check a device tree or possible device tree
+ * @fdt: pointer to data which might be a flattened device tree
+ *
+ * fdt_check_header() checks that the given buffer contains what
+ * appears to be a flattened device tree with sane information in its
+ * header.
+ *
+ * returns:
+ *     0, if the buffer appears to contain a valid device tree
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings, as above
+ */
+int fdt_check_header(const void *fdt);
+
+/**
+ * fdt_move - move a device tree around in memory
+ * @fdt: pointer to the device tree to move
+ * @buf: pointer to memory where the device is to be moved
+ * @bufsize: size of the memory space at buf
+ *
+ * fdt_move() relocates, if possible, the device tree blob located at
+ * fdt to the buffer at buf of size bufsize.  The buffer may overlap
+ * with the existing device tree blob at fdt.  Therefore,
+ *     fdt_move(fdt, fdt, fdt_totalsize(fdt))
+ * should always succeed.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_move(const void *fdt, void *buf, int bufsize);
+
+/**********************************************************************/
+/* Read-only functions                                                */
+/**********************************************************************/
+
+/**
+ * fdt_string - retrieve a string from the strings block of a device tree
+ * @fdt: pointer to the device tree blob
+ * @stroffset: offset of the string within the strings block (native endian)
+ *
+ * fdt_string() retrieves a pointer to a single string from the
+ * strings block of the device tree blob at fdt.
+ *
+ * returns:
+ *     a pointer to the string, on success
+ *     NULL, if stroffset is out of bounds
+ */
+const char *fdt_string(const void *fdt, int stroffset);
+
+/**
+ * fdt_num_mem_rsv - retrieve the number of memory reserve map entries
+ * @fdt: pointer to the device tree blob
+ *
+ * Returns the number of entries in the device tree blob's memory
+ * reservation map.  This does not include the terminating 0,0 entry
+ * or any other (0,0) entries reserved for expansion.
+ *
+ * returns:
+ *     the number of entries
+ */
+int fdt_num_mem_rsv(const void *fdt);
+
+/**
+ * fdt_get_mem_rsv - retrieve one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: pointers to 64-bit variables
+ *
+ * On success, *address and *size will contain the address and size of
+ * the n-th reserve map entry from the device tree blob, in
+ * native-endian format.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size);
+
+/**
+ * fdt_subnode_offset_namelen - find a subnode based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_subnode_offset(), but only examine the first
+ * namelen characters of name for matching the subnode name.  This is
+ * useful for finding subnodes based on a portion of a larger string,
+ * such as a full path.
+ */
+int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
+			       const char *name, int namelen);
+/**
+ * fdt_subnode_offset - find a subnode of a given node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_subnode_offset() finds a subnode of the node at structure block
+ * offset parentoffset with the given name.  name may include a unit
+ * address, in which case fdt_subnode_offset() will find the subnode
+ * with that unit address, or the unit address may be omitted, in
+ * which case fdt_subnode_offset() will find an arbitrary subnode
+ * whose name excluding unit address matches the given name.
+ *
+ * returns:
+ *	structure block offset of the requested subnode (>=0), on success
+ *	-FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ *	-FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_path_offset - find a tree node by its full path
+ * @fdt: pointer to the device tree blob
+ * @path: full path of the node to locate
+ *
+ * fdt_path_offset() finds a node of a given path in the device tree.
+ * Each path component may omit the unit address portion, but the
+ * results of this are undefined if any such path component is
+ * ambiguous (that is if there are multiple nodes at the relevant
+ * level matching the given component, differentiated only by unit
+ * address).
+ *
+ * returns:
+ *	structure block offset of the node with the requested path (>=0), on success
+ *	-FDT_ERR_BADPATH, given path does not begin with '/' or is invalid
+ *	-FDT_ERR_NOTFOUND, if the requested node does not exist
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_path_offset(const void *fdt, const char *path);
+
+/**
+ * fdt_get_name - retrieve the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the starting node
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_name() retrieves the name (including unit address) of the
+ * device tree node at structure block offset nodeoffset.  If lenp is
+ * non-NULL, the length of this name is also returned, in the integer
+ * pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the node's name, on success
+ *		If lenp is non-NULL, *lenp contains the length of that name (>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL *lenp contains an error code (<0):
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE, standard meanings
+ */
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp);
+
+/**
+ * fdt_first_property_offset - find the offset of a node's first property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ *
+ * fdt_first_property_offset() finds the first property of the node at
+ * the given structure block offset.
+ *
+ * returns:
+ *	structure block offset of the property (>=0), on success
+ *	-FDT_ERR_NOTFOUND, if the requested node has no properties
+ *	-FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_first_property_offset(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_next_property_offset - step through a node's properties
+ * @fdt: pointer to the device tree blob
+ * @offset: structure block offset of a property
+ *
+ * fdt_next_property_offset() finds the property immediately after the
+ * one at the given structure block offset.  This will be a property
+ * of the same node as the given property.
+ *
+ * returns:
+ *	structure block offset of the next property (>=0), on success
+ *	-FDT_ERR_NOTFOUND, if the given property is the last in its node
+ *	-FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_next_property_offset(const void *fdt, int offset);
+
+/**
+ * fdt_get_property_by_offset - retrieve the property at a given offset
+ * @fdt: pointer to the device tree blob
+ * @offset: offset of the property to retrieve
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_property_by_offset() retrieves a pointer to the
+ * fdt_property structure within the device tree blob at the given
+ * offset.  If lenp is non-NULL, the length of the property value is
+ * also returned, in the integer pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the structure representing the property
+ *		if lenp is non-NULL, *lenp contains the length of the property
+ *		value (>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL, *lenp contains an error code (<0):
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE,
+ *		-FDT_ERR_BADSTRUCTURE,
+ *		-FDT_ERR_TRUNCATED, standard meanings
+ */
+const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
+						      int offset,
+						      int *lenp);
+
+/**
+ * fdt_get_property_namelen - find a property based on substring
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @namelen: number of characters of name to consider
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * Identical to fdt_get_property_namelen(), but only examine the first
+ * namelen characters of name for matching the property name.
+ */
+const struct fdt_property *fdt_get_property_namelen(const void *fdt,
+						    int nodeoffset,
+						    const char *name,
+						    int namelen, int *lenp);
+
+/**
+ * fdt_get_property - find a given property in a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_property() retrieves a pointer to the fdt_property
+ * structure within the device tree blob corresponding to the property
+ * named 'name' of the node at offset nodeoffset.  If lenp is
+ * non-NULL, the length of the property value is also returned, in the
+ * integer pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the structure representing the property
+ *		if lenp is non-NULL, *lenp contains the length of the property
+ *		value (>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL, *lenp contains an error code (<0):
+ *		-FDT_ERR_NOTFOUND, node does not have named property
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE,
+ *		-FDT_ERR_BADSTRUCTURE,
+ *		-FDT_ERR_TRUNCATED, standard meanings
+ */
+const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset,
+					    const char *name, int *lenp);
+static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
+						      const char *name,
+						      int *lenp)
+{
+	return (struct fdt_property *)(uintptr_t)
+		fdt_get_property(fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_getprop_by_offset - retrieve the value of a property at a given offset
+ * @fdt: pointer to the device tree blob
+ * @ffset: offset of the property to read
+ * @namep: pointer to a string variable (will be overwritten) or NULL
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop_by_offset() retrieves a pointer to the value of the
+ * property at structure block offset 'offset' (this will be a pointer
+ * to within the device blob itself, not a copy of the value).  If
+ * lenp is non-NULL, the length of the property value is also
+ * returned, in the integer pointed to by lenp.  If namep is non-NULL,
+ * the property's namne will also be returned in the char * pointed to
+ * by namep (this will be a pointer to within the device tree's string
+ * block, not a new copy of the name).
+ *
+ * returns:
+ *	pointer to the property's value
+ *		if lenp is non-NULL, *lenp contains the length of the property
+ *		value (>=0)
+ *		if namep is non-NULL *namep contiains a pointer to the property
+ *		name.
+ *	NULL, on error
+ *		if lenp is non-NULL, *lenp contains an error code (<0):
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE,
+ *		-FDT_ERR_BADSTRUCTURE,
+ *		-FDT_ERR_TRUNCATED, standard meanings
+ */
+const void *fdt_getprop_by_offset(const void *fdt, int offset,
+				  const char **namep, int *lenp);
+
+/**
+ * fdt_getprop_namelen - get property value based on substring
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @namelen: number of characters of name to consider
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * Identical to fdt_getprop(), but only examine the first namelen
+ * characters of name for matching the property name.
+ */
+const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
+				const char *name, int namelen, int *lenp);
+
+/**
+ * fdt_getprop - retrieve the value of a given property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop() retrieves a pointer to the value of the property
+ * named 'name' of the node at offset nodeoffset (this will be a
+ * pointer to within the device blob itself, not a copy of the value).
+ * If lenp is non-NULL, the length of the property value is also
+ * returned, in the integer pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the property's value
+ *		if lenp is non-NULL, *lenp contains the length of the property
+ *		value (>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL, *lenp contains an error code (<0):
+ *		-FDT_ERR_NOTFOUND, node does not have named property
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE,
+ *		-FDT_ERR_BADSTRUCTURE,
+ *		-FDT_ERR_TRUNCATED, standard meanings
+ */
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+			const char *name, int *lenp);
+static inline void *fdt_getprop_w(void *fdt, int nodeoffset,
+				  const char *name, int *lenp)
+{
+	return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_get_phandle - retrieve the phandle of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the node
+ *
+ * fdt_get_phandle() retrieves the phandle of the device tree node at
+ * structure block offset nodeoffset.
+ *
+ * returns:
+ *	the phandle of the node at nodeoffset, on success (!= 0, != -1)
+ *	0, if the node has no phandle, or another error occurs
+ */
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_get_alias_namelen - get alias based on substring
+ * @fdt: pointer to the device tree blob
+ * @name: name of the alias th look up
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_get_alias(), but only examine the first namelen
+ * characters of name for matching the alias name.
+ */
+const char *fdt_get_alias_namelen(const void *fdt,
+				  const char *name, int namelen);
+
+/**
+ * fdt_get_alias - retreive the path referenced by a given alias
+ * @fdt: pointer to the device tree blob
+ * @name: name of the alias th look up
+ *
+ * fdt_get_alias() retrieves the value of a given alias.  That is, the
+ * value of the property named 'name' in the node /aliases.
+ *
+ * returns:
+ *	a pointer to the expansion of the alias named 'name', of it exists
+ *	NULL, if the given alias or the /aliases node does not exist
+ */
+const char *fdt_get_alias(const void *fdt, const char *name);
+
+/**
+ * fdt_get_path - determine the full path of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose path to find
+ * @buf: character buffer to contain the returned path (will be overwritten)
+ * @buflen: size of the character buffer at buf
+ *
+ * fdt_get_path() computes the full path of the node at offset
+ * nodeoffset, and records that path in the buffer at buf.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ *	0, on success
+ *		buf contains the absolute path of the node at
+ *		nodeoffset, as a NUL-terminated string.
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1)
+ *		characters and will not fit in the given buffer.
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen);
+
+/**
+ * fdt_supernode_atdepth_offset - find a specific ancestor of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ * @supernodedepth: depth of the ancestor to find
+ * @nodedepth: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_supernode_atdepth_offset() finds an ancestor of the given node
+ * at a specific depth from the root (where the root itself has depth
+ * 0, its immediate subnodes depth 1 and so forth).  So
+ *	fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL);
+ * will always return 0, the offset of the root node.  If the node at
+ * nodeoffset has depth D, then:
+ *	fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL);
+ * will return nodeoffset itself.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+
+ *	structure block offset of the node at node offset's ancestor
+ *		of depth supernodedepth (>=0), on success
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+*	-FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+				 int supernodedepth, int *nodedepth);
+
+/**
+ * fdt_node_depth - find the depth of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_node_depth() finds the depth of a given node.  The root node
+ * has depth 0, its immediate subnodes depth 1 and so forth.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ *	depth of the node at nodeoffset (>=0), on success
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_depth(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_parent_offset - find the parent of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_parent_offset() locates the parent node of a given node (that
+ * is, it finds the offset of the node which contains the node at
+ * nodeoffset as a subnode).
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset, *twice*.
+ *
+ * returns:
+ *	structure block offset of the parent of the node at nodeoffset
+ *		(>=0), on success
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_parent_offset(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_node_offset_by_prop_value - find nodes with a given property value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @propname: property name to check
+ * @propval: property value to search for
+ * @proplen: length of the value in propval
+ *
+ * fdt_node_offset_by_prop_value() returns the offset of the first
+ * node after startoffset, which has a property named propname whose
+ * value is of length proplen and has value equal to propval; or if
+ * startoffset is -1, the very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ *	offset = fdt_node_offset_by_prop_value(fdt, -1, propname,
+ *					       propval, proplen);
+ *	while (offset != -FDT_ERR_NOTFOUND) {
+ *		// other code here
+ *		offset = fdt_node_offset_by_prop_value(fdt, offset, propname,
+ *						       propval, proplen);
+ *	}
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ *	structure block offset of the located node (>= 0, >startoffset),
+ *		 on success
+ *	-FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ *		tree after startoffset
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+				  const char *propname,
+				  const void *propval, int proplen);
+
+/**
+ * fdt_node_offset_by_phandle - find the node with a given phandle
+ * @fdt: pointer to the device tree blob
+ * @phandle: phandle value
+ *
+ * fdt_node_offset_by_phandle() returns the offset of the node
+ * which has the given phandle value.  If there is more than one node
+ * in the tree with the given phandle (an invalid tree), results are
+ * undefined.
+ *
+ * returns:
+ *	structure block offset of the located node (>= 0), on success
+ *	-FDT_ERR_NOTFOUND, no node with that phandle exists
+ *	-FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1)
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle);
+
+/**
+ * fdt_node_check_compatible: check a node's compatible property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @compatible: string to match against
+ *
+ *
+ * fdt_node_check_compatible() returns 0 if the given node contains a
+ * 'compatible' property with the given string as one of its elements,
+ * it returns non-zero otherwise, or on error.
+ *
+ * returns:
+ *	0, if the node has a 'compatible' property listing the given string
+ *	1, if the node has a 'compatible' property, but it does not list
+ *		the given string
+ *	-FDT_ERR_NOTFOUND, if the given node has no 'compatible' property
+ * 	-FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+			      const char *compatible);
+
+/**
+ * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @compatible: 'compatible' string to match against
+ *
+ * fdt_node_offset_by_compatible() returns the offset of the first
+ * node after startoffset, which has a 'compatible' property which
+ * lists the given compatible string; or if startoffset is -1, the
+ * very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ *	offset = fdt_node_offset_by_compatible(fdt, -1, compatible);
+ *	while (offset != -FDT_ERR_NOTFOUND) {
+ *		// other code here
+ *		offset = fdt_node_offset_by_compatible(fdt, offset, compatible);
+ *	}
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ *	structure block offset of the located node (>= 0, >startoffset),
+ *		 on success
+ *	-FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ *		tree after startoffset
+ * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+				  const char *compatible);
+
+/**********************************************************************/
+/* Write-in-place functions                                           */
+/**********************************************************************/
+
+/**
+ * fdt_setprop_inplace - change a property's value, but not its size
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to replace the property value with
+ * @len: length of the property value
+ *
+ * fdt_setprop_inplace() replaces the value of a given property with
+ * the data in val, of length len.  This function cannot change the
+ * size of a property, and so will only work if len is equal to the
+ * current length of the property.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, if len is not equal to the property's current length
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+			const void *val, int len);
+
+/**
+ * fdt_setprop_inplace_u32 - change the value of a 32-bit integer property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value to replace the property with
+ *
+ * fdt_setprop_inplace_u32() replaces the value of a given property
+ * with the 32-bit integer value in val, converting val to big-endian
+ * if necessary.  This function cannot change the size of a property,
+ * and so will only work if the property already exists and has length
+ * 4.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, if the property's length is not equal to 4
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_inplace_u32(void *fdt, int nodeoffset,
+					  const char *name, uint32_t val)
+{
+	val = cpu_to_fdt32(val);
+	return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val));
+}
+
+/**
+ * fdt_setprop_inplace_u64 - change the value of a 64-bit integer property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 64-bit integer value to replace the property with
+ *
+ * fdt_setprop_inplace_u64() replaces the value of a given property
+ * with the 64-bit integer value in val, converting val to big-endian
+ * if necessary.  This function cannot change the size of a property,
+ * and so will only work if the property already exists and has length
+ * 8.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, if the property's length is not equal to 8
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset,
+					  const char *name, uint64_t val)
+{
+	val = cpu_to_fdt64(val);
+	return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val));
+}
+
+/**
+ * fdt_setprop_inplace_cell - change the value of a single-cell property
+ *
+ * This is an alternative name for fdt_setprop_inplace_u32()
+ */
+static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset,
+					   const char *name, uint32_t val)
+{
+	return fdt_setprop_inplace_u32(fdt, nodeoffset, name, val);
+}
+
+/**
+ * fdt_nop_property - replace a property with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_nop_property() will replace a given property's representation
+ * in the blob with FDT_NOP tags, effectively removing it from the
+ * tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the property, and will not alter or move any other part of the
+ * tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_nop_node - replace a node (subtree) with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_nop_node() will replace a given node's representation in the
+ * blob, including all its subnodes, if any, with FDT_NOP tags,
+ * effectively removing it from the tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the node and its properties and subnodes, and will not alter or
+ * move any other part of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_node(void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Sequential write functions                                         */
+/**********************************************************************/
+
+int fdt_create(void *buf, int bufsize);
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
+int fdt_finish_reservemap(void *fdt);
+int fdt_begin_node(void *fdt, const char *name);
+int fdt_property(void *fdt, const char *name, const void *val, int len);
+static inline int fdt_property_u32(void *fdt, const char *name, uint32_t val)
+{
+	val = cpu_to_fdt32(val);
+	return fdt_property(fdt, name, &val, sizeof(val));
+}
+static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val)
+{
+	val = cpu_to_fdt64(val);
+	return fdt_property(fdt, name, &val, sizeof(val));
+}
+static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
+{
+	return fdt_property_u32(fdt, name, val);
+}
+#define fdt_property_string(fdt, name, str) \
+	fdt_property(fdt, name, str, strlen(str)+1)
+int fdt_end_node(void *fdt);
+int fdt_finish(void *fdt);
+
+/**********************************************************************/
+/* Read-write functions                                               */
+/**********************************************************************/
+
+int fdt_create_empty_tree(void *buf, int bufsize);
+int fdt_open_into(const void *fdt, void *buf, int bufsize);
+int fdt_pack(void *fdt);
+
+/**
+ * fdt_add_mem_rsv - add one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: 64-bit values (native endian)
+ *
+ * Adds a reserve map entry to the given blob reserving a region at
+ * address address of length size.
+ *
+ * This function will insert data into the reserve map and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new reservation entry
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size);
+
+/**
+ * fdt_del_mem_rsv - remove a memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @n: entry to remove
+ *
+ * fdt_del_mem_rsv() removes the n-th memory reserve map entry from
+ * the blob.
+ *
+ * This function will delete data from the reservation table and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there
+ *		are less than n+1 reserve map entries)
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_mem_rsv(void *fdt, int n);
+
+/**
+ * fdt_set_name - change the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ * @name: name to give the node
+ *
+ * fdt_set_name() replaces the name (including unit address, if any)
+ * of the given node with the given string.  NOTE: this function can't
+ * efficiently check if the new name is unique amongst the given
+ * node's siblings; results are undefined if this function is invoked
+ * with a name equal to one of the given node's siblings.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob
+ *		to contain the new name
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_set_name(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_setprop - create or change a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to set the property value to
+ * @len: length of the property value
+ *
+ * fdt_setprop() sets the value of the named property in the given
+ * node to the given value and length, creating the property if it
+ * does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+		const void *val, int len);
+
+/**
+ * fdt_setprop_u32 - set a property to a 32-bit integer
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value for the property (native endian)
+ *
+ * fdt_setprop_u32() sets the value of the named property in the given
+ * node to the given 32-bit integer value (converting to big-endian if
+ * necessary), or creates a new property with that value if it does
+ * not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name,
+				  uint32_t val)
+{
+	val = cpu_to_fdt32(val);
+	return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val));
+}
+
+/**
+ * fdt_setprop_u64 - set a property to a 64-bit integer
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 64-bit integer value for the property (native endian)
+ *
+ * fdt_setprop_u64() sets the value of the named property in the given
+ * node to the given 64-bit integer value (converting to big-endian if
+ * necessary), or creates a new property with that value if it does
+ * not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name,
+				  uint64_t val)
+{
+	val = cpu_to_fdt64(val);
+	return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val));
+}
+
+/**
+ * fdt_setprop_cell - set a property to a single cell value
+ *
+ * This is an alternative name for fdt_setprop_u32()
+ */
+static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
+				   uint32_t val)
+{
+	return fdt_setprop_u32(fdt, nodeoffset, name, val);
+}
+
+/**
+ * fdt_setprop_string - set a property to a string value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @str: string value for the property
+ *
+ * fdt_setprop_string() sets the value of the named property in the
+ * given node to the given string value (using the length of the
+ * string to determine the new length of the property), or creates a
+ * new property with that value if it does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+#define fdt_setprop_string(fdt, nodeoffset, name, str) \
+	fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+
+/**
+ * fdt_appendprop - append to or create a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to append to
+ * @val: pointer to data to append to the property value
+ * @len: length of the data to append to the property value
+ *
+ * fdt_appendprop() appends the value to the named property in the
+ * given node, creating the property if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
+		   const void *val, int len);
+
+/**
+ * fdt_appendprop_u32 - append a 32-bit integer value to a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value to append to the property (native endian)
+ *
+ * fdt_appendprop_u32() appends the given 32-bit integer value
+ * (converting to big-endian if necessary) to the value of the named
+ * property in the given node, or creates a new property with that
+ * value if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_appendprop_u32(void *fdt, int nodeoffset,
+				     const char *name, uint32_t val)
+{
+	val = cpu_to_fdt32(val);
+	return fdt_appendprop(fdt, nodeoffset, name, &val, sizeof(val));
+}
+
+/**
+ * fdt_appendprop_u64 - append a 64-bit integer value to a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 64-bit integer value to append to the property (native endian)
+ *
+ * fdt_appendprop_u64() appends the given 64-bit integer value
+ * (converting to big-endian if necessary) to the value of the named
+ * property in the given node, or creates a new property with that
+ * value if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_appendprop_u64(void *fdt, int nodeoffset,
+				     const char *name, uint64_t val)
+{
+	val = cpu_to_fdt64(val);
+	return fdt_appendprop(fdt, nodeoffset, name, &val, sizeof(val));
+}
+
+/**
+ * fdt_appendprop_cell - append a single cell value to a property
+ *
+ * This is an alternative name for fdt_appendprop_u32()
+ */
+static inline int fdt_appendprop_cell(void *fdt, int nodeoffset,
+				      const char *name, uint32_t val)
+{
+	return fdt_appendprop_u32(fdt, nodeoffset, name, val);
+}
+
+/**
+ * fdt_appendprop_string - append a string to a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @str: string value to append to the property
+ *
+ * fdt_appendprop_string() appends the given string to the value of
+ * the named property in the given node, or creates a new property
+ * with that value if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+#define fdt_appendprop_string(fdt, nodeoffset, name, str) \
+	fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+
+/**
+ * fdt_delprop - delete a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_del_property() will delete the given property.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_delprop(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_add_subnode_namelen - creates a new node based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_add_subnode(), but use only the first namelen
+ * characters of name as the name of the new node.  This is useful for
+ * creating subnodes based on a portion of a larger string, such as a
+ * full path.
+ */
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+			    const char *name, int namelen);
+
+/**
+ * fdt_add_subnode - creates a new node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_add_subnode() creates a new node as a subnode of the node at
+ * structure block offset parentoffset, with the given name (which
+ * should include the unit address, if any).
+ *
+ * This function will insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+
+ * returns:
+ *	structure block offset of the created nodeequested subnode (>=0), on success
+ *	-FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ *	-FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ *	-FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of
+ *		the given name
+ *	-FDT_ERR_NOSPACE, if there is insufficient free space in the
+ *		blob to contain the new node
+ *	-FDT_ERR_NOSPACE
+ *	-FDT_ERR_BADLAYOUT
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_del_node - delete a node (subtree)
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_del_node() will remove the given node, including all its
+ * subnodes if any, from the blob.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_node(void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Debugging / informational functions                                */
+/**********************************************************************/
+
+const char *fdt_strerror(int errval);
+
+#endif /* _LIBFDT_H */
diff --git a/extras/mini-os/include/libfdt_env.h b/extras/mini-os/include/libfdt_env.h
new file mode 100644
index 0000000..f91f137
--- /dev/null
+++ b/extras/mini-os/include/libfdt_env.h
@@ -0,0 +1,37 @@
+#ifndef _LIBFDT_ENV_H
+#define _LIBFDT_ENV_H
+
+#ifdef _KERNEL
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/stdint.h>
+#else
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#endif
+
+#define EXTRACT_BYTE(n)	((unsigned long long)((uint8_t *)&x)[n])
+static inline uint16_t fdt16_to_cpu(uint16_t x)
+{
+	return (EXTRACT_BYTE(0) << 8) | EXTRACT_BYTE(1);
+}
+#define cpu_to_fdt16(x) fdt16_to_cpu(x)
+
+static inline uint32_t fdt32_to_cpu(uint32_t x)
+{
+	return (EXTRACT_BYTE(0) << 24) | (EXTRACT_BYTE(1) << 16) | (EXTRACT_BYTE(2) << 8) | EXTRACT_BYTE(3);
+}
+#define cpu_to_fdt32(x) fdt32_to_cpu(x)
+
+static inline uint64_t fdt64_to_cpu(uint64_t x)
+{
+	return (EXTRACT_BYTE(0) << 56) | (EXTRACT_BYTE(1) << 48) | (EXTRACT_BYTE(2) << 40) | (EXTRACT_BYTE(3) << 32)
+		| (EXTRACT_BYTE(4) << 24) | (EXTRACT_BYTE(5) << 16) | (EXTRACT_BYTE(6) << 8) | EXTRACT_BYTE(7);
+}
+#define cpu_to_fdt64(x) fdt64_to_cpu(x)
+#undef EXTRACT_BYTE
+
+#endif /* _LIBFDT_ENV_H */
diff --git a/extras/mini-os/lib/fdt/fdt.c b/extras/mini-os/lib/fdt/fdt.c
new file mode 100644
index 0000000..e56833a
--- /dev/null
+++ b/extras/mini-os/lib/fdt/fdt.c
@@ -0,0 +1,222 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+int fdt_check_header(const void *fdt)
+{
+	if (fdt_magic(fdt) == FDT_MAGIC) {
+		/* Complete tree */
+		if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
+			return -FDT_ERR_BADVERSION;
+		if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
+			return -FDT_ERR_BADVERSION;
+	} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
+		/* Unfinished sequential-write blob */
+		if (fdt_size_dt_struct(fdt) == 0)
+			return -FDT_ERR_BADSTATE;
+	} else {
+		return -FDT_ERR_BADMAGIC;
+	}
+
+	return 0;
+}
+
+const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
+{
+	const char *p;
+
+	if (fdt_version(fdt) >= 0x11)
+		if (((offset + len) < offset)
+		    || ((offset + len) > fdt_size_dt_struct(fdt)))
+			return NULL;
+
+	p = _fdt_offset_ptr(fdt, offset);
+
+	if (p + len < p)
+		return NULL;
+	return p;
+}
+
+uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
+{
+	const uint32_t *tagp, *lenp;
+	uint32_t tag;
+	int offset = startoffset;
+	const char *p;
+
+	*nextoffset = -FDT_ERR_TRUNCATED;
+	tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
+	if (!tagp)
+		return FDT_END; /* premature end */
+	tag = fdt32_to_cpu(*tagp);
+	offset += FDT_TAGSIZE;
+
+	*nextoffset = -FDT_ERR_BADSTRUCTURE;
+	switch (tag) {
+	case FDT_BEGIN_NODE:
+		/* skip name */
+		do {
+			p = fdt_offset_ptr(fdt, offset++, 1);
+		} while (p && (*p != '\0'));
+		if (!p)
+			return FDT_END; /* premature end */
+		break;
+
+	case FDT_PROP:
+		lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
+		if (!lenp)
+			return FDT_END; /* premature end */
+		/* skip-name offset, length and value */
+		offset += sizeof(struct fdt_property) - FDT_TAGSIZE
+			+ fdt32_to_cpu(*lenp);
+		break;
+
+	case FDT_END:
+	case FDT_END_NODE:
+	case FDT_NOP:
+		break;
+
+	default:
+		return FDT_END;
+	}
+
+	if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
+		return FDT_END; /* premature end */
+
+	*nextoffset = FDT_TAGALIGN(offset);
+	return tag;
+}
+
+int _fdt_check_node_offset(const void *fdt, int offset)
+{
+	if ((offset < 0) || (offset % FDT_TAGSIZE)
+	    || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
+		return -FDT_ERR_BADOFFSET;
+
+	return offset;
+}
+
+int _fdt_check_prop_offset(const void *fdt, int offset)
+{
+	if ((offset < 0) || (offset % FDT_TAGSIZE)
+	    || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
+		return -FDT_ERR_BADOFFSET;
+
+	return offset;
+}
+
+int fdt_next_node(const void *fdt, int offset, int *depth)
+{
+	int nextoffset = 0;
+	uint32_t tag;
+
+	if (offset >= 0)
+		if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)
+			return nextoffset;
+
+	do {
+		offset = nextoffset;
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+		switch (tag) {
+		case FDT_PROP:
+		case FDT_NOP:
+			break;
+
+		case FDT_BEGIN_NODE:
+			if (depth)
+				(*depth)++;
+			break;
+
+		case FDT_END_NODE:
+			if (depth && ((--(*depth)) < 0))
+				return nextoffset;
+			break;
+
+		case FDT_END:
+			if ((nextoffset >= 0)
+			    || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth))
+				return -FDT_ERR_NOTFOUND;
+			else
+				return nextoffset;
+		}
+	} while (tag != FDT_BEGIN_NODE);
+
+	return offset;
+}
+
+const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
+{
+	int len = strlen(s) + 1;
+	const char *last = strtab + tabsize - len;
+	const char *p;
+
+	for (p = strtab; p <= last; p++)
+		if (memcmp(p, s, len) == 0)
+			return p;
+	return NULL;
+}
+
+int fdt_move(const void *fdt, void *buf, int bufsize)
+{
+	FDT_CHECK_HEADER(fdt);
+
+	if (fdt_totalsize(fdt) > bufsize)
+		return -FDT_ERR_NOSPACE;
+
+	memmove(buf, fdt, fdt_totalsize(fdt));
+	return 0;
+}
diff --git a/extras/mini-os/lib/fdt/fdt_empty_tree.c b/extras/mini-os/lib/fdt/fdt_empty_tree.c
new file mode 100644
index 0000000..f72d13b
--- /dev/null
+++ b/extras/mini-os/lib/fdt/fdt_empty_tree.c
@@ -0,0 +1,84 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2012 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+int fdt_create_empty_tree(void *buf, int bufsize)
+{
+	int err;
+
+	err = fdt_create(buf, bufsize);
+	if (err)
+		return err;
+
+	err = fdt_finish_reservemap(buf);
+	if (err)
+		return err;
+
+	err = fdt_begin_node(buf, "");
+	if (err)
+		return err;
+
+	err =  fdt_end_node(buf);
+	if (err)
+		return err;
+
+	err = fdt_finish(buf);
+	if (err)
+		return err;
+
+	return fdt_open_into(buf, buf, bufsize);
+}
+
diff --git a/extras/mini-os/lib/fdt/fdt_ro.c b/extras/mini-os/lib/fdt/fdt_ro.c
new file mode 100644
index 0000000..02b6d68
--- /dev/null
+++ b/extras/mini-os/lib/fdt/fdt_ro.c
@@ -0,0 +1,574 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int _fdt_nodename_eq(const void *fdt, int offset,
+			    const char *s, int len)
+{
+	const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
+
+	if (! p)
+		/* short match */
+		return 0;
+
+	if (memcmp(p, s, len) != 0)
+		return 0;
+
+	if (p[len] == '\0')
+		return 1;
+	else if (!memchr(s, '@', len) && (p[len] == '@'))
+		return 1;
+	else
+		return 0;
+}
+
+const char *fdt_string(const void *fdt, int stroffset)
+{
+	return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
+}
+
+static int _fdt_string_eq(const void *fdt, int stroffset,
+			  const char *s, int len)
+{
+	const char *p = fdt_string(fdt, stroffset);
+
+	return (strlen(p) == len) && (memcmp(p, s, len) == 0);
+}
+
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
+{
+	FDT_CHECK_HEADER(fdt);
+	*address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
+	*size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
+	return 0;
+}
+
+int fdt_num_mem_rsv(const void *fdt)
+{
+	int i = 0;
+
+	while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
+		i++;
+	return i;
+}
+
+static int _nextprop(const void *fdt, int offset)
+{
+	uint32_t tag;
+	int nextoffset;
+
+	do {
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+		switch (tag) {
+		case FDT_END:
+			if (nextoffset >= 0)
+				return -FDT_ERR_BADSTRUCTURE;
+			else
+				return nextoffset;
+
+		case FDT_PROP:
+			return offset;
+		}
+		offset = nextoffset;
+	} while (tag == FDT_NOP);
+
+	return -FDT_ERR_NOTFOUND;
+}
+
+int fdt_subnode_offset_namelen(const void *fdt, int offset,
+			       const char *name, int namelen)
+{
+	int depth;
+
+	FDT_CHECK_HEADER(fdt);
+
+	for (depth = 0;
+	     (offset >= 0) && (depth >= 0);
+	     offset = fdt_next_node(fdt, offset, &depth))
+		if ((depth == 1)
+		    && _fdt_nodename_eq(fdt, offset, name, namelen))
+			return offset;
+
+	if (depth < 0)
+		return -FDT_ERR_NOTFOUND;
+	return offset; /* error */
+}
+
+int fdt_subnode_offset(const void *fdt, int parentoffset,
+		       const char *name)
+{
+	return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_path_offset(const void *fdt, const char *path)
+{
+	const char *end = path + strlen(path);
+	const char *p = path;
+	int offset = 0;
+
+	FDT_CHECK_HEADER(fdt);
+
+	/* see if we have an alias */
+	if (*path != '/') {
+		const char *q = strchr(path, '/');
+
+		if (!q)
+			q = end;
+
+		p = fdt_get_alias_namelen(fdt, p, q - p);
+		if (!p)
+			return -FDT_ERR_BADPATH;
+		offset = fdt_path_offset(fdt, p);
+
+		p = q;
+	}
+
+	while (*p) {
+		const char *q;
+
+		while (*p == '/')
+			p++;
+		if (! *p)
+			return offset;
+		q = strchr(p, '/');
+		if (! q)
+			q = end;
+
+		offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
+		if (offset < 0)
+			return offset;
+
+		p = q;
+	}
+
+	return offset;
+}
+
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
+{
+	const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
+	int err;
+
+	if (((err = fdt_check_header(fdt)) != 0)
+	    || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
+			goto fail;
+
+	if (len)
+		*len = strlen(nh->name);
+
+	return nh->name;
+
+ fail:
+	if (len)
+		*len = err;
+	return NULL;
+}
+
+int fdt_first_property_offset(const void *fdt, int nodeoffset)
+{
+	int offset;
+
+	if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
+		return offset;
+
+	return _nextprop(fdt, offset);
+}
+
+int fdt_next_property_offset(const void *fdt, int offset)
+{
+	if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0)
+		return offset;
+
+	return _nextprop(fdt, offset);
+}
+
+const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
+						      int offset,
+						      int *lenp)
+{
+	int err;
+	const struct fdt_property *prop;
+
+	if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) {
+		if (lenp)
+			*lenp = err;
+		return NULL;
+	}
+
+	prop = _fdt_offset_ptr(fdt, offset);
+
+	if (lenp)
+		*lenp = fdt32_to_cpu(prop->len);
+
+	return prop;
+}
+
+const struct fdt_property *fdt_get_property_namelen(const void *fdt,
+						    int offset,
+						    const char *name,
+						    int namelen, int *lenp)
+{
+	for (offset = fdt_first_property_offset(fdt, offset);
+	     (offset >= 0);
+	     (offset = fdt_next_property_offset(fdt, offset))) {
+		const struct fdt_property *prop;
+
+		if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) {
+			offset = -FDT_ERR_INTERNAL;
+			break;
+		}
+		if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
+				   name, namelen))
+			return prop;
+	}
+
+	if (lenp)
+		*lenp = offset;
+	return NULL;
+}
+
+const struct fdt_property *fdt_get_property(const void *fdt,
+					    int nodeoffset,
+					    const char *name, int *lenp)
+{
+	return fdt_get_property_namelen(fdt, nodeoffset, name,
+					strlen(name), lenp);
+}
+
+const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
+				const char *name, int namelen, int *lenp)
+{
+	const struct fdt_property *prop;
+
+	prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
+	if (! prop)
+		return NULL;
+
+	return prop->data;
+}
+
+const void *fdt_getprop_by_offset(const void *fdt, int offset,
+				  const char **namep, int *lenp)
+{
+	const struct fdt_property *prop;
+
+	prop = fdt_get_property_by_offset(fdt, offset, lenp);
+	if (!prop)
+		return NULL;
+	if (namep)
+		*namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+	return prop->data;
+}
+
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+			const char *name, int *lenp)
+{
+	return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
+}
+
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
+{
+	const uint32_t *php;
+	int len;
+
+	/* FIXME: This is a bit sub-optimal, since we potentially scan
+	 * over all the properties twice. */
+	php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
+	if (!php || (len != sizeof(*php))) {
+		php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
+		if (!php || (len != sizeof(*php)))
+			return 0;
+	}
+
+	return fdt32_to_cpu(*php);
+}
+
+const char *fdt_get_alias_namelen(const void *fdt,
+				  const char *name, int namelen)
+{
+	int aliasoffset;
+
+	aliasoffset = fdt_path_offset(fdt, "/aliases");
+	if (aliasoffset < 0)
+		return NULL;
+
+	return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
+}
+
+const char *fdt_get_alias(const void *fdt, const char *name)
+{
+	return fdt_get_alias_namelen(fdt, name, strlen(name));
+}
+
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
+{
+	int pdepth = 0, p = 0;
+	int offset, depth, namelen;
+	const char *name;
+
+	FDT_CHECK_HEADER(fdt);
+
+	if (buflen < 2)
+		return -FDT_ERR_NOSPACE;
+
+	for (offset = 0, depth = 0;
+	     (offset >= 0) && (offset <= nodeoffset);
+	     offset = fdt_next_node(fdt, offset, &depth)) {
+		while (pdepth > depth) {
+			do {
+				p--;
+			} while (buf[p-1] != '/');
+			pdepth--;
+		}
+
+		if (pdepth >= depth) {
+			name = fdt_get_name(fdt, offset, &namelen);
+			if (!name)
+				return namelen;
+			if ((p + namelen + 1) <= buflen) {
+				memcpy(buf + p, name, namelen);
+				p += namelen;
+				buf[p++] = '/';
+				pdepth++;
+			}
+		}
+
+		if (offset == nodeoffset) {
+			if (pdepth < (depth + 1))
+				return -FDT_ERR_NOSPACE;
+
+			if (p > 1) /* special case so that root path is "/", not "" */
+				p--;
+			buf[p] = '\0';
+			return 0;
+		}
+	}
+
+	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+		return -FDT_ERR_BADOFFSET;
+	else if (offset == -FDT_ERR_BADOFFSET)
+		return -FDT_ERR_BADSTRUCTURE;
+
+	return offset; /* error from fdt_next_node() */
+}
+
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+				 int supernodedepth, int *nodedepth)
+{
+	int offset, depth;
+	int supernodeoffset = -FDT_ERR_INTERNAL;
+
+	FDT_CHECK_HEADER(fdt);
+
+	if (supernodedepth < 0)
+		return -FDT_ERR_NOTFOUND;
+
+	for (offset = 0, depth = 0;
+	     (offset >= 0) && (offset <= nodeoffset);
+	     offset = fdt_next_node(fdt, offset, &depth)) {
+		if (depth == supernodedepth)
+			supernodeoffset = offset;
+
+		if (offset == nodeoffset) {
+			if (nodedepth)
+				*nodedepth = depth;
+
+			if (supernodedepth > depth)
+				return -FDT_ERR_NOTFOUND;
+			else
+				return supernodeoffset;
+		}
+	}
+
+	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+		return -FDT_ERR_BADOFFSET;
+	else if (offset == -FDT_ERR_BADOFFSET)
+		return -FDT_ERR_BADSTRUCTURE;
+
+	return offset; /* error from fdt_next_node() */
+}
+
+int fdt_node_depth(const void *fdt, int nodeoffset)
+{
+	int nodedepth;
+	int err;
+
+	err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
+	if (err)
+		return (err < 0) ? err : -FDT_ERR_INTERNAL;
+	return nodedepth;
+}
+
+int fdt_parent_offset(const void *fdt, int nodeoffset)
+{
+	int nodedepth = fdt_node_depth(fdt, nodeoffset);
+
+	if (nodedepth < 0)
+		return nodedepth;
+	return fdt_supernode_atdepth_offset(fdt, nodeoffset,
+					    nodedepth - 1, NULL);
+}
+
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+				  const char *propname,
+				  const void *propval, int proplen)
+{
+	int offset;
+	const void *val;
+	int len;
+
+	FDT_CHECK_HEADER(fdt);
+
+	/* FIXME: The algorithm here is pretty horrible: we scan each
+	 * property of a node in fdt_getprop(), then if that didn't
+	 * find what we want, we scan over them again making our way
+	 * to the next node.  Still it's the easiest to implement
+	 * approach; performance can come later. */
+	for (offset = fdt_next_node(fdt, startoffset, NULL);
+	     offset >= 0;
+	     offset = fdt_next_node(fdt, offset, NULL)) {
+		val = fdt_getprop(fdt, offset, propname, &len);
+		if (val && (len == proplen)
+		    && (memcmp(val, propval, len) == 0))
+			return offset;
+	}
+
+	return offset; /* error from fdt_next_node() */
+}
+
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
+{
+	int offset;
+
+	if ((phandle == 0) || (phandle == -1))
+		return -FDT_ERR_BADPHANDLE;
+
+	FDT_CHECK_HEADER(fdt);
+
+	/* FIXME: The algorithm here is pretty horrible: we
+	 * potentially scan each property of a node in
+	 * fdt_get_phandle(), then if that didn't find what
+	 * we want, we scan over them again making our way to the next
+	 * node.  Still it's the easiest to implement approach;
+	 * performance can come later. */
+	for (offset = fdt_next_node(fdt, -1, NULL);
+	     offset >= 0;
+	     offset = fdt_next_node(fdt, offset, NULL)) {
+		if (fdt_get_phandle(fdt, offset) == phandle)
+			return offset;
+	}
+
+	return offset; /* error from fdt_next_node() */
+}
+
+static int _fdt_stringlist_contains(const char *strlist, int listlen,
+				    const char *str)
+{
+	int len = strlen(str);
+	const char *p;
+
+	while (listlen >= len) {
+		if (memcmp(str, strlist, len+1) == 0)
+			return 1;
+		p = memchr(strlist, '\0', listlen);
+		if (!p)
+			return 0; /* malformed strlist.. */
+		listlen -= (p-strlist) + 1;
+		strlist = p + 1;
+	}
+	return 0;
+}
+
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+			      const char *compatible)
+{
+	const void *prop;
+	int len;
+
+	prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
+	if (!prop)
+		return len;
+	if (_fdt_stringlist_contains(prop, len, compatible))
+		return 0;
+	else
+		return 1;
+}
+
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+				  const char *compatible)
+{
+	int offset, err;
+
+	FDT_CHECK_HEADER(fdt);
+
+	/* FIXME: The algorithm here is pretty horrible: we scan each
+	 * property of a node in fdt_node_check_compatible(), then if
+	 * that didn't find what we want, we scan over them again
+	 * making our way to the next node.  Still it's the easiest to
+	 * implement approach; performance can come later. */
+	for (offset = fdt_next_node(fdt, startoffset, NULL);
+	     offset >= 0;
+	     offset = fdt_next_node(fdt, offset, NULL)) {
+		err = fdt_node_check_compatible(fdt, offset, compatible);
+		if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
+			return err;
+		else if (err == 0)
+			return offset;
+	}
+
+	return offset; /* error from fdt_next_node() */
+}
diff --git a/extras/mini-os/lib/fdt/fdt_rw.c b/extras/mini-os/lib/fdt/fdt_rw.c
new file mode 100644
index 0000000..24437df
--- /dev/null
+++ b/extras/mini-os/lib/fdt/fdt_rw.c
@@ -0,0 +1,492 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int _fdt_blocks_misordered(const void *fdt,
+			      int mem_rsv_size, int struct_size)
+{
+	return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
+		|| (fdt_off_dt_struct(fdt) <
+		    (fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
+		|| (fdt_off_dt_strings(fdt) <
+		    (fdt_off_dt_struct(fdt) + struct_size))
+		|| (fdt_totalsize(fdt) <
+		    (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
+}
+
+static int _fdt_rw_check_header(void *fdt)
+{
+	FDT_CHECK_HEADER(fdt);
+
+	if (fdt_version(fdt) < 17)
+		return -FDT_ERR_BADVERSION;
+	if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
+				   fdt_size_dt_struct(fdt)))
+		return -FDT_ERR_BADLAYOUT;
+	if (fdt_version(fdt) > 17)
+		fdt_set_version(fdt, 17);
+
+	return 0;
+}
+
+#define FDT_RW_CHECK_HEADER(fdt) \
+	{ \
+		int err; \
+		if ((err = _fdt_rw_check_header(fdt)) != 0) \
+			return err; \
+	}
+
+static inline int _fdt_data_size(void *fdt)
+{
+	return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+}
+
+static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen)
+{
+	char *p = splicepoint;
+	char *end = (char *)fdt + _fdt_data_size(fdt);
+
+	if (((p + oldlen) < p) || ((p + oldlen) > end))
+		return -FDT_ERR_BADOFFSET;
+	if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
+		return -FDT_ERR_NOSPACE;
+	memmove(p + newlen, p + oldlen, end - p - oldlen);
+	return 0;
+}
+
+static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
+			       int oldn, int newn)
+{
+	int delta = (newn - oldn) * sizeof(*p);
+	int err;
+	err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
+	if (err)
+		return err;
+	fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
+	fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+	return 0;
+}
+
+static int _fdt_splice_struct(void *fdt, void *p,
+			      int oldlen, int newlen)
+{
+	int delta = newlen - oldlen;
+	int err;
+
+	if ((err = _fdt_splice(fdt, p, oldlen, newlen)))
+		return err;
+
+	fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
+	fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+	return 0;
+}
+
+static int _fdt_splice_string(void *fdt, int newlen)
+{
+	void *p = (char *)fdt
+		+ fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+	int err;
+
+	if ((err = _fdt_splice(fdt, p, 0, newlen)))
+		return err;
+
+	fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
+	return 0;
+}
+
+static int _fdt_find_add_string(void *fdt, const char *s)
+{
+	char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
+	const char *p;
+	char *new;
+	int len = strlen(s) + 1;
+	int err;
+
+	p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s);
+	if (p)
+		/* found it */
+		return (p - strtab);
+
+	new = strtab + fdt_size_dt_strings(fdt);
+	err = _fdt_splice_string(fdt, len);
+	if (err)
+		return err;
+
+	memcpy(new, s, len);
+	return (new - strtab);
+}
+
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
+{
+	struct fdt_reserve_entry *re;
+	int err;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
+	err = _fdt_splice_mem_rsv(fdt, re, 0, 1);
+	if (err)
+		return err;
+
+	re->address = cpu_to_fdt64(address);
+	re->size = cpu_to_fdt64(size);
+	return 0;
+}
+
+int fdt_del_mem_rsv(void *fdt, int n)
+{
+	struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
+	int err;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	if (n >= fdt_num_mem_rsv(fdt))
+		return -FDT_ERR_NOTFOUND;
+
+	err = _fdt_splice_mem_rsv(fdt, re, 1, 0);
+	if (err)
+		return err;
+	return 0;
+}
+
+static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
+				int len, struct fdt_property **prop)
+{
+	int oldlen;
+	int err;
+
+	*prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
+	if (! (*prop))
+		return oldlen;
+
+	if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
+				      FDT_TAGALIGN(len))))
+		return err;
+
+	(*prop)->len = cpu_to_fdt32(len);
+	return 0;
+}
+
+static int _fdt_add_property(void *fdt, int nodeoffset, const char *name,
+			     int len, struct fdt_property **prop)
+{
+	int proplen;
+	int nextoffset;
+	int namestroff;
+	int err;
+
+	if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
+		return nextoffset;
+
+	namestroff = _fdt_find_add_string(fdt, name);
+	if (namestroff < 0)
+		return namestroff;
+
+	*prop = _fdt_offset_ptr_w(fdt, nextoffset);
+	proplen = sizeof(**prop) + FDT_TAGALIGN(len);
+
+	err = _fdt_splice_struct(fdt, *prop, 0, proplen);
+	if (err)
+		return err;
+
+	(*prop)->tag = cpu_to_fdt32(FDT_PROP);
+	(*prop)->nameoff = cpu_to_fdt32(namestroff);
+	(*prop)->len = cpu_to_fdt32(len);
+	return 0;
+}
+
+int fdt_set_name(void *fdt, int nodeoffset, const char *name)
+{
+	char *namep;
+	int oldlen, newlen;
+	int err;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
+	if (!namep)
+		return oldlen;
+
+	newlen = strlen(name);
+
+	err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1),
+				 FDT_TAGALIGN(newlen+1));
+	if (err)
+		return err;
+
+	memcpy(namep, name, newlen+1);
+	return 0;
+}
+
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+		const void *val, int len)
+{
+	struct fdt_property *prop;
+	int err;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop);
+	if (err == -FDT_ERR_NOTFOUND)
+		err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
+	if (err)
+		return err;
+
+	memcpy(prop->data, val, len);
+	return 0;
+}
+
+int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
+		   const void *val, int len)
+{
+	struct fdt_property *prop;
+	int err, oldlen, newlen;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
+	if (prop) {
+		newlen = len + oldlen;
+		err = _fdt_splice_struct(fdt, prop->data,
+					 FDT_TAGALIGN(oldlen),
+					 FDT_TAGALIGN(newlen));
+		if (err)
+			return err;
+		prop->len = cpu_to_fdt32(newlen);
+		memcpy(prop->data + oldlen, val, len);
+	} else {
+		err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
+		if (err)
+			return err;
+		memcpy(prop->data, val, len);
+	}
+	return 0;
+}
+
+int fdt_delprop(void *fdt, int nodeoffset, const char *name)
+{
+	struct fdt_property *prop;
+	int len, proplen;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
+	if (! prop)
+		return len;
+
+	proplen = sizeof(*prop) + FDT_TAGALIGN(len);
+	return _fdt_splice_struct(fdt, prop, proplen, 0);
+}
+
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+			    const char *name, int namelen)
+{
+	struct fdt_node_header *nh;
+	int offset, nextoffset;
+	int nodelen;
+	int err;
+	uint32_t tag;
+	uint32_t *endtag;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
+	if (offset >= 0)
+		return -FDT_ERR_EXISTS;
+	else if (offset != -FDT_ERR_NOTFOUND)
+		return offset;
+
+	/* Try to place the new node after the parent's properties */
+	fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
+	do {
+		offset = nextoffset;
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+	} while ((tag == FDT_PROP) || (tag == FDT_NOP));
+
+	nh = _fdt_offset_ptr_w(fdt, offset);
+	nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
+
+	err = _fdt_splice_struct(fdt, nh, 0, nodelen);
+	if (err)
+		return err;
+
+	nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+	memset(nh->name, 0, FDT_TAGALIGN(namelen+1));
+	memcpy(nh->name, name, namelen);
+	endtag = (uint32_t *)((char *)nh + nodelen - FDT_TAGSIZE);
+	*endtag = cpu_to_fdt32(FDT_END_NODE);
+
+	return offset;
+}
+
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
+{
+	return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_del_node(void *fdt, int nodeoffset)
+{
+	int endoffset;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+	if (endoffset < 0)
+		return endoffset;
+
+	return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
+				  endoffset - nodeoffset, 0);
+}
+
+static void _fdt_packblocks(const char *old, char *new,
+			    int mem_rsv_size, int struct_size)
+{
+	int mem_rsv_off, struct_off, strings_off;
+
+	mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
+	struct_off = mem_rsv_off + mem_rsv_size;
+	strings_off = struct_off + struct_size;
+
+	memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size);
+	fdt_set_off_mem_rsvmap(new, mem_rsv_off);
+
+	memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size);
+	fdt_set_off_dt_struct(new, struct_off);
+	fdt_set_size_dt_struct(new, struct_size);
+
+	memmove(new + strings_off, old + fdt_off_dt_strings(old),
+		fdt_size_dt_strings(old));
+	fdt_set_off_dt_strings(new, strings_off);
+	fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
+}
+
+int fdt_open_into(const void *fdt, void *buf, int bufsize)
+{
+	int err;
+	int mem_rsv_size, struct_size;
+	int newsize;
+	const char *fdtstart = fdt;
+	const char *fdtend = fdtstart + fdt_totalsize(fdt);
+	char *tmp;
+
+	FDT_CHECK_HEADER(fdt);
+
+	mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+		* sizeof(struct fdt_reserve_entry);
+
+	if (fdt_version(fdt) >= 17) {
+		struct_size = fdt_size_dt_struct(fdt);
+	} else {
+		struct_size = 0;
+		while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
+			;
+		if (struct_size < 0)
+			return struct_size;
+	}
+
+	if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
+		/* no further work necessary */
+		err = fdt_move(fdt, buf, bufsize);
+		if (err)
+			return err;
+		fdt_set_version(buf, 17);
+		fdt_set_size_dt_struct(buf, struct_size);
+		fdt_set_totalsize(buf, bufsize);
+		return 0;
+	}
+
+	/* Need to reorder */
+	newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
+		+ struct_size + fdt_size_dt_strings(fdt);
+
+	if (bufsize < newsize)
+		return -FDT_ERR_NOSPACE;
+
+	/* First attempt to build converted tree at beginning of buffer */
+	tmp = buf;
+	/* But if that overlaps with the old tree... */
+	if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) {
+		/* Try right after the old tree instead */
+		tmp = (char *)(uintptr_t)fdtend;
+		if ((tmp + newsize) > ((char *)buf + bufsize))
+			return -FDT_ERR_NOSPACE;
+	}
+
+	_fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size);
+	memmove(buf, tmp, newsize);
+
+	fdt_set_magic(buf, FDT_MAGIC);
+	fdt_set_totalsize(buf, bufsize);
+	fdt_set_version(buf, 17);
+	fdt_set_last_comp_version(buf, 16);
+	fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
+
+	return 0;
+}
+
+int fdt_pack(void *fdt)
+{
+	int mem_rsv_size;
+
+	FDT_RW_CHECK_HEADER(fdt);
+
+	mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+		* sizeof(struct fdt_reserve_entry);
+	_fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
+	fdt_set_totalsize(fdt, _fdt_data_size(fdt));
+
+	return 0;
+}
diff --git a/extras/mini-os/lib/fdt/fdt_strerror.c b/extras/mini-os/lib/fdt/fdt_strerror.c
new file mode 100644
index 0000000..e6c3cee
--- /dev/null
+++ b/extras/mini-os/lib/fdt/fdt_strerror.c
@@ -0,0 +1,96 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+struct fdt_errtabent {
+	const char *str;
+};
+
+#define FDT_ERRTABENT(val) \
+	[(val)] = { .str = #val, }
+
+static struct fdt_errtabent fdt_errtable[] = {
+	FDT_ERRTABENT(FDT_ERR_NOTFOUND),
+	FDT_ERRTABENT(FDT_ERR_EXISTS),
+	FDT_ERRTABENT(FDT_ERR_NOSPACE),
+
+	FDT_ERRTABENT(FDT_ERR_BADOFFSET),
+	FDT_ERRTABENT(FDT_ERR_BADPATH),
+	FDT_ERRTABENT(FDT_ERR_BADSTATE),
+
+	FDT_ERRTABENT(FDT_ERR_TRUNCATED),
+	FDT_ERRTABENT(FDT_ERR_BADMAGIC),
+	FDT_ERRTABENT(FDT_ERR_BADVERSION),
+	FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE),
+	FDT_ERRTABENT(FDT_ERR_BADLAYOUT),
+};
+#define FDT_ERRTABSIZE	(sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
+
+const char *fdt_strerror(int errval)
+{
+	if (errval > 0)
+		return "<valid offset/length>";
+	else if (errval == 0)
+		return "<no error>";
+	else if (errval > -FDT_ERRTABSIZE) {
+		const char *s = fdt_errtable[-errval].str;
+
+		if (s)
+			return s;
+	}
+
+	return "<unknown error>";
+}
diff --git a/extras/mini-os/lib/fdt/fdt_sw.c b/extras/mini-os/lib/fdt/fdt_sw.c
new file mode 100644
index 0000000..55ebebf
--- /dev/null
+++ b/extras/mini-os/lib/fdt/fdt_sw.c
@@ -0,0 +1,256 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int _fdt_sw_check_header(void *fdt)
+{
+	if (fdt_magic(fdt) != FDT_SW_MAGIC)
+		return -FDT_ERR_BADMAGIC;
+	/* FIXME: should check more details about the header state */
+	return 0;
+}
+
+#define FDT_SW_CHECK_HEADER(fdt) \
+	{ \
+		int err; \
+		if ((err = _fdt_sw_check_header(fdt)) != 0) \
+			return err; \
+	}
+
+static void *_fdt_grab_space(void *fdt, size_t len)
+{
+	int offset = fdt_size_dt_struct(fdt);
+	int spaceleft;
+
+	spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
+		- fdt_size_dt_strings(fdt);
+
+	if ((offset + len < offset) || (offset + len > spaceleft))
+		return NULL;
+
+	fdt_set_size_dt_struct(fdt, offset + len);
+	return _fdt_offset_ptr_w(fdt, offset);
+}
+
+int fdt_create(void *buf, int bufsize)
+{
+	void *fdt = buf;
+
+	if (bufsize < sizeof(struct fdt_header))
+		return -FDT_ERR_NOSPACE;
+
+	memset(buf, 0, bufsize);
+
+	fdt_set_magic(fdt, FDT_SW_MAGIC);
+	fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
+	fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
+	fdt_set_totalsize(fdt,  bufsize);
+
+	fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header),
+					      sizeof(struct fdt_reserve_entry)));
+	fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
+	fdt_set_off_dt_strings(fdt, bufsize);
+
+	return 0;
+}
+
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
+{
+	struct fdt_reserve_entry *re;
+	int offset;
+
+	FDT_SW_CHECK_HEADER(fdt);
+
+	if (fdt_size_dt_struct(fdt))
+		return -FDT_ERR_BADSTATE;
+
+	offset = fdt_off_dt_struct(fdt);
+	if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
+		return -FDT_ERR_NOSPACE;
+
+	re = (struct fdt_reserve_entry *)((char *)fdt + offset);
+	re->address = cpu_to_fdt64(addr);
+	re->size = cpu_to_fdt64(size);
+
+	fdt_set_off_dt_struct(fdt, offset + sizeof(*re));
+
+	return 0;
+}
+
+int fdt_finish_reservemap(void *fdt)
+{
+	return fdt_add_reservemap_entry(fdt, 0, 0);
+}
+
+int fdt_begin_node(void *fdt, const char *name)
+{
+	struct fdt_node_header *nh;
+	int namelen = strlen(name) + 1;
+
+	FDT_SW_CHECK_HEADER(fdt);
+
+	nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
+	if (! nh)
+		return -FDT_ERR_NOSPACE;
+
+	nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+	memcpy(nh->name, name, namelen);
+	return 0;
+}
+
+int fdt_end_node(void *fdt)
+{
+	uint32_t *en;
+
+	FDT_SW_CHECK_HEADER(fdt);
+
+	en = _fdt_grab_space(fdt, FDT_TAGSIZE);
+	if (! en)
+		return -FDT_ERR_NOSPACE;
+
+	*en = cpu_to_fdt32(FDT_END_NODE);
+	return 0;
+}
+
+static int _fdt_find_add_string(void *fdt, const char *s)
+{
+	char *strtab = (char *)fdt + fdt_totalsize(fdt);
+	const char *p;
+	int strtabsize = fdt_size_dt_strings(fdt);
+	int len = strlen(s) + 1;
+	int struct_top, offset;
+
+	p = _fdt_find_string(strtab - strtabsize, strtabsize, s);
+	if (p)
+		return p - strtab;
+
+	/* Add it */
+	offset = -strtabsize - len;
+	struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+	if (fdt_totalsize(fdt) + offset < struct_top)
+		return 0; /* no more room :( */
+
+	memcpy(strtab + offset, s, len);
+	fdt_set_size_dt_strings(fdt, strtabsize + len);
+	return offset;
+}
+
+int fdt_property(void *fdt, const char *name, const void *val, int len)
+{
+	struct fdt_property *prop;
+	int nameoff;
+
+	FDT_SW_CHECK_HEADER(fdt);
+
+	nameoff = _fdt_find_add_string(fdt, name);
+	if (nameoff == 0)
+		return -FDT_ERR_NOSPACE;
+
+	prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
+	if (! prop)
+		return -FDT_ERR_NOSPACE;
+
+	prop->tag = cpu_to_fdt32(FDT_PROP);
+	prop->nameoff = cpu_to_fdt32(nameoff);
+	prop->len = cpu_to_fdt32(len);
+	memcpy(prop->data, val, len);
+	return 0;
+}
+
+int fdt_finish(void *fdt)
+{
+	char *p = (char *)fdt;
+	uint32_t *end;
+	int oldstroffset, newstroffset;
+	uint32_t tag;
+	int offset, nextoffset;
+
+	FDT_SW_CHECK_HEADER(fdt);
+
+	/* Add terminator */
+	end = _fdt_grab_space(fdt, sizeof(*end));
+	if (! end)
+		return -FDT_ERR_NOSPACE;
+	*end = cpu_to_fdt32(FDT_END);
+
+	/* Relocate the string table */
+	oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
+	newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+	memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
+	fdt_set_off_dt_strings(fdt, newstroffset);
+
+	/* Walk the structure, correcting string offsets */
+	offset = 0;
+	while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
+		if (tag == FDT_PROP) {
+			struct fdt_property *prop =
+				_fdt_offset_ptr_w(fdt, offset);
+			int nameoff;
+
+			nameoff = fdt32_to_cpu(prop->nameoff);
+			nameoff += fdt_size_dt_strings(fdt);
+			prop->nameoff = cpu_to_fdt32(nameoff);
+		}
+		offset = nextoffset;
+	}
+	if (nextoffset < 0)
+		return nextoffset;
+
+	/* Finally, adjust the header */
+	fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
+	fdt_set_magic(fdt, FDT_MAGIC);
+	return 0;
+}
diff --git a/extras/mini-os/lib/fdt/fdt_wip.c b/extras/mini-os/lib/fdt/fdt_wip.c
new file mode 100644
index 0000000..6025fa1
--- /dev/null
+++ b/extras/mini-os/lib/fdt/fdt_wip.c
@@ -0,0 +1,118 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+			const void *val, int len)
+{
+	void *propval;
+	int proplen;
+
+	propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen);
+	if (! propval)
+		return proplen;
+
+	if (proplen != len)
+		return -FDT_ERR_NOSPACE;
+
+	memcpy(propval, val, len);
+	return 0;
+}
+
+static void _fdt_nop_region(void *start, int len)
+{
+	uint32_t *p;
+
+	for (p = start; (char *)p < ((char *)start + len); p++)
+		*p = cpu_to_fdt32(FDT_NOP);
+}
+
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
+{
+	struct fdt_property *prop;
+	int len;
+
+	prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
+	if (! prop)
+		return len;
+
+	_fdt_nop_region(prop, len + sizeof(*prop));
+
+	return 0;
+}
+
+int _fdt_node_end_offset(void *fdt, int offset)
+{
+	int depth = 0;
+
+	while ((offset >= 0) && (depth >= 0))
+		offset = fdt_next_node(fdt, offset, &depth);
+
+	return offset;
+}
+
+int fdt_nop_node(void *fdt, int nodeoffset)
+{
+	int endoffset;
+
+	endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+	if (endoffset < 0)
+		return endoffset;
+
+	_fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0),
+			endoffset - nodeoffset);
+	return 0;
+}
diff --git a/extras/mini-os/lib/fdt/libfdt_internal.h b/extras/mini-os/lib/fdt/libfdt_internal.h
new file mode 100644
index 0000000..381133b
--- /dev/null
+++ b/extras/mini-os/lib/fdt/libfdt_internal.h
@@ -0,0 +1,95 @@
+#ifndef _LIBFDT_INTERNAL_H
+#define _LIBFDT_INTERNAL_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <fdt.h>
+
+#define FDT_ALIGN(x, a)		(((x) + (a) - 1) & ~((a) - 1))
+#define FDT_TAGALIGN(x)		(FDT_ALIGN((x), FDT_TAGSIZE))
+
+#define FDT_CHECK_HEADER(fdt) \
+	{ \
+		int err; \
+		if ((err = fdt_check_header(fdt)) != 0) \
+			return err; \
+	}
+
+int _fdt_check_node_offset(const void *fdt, int offset);
+int _fdt_check_prop_offset(const void *fdt, int offset);
+const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
+int _fdt_node_end_offset(void *fdt, int nodeoffset);
+
+static inline const void *_fdt_offset_ptr(const void *fdt, int offset)
+{
+	return (const char *)fdt + fdt_off_dt_struct(fdt) + offset;
+}
+
+static inline void *_fdt_offset_ptr_w(void *fdt, int offset)
+{
+	return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset);
+}
+
+static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n)
+{
+	const struct fdt_reserve_entry *rsv_table =
+		(const struct fdt_reserve_entry *)
+		((const char *)fdt + fdt_off_mem_rsvmap(fdt));
+
+	return rsv_table + n;
+}
+static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n)
+{
+	return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n);
+}
+
+#define FDT_SW_MAGIC		(~FDT_MAGIC)
+
+#endif /* _LIBFDT_INTERNAL_H */
diff --git a/extras/mini-os/lib/memmove.c b/extras/mini-os/lib/memmove.c
new file mode 100644
index 0000000..0298b7c
--- /dev/null
+++ b/extras/mini-os/lib/memmove.c
@@ -0,0 +1,45 @@
+/*
+ *	memmove.c: memmove compat implementation.
+ *
+ *	Copyright (c) 2001-2008, NLnet Labs. All rights reserved.
+ *
+ * See COPYING for the license.
+*/
+
+#include <os.h>
+#include <mini-os/lib.h>
+
+#ifndef HAVE_LIBC
+
+void *memmove(void *dest, const void *src, size_t n)
+{
+	uint8_t* from = (uint8_t*) src;
+	uint8_t* to = (uint8_t*) dest;
+
+	if (from == to || n == 0)
+		return dest;
+	if (to > from && to-from < (int)n) {
+		/* to overlaps with from */
+		/*  <from......>         */
+		/*         <to........>  */
+		/* copy in reverse, to avoid overwriting from */
+		int i;
+		for(i=n-1; i>=0; i--)
+			to[i] = from[i];
+		return dest;
+	}
+	if (from > to  && from-to < (int)n) {
+		/* to overlaps with from */
+		/*        <from......>   */
+		/*  <to........>         */
+		/* copy forwards, to avoid overwriting from */
+		size_t i;
+		for(i=0; i<n; i++)
+			to[i] = from[i];
+		return dest;
+	}
+	memcpy(dest, src, n);
+	return dest;
+}
+
+#endif
diff --git a/extras/mini-os/lib/string.c b/extras/mini-os/lib/string.c
index 8b24146..c96ca41 100644
--- a/extras/mini-os/lib/string.c
+++ b/extras/mini-os/lib/string.c
@@ -225,4 +225,16 @@ int ffs(int i)
    return 0;
 }
 
+void *memchr(const void *s, int c, size_t n)
+{
+    if (n != 0) {
+        const unsigned char *p = s;
+
+        do {
+            if (*p++ == (unsigned char)c)
+                return ((void *)(uintptr_t)(p - 1));
+        } while (--n != 0);
+    }
+    return (NULL);
+}
 #endif
-- 
2.0.0

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH ARM v4 10/12] mini-os: get RAM base and size from the FDT
  2014-06-18 15:08 [PATCH ARM v4 00/12] mini-os: initial ARM support Thomas Leonard
                   ` (8 preceding siblings ...)
  2014-06-18 15:08 ` [PATCH ARM v4 09/12] mini-os: import libfdt Thomas Leonard
@ 2014-06-18 15:08 ` Thomas Leonard
  2014-06-18 17:38   ` Julien Grall
  2014-06-18 15:08 ` [PATCH ARM v4 11/12] mini-os: get GIC addresses from FDT Thomas Leonard
  2014-06-18 15:08 ` [PATCH ARM v4 12/12] mini-os: added ARM grant table initialisation Thomas Leonard
  11 siblings, 1 reply; 41+ messages in thread
From: Thomas Leonard @ 2014-06-18 15:08 UTC (permalink / raw)
  To: xen-devel
  Cc: Thomas Leonard, Dave.Scott, anil, stefano.stabellini, samuel.thibault

Signed-off-by: Thomas Leonard <talex5@gmail.com>
---
 extras/mini-os/arch/arm/mm.c    | 70 ++++++++++++++++++++++++++++++++++++++---
 extras/mini-os/arch/arm/setup.c | 12 ++++++-
 extras/mini-os/include/arm/os.h |  2 ++
 extras/mini-os/mm.c             |  4 +--
 4 files changed, 80 insertions(+), 8 deletions(-)

diff --git a/extras/mini-os/arch/arm/mm.c b/extras/mini-os/arch/arm/mm.c
index bb6aa0e..be8e747 100644
--- a/extras/mini-os/arch/arm/mm.c
+++ b/extras/mini-os/arch/arm/mm.c
@@ -1,5 +1,7 @@
 #include <console.h>
 #include <arch_mm.h>
+#include <libfdt.h>
+#include <lib.h>
 
 #define PHYS_START (0x80008000 + (1000 * 4 * 1024))
 #define PHYS_SIZE (40*1024*1024)
@@ -25,12 +27,70 @@ void arch_init_mm(unsigned long* start_pfn_p, unsigned long* max_pfn_p)
     printk("    stack start: %p(VA)\n", stack);
     printk("    _end: %p(VA)\n", &_end);
 
-    // FIXME Get from dt!
-    *start_pfn_p = (((unsigned long)&_end) >> PAGE_SHIFT) + 1000;
-    *max_pfn_p = ((unsigned long)&_end + PHYS_SIZE) >> PAGE_SHIFT;
+    *start_pfn_p = 0;
+    *max_pfn_p = 0;
 
-    printk("    start_pfn: %lx\n", *start_pfn_p);
-    printk("    max_pfn: %lx\n", *max_pfn_p);
+    if (fdt_num_mem_rsv(device_tree) != 0)
+        printk("WARNING: reserved memory not supported!\n");
+
+    int node = 0;
+    int depth = 0;
+    for (;;)
+    {
+        node = fdt_next_node(device_tree, node, &depth);
+        if (node <= 0 || depth < 0)
+            break;
+        /*
+           int name_len = 0;
+           const char *name = fdt_get_name(device_tree, node, &name_len);
+           printk("Found node: %d (%.*s)\n", node, name_len, name);
+         */
+
+        const char *device_type = fdt_getprop(device_tree, node, "device_type", NULL);
+        if (device_type && !strcmp(device_type, "memory"))
+        {
+            /* Note: we assume there's only a single region of memory.
+             * Since Xen is already translating our "physical"
+             * addresses to the real physical RAM, there's no
+             * reason for it to give us multiple blocks. */
+            int len = 0;
+            const uint64_t *regs = fdt_getprop(device_tree, node, "reg", &len);
+            if (regs == NULL || len != 16) {
+                printk("Bad 'reg' property: %p %d\n", regs, len);
+                continue;
+            }
+            unsigned int start = (unsigned int) &_text;
+            unsigned int end = (unsigned int) &_end;
+            unsigned int mem_base = fdt64_to_cpu(regs[0]);
+            unsigned int mem_size = fdt64_to_cpu(regs[1]);
+            printk("Found memory at %p (len 0x%x)\n", mem_base, mem_size);
+
+            BUG_ON(mem_base > start);          /* Our image isn't in our RAM! */
+            *start_pfn_p = PFN_UP(end);
+            int heap_len = mem_size - ((*start_pfn_p << PAGE_SHIFT) - mem_base);
+            *max_pfn_p = *start_pfn_p + PFN_DOWN(heap_len);
+
+            printk("Using pages %d to %d as free space for heap.\n", *start_pfn_p, *max_pfn_p);
+            break;
+        }
+    }
+
+    if (*max_pfn_p == 0)
+    {
+        printk("No memory found in FDT!\n");
+        BUG();
+    }
+
+    /* The device tree is probably in memory that we're about to hand over to the page
+     * allocator, so move it to the end and reserve that space.
+     */
+    int fdt_size = fdt_totalsize(device_tree);
+    void *new_device_tree = (void *) (((*max_pfn_p << PAGE_SHIFT) - fdt_size) & PAGE_MASK);
+    if (new_device_tree != device_tree) {
+	memmove(new_device_tree, device_tree, fdt_size);
+    }
+    device_tree = new_device_tree;
+    *max_pfn_p = ((unsigned long) new_device_tree) >> PAGE_SHIFT;
 
     build_pagetable(start_pfn_p, max_pfn_p);
 }
diff --git a/extras/mini-os/arch/arm/setup.c b/extras/mini-os/arch/arm/setup.c
index 3499b37..e59665e 100644
--- a/extras/mini-os/arch/arm/setup.c
+++ b/extras/mini-os/arch/arm/setup.c
@@ -4,6 +4,7 @@
 #include <xen/memory.h>
 #include <xen/hvm/params.h>
 #include <arch_mm.h>
+#include <libfdt.h>
 
 /*
  * This structure contains start-of-day info, such as pagetable base pointer,
@@ -20,6 +21,8 @@ shared_info_t *HYPERVISOR_shared_info;
 
 extern char shared_info_page[PAGE_SIZE];
 
+void *device_tree;
+
 static int hvm_get_parameter(int idx, uint64_t *value)
 {
     struct xen_hvm_param xhv;
@@ -72,7 +75,14 @@ void arch_init(void *dtb_pointer)
 
     memset(&__bss_start, 0, &_end - &__bss_start);
 
-    printk("dtb_pointer : %x\n", dtb_pointer);
+    printk("Checking DTB at %x...\n", dtb_pointer);
+
+    int r;
+    if ((r = fdt_check_header(dtb_pointer))) {
+        printk("Invalid DTB from Xen: %s\n", fdt_strerror(r));
+        BUG();
+    }
+    device_tree = dtb_pointer;
 
     /* Map shared_info page */
     xatp.domid = DOMID_SELF;
diff --git a/extras/mini-os/include/arm/os.h b/extras/mini-os/include/arm/os.h
index 8d76089..2f423c0 100644
--- a/extras/mini-os/include/arm/os.h
+++ b/extras/mini-os/include/arm/os.h
@@ -10,6 +10,8 @@
 void arch_fini(void);
 void timer_handler(evtchn_port_t port, struct pt_regs *regs, void *ign);
 
+extern void *device_tree;
+
 #define BUG() while(1){asm volatile (".word 0xe7f000f0\n");} /* Undefined instruction; will call our fault handler. */
 
 #define smp_processor_id() 0
diff --git a/extras/mini-os/mm.c b/extras/mini-os/mm.c
index d2d5264..d31ef97 100644
--- a/extras/mini-os/mm.c
+++ b/extras/mini-os/mm.c
@@ -409,8 +409,8 @@ void init_mm(void)
      * now we can initialise the page allocator
      */
     printk("MM: Initialise page allocator for %lx(%lx)-%lx(%lx)\n",
-           (u_long)to_virt(PFN_PHYS(start_pfn)), PFN_PHYS(start_pfn), 
-           (u_long)to_virt(PFN_PHYS(max_pfn)), PFN_PHYS(max_pfn));
+           (u_long)to_virt(PFN_PHYS(start_pfn)), (u_long)PFN_PHYS(start_pfn), 
+           (u_long)to_virt(PFN_PHYS(max_pfn)), (u_long)PFN_PHYS(max_pfn));
     init_page_allocator(PFN_PHYS(start_pfn), PFN_PHYS(max_pfn));
     printk("MM: done\n");
 
-- 
2.0.0

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH ARM v4 11/12] mini-os: get GIC addresses from FDT
  2014-06-18 15:08 [PATCH ARM v4 00/12] mini-os: initial ARM support Thomas Leonard
                   ` (9 preceding siblings ...)
  2014-06-18 15:08 ` [PATCH ARM v4 10/12] mini-os: get RAM base and size from the FDT Thomas Leonard
@ 2014-06-18 15:08 ` Thomas Leonard
  2014-06-18 17:25   ` Julien Grall
  2014-06-18 15:08 ` [PATCH ARM v4 12/12] mini-os: added ARM grant table initialisation Thomas Leonard
  11 siblings, 1 reply; 41+ messages in thread
From: Thomas Leonard @ 2014-06-18 15:08 UTC (permalink / raw)
  To: xen-devel
  Cc: Thomas Leonard, Dave.Scott, anil, stefano.stabellini, samuel.thibault

Signed-off-by: Thomas Leonard <talex5@gmail.com>
---
 extras/mini-os/drivers/gic.c | 36 +++++++++++++++++++++++++++++++++---
 1 file changed, 33 insertions(+), 3 deletions(-)

diff --git a/extras/mini-os/drivers/gic.c b/extras/mini-os/drivers/gic.c
index 3141830..8a9e427 100644
--- a/extras/mini-os/drivers/gic.c
+++ b/extras/mini-os/drivers/gic.c
@@ -2,6 +2,7 @@
 
 #include <mini-os/os.h>
 #include <mini-os/hypervisor.h>
+#include <libfdt.h>
 
 //#define VGIC_DEBUG
 #ifdef VGIC_DEBUG
@@ -168,9 +169,38 @@ static void gic_handler(void) {
 }
 
 void gic_init(void) {
-    // FIXME Get from dt!
-    gic.gicd_base = (char *)0x2c001000ULL;
-    gic.gicc_base = (char *)0x2c002000ULL;
+    gic.gicd_base = NULL;
+    int node = 0;
+    int depth = 0;
+    for (;;)
+    {
+        node = fdt_next_node(device_tree, node, &depth);
+        if (node <= 0 || depth < 0)
+            break;
+
+        /*
+           int name_len = 0;
+           const char *name = fdt_get_name(device_tree, node, &name_len);
+           printk("Found node: %d (%.*s)\n", node, name_len, name);
+         */
+
+        if (fdt_getprop(device_tree, node, "interrupt-controller", NULL)) {
+            int len = 0;
+            const uint64_t *reg = fdt_getprop(device_tree, node, "reg", &len);
+            if (reg == NULL || len != 32) {
+                printk("Bad 'reg' property: %p %d\n", reg, len);
+                continue;
+            }
+            gic.gicd_base = (char *) (long) fdt64_to_cpu(reg[0]);
+            gic.gicc_base = (char *) (long) fdt64_to_cpu(reg[2]);
+            printk("Found GIC: gicd_base = %p, gicc_base = %p\n", gic.gicd_base, gic.gicc_base);
+            break;
+        }
+    }
+    if (!gic.gicd_base) {
+        printk("GIC not found!\n");
+        BUG();
+    }
     wmb();
 
     IRQ_handler = gic_handler;
-- 
2.0.0

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH ARM v4 12/12] mini-os: added ARM grant table initialisation
  2014-06-18 15:08 [PATCH ARM v4 00/12] mini-os: initial ARM support Thomas Leonard
                   ` (10 preceding siblings ...)
  2014-06-18 15:08 ` [PATCH ARM v4 11/12] mini-os: get GIC addresses from FDT Thomas Leonard
@ 2014-06-18 15:08 ` Thomas Leonard
  2014-06-18 17:27   ` Julien Grall
  2014-06-18 18:05   ` Samuel Thibault
  11 siblings, 2 replies; 41+ messages in thread
From: Thomas Leonard @ 2014-06-18 15:08 UTC (permalink / raw)
  To: xen-devel
  Cc: Thomas Leonard, Dave.Scott, anil, stefano.stabellini, samuel.thibault

On x86, we get told which pages to use, but on ARM we get the base
address in the FDT and have to map each page.

Signed-off-by: Thomas Leonard <talex5@gmail.com>
---
 extras/mini-os/ARM-TODO.txt     |  1 -
 extras/mini-os/arch/arm/mm.c    | 58 +++++++++++++++++++++++++++++++++++++++++
 extras/mini-os/arch/x86/mm.c    | 13 +++++++++
 extras/mini-os/gnttab.c         | 11 ++------
 extras/mini-os/include/gnttab.h |  1 +
 5 files changed, 74 insertions(+), 10 deletions(-)

diff --git a/extras/mini-os/ARM-TODO.txt b/extras/mini-os/ARM-TODO.txt
index 8f4f1da..e30760a 100644
--- a/extras/mini-os/ARM-TODO.txt
+++ b/extras/mini-os/ARM-TODO.txt
@@ -1,6 +1,5 @@
 * scheduling!
 * gic request_irq implementation, currently all IRQs all hardcoded in gic irq handler.
-* use device tree instead of the currently hardcoded values
 * Add virtual memory support and make vstart = 0 ( use 4k descriptors instead of 1M descriptors )
 * sched
 * fini_gnttab
diff --git a/extras/mini-os/arch/arm/mm.c b/extras/mini-os/arch/arm/mm.c
index be8e747..050e845 100644
--- a/extras/mini-os/arch/arm/mm.c
+++ b/extras/mini-os/arch/arm/mm.c
@@ -1,5 +1,7 @@
 #include <console.h>
+#include <xen/memory.h>
 #include <arch_mm.h>
+#include <mini-os/hypervisor.h>
 #include <libfdt.h>
 #include <lib.h>
 
@@ -102,3 +104,59 @@ void arch_init_p2m(unsigned long max_pfn)
 void arch_init_demand_mapping_area(unsigned long cur_pfn)
 {
 }
+
+/* Get Xen's sugggested physical page assignments for the grant table. */
+static grant_entry_t *get_gnttab_base(void)
+{
+    int hypervisor;
+
+    hypervisor = fdt_path_offset(device_tree, "/hypervisor");
+    BUG_ON(hypervisor < 0);
+
+    int len = 0;
+    const uint64_t *regs = fdt_getprop(device_tree, hypervisor, "reg", &len);
+    if (regs == NULL || len != 16) {
+            printk("Bad 'reg' property: %p %d\n", regs, len);
+            BUG();
+    }
+
+    unsigned int gnttab_base = fdt64_to_cpu(regs[0]);
+
+    printk("FDT suggests grant table base %lx\n", gnttab_base);
+
+    return (grant_entry_t *) gnttab_base;
+}
+
+grant_entry_t *arch_init_gnttab(int nr_grant_frames)
+{
+    struct xen_add_to_physmap xatp;
+    struct gnttab_setup_table setup;
+    xen_pfn_t frames[nr_grant_frames];
+    grant_entry_t *gnttab_table;
+    int i, rc;
+
+    gnttab_table = get_gnttab_base();
+
+    for (i = 0; i < nr_grant_frames; i++)
+    {
+        xatp.domid = DOMID_SELF;
+        xatp.size = 0;      /* Seems to be unused */
+        xatp.space = XENMAPSPACE_grant_table;
+        xatp.idx = i;
+        xatp.gpfn = (((unsigned long) gnttab_table) >> PAGE_SHIFT) + i;
+        rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp);
+        BUG_ON(rc != 0);
+    }
+
+    setup.dom = DOMID_SELF;
+    setup.nr_frames = nr_grant_frames;
+    set_xen_guest_handle(setup.frame_list, frames);
+    HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
+    if (setup.status != 0)
+    {
+        printk("GNTTABOP_setup_table failed; status = %d\n", setup.status);
+        BUG();
+    }
+
+    return gnttab_table;
+}
diff --git a/extras/mini-os/arch/x86/mm.c b/extras/mini-os/arch/x86/mm.c
index 35df15b..9c6d1b8 100644
--- a/extras/mini-os/arch/x86/mm.c
+++ b/extras/mini-os/arch/x86/mm.c
@@ -942,3 +942,16 @@ void arch_init_mm(unsigned long* start_pfn_p, unsigned long* max_pfn_p)
     *start_pfn_p = start_pfn;
     *max_pfn_p = max_pfn;
 }
+
+grant_entry_t *arch_init_gnttab(int nr_grant_frames)
+{
+    struct gnttab_setup_table setup;
+    unsigned long frames[nr_grant_frames];
+
+    setup.dom = DOMID_SELF;
+    setup.nr_frames = nr_grant_frames;
+    set_xen_guest_handle(setup.frame_list, frames);
+
+    HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
+    return map_frames(frames, nr_grant_frames);
+}
diff --git a/extras/mini-os/gnttab.c b/extras/mini-os/gnttab.c
index 2f1b3d7..f395d12 100644
--- a/extras/mini-os/gnttab.c
+++ b/extras/mini-os/gnttab.c
@@ -164,7 +164,7 @@ gnttabop_error(int16_t status)
 {
     status = -status;
     if (status < 0 || status >= ARRAY_SIZE(gnttabop_error_msgs))
-	return "bad status";
+        return "bad status";
     else
         return gnttabop_error_msgs[status];
 }
@@ -172,8 +172,6 @@ gnttabop_error(int16_t status)
 void
 init_gnttab(void)
 {
-    struct gnttab_setup_table setup;
-    unsigned long frames[NR_GRANT_FRAMES];
     int i;
 
 #ifdef GNT_DEBUG
@@ -182,12 +180,7 @@ init_gnttab(void)
     for (i = NR_RESERVED_ENTRIES; i < NR_GRANT_ENTRIES; i++)
         put_free_entry(i);
 
-    setup.dom = DOMID_SELF;
-    setup.nr_frames = NR_GRANT_FRAMES;
-    set_xen_guest_handle(setup.frame_list, frames);
-
-    HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
-    gnttab_table = map_frames(frames, NR_GRANT_FRAMES);
+    gnttab_table = arch_init_gnttab(NR_GRANT_FRAMES);
     printk("gnttab_table mapped at %p.\n", gnttab_table);
 }
 
diff --git a/extras/mini-os/include/gnttab.h b/extras/mini-os/include/gnttab.h
index acd6c39..c43ad42 100644
--- a/extras/mini-os/include/gnttab.h
+++ b/extras/mini-os/include/gnttab.h
@@ -12,5 +12,6 @@ unsigned long gnttab_end_transfer(grant_ref_t gref);
 int gnttab_end_access(grant_ref_t ref);
 const char *gnttabop_error(int16_t status);
 void fini_gnttab(void);
+grant_entry_t *arch_init_gnttab(int nr_grant_frames);
 
 #endif /* !__GNTTAB_H__ */
-- 
2.0.0

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 01/12] mini-os: build fixes
  2014-06-18 15:08 ` [PATCH ARM v4 01/12] mini-os: build fixes Thomas Leonard
@ 2014-06-18 16:26   ` Ian Campbell
  2014-06-18 17:41   ` Samuel Thibault
  1 sibling, 0 replies; 41+ messages in thread
From: Ian Campbell @ 2014-06-18 16:26 UTC (permalink / raw)
  To: Thomas Leonard
  Cc: xen-devel, stefano.stabellini, Dave.Scott, samuel.thibault, anil

On Wed, 2014-06-18 at 16:08 +0100, Thomas Leonard wrote:
> Make .o rules depend on the includes. Before, only the final link step
> depended on setting up the includes directory, making parallel builds
> unreliable.
> 
> Make symlinks use explicit make rules instead of using a phony target.
> Avoids unnecessary rebuilds.
> 
> [talex5@gmail.com: bring back "make links", for stubdom]
> Signed-off-by: Thomas Leonard <talex5@gmail.com>

Acked-by: Ian Campbell <ian.campbell@citrix.com>

> ---
>  extras/mini-os/Makefile | 23 +++++++++++++++++------
>  1 file changed, 17 insertions(+), 6 deletions(-)
> 
> diff --git a/extras/mini-os/Makefile b/extras/mini-os/Makefile
> index 50d038b..6d6537e 100644
> --- a/extras/mini-os/Makefile
> +++ b/extras/mini-os/Makefile
> @@ -50,6 +50,11 @@ flags-$(CONFIG_XENBUS) += -DCONFIG_XENBUS
>  
>  DEF_CFLAGS += $(flags-y)
>  
> +# Symlinks and headers that must be created before building the C files
> +GENERATED_HEADERS := include/list.h $(ARCH_LINKS) include/mini-os include/xen include/$(TARGET_ARCH_FAM)/mini-os
> +
> +EXTRA_DEPS += $(GENERATED_HEADERS)
> +
>  # Include common mini-os makerules.
>  include minios.mk
>  
> @@ -124,11 +129,18 @@ include/list.h: $(XEN_ROOT)/tools/include/xen-external/bsd-sys-queue-h-seddery $
>  	perl $^ --prefix=minios  >$@.new
>  	$(call move-if-changed,$@.new,$@)
>  
> +# Used by stubdom's Makefile
>  .PHONY: links
> -links: include/list.h $(ARCH_LINKS)
> -	[ -e include/xen ] || ln -sf ../../../xen/include/public include/xen
> -	[ -e include/mini-os ] || ln -sf . include/mini-os
> -	[ -e include/$(TARGET_ARCH_FAM)/mini-os ] || ln -sf . include/$(TARGET_ARCH_FAM)/mini-os
> +links: $(GENERATED_HEADERS)
> +
> +include/xen:
> +	ln -sf ../../../xen/include/public $@
> +
> +include/mini-os:
> +	ln -sf . $@
> +
> +include/$(TARGET_ARCH_FAM)/mini-os:
> +	ln -sf . $@
>  
>  .PHONY: arch_lib
>  arch_lib:
> @@ -174,7 +186,7 @@ ifneq ($(APP_OBJS),)
>  APP_O=$(OBJ_DIR)/$(TARGET)_app.o 
>  endif
>  
> -$(OBJ_DIR)/$(TARGET): links include/list.h $(OBJS) $(APP_O) arch_lib
> +$(OBJ_DIR)/$(TARGET): $(OBJS) $(APP_O) arch_lib
>  	$(LD) -r $(LDFLAGS) $(HEAD_OBJ) $(APP_O) $(OBJS) $(LDARCHLIB) $(LDLIBS) -o $@.o
>  	$(OBJCOPY) -w -G $(GLOBAL_PREFIX)* -G _start $@.o $@.o
>  	$(LD) $(LDFLAGS) $(LDFLAGS_FINAL) $@.o $(EXTRA_OBJS) -o $@
> @@ -212,4 +224,3 @@ tags:
>  .PHONY: TAGS
>  TAGS:
>  	$(all_sources) | xargs etags
> -

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 03/12] mini-os: fixed format string error in unbind_evtchn
  2014-06-18 15:08 ` [PATCH ARM v4 03/12] mini-os: fixed format string error in unbind_evtchn Thomas Leonard
@ 2014-06-18 16:28   ` Ian Campbell
  2014-06-18 17:42   ` Samuel Thibault
  1 sibling, 0 replies; 41+ messages in thread
From: Ian Campbell @ 2014-06-18 16:28 UTC (permalink / raw)
  To: Thomas Leonard
  Cc: xen-devel, stefano.stabellini, Dave.Scott, samuel.thibault, anil

On Wed, 2014-06-18 at 16:08 +0100, Thomas Leonard wrote:
> Would crash if HYPERVISOR_event_channel_op returned an error code.
> The other changes in this commit are just fixing indentation.

A little bit of this sort of mixing is tolerable, but a 4 bit change
with two dozen lines of reindenting around it might be considered by
some to be going to far ;-)

> Signed-off-by: Thomas Leonard <talex5@gmail.com>

Acked-by: Ian Campbell <ian.cammpbell@citrix.com> 
(this time)

Ian.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 04/12] mini-os: use unbind_evtchn in unbind_all_ports
  2014-06-18 15:08 ` [PATCH ARM v4 04/12] mini-os: use unbind_evtchn in unbind_all_ports Thomas Leonard
@ 2014-06-18 16:30   ` Ian Campbell
  2014-06-18 17:44   ` Samuel Thibault
  1 sibling, 0 replies; 41+ messages in thread
From: Ian Campbell @ 2014-06-18 16:30 UTC (permalink / raw)
  To: Thomas Leonard
  Cc: xen-devel, stefano.stabellini, Dave.Scott, samuel.thibault, anil

On Wed, 2014-06-18 at 16:08 +0100, Thomas Leonard wrote:
> This marks the channel as closed, in case someone tries to use it again.
> 
> Signed-off-by: Thomas Leonard <talex5@gmail.com>

Acked-by: Ian Campbell <ian.campbell@citrix.com>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 05/12] mini-os: made off_t type signed
  2014-06-18 15:08 ` [PATCH ARM v4 05/12] mini-os: made off_t type signed Thomas Leonard
@ 2014-06-18 16:31   ` Ian Campbell
  2014-06-18 17:44   ` Samuel Thibault
  1 sibling, 0 replies; 41+ messages in thread
From: Ian Campbell @ 2014-06-18 16:31 UTC (permalink / raw)
  To: Thomas Leonard
  Cc: xen-devel, stefano.stabellini, Dave.Scott, samuel.thibault, anil

On Wed, 2014-06-18 at 16:08 +0100, Thomas Leonard wrote:
> POSIX requires this.
> 
> Signed-off-by: Thomas Leonard <talex5@gmail.com>

Acked-by: Ian Campbell <ian.campbell@citrix.com>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 11/12] mini-os: get GIC addresses from FDT
  2014-06-18 15:08 ` [PATCH ARM v4 11/12] mini-os: get GIC addresses from FDT Thomas Leonard
@ 2014-06-18 17:25   ` Julien Grall
  2014-06-19  8:50     ` Thomas Leonard
  0 siblings, 1 reply; 41+ messages in thread
From: Julien Grall @ 2014-06-18 17:25 UTC (permalink / raw)
  To: Thomas Leonard, xen-devel
  Cc: samuel.thibault, stefano.stabellini, Dave.Scott, anil

Hi Thomas,

On 06/18/2014 04:08 PM, Thomas Leonard wrote:
>  //#define VGIC_DEBUG
>  #ifdef VGIC_DEBUG
> @@ -168,9 +169,38 @@ static void gic_handler(void) {
>  }
>  
>  void gic_init(void) {
> -    // FIXME Get from dt!
> -    gic.gicd_base = (char *)0x2c001000ULL;
> -    gic.gicc_base = (char *)0x2c002000ULL;
> +    gic.gicd_base = NULL;

Any reason to not fold this patch in patch #7? Or better move the gic
code in a separate patch?

This would avoid to hardcode a GIC address which is completely wrong
with Xen unstable.

> +    int node = 0;
> +    int depth = 0;
> +    for (;;)
> +    {
> +        node = fdt_next_node(device_tree, node, &depth);
> +        if (node <= 0 || depth < 0)
> +            break;
> +
> +        /*
> +           int name_len = 0;
> +           const char *name = fdt_get_name(device_tree, node, &name_len);
> +           printk("Found node: %d (%.*s)\n", node, name_len, name);
> +         */

This should be drop.

> +
> +        if (fdt_getprop(device_tree, node, "interrupt-controller", NULL)) {

You have to check the compatible string here.

> +            int len = 0;
> +            const uint64_t *reg = fdt_getprop(device_tree, node, "reg", &len);
> +            if (reg == NULL || len != 32) {

You made assumption of the layout of the device tree provided by Xen:
	- #address-cells == #size-cells == 2
	- regs contains a valid physical address, i.e the device is not under a bus

This can be changed by the toolstack in the future and will likely break
mini-os.

I would add a layer to support FDT address and interrupt translation
correctly. I'm not the maintainer of the mini-os, so I let them decide :).

I think, FreeBSD provides a good library for the translation (see
sys/dev/fdt/fdt_common.c).

I spent lots of time to play with device tree on Xen side, so I can help
you if you needed.

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 12/12] mini-os: added ARM grant table initialisation
  2014-06-18 15:08 ` [PATCH ARM v4 12/12] mini-os: added ARM grant table initialisation Thomas Leonard
@ 2014-06-18 17:27   ` Julien Grall
  2014-06-25 16:41     ` Thomas Leonard
  2014-06-18 18:05   ` Samuel Thibault
  1 sibling, 1 reply; 41+ messages in thread
From: Julien Grall @ 2014-06-18 17:27 UTC (permalink / raw)
  To: Thomas Leonard, xen-devel
  Cc: samuel.thibault, stefano.stabellini, Dave.Scott, anil

Hi Thomas,

On 06/18/2014 04:08 PM, Thomas Leonard wrote:
> +
> +/* Get Xen's sugggested physical page assignments for the grant table. */
> +static grant_entry_t *get_gnttab_base(void)
> +{
> +    int hypervisor;
> +
> +    hypervisor = fdt_path_offset(device_tree, "/hypervisor");

Same comment as on patch #11, you need to search the hypervisor node via
the compatible string.


> index 2f1b3d7..f395d12 100644
> --- a/extras/mini-os/gnttab.c
> +++ b/extras/mini-os/gnttab.c
> @@ -164,7 +164,7 @@ gnttabop_error(int16_t status)
>  {
>      status = -status;
>      if (status < 0 || status >= ARRAY_SIZE(gnttabop_error_msgs))
> -	return "bad status";
> +        return "bad status";

Spurious change?

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 10/12] mini-os: get RAM base and size from the FDT
  2014-06-18 15:08 ` [PATCH ARM v4 10/12] mini-os: get RAM base and size from the FDT Thomas Leonard
@ 2014-06-18 17:38   ` Julien Grall
  2014-06-19  8:39     ` Thomas Leonard
  0 siblings, 1 reply; 41+ messages in thread
From: Julien Grall @ 2014-06-18 17:38 UTC (permalink / raw)
  To: Thomas Leonard, xen-devel
  Cc: samuel.thibault, stefano.stabellini, Dave.Scott, anil

Hi Thomas,

On 06/18/2014 04:08 PM, Thomas Leonard wrote:
> +        const char *device_type = fdt_getprop(device_tree, node, "device_type", NULL);
> +        if (device_type && !strcmp(device_type, "memory"))
> +        {
> +            /* Note: we assume there's only a single region of memory.
> +             * Since Xen is already translating our "physical"
> +             * addresses to the real physical RAM, there's no
> +             * reason for it to give us multiple blocks. */

This comment looks wrong to me. Even tho, Xen is providing a stage-2
translation to show you a virtual layout (your guest physical memory),
the new layout in Xen upstream may contain multiple banks. The first
bank will contain up to 3G of RAM.
> index d2d5264..d31ef97 100644
> --- a/extras/mini-os/mm.c
> +++ b/extras/mini-os/mm.c
> @@ -409,8 +409,8 @@ void init_mm(void)
>       * now we can initialise the page allocator
>       */
>      printk("MM: Initialise page allocator for %lx(%lx)-%lx(%lx)\n",
> -           (u_long)to_virt(PFN_PHYS(start_pfn)), PFN_PHYS(start_pfn), 
> -           (u_long)to_virt(PFN_PHYS(max_pfn)), PFN_PHYS(max_pfn));
> +           (u_long)to_virt(PFN_PHYS(start_pfn)), (u_long)PFN_PHYS(start_pfn), 
> +           (u_long)to_virt(PFN_PHYS(max_pfn)), (u_long)PFN_PHYS(max_pfn));

I don't see any modification of the type of max_pfn, start_pfn,
PFN_PHYS. This change should not be part of this patch.

Regards,
-- 
Julien Grall

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 01/12] mini-os: build fixes
  2014-06-18 15:08 ` [PATCH ARM v4 01/12] mini-os: build fixes Thomas Leonard
  2014-06-18 16:26   ` Ian Campbell
@ 2014-06-18 17:41   ` Samuel Thibault
  1 sibling, 0 replies; 41+ messages in thread
From: Samuel Thibault @ 2014-06-18 17:41 UTC (permalink / raw)
  To: Thomas Leonard; +Cc: xen-devel, anil, Dave.Scott, stefano.stabellini

Thomas Leonard, le Wed 18 Jun 2014 16:08:15 +0100, a écrit :
> Make .o rules depend on the includes. Before, only the final link step
> depended on setting up the includes directory, making parallel builds
> unreliable.
> 
> Make symlinks use explicit make rules instead of using a phony target.
> Avoids unnecessary rebuilds.
> 
> [talex5@gmail.com: bring back "make links", for stubdom]
> Signed-off-by: Thomas Leonard <talex5@gmail.com>

Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org>

> ---
>  extras/mini-os/Makefile | 23 +++++++++++++++++------
>  1 file changed, 17 insertions(+), 6 deletions(-)
> 
> diff --git a/extras/mini-os/Makefile b/extras/mini-os/Makefile
> index 50d038b..6d6537e 100644
> --- a/extras/mini-os/Makefile
> +++ b/extras/mini-os/Makefile
> @@ -50,6 +50,11 @@ flags-$(CONFIG_XENBUS) += -DCONFIG_XENBUS
>  
>  DEF_CFLAGS += $(flags-y)
>  
> +# Symlinks and headers that must be created before building the C files
> +GENERATED_HEADERS := include/list.h $(ARCH_LINKS) include/mini-os include/xen include/$(TARGET_ARCH_FAM)/mini-os
> +
> +EXTRA_DEPS += $(GENERATED_HEADERS)
> +
>  # Include common mini-os makerules.
>  include minios.mk
>  
> @@ -124,11 +129,18 @@ include/list.h: $(XEN_ROOT)/tools/include/xen-external/bsd-sys-queue-h-seddery $
>  	perl $^ --prefix=minios  >$@.new
>  	$(call move-if-changed,$@.new,$@)
>  
> +# Used by stubdom's Makefile
>  .PHONY: links
> -links: include/list.h $(ARCH_LINKS)
> -	[ -e include/xen ] || ln -sf ../../../xen/include/public include/xen
> -	[ -e include/mini-os ] || ln -sf . include/mini-os
> -	[ -e include/$(TARGET_ARCH_FAM)/mini-os ] || ln -sf . include/$(TARGET_ARCH_FAM)/mini-os
> +links: $(GENERATED_HEADERS)
> +
> +include/xen:
> +	ln -sf ../../../xen/include/public $@
> +
> +include/mini-os:
> +	ln -sf . $@
> +
> +include/$(TARGET_ARCH_FAM)/mini-os:
> +	ln -sf . $@
>  
>  .PHONY: arch_lib
>  arch_lib:
> @@ -174,7 +186,7 @@ ifneq ($(APP_OBJS),)
>  APP_O=$(OBJ_DIR)/$(TARGET)_app.o 
>  endif
>  
> -$(OBJ_DIR)/$(TARGET): links include/list.h $(OBJS) $(APP_O) arch_lib
> +$(OBJ_DIR)/$(TARGET): $(OBJS) $(APP_O) arch_lib
>  	$(LD) -r $(LDFLAGS) $(HEAD_OBJ) $(APP_O) $(OBJS) $(LDARCHLIB) $(LDLIBS) -o $@.o
>  	$(OBJCOPY) -w -G $(GLOBAL_PREFIX)* -G _start $@.o $@.o
>  	$(LD) $(LDFLAGS) $(LDFLAGS_FINAL) $@.o $(EXTRA_OBJS) -o $@
> @@ -212,4 +224,3 @@ tags:
>  .PHONY: TAGS
>  TAGS:
>  	$(all_sources) | xargs etags
> -
> -- 
> 2.0.0
> 

-- 
Samuel
I develop for Linux for a living, I used to develop for DOS.
Going from DOS to Linux is like trading a glider for an F117.
(By entropy@world.std.com, Lawrence Foard)

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 03/12] mini-os: fixed format string error in unbind_evtchn
  2014-06-18 15:08 ` [PATCH ARM v4 03/12] mini-os: fixed format string error in unbind_evtchn Thomas Leonard
  2014-06-18 16:28   ` Ian Campbell
@ 2014-06-18 17:42   ` Samuel Thibault
  1 sibling, 0 replies; 41+ messages in thread
From: Samuel Thibault @ 2014-06-18 17:42 UTC (permalink / raw)
  To: Thomas Leonard; +Cc: xen-devel, anil, Dave.Scott, stefano.stabellini

Thomas Leonard, le Wed 18 Jun 2014 16:08:17 +0100, a écrit :
> Would crash if HYPERVISOR_event_channel_op returned an error code.
> The other changes in this commit are just fixing indentation.
> 
> Signed-off-by: Thomas Leonard <talex5@gmail.com>

Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 04/12] mini-os: use unbind_evtchn in unbind_all_ports
  2014-06-18 15:08 ` [PATCH ARM v4 04/12] mini-os: use unbind_evtchn in unbind_all_ports Thomas Leonard
  2014-06-18 16:30   ` Ian Campbell
@ 2014-06-18 17:44   ` Samuel Thibault
  1 sibling, 0 replies; 41+ messages in thread
From: Samuel Thibault @ 2014-06-18 17:44 UTC (permalink / raw)
  To: Thomas Leonard; +Cc: xen-devel, anil, Dave.Scott, stefano.stabellini

Thomas Leonard, le Wed 18 Jun 2014 16:08:18 +0100, a écrit :
> This marks the channel as closed, in case someone tries to use it again.
> 
> Signed-off-by: Thomas Leonard <talex5@gmail.com>

Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 05/12] mini-os: made off_t type signed
  2014-06-18 15:08 ` [PATCH ARM v4 05/12] mini-os: made off_t type signed Thomas Leonard
  2014-06-18 16:31   ` Ian Campbell
@ 2014-06-18 17:44   ` Samuel Thibault
  1 sibling, 0 replies; 41+ messages in thread
From: Samuel Thibault @ 2014-06-18 17:44 UTC (permalink / raw)
  To: Thomas Leonard; +Cc: xen-devel, anil, Dave.Scott, stefano.stabellini

Thomas Leonard, le Wed 18 Jun 2014 16:08:19 +0100, a écrit :
> POSIX requires this.
> 
> Signed-off-by: Thomas Leonard <talex5@gmail.com>

Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 07/12] mini-os: initial ARM support
  2014-06-18 15:08 ` [PATCH ARM v4 07/12] mini-os: initial ARM support Thomas Leonard
@ 2014-06-18 17:48   ` Samuel Thibault
  2014-06-18 22:40   ` Julien Grall
  1 sibling, 0 replies; 41+ messages in thread
From: Samuel Thibault @ 2014-06-18 17:48 UTC (permalink / raw)
  To: Thomas Leonard; +Cc: xen-devel, anil, Dave.Scott, stefano.stabellini

Thomas Leonard, le Wed 18 Jun 2014 16:08:21 +0100, a écrit :
> From: Karim Raslan <karim.allah.ahmed@gmail.com>
> 
> On ARM, Mini-OS will boot and display some output on the console.
> Tested with:
> 
> make XEN_TARGET_ARCH=arm32 CROSS_COMPILE=arm-linux-gnueabihf- \
> 	CONFIG_TEST=y CONFIG_START_NETWORK=n CONFIG_BLKFRONT=n \
> 	CONFIG_NETFRONT=n CONFIG_FBFRONT=n CONFIG_KBDFRONT=n \
> 	CONFIG_CONSFRONT=n CONFIG_XC=n -j4
> 
> Signed-off-by: Karim Allah Ahmed <karim.allah.ahmed@gmail.com>
> [talex5@gmail.com: made x86_64 support work again]
> [talex5@gmail.com: split into multiple patches]
> [talex5@gmail.com: re-enabled force_evtchn_callback]
> [talex5@gmail.com: enable regular console]
> [talex5@gmail.com: fixed initialisation code:
> - Configure write-back caching in page table. This is needed for
>   reliable hypercalls to Xen (thanks to Julien Grall).
> - Use "client mode" for access control (domains are deprecated,
>   according to ARM Cortex-A Series Programmer’s Guide version 4.0,
>   section 9.6.4).
> - Enable more SCTLR features (icache, branch prediction)]
> [talex5@gmail.com: use Virtual Count register for monotonic time]
> [talex5@gmail.com: fixed HYPERVISOR_shutdown]
> [talex5@gmail.com: get xenstore details from hypervisor]
> [talex5@gmail.com: use GCC implementation of division]
> [talex5@gmail.com: include hypervisor.h from os.h, as on x86]
> [talex5@gmail.com: cleaned up interrupt handlers and threading]
> [talex5@gmail.com: call exit_thread when a thread returns]
> [talex5@gmail.com: implemented block_domain for ARM]
> [talex5@gmail.com: fixed hang when enabling interrupts]
> [talex5@gmail.com: added -march=armv7-a to flags]
> [talex5@gmail.com: implemented bitops for ARM]
> [talex5@gmail.com: CLREX after handling IRQs]
> [talex5@gmail.com: unbind debug port at shutdown]
> [talex5@gmail.com: allow unaligned accesses]
> [talex5@gmail.com: added arch_endian.h for ARM]
> [talex5@gmail.com: fix zImage header for XSA-95]
> Signed-off-by: Thomas Leonard <talex5@gmail.com>

It looks good to me, although I haven't reviewed the purely arm parts
such as bootup.  I don't know how I'm supposed to tag it :)

Samuel

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 09/12] mini-os: import libfdt
  2014-06-18 15:08 ` [PATCH ARM v4 09/12] mini-os: import libfdt Thomas Leonard
@ 2014-06-18 18:02   ` Samuel Thibault
  0 siblings, 0 replies; 41+ messages in thread
From: Samuel Thibault @ 2014-06-18 18:02 UTC (permalink / raw)
  To: Thomas Leonard; +Cc: xen-devel, anil, Dave.Scott, stefano.stabellini

Thomas Leonard, le Wed 18 Jun 2014 16:08:23 +0100, a écrit :
> From: Karim Raslan <karim.allah.ahmed@gmail.com>
> 
> Looks like this is revision v1.3.0-47-gbe60268 from
> http://git.jdl.com/gitweb/?p=dtc.git
> 
> The memmove implementation is from FreeBSD's
> contrib/ldns/compat/memmove.c
> 
> Signed-off-by: Karim Allah Ahmed <karim.allah.ahmed@gmail.com>
> [talex5@gmail.com: split out FDT support into a separate patch]
> [talex5@gmail.com: fixed "make clean" for FDT]
> [talex5@gmail.com: replaced GPL memmove with BSD one]
> Signed-off-by: Thomas Leonard <talex5@gmail.com>

Another case of "integration looks fine to me, I haven't reviewed the
additional feature".

Samuel

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 12/12] mini-os: added ARM grant table initialisation
  2014-06-18 15:08 ` [PATCH ARM v4 12/12] mini-os: added ARM grant table initialisation Thomas Leonard
  2014-06-18 17:27   ` Julien Grall
@ 2014-06-18 18:05   ` Samuel Thibault
  1 sibling, 0 replies; 41+ messages in thread
From: Samuel Thibault @ 2014-06-18 18:05 UTC (permalink / raw)
  To: Thomas Leonard; +Cc: xen-devel, anil, Dave.Scott, stefano.stabellini

Thomas Leonard, le Wed 18 Jun 2014 16:08:26 +0100, a écrit :
> On x86, we get told which pages to use, but on ARM we get the base
> address in the FDT and have to map each page.
> 
> Signed-off-by: Thomas Leonard <talex5@gmail.com>

Integration is OK to me, I don't know about FDT :)

Samuel

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 07/12] mini-os: initial ARM support
  2014-06-18 15:08 ` [PATCH ARM v4 07/12] mini-os: initial ARM support Thomas Leonard
  2014-06-18 17:48   ` Samuel Thibault
@ 2014-06-18 22:40   ` Julien Grall
  2014-06-23 15:10     ` Thomas Leonard
  1 sibling, 1 reply; 41+ messages in thread
From: Julien Grall @ 2014-06-18 22:40 UTC (permalink / raw)
  To: Thomas Leonard, xen-devel
  Cc: samuel.thibault, stefano.stabellini, Dave.Scott, anil

Hi Thomas,

On 06/18/2014 04:08 PM, Thomas Leonard wrote:
> diff --git a/extras/mini-os/arch/arm/arm32.S b/extras/mini-os/arch/arm/arm32.S
> new file mode 100644
> index 0000000..4f953ec
> --- /dev/null
> +++ b/extras/mini-os/arch/arm/arm32.S
> @@ -0,0 +1,155 @@
> +#define PHYS_START (0x80008000)

This address is wrong with the latest xen unstable. Any reason to make
mini-os tight to a specific physical address?

[..]

> diff --git a/extras/mini-os/arch/arm/hypercalls32.S b/extras/mini-os/arch/arm/hypercalls32.S
> new file mode 100644
> index 0000000..e2f21c4
> --- /dev/null
> +++ b/extras/mini-os/arch/arm/hypercalls32.S

This code is based on the one in Linux  (arch/arm/xen/hypercall.S),
right? IIRC it's a BSD license but you have to keep it.

[..]

> diff --git a/extras/mini-os/arch/arm/mm.c b/extras/mini-os/arch/arm/mm.c
> new file mode 100644
> index 0000000..bb6aa0e
> --- /dev/null
> +++ b/extras/mini-os/arch/arm/mm.c
> @@ -0,0 +1,44 @@
> +#include <console.h>
> +#include <arch_mm.h>
> +
> +#define PHYS_START (0x80008000 + (1000 * 4 * 1024))
> +#define PHYS_SIZE (40*1024*1024)

Same remark as earlier in arm/arm32.S. But I see you don't use them
anymore after patch #10. So please drop the both defines in #10.

[..]

> +void set_vtimer_compare(uint64_t value) {
> +    uint32_t x, y;
> +
> +    DEBUG("New CompareValue : %llx\n", value);
> +    x = 0xFFFFFFFFULL & value;
> +    y = (value >> 32) & 0xFFFFFFFF;
> +
> +    __asm__ __volatile__("mcrr p15, 3, %0, %1, c14\n"
> +            "isb"::"r"(x), "r"(y));
> +
> +    __asm__ __volatile__("mov %0, #0x1\n"
> +            "mcr p15, 0, %0, c14, c3, 1\n" /* Enable timer and unmask the output signal */
> +            "isb":"=r"(x));

I don't think you need to add an isb per instruction. One should be enough.

[..]

> diff --git a/extras/mini-os/drivers/gic.c b/extras/mini-os/drivers/gic.c
> new file mode 100644
> index 0000000..3141830
> --- /dev/null
> +++ b/extras/mini-os/drivers/gic.c
> @@ -0,0 +1,187 @@
> +// ARM GIC implementation
> +
> +#include <mini-os/os.h>
> +#include <mini-os/hypervisor.h>
> +
> +//#define VGIC_DEBUG
> +#ifdef VGIC_DEBUG
> +#define DEBUG(_f, _a...) \
> +    DEBUG("MINI_OS(file=vgic.c, line=%d) " _f , __LINE__, ## _a)
> +#else
> +#define DEBUG(_f, _a...)    ((void)0)
> +#endif
> +
> +extern void (*IRQ_handler)(void);
> +
> +struct gic {
> +    volatile char *gicd_base;
> +    volatile char *gicc_base;
> +};
> +
> +static struct gic gic;
> +
> +// Distributor Interface
> +#define GICD_CTLR        0x0
> +#define GICD_ISENABLER    0x100
> +#define GICD_PRIORITY    0x400

You use the right name for every macro except this one. I would rename 
it to GICD_IPRIORITYR to stay consistent.

> +#define GICD_ITARGETSR    0x800
> +#define GICD_ICFGR        0xC00
> +
> +// CPU Interface
> +#define GICC_CTLR    0x0
> +#define GICC_PMR    0x4
> +#define GICC_IAR    0xc
> +#define GICC_EOIR    0x10
> +#define GICC_HPPIR    0x18
> +
> +#define gicd(gic, offset) ((gic)->gicd_base + (offset))
> +#define gicc(gic, offset) ((gic)->gicc_base + (offset))
> +
> +#define REG(addr) ((uint32_t *)(addr))
> +
> +static inline uint32_t REG_READ32(volatile uint32_t *addr)
> +{
> +    uint32_t value;
> +    __asm__ __volatile__("ldr %0, [%1]":"=&r"(value):"r"(addr));
> +    rmb();
> +    return value;
> +}
> +
> +static inline void REG_WRITE32(volatile uint32_t *addr, unsigned int value)
> +{
> +    __asm__ __volatile__("str %0, [%1]"::"r"(value), "r"(addr));
> +    wmb();
> +}
> +
> +static void gic_set_priority(struct gic *gic, unsigned char irq_number, unsigned char priority)

hmmmm why do you use unsigned char to describe the interrupt?

> +{
> +    uint32_t value;
> +    value = REG_READ32(REG(gicd(gic, GICD_PRIORITY)) + irq_number);

There is 4 interrupts describe per register, this should be (irq_number 
& ~3).

> +    value &= ~(0xff << (8 * (irq_number & 0x3))); // set priority to '0'
> +    value |= priority << (8 * (irq_number & 0x3)); // add our priority

It looks strange that you correctly handle the shift here.

> +    REG_WRITE32(REG(gicd(gic, GICD_PRIORITY)) + irq_number, value);

irq_number & ~3


> +}
> +
> +static void gic_route_interrupt(struct gic *gic, unsigned char irq_number, unsigned char cpu_set)
> +{
> +    uint32_t value;
> +    value = REG_READ32(REG(gicd(gic, GICD_ITARGETSR)) + irq_number);

Same remark as gic_set_priority here.

> +    value &= ~(0xff << (8 * (irq_number & 0x3))); // set priority to '0'
> +    value |= cpu_set << (8 * (irq_number & 0x3)); // add our priority

The comments are wrong in the 2 lines above.

> +    REG_WRITE32(REG(gicd(gic, GICD_ITARGETSR)) + irq_number, value);

irq_number & ~3;

> +}
> +
> +/* When accessing the GIC registers, we can't use LDREX/STREX because it's not regular memory. */
> +static __inline__ void clear_bit_non_atomic(int nr, volatile void *base)
> +{
> +    uint32_t *tmp = (uint32_t *)base;

You don't need to cast here and I suspect your variable need to be 
volatile otherwise the compiler may do some assumption.

> +    tmp[nr >> 5] &= (unsigned long)~(1 << (nr & 0x1f));
> +}
> +
> +static __inline__ void set_bit_non_atomic(int nr, volatile void *base)
> +{
> +    uint32_t *tmp = (uint32_t *)base;

Same remark here.

> +void gic_init(void) {
> +    // FIXME Get from dt!
> +    gic.gicd_base = (char *)0x2c001000ULL;
> +    gic.gicc_base = (char *)0x2c002000ULL;

Those values are wrong.

> diff --git a/extras/mini-os/events.c b/extras/mini-os/events.c
> index 3c92d82..780c74a 100644
> --- a/extras/mini-os/events.c
> +++ b/extras/mini-os/events.c
> @@ -179,6 +179,7 @@ void init_events(void)
>  void fini_events(void)
>  {
>      /* Dealloc all events */
> +    arch_unbind_ports();
>      unbind_all_ports();
>      arch_fini_events();
>  }
> @@ -238,7 +239,8 @@ int evtchn_bind_interdomain(domid_t pal, evtchn_port_t remote_port,
>
>  int evtchn_get_peercontext(evtchn_port_t local_port, char *ctx, int size)
>  {
> -    int rc;
> +    int rc = 0;
> +#ifndef __arm__			/* TODO */

Do you still need this TODO & ifdef? XSM is working correctly on ARM. 
And even if it was not implemented the compilation should not failed.

>      uint32_t sid;
>      struct xen_flask_op op;
>      op.cmd = FLASK_GET_PEER_SID;
> @@ -253,6 +255,7 @@ int evtchn_get_peercontext(evtchn_port_t local_port, char *ctx, int size)
>      op.u.sid_context.size = size;
>      set_xen_guest_handle(op.u.sid_context.context, ctx);
>      rc = _hypercall1(int, xsm_op, &op);
> +#endif
>      return rc;
>  }
>
> diff --git a/extras/mini-os/hypervisor.c b/extras/mini-os/hypervisor.c
> index b4688a0..1b61d9b 100644
> --- a/extras/mini-os/hypervisor.c
> +++ b/extras/mini-os/hypervisor.c
> @@ -64,7 +64,7 @@ void do_hypervisor_callback(struct pt_regs *regs)
>              l2 &= ~(1UL << l2i);
>
>              port = (l1i * (sizeof(unsigned long) * 8)) + l2i;
> -			do_event(port, regs);
> +            do_event(port, regs);

This patch is long and difficult to read. Please avoid indentation 
change in non-modified code at the same time.

>          }
>      }
>
> @@ -73,18 +73,26 @@ void do_hypervisor_callback(struct pt_regs *regs)
>
>  void force_evtchn_callback(void)
>  {
> +#ifdef XEN_HAVE_PV_UPCALL_MASK
>      int save;
> +#endif
>      vcpu_info_t *vcpu;
>      vcpu = &HYPERVISOR_shared_info->vcpu_info[smp_processor_id()];
> +#ifdef XEN_HAVE_PV_UPCALL_MASK
>      save = vcpu->evtchn_upcall_mask;
> +#endif
>
>      while (vcpu->evtchn_upcall_pending) {
> +#ifdef XEN_HAVE_PV_UPCALL_MASK
>          vcpu->evtchn_upcall_mask = 1;
> +#endif
>          barrier();
>          do_hypervisor_callback(NULL);
>          barrier();
> +#ifdef XEN_HAVE_PV_UPCALL_MASK
>          vcpu->evtchn_upcall_mask = save;
>          barrier();
> +#endif
>      };
>  }
>
> @@ -110,7 +118,9 @@ inline void unmask_evtchn(uint32_t port)
>                &vcpu_info->evtchn_pending_sel) )
>      {
>          vcpu_info->evtchn_upcall_pending = 1;
> +#ifdef XEN_HAVE_PV_UPCALL_MASK
>          if ( !vcpu_info->evtchn_upcall_mask )
> +#endif
>              force_evtchn_callback();
>      }
>  }

I would have move those change in a separate patch.


[..]

> diff --git a/extras/mini-os/include/arm/arch_spinlock.h b/extras/mini-os/include/arm/arch_spinlock.h
> new file mode 100755
> index 0000000..d57f150
> --- /dev/null
> +++ b/extras/mini-os/include/arm/arch_spinlock.h
> @@ -0,0 +1,49 @@
> +
> +
> +#ifndef __ARCH_ASM_SPINLOCK_H
> +#define __ARCH_ASM_SPINLOCK_H
> +
> +#include "os.h"
> +
> +
> +#define ARCH_SPIN_LOCK_UNLOCKED { 1 }
> +
> +/*
> + * Simple spin lock operations.  There are two variants, one clears IRQ's
> + * on the local processor, one does not.
> + *
> + * We make no fairness assumptions. They have a cost.
> + */
> +
> +#define arch_spin_is_locked(x)    (*(volatile signed char *)(&(x)->slock) <= 0)
> +#define arch_spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x))
> +
> +/*
> + * This works. Despite all the confusion.
> + * (except on PPro SMP or if we are using OOSTORE)
> + * (PPro errata 66, 92)
> + */

This comment is x86... It should not have been copied here.

> +
> +static inline void _raw_spin_unlock(spinlock_t *lock)
> +{
> +    xchg(&lock->slock, 1);
> +}
> +
> +static inline int _raw_spin_trylock(spinlock_t *lock)
> +{
> +    return xchg(&lock->slock, 0) != 0 ? 1 : 0;
> +}
> +
> +static inline void _raw_spin_lock(spinlock_t *lock)
> +{
> +    volatile int was_locked;
> +    do {
> +        was_locked = xchg(&lock->slock, 0) == 0 ? 1 : 0;
> +    } while(was_locked);
> +}
> +
> +static inline void _raw_spin_lock_flags (spinlock_t *lock, unsigned long flags)
> +{

You didn't implement this function. It looks like it's not used in 
mini-os, right? If so, please add a BUG_ON just in case that someone 
decide to use it later.

> diff --git a/extras/mini-os/include/arm/hypercall-arm32.h b/extras/mini-os/include/arm/hypercall-arm32.h
> new file mode 100644
> index 0000000..0fc1c03
> --- /dev/null
> +++ b/extras/mini-os/include/arm/hypercall-arm32.h

Actually this file can be name hypercall.h. On ARM64 the set of 
hypercall is exactly the same. The only different that you will have 
between both architecture is the assembly code and the system registers.

[..]

> +inline int
> +HYPERVISOR_mmu_update(
> +    mmu_update_t *req, int count, int *success_count, domid_t domid);

Why do you use inline in all external functions in this include?

Hence most of this hypercall doesn't exist on ARM. Please define only 
the necessary one.

[..]

> +#endif /* __HYPERCALL_X86_64_H__ */

__HYPERCALL_ARM_H__


[..]

> +// disable interrupts
> +static inline __cli(void) {

I see that you use __cli and __sti only
__cli and __sti are only in 2 defines below. These name are only x86 
specific. Please rename them or merge this code in 
local_irq_{disable,enable}

> +    int x;
> +    __asm__ __volatile__("mrs %0, cpsr;cpsid i":"=r"(x)::"memory");

Why do you need to read cpsr. cpsid i is enough here.

> +}
> +
> +// enable interrupts
> +static inline __sti(void) {
> +    int x;
> +    __asm__ __volatile__("mrs %0, cpsr\n"
> +                        "bic %0, %0, #0x80\n"
> +                        "msr cpsr_c, %0"
> +                        :"=r"(x)::"memory");

This can simply be done by cpsie i

> +}
> +
> +static inline int irqs_disabled() {
> +    int x;
> +    __asm__ __volatile__("mrs %0, cpsr\n":"=r"(x)::"memory");
> +    return (x & 0x80);

You can use local_save_flags directly.

> +}
> +
> +#define local_irq_save(x) { \
> +    __asm__ __volatile__("mrs %0, cpsr;cpsid i; and %0, %0, #0x80":"=r"(x)::"memory");    \
> +}
> +
> +#define local_irq_restore(x) {    \
> +    __asm__ __volatile__("msr cpsr_c, %0"::"r"(x):"memory");    \
> +}

If you mask the result in local_irq_save, and use this value directly is 
local_irq_restore, you will disable by mistake the Asynchronous Abort 
exception....

You have to remove the and %0... at the end.

> +#define local_save_flags(x)    { \
> +    __asm__ __volatile__("mrs %0, cpsr; and %0, %0, 0x80":"=r"(x)::"memory");    \
> +}

Same remark here.

> +#define local_irq_disable()    __cli()
> +#define local_irq_enable() __sti()
> +
> +#if defined(__arm__)
> +#define mb() __asm__("dmb");
> +#define rmb() __asm__("dmb");
> +#define wmb() __asm__("dmb");

I suspect you want to dsb here. You want to make sure that every memory 
access has finished avoid executing new instruction until this is done.

dmb only ensure the memory ordering.

Also, you want to clobber the memory to avoid the compiler:
	1) reordering the instructions
	2) prefetch data from the memory

> +#elif defined(__aarch64__)
> +#define mb()
> +#define rmb()
> +#define wmb()

I'm confused with this piece of code... memory barrier are also required 
on aarch64. Hence dmb/isb also exist on this architecture

You don't need the if ... elif ... else

> +#define unlikely(x)  __builtin_expect((x),0)
> +#define likely(x)  __builtin_expect((x),1)

Can't it be common with x86?

[..]

>  int do_event(evtchn_port_t port, struct pt_regs *regs);
> diff --git a/extras/mini-os/include/gic.h b/extras/mini-os/include/gic.h
> new file mode 100644
> index 0000000..cead2e5
> --- /dev/null
> +++ b/extras/mini-os/include/gic.h
> @@ -0,0 +1 @@
> +void gic_init(void);
> diff --git a/extras/mini-os/include/hypervisor.h b/extras/mini-os/include/hypervisor.h
> index a62cb78..052f4f8 100644
> --- a/extras/mini-os/include/hypervisor.h
> +++ b/extras/mini-os/include/hypervisor.h
> @@ -18,6 +18,10 @@
>  #include <hypercall-x86_32.h>
>  #elif defined(__x86_64__)
>  #include <hypercall-x86_64.h>
> +#elif defined(__arm__)
> +#include <hypercall-arm32.h>
> +#elif defined(__aarch64__)
> +#include <hypercall-arm64.h>

Hmmm, the filehypercall-arm64.h doesn't exists in this series...

Futhermore, as I said ealier the set of hypercall is exactly the same on 
arm64.

[..]

> +#if defined(__i386__) || defined(__arm__)
>  typedef long long           quad_t;
>  typedef unsigned long long  u_quad_t;
>
> @@ -40,7 +40,7 @@ typedef unsigned long       u_quad_t;
>  typedef struct { unsigned long pte; } pte_t;
>  #endif /* __i386__ || __x86_64__ */
>
> -#ifdef __x86_64__
> +#if defined(__x86_64__) || defined(__aarch64__)
>  #define __pte(x) ((pte_t) { (x) } )

This looks wrong to me. The pte layout is exactly the same on arm32 and 
arm64. Hence, this is only used in the x86 code. Please either move 
pte_t in x86 part or define it correctly on ARM...

[..]

> diff --git a/extras/mini-os/kernel.c b/extras/mini-os/kernel.c
> index 9a30550..7b2b8fc 100644
> --- a/extras/mini-os/kernel.c
> +++ b/extras/mini-os/kernel.c
> @@ -47,6 +47,10 @@
>  #include <xen/features.h>
>  #include <xen/version.h>
>
> +#ifdef __arm__
> +#include <mini-os/gic.h>
> +#endif
> +
>  uint8_t xen_features[XENFEAT_NR_SUBMAPS * 32];
>
>  void setup_xen_features(void)
> @@ -147,6 +151,10 @@ void start_kernel(void)
>      create_thread("shutdown", shutdown_thread, NULL);
>  #endif
>
> +#ifdef __arm__
> +    gic_init();
> +#endif
> +

I would define a function arch_init. This will avoid the #ifdef __arm__ 
in the code common.

Hence, it looks strange that sometime you have #if __arm__ && __arch64__ 
and sometimes not...

>      /* Call (possibly overridden) app_main() */
>      app_main(&start_info);
>
> diff --git a/extras/mini-os/sched.c b/extras/mini-os/sched.c
> index 174945e..b99d7dc 100644
> --- a/extras/mini-os/sched.c
> +++ b/extras/mini-os/sched.c
> @@ -145,6 +145,9 @@ struct thread* create_thread(char *name, void (*function)(void *), void *data)
>      unsigned long flags;
>      /* Call architecture specific setup. */
>      thread = arch_create_thread(name, function, data);
> +    if(!thread)
> +        BUG(); //For now, FIXME should just return NULL
> +

This change is in the common code. I think this should go in a separate 
patch.

Hence looking again to arch_create_thread for ARM you:
	1) never return NULL
	2) never check the xmalloc/alloc_pages return.

>      /* Not runable, not exited, not sleeping */
>      thread->flags = 0;
>      thread->wakeup_time = 0LL;
> @@ -165,28 +168,28 @@ struct _reent *__getreent(void)
>      struct _reent *_reent;
>
>      if (!threads_started)
> -	_reent = _impure_ptr;
> +        _reent = _impure_ptr;
>      else if (in_callback)
> -	_reent = &callback_reent;
> +        _reent = &callback_reent;
>      else
> -	_reent = &get_current()->reent;
> +        _reent = &get_current()->reent;
>  #ifndef NDEBUG
>  #if defined(__x86_64__) || defined(__x86__)
>      {
>  #ifdef __x86_64__
> -	register unsigned long sp asm ("rsp");
> +        register unsigned long sp asm ("rsp");
>  #else
> -	register unsigned long sp asm ("esp");
> +        register unsigned long sp asm ("esp");
>  #endif
> -	if ((sp & (STACK_SIZE-1)) < STACK_SIZE / 16) {
> -	    static int overflowing;
> -	    if (!overflowing) {
> -		overflowing = 1;
> -		printk("stack overflow\n");
> -		BUG();
> -	    }
> -	}
> +        if ((sp & (STACK_SIZE-1)) < STACK_SIZE / 16) {
> +            static int overflowing;
> +            if (!overflowing) {
> +                overflowing = 1;
> +                printk("stack overflow\n");
> +                BUG();
> +            }
> +        }

all this chunk: spurious changes?

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 10/12] mini-os: get RAM base and size from the FDT
  2014-06-18 17:38   ` Julien Grall
@ 2014-06-19  8:39     ` Thomas Leonard
  2014-06-19 11:24       ` Julien Grall
  0 siblings, 1 reply; 41+ messages in thread
From: Thomas Leonard @ 2014-06-19  8:39 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Stefano Stabellini, David Scott, Samuel Thibault,
	Anil Madhavapeddy

On 18 June 2014 18:38, Julien Grall <julien.grall@linaro.org> wrote:
> Hi Thomas,
>
> On 06/18/2014 04:08 PM, Thomas Leonard wrote:
>> +        const char *device_type = fdt_getprop(device_tree, node, "device_type", NULL);
>> +        if (device_type && !strcmp(device_type, "memory"))
>> +        {
>> +            /* Note: we assume there's only a single region of memory.
>> +             * Since Xen is already translating our "physical"
>> +             * addresses to the real physical RAM, there's no
>> +             * reason for it to give us multiple blocks. */
>
> This comment looks wrong to me. Even tho, Xen is providing a stage-2
> translation to show you a virtual layout (your guest physical memory),
> the new layout in Xen upstream may contain multiple banks. The first
> bank will contain up to 3G of RAM.

Hi Julien,

At the Hackathon, we decided Mini-OS could always rely on Xen to
provide the memory in a single block:

"ARM guests are allowed to assume one bank of memory. We need to
document this in the ABI. ARM guests should assume the presence of an
FDT."

http://lists.xenproject.org/archives/html/mirageos-devel/2014-06/msg00004.html

A lot of the value of running on Xen is that we only have to support a
small number of configurations, because Xen hides the details of the
physical hardware. I assume the only reason for using the (very
flexible) FDT format to provide this information is that it's simpler
for full OSs which already use FDTs.

Is the ARM guest ABI documented somewhere?


>> index d2d5264..d31ef97 100644
>> --- a/extras/mini-os/mm.c
>> +++ b/extras/mini-os/mm.c
>> @@ -409,8 +409,8 @@ void init_mm(void)
>>       * now we can initialise the page allocator
>>       */
>>      printk("MM: Initialise page allocator for %lx(%lx)-%lx(%lx)\n",
>> -           (u_long)to_virt(PFN_PHYS(start_pfn)), PFN_PHYS(start_pfn),
>> -           (u_long)to_virt(PFN_PHYS(max_pfn)), PFN_PHYS(max_pfn));
>> +           (u_long)to_virt(PFN_PHYS(start_pfn)), (u_long)PFN_PHYS(start_pfn),
>> +           (u_long)to_virt(PFN_PHYS(max_pfn)), (u_long)PFN_PHYS(max_pfn));
>
> I don't see any modification of the type of max_pfn, start_pfn,
> PFN_PHYS. This change should not be part of this patch.




-- 
Dr Thomas Leonard        http://0install.net/
GPG: 9242 9807 C985 3C07 44A6  8B9A AE07 8280 59A5 3CC1
GPG: DA98 25AE CAD0 8975 7CDA  BD8E 0713 3F96 CA74 D8BA

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 11/12] mini-os: get GIC addresses from FDT
  2014-06-18 17:25   ` Julien Grall
@ 2014-06-19  8:50     ` Thomas Leonard
  2014-06-19 10:58       ` Julien Grall
  2014-07-02 15:55       ` Ian Campbell
  0 siblings, 2 replies; 41+ messages in thread
From: Thomas Leonard @ 2014-06-19  8:50 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Stefano Stabellini, David Scott, Samuel Thibault,
	Anil Madhavapeddy

On 18 June 2014 18:25, Julien Grall <julien.grall@linaro.org> wrote:
> Hi Thomas,
>
> On 06/18/2014 04:08 PM, Thomas Leonard wrote:
>>  //#define VGIC_DEBUG
>>  #ifdef VGIC_DEBUG
>> @@ -168,9 +169,38 @@ static void gic_handler(void) {
>>  }
>>
>>  void gic_init(void) {
>> -    // FIXME Get from dt!
>> -    gic.gicd_base = (char *)0x2c001000ULL;
>> -    gic.gicc_base = (char *)0x2c002000ULL;
>> +    gic.gicd_base = NULL;
>
> Any reason to not fold this patch in patch #7? Or better move the gic
> code in a separate patch?

It was previously requested that I split the FDT patch from the main
ARM one. This patch depends on libfdt being present, so it has to go
after that.

Moving all the GIC code to this patch would mean that the original
patch wouldn't work on its own.

> This would avoid to hardcode a GIC address which is completely wrong
> with Xen unstable.
>
>> +    int node = 0;
>> +    int depth = 0;
>> +    for (;;)
>> +    {
>> +        node = fdt_next_node(device_tree, node, &depth);
>> +        if (node <= 0 || depth < 0)
>> +            break;
>> +
>> +        /*
>> +           int name_len = 0;
>> +           const char *name = fdt_get_name(device_tree, node, &name_len);
>> +           printk("Found node: %d (%.*s)\n", node, name_len, name);
>> +         */
>
> This should be drop.
>
>> +
>> +        if (fdt_getprop(device_tree, node, "interrupt-controller", NULL)) {
>
> You have to check the compatible string here.
>
>> +            int len = 0;
>> +            const uint64_t *reg = fdt_getprop(device_tree, node, "reg", &len);
>> +            if (reg == NULL || len != 32) {
>
> You made assumption of the layout of the device tree provided by Xen:
>         - #address-cells == #size-cells == 2
>         - regs contains a valid physical address, i.e the device is not under a bus
>
> This can be changed by the toolstack in the future and will likely break
> mini-os.

Is that likely? Seems like using BUG here is the right thing to do
until that happens.

> I would add a layer to support FDT address and interrupt translation
> correctly. I'm not the maintainer of the mini-os, so I let them decide :).
>
> I think, FreeBSD provides a good library for the translation (see
> sys/dev/fdt/fdt_common.c).
>
> I spent lots of time to play with device tree on Xen side, so I can help
> you if you needed.

That would be very helpful - thanks!



-- 
Dr Thomas Leonard        http://0install.net/
GPG: 9242 9807 C985 3C07 44A6  8B9A AE07 8280 59A5 3CC1
GPG: DA98 25AE CAD0 8975 7CDA  BD8E 0713 3F96 CA74 D8BA

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 11/12] mini-os: get GIC addresses from FDT
  2014-06-19  8:50     ` Thomas Leonard
@ 2014-06-19 10:58       ` Julien Grall
  2014-06-19 16:14         ` Thomas Leonard
  2014-07-02 15:55       ` Ian Campbell
  1 sibling, 1 reply; 41+ messages in thread
From: Julien Grall @ 2014-06-19 10:58 UTC (permalink / raw)
  To: Thomas Leonard
  Cc: xen-devel, Stefano Stabellini, David Scott, Samuel Thibault,
	Anil Madhavapeddy

Hi Thomas,

On 06/19/2014 09:50 AM, Thomas Leonard wrote:
> On 18 June 2014 18:25, Julien Grall <julien.grall@linaro.org> wrote:
>> Hi Thomas,
>>
>> On 06/18/2014 04:08 PM, Thomas Leonard wrote:
>>>  //#define VGIC_DEBUG
>>>  #ifdef VGIC_DEBUG
>>> @@ -168,9 +169,38 @@ static void gic_handler(void) {
>>>  }
>>>
>>>  void gic_init(void) {
>>> -    // FIXME Get from dt!
>>> -    gic.gicd_base = (char *)0x2c001000ULL;
>>> -    gic.gicc_base = (char *)0x2c002000ULL;
>>> +    gic.gicd_base = NULL;
>>
>> Any reason to not fold this patch in patch #7? Or better move the gic
>> code in a separate patch?
> 
> It was previously requested that I split the FDT patch from the main
> ARM one. This patch depends on libfdt being present, so it has to go
> after that.

Please make sure that this "standalone patch" works correctly on Xen
unstable...

> Moving all the GIC code to this patch would mean that the original
> patch wouldn't work on its own.

I'm not sure why you want to have a single big patch to support ARM...
AFAIU, there is some patch requirements to work correctly.


>> You made assumption of the layout of the device tree provided by Xen:
>>         - #address-cells == #size-cells == 2
>>         - regs contains a valid physical address, i.e the device is not under a bus
>>
>> This can be changed by the toolstack in the future and will likely break
>> mini-os.
> 
> Is that likely? Seems like using BUG here is the right thing to do
> until that happens.

You need at least to add a comment about the (len != 32). It's confusing
for people that doesn't know how the device tree has been created.

I still think that a layer for IRQ and MMIO translation would be helpful
for mini-os. So you will directly get the range (base + size), and won't
duplicate checking code on every part of mini-os.

> That would be very helpful - thanks!

You can join #xenarm for any question if you are not already there.

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 10/12] mini-os: get RAM base and size from the FDT
  2014-06-19  8:39     ` Thomas Leonard
@ 2014-06-19 11:24       ` Julien Grall
  2014-07-02 15:51         ` Ian Campbell
  0 siblings, 1 reply; 41+ messages in thread
From: Julien Grall @ 2014-06-19 11:24 UTC (permalink / raw)
  To: Thomas Leonard
  Cc: xen-devel, Stefano Stabellini, David Scott, Samuel Thibault,
	Anil Madhavapeddy

On 06/19/2014 09:39 AM, Thomas Leonard wrote:
> On 18 June 2014 18:38, Julien Grall <julien.grall@linaro.org> wrote:
>> Hi Thomas,
>>
>> On 06/18/2014 04:08 PM, Thomas Leonard wrote:
>>> +        const char *device_type = fdt_getprop(device_tree, node, "device_type", NULL);
>>> +        if (device_type && !strcmp(device_type, "memory"))
>>> +        {
>>> +            /* Note: we assume there's only a single region of memory.
>>> +             * Since Xen is already translating our "physical"
>>> +             * addresses to the real physical RAM, there's no
>>> +             * reason for it to give us multiple blocks. */
>>
>> This comment looks wrong to me. Even tho, Xen is providing a stage-2
>> translation to show you a virtual layout (your guest physical memory),
>> the new layout in Xen upstream may contain multiple banks. The first
>> bank will contain up to 3G of RAM.
> 
> Hi Julien,

Hello Thomas,

> At the Hackathon, we decided Mini-OS could always rely on Xen to
> provide the memory in a single block:
> 
> "ARM guests are allowed to assume one bank of memory. We need to
> document this in the ABI. ARM guests should assume the presence of an
> FDT."

I'm not against only supporting one bank... I pointed that your comment
is wrong and doesn't reflect this sentence.

I didn't attend to this meeting, but I guess it was meant that the guest
can assume there is always one bank of memory.

I would change your comment into:

"Xen will always provide us at least one bank of memory. Mini-os will
use the first bank for the time-being"

> http://lists.xenproject.org/archives/html/mirageos-devel/2014-06/msg00004.html
> 
> A lot of the value of running on Xen is that we only have to support a
> small number of configurations, because Xen hides the details of the
> physical hardware. I assume the only reason for using the (very
> flexible) FDT format to provide this information is that it's simpler
> for full OSs which already use FDTs.

As specified in the ABI, the guest layout may change from time to time.
Actually, the layout is not compatible between Xen 4.4 and 4.5.

Unless you want your OS tight to a Xen specific version, I don't think
we want that for mini-os. You have to correctly support FDT and retrieve
every information (MMIO, IRQ) from it.

> Is the ARM guest ABI documented somewhere?

You can find the guest layout described in xen/include/public/arch-arm.h

Regards

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 11/12] mini-os: get GIC addresses from FDT
  2014-06-19 10:58       ` Julien Grall
@ 2014-06-19 16:14         ` Thomas Leonard
  2014-06-19 16:20           ` Julien Grall
  0 siblings, 1 reply; 41+ messages in thread
From: Thomas Leonard @ 2014-06-19 16:14 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Stefano Stabellini, David Scott, Samuel Thibault,
	Anil Madhavapeddy

On 19 June 2014 11:58, Julien Grall <julien.grall@linaro.org> wrote:
> Hi Thomas,
>
> On 06/19/2014 09:50 AM, Thomas Leonard wrote:
>> On 18 June 2014 18:25, Julien Grall <julien.grall@linaro.org> wrote:
>>> Hi Thomas,
>>>
>>> On 06/18/2014 04:08 PM, Thomas Leonard wrote:
>>>>  //#define VGIC_DEBUG
>>>>  #ifdef VGIC_DEBUG
>>>> @@ -168,9 +169,38 @@ static void gic_handler(void) {
>>>>  }
>>>>
>>>>  void gic_init(void) {
>>>> -    // FIXME Get from dt!
>>>> -    gic.gicd_base = (char *)0x2c001000ULL;
>>>> -    gic.gicc_base = (char *)0x2c002000ULL;
>>>> +    gic.gicd_base = NULL;
>>>
>>> Any reason to not fold this patch in patch #7? Or better move the gic
>>> code in a separate patch?
>>
>> It was previously requested that I split the FDT patch from the main
>> ARM one. This patch depends on libfdt being present, so it has to go
>> after that.
>
> Please make sure that this "standalone patch" works correctly on Xen
> unstable...

OK, I can make it use GUEST_GICD_BASE/GUEST_GICC_BASE (with a FIXME)
so that the first commit works on unstable.

I tried installing the unstable version (staging branch) of Xen to
test it, but for some reason it didn't work:

# LD_LIBRARY_PATH=/opt/xen-4.5-unstable/lib/ /opt/xen-4.5-unstable/sbin/xl dmesg
xc: error: Could not obtain handle on privileged command interface (2
= No such file or directory): Internal error
libxl: error: libxl.c:99:libxl_ctx_alloc: cannot open libxc handle: No
such file or directory
cannot init xl context

It tries to open "/proc/xen/privcmd", which doesn't exist. Maybe I
need a newer Linux kernel? That could be tricky, as I'm using a
special fork for this board.

>> Moving all the GIC code to this patch would mean that the original
>> patch wouldn't work on its own.
>
> I'm not sure why you want to have a single big patch to support ARM...
> AFAIU, there is some patch requirements to work correctly.

If it isn't necessary that the first commit works, then I can split
things up further (e.g. all the include files first, then just
arm32.S, etc), but I'm not sure how much that would help. Let me know
what's easiest for reviewing.

>>> You made assumption of the layout of the device tree provided by Xen:
>>>         - #address-cells == #size-cells == 2
>>>         - regs contains a valid physical address, i.e the device is not under a bus
>>>
>>> This can be changed by the toolstack in the future and will likely break
>>> mini-os.
>>
>> Is that likely? Seems like using BUG here is the right thing to do
>> until that happens.
>
> You need at least to add a comment about the (len != 32). It's confusing
> for people that doesn't know how the device tree has been created.
>
> I still think that a layer for IRQ and MMIO translation would be helpful
> for mini-os. So you will directly get the range (base + size), and won't
> duplicate checking code on every part of mini-os.
>
>> That would be very helpful - thanks!
>
> You can join #xenarm for any question if you are not already there.
>
> Regards,
>
> --
> Julien Grall



-- 
Dr Thomas Leonard        http://0install.net/
GPG: 9242 9807 C985 3C07 44A6  8B9A AE07 8280 59A5 3CC1
GPG: DA98 25AE CAD0 8975 7CDA  BD8E 0713 3F96 CA74 D8BA

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 11/12] mini-os: get GIC addresses from FDT
  2014-06-19 16:14         ` Thomas Leonard
@ 2014-06-19 16:20           ` Julien Grall
  0 siblings, 0 replies; 41+ messages in thread
From: Julien Grall @ 2014-06-19 16:20 UTC (permalink / raw)
  To: Thomas Leonard
  Cc: xen-devel, Stefano Stabellini, David Scott, Samuel Thibault,
	Anil Madhavapeddy

On 06/19/2014 05:14 PM, Thomas Leonard wrote:
> On 19 June 2014 11:58, Julien Grall <julien.grall@linaro.org> wrote:
>> On 06/19/2014 09:50 AM, Thomas Leonard wrote:
>>> On 18 June 2014 18:25, Julien Grall <julien.grall@linaro.org> wrote:
>>>> Hi Thomas,
>>>>
>>>> On 06/18/2014 04:08 PM, Thomas Leonard wrote:
>>>>>  //#define VGIC_DEBUG
>>>>>  #ifdef VGIC_DEBUG
>>>>> @@ -168,9 +169,38 @@ static void gic_handler(void) {
>>>>>  }
>>>>>
>>>>>  void gic_init(void) {
>>>>> -    // FIXME Get from dt!
>>>>> -    gic.gicd_base = (char *)0x2c001000ULL;
>>>>> -    gic.gicc_base = (char *)0x2c002000ULL;
>>>>> +    gic.gicd_base = NULL;
>>>>
>>>> Any reason to not fold this patch in patch #7? Or better move the gic
>>>> code in a separate patch?
>>>
>>> It was previously requested that I split the FDT patch from the main
>>> ARM one. This patch depends on libfdt being present, so it has to go
>>> after that.
>>
>> Please make sure that this "standalone patch" works correctly on Xen
>> unstable...
> 
> OK, I can make it use GUEST_GICD_BASE/GUEST_GICC_BASE (with a FIXME)
> so that the first commit works on unstable.

This 2 defines are only exposed to XEN and XEN tools. I don't think you
will be able to use it for mini-os.

> I tried installing the unstable version (staging branch) of Xen to
> test it, but for some reason it didn't work:
> 
> # LD_LIBRARY_PATH=/opt/xen-4.5-unstable/lib/ /opt/xen-4.5-unstable/sbin/xl dmesg
> xc: error: Could not obtain handle on privileged command interface (2
> = No such file or directory): Internal error
> libxl: error: libxl.c:99:libxl_ctx_alloc: cannot open libxc handle: No
> such file or directory
> cannot init xl context
> 
> It tries to open "/proc/xen/privcmd", which doesn't exist. Maybe I
> need a newer Linux kernel? That could be tricky, as I'm using a
> special fork for this board.

Did you start xencommons?

/etc/init.d/xencommons start

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 07/12] mini-os: initial ARM support
  2014-06-18 22:40   ` Julien Grall
@ 2014-06-23 15:10     ` Thomas Leonard
  2014-06-23 16:55       ` Julien Grall
  0 siblings, 1 reply; 41+ messages in thread
From: Thomas Leonard @ 2014-06-23 15:10 UTC (permalink / raw)
  To: Julien Grall
  Cc: David Scott, Stefano Stabellini, Anil Madhavapeddy,
	Samuel Thibault, xen-devel

On 18 June 2014 23:40, Julien Grall <julien.grall@linaro.org> wrote:
> Hi Thomas,

Hi Julien,

Thanks for reviewing this!

> On 06/18/2014 04:08 PM, Thomas Leonard wrote:
>>
>> diff --git a/extras/mini-os/arch/arm/arm32.S
>> b/extras/mini-os/arch/arm/arm32.S
>> new file mode 100644
>> index 0000000..4f953ec
>> --- /dev/null
>> +++ b/extras/mini-os/arch/arm/arm32.S
>> @@ -0,0 +1,155 @@
>> +#define PHYS_START (0x80008000)
>
>
> This address is wrong with the latest xen unstable. Any reason to make
> mini-os tight to a specific physical address?

I'll remove this in the next version.

> [..]
>
>
>> diff --git a/extras/mini-os/arch/arm/hypercalls32.S
>> b/extras/mini-os/arch/arm/hypercalls32.S
>> new file mode 100644
>> index 0000000..e2f21c4
>> --- /dev/null
>> +++ b/extras/mini-os/arch/arm/hypercalls32.S
>
>
> This code is based on the one in Linux  (arch/arm/xen/hypercall.S),
> right? IIRC it's a BSD license but you have to keep it.

I don't know where it came from, but you're probably right. I've added
the header back in.

> [..]
>
>
>> diff --git a/extras/mini-os/arch/arm/mm.c b/extras/mini-os/arch/arm/mm.c
>> new file mode 100644
>> index 0000000..bb6aa0e
>> --- /dev/null
>> +++ b/extras/mini-os/arch/arm/mm.c
>> @@ -0,0 +1,44 @@
>> +#include <console.h>
>> +#include <arch_mm.h>
>> +
>> +#define PHYS_START (0x80008000 + (1000 * 4 * 1024))
>> +#define PHYS_SIZE (40*1024*1024)
>
>
> Same remark as earlier in arm/arm32.S. But I see you don't use them
> anymore after patch #10. So please drop the both defines in #10.

I've reordered the patches so we don't need this now.

> [..]
>
>
>> +void set_vtimer_compare(uint64_t value) {
>> +    uint32_t x, y;
>> +
>> +    DEBUG("New CompareValue : %llx\n", value);
>> +    x = 0xFFFFFFFFULL & value;
>> +    y = (value >> 32) & 0xFFFFFFFF;
>> +
>> +    __asm__ __volatile__("mcrr p15, 3, %0, %1, c14\n"
>> +            "isb"::"r"(x), "r"(y));
>> +
>> +    __asm__ __volatile__("mov %0, #0x1\n"
>> +            "mcr p15, 0, %0, c14, c3, 1\n" /* Enable timer and unmask the
>> output signal */
>> +            "isb":"=r"(x));
>
>
> I don't think you need to add an isb per instruction. One should be enough.

Actually, do we need one at all? Setting the timer shouldn't affect
the instruction pipline, I think.

> [..]
>
>
>> diff --git a/extras/mini-os/drivers/gic.c b/extras/mini-os/drivers/gic.c
>> new file mode 100644
>> index 0000000..3141830
>> --- /dev/null
>> +++ b/extras/mini-os/drivers/gic.c
>> @@ -0,0 +1,187 @@
>> +// ARM GIC implementation
>> +
>> +#include <mini-os/os.h>
>> +#include <mini-os/hypervisor.h>
>> +
>> +//#define VGIC_DEBUG
>> +#ifdef VGIC_DEBUG
>> +#define DEBUG(_f, _a...) \
>> +    DEBUG("MINI_OS(file=vgic.c, line=%d) " _f , __LINE__, ## _a)
>> +#else
>> +#define DEBUG(_f, _a...)    ((void)0)
>> +#endif
>> +
>> +extern void (*IRQ_handler)(void);
>> +
>> +struct gic {
>> +    volatile char *gicd_base;
>> +    volatile char *gicc_base;
>> +};
>> +
>> +static struct gic gic;
>> +
>> +// Distributor Interface
>> +#define GICD_CTLR        0x0
>> +#define GICD_ISENABLER    0x100
>> +#define GICD_PRIORITY    0x400
>
>
> You use the right name for every macro except this one. I would rename it to
> GICD_IPRIORITYR to stay consistent.

Done.

>> +#define GICD_ITARGETSR    0x800
>> +#define GICD_ICFGR        0xC00
>> +
>> +// CPU Interface
>> +#define GICC_CTLR    0x0
>> +#define GICC_PMR    0x4
>> +#define GICC_IAR    0xc
>> +#define GICC_EOIR    0x10
>> +#define GICC_HPPIR    0x18
>> +
>> +#define gicd(gic, offset) ((gic)->gicd_base + (offset))
>> +#define gicc(gic, offset) ((gic)->gicc_base + (offset))
>> +
>> +#define REG(addr) ((uint32_t *)(addr))
>> +
>> +static inline uint32_t REG_READ32(volatile uint32_t *addr)
>> +{
>> +    uint32_t value;
>> +    __asm__ __volatile__("ldr %0, [%1]":"=&r"(value):"r"(addr));
>> +    rmb();
>> +    return value;
>> +}
>> +
>> +static inline void REG_WRITE32(volatile uint32_t *addr, unsigned int
>> value)
>> +{
>> +    __asm__ __volatile__("str %0, [%1]"::"r"(value), "r"(addr));
>> +    wmb();
>> +}
>> +

Do we need inline assembler to write these values? I'd imagine that a
plain C store to a volatile 32-bit pointer would always do the same
thing.

>> +static void gic_set_priority(struct gic *gic, unsigned char irq_number,
>> unsigned char priority)
>
>
> hmmmm why do you use unsigned char to describe the interrupt?

Yes, that's clearly wrong. Interrupt numbers don't fit in 8 bits.

>> +{
>> +    uint32_t value;
>> +    value = REG_READ32(REG(gicd(gic, GICD_PRIORITY)) + irq_number);
>
>
> There is 4 interrupts describe per register, this should be (irq_number &
> ~3).

Or should it be (irq_number >> 2)? REG casts to uint32_t.

>> +    value &= ~(0xff << (8 * (irq_number & 0x3))); // set priority to '0'
>> +    value |= priority << (8 * (irq_number & 0x3)); // add our priority
>
>
> It looks strange that you correctly handle the shift here.

>> +    REG_WRITE32(REG(gicd(gic, GICD_PRIORITY)) + irq_number, value);
>
>
> irq_number & ~3
>
>
>
>> +}
>> +
>> +static void gic_route_interrupt(struct gic *gic, unsigned char
>> irq_number, unsigned char cpu_set)
>> +{
>> +    uint32_t value;
>> +    value = REG_READ32(REG(gicd(gic, GICD_ITARGETSR)) + irq_number);
>
>
> Same remark as gic_set_priority here.
>
>
>> +    value &= ~(0xff << (8 * (irq_number & 0x3))); // set priority to '0'
>> +    value |= cpu_set << (8 * (irq_number & 0x3)); // add our priority
>
>
> The comments are wrong in the 2 lines above.
>
>
>> +    REG_WRITE32(REG(gicd(gic, GICD_ITARGETSR)) + irq_number, value);
>
>
> irq_number & ~3;

The ARM Generic Interrupt Controller Architecture Specification says
"These registers are byte-accessible.". So we should be able to write
the byte directly. I thought this might work:

static void gic_route_interrupt(struct gic *gic, int irq_number,
unsigned char cpu_set)
{
    gicd(gic, GICD_ITARGETSR)[irq_number] = cpu_set;
    wmb();
}

But it doesn't, because Xen's write_ignore handler (vgic.c:656 on the
4.4 branch) does:

write_ignore:
  if ( dabt.size != 2 ) goto bad_width;

Bug?

>> +}
>> +
>> +/* When accessing the GIC registers, we can't use LDREX/STREX because
>> it's not regular memory. */
>> +static __inline__ void clear_bit_non_atomic(int nr, volatile void *base)
>> +{
>> +    uint32_t *tmp = (uint32_t *)base;
>
>
> You don't need to cast here and I suspect your variable need to be volatile
> otherwise the compiler may do some assumption.

OK.

>> +    tmp[nr >> 5] &= (unsigned long)~(1 << (nr & 0x1f));
>> +}
>> +
>> +static __inline__ void set_bit_non_atomic(int nr, volatile void *base)
>> +{
>> +    uint32_t *tmp = (uint32_t *)base;
>
>
> Same remark here.

OK.

>> +void gic_init(void) {
>> +    // FIXME Get from dt!
>> +    gic.gicd_base = (char *)0x2c001000ULL;
>> +    gic.gicc_base = (char *)0x2c002000ULL;
>
>
> Those values are wrong.

Now fixed by patch reordering.

>> diff --git a/extras/mini-os/events.c b/extras/mini-os/events.c
>> index 3c92d82..780c74a 100644
>> --- a/extras/mini-os/events.c
>> +++ b/extras/mini-os/events.c
>> @@ -179,6 +179,7 @@ void init_events(void)
>>  void fini_events(void)
>>  {
>>      /* Dealloc all events */
>> +    arch_unbind_ports();
>>      unbind_all_ports();
>>      arch_fini_events();
>>  }
>> @@ -238,7 +239,8 @@ int evtchn_bind_interdomain(domid_t pal, evtchn_port_t
>> remote_port,
>>
>>  int evtchn_get_peercontext(evtchn_port_t local_port, char *ctx, int size)
>>  {
>> -    int rc;
>> +    int rc = 0;
>> +#ifndef __arm__                        /* TODO */
>
>
> Do you still need this TODO & ifdef? XSM is working correctly on ARM. And
> even if it was not implemented the compilation should not failed.

It used "_hypercall1", which was missing from ARM. I've now added
HYPERVISOR_xsm_op and changed it to use that instead.

>>      uint32_t sid;
>>      struct xen_flask_op op;
>>      op.cmd = FLASK_GET_PEER_SID;
>> @@ -253,6 +255,7 @@ int evtchn_get_peercontext(evtchn_port_t local_port,
>> char *ctx, int size)
>>      op.u.sid_context.size = size;
>>      set_xen_guest_handle(op.u.sid_context.context, ctx);
>>      rc = _hypercall1(int, xsm_op, &op);
>> +#endif
>>      return rc;
>>  }
>>
>> diff --git a/extras/mini-os/hypervisor.c b/extras/mini-os/hypervisor.c
>> index b4688a0..1b61d9b 100644
>> --- a/extras/mini-os/hypervisor.c
>> +++ b/extras/mini-os/hypervisor.c
>> @@ -64,7 +64,7 @@ void do_hypervisor_callback(struct pt_regs *regs)
>>              l2 &= ~(1UL << l2i);
>>
>>              port = (l1i * (sizeof(unsigned long) * 8)) + l2i;
>> -                       do_event(port, regs);
>> +            do_event(port, regs);
>
>
> This patch is long and difficult to read. Please avoid indentation change in
> non-modified code at the same time.

OK, split off.

>>          }
>>      }
>>
>> @@ -73,18 +73,26 @@ void do_hypervisor_callback(struct pt_regs *regs)
>>
>>  void force_evtchn_callback(void)
>>  {
>> +#ifdef XEN_HAVE_PV_UPCALL_MASK
>>      int save;
>> +#endif
>>      vcpu_info_t *vcpu;
>>      vcpu = &HYPERVISOR_shared_info->vcpu_info[smp_processor_id()];
>> +#ifdef XEN_HAVE_PV_UPCALL_MASK
>>      save = vcpu->evtchn_upcall_mask;
>> +#endif
>>
>>      while (vcpu->evtchn_upcall_pending) {
>> +#ifdef XEN_HAVE_PV_UPCALL_MASK
>>          vcpu->evtchn_upcall_mask = 1;
>> +#endif
>>          barrier();
>>          do_hypervisor_callback(NULL);
>>          barrier();
>> +#ifdef XEN_HAVE_PV_UPCALL_MASK
>>          vcpu->evtchn_upcall_mask = save;
>>          barrier();
>> +#endif
>>      };
>>  }
>>
>> @@ -110,7 +118,9 @@ inline void unmask_evtchn(uint32_t port)
>>                &vcpu_info->evtchn_pending_sel) )
>>      {
>>          vcpu_info->evtchn_upcall_pending = 1;
>> +#ifdef XEN_HAVE_PV_UPCALL_MASK
>>          if ( !vcpu_info->evtchn_upcall_mask )
>> +#endif
>>              force_evtchn_callback();
>>      }
>>  }
>
>
> I would have move those change in a separate patch.

OK.

> [..]
>
>
>> diff --git a/extras/mini-os/include/arm/arch_spinlock.h
>> b/extras/mini-os/include/arm/arch_spinlock.h
>> new file mode 100755
>> index 0000000..d57f150
>> --- /dev/null
>> +++ b/extras/mini-os/include/arm/arch_spinlock.h
>> @@ -0,0 +1,49 @@
>> +
>> +
>> +#ifndef __ARCH_ASM_SPINLOCK_H
>> +#define __ARCH_ASM_SPINLOCK_H
>> +
>> +#include "os.h"
>> +
>> +
>> +#define ARCH_SPIN_LOCK_UNLOCKED { 1 }
>> +
>> +/*
>> + * Simple spin lock operations.  There are two variants, one clears IRQ's
>> + * on the local processor, one does not.
>> + *
>> + * We make no fairness assumptions. They have a cost.
>> + */
>> +
>> +#define arch_spin_is_locked(x)    (*(volatile signed char *)(&(x)->slock)
>> <= 0)
>> +#define arch_spin_unlock_wait(x) do { barrier(); }
>> while(spin_is_locked(x))
>> +
>> +/*
>> + * This works. Despite all the confusion.
>> + * (except on PPro SMP or if we are using OOSTORE)
>> + * (PPro errata 66, 92)
>> + */
>
>
> This comment is x86... It should not have been copied here.

OK.

>> +
>> +static inline void _raw_spin_unlock(spinlock_t *lock)
>> +{
>> +    xchg(&lock->slock, 1);
>> +}
>> +
>> +static inline int _raw_spin_trylock(spinlock_t *lock)
>> +{
>> +    return xchg(&lock->slock, 0) != 0 ? 1 : 0;
>> +}
>> +
>> +static inline void _raw_spin_lock(spinlock_t *lock)
>> +{
>> +    volatile int was_locked;
>> +    do {
>> +        was_locked = xchg(&lock->slock, 0) == 0 ? 1 : 0;
>> +    } while(was_locked);
>> +}
>> +
>> +static inline void _raw_spin_lock_flags (spinlock_t *lock, unsigned long
>> flags)
>> +{
>
>
> You didn't implement this function. It looks like it's not used in mini-os,
> right? If so, please add a BUG_ON just in case that someone decide to use it
> later.

I'll remove it completely. Better to find out it's missing at compile time.

>
>> diff --git a/extras/mini-os/include/arm/hypercall-arm32.h
>> b/extras/mini-os/include/arm/hypercall-arm32.h
>> new file mode 100644
>> index 0000000..0fc1c03
>> --- /dev/null
>> +++ b/extras/mini-os/include/arm/hypercall-arm32.h
>
>
> Actually this file can be name hypercall.h. On ARM64 the set of hypercall is
> exactly the same. The only different that you will have between both
> architecture is the assembly code and the system registers.

I've renamed it to hypercall-arm.h (to match the x86 naming).

> [..]
>
>
>> +inline int
>> +HYPERVISOR_mmu_update(
>> +    mmu_update_t *req, int count, int *success_count, domid_t domid);
>
>
> Why do you use inline in all external functions in this include?

No idea. I've removed all the inlines.

> Hence most of this hypercall doesn't exist on ARM. Please define only the
> necessary one.

OK.

> [..]
>
>> +#endif /* __HYPERCALL_X86_64_H__ */
>
>
> __HYPERCALL_ARM_H__

Fixed.

> [..]
>
>
>> +// disable interrupts
>> +static inline __cli(void) {
>
>
> I see that you use __cli and __sti only
> __cli and __sti are only in 2 defines below. These name are only x86
> specific. Please rename them or merge this code in
> local_irq_{disable,enable}

Done.

>> +    int x;
>> +    __asm__ __volatile__("mrs %0, cpsr;cpsid i":"=r"(x)::"memory");
>
>
> Why do you need to read cpsr. cpsid i is enough here.

Removed.

>> +}
>> +
>> +// enable interrupts
>> +static inline __sti(void) {
>> +    int x;
>> +    __asm__ __volatile__("mrs %0, cpsr\n"
>> +                        "bic %0, %0, #0x80\n"
>> +                        "msr cpsr_c, %0"
>> +                        :"=r"(x)::"memory");
>
>
> This can simply be done by cpsie i

Done.

>> +}
>> +
>> +static inline int irqs_disabled() {
>> +    int x;
>> +    __asm__ __volatile__("mrs %0, cpsr\n":"=r"(x)::"memory");
>> +    return (x & 0x80);
>
>
> You can use local_save_flags directly.

OK.

>> +}
>> +
>> +#define local_irq_save(x) { \
>> +    __asm__ __volatile__("mrs %0, cpsr;cpsid i; and %0, %0,
>> #0x80":"=r"(x)::"memory");    \
>> +}
>> +
>> +#define local_irq_restore(x) {    \
>> +    __asm__ __volatile__("msr cpsr_c, %0"::"r"(x):"memory");    \
>> +}
>
>
> If you mask the result in local_irq_save, and use this value directly is
> local_irq_restore, you will disable by mistake the Asynchronous Abort
> exception....
>
> You have to remove the and %0... at the end.

This makes schedule() fail, because it checks whether the result is zero.
Perhaps we should continue to mask it, but only apply the IRQ bit in
local_irq_restore?

>> +#define local_save_flags(x)    { \
>> +    __asm__ __volatile__("mrs %0, cpsr; and %0, %0,
>> 0x80":"=r"(x)::"memory");    \
>> +}
>
>
> Same remark here.

If we mask on restore, this is OK.

>> +#define local_irq_disable()    __cli()
>> +#define local_irq_enable() __sti()
>> +
>> +#if defined(__arm__)
>> +#define mb() __asm__("dmb");
>> +#define rmb() __asm__("dmb");
>> +#define wmb() __asm__("dmb");
>
>
> I suspect you want to dsb here. You want to make sure that every memory
> access has finished avoid executing new instruction until this is done.

Is this necessary? As I understand it, using Xen's ring system
requires a strict ordering (dmb), but we don't need to stall the
processor waiting for each write to complete before going on to the
next one.

> dmb only ensure the memory ordering.

> Also, you want to clobber the memory to avoid the compiler:
>         1) reordering the instructions
>         2) prefetch data from the memory

OK.

>> +#elif defined(__aarch64__)
>> +#define mb()
>> +#define rmb()
>> +#define wmb()
>
>
> I'm confused with this piece of code... memory barrier are also required on
> aarch64. Hence dmb/isb also exist on this architecture
>
> You don't need the if ... elif ... else

Removed.

>> +#define unlikely(x)  __builtin_expect((x),0)
>> +#define likely(x)  __builtin_expect((x),1)
>
>
> Can't it be common with x86?

Which header file should it go in?

> [..]
>
>
>>  int do_event(evtchn_port_t port, struct pt_regs *regs);
>> diff --git a/extras/mini-os/include/gic.h b/extras/mini-os/include/gic.h
>> new file mode 100644
>> index 0000000..cead2e5
>> --- /dev/null
>> +++ b/extras/mini-os/include/gic.h
>> @@ -0,0 +1 @@
>> +void gic_init(void);
>> diff --git a/extras/mini-os/include/hypervisor.h
>> b/extras/mini-os/include/hypervisor.h
>> index a62cb78..052f4f8 100644
>> --- a/extras/mini-os/include/hypervisor.h
>> +++ b/extras/mini-os/include/hypervisor.h
>> @@ -18,6 +18,10 @@
>>  #include <hypercall-x86_32.h>
>>  #elif defined(__x86_64__)
>>  #include <hypercall-x86_64.h>
>> +#elif defined(__arm__)
>> +#include <hypercall-arm32.h>
>> +#elif defined(__aarch64__)
>> +#include <hypercall-arm64.h>
>
>
> Hmmm, the filehypercall-arm64.h doesn't exists in this series...
>
> Futhermore, as I said ealier the set of hypercall is exactly the same on
> arm64.

Fixed.

> [..]
>
>
>> +#if defined(__i386__) || defined(__arm__)
>>  typedef long long           quad_t;
>>  typedef unsigned long long  u_quad_t;
>>
>> @@ -40,7 +40,7 @@ typedef unsigned long       u_quad_t;
>>  typedef struct { unsigned long pte; } pte_t;
>>  #endif /* __i386__ || __x86_64__ */
>>
>> -#ifdef __x86_64__
>> +#if defined(__x86_64__) || defined(__aarch64__)
>>  #define __pte(x) ((pte_t) { (x) } )
>
>
> This looks wrong to me. The pte layout is exactly the same on arm32 and
> arm64. Hence, this is only used in the x86 code. Please either move pte_t in
> x86 part or define it correctly on ARM...

Moved to x86. Actually, this simplifies things further, because it can
go in the separate hypercall-*.h files and lose the #ifdef completely.

> [..]
>
>
>> diff --git a/extras/mini-os/kernel.c b/extras/mini-os/kernel.c
>> index 9a30550..7b2b8fc 100644
>> --- a/extras/mini-os/kernel.c
>> +++ b/extras/mini-os/kernel.c
>> @@ -47,6 +47,10 @@
>>  #include <xen/features.h>
>>  #include <xen/version.h>
>>
>> +#ifdef __arm__
>> +#include <mini-os/gic.h>
>> +#endif
>> +
>>  uint8_t xen_features[XENFEAT_NR_SUBMAPS * 32];
>>
>>  void setup_xen_features(void)
>> @@ -147,6 +151,10 @@ void start_kernel(void)
>>      create_thread("shutdown", shutdown_thread, NULL);
>>  #endif
>>
>> +#ifdef __arm__
>> +    gic_init();
>> +#endif
>> +
>
>
> I would define a function arch_init. This will avoid the #ifdef __arm__ in
> the code common.

I've moved it to the existing arch_init. I can't see any obvious
reason why we should init the GIC long after enabling interrupts
anyway.

> Hence, it looks strange that sometime you have #if __arm__ && __arch64__ and
> sometimes not...

>
>>      /* Call (possibly overridden) app_main() */
>>      app_main(&start_info);
>>
>> diff --git a/extras/mini-os/sched.c b/extras/mini-os/sched.c
>> index 174945e..b99d7dc 100644
>> --- a/extras/mini-os/sched.c
>> +++ b/extras/mini-os/sched.c
>> @@ -145,6 +145,9 @@ struct thread* create_thread(char *name, void
>> (*function)(void *), void *data)
>>      unsigned long flags;
>>      /* Call architecture specific setup. */
>>      thread = arch_create_thread(name, function, data);
>> +    if(!thread)
>> +        BUG(); //For now, FIXME should just return NULL
>> +
>
>
> This change is in the common code. I think this should go in a separate
> patch.

I'll remove this for now.

> Hence looking again to arch_create_thread for ARM you:
>         1) never return NULL
>         2) never check the xmalloc/alloc_pages return.
>
>
>>      /* Not runable, not exited, not sleeping */
>>      thread->flags = 0;
>>      thread->wakeup_time = 0LL;
>> @@ -165,28 +168,28 @@ struct _reent *__getreent(void)
>>      struct _reent *_reent;
>>
>>      if (!threads_started)
>> -       _reent = _impure_ptr;
>> +        _reent = _impure_ptr;
>>      else if (in_callback)
>> -       _reent = &callback_reent;
>> +        _reent = &callback_reent;
>>      else
>> -       _reent = &get_current()->reent;
>> +        _reent = &get_current()->reent;
>>  #ifndef NDEBUG
>>  #if defined(__x86_64__) || defined(__x86__)
>>      {
>>  #ifdef __x86_64__
>> -       register unsigned long sp asm ("rsp");
>> +        register unsigned long sp asm ("rsp");
>>  #else
>> -       register unsigned long sp asm ("esp");
>> +        register unsigned long sp asm ("esp");
>>  #endif
>> -       if ((sp & (STACK_SIZE-1)) < STACK_SIZE / 16) {
>> -           static int overflowing;
>> -           if (!overflowing) {
>> -               overflowing = 1;
>> -               printk("stack overflow\n");
>> -               BUG();
>> -           }
>> -       }
>> +        if ((sp & (STACK_SIZE-1)) < STACK_SIZE / 16) {
>> +            static int overflowing;
>> +            if (!overflowing) {
>> +                overflowing = 1;
>> +                printk("stack overflow\n");
>> +                BUG();
>> +            }
>> +        }
>
>
> all this chunk: spurious changes?

I'll move the whitespace fixes to a separate patch.

Thanks! I'll do some more clean ups and send another patch series soon.


-- 
Dr Thomas Leonard        http://0install.net/
GPG: 9242 9807 C985 3C07 44A6  8B9A AE07 8280 59A5 3CC1
GPG: DA98 25AE CAD0 8975 7CDA  BD8E 0713 3F96 CA74 D8BA

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 07/12] mini-os: initial ARM support
  2014-06-23 15:10     ` Thomas Leonard
@ 2014-06-23 16:55       ` Julien Grall
  2014-06-23 22:33         ` Samuel Thibault
  0 siblings, 1 reply; 41+ messages in thread
From: Julien Grall @ 2014-06-23 16:55 UTC (permalink / raw)
  To: Thomas Leonard
  Cc: David Scott, Stefano Stabellini, Anil Madhavapeddy,
	Samuel Thibault, xen-devel, Ian Campbell

On 06/23/2014 04:10 PM, Thomas Leonard wrote:
> On 18 June 2014 23:40, Julien Grall <julien.grall@linaro.org> wrote: 
> Hi Julien,

Hi Thomas,

>>
>>
>>> +void set_vtimer_compare(uint64_t value) {
>>> +    uint32_t x, y;
>>> +
>>> +    DEBUG("New CompareValue : %llx\n", value);
>>> +    x = 0xFFFFFFFFULL & value;
>>> +    y = (value >> 32) & 0xFFFFFFFF;
>>> +
>>> +    __asm__ __volatile__("mcrr p15, 3, %0, %1, c14\n"
>>> +            "isb"::"r"(x), "r"(y));
>>> +
>>> +    __asm__ __volatile__("mov %0, #0x1\n"
>>> +            "mcr p15, 0, %0, c14, c3, 1\n" /* Enable timer and unmask the
>>> output signal */
>>> +            "isb":"=r"(x));
>>
>>
>> I don't think you need to add an isb per instruction. One should be enough.
> 
> Actually, do we need one at all? Setting the timer shouldn't affect
> the instruction pipline, I think.

The isb is also used to make sure that an access to a system control
registers (such as setting the page table) has finished before executing
the next instruction.

>> [..]
>>
>>
>>> diff --git a/extras/mini-os/drivers/gic.c b/extras/mini-os/drivers/gic.c
>>> new file mode 100644
>>> index 0000000..3141830
>>> --- /dev/null
>>> +++ b/extras/mini-os/drivers/gic.c
>>> @@ -0,0 +1,187 @@
>>> +// ARM GIC implementation
>>> +
>>> +#include <mini-os/os.h>
>>> +#include <mini-os/hypervisor.h>
>>> +
>>> +//#define VGIC_DEBUG
>>> +#ifdef VGIC_DEBUG
>>> +#define DEBUG(_f, _a...) \
>>> +    DEBUG("MINI_OS(file=vgic.c, line=%d) " _f , __LINE__, ## _a)
>>> +#else
>>> +#define DEBUG(_f, _a...)    ((void)0)
>>> +#endif
>>> +
>>> +extern void (*IRQ_handler)(void);
>>> +
>>> +struct gic {
>>> +    volatile char *gicd_base;
>>> +    volatile char *gicc_base;
>>> +};
>>> +
>>> +static struct gic gic;
>>> +
>>> +// Distributor Interface
>>> +#define GICD_CTLR        0x0
>>> +#define GICD_ISENABLER    0x100
>>> +#define GICD_PRIORITY    0x400
>>
>>
>> You use the right name for every macro except this one. I would rename it to
>> GICD_IPRIORITYR to stay consistent.
> 
> Done.

Thanks !

>>> +static inline void REG_WRITE32(volatile uint32_t *addr, unsigned int
>>> value)
>>> +{
>>> +    __asm__ __volatile__("str %0, [%1]"::"r"(value), "r"(addr));
>>> +    wmb();
>>> +}
>>> +
> 
> Do we need inline assembler to write these values? I'd imagine that a
> plain C store to a volatile 32-bit pointer would always do the same
> thing.

The compiler may do strange things to store the value, such as 4
byte-store instead of a word-store.

So we have to use inline assembly to make sure the correct access will
be done.

>>> +{
>>> +    uint32_t value;
>>> +    value = REG_READ32(REG(gicd(gic, GICD_PRIORITY)) + irq_number);
>>
>>
>> There is 4 interrupts describe per register, this should be (irq_number &
>> ~3).
> 
> Or should it be (irq_number >> 2)? REG casts to uint32_t.

It's the same :).

>>> +}
>>> +
>>> +static void gic_route_interrupt(struct gic *gic, unsigned char
>>> irq_number, unsigned char cpu_set)
>>> +{
>>> +    uint32_t value;
>>> +    value = REG_READ32(REG(gicd(gic, GICD_ITARGETSR)) + irq_number);
>>
>>
>> Same remark as gic_set_priority here.
>>
>>
>>> +    value &= ~(0xff << (8 * (irq_number & 0x3))); // set priority to '0'
>>> +    value |= cpu_set << (8 * (irq_number & 0x3)); // add our priority
>>
>>
>> The comments are wrong in the 2 lines above.
>>
>>
>>> +    REG_WRITE32(REG(gicd(gic, GICD_ITARGETSR)) + irq_number, value);
>>
>>
>> irq_number & ~3;
> 
> The ARM Generic Interrupt Controller Architecture Specification says
> "These registers are byte-accessible.". So we should be able to write
> the byte directly. I thought this might work:
> 
> static void gic_route_interrupt(struct gic *gic, int irq_number,
> unsigned char cpu_set)
> {
>     gicd(gic, GICD_ITARGETSR)[irq_number] = cpu_set;
>     wmb();
> }

This code looks good to me.

> 
> But it doesn't, because Xen's write_ignore handler (vgic.c:656 on the
> 4.4 branch) does:
> 
> write_ignore:
>   if ( dabt.size != 2 ) goto bad_width;
> 
> Bug?

This is a bug in Xen. I think, write_ignore should just ignore the write
rather checking badly the size.

Can you send a patch for it?

>>> +}
>>> +
>>> +#define local_irq_save(x) { \
>>> +    __asm__ __volatile__("mrs %0, cpsr;cpsid i; and %0, %0,
>>> #0x80":"=r"(x)::"memory");    \
>>> +}
>>> +
>>> +#define local_irq_restore(x) {    \
>>> +    __asm__ __volatile__("msr cpsr_c, %0"::"r"(x):"memory");    \
>>> +}
>>
>>
>> If you mask the result in local_irq_save, and use this value directly is
>> local_irq_restore, you will disable by mistake the Asynchronous Abort
>> exception....
>>
>> You have to remove the and %0... at the end.
> 
> This makes schedule() fail, because it checks whether the result is zero.
> Perhaps we should continue to mask it, but only apply the IRQ bit in
> local_irq_restore?

I would prefer to change the schedule code if it's possible to keep
local_irq_restore as simple as possible. This helper is often used.

I don't know much the code of schedule. Why don't we only check that the
IRQ are disabled rather than call local_irq_{save,restore}?

>>> +#define local_irq_disable()    __cli()
>>> +#define local_irq_enable() __sti()
>>> +
>>> +#if defined(__arm__)
>>> +#define mb() __asm__("dmb");
>>> +#define rmb() __asm__("dmb");
>>> +#define wmb() __asm__("dmb");
>>
>>
>> I suspect you want to dsb here. You want to make sure that every memory
>> access has finished avoid executing new instruction until this is done.
> 
> Is this necessary? As I understand it, using Xen's ring system
> requires a strict ordering (dmb), but we don't need to stall the
> processor waiting for each write to complete before going on to the
> next one.

Is it written somewhere? FIY, Linux is using dsb with ring system. Even
tho, I think dmb is fine here. I'd like confirmation for either Ian C.
or Stefano.

Futhermore, there is other place in mini-os (such as the GIC) where I
think we have to use dsb.

>>> +#define unlikely(x)  __builtin_expect((x),0)
>>> +#define likely(x)  __builtin_expect((x),1)
>>
>>
>> Can't it be common with x86?
> 
> Which header file should it go in?

I don't know much mini-os, but I would add either in lib.h or create a
new header compiler.h.

>> [..]
>>
>>
>>> +#if defined(__i386__) || defined(__arm__)
>>>  typedef long long           quad_t;
>>>  typedef unsigned long long  u_quad_t;
>>>
>>> @@ -40,7 +40,7 @@ typedef unsigned long       u_quad_t;
>>>  typedef struct { unsigned long pte; } pte_t;
>>>  #endif /* __i386__ || __x86_64__ */
>>>
>>> -#ifdef __x86_64__
>>> +#if defined(__x86_64__) || defined(__aarch64__)
>>>  #define __pte(x) ((pte_t) { (x) } )
>>
>>
>> This looks wrong to me. The pte layout is exactly the same on arm32 and
>> arm64. Hence, this is only used in the x86 code. Please either move pte_t in
>> x86 part or define it correctly on ARM...
> 
> Moved to x86. Actually, this simplifies things further, because it can
> go in the separate hypercall-*.h files and lose the #ifdef completely.

Great, thanks!

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 07/12] mini-os: initial ARM support
  2014-06-23 16:55       ` Julien Grall
@ 2014-06-23 22:33         ` Samuel Thibault
  0 siblings, 0 replies; 41+ messages in thread
From: Samuel Thibault @ 2014-06-23 22:33 UTC (permalink / raw)
  To: Julien Grall
  Cc: Thomas Leonard, David Scott, Stefano Stabellini,
	Anil Madhavapeddy, xen-devel, Ian Campbell

Julien Grall, le Mon 23 Jun 2014 17:55:05 +0100, a écrit :
> >>> +#define unlikely(x)  __builtin_expect((x),0)
> >>> +#define likely(x)  __builtin_expect((x),1)
> >>
> >>
> >> Can't it be common with x86?
> > 
> > Which header file should it go in?
> 
> I don't know much mini-os, but I would add either in lib.h or create a
> new header compiler.h.

A new compiler.h makes sense to me.

Samuel

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 12/12] mini-os: added ARM grant table initialisation
  2014-06-18 17:27   ` Julien Grall
@ 2014-06-25 16:41     ` Thomas Leonard
  2014-06-25 16:50       ` Ian Campbell
  0 siblings, 1 reply; 41+ messages in thread
From: Thomas Leonard @ 2014-06-25 16:41 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Stefano Stabellini, David Scott, Samuel Thibault,
	Anil Madhavapeddy

On 18 June 2014 18:27, Julien Grall <julien.grall@linaro.org> wrote:
> Hi Thomas,
>
> On 06/18/2014 04:08 PM, Thomas Leonard wrote:
>> +
>> +/* Get Xen's sugggested physical page assignments for the grant table. */
>> +static grant_entry_t *get_gnttab_base(void)
>> +{
>> +    int hypervisor;
>> +
>> +    hypervisor = fdt_path_offset(device_tree, "/hypervisor");
>
> Same comment as on patch #11, you need to search the hypervisor node via
> the compatible string.

It's not clear to me what I should do with this attribute. On
Xen/unstable, it contains the single value "xen,xen-4.5", meaning (I
think) that Xen 4.5 is incompatible with Xen 4.4. But I'd still like
Mini-OS to run. Presumably, 4.6 will be incompatible too. What could I
do if the value doesn't match except try to use it anyway?


-- 
Dr Thomas Leonard        http://0install.net/
GPG: 9242 9807 C985 3C07 44A6  8B9A AE07 8280 59A5 3CC1
GPG: DA98 25AE CAD0 8975 7CDA  BD8E 0713 3F96 CA74 D8BA

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 12/12] mini-os: added ARM grant table initialisation
  2014-06-25 16:41     ` Thomas Leonard
@ 2014-06-25 16:50       ` Ian Campbell
  0 siblings, 0 replies; 41+ messages in thread
From: Ian Campbell @ 2014-06-25 16:50 UTC (permalink / raw)
  To: Thomas Leonard
  Cc: David Scott, Anil Madhavapeddy, Julien Grall, Samuel Thibault,
	xen-devel, Stefano Stabellini

On Wed, 2014-06-25 at 17:41 +0100, Thomas Leonard wrote:
> On 18 June 2014 18:27, Julien Grall <julien.grall@linaro.org> wrote:
> > Hi Thomas,
> >
> > On 06/18/2014 04:08 PM, Thomas Leonard wrote:
> >> +
> >> +/* Get Xen's sugggested physical page assignments for the grant table. */

Too many g's.

> >> +static grant_entry_t *get_gnttab_base(void)
> >> +{
> >> +    int hypervisor;
> >> +
> >> +    hypervisor = fdt_path_offset(device_tree, "/hypervisor");
> >
> > Same comment as on patch #11, you need to search the hypervisor node via
> > the compatible string.
> 
> It's not clear to me what I should do with this attribute. On
> Xen/unstable, it contains the single value "xen,xen-4.5",

It should contain "xen,xen-X.Y\0xen,xen\0\0", i.e. multiple strings. If
you don't care about the specific version then you should check for
"xen,xen" somewhere in the list.

(This is how device tree compatibile strings work, more specific to more
general).

>  meaning (I
> think) that Xen 4.5 is incompatible with Xen 4.4. But I'd still like
> Mini-OS to run. Presumably, 4.6 will be incompatible too. What could I
> do if the value doesn't match except try to use it anyway?
> 
> 

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 10/12] mini-os: get RAM base and size from the FDT
  2014-06-19 11:24       ` Julien Grall
@ 2014-07-02 15:51         ` Ian Campbell
  0 siblings, 0 replies; 41+ messages in thread
From: Ian Campbell @ 2014-07-02 15:51 UTC (permalink / raw)
  To: Julien Grall
  Cc: Thomas Leonard, David Scott, Anil Madhavapeddy,
	Stefano Stabellini, Samuel Thibault, xen-devel

On Thu, 2014-06-19 at 12:24 +0100, Julien Grall wrote:
> On 06/19/2014 09:39 AM, Thomas Leonard wrote:
> > On 18 June 2014 18:38, Julien Grall <julien.grall@linaro.org> wrote:
> >> Hi Thomas,
> >>
> >> On 06/18/2014 04:08 PM, Thomas Leonard wrote:
> >>> +        const char *device_type = fdt_getprop(device_tree, node, "device_type", NULL);
> >>> +        if (device_type && !strcmp(device_type, "memory"))
> >>> +        {
> >>> +            /* Note: we assume there's only a single region of memory.
> >>> +             * Since Xen is already translating our "physical"
> >>> +             * addresses to the real physical RAM, there's no
> >>> +             * reason for it to give us multiple blocks. */
> >>
> >> This comment looks wrong to me. Even tho, Xen is providing a stage-2
> >> translation to show you a virtual layout (your guest physical memory),
> >> the new layout in Xen upstream may contain multiple banks. The first
> >> bank will contain up to 3G of RAM.
> > 
> > Hi Julien,
> 
> Hello Thomas,
> 
> > At the Hackathon, we decided Mini-OS could always rely on Xen to
> > provide the memory in a single block:
> > 
> > "ARM guests are allowed to assume one bank of memory. We need to
> > document this in the ABI. ARM guests should assume the presence of an
> > FDT."
> 
> I'm not against only supporting one bank... I pointed that your comment
> is wrong and doesn't reflect this sentence.
> 
> I didn't attend to this meeting, but I guess it was meant that the guest
> can assume there is always one bank of memory.
> 
> I would change your comment into:
> 
> "Xen will always provide us at least one bank of memory. Mini-os will
> use the first bank for the time-being"

Yes. The ABI definitely doesn't say "at most one bank". We already have
two in 4.5 for sufficiently large guests.

> > http://lists.xenproject.org/archives/html/mirageos-devel/2014-06/msg00004.html
> > 
> > A lot of the value of running on Xen is that we only have to support a
> > small number of configurations, because Xen hides the details of the
> > physical hardware. I assume the only reason for using the (very
> > flexible) FDT format to provide this information is that it's simpler
> > for full OSs which already use FDTs.
> 
> As specified in the ABI, the guest layout may change from time to time.
> Actually, the layout is not compatible between Xen 4.4 and 4.5.
> 
> Unless you want your OS tight to a Xen specific version, I don't think
> we want that for mini-os. You have to correctly support FDT and retrieve
> every information (MMIO, IRQ) from it.
> 
> > Is the ARM guest ABI documented somewhere?
> 
> You can find the guest layout described in xen/include/public/arch-arm.h

Note that this is for the benefit of the toolstack (matched to Xen)
only. If you decide you want to use those values yourself then you are
agreeing with yourself that you are happy to recompile in order to run
on another version of Xen.

If you aren't happy with that then you should use the FDT which has been
provided for this purpose.

Ian.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH ARM v4 11/12] mini-os: get GIC addresses from FDT
  2014-06-19  8:50     ` Thomas Leonard
  2014-06-19 10:58       ` Julien Grall
@ 2014-07-02 15:55       ` Ian Campbell
  1 sibling, 0 replies; 41+ messages in thread
From: Ian Campbell @ 2014-07-02 15:55 UTC (permalink / raw)
  To: Thomas Leonard
  Cc: David Scott, Anil Madhavapeddy, Julien Grall, Samuel Thibault,
	xen-devel, Stefano Stabellini

On Thu, 2014-06-19 at 09:50 +0100, Thomas Leonard wrote:
> On 18 June 2014 18:25, Julien Grall <julien.grall@linaro.org> wrote:
> > Hi Thomas,
> >
> > On 06/18/2014 04:08 PM, Thomas Leonard wrote:
> >>  //#define VGIC_DEBUG
> >>  #ifdef VGIC_DEBUG
> >> @@ -168,9 +169,38 @@ static void gic_handler(void) {
> >>  }
> >>
> >>  void gic_init(void) {
> >> -    // FIXME Get from dt!
> >> -    gic.gicd_base = (char *)0x2c001000ULL;
> >> -    gic.gicc_base = (char *)0x2c002000ULL;
> >> +    gic.gicd_base = NULL;
> >
> > Any reason to not fold this patch in patch #7? Or better move the gic
> > code in a separate patch?
> 
> It was previously requested that I split the FDT patch from the main
> ARM one. This patch depends on libfdt being present, so it has to go
> after that.
> 
> Moving all the GIC code to this patch would mean that the original
> patch wouldn't work on its own.

Is it not possible to put the fdt stuff before patch #7 so it is already
present?

That said:

For things such as a new minios port we are more accepting of "bisection
hazards" so long as they are all before some strict cut-off point, i.e.
the point at which the build is actually wired up to make the series do
anything.

IOW so long as this stuff isn't actually being built until patch #12
then you can play a bit fast a loose with the "it must always build"
rule.

Ian.

^ permalink raw reply	[flat|nested] 41+ messages in thread

end of thread, other threads:[~2014-07-02 15:55 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-18 15:08 [PATCH ARM v4 00/12] mini-os: initial ARM support Thomas Leonard
2014-06-18 15:08 ` [PATCH ARM v4 01/12] mini-os: build fixes Thomas Leonard
2014-06-18 16:26   ` Ian Campbell
2014-06-18 17:41   ` Samuel Thibault
2014-06-18 15:08 ` [PATCH ARM v4 02/12] mini-os: fixed shutdown thread Thomas Leonard
2014-06-18 15:08 ` [PATCH ARM v4 03/12] mini-os: fixed format string error in unbind_evtchn Thomas Leonard
2014-06-18 16:28   ` Ian Campbell
2014-06-18 17:42   ` Samuel Thibault
2014-06-18 15:08 ` [PATCH ARM v4 04/12] mini-os: use unbind_evtchn in unbind_all_ports Thomas Leonard
2014-06-18 16:30   ` Ian Campbell
2014-06-18 17:44   ` Samuel Thibault
2014-06-18 15:08 ` [PATCH ARM v4 05/12] mini-os: made off_t type signed Thomas Leonard
2014-06-18 16:31   ` Ian Campbell
2014-06-18 17:44   ` Samuel Thibault
2014-06-18 15:08 ` [PATCH ARM v4 06/12] mini-os: switched initial C entry point to arch_init Thomas Leonard
2014-06-18 15:08 ` [PATCH ARM v4 07/12] mini-os: initial ARM support Thomas Leonard
2014-06-18 17:48   ` Samuel Thibault
2014-06-18 22:40   ` Julien Grall
2014-06-23 15:10     ` Thomas Leonard
2014-06-23 16:55       ` Julien Grall
2014-06-23 22:33         ` Samuel Thibault
2014-06-18 15:08 ` [PATCH ARM v4 08/12] mini-os: arm: show registers, stack and exception vector on fault Thomas Leonard
2014-06-18 15:08 ` [PATCH ARM v4 09/12] mini-os: import libfdt Thomas Leonard
2014-06-18 18:02   ` Samuel Thibault
2014-06-18 15:08 ` [PATCH ARM v4 10/12] mini-os: get RAM base and size from the FDT Thomas Leonard
2014-06-18 17:38   ` Julien Grall
2014-06-19  8:39     ` Thomas Leonard
2014-06-19 11:24       ` Julien Grall
2014-07-02 15:51         ` Ian Campbell
2014-06-18 15:08 ` [PATCH ARM v4 11/12] mini-os: get GIC addresses from FDT Thomas Leonard
2014-06-18 17:25   ` Julien Grall
2014-06-19  8:50     ` Thomas Leonard
2014-06-19 10:58       ` Julien Grall
2014-06-19 16:14         ` Thomas Leonard
2014-06-19 16:20           ` Julien Grall
2014-07-02 15:55       ` Ian Campbell
2014-06-18 15:08 ` [PATCH ARM v4 12/12] mini-os: added ARM grant table initialisation Thomas Leonard
2014-06-18 17:27   ` Julien Grall
2014-06-25 16:41     ` Thomas Leonard
2014-06-25 16:50       ` Ian Campbell
2014-06-18 18:05   ` Samuel Thibault

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.