Added: Added Arch Specific Folders in libbarrelfish / barrelfish-kpi / kernel based...
authorReto Achermann <acreto@student.ethz.ch>
Sun, 23 Mar 2014 16:18:20 +0000 (17:18 +0100)
committerStefan Kaestle <stefan.kaestle@inf.ethz.ch>
Wed, 20 Aug 2014 13:27:56 +0000 (15:27 +0200)
52 files changed:
include/arch/k1om/_fpmath.h [new file with mode: 0644]
include/arch/k1om/arch/inttypes.h [new file with mode: 0644]
include/arch/k1om/arch/setjmp.h [new file with mode: 0644]
include/arch/k1om/arch/stdint.h [new file with mode: 0644]
include/arch/k1om/barrelfish/bulk_transfer_arch.h [new file with mode: 0644]
include/arch/k1om/barrelfish/core_state_arch.h [new file with mode: 0644]
include/arch/k1om/barrelfish/cpu_arch.h [new file with mode: 0644]
include/arch/k1om/barrelfish/curdispatcher_arch.h [new file with mode: 0644]
include/arch/k1om/barrelfish/dispatcher_arch.h [new file with mode: 0644]
include/arch/k1om/barrelfish/invocations_arch.h [new file with mode: 0644]
include/arch/k1om/barrelfish/ldt.h [new file with mode: 0644]
include/arch/k1om/barrelfish/lmp_chan_arch.h [new file with mode: 0644]
include/arch/k1om/barrelfish/pmap_arch.h [new file with mode: 0644]
include/arch/k1om/barrelfish/syscall_arch.h [new file with mode: 0644]
include/arch/k1om/barrelfish_kpi/asm_inlines_arch.h [new file with mode: 0644]
include/arch/k1om/barrelfish_kpi/cpu_arch.h [new file with mode: 0644]
include/arch/k1om/barrelfish_kpi/dispatcher_shared_arch.h [new file with mode: 0644]
include/arch/k1om/barrelfish_kpi/eflags_arch.h [new file with mode: 0644]
include/arch/k1om/barrelfish_kpi/generic_arch.h [new file with mode: 0644]
include/arch/k1om/barrelfish_kpi/lmp_arch.h [new file with mode: 0644]
include/arch/k1om/barrelfish_kpi/paging_arch.h [new file with mode: 0644]
include/arch/k1om/barrelfish_kpi/registers_arch.h [new file with mode: 0644]
include/arch/k1om/barrelfish_kpi/spinlocks_arch.h [new file with mode: 0644]
include/arch/k1om/bench/bench_arch.h [new file with mode: 0644]
include/arch/k1om/concurrent/arch/cas.h [new file with mode: 0644]
include/arch/k1om/fenv.h [new file with mode: 0644]
include/arch/k1om/float.h [new file with mode: 0644]
include/arch/k1om/machine/_limits.h [new file with mode: 0644]
include/arch/k1om/machine/asm.h [new file with mode: 0644]
include/arch/k1om/machine/endian.h [new file with mode: 0644]
include/arch/k1om/machine/fpu.h [new file with mode: 0644]
include/arch/k1om/machine/types.h [new file with mode: 0644]
kernel/arch/k1om/boot.S [new file with mode: 0644]
kernel/arch/k1om/debug.c [new file with mode: 0644]
kernel/arch/k1om/entry.S [new file with mode: 0644]
kernel/arch/k1om/exec.c [new file with mode: 0644]
kernel/arch/k1om/gdb_arch.c [new file with mode: 0644]
kernel/arch/k1om/init.c [new file with mode: 0644]
kernel/arch/k1om/irq.c [new file with mode: 0644]
kernel/arch/k1om/linker.lds.in [new file with mode: 0644]
kernel/arch/k1om/microbenchmarks.c [new file with mode: 0644]
kernel/arch/k1om/page_mappings_arch.c [new file with mode: 0644]
kernel/arch/k1om/paging.c [new file with mode: 0644]
kernel/arch/k1om/startup_arch.c [new file with mode: 0644]
kernel/arch/k1om/syscall.c [new file with mode: 0644]
kernel/arch/k1om/vmkit.c [new file with mode: 0644]
lib/barrelfish/arch/k1om/debug.c [new file with mode: 0644]
lib/barrelfish/arch/k1om/dispatch.c [new file with mode: 0644]
lib/barrelfish/arch/k1om/entry.S [new file with mode: 0644]
lib/barrelfish/arch/k1om/ldt.c [new file with mode: 0644]
lib/barrelfish/arch/k1om/sys_debug.c [new file with mode: 0644]
lib/barrelfish/arch/k1om/syscalls.c [new file with mode: 0644]

diff --git a/include/arch/k1om/_fpmath.h b/include/arch/k1om/_fpmath.h
new file mode 100644 (file)
index 0000000..41b01c3
--- /dev/null
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 2002, 2003 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD: src/lib/libc/amd64/_fpmath.h,v 1.7 2008/01/17 16:39:06 bde Exp $
+ */
+
+union IEEEl2bits {
+       long double     e;
+       struct {
+               unsigned int    manl    :32;
+               unsigned int    manh    :32;
+               unsigned int    exp     :15;
+               unsigned int    sign    :1;
+               unsigned int    junkl   :16;
+               unsigned int    junkh   :32;
+       } bits;
+       struct {
+               unsigned long   man     :64;
+               unsigned int    expsign :16;
+               unsigned long   junk    :48;
+       } xbits;
+};
+
+#define        LDBL_NBIT       0x80000000
+#define        mask_nbit_l(u)  ((u).bits.manh &= ~LDBL_NBIT)
+
+#define        LDBL_MANH_SIZE  32
+#define        LDBL_MANL_SIZE  32
+
+#define        LDBL_TO_ARRAY32(u, a) do {                      \
+       (a)[0] = (uint32_t)(u).bits.manl;               \
+       (a)[1] = (uint32_t)(u).bits.manh;               \
+} while (0)
diff --git a/include/arch/k1om/arch/inttypes.h b/include/arch/k1om/arch/inttypes.h
new file mode 100644 (file)
index 0000000..73ee8f7
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Australian Public Licence B (OZPLB)
+ *
+ * Version 1-0
+ *
+ * Copyright (c) 2004 National ICT Australia
+ *
+ * All rights reserved.
+ *
+ * Developed by: Embedded, Real-time and Operating Systems Program (ERTOS)
+ *               National ICT Australia
+ *               http://www.ertos.nicta.com.au
+ *
+ * Permission is granted by National ICT Australia, free of charge, to
+ * any person obtaining a copy of this software and any associated
+ * documentation files (the "Software") to deal with the Software without
+ * restriction, including (without limitation) the rights to use, copy,
+ * modify, adapt, merge, publish, distribute, communicate to the public,
+ * sublicense, and/or sell, lend or rent out copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimers.
+ *
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimers in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ *     * Neither the name of National ICT Australia, nor the names of its
+ *       contributors, may be used to endorse or promote products derived
+ *       from this Software without specific prior written permission.
+ *
+ * EXCEPT AS EXPRESSLY STATED IN THIS LICENCE AND TO THE FULL EXTENT
+ * PERMITTED BY APPLICABLE LAW, THE SOFTWARE IS PROVIDED "AS-IS", AND
+ * NATIONAL ICT AUSTRALIA AND ITS CONTRIBUTORS MAKE NO REPRESENTATIONS,
+ * WARRANTIES OR CONDITIONS OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO ANY REPRESENTATIONS, WARRANTIES OR CONDITIONS
+ * REGARDING THE CONTENTS OR ACCURACY OF THE SOFTWARE, OR OF TITLE,
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT,
+ * THE ABSENCE OF LATENT OR OTHER DEFECTS, OR THE PRESENCE OR ABSENCE OF
+ * ERRORS, WHETHER OR NOT DISCOVERABLE.
+ *
+ * TO THE FULL EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL
+ * NATIONAL ICT AUSTRALIA OR ITS CONTRIBUTORS BE LIABLE ON ANY LEGAL
+ * THEORY (INCLUDING, WITHOUT LIMITATION, IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHERWISE) FOR ANY CLAIM, LOSS, DAMAGES OR OTHER
+ * LIABILITY, INCLUDING (WITHOUT LIMITATION) LOSS OF PRODUCTION OR
+ * OPERATION TIME, LOSS, DAMAGE OR CORRUPTION OF DATA OR RECORDS; OR LOSS
+ * OF ANTICIPATED SAVINGS, OPPORTUNITY, REVENUE, PROFIT OR GOODWILL, OR
+ * OTHER ECONOMIC LOSS; OR ANY SPECIAL, INCIDENTAL, INDIRECT,
+ * CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES, ARISING OUT OF OR IN
+ * CONNECTION WITH THIS LICENCE, THE SOFTWARE OR THE USE OF OR OTHER
+ * DEALINGS WITH THE SOFTWARE, EVEN IF NATIONAL ICT AUSTRALIA OR ITS
+ * CONTRIBUTORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH CLAIM, LOSS,
+ * DAMAGES OR OTHER LIABILITY.
+ *
+ * If applicable legislation implies representations, warranties, or
+ * conditions, or imposes obligations or liability on National ICT
+ * Australia or one of its contributors in respect of the Software that
+ * cannot be wholly or partly excluded, restricted or modified, the
+ * liability of National ICT Australia or the contributor is limited, to
+ * the full extent permitted by the applicable legislation, at its
+ * option, to:
+ * a.  in the case of goods, any one or more of the following:
+ * i.  the replacement of the goods or the supply of equivalent goods;
+ * ii.  the repair of the goods;
+ * iii. the payment of the cost of replacing the goods or of acquiring
+ *  equivalent goods;
+ * iv.  the payment of the cost of having the goods repaired; or
+ * b.  in the case of services:
+ * i.  the supplying of the services again; or
+ * ii.  the payment of the cost of having the services supplied again.
+ *
+ * The construction, validity and performance of this licence is governed
+ * by the laws in force in New South Wales, Australia.
+ */
+#ifndef _ARCH_IA32_INT_TYPES
+#define _ARCH_IA32_INT_TYPES
+
+#define __LENGTH_8_MOD "hh"
+#define __LENGTH_16_MOD "h"
+#define __LENGTH_32_MOD
+#define __LENGTH_64_MOD "l"
+#define __LENGTH_MAX_MOD "l"
+#define __LENGTH_PTR_MOD "l"
+
+#endif
diff --git a/include/arch/k1om/arch/setjmp.h b/include/arch/k1om/arch/setjmp.h
new file mode 100644 (file)
index 0000000..e606c8f
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Australian Public Licence B (OZPLB)
+ * 
+ * Version 1-0
+ * 
+ * Copyright (c) 2004 National ICT Australia
+ * 
+ * All rights reserved. 
+ * 
+ * Developed by: Embedded, Real-time and Operating Systems Program (ERTOS)
+ *               National ICT Australia
+ *               http://www.ertos.nicta.com.au
+ * 
+ * Permission is granted by National ICT Australia, free of charge, to
+ * any person obtaining a copy of this software and any associated
+ * documentation files (the "Software") to deal with the Software without
+ * restriction, including (without limitation) the rights to use, copy,
+ * modify, adapt, merge, publish, distribute, communicate to the public,
+ * sublicense, and/or sell, lend or rent out copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ * 
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimers.
+ * 
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimers in the documentation and/or other materials provided
+ *       with the distribution.
+ * 
+ *     * Neither the name of National ICT Australia, nor the names of its
+ *       contributors, may be used to endorse or promote products derived
+ *       from this Software without specific prior written permission.
+ * 
+ * EXCEPT AS EXPRESSLY STATED IN THIS LICENCE AND TO THE FULL EXTENT
+ * PERMITTED BY APPLICABLE LAW, THE SOFTWARE IS PROVIDED "AS-IS", AND
+ * NATIONAL ICT AUSTRALIA AND ITS CONTRIBUTORS MAKE NO REPRESENTATIONS,
+ * WARRANTIES OR CONDITIONS OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO ANY REPRESENTATIONS, WARRANTIES OR CONDITIONS
+ * REGARDING THE CONTENTS OR ACCURACY OF THE SOFTWARE, OR OF TITLE,
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT,
+ * THE ABSENCE OF LATENT OR OTHER DEFECTS, OR THE PRESENCE OR ABSENCE OF
+ * ERRORS, WHETHER OR NOT DISCOVERABLE.
+ * 
+ * TO THE FULL EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL
+ * NATIONAL ICT AUSTRALIA OR ITS CONTRIBUTORS BE LIABLE ON ANY LEGAL
+ * THEORY (INCLUDING, WITHOUT LIMITATION, IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHERWISE) FOR ANY CLAIM, LOSS, DAMAGES OR OTHER
+ * LIABILITY, INCLUDING (WITHOUT LIMITATION) LOSS OF PRODUCTION OR
+ * OPERATION TIME, LOSS, DAMAGE OR CORRUPTION OF DATA OR RECORDS; OR LOSS
+ * OF ANTICIPATED SAVINGS, OPPORTUNITY, REVENUE, PROFIT OR GOODWILL, OR
+ * OTHER ECONOMIC LOSS; OR ANY SPECIAL, INCIDENTAL, INDIRECT,
+ * CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES, ARISING OUT OF OR IN
+ * CONNECTION WITH THIS LICENCE, THE SOFTWARE OR THE USE OF OR OTHER
+ * DEALINGS WITH THE SOFTWARE, EVEN IF NATIONAL ICT AUSTRALIA OR ITS
+ * CONTRIBUTORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH CLAIM, LOSS,
+ * DAMAGES OR OTHER LIABILITY.
+ * 
+ * If applicable legislation implies representations, warranties, or
+ * conditions, or imposes obligations or liability on National ICT
+ * Australia or one of its contributors in respect of the Software that
+ * cannot be wholly or partly excluded, restricted or modified, the
+ * liability of National ICT Australia or the contributor is limited, to
+ * the full extent permitted by the applicable legislation, at its
+ * option, to:
+ * a.  in the case of goods, any one or more of the following:
+ * i.  the replacement of the goods or the supply of equivalent goods;
+ * ii.  the repair of the goods;
+ * iii. the payment of the cost of replacing the goods or of acquiring
+ *  equivalent goods;
+ * iv.  the payment of the cost of having the goods repaired; or
+ * b.  in the case of services:
+ * i.  the supplying of the services again; or
+ * ii.  the payment of the cost of having the services supplied again.
+ * 
+ * The construction, validity and performance of this licence is governed
+ * by the laws in force in New South Wales, Australia.
+ */
+/*
+  Author: Alex Webster
+*/
+
+typedef unsigned long jmp_buf[8];
diff --git a/include/arch/k1om/arch/stdint.h b/include/arch/k1om/arch/stdint.h
new file mode 100644 (file)
index 0000000..f37fbb3
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Modifications Copyright (c) 2008, ETH Zurich.
+ */
+/*
+ * Australian Public Licence B (OZPLB)
+ * 
+ * Version 1-0
+ * 
+ * Copyright (c) 2004 National ICT Australia
+ * 
+ * All rights reserved. 
+ * 
+ * Developed by: Embedded, Real-time and Operating Systems Program (ERTOS)
+ *               National ICT Australia
+ *               http://www.ertos.nicta.com.au
+ * 
+ * Permission is granted by National ICT Australia, free of charge, to
+ * any person obtaining a copy of this software and any associated
+ * documentation files (the "Software") to deal with the Software without
+ * restriction, including (without limitation) the rights to use, copy,
+ * modify, adapt, merge, publish, distribute, communicate to the public,
+ * sublicense, and/or sell, lend or rent out copies of the Software, and
+ * to permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ * 
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimers.
+ * 
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimers in the documentation and/or other materials provided
+ *       with the distribution.
+ * 
+ *     * Neither the name of National ICT Australia, nor the names of its
+ *       contributors, may be used to endorse or promote products derived
+ *       from this Software without specific prior written permission.
+ * 
+ * EXCEPT AS EXPRESSLY STATED IN THIS LICENCE AND TO THE FULL EXTENT
+ * PERMITTED BY APPLICABLE LAW, THE SOFTWARE IS PROVIDED "AS-IS", AND
+ * NATIONAL ICT AUSTRALIA AND ITS CONTRIBUTORS MAKE NO REPRESENTATIONS,
+ * WARRANTIES OR CONDITIONS OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO ANY REPRESENTATIONS, WARRANTIES OR CONDITIONS
+ * REGARDING THE CONTENTS OR ACCURACY OF THE SOFTWARE, OR OF TITLE,
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT,
+ * THE ABSENCE OF LATENT OR OTHER DEFECTS, OR THE PRESENCE OR ABSENCE OF
+ * ERRORS, WHETHER OR NOT DISCOVERABLE.
+ * 
+ * TO THE FULL EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL
+ * NATIONAL ICT AUSTRALIA OR ITS CONTRIBUTORS BE LIABLE ON ANY LEGAL
+ * THEORY (INCLUDING, WITHOUT LIMITATION, IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHERWISE) FOR ANY CLAIM, LOSS, DAMAGES OR OTHER
+ * LIABILITY, INCLUDING (WITHOUT LIMITATION) LOSS OF PRODUCTION OR
+ * OPERATION TIME, LOSS, DAMAGE OR CORRUPTION OF DATA OR RECORDS; OR LOSS
+ * OF ANTICIPATED SAVINGS, OPPORTUNITY, REVENUE, PROFIT OR GOODWILL, OR
+ * OTHER ECONOMIC LOSS; OR ANY SPECIAL, INCIDENTAL, INDIRECT,
+ * CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES, ARISING OUT OF OR IN
+ * CONNECTION WITH THIS LICENCE, THE SOFTWARE OR THE USE OF OR OTHER
+ * DEALINGS WITH THE SOFTWARE, EVEN IF NATIONAL ICT AUSTRALIA OR ITS
+ * CONTRIBUTORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH CLAIM, LOSS,
+ * DAMAGES OR OTHER LIABILITY.
+ * 
+ * If applicable legislation implies representations, warranties, or
+ * conditions, or imposes obligations or liability on National ICT
+ * Australia or one of its contributors in respect of the Software that
+ * cannot be wholly or partly excluded, restricted or modified, the
+ * liability of National ICT Australia or the contributor is limited, to
+ * the full extent permitted by the applicable legislation, at its
+ * option, to:
+ * a.  in the case of goods, any one or more of the following:
+ * i.  the replacement of the goods or the supply of equivalent goods;
+ * ii.  the repair of the goods;
+ * iii. the payment of the cost of replacing the goods or of acquiring
+ *  equivalent goods;
+ * iv.  the payment of the cost of having the goods repaired; or
+ * b.  in the case of services:
+ * i.  the supplying of the services again; or
+ * ii.  the payment of the cost of having the services supplied again.
+ * 
+ * The construction, validity and performance of this licence is governed
+ * by the laws in force in New South Wales, Australia.
+ */
+#ifndef _ARCH_IA32_STD_INT
+#define _ARCH_IA32_STD_INT
+
+typedef signed char int8_t;
+typedef short int16_t;
+typedef int int32_t;
+typedef long int64_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long uint64_t;
+
+#define __PTR_SIZE 64
+
+#endif
diff --git a/include/arch/k1om/barrelfish/bulk_transfer_arch.h b/include/arch/k1om/barrelfish/bulk_transfer_arch.h
new file mode 100644 (file)
index 0000000..5f5af51
--- /dev/null
@@ -0,0 +1,15 @@
+/**
+ * \file
+ * \brief Unidirectional bulk data transfer via shared memory
+ */
+
+/*
+ * Copyright (c) 2009, 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <arch/x86/barrelfish/bulk_transfer_arch.h>
diff --git a/include/arch/k1om/barrelfish/core_state_arch.h b/include/arch/k1om/barrelfish/core_state_arch.h
new file mode 100644 (file)
index 0000000..2ae7733
--- /dev/null
@@ -0,0 +1,20 @@
+/**
+ * \file
+ * \brief
+ */
+
+/*
+ * Copyright (c) 2008, 2009, 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef ARCH_X86_64_BARRELFISH_CORESTATE_H
+#define ARCH_X86_64_BARRELFISH_CORESTATE_H
+
+#include <arch/x86/barrelfish/core_state_arch.h>
+
+#endif
diff --git a/include/arch/k1om/barrelfish/cpu_arch.h b/include/arch/k1om/barrelfish/cpu_arch.h
new file mode 100644 (file)
index 0000000..16b472d
--- /dev/null
@@ -0,0 +1,20 @@
+/**
+ * \file
+ * \brief Architecture specific CPU bits.
+ */
+
+/*
+ * Copyright (c) 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef X86_64_BARRELFISH_CPU_H
+#define X86_64_BARRELFISH_CPU_H
+
+#define CURRENT_CPU_TYPE CPU_X86_64
+
+#endif
diff --git a/include/arch/k1om/barrelfish/curdispatcher_arch.h b/include/arch/k1om/barrelfish/curdispatcher_arch.h
new file mode 100644 (file)
index 0000000..96deceb
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * \file
+ * \brief Implementation of curdispatcher
+ */
+
+/*
+ * Copyright (c) 2007, 2008, 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef ARCH_X86_64_BARRELFISH_CURDISPATCHER_H
+#define ARCH_X86_64_BARRELFISH_CURDISPATCHER_H
+
+/**
+ * \brief Returns pointer to current dispatcher, using thread register
+ */
+static inline dispatcher_handle_t curdispatcher(void)
+{
+    dispatcher_handle_t ret;
+
+    __asm("movq %%fs:8, %[ret]" // XXX: assume offsetof(struct thread, disp) == 8
+          : [ret] "=r" (ret));
+
+    return ret;
+}
+
+#endif // ARCH_X86_64_BARRELFISH_CURDISPATCHER_H
diff --git a/include/arch/k1om/barrelfish/dispatcher_arch.h b/include/arch/k1om/barrelfish/dispatcher_arch.h
new file mode 100644 (file)
index 0000000..81019ba
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * \file
+ * \brief Architecture specific dispatcher structure private to the user
+ */
+
+/*
+ * Copyright (c) 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef ARCH_X86_64_BARRELFISH_DISPATCHER_H
+#define ARCH_X86_64_BARRELFISH_DISPATCHER_H
+
+#include <target/x86_64/barrelfish/dispatcher_target.h>
+
+static inline struct dispatcher_generic*
+get_dispatcher_generic(dispatcher_handle_t handle)
+{
+    return get_dispatcher_generic_x86_64(handle);
+}
+
+static inline size_t get_dispatcher_size(void)
+{
+    return sizeof(struct dispatcher_x86_64);
+}
+
+#endif // ARCH_X86_64_BARRELFISH_DISPATCHER_H
diff --git a/include/arch/k1om/barrelfish/invocations_arch.h b/include/arch/k1om/barrelfish/invocations_arch.h
new file mode 100644 (file)
index 0000000..c6df334
--- /dev/null
@@ -0,0 +1,414 @@
+/**
+ * \file
+ * \brief Low-level capability invocations
+ */
+
+/*
+ * Copyright (c) 2007, 2008, 2009, 2010, 2012, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef INVOCATIONS_ARCH_H
+#define INVOCATIONS_ARCH_H
+
+#include <barrelfish/syscall_arch.h>
+#include <barrelfish_kpi/dispatcher_shared.h>
+#include <barrelfish/caddr.h>
+#include <barrelfish_kpi/paging_arch.h>
+
+static inline struct sysret cap_invoke(struct capref to, uintptr_t arg1,
+                                       uintptr_t arg2, uintptr_t arg3,
+                                       uintptr_t arg4, uintptr_t arg5,
+                                       uintptr_t arg6, uintptr_t arg7,
+                                       uintptr_t arg8, uintptr_t arg9,
+                                       uintptr_t arg10)
+{
+    uint8_t invoke_bits = get_cap_valid_bits(to);
+    capaddr_t invoke_cptr = get_cap_addr(to) >> (CPTR_BITS - invoke_bits);
+
+    return syscall(SYSCALL_INVOKE, (uint64_t)invoke_cptr << 32 |
+                   (uint64_t)invoke_bits << 16 | 10 << 8, 0,
+                   arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9,
+                   arg10);
+}
+
+#define cap_invoke10(to, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j)   \
+    cap_invoke(to, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j)
+#define cap_invoke9(to, _a, _b, _c, _d, _e, _f, _g, _h, _i)        \
+    cap_invoke10(to, _a, _b, _c, _d, _e, _f, _g, _h, _i, 0)
+#define cap_invoke8(to, _a, _b, _c, _d, _e, _f, _g, _h)    \
+    cap_invoke9(to, _a, _b, _c, _d, _e, _f, _g, _h, 0)
+#define cap_invoke7(to, _a, _b, _c, _d, _e, _f, _g)    \
+    cap_invoke8(to, _a, _b, _c, _d, _e, _f, _g, 0)
+#define cap_invoke6(to, _a, _b, _c, _d, _e, _f)        \
+    cap_invoke7(to, _a, _b, _c, _d, _e, _f, 0)
+#define cap_invoke5(to, _a, _b, _c, _d, _e)            \
+    cap_invoke6(to, _a, _b, _c, _d, _e, 0)
+#define cap_invoke4(to, _a, _b, _c, _d)                \
+    cap_invoke5(to, _a, _b, _c, _d, 0)
+#define cap_invoke3(to, _a, _b, _c)                    \
+    cap_invoke4(to, _a, _b, _c, 0)
+#define cap_invoke2(to, _a, _b)                        \
+    cap_invoke3(to, _a, _b, 0)
+#define cap_invoke1(to, _a)                            \
+    cap_invoke2(to, _a, 0)
+
+
+/**
+ * \brief Retype a capability.
+ *
+ * Retypes CPtr 'cap' into 2^'objbits' caps of type 'newtype' and places them
+ * into slots starting at slot 'slot' in the CNode, addressed by 'to', with
+ * 'bits' address bits of 'to' valid.
+ *
+ * See also cap_retype(), which wraps this.
+ *
+ * \param root          Capability of the CNode to invoke
+ * \param cap           Address of cap to retype.
+ * \param newtype       Kernel object type to retype to.
+ * \param objbits       Size of created objects, for variable-sized types
+ * \param to            Address of CNode cap to place retyped caps into.
+ * \param slot          Slot in CNode cap to start placement.
+ * \param bits          Number of valid address bits in 'to'.
+ *
+ * \return Error code
+ */
+static inline errval_t invoke_cnode_retype(struct capref root, capaddr_t cap,
+                                           enum objtype newtype, int objbits,
+                                           capaddr_t to, capaddr_t slot, int bits)
+{
+    assert(cap != CPTR_NULL);
+    return cap_invoke7(root, CNodeCmd_Retype, cap, newtype, objbits, to,
+                       slot, bits).error;
+}
+
+/**
+ * \brief Create a capability.
+ *
+ * Create a new capability of type 'type' and size 'objbits'. The new cap will
+ * be placed in the slot 'dest_slot' of the CNode located at 'dest_cnode_cptr'
+ * in the address space rooted at 'root'.
+ *
+ * See also cap_create(), which wraps this.
+ *
+ * \param root            Capability of the CNode to invoke.
+ * \param type            Kernel object type to create.
+ * \param objbits         Size of created object
+ *                        (ignored for fixed-size objects)
+ * \param dest_cnode_cptr Address of CNode cap, where newly created cap will be
+ *                        placed into.
+ * \param dest_slot       Slot in CNode cap to place new cap.
+ * \param dest_vbits      Number of valid address bits in 'dest_cnode_cptr'.
+ *
+ * \return Error code
+ */
+static inline errval_t invoke_cnode_create(struct capref root,
+                                           enum objtype type, uint8_t objbits,
+                                           capaddr_t dest_cnode_cptr,
+                                           capaddr_t dest_slot,
+                                           uint8_t dest_vbits)
+{
+    assert(dest_cnode_cptr != CPTR_NULL);
+    return cap_invoke6(root, CNodeCmd_Create, type, objbits, dest_cnode_cptr,
+                       dest_slot, dest_vbits).error;
+}
+
+/**
+ * \brief "Mint" a capability.
+ *
+ * Copies CPtr 'from' into slot 'slot' in the CNode, addressed by 'to', within
+ * the address space, rooted at 'root' and with 'tobits' and 'frombits' address
+ * bits of 'to' and 'from' valid, respectively.
+ *
+ * See also cap_mint(), which wraps this.
+ *
+ * \param root          Capability of the CNode to invoke
+ * \param to            CNode to place copy into.
+ * \param slot          Slot in CNode cap to place copy into.
+ * \param from          Address of cap to copy.
+ * \param tobits        Number of valid address bits in 'to'.
+ * \param frombits      Number of valid address bits in 'from'.
+ * \param param1        1st cap-dependent parameter.
+ * \param param2        2nd cap-dependent parameter.
+ *
+ * \return Error code
+ */
+static inline errval_t invoke_cnode_mint(struct capref root, capaddr_t to,
+                                         capaddr_t slot, capaddr_t from, int tobits,
+                                         int frombits, uint64_t param1,
+                                         uint64_t param2)
+{
+    return cap_invoke8(root, CNodeCmd_Mint, to, slot, from, tobits, frombits,
+                       param1, param2).error;
+}
+
+/**
+ * \brief Copy a capability.
+ *
+ * Copies CPtr 'from' into slot 'slot' in the CNode, addressed by 'to', within
+ * the address space, rooted at 'root' and with 'tobits' and 'frombits' address
+ * bits of 'to' and 'from' valid, respectively.
+ *
+ * See also cap_copy(), which wraps this.
+ *
+ * \param root          Capability of the CNode to invoke
+ * \param to            CNode to place copy into.
+ * \param slot          Slot in CNode cap to place copy into.
+ * \param from          Address of cap to copy.
+ * \param tobits        Number of valid address bits in 'to'.
+ * \param frombits      Number of valid address bits in 'from'.
+ *
+ * \return Error code
+ */
+static inline errval_t invoke_cnode_copy(struct capref root, capaddr_t to,
+                                         capaddr_t slot, capaddr_t from, int tobits,
+                                         int frombits)
+{
+    return cap_invoke6(root, CNodeCmd_Copy, to, slot, from,
+                       tobits, frombits).error;
+}
+
+/**
+ * \brief Delete a capability.
+ *
+ * Delete the capability pointed to by 'cap', with 'bits' address bits
+ * of it valid, from the address space rooted at 'root'.
+ *
+ * \param root  Capability of the CNode to invoke
+ * \param cap   Address of cap to delete.
+ * \param bits  Number of valid bits within 'cap'.
+ *
+ * \return Error code
+ */
+static inline errval_t invoke_cnode_delete(struct capref root, capaddr_t cap,
+                                           int bits)
+{
+    return cap_invoke3(root, CNodeCmd_Delete, cap, bits).error;
+}
+
+static inline errval_t invoke_cnode_revoke(struct capref root, capaddr_t cap,
+                                           int bits)
+{
+    return cap_invoke3(root, CNodeCmd_Revoke, cap, bits).error;
+}
+
+static inline errval_t invoke_vnode_map(struct capref ptable, capaddr_t slot,
+                                        capaddr_t src, int frombits, size_t flags,
+                                        size_t offset, size_t pte_count)
+{
+    return cap_invoke7(ptable, VNodeCmd_Map, slot, src, frombits, flags, offset, pte_count).error;
+}
+
+static inline errval_t invoke_vnode_unmap(struct capref cap, capaddr_t mapping_addr,
+                                          int bits, size_t entry, size_t num_pages)
+{
+    return cap_invoke5(cap, VNodeCmd_Unmap, mapping_addr, bits, entry, num_pages).error;
+}
+
+/**
+ * \brief Return the physical address and size of a frame capability
+ *
+ * \param frame    CSpace address of frame capability
+ * \param ret      frame_identity struct filled in with relevant data
+ *
+ * \return Error code
+ */
+static inline errval_t invoke_frame_identify(struct capref frame,
+                                             struct frame_identity *ret)
+{
+    struct sysret sysret = cap_invoke1(frame, FrameCmd_Identify);
+
+    assert(ret != NULL);
+    if (err_is_ok(sysret.error)) {
+        ret->base = sysret.value & (~BASE_PAGE_MASK);
+        ret->bits = sysret.value & BASE_PAGE_MASK;
+        return sysret.error;
+    }
+
+    ret->base = 0;
+    ret->bits = 0;
+    return sysret.error;
+}
+
+/**
+ * \brief Modify mapping flags on parts of a mapped frame
+ *
+ * \param frame    CSpace address of frame capability
+ * \param off      Offset (in #pages) of the first page to get new set of flags
+ *                 from the first page in the mapping identified by `frame`
+ * \param pages    Number of pages that should get new set of flags
+ * \param flags    New set of flags
+ *
+ * \return Error code
+ */
+static inline errval_t invoke_frame_modify_flags(struct capref frame,
+                                                 size_t offset,
+                                                 size_t pages,
+                                                 size_t flags)
+{
+    return cap_invoke4(frame, FrameCmd_ModifyFlags, offset, pages, flags).error;
+}
+
+static inline errval_t invoke_iocap_in(struct capref iocap, enum io_cmd cmd,
+                                       uint16_t port, uint32_t *data)
+{
+    struct sysret sysret = cap_invoke2(iocap, cmd, port);
+
+    if (err_is_ok(sysret.error)) {
+        assert(data != NULL);
+        *data = sysret.value;
+    }
+    return sysret.error;
+}
+
+static inline errval_t invoke_iocap_out(struct capref iocap, enum io_cmd cmd,
+                                        uint16_t port, uint32_t data)
+{
+    return cap_invoke3(iocap, cmd, port, data).error;
+}
+
+/**
+ * \brief Setup a dispatcher, possibly making it runnable
+ *
+ * \param dispatcher    Address of dispatcher capability
+ * \param domdispatcher Address of existing dispatcher for domain ID
+ * \param cspace_root   Root of CSpace for new dispatcher
+ * \param cspace_root_bits  Number of valid bits in cspace_root
+ * \param vspace_root   Root of VSpace for new dispatcher
+ * \param dispatcher_frame Frame capability for dispatcher structure
+ * \param run           Make runnable if true
+ *
+ * Any arguments of CPTR_NULL are ignored.
+ *
+ * \return Error code
+ */
+static inline errval_t
+invoke_dispatcher(struct capref dispatcher, struct capref domdispatcher,
+                  struct capref cspace, struct capref vspace,
+                  struct capref dispframe, bool run)
+{
+    uint8_t root_vbits = get_cap_valid_bits(cspace);
+    capaddr_t root_caddr = get_cap_addr(cspace) >> (CPTR_BITS - root_vbits);
+    capaddr_t vtree_caddr = get_cap_addr(vspace);
+    capaddr_t disp_caddr = get_cap_addr(dispframe);
+    capaddr_t dd_caddr = get_cap_addr(domdispatcher);
+
+    return cap_invoke7(dispatcher, DispatcherCmd_Setup, root_caddr,
+                       root_vbits, vtree_caddr, disp_caddr, run,
+                       dd_caddr).error;
+}
+
+/**
+ * \brief Setup a VM guest DCB
+ *
+ * \param dcb       Dispatcher capability
+ */
+static inline errval_t
+invoke_dispatcher_setup_guest(struct capref dispatcher,
+                              struct capref ep_cap,
+                              struct capref vnode,
+                              struct capref vmkit_guest,
+                              struct capref guest_control_cap)
+{
+    return cap_invoke5(dispatcher, DispatcherCmd_SetupGuest,
+                       get_cap_addr(ep_cap), get_cap_addr(vnode),
+                       get_cap_addr(vmkit_guest),
+                       get_cap_addr(guest_control_cap)).error;
+}
+
+static inline errval_t invoke_irqtable_set(struct capref irqcap, int irq,
+                                           struct capref ep)
+{
+    return cap_invoke3(irqcap, IRQTableCmd_Set, irq, get_cap_addr(ep)).error;
+}
+
+static inline errval_t invoke_irqtable_delete(struct capref irqcap, int irq)
+{
+    return cap_invoke2(irqcap, IRQTableCmd_Delete, irq).error;
+}
+
+/**
+ * \brief do a kernel cap invocation to get the core id
+ */
+static inline errval_t invoke_kernel_get_core_id(struct capref kern_cap,
+                                                 coreid_t *core_id)
+{
+    assert(core_id != NULL);
+
+    struct sysret sysret = cap_invoke1(kern_cap, KernelCmd_Get_core_id);
+    if (sysret.error == SYS_ERR_OK) {
+        *core_id = sysret.value;
+    }
+    return sysret.error;
+}
+
+static inline errval_t invoke_dispatcher_dump_ptables(struct capref dispcap)
+{
+    return cap_invoke1(dispcap, DispatcherCmd_DumpPTables).error;
+}
+
+static inline errval_t invoke_perfmon_activate(struct capref perfmon_cap,
+                                               uint8_t event, uint8_t perf_umask, 
+                                               bool kernel, uint8_t counter_id,
+                                               uint64_t counter_value, 
+                                               capaddr_t ep_addr)
+{
+    return cap_invoke7(perfmon_cap, PerfmonCmd_Activate, 
+                       event, perf_umask, counter_id, kernel, 
+                       counter_value, ep_addr).error;
+}
+
+static inline errval_t invoke_perfmon_write(struct capref perfmon_cap,
+                                                  uint8_t counter_id,
+                                                  uint64_t counter_value)
+{
+    return cap_invoke3(perfmon_cap, PerfmonCmd_Write, counter_id, counter_value).error;
+}
+
+static inline errval_t invoke_perfmon_deactivate(struct capref perfmon_cap)
+{
+    return cap_invoke1(perfmon_cap, PerfmonCmd_Deactivate).error;
+}
+
+static inline errval_t
+invoke_dispatcher_properties(struct capref dispatcher,
+                             enum task_type type, unsigned long deadline,
+                             unsigned long wcet, unsigned long period,
+                             unsigned long release, unsigned short weight)
+{
+    return cap_invoke7(dispatcher, DispatcherCmd_Properties, type, deadline,
+                       wcet, period, release, weight).error;
+}
+
+static inline errval_t invoke_ipi_notify_send(struct capref notify_cap)
+{
+    return cap_invoke1(notify_cap, NotifyCmd_Send).error;
+}
+
+/**
+ * \brief Return the system-wide unique ID of the passed ID capability.
+ *
+ * \param idcap ID capability to invoke.
+ * \param id    Filled-in with system-wide unique ID of ID cap.
+ *
+ * \return      Error code
+ */
+static inline errval_t invoke_idcap_identify(struct capref idcap,
+                                             idcap_id_t *id)
+{
+    assert(id != NULL);
+
+    struct sysret sysret = cap_invoke1(idcap, IDCmd_Identify);
+
+    if (err_is_ok(sysret.error)) {
+        *id = sysret.value;
+    }
+
+    return sysret.error;
+}
+
+#endif
diff --git a/include/arch/k1om/barrelfish/ldt.h b/include/arch/k1om/barrelfish/ldt.h
new file mode 100644 (file)
index 0000000..5f9f145
--- /dev/null
@@ -0,0 +1,22 @@
+/**
+ * \file
+ * \brief "Public" interface to Barrelfish userland LDT
+ */
+
+/*
+ * Copyright (c) 2011, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef _BARRELFISH_X86_64_LDT_H
+#define _BARRELFISH_X86_64_LDT_H
+
+errval_t ldt_alloc_segment(void *segbase, uint16_t *ret_selector);
+errval_t ldt_update_segment(uint16_t selector, void *segbase);
+errval_t ldt_free_segment(uint16_t selector);
+
+#endif
diff --git a/include/arch/k1om/barrelfish/lmp_chan_arch.h b/include/arch/k1om/barrelfish/lmp_chan_arch.h
new file mode 100644 (file)
index 0000000..534c390
--- /dev/null
@@ -0,0 +1,116 @@
+/**
+ * \file
+ * \brief
+ */
+
+/*
+ * Copyright (c) 2007, 2008, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef ARCH_X86_64_BARRELFISH_LMP_CHAN_H
+#define ARCH_X86_64_BARRELFISH_LMP_CHAN_H
+
+#include <barrelfish/syscall_arch.h>
+#include <barrelfish/caddr.h>
+#include <barrelfish_kpi/lmp.h>
+
+/**
+ * \brief Send a message on the given LMP endpoint, if possible
+ *
+ * Non-blocking, may fail if there is no space in the receiver's endpoint.
+ *
+ * \param ep Remote endpoint
+ * \param flags LMP send flags
+ * \param send_cap (Optional) capability to send with the message
+ * \param length_words Length of the message in words; payload beyond this
+ *                      size will not be delivered
+ * \param arg1..N Message payload
+ */
+static inline errval_t lmp_ep_send(struct capref ep, lmp_send_flags_t flags,
+                                   struct capref send_cap, uint8_t length_words,
+                                   uint64_t arg1, uint64_t arg2, uint64_t arg3,
+                                   uint64_t arg4, uint64_t arg5, uint64_t arg6,
+                                   uint64_t arg7, uint64_t arg8, uint64_t arg9,
+                                   uint64_t arg10)
+{
+    uint8_t send_bits = get_cap_valid_bits(send_cap);
+    capaddr_t send_cptr = get_cap_addr(send_cap) >> (CPTR_BITS - send_bits);
+
+#ifndef TRACE_DISABLE_LRPC
+    // Do an LRPC if possible
+    if (send_cptr == 0 && send_bits == 0          // Not sending a cap
+        && ep.cnode.address == CPTR_ROOTCN        // EP in rootcn
+        && (flags & LMP_FLAG_SYNC) != 0           // sync option
+        && length_words <= LRPC_MSG_LENGTH) {     // Check length
+
+        assert(LRPC_MSG_LENGTH == 4);
+        return syscall6(SYSCALL_LRPC, ep.slot, arg1, arg2, arg3, arg4).error;
+    }
+#endif
+
+    uint8_t invoke_bits = get_cap_valid_bits(ep);
+    capaddr_t invoke_cptr = get_cap_addr(ep) >> (CPTR_BITS - invoke_bits);
+
+    return syscall(SYSCALL_INVOKE,
+                   (uint64_t)invoke_cptr << 32 | (uint64_t)send_bits << 24 |
+                   (uint64_t)invoke_bits << 16 | (uint64_t)length_words << 8 |
+                   flags, send_cptr,
+                   arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9,
+                   arg10).error;
+}
+
+#define lmp_ep_send10(ep, flags, send_cap, a, b, c, d, e, f, g, h, i, j) \
+  lmp_ep_send((ep), (flags), (send_cap), 10, (a), (b), (c), (d), (e), (f), (g), (h), (i), (j))
+#define lmp_ep_send9(ep, flags, send_cap, a, b, c, d, e, f, g, h, i) \
+  lmp_ep_send((ep), (flags), (send_cap), 9, (a), (b), (c), (d), (e), (f), (g), (h), (i), 0)
+#define lmp_ep_send8(ep, flags, send_cap, a, b, c, d, e, f, g, h) \
+  lmp_ep_send((ep), (flags), (send_cap), 8, (a), (b), (c), (d), (e), (f), (g), (h), 0, 0)
+#define lmp_ep_send7(ep, flags, send_cap, a, b, c, d, e, f, g) \
+  lmp_ep_send((ep), (flags), (send_cap), 7, (a), (b), (c), (d), (e), (f), (g), 0, 0, 0)
+#define lmp_ep_send6(ep, flags, send_cap, a, b, c, d, e, f) \
+  lmp_ep_send((ep), (flags), (send_cap), 6, (a), (b), (c), (d), (e), (f), 0, 0, 0, 0)
+#define lmp_ep_send5(ep, flags, send_cap, a, b, c, d, e) \
+  lmp_ep_send((ep), (flags), (send_cap), 5, (a), (b), (c), (d), (e), 0, 0, 0, 0, 0)
+#define lmp_ep_send4(ep, flags, send_cap, a, b, c, d) \
+  lmp_ep_send((ep), (flags), (send_cap), 4, (a), (b), (c), (d), 0, 0, 0, 0, 0, 0)
+#define lmp_ep_send3(ep, flags, send_cap, a, b, c) \
+  lmp_ep_send((ep), (flags), (send_cap), 3, (a), (b), (c), 0, 0, 0, 0, 0, 0, 0)
+#define lmp_ep_send2(ep, flags, send_cap, a, b) \
+  lmp_ep_send((ep), (flags), (send_cap), 2, (a), (b), 0, 0, 0, 0, 0, 0, 0, 0)
+#define lmp_ep_send1(ep, flags, send_cap, a) \
+  lmp_ep_send((ep), (flags), (send_cap), 1, (a), 0, 0, 0, 0, 0, 0, 0, 0, 0)
+#define lmp_ep_send0(ep, flags, send_cap) \
+  lmp_ep_send((ep), (flags), (send_cap), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+
+#define lmp_chan_send(lc, flags, send_cap, len, a, b, c, d, e, f, g, h, i, j) \
+  lmp_ep_send((lc)->remote_cap, (flags), (send_cap), (len), (a), (b), (c), (d), (e), (f), (g), (h), (i), (j))
+
+#define lmp_chan_send10(lc, flags, send_cap, a, b, c, d, e, f, g, h, i, j) \
+  lmp_ep_send10((lc)->remote_cap, (flags), (send_cap), (a), (b), (c), (d), (e), (f), (g), (h), (i), (j))
+#define lmp_chan_send9(lc, flags, send_cap, a, b, c, d, e, f, g, h, i) \
+  lmp_ep_send9((lc)->remote_cap, (flags), (send_cap), (a), (b), (c), (d), (e), (f), (g), (h), (i))
+#define lmp_chan_send8(lc, flags, send_cap, a, b, c, d, e, f, g, h) \
+  lmp_ep_send8((lc)->remote_cap, (flags), (send_cap), (a), (b), (c), (d), (e), (f), (g), (h))
+#define lmp_chan_send7(lc, flags, send_cap, a, b, c, d, e, f, g) \
+  lmp_ep_send7((lc)->remote_cap, (flags), (send_cap), (a), (b), (c), (d), (e), (f), (g))
+#define lmp_chan_send6(lc, flags, send_cap, a, b, c, d, e, f) \
+  lmp_ep_send6((lc)->remote_cap, (flags), (send_cap), (a), (b), (c), (d), (e), (f))
+#define lmp_chan_send5(lc, flags, send_cap, a, b, c, d, e) \
+  lmp_ep_send5((lc)->remote_cap, (flags), (send_cap), (a), (b), (c), (d), (e))
+#define lmp_chan_send4(lc, flags, send_cap, a, b, c, d) \
+  lmp_ep_send4((lc)->remote_cap, (flags), (send_cap), (a), (b), (c), (d))
+#define lmp_chan_send3(lc, flags, send_cap, a, b, c) \
+  lmp_ep_send3((lc)->remote_cap, (flags), (send_cap), (a), (b), (c))
+#define lmp_chan_send2(lc, flags, send_cap, a, b) \
+  lmp_ep_send2((lc)->remote_cap, (flags), (send_cap), (a), (b))
+#define lmp_chan_send1(lc, flags, send_cap, a) \
+  lmp_ep_send1((lc)->remote_cap, (flags), (send_cap), (a))
+#define lmp_chan_send0(lc, flags, send_cap) \
+  lmp_ep_send0((lc)->remote_cap, (flags), (send_cap))
+
+#endif // ARCH_X86_64_BARRELFISH_LMP_CHAN_H
diff --git a/include/arch/k1om/barrelfish/pmap_arch.h b/include/arch/k1om/barrelfish/pmap_arch.h
new file mode 100644 (file)
index 0000000..aa84f15
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * \file
+ * \brief pmap management wrappers
+ */
+
+/*
+ * Copyright (c) 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef ARCH_X86_64_BARRELFISH_PMAP_H
+#define ARCH_X86_64_BARRELFISH_PMAP_H
+
+#include <target/x86_64/barrelfish/pmap_target.h>
+
+#define ARCH_DEFAULT_PMAP_SIZE sizeof(struct pmap_x86)
+
+static inline errval_t pmap_init(struct pmap *pmap, struct vspace *vspace,
+                                 struct capref vnode,
+                                 struct slot_allocator *opt_slot_alloc)
+{
+    return pmap_x86_64_init(pmap, vspace, vnode, opt_slot_alloc);
+}
+
+static inline errval_t pmap_current_init(bool init_domain)
+{
+    return pmap_x86_64_current_init(init_domain);
+}
+
+#endif // ARCH_X86_64_BARRELFISH_PMAP_H
diff --git a/include/arch/k1om/barrelfish/syscall_arch.h b/include/arch/k1om/barrelfish/syscall_arch.h
new file mode 100644 (file)
index 0000000..1452f09
--- /dev/null
@@ -0,0 +1,134 @@
+/**
+ * \file
+ * \brief User-side system call implementation
+ */
+
+/*
+ * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef ARCH_X86_64_BARRELFISH_SYSCALL_H
+#define ARCH_X86_64_BARRELFISH_SYSCALL_H
+
+#include <barrelfish_kpi/syscalls.h>  // for struct sysret.
+
+/*
+ * Introduction to the syscall macros, or "what the hell is going on here"?
+ *
+ * The macros here are collectively used to expand the body of the inlined
+ * function syscall() that implements all syscalls except for cap_invoke(),
+ * which is a special case, due to the thread_invoke_cap_and_exit() hack.
+ *
+ * First, BF_SYSCALL_BODY sets up the register arguments to be passed into the
+ * syscall, then BF_SYSCALL_ASM contains the asm code that includes the actual
+ * syscall. This macro has a "label" argument which can be used to emit an
+ * arbitrary bit of assembly code after the syscall instruction. This is used
+ * by cap_invoke() to insert a label immediately following the syscall, so that
+ * the threads package can tell if a thread that was about to do an invocation
+ * actually reached the syscall instruction. Note that this can't be inserted
+ * in the syscall code unconditionally, because we want it to be inlined, and
+ * that would result in multiple definitions of the symbol.
+ *
+ * If you can think of a better way to do this, by all means clean it up! :)
+ */
+
+/* FIXME: the first version of this code is optimal, and works when we are
+ * compiling either with optimisation on (-O) or at any optimisation level
+ * without a frame pointer (-fomit-frame-pointer), however not for the
+ * standard unoptimised GCC, which insists on using RBP.
+ */
+#if 0 /* was if defined(NDEBUG), but gcc is still screwing this up -- AB */
+// XXX: Need to update this to the new syscall ABI before it will work again
+# define BF_SYSCALL_ASM(arg11, label) \
+    register uint64_t a11 __asm("rbp") = arg11;     \
+    __asm volatile("syscall\n\t"                    \
+                   label                            \
+        : "+r" (a10_ret1), "+r" (a2_ret2)           \
+        : "r" (a1), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7), \
+          "r" (a8), "r" (a9), "r" (a11), "r" (a12), "r" (syscall_num) \
+        : "r11", "rcx");
+#else /* DEBUG */
+# define BF_SYSCALL_ASM(arg11, label) \
+    __asm volatile("pushq %%rbp             \n\t"   \
+                   "movq %%rcx, %%rbp       \n\t"   \
+                   "syscall                 \n\t"   \
+                   label                            \
+                   "popq %%rbp              \n\t"   \
+        : "+a" (a10_ret1), "+c" (arg11), "+d" (a2_ret2), "+r" (a1), \
+          "+r" (a3), "+r" (a4), "+r" (a5), "+r" (syscall_num)  \
+        : "r" (a6), "r" (a7), "r" (a8), "r" (a9), "r" (a12) \
+        : "r11");
+#endif
+
+/* NB: We use a10_ret (in the rax register) as both input and output
+ * register, because some versions of GCC (eg. 4.2.3) fail to use rax as
+ * both an input and separately as an output register
+ */
+#define BF_SYSCALL_BODY(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, \
+                        arg9, arg10, arg11, arg12, label) \
+    register uint64_t syscall_num __asm("rdi") = num;   \
+    register uint64_t a1 __asm("rsi") = arg1;           \
+    register uint64_t a2_ret2 __asm("rdx") = arg2;           \
+    register uint64_t a3 __asm("r10") = arg3;           \
+    register uint64_t a4 __asm("r8") = arg4;            \
+    register uint64_t a5 __asm("r9") = arg5;            \
+    register uint64_t a6 __asm("r12") = arg6;           \
+    register uint64_t a7 __asm("r13") = arg7;           \
+    register uint64_t a8 __asm("r14") = arg8;           \
+    register uint64_t a9 __asm("r15") = arg9;           \
+    register uint64_t a12 __asm("rbx") = arg12;         \
+    register uint64_t a10_ret1 __asm("rax") = arg10;     \
+    BF_SYSCALL_ASM(arg11, label)
+
+
+static inline struct sysret syscall(uint64_t num, uint64_t arg1, uint64_t arg2,
+                 uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6,
+                 uint64_t arg7, uint64_t arg8, uint64_t arg9, uint64_t arg10,
+                 uint64_t arg11, uint64_t arg12)
+{
+    BF_SYSCALL_BODY(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9,
+                    arg10, arg11, arg12, "");
+    return (struct sysret){/*error*/ a10_ret1, /*value*/ a2_ret2};
+}
+
+#define syscall12(_a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l) \
+       syscall(_a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, 0)
+#define syscall11(_a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k) \
+       syscall12(_a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, 0)
+#define syscall10(_a, _b, _c, _d, _e, _f, _g, _h, _i, _j) \
+       syscall11(_a, _b, _c, _d, _e, _f, _g, _h, _i, _j, 0)
+#define syscall9(_a, _b, _c, _d, _e, _f, _g, _h, _i) \
+       syscall10(_a, _b, _c, _d, _e, _f, _g, _h, _i, 0)
+#define syscall8(_a, _b, _c, _d, _e, _f, _g, _h) \
+       syscall9(_a, _b, _c, _d, _e, _f, _g, _h, 0)
+#define syscall7(_a, _b, _c, _d, _e, _f, _g) \
+       syscall8(_a, _b, _c, _d, _e, _f, _g, 0)
+#define syscall6(_a, _b, _c, _d, _e, _f) \
+       syscall7(_a, _b, _c, _d, _e, _f, 0)
+#define syscall5(_a, _b, _c, _d, _e) \
+       syscall6(_a, _b, _c, _d, _e, 0)
+#define syscall4(_a, _b, _c, _d) \
+       syscall5(_a, _b, _c, _d, 0)
+#define syscall3(_a, _b, _c) \
+       syscall4(_a, _b, _c, 0)
+#define syscall2(_a, _b) \
+       syscall3(_a, _b, 0)
+#define syscall1(_a) \
+       syscall2(_a, 0)
+
+static inline errval_t sys_x86_fpu_trap_on(void)
+{
+    return syscall1(SYSCALL_X86_FPU_TRAP_ON).error;
+}
+
+static inline errval_t sys_x86_reload_ldt(void)
+{
+    return syscall1(SYSCALL_X86_RELOAD_LDT).error;
+}
+
+#endif
diff --git a/include/arch/k1om/barrelfish_kpi/asm_inlines_arch.h b/include/arch/k1om/barrelfish_kpi/asm_inlines_arch.h
new file mode 100644 (file)
index 0000000..fc04c23
--- /dev/null
@@ -0,0 +1,89 @@
+/**
+ * \file
+ * \brief
+ */
+
+/*
+ * Copyright (c) 2007, 2008, 2009, 2010, 2011, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef ARCH_X86_64_BARRELFISH_KPI_ASM_INLINES_H
+#define ARCH_X86_64_BARRELFISH_KPI_ASM_INLINES_H
+
+#ifndef __ASSEMBLER__
+
+#include <target/x86_64/barrelfish_kpi/registers_target.h>
+
+static inline void cpuid(uint32_t function, uint32_t *eax, uint32_t *ebx,
+                         uint32_t *ecx, uint32_t *edx)
+{
+    // make it possible to omit certain return registers
+    uint32_t a, b, c, d;
+    if (eax == NULL) {
+        eax = &a;
+    }
+    if (ebx == NULL) {
+        ebx = &b;
+    }
+    if (ecx == NULL) {
+        ecx = &c;
+    }
+    if (edx == NULL) {
+        edx = &d;
+    }
+    __asm volatile("cpuid"
+                   : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
+                   : "a" (function)
+                   );
+}
+
+
+/** \brief Atomic compare-and-swap on 128 bits
+ *
+ * If *dst == old then *dst = new, returns 0 on failure
+ * 
+ * Note, dest should point to a 128bit structure that is to be overwritten 
+ */
+static inline int cmpxchg128(volatile uint64_t dest[2], uint64_t old_top, uint64_t old_bot, uint64_t new_top, uint64_t new_bot)
+{
+    uint8_t ret;
+
+    __asm volatile (
+        "lock cmpxchg16b %1\n\t"
+        "setz %0\n\t"
+        : "=a"(ret), "=m"(*dest)//, "=d"(old_top), "=a"(old_bot)
+        : "a"(old_top), "d"(old_bot), "b"(new_top), "c"(new_bot), "m"(*dest)
+        : "memory");
+
+    return ret;
+}
+
+static inline void fpu_init(void)
+{
+    __asm volatile ("fninit");
+}
+
+static inline void fpu_save(struct registers_fpu_x86_64 *fpustate)
+{
+    uint8_t *regs = fpustate->registers;
+    regs += 16 - ((uintptr_t)regs % 16);
+
+    __asm volatile("fxsaveq %0" : "=m" (*regs));
+}
+
+static inline void fpu_restore(struct registers_fpu_x86_64 *fpustate)
+{
+    uint8_t *regs = fpustate->registers;
+    regs += 16 - ((uintptr_t)regs % 16);
+
+    __asm volatile ("fxrstorq %0" :: "m" (*regs));
+}
+
+#endif // __ASSEMBLER__
+
+#endif // ARCH_X86_64_BARRELFISH_KPI_ASM_INLINES_H
diff --git a/include/arch/k1om/barrelfish_kpi/cpu_arch.h b/include/arch/k1om/barrelfish_kpi/cpu_arch.h
new file mode 100644 (file)
index 0000000..b005071
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+ * \file
+ * \brief Arch specific CPU declarations
+ */
+
+/*
+ * Copyright (c) 2010, 2011, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef ARCH_X86_64_BARRELFISH_KPI_CPU_H
+#define ARCH_X86_64_BARRELFISH_KPI_CPU_H
+
+/// This CPU supports lazy FPU context switching
+#define FPU_LAZY_CONTEXT_SWITCH
+
+/*
+ * Entries in the Interrupt Descriptor Table (IDT)
+ */
+#define IDT_DE          0       /* #DE: Divide Error */
+#define IDT_DB          1       /* #DB: Debug */
+#define IDT_NMI         2       /* Nonmaskable External Interrupt */
+#define IDT_BP          3       /* #BP: Breakpoint */
+#define IDT_OF          4       /* #OF: Overflow */
+#define IDT_BR          5       /* #BR: Bound Range Exceeded */
+#define IDT_UD          6       /* #UD: Undefined/Invalid Opcode */
+#define IDT_NM          7       /* #NM: No Math Coprocessor */
+#define IDT_DF          8       /* #DF: Double Fault */
+#define IDT_FPUGP       9       /* Coprocessor Segment Overrun */
+#define IDT_TS          10      /* #TS: Invalid TSS */
+#define IDT_NP          11      /* #NP: Segment Not Present */
+#define IDT_SS          12      /* #SS: Stack Segment Fault */
+#define IDT_GP          13      /* #GP: General Protection Fault */
+#define IDT_PF          14      /* #PF: Page Fault */
+#define IDT_MF          16      /* #MF: FPU Floating-Point Error */
+#define IDT_AC          17      /* #AC: Alignment Check */
+#define IDT_MC          18      /* #MC: Machine Check */
+#define IDT_XF          19      /* #XF: SIMD Floating-Point Exception */
+
+#endif
diff --git a/include/arch/k1om/barrelfish_kpi/dispatcher_shared_arch.h b/include/arch/k1om/barrelfish_kpi/dispatcher_shared_arch.h
new file mode 100644 (file)
index 0000000..f1a12be
--- /dev/null
@@ -0,0 +1,70 @@
+/**
+ * \file
+ * \brief Architecture specific dispatcher struct shared between kernel and user
+ */
+
+/*
+ * Copyright (c) 2010, 2011, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef ARCH_X86_64_BARRELFISH_KPI_DISPATCHER_SHARED_ARCH_H
+#define ARCH_X86_64_BARRELFISH_KPI_DISPATCHER_SHARED_ARCH_H
+
+#include <target/x86_64/barrelfish_kpi/dispatcher_shared_target.h>
+
+/**
+ * \brief Returns whether dispatcher is currently disabled, given IP.
+ *
+ * \param disp  Pointer to dispatcher
+ * \param ip    User-level instruction pointer.
+ *
+ * \return true if dispatcher disabled, false otherwise.
+ */
+static inline bool dispatcher_is_disabled_ip(dispatcher_handle_t handle,
+                                             uintptr_t rip)
+{
+    /* one crit_pc pair */
+    struct dispatcher_shared_generic *disp =
+        get_dispatcher_shared_generic(handle);
+    struct dispatcher_shared_x86_64 *disp64 =
+        get_dispatcher_shared_x86_64(handle);
+    return disp->disabled ||
+        (disp64->crit_pc_low <= rip && rip < disp64->crit_pc_high);
+}
+
+static inline arch_registers_state_t*
+dispatcher_get_enabled_save_area(dispatcher_handle_t handle)
+{
+    return dispatcher_x86_64_get_enabled_save_area(handle);
+}
+
+static inline arch_registers_state_t*
+dispatcher_get_disabled_save_area(dispatcher_handle_t handle)
+{
+    return dispatcher_x86_64_get_disabled_save_area(handle);
+}
+
+static inline arch_registers_state_t*
+dispatcher_get_trap_save_area(dispatcher_handle_t handle)
+{
+    return dispatcher_x86_64_get_trap_save_area(handle);
+}
+
+static inline arch_registers_fpu_state_t*
+dispatcher_get_enabled_fpu_save_area(dispatcher_handle_t handle)
+{
+    return dispatcher_x86_64_get_enabled_fpu_save_area(handle);
+}
+
+static inline arch_registers_fpu_state_t*
+dispatcher_get_disabled_fpu_save_area(dispatcher_handle_t handle)
+{
+    return dispatcher_x86_64_get_disabled_fpu_save_area(handle);
+}
+
+#endif // ARCH_X86_64_BARRELFISH_KPI_DISPATCHER_SHARED_ARCH_H
diff --git a/include/arch/k1om/barrelfish_kpi/eflags_arch.h b/include/arch/k1om/barrelfish_kpi/eflags_arch.h
new file mode 100644 (file)
index 0000000..4fffc24
--- /dev/null
@@ -0,0 +1,25 @@
+/**
+ * \file
+ * \brief
+ */
+
+/*
+ * Copyright (c) 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef ARCH_X86_64_BARRELFISH_KPI_EFLAGS_H
+#define ARCH_X86_64_BARRELFISH_KPI_EFLAGS_H
+
+/**
+ * State of EFLAGS when executing a user-space program: Enable interrupts
+ */
+#define USER_CS                         0x23
+#define USER_SS                         0x1b
+#define USER_EFLAGS                     0x202
+
+#endif // ARCH_X86_64_BARRELFISH_KPI_EFLAGS_H
diff --git a/include/arch/k1om/barrelfish_kpi/generic_arch.h b/include/arch/k1om/barrelfish_kpi/generic_arch.h
new file mode 100644 (file)
index 0000000..c7fdaed
--- /dev/null
@@ -0,0 +1,22 @@
+/**
+ * \file
+ * \brief Generic include for a bunch of arch specific files
+ */
+
+/*
+ * Copyright (c) 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef ARCH_X86_64_BARRELFISH_KPI_GENERIC_H
+#define ARCH_X86_64_BARRELFISH_KPI_GENERIC_H
+
+#include <barrelfish_kpi/eflags_arch.h>
+#include <barrelfish_kpi/asm_inlines_arch.h>
+#include <arch/x86/barrelfish_kpi/asm_inlines_arch.h>
+
+#endif // ARCH_X86_64_BARRELFISH_KPI_GENERIC_H
diff --git a/include/arch/k1om/barrelfish_kpi/lmp_arch.h b/include/arch/k1om/barrelfish_kpi/lmp_arch.h
new file mode 100644 (file)
index 0000000..5c02376
--- /dev/null
@@ -0,0 +1,26 @@
+/**
+ * \file
+ * \brief Arch specific LMP declarations
+ */
+
+/*
+ * Copyright (c) 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef ARCH_X86_64_BARRELFISH_KPI_LMP_H
+#define ARCH_X86_64_BARRELFISH_KPI_LMP_H
+
+/**
+ * \brief Maximum total length of LMP and LRPC messages (payload)
+ *
+ * Determined by number of registers available to transfer messages.
+ */
+#define LMP_MSG_LENGTH          10
+#define LRPC_MSG_LENGTH         4
+
+#endif // ARCH_X86_64_BARRELFISH_KPI_LMP_H
diff --git a/include/arch/k1om/barrelfish_kpi/paging_arch.h b/include/arch/k1om/barrelfish_kpi/paging_arch.h
new file mode 100644 (file)
index 0000000..02d8113
--- /dev/null
@@ -0,0 +1,56 @@
+/**
+ * \file
+ * \brief Define generics for arch specific definitions
+ */
+
+/*
+ * Copyright (c) 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef ARCH_X86_64_BARRELFISH_KPI_PAGING_H
+#define ARCH_X86_64_BARRELFISH_KPI_PAGING_H
+
+#include <target/x86_64/barrelfish_kpi/paging_target.h>
+
+/**
+ * Information about page sizes
+ */
+#define BASE_PAGE_BITS      X86_64_BASE_PAGE_BITS
+#define BASE_PAGE_SIZE      X86_64_BASE_PAGE_SIZE
+#define BASE_PAGE_MASK      X86_64_BASE_PAGE_MASK
+#define BASE_PAGE_OFFSET    X86_64_BASE_PAGE_OFFSET
+
+#define LARGE_PAGE_BITS      X86_64_LARGE_PAGE_BITS
+#define LARGE_PAGE_SIZE      X86_64_LARGE_PAGE_SIZE
+#define LARGE_PAGE_MASK      X86_64_LARGE_PAGE_MASK
+#define LARGE_PAGE_OFFSET    X86_64_LARGE_PAGE_OFFSET
+
+/**
+ * Bits within the various page directories and tables.
+ */
+#define PTABLE_EXECUTE_DISABLE  X86_64_PTABLE_EXECUTE_DISABLE
+#define PTABLE_GLOBAL_PAGE      X86_64_PTABLE_GLOBAL_PAGE
+#define PTABLE_ATTR_INDEX       X86_64_PTABLE_ATTR_INDEX
+#define PTABLE_DIRTY            X86_64_PTABLE_DIRTY
+#define PTABLE_ACCESSED         X86_64_PTABLE_ACCESSED
+#define PTABLE_CACHE_DISABLED   X86_64_PTABLE_CACHE_DISABLED
+#define PTABLE_WRITE_THROUGH    X86_64_PTABLE_WRITE_THROUGH
+#define PTABLE_USER_SUPERVISOR  X86_64_PTABLE_USER_SUPERVISOR
+#define PTABLE_READ_WRITE       X86_64_PTABLE_READ_WRITE
+#define PTABLE_PRESENT          X86_64_PTABLE_PRESENT
+
+#define PTABLE_SIZE             X86_64_PTABLE_SIZE
+#define PTABLE_MASK             X86_64_PTABLE_MASK
+#define PTABLE_CLEAR            X86_64_PTABLE_CLEAR
+
+#define PTABLE_ACCESS_DEFAULT   X86_64_PTABLE_ACCESS_DEFAULT
+#define PTABLE_ACCESS_READONLY  X86_64_PTABLE_ACCESS_READONLY
+
+#define PTABLE_ENTRY_SIZE       X86_64_PTABLE_ENTRY_SIZE
+
+#endif // ARCH_X86_64_BARRELFISH_KPI_PAGING_H
diff --git a/include/arch/k1om/barrelfish_kpi/registers_arch.h b/include/arch/k1om/barrelfish_kpi/registers_arch.h
new file mode 100644 (file)
index 0000000..85f8109
--- /dev/null
@@ -0,0 +1,58 @@
+/**
+ * \file
+ * \brief Arch independent accessor functions for use in generic code
+ * Generic include for kernel
+ */
+
+/*
+ * Copyright (c) 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef ARCH_X86_64_BARRELFISH_KPI_REGISTERS_H
+#define ARCH_X86_64_BARRELFISH_KPI_REGISTERS_H
+
+#include <barrelfish_kpi/types.h> // for lvaddr_t
+#include <target/x86_64/barrelfish_kpi/registers_target.h>
+
+///< Opaque handle for the register state
+typedef struct registers_x86_64 arch_registers_state_t;
+
+///< Opaque handle for the FPU register state
+typedef struct registers_fpu_x86_64 arch_registers_fpu_state_t;
+
+static inline void
+registers_set_entry(arch_registers_state_t *regs, lvaddr_t entry)
+{
+    registers_x86_64_set_entry(regs, entry);
+}
+
+static inline void
+registers_set_param(arch_registers_state_t *regs, uint64_t param)
+{
+    registers_x86_64_set_param(regs, param);
+}
+
+static inline void
+registers_get_param(arch_registers_state_t *regs, uint64_t *param)
+{
+    registers_x86_64_get_param(regs, param);
+}
+
+static inline uint64_t
+registers_get_ip(arch_registers_state_t *regs)
+{
+    return registers_x86_64_get_ip(regs);
+}
+
+static inline uint64_t
+registers_get_sp(arch_registers_state_t *regs)
+{
+    return registers_x86_64_get_sp(regs);
+}
+
+#endif // ARCH_X86_64_BARRELFISH_KPI_REGISTERS_H
diff --git a/include/arch/k1om/barrelfish_kpi/spinlocks_arch.h b/include/arch/k1om/barrelfish_kpi/spinlocks_arch.h
new file mode 100644 (file)
index 0000000..ce92742
--- /dev/null
@@ -0,0 +1,15 @@
+/**
+ * \file
+ * \brief
+ */
+
+/*
+ * Copyright (c) 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <arch/x86/barrelfish_kpi/spinlocks_arch.h>
diff --git a/include/arch/k1om/bench/bench_arch.h b/include/arch/k1om/bench/bench_arch.h
new file mode 100644 (file)
index 0000000..fc41255
--- /dev/null
@@ -0,0 +1,20 @@
+/**
+ * \file
+ * \brief Arch specific bench include.
+ */
+
+/*
+ * Copyright (c) 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef ARCH_X86_64_BARRELFISH_BENCH_H
+#define ARCH_X86_64_BARRELFISH_BENCH_H
+
+#include <arch/x86/bench/bench_arch.h>
+
+#endif
diff --git a/include/arch/k1om/concurrent/arch/cas.h b/include/arch/k1om/concurrent/arch/cas.h
new file mode 100644 (file)
index 0000000..5eabeef
--- /dev/null
@@ -0,0 +1,53 @@
+/** \file
+ *  \brief compare and set (cas) implementations
+ */
+
+/*
+ * Copyright (c) 2009, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef CAS_H_
+#define CAS_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/*
+ * \brief compare and set. If the value at address
+ *        equals old, set it to new otherwise don't write to address.
+ *        Returns the actual previous value at the address.
+ */
+static inline uintptr_t cas_ret_act(volatile uintptr_t *address, uintptr_t old,
+        uintptr_t new)
+{
+    register uintptr_t res;
+    __asm volatile("lock; cmpxchgq %2,%0    \n\t"
+                   : "+m" (*address), "=a" (res)
+                   : "r" (new), "a" (old)
+                   : "memory");
+    return res;
+}
+
+/*
+ * \brief compare and set. If the value at address
+ *        equals old, set it to new and return true,
+ *        otherwise don't write to address and return false
+ */
+static inline bool cas(volatile uintptr_t *address, uintptr_t old,
+        uintptr_t new)
+{
+    register bool res;
+    __asm volatile("lock; cmpxchgq %2,%0     \n\t"
+                   "setz %1                  \n\t"
+                   : "+m" (*address), "=q" (res)
+                   : "r" (new), "a" (old)
+                   : "memory");
+    return res;
+}
+
+#endif /* CAS_H_ */
diff --git a/include/arch/k1om/fenv.h b/include/arch/k1om/fenv.h
new file mode 100644 (file)
index 0000000..1d150db
--- /dev/null
@@ -0,0 +1,218 @@
+/*-
+ * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD: src/lib/msun/amd64/fenv.h,v 1.6 2007/01/06 21:46:23 das Exp $
+ */
+
+#ifndef        _FENV_H_
+#define        _FENV_H_
+
+#include <sys/cdefs.h>
+#include <sys/_types.h>
+
+typedef struct {
+       struct {
+               __uint32_t      __control;
+               __uint32_t      __status;
+               __uint32_t      __tag;
+               char            __other[16];
+       } __x87;
+       __uint32_t              __mxcsr;
+} fenv_t;
+
+typedef        __uint16_t      fexcept_t;
+
+/* Exception flags */
+#define        FE_INVALID      0x01
+#define        FE_DENORMAL     0x02
+#define        FE_DIVBYZERO    0x04
+#define        FE_OVERFLOW     0x08
+#define        FE_UNDERFLOW    0x10
+#define        FE_INEXACT      0x20
+#define        FE_ALL_EXCEPT   (FE_DIVBYZERO | FE_DENORMAL | FE_INEXACT | \
+                        FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
+
+/* Rounding modes */
+#define        FE_TONEAREST    0x0000
+#define        FE_DOWNWARD     0x0400
+#define        FE_UPWARD       0x0800
+#define        FE_TOWARDZERO   0x0c00
+#define        _ROUND_MASK     (FE_TONEAREST | FE_DOWNWARD | \
+                        FE_UPWARD | FE_TOWARDZERO)
+
+/*
+ * As compared to the x87 control word, the SSE unit's control word
+ * has the rounding control bits offset by 3 and the exception mask
+ * bits offset by 7.
+ */
+#define        _SSE_ROUND_SHIFT        3
+#define        _SSE_EMASK_SHIFT        7
+
+__BEGIN_DECLS
+
+/* Default floating-point environment */
+extern const fenv_t    __fe_dfl_env;
+#define        FE_DFL_ENV      (&__fe_dfl_env)
+
+#define        __fldcw(__cw)           __asm __volatile("fldcw %0" : : "m" (__cw))
+#define        __fldenv(__env)         __asm __volatile("fldenv %0" : : "m" (__env))
+#define        __fldenvx(__env)        __asm __volatile("fldenv %0" : : "m" (__env)  \
+                               : "st", "st(1)", "st(2)", "st(3)", "st(4)",   \
+                               "st(5)", "st(6)", "st(7)")
+#define        __fnclex()              __asm __volatile("fnclex")
+#define        __fnstenv(__env)        __asm __volatile("fnstenv %0" : "=m" (*(__env)))
+#define        __fnstcw(__cw)          __asm __volatile("fnstcw %0" : "=m" (*(__cw)))
+//according to
+//http://www.nabble.com/The-Linux-binutils-2.18.50.0.4-is-released-td15360254.html
+//we need to use %ax now...
+//#define      __fnstsw(__sw)          __asm __volatile("fnstsw %0" : "=am" (*(__sw)))
+#define __fnstsw(__sw)      __asm __volatile("fnstsw %%ax" : "=am" (*(__sw)))
+#define        __fwait()               __asm __volatile("fwait")
+#define        __ldmxcsr(__csr)        __asm __volatile("ldmxcsr %0" : : "m" (__csr))
+#define        __stmxcsr(__csr)        __asm __volatile("stmxcsr %0" : "=m" (*(__csr)))
+
+static __inline int
+feclearexcept(int __excepts)
+{
+       fenv_t __env;
+
+       if (__excepts == FE_ALL_EXCEPT) {
+               __fnclex();
+       } else {
+               __fnstenv(&__env.__x87);
+               __env.__x87.__status &= ~__excepts;
+               __fldenv(__env.__x87);
+       }
+       __stmxcsr(&__env.__mxcsr);
+       __env.__mxcsr &= ~__excepts;
+       __ldmxcsr(__env.__mxcsr);
+       return (0);
+}
+
+static __inline int
+fegetexceptflag(fexcept_t *__flagp, int __excepts)
+{
+       int __mxcsr, __status;
+
+       __stmxcsr(&__mxcsr);
+       __fnstsw(&__status);
+       *__flagp = (__mxcsr | __status) & __excepts;
+       return (0);
+}
+
+int fesetexceptflag(const fexcept_t *__flagp, int __excepts);
+int feraiseexcept(int __excepts);
+
+static __inline int
+fetestexcept(int __excepts)
+{
+       int __mxcsr, __status;
+
+       __stmxcsr(&__mxcsr);
+       __fnstsw(&__status);
+       return ((__status | __mxcsr) & __excepts);
+}
+
+static __inline int
+fegetround(void)
+{
+       int __control;
+
+       /*
+        * We assume that the x87 and the SSE unit agree on the
+        * rounding mode.  Reading the control word on the x87 turns
+        * out to be about 5 times faster than reading it on the SSE
+        * unit on an Opteron 244.
+        */
+       __fnstcw(&__control);
+       return (__control & _ROUND_MASK);
+}
+
+static __inline int
+fesetround(int __round)
+{
+       int __mxcsr, __control;
+
+       if (__round & ~_ROUND_MASK)
+               return (-1);
+
+       __fnstcw(&__control);
+       __control &= ~_ROUND_MASK;
+       __control |= __round;
+       __fldcw(__control);
+
+       __stmxcsr(&__mxcsr);
+       __mxcsr &= ~(_ROUND_MASK << _SSE_ROUND_SHIFT);
+       __mxcsr |= __round << _SSE_ROUND_SHIFT;
+       __ldmxcsr(__mxcsr);
+
+       return (0);
+}
+
+int fegetenv(fenv_t *__envp);
+int feholdexcept(fenv_t *__envp);
+
+static __inline int
+fesetenv(const fenv_t *__envp)
+{
+
+       /*
+        * XXX Using fldenvx() instead of fldenv() tells the compiler that this
+        * instruction clobbers the i387 register stack.  This happens because
+        * we restore the tag word from the saved environment.  Normally, this
+        * would happen anyway and we wouldn't care, because the ABI allows
+        * function calls to clobber the i387 regs.  However, fesetenv() is
+        * inlined, so we need to be more careful.
+        */
+       __fldenvx(__envp->__x87);
+       __ldmxcsr(__envp->__mxcsr);
+       return (0);
+}
+
+int feupdateenv(const fenv_t *__envp);
+
+#if __BSD_VISIBLE
+
+int feenableexcept(int __mask);
+int fedisableexcept(int __mask);
+
+static __inline int
+fegetexcept(void)
+{
+       int __control;
+
+       /*
+        * We assume that the masks for the x87 and the SSE unit are
+        * the same.
+        */
+       __fnstcw(&__control);
+       return (~__control & FE_ALL_EXCEPT);
+}
+
+#endif /* __BSD_VISIBLE */
+
+__END_DECLS
+
+#endif /* !_FENV_H_ */
diff --git a/include/arch/k1om/float.h b/include/arch/k1om/float.h
new file mode 100644 (file)
index 0000000..d700e29
--- /dev/null
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * 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.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ *     from: @(#)float.h       7.1 (Berkeley) 5/8/90
+ * $FreeBSD: src/sys/amd64/include/float.h,v 1.16 2008/01/17 13:12:46 bde Exp $
+ */
+
+#ifndef _MACHINE_FLOAT_H_
+#define _MACHINE_FLOAT_H_ 1
+
+#include <sys/cdefs.h>
+
+#ifdef CONFIG_OLDC
+__BEGIN_DECLS
+extern int __flt_rounds(void);
+__END_DECLS
+#define FLT_ROUNDS  __flt_rounds()
+#else
+#define FLT_ROUNDS  1
+#endif /* CONFIGOLDC */
+
+#define FLT_RADIX      2               /* b */
+#if __ISO_C_VISIBLE >= 1999
+#define        FLT_EVAL_METHOD 0               /* no promotions */
+#define        DECIMAL_DIG     21              /* max precision in decimal digits */
+#endif
+
+#define FLT_MANT_DIG   24              /* p */
+#define FLT_EPSILON    1.19209290E-07F /* b**(1-p) */
+#define FLT_DIG                6               /* floor((p-1)*log10(b))+(b == 10) */
+#define FLT_MIN_EXP    (-125)          /* emin */
+#define FLT_MIN                1.17549435E-38F /* b**(emin-1) */
+#define FLT_MIN_10_EXP (-37)           /* ceil(log10(b**(emin-1))) */
+#define FLT_MAX_EXP    128             /* emax */
+#define FLT_MAX                3.40282347E+38F /* (1-b**(-p))*b**emax */
+#define FLT_MAX_10_EXP 38              /* floor(log10((1-b**(-p))*b**emax)) */
+
+#define DBL_MANT_DIG   53
+#define DBL_EPSILON    2.2204460492503131E-16
+#define DBL_DIG                15
+#define DBL_MIN_EXP    (-1021)
+#define DBL_MIN                2.2250738585072014E-308
+#define DBL_MIN_10_EXP (-307)
+#define DBL_MAX_EXP    1024
+#define DBL_MAX                1.7976931348623157E+308
+#define DBL_MAX_10_EXP 308
+
+#define LDBL_MANT_DIG  64
+#define LDBL_EPSILON   1.0842021724855044340E-19L
+#define LDBL_DIG       18
+#define LDBL_MIN_EXP   (-16381)
+#define LDBL_MIN       3.3621031431120935063E-4932L
+#define LDBL_MIN_10_EXP        (-4931)
+#define LDBL_MAX_EXP   16384
+#define LDBL_MAX       1.1897314953572317650E+4932L
+#define LDBL_MAX_10_EXP        4932
+#endif /* _MACHINE_FLOAT_H_ */
diff --git a/include/arch/k1om/machine/_limits.h b/include/arch/k1om/machine/_limits.h
new file mode 100644 (file)
index 0000000..afbf51c
--- /dev/null
@@ -0,0 +1,92 @@
+/*-
+ * Copyright (c) 1988, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * 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.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ *     @(#)limits.h    8.3 (Berkeley) 1/4/94
+ * $FreeBSD: src/sys/amd64/include/_limits.h,v 1.11 2005/08/20 16:44:40 stefanf Exp $
+ */
+
+#ifndef        _MACHINE__LIMITS_H_
+#define        _MACHINE__LIMITS_H_
+
+/*
+ * According to ANSI (section 2.2.4.2), the values below must be usable by
+ * #if preprocessing directives.  Additionally, the expression must have the
+ * same type as would an expression that is an object of the corresponding
+ * type converted according to the integral promotions.  The subtraction for
+ * INT_MIN, etc., is so the value is not unsigned; e.g., 0x80000000 is an
+ * unsigned int for 32-bit two's complement ANSI compilers (section 3.1.3.2).
+ * These numbers are for the default configuration of gcc.  They work for
+ * some other compilers as well, but this should not be depended on.
+ */
+
+#define        __CHAR_BIT      8               /* number of bits in a char */
+
+#define        __SCHAR_MAX     0x7f            /* max value for a signed char */
+#define        __SCHAR_MIN     (-0x7f - 1)     /* min value for a signed char */
+
+#define        __UCHAR_MAX     0xffU           /* max value for an unsigned char */
+
+#define        __USHRT_MAX     0xffffU         /* max value for an unsigned short */
+#define        __SHRT_MAX      0x7fff          /* max value for a short */
+#define        __SHRT_MIN      (-0x7fff - 1)   /* min value for a short */
+
+#define        __UINT_MAX      0xffffffffU     /* max value for an unsigned int */
+#define        __INT_MAX       0x7fffffff      /* max value for an int */
+#define        __INT_MIN       (-0x7fffffff - 1)       /* min value for an int */
+
+#define        __ULONG_MAX     0xffffffffffffffffUL    /* max for an unsigned long */
+#define        __LONG_MAX      0x7fffffffffffffffL     /* max for a long */
+#define        __LONG_MIN      (-0x7fffffffffffffffL - 1) /* min for a long */
+
+                       /* max value for an unsigned long long */
+#define        __ULLONG_MAX    0xffffffffffffffffULL
+#define        __LLONG_MAX     0x7fffffffffffffffLL    /* max value for a long long */
+#define        __LLONG_MIN     (-0x7fffffffffffffffLL - 1)  /* min for a long long */
+
+#define        __SSIZE_MAX     __LONG_MAX      /* max value for a ssize_t */
+
+#define        __SIZE_T_MAX    __ULONG_MAX     /* max value for a size_t */
+
+#define        __OFF_MAX       __LONG_MAX      /* max value for an off_t */
+#define        __OFF_MIN       __LONG_MIN      /* min value for an off_t */
+
+/* Quads and longs are the same on the amd64.  Ensure they stay in sync. */
+#define        __UQUAD_MAX     __ULONG_MAX     /* max value for a uquad_t */
+#define        __QUAD_MAX      __LONG_MAX      /* max value for a quad_t */
+#define        __QUAD_MIN      __LONG_MIN      /* min value for a quad_t */
+
+#define        __LONG_BIT      64
+#define        __WORD_BIT      32
+
+/*
+ * Minimum signal stack size. The current signal frame
+ * for i386 is 408 bytes large.
+ */
+#define        __MINSIGSTKSZ   (512 * 4)
+
+#endif /* !_MACHINE__LIMITS_H_ */
diff --git a/include/arch/k1om/machine/asm.h b/include/arch/k1om/machine/asm.h
new file mode 100644 (file)
index 0000000..7efd642
--- /dev/null
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * 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.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ *     from: @(#)DEFS.h        5.1 (Berkeley) 4/23/90
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_ASM_H_
+#define        _MACHINE_ASM_H_
+
+#include <sys/cdefs.h>
+
+#ifdef PIC
+#define        PIC_PLT(x)      x@PLT
+#define        PIC_GOT(x)      x@GOTPCREL(%rip)
+#else
+#define        PIC_PLT(x)      x
+#define        PIC_GOT(x)      x
+#endif
+
+/*
+ * CNAME and HIDENAME manage the relationship between symbol names in C
+ * and the equivalent assembly language names.  CNAME is given a name as
+ * it would be used in a C program.  It expands to the equivalent assembly
+ * language name.  HIDENAME is given an assembly-language name, and expands
+ * to a possibly-modified form that will be invisible to C programs.
+ */
+#define CNAME(csym)            csym
+#define HIDENAME(asmsym)       .asmsym
+
+#define _START_ENTRY   .text; .p2align 4,0x90
+
+#define _ENTRY(x)      _START_ENTRY; \
+                       .globl CNAME(x); .type CNAME(x),@function; CNAME(x):
+
+#ifdef PROF
+#define        ALTENTRY(x)     _ENTRY(x); \
+                       pushq %rbp; movq %rsp,%rbp; \
+                       call PIC_PLT(HIDENAME(mcount)); \
+                       popq %rbp; \
+                       jmp 9f
+#define        ENTRY(x)        _ENTRY(x); \
+                       pushq %rbp; movq %rsp,%rbp; \
+                       call PIC_PLT(HIDENAME(mcount)); \
+                       popq %rbp; \
+                       9:
+#else
+#define        ALTENTRY(x)     _ENTRY(x)
+#define        ENTRY(x)        _ENTRY(x)
+#endif
+
+#define        END(x)          .size x, . - x
+
+#define RCSID(x)       .text; .asciz x
+
+#undef __FBSDID
+#if !defined(lint) && !defined(STRIP_FBSDID)
+#define __FBSDID(s)    .ident s
+#else
+#define __FBSDID(s)    /* nothing */
+#endif /* not lint and not STRIP_FBSDID */
+
+#endif /* !_MACHINE_ASM_H_ */
diff --git a/include/arch/k1om/machine/endian.h b/include/arch/k1om/machine/endian.h
new file mode 100644 (file)
index 0000000..5455cbe
--- /dev/null
@@ -0,0 +1,199 @@
+/*-
+ * Copyright (c) 1987, 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * 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.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ *     @(#)endian.h    7.8 (Berkeley) 4/3/91
+ * $FreeBSD: src/sys/amd64/include/endian.h,v 1.8 2005/03/11 21:46:01 peter Exp $
+ */
+
+#ifndef _MACHINE_ENDIAN_H_
+#define        _MACHINE_ENDIAN_H_
+
+#include <sys/cdefs.h>
+#include <sys/_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Define the order of 32-bit words in 64-bit words.
+ */
+#define        _QUAD_HIGHWORD 1
+#define        _QUAD_LOWWORD 0
+
+/*
+ * Definitions for byte order, according to byte significance from low
+ * address to high.
+ */
+#define        _LITTLE_ENDIAN  1234    /* LSB first: i386, vax */
+#define        _BIG_ENDIAN     4321    /* MSB first: 68000, ibm, net */
+#define        _PDP_ENDIAN     3412    /* LSB first in word, MSW first in long */
+
+#define        _BYTE_ORDER     _LITTLE_ENDIAN
+
+/*
+ * Deprecated variants that don't have enough underscores to be useful in more
+ * strict namespaces.
+ */
+#if __BSD_VISIBLE
+#define        LITTLE_ENDIAN   _LITTLE_ENDIAN
+#define        BIG_ENDIAN      _BIG_ENDIAN
+#define        PDP_ENDIAN      _PDP_ENDIAN
+#define        BYTE_ORDER      _BYTE_ORDER
+#endif
+
+#if defined(__GNUCLIKE_ASM) && defined(__GNUCLIKE_BUILTIN_CONSTANT_P)
+
+#define __word_swap_int_var(x) \
+__extension__ ({ register __uint32_t __X = (x); \
+   __asm ("rorl $16, %0" : "+r" (__X)); \
+   __X; })
+
+#ifdef __OPTIMIZE__
+
+#define        __word_swap_int_const(x) \
+       ((((x) & 0xffff0000) >> 16) | \
+        (((x) & 0x0000ffff) << 16))
+#define        __word_swap_int(x) (__builtin_constant_p(x) ? \
+       __word_swap_int_const(x) : __word_swap_int_var(x))
+
+#else  /* __OPTIMIZE__ */
+
+#define        __word_swap_int(x) __word_swap_int_var(x)
+
+#endif /* __OPTIMIZE__ */
+
+#define __byte_swap_int_var(x) \
+__extension__ ({ register __uint32_t __X = (x); \
+   __asm ("bswap %0" : "+r" (__X)); \
+   __X; })
+
+#ifdef __OPTIMIZE__
+
+#define        __byte_swap_int_const(x) \
+       ((((x) & 0xff000000) >> 24) | \
+        (((x) & 0x00ff0000) >>  8) | \
+        (((x) & 0x0000ff00) <<  8) | \
+        (((x) & 0x000000ff) << 24))
+#define        __byte_swap_int(x) (__builtin_constant_p(x) ? \
+       __byte_swap_int_const(x) : __byte_swap_int_var(x))
+
+#else  /* __OPTIMIZE__ */
+
+#define        __byte_swap_int(x) __byte_swap_int_var(x)
+
+#endif /* __OPTIMIZE__ */
+
+#define __byte_swap_long_var(x) \
+__extension__ ({ register __uint64_t __X = (x); \
+   __asm ("bswap %0" : "+r" (__X)); \
+   __X; })
+
+#ifdef __OPTIMIZE__
+
+#define        __byte_swap_long_const(x) \
+       (((x >> 56) | \
+        ((x >> 40) & 0xff00) | \
+        ((x >> 24) & 0xff0000) | \
+        ((x >> 8) & 0xff000000) | \
+        ((x << 8) & (0xfful << 32)) | \
+        ((x << 24) & (0xfful << 40)) | \
+        ((x << 40) & (0xfful << 48)) | \
+        ((x << 56))))
+
+#define        __byte_swap_long(x) (__builtin_constant_p(x) ? \
+       __byte_swap_long_const(x) : __byte_swap_long_var(x))
+
+#else  /* __OPTIMIZE__ */
+
+#define        __byte_swap_long(x) __byte_swap_long_var(x)
+
+#endif /* __OPTIMIZE__ */
+
+#define __byte_swap_word_var(x) \
+__extension__ ({ register __uint16_t __X = (x); \
+   __asm ("xchgb %h0, %b0" : "+Q" (__X)); \
+   __X; })
+
+#ifdef __OPTIMIZE__
+
+#define        __byte_swap_word_const(x) \
+       ((((x) & 0xff00) >> 8) | \
+        (((x) & 0x00ff) << 8))
+
+#define        __byte_swap_word(x) (__builtin_constant_p(x) ? \
+       __byte_swap_word_const(x) : __byte_swap_word_var(x))
+
+#else  /* __OPTIMIZE__ */
+
+#define        __byte_swap_word(x) __byte_swap_word_var(x)
+
+#endif /* __OPTIMIZE__ */
+
+static __inline __uint64_t
+__bswap64(__uint64_t _x)
+{
+
+       return (__byte_swap_long(_x));
+}
+
+static __inline __uint32_t
+__bswap32(__uint32_t _x)
+{
+
+       return (__byte_swap_int(_x));
+}
+
+static __inline __uint16_t
+__bswap16(__uint16_t _x)
+{
+
+       return (__byte_swap_word(_x));
+}
+
+#define        __htonl(x)      __bswap32(x)
+#define        __htons(x)      __bswap16(x)
+#define        __ntohl(x)      __bswap32(x)
+#define        __ntohs(x)      __bswap16(x)
+
+#else /* !(__GNUCLIKE_ASM && __GNUCLIKE_BUILTIN_CONSTANT_P) */
+
+/*
+ * No optimizations are available for this compiler.  Fall back to
+ * non-optimized functions by defining the constant usually used to prevent
+ * redefinition.
+ */
+#define        _BYTEORDER_FUNC_DEFINED
+
+#endif /* __GNUCLIKE_ASM && __GNUCLIKE_BUILTIN_CONSTANT_P */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_MACHINE_ENDIAN_H_ */
diff --git a/include/arch/k1om/machine/fpu.h b/include/arch/k1om/machine/fpu.h
new file mode 100644 (file)
index 0000000..04b205b
--- /dev/null
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * 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.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ *     from: @(#)npx.h 5.3 (Berkeley) 1/18/91
+ * $FreeBSD: src/sys/amd64/include/fpu.h,v 1.33 2004/04/05 21:25:51 imp Exp $
+ */
+
+/*
+ * Floating Point Data Structures and Constants
+ * W. Jolitz 1/90
+ */
+
+#ifndef _MACHINE_FPU_H_
+#define        _MACHINE_FPU_H_
+
+/* Contents of each x87 floating point accumulator */
+struct fpacc87 {
+       u_char  fp_bytes[10];
+};
+
+/* Contents of each SSE extended accumulator */
+struct  xmmacc {
+       u_char  xmm_bytes[16];
+};
+
+struct  envxmm {
+       u_int16_t       en_cw;          /* control word (16bits) */
+       u_int16_t       en_sw;          /* status word (16bits) */
+       u_int8_t        en_tw;          /* tag word (8bits) */
+       u_int8_t        en_zero;
+       u_int16_t       en_opcode;      /* opcode last executed (11 bits ) */
+       u_int64_t       en_rip;         /* floating point instruction pointer */
+       u_int64_t       en_rdp;         /* floating operand pointer */
+       u_int32_t       en_mxcsr;       /* SSE sontorol/status register */
+       u_int32_t       en_mxcsr_mask;  /* valid bits in mxcsr */
+};
+
+struct  savefpu {
+       struct  envxmm  sv_env;
+       struct {
+               struct fpacc87  fp_acc;
+               u_char          fp_pad[6];      /* padding */
+       } sv_fp[8];
+       struct xmmacc   sv_xmm[16];
+       u_char sv_pad[96];
+} __aligned(16);
+
+/*
+ * The hardware default control word for i387's and later coprocessors is
+ * 0x37F, giving:
+ *
+ *     round to nearest
+ *     64-bit precision
+ *     all exceptions masked.
+ *
+ * FreeBSD/i386 uses 53 bit precision for things like fadd/fsub/fsqrt etc
+ * because of the difference between memory and fpu register stack arguments.
+ * If its using an intermediate fpu register, it has 80/64 bits to work
+ * with.  If it uses memory, it has 64/53 bits to work with.  However,
+ * gcc is aware of this and goes to a fair bit of trouble to make the
+ * best use of it.
+ *
+ * This is mostly academic for AMD64, because the ABI prefers the use
+ * SSE2 based math.  For FreeBSD/amd64, we go with the default settings.
+ */
+#define        __INITIAL_FPUCW__       0x037F
+#define        __INITIAL_MXCSR__       0x1F80
+#define        __INITIAL_MXCSR_MASK__  0xFFBF
+
+#ifdef _KERNEL
+int    fpudna(void);
+void   fpudrop(void);
+void   fpuexit(struct thread *td);
+int    fpuformat(void);
+int    fpugetregs(struct thread *td, struct savefpu *addr);
+void   fpuinit(void);
+void   fpusetregs(struct thread *td, struct savefpu *addr);
+int    fputrap(void);
+#endif
+
+#endif /* !_MACHINE_FPU_H_ */
diff --git a/include/arch/k1om/machine/types.h b/include/arch/k1om/machine/types.h
new file mode 100644 (file)
index 0000000..5072a88
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef        _MACHTYPES_H_
+#define        _MACHTYPES_H_
+
+/*
+ *  The following section is RTEMS specific and is needed to more
+ *  closely match the types defined in the BSD machine/types.h.
+ *  This is needed to let the RTEMS/BSD TCP/IP stack compile.
+ */
+#if defined(__rtems__)
+#include <machine/_types.h>
+#endif
+
+#define        _CLOCK_T_       __clock_t               /* clock() */
+#define        _TIME_T_        long                    /* time() */
+#define _CLOCKID_T_    unsigned long
+#define _TIMER_T_      unsigned long
+
+#ifndef _HAVE_SYSTYPES
+typedef long int __off_t;
+typedef int __pid_t;
+#ifdef __GNUC__
+__extension__ typedef long long int __loff_t;
+#else
+typedef long int __loff_t;
+#endif
+#endif
+
+#endif /* _MACHTYPES_H_ */
+
+
diff --git a/kernel/arch/k1om/boot.S b/kernel/arch/k1om/boot.S
new file mode 100644 (file)
index 0000000..2c004b1
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+ * \file
+ * \brief Bootstrap the kernel.
+ */
+
+/*
+ * Copyright (c) 2007, 2008, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <multiboot.h>
+#include <target/x86_64/offsets_target.h>
+
+/* The flags for the Multiboot header */
+#define MB_FLAGS (MULTIBOOT_HEADER_FLAG_MODS_PGALIGNED | MULTIBOOT_HEADER_FLAG_NEED_MEMINFO)
+
+       .text
+       .globl  start, halt
+       /* Multiboot header, 4-byte aligned */
+       .align  4
+       .long   MULTIBOOT_HEADER_MAGIC               /* magic */
+       .long   MB_FLAGS                             /* flags */
+       .long   -(MULTIBOOT_HEADER_MAGIC + MB_FLAGS) /* checksum */
+
+start:
+       /* Initialize the stack pointer */
+       lea     (x86_64_kernel_stack + X86_64_KERNEL_STACK_SIZE)(%rip), %rsp
+
+       /* Reset EFLAGS */
+       pushq   $0
+       popf
+
+       /* Enter architecture-specific init -- this should never return */
+       movl    %eax, %edi      /* Multiboot magic value */
+       movl    %ebx, %esi      /* Pointer to multiboot info struct */
+       call    arch_init
+
+       /* Halt -- this should never be reached */
+halt:  hlt
+       jmp     halt
diff --git a/kernel/arch/k1om/debug.c b/kernel/arch/k1om/debug.c
new file mode 100644 (file)
index 0000000..d51787a
--- /dev/null
@@ -0,0 +1,88 @@
+/**
+ * \file
+ * \brief Kernel debugging functions
+ */
+
+/*
+ * Copyright (c) 2008, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <kernel.h>
+#include <stdio.h>
+#include <arch/x86/debug.h>
+#include <paging_kernel_arch.h>
+
+union lin_addr {
+    uint64_t raw;
+    struct {
+        uint64_t  offset       :12;
+        uint64_t  ptable       :9;
+        uint64_t  pdir         :9;
+        uint64_t  pdpt         :9;
+        uint64_t  pml4         :9;
+        uint64_t  sign_extend  :16;
+    } d;
+};
+
+void debug_vaddr_identify(lvaddr_t debug_pml4, lvaddr_t vaddr)
+{
+    int i;
+    printf("cr3 register      %lx\n", debug_pml4);
+    printf("identifying vaddr %lx\n", vaddr);
+
+    volatile uint64_t *temp = (uint64_t*)vaddr;
+
+    for(i = 0; i < 512; i++) {
+        printf("at addr %lx content is %lx\n", (uint64_t)(temp + i), *(temp + i));
+    }
+    printf("\n");
+
+    union lin_addr lin_addr;
+    lin_addr.raw = (uint64_t)vaddr;
+
+    printf("vaddr broken down\n");
+    printf("sign_extend = %x\n", lin_addr.d.sign_extend);
+    printf("pml4        = %x\n", lin_addr.d.pml4);
+    printf("pdpt        = %x\n", lin_addr.d.pdpt);
+    printf("pdir        = %x\n", lin_addr.d.pdir);
+    printf("ptable      = %x\n", lin_addr.d.ptable);
+    printf("offset      = %x\n", lin_addr.d.offset);
+
+    uint64_t *pml4et;
+    pml4et = (uint64_t*)(debug_pml4 +
+                         (lin_addr.d.pml4 * sizeof(union x86_64_pdir_entry)));
+    printf("addr = %lx ", (uint64_t)pml4et);
+    printf("content = %lx\n", *pml4et);
+
+    lvaddr_t pdpt_addr;
+    pdpt_addr = local_phys_to_mem(((union x86_64_pdir_entry*)pml4et)->d.base_addr << 12);
+    uint64_t *pdptet;
+    pdptet = (uint64_t*)(pdpt_addr +
+                         (lin_addr.d.pdpt * sizeof(union x86_64_pdir_entry)));
+    printf("addr = %lx ", (uint64_t)pdptet);
+    printf("content = %lx\n", *pdptet);
+
+    lvaddr_t pdir_addr;
+    pdir_addr = local_phys_to_mem(((union x86_64_pdir_entry*)pdptet)->d.base_addr << 12);
+    uint64_t *pdiret;
+    pdiret = (uint64_t*)(pdir_addr +
+                         (lin_addr.d.pdir * sizeof(union x86_64_pdir_entry)));
+    printf("addr = %lx ", (uint64_t)pdiret);
+    printf("content = %lx\n", *pdiret);
+
+    lvaddr_t ptable_addr;
+    ptable_addr = local_phys_to_mem(((union x86_64_pdir_entry*)pdiret)->d.base_addr << 12);
+    uint64_t *ptableet;
+    ptableet = (uint64_t*)(ptable_addr +
+                         (lin_addr.d.ptable * sizeof(union x86_64_pdir_entry)));
+    printf("addr = %lx ", (uint64_t)ptableet);
+    printf("content = %lx\n", *ptableet);
+
+    lpaddr_t addr = ((union x86_64_ptable_entry*)ptableet)->base.base_addr << 12;
+    printf("addr = %lx\n", addr);
+}
diff --git a/kernel/arch/k1om/entry.S b/kernel/arch/k1om/entry.S
new file mode 100644 (file)
index 0000000..959be91
--- /dev/null
@@ -0,0 +1,392 @@
+/**
+ * \file
+ * \brief System call entry point to the kernel and LRPC fast-path
+ */
+
+/*
+ * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish_kpi/syscalls.h>
+#include <barrelfish_kpi/capabilities.h>
+#include <barrelfish_kpi/lmp.h>
+#include <target/x86_64/offsets_target.h>
+#include <x86.h>
+#include <asmoffsets.h>
+
+    .text
+    .globl syscall_entry
+
+syscall_entry:
+        /* is this an LRPC or a normal syscall? */
+        cmp $SYSCALL_LRPC, %rdi
+        jne  syscall_path   /* normal syscall, branch off */
+
+       /* Load pointer to current DCB */
+       mov     dcb_current(%rip), %rdi
+
+       /* TODO: Check that caller is not disabled */
+
+        /* dcb_current->disabled=false */
+        movb $0, OFFSETOF_DCB_DISABLED(%rdi)
+
+        /* Save caller's registers */
+       mov     OFFSETOF_DCB_DISP(%rdi), %rdi
+       lea     OFFSETOF_DISP_X86_64_ENABLED_AREA(%rdi), %rdi
+       movq    $SYS_ERR_OK, OFFSETOF_RAX_REG(%rdi)
+       mov     %rcx, OFFSETOF_RIP_REG(%rdi)
+       mov     %r11, OFFSETOF_EFLAGS_REG(%rdi)
+       mov     %rsp, OFFSETOF_RSP_REG(%rdi)
+       mov     %fs, OFFSETOF_FS_REG(%rdi)
+       mov     %gs, OFFSETOF_GS_REG(%rdi)
+
+       /* Load pointer to root CNode cap */
+       mov     dcb_current(%rip), %rdi
+       lea     OFFSETOF_DCB_CSPACE_CAP(%rdi), %rdi
+
+       /* Check that slot number is within CNode */
+        movb OFFSETOF_CAP_CNODE_BITS(%rdi), %cl
+        mov $1, %r15
+        shl %cl, %r15
+       cmp     %r15, %rsi
+       jae     err_slot
+
+       /* Load pointer to endpoint cap */
+       shl     $OBJBITS_CTE, %rsi
+       mov     OFFSETOF_CAP_CNODE_CNODE(%rdi), %rcx
+       mov     $0xffffff8000000000, %rdi       // phys_to_mem()
+       add     %rdi, %rcx
+       add     %rsi, %rcx
+
+       /* Check that it's an endpoint */
+       cmpl    $OBJTYPE_ENDPOINT, OFFSETOF_CAP_TYPE(%rcx)
+       jne     err_endpoint
+
+       /* TODO: Check rights on the endpoint */
+
+       /* Set epoffset for receiver, load epbuflen */
+       mov     OFFSETOF_CAP_ENDPOINT_EPOFFSET(%rcx), %rdi
+        mov     OFFSETOF_CAP_ENDPOINT_EPBUFLEN(%rcx), %r13d /* r13d = epbuflen */
+
+       /* Load pointer to listener's DCB */
+       mov     OFFSETOF_CAP_ENDPOINT_LISTENER(%rcx), %rsi
+
+       /* Check whether listener is runnable */
+#if defined(CONFIG_SCHEDULER_RR)
+       cmpl    $0, OFFSETOF_DCB_RR_PREV(%rsi)
+       je      lrpc_make_runnable
+#elif defined(CONFIG_SCHEDULER_RBED)
+       cmpl    $0, OFFSETOF_DCB_RBED_NEXT(%rsi)
+       je      lrpc_rbed_check_runnable
+#else
+# error Must define a kernel scheduling policy!
+#endif
+
+lrpc_check_runnable_continue:
+       /* Check whether listener is disabled */
+       cmpb    $0, OFFSETOF_DCB_DISABLED(%rsi)
+       jne     err_disabled
+
+        /* RCX = target dispatcher */
+        mov OFFSETOF_DCB_DISP(%rsi), %rcx
+
+        /* Remember LRPC entry point on target (R15) */
+        mov OFFSETOF_DISP_LRPC(%rcx), %r15
+
+        /* check that the receiver has space in their buffer */
+        add %rdi, %rcx /* add epoffset to dispatcher: rcx = endpoint pointer */
+        mov OFFSETOF_LMP_ENDPOINT_DELIVERED(%rcx), %r11d /* r11d = delivered */
+        mov %r11d, %r12d /* r12d = delivered */
+        mov OFFSETOF_LMP_ENDPOINT_CONSUMED(%rcx), %r14d /* r14d = consumed */
+
+        /*
+         *  newpos = delivered + len;
+         *  if (newpos >= consumed && consumed > delivered)
+         *    goto err_buflen;
+         *  if (newpos >= epbuflen) {
+         *    newpos -= epbuflen;
+         *    if (newpos >= consumed)
+         *      goto err_buflen;
+         *  }
+         *  delivered = newpos
+         */
+
+        add $(LRPC_MSG_LENGTH + LMP_RECV_HEADER_LENGTH), %r11d /* r11d (newpos) = delivered + len */
+
+        cmp %r14d, %r11d
+        jb 1f /* if newpos < consumed */
+        cmp %r12d, %r14d
+        ja err_buflen /* if consumed > delivered */
+
+1:
+        cmp %r13d, %r11d
+        jb 2f /* if newpos < epbuflen */
+
+        /* newpos >= epbuflen */
+        sub %r13d, %r11d /* newpos (r11d) -= epbuflen (r13d) */
+        cmp %r14d, %r11d /* if newpos >= consumed */
+        jae err_buflen
+
+2:      /* there's enough space, reserve it by updating delivered = newpos */
+        mov %r11d, OFFSETOF_LMP_ENDPOINT_DELIVERED(%rcx)
+
+       /* Set current domain to receiver */
+       mov     %rsi, dcb_current(%rip)
+
+       /* Switch to listener address space */
+       mov     OFFSETOF_DCB_VSPACE(%rsi), %rax
+       mov     %rax, %cr3
+
+        /* Zero registers to avoid the receiver getting hold of them
+         * FIXME: should zero all non-payload registers */
+        xor     %eax, %eax
+        mov     %eax, %fs
+        mov     %eax, %gs
+        
+       /* Get new dispatcher pointer */
+       mov     OFFSETOF_DCB_DISP(%rsi), %rax
+       /* Disable target dispatcher -- gotta do it here for TLB hit reasons */
+       movl    $1, OFFSETOF_DISP_DISABLED(%rax)
+        /* update dispatcher's global delivered count */
+        addl    $(LRPC_MSG_LENGTH + LMP_RECV_HEADER_LENGTH), OFFSETOF_DISP_LMP_DELIVERED(%rax)
+        /* update systime field in dispatcher from kernel_now variable */
+        movq    kernel_now(%rip), %r11
+        movq    %r11, OFFSETOF_DISP_SYSTIME(%rax)
+
+        /* Check if it's necessary to load a new LDT */
+       mov     OFFSETOF_DISP_X86_64_LDT_BASE(%rax), %r11
+        mov     OFFSETOF_DISP_X86_64_LDT_NPAGES(%rax), %r14
+        cmp     current_ldt_base(%rip), %r11
+        jne load_ldt
+
+        cmp     current_ldt_npages(%rip), %r14
+        jne load_ldt
+
+load_ldt_continue:
+       /* Enter at LRPC entry point */
+        mov     %r12d, %esi            /* bufpos of reserved space in EP buffer */
+       mov     %r15, %rcx             /* saved LRPC EP */
+        movq    OFFSETOF_DISP_UDISP(%rax), %rax /* user-level dispatcher pointer */
+       mov     $USER_RFLAGS, %r11  /* eflags */
+       sysretq
+
+load_ldt: /* Load a new LDT: r11 = base, r14 = npages, rcx = temp for descriptor */
+
+        /* If either base or npages is zero, load an invalid LDT */
+        cmpq    $0, %r11
+        je load_ldt_invalid
+        cmpq    $0, %r14
+        je load_ldt_invalid
+        
+        /* Update segment descriptor for LDT */
+
+        movq    %r11, current_ldt_base(%rip)
+        movq    %r14, current_ldt_npages(%rip)
+
+        /* Format of high word of descriptor is:
+         * 32 bits of zero/reserved
+         * Base bits 63-32 */
+        mov %r11, %rcx
+        shr $32, %rcx
+        shl $32, %rcx
+
+        // Store new descriptor (high half) to GDT
+        mov %rcx, (gdt + 8*LDT_HI_SEL)(%rip)
+
+        /* Format of low word of descriptor is:
+         * Base bits 31-24 (top 8 bits of 32-bit addr)
+         * 16 bits of flags/miscellany: 0x80e2
+         *   granularity = 1
+         *   operation_size = irrelevant
+         *   long_mode = irrelevant
+         *   available = irrelevant
+         *   4 high bits of limit address = 0 (assuming LDT is < 2**16 * 4k)
+         *   present = 1
+         *   privilege_level (2 bits wide) = 3 (user privilege)
+         *   system descriptor = 0
+         *   type (4 bits wide) = 2
+         * low 24 bits of base addr
+         * low 16 bits of limit
+         */
+
+        // bits 24:31 of base
+        mov %r11, %rcx
+        shr $24, %rcx
+
+        // flags/misc
+        shl $16, %rcx
+        or  $0x80e2, %rcx
+
+        // low 24 bits of base
+        shl $24, %rcx
+        shl $40, %r11
+        shr $40, %r11
+        or  %r11, %rcx
+
+        // low 16 bits of limit
+        shl $16, %rcx
+        shl $48, %r14
+        shr $48, %r14
+        or  %r14, %rcx
+
+        // Store new descriptor (low half) to GDT
+        mov %rcx, (gdt + 8*LDT_LO_SEL)(%rip)
+        
+        // Construct segment selector and load it
+        mov     $LDT_SELECTOR, %cx        
+        lldt    %cx
+       jmp     load_ldt_continue
+
+load_ldt_invalid:  /* Load an invalid LDT */
+        mov     $0, %cx
+        lldt    %cx
+        movq    $0, current_ldt_base(%rip)
+        movq    $0, current_ldt_npages(%rip)
+        jmp     load_ldt_continue
+
+err_slot:      // Wrong slot
+       mov     $SYS_ERR_LRPC_SLOT_INVALID, %rax
+       jmp     err
+
+err_endpoint:  // Not an endpoint
+       mov     $SYS_ERR_LRPC_NOT_ENDPOINT, %rax
+       /* jmp  err  - fall through */
+
+    /* An error occured */
+err:
+    /* Restore user's state */
+    mov dcb_current(%rip), %rdi
+    mov OFFSETOF_DCB_DISP(%rdi), %rdi
+    lea OFFSETOF_DISP_X86_64_ENABLED_AREA(%rdi), %rdi
+    mov OFFSETOF_RIP_REG(%rdi), %rcx
+    mov OFFSETOF_EFLAGS_REG(%rdi), %r11
+    mov OFFSETOF_RSP_REG(%rdi), %rsp
+    sysretq
+
+err_disabled:  // Target disabled
+    /* Return error to caller in their enabled save area */
+    mov dcb_current(%rip), %rdi
+    mov OFFSETOF_DCB_DISP(%rdi), %rdi
+    lea OFFSETOF_DISP_X86_64_ENABLED_AREA(%rdi), %rdi
+    movq $SYS_ERR_LMP_TARGET_DISABLED, OFFSETOF_RAX_REG(%rdi)
+
+    /* Yield to target (call dispatch(target) in C) */
+    mov %rsi, %rdi /* rdi = target DCB */
+    lea (x86_64_kernel_stack + X86_64_KERNEL_STACK_SIZE)(%rip), %rsp
+    jmp dispatch /* no return */
+
+err_buflen:     /* Target's endpoint buffer is full */
+    /* Return error to caller in their enabled save area */
+    mov dcb_current(%rip), %rdi
+    mov OFFSETOF_DCB_DISP(%rdi), %rdi
+    lea OFFSETOF_DISP_X86_64_ENABLED_AREA(%rdi), %rdi
+    movq $SYS_ERR_LMP_BUF_OVERFLOW, OFFSETOF_RAX_REG(%rdi)
+
+    /* Yield to target (call dispatch(target) in C) */
+    mov %rsi, %rdi /* rdi = target DCB */
+    lea (x86_64_kernel_stack + X86_64_KERNEL_STACK_SIZE)(%rip), %rsp
+    jmp dispatch /* no return */
+
+#ifdef CONFIG_SCHEDULER_RBED
+lrpc_rbed_check_runnable:
+       cmp     queue_tail(%rip), %rsi
+       jne     lrpc_make_runnable
+       jmp     lrpc_check_runnable_continue
+#endif
+
+lrpc_make_runnable:
+       /* Save user stack */
+       movq    %rsp, user_stack_save(%rip)
+
+       /* Get kernel stack */
+       lea     (x86_64_kernel_stack + X86_64_KERNEL_STACK_SIZE)(%rip), %rsp
+
+       // Save complete register state
+       pushq   %rdx
+       pushq   %rcx
+       pushq   %rbx
+       pushq   %rax
+       pushq   %r15
+       pushq   %r14
+       pushq   %r13
+       pushq   %r12
+       pushq   %r11
+       pushq   %r10
+       pushq   %r9
+       pushq   %r8
+       pushq   %rbp
+       pushq   %rdi
+       pushq   %rsi
+
+       // Call make runnable in C
+       movq    %rsi, %rdi
+       callq   make_runnable
+
+       // Restore complete register state
+       popq    %rsi
+       popq    %rdi
+       popq    %rbp
+       popq    %r8
+       popq    %r9
+       popq    %r10
+       popq    %r11
+       popq    %r12
+       popq    %r13
+       popq    %r14
+       popq    %r15
+       popq    %rax
+       popq    %rbx
+       popq    %rcx
+       popq    %rdx
+
+       /* Restore user stack */
+       movq    user_stack_save(%rip), %rsp
+
+       // Jump back
+       jmp     lrpc_check_runnable_continue
+
+
+/* regular syscall path */
+syscall_path:
+        /* Save user stack */
+        movq    %rsp, user_stack_save(%rip)
+
+        /* Get kernel stack */
+        lea (x86_64_kernel_stack + X86_64_KERNEL_STACK_SIZE)(%rip), %rsp
+
+        pushq   %rcx            /* Save user-space RIP */
+        pushq   %r11            /* Save user-space RFLAGS */
+
+        pushq   %rbx            /* arg11 */
+        pushq   %rbp            /* arg10 */
+        pushq   %rax            /* arg9 */
+        pushq   %r15            /* arg8 */
+        pushq   %r14            /* arg7 */
+        pushq   %r13            /* arg6 */
+        pushq   %r12            /* arg5 */
+        pushq   %r9             /* arg4 */
+        pushq   %r8             /* arg3 */
+        pushq   %r10            /* arg2 in r10, NOT rcx from syscall */
+
+        /* syscall number is in rdi (1st function argument) */
+        /* arg0 is in rsi (2nd function argument) */
+        /* arg1 is in rdx (3rd function argument) */
+        movq    %r11, %r8   /* 5th function argument is user's flags */
+        movq    %rcx, %r9   /* 6th function argument is user's IP */
+        movq    %rsp, %rcx  /* 4th function argument is pointer to arg buffer */
+
+        callq   sys_syscall     /* Process system call in C */
+
+        addq    $0x50, %rsp     /* Remove buffer from stack */
+        popq    %r11            /* Restore RFLAGS */
+        popq    %rcx            /* Restore RIP */
+        movq    user_stack_save(%rip), %rsp /* Restore user stack */
+        sysretq             /* Return to user-space */
+
+       .bss
+       .comm   user_stack_save, 8
diff --git a/kernel/arch/k1om/exec.c b/kernel/arch/k1om/exec.c
new file mode 100644 (file)
index 0000000..387ab5f
--- /dev/null
@@ -0,0 +1,263 @@
+/**
+ * \file
+ * \brief x86-64 execution and miscellany
+ */
+
+/*
+ * Copyright (c) 2007, 2008, 2009, 2010, 2011, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <kernel.h>
+#include <init.h>
+#include <barrelfish_kpi/cpu.h>
+#include <barrelfish_kpi/cpu_arch.h>
+#include <exec.h>
+#include <irq.h>
+#include <x86.h>
+#include <dispatch.h>
+#include <target/x86_64/barrelfish_kpi/cpu_target.h>
+
+/**
+ * \brief Reboots the system.
+ *
+ * This function tries hard not to return.
+ */
+void reboot(void)
+{
+    struct region_descriptor region = {
+        .rd_limit = 0,
+        .rd_base = 0
+    };
+
+    printk(LOG_NOTE, "Rebooting...\n");
+
+    // try PCI reset register
+    uint8_t val = inb(0xcf9) & ~0x6;
+    val |= 0x2; // hard reset mode
+    outb(0xcf9, val);
+    val |= 0x4; // do the reset!
+    outb(0xcf9, val);
+
+    // try to reboot using keyboard controller hack (this works on QEMU)
+    printk(LOG_NOTE, "PCI reset failed, trying keyboard controller\n");
+    // try 10 times!
+    for (int i = 0; i < 10; i++) {
+        // toggle reset line
+        outb(0x64, 0xfe);
+    }
+
+    // Otherwise load invalid IDT and cause illegal opcode for triple fault
+    printk(LOG_NOTE, "Keyboard controller reset failed, trying triple fault\n");
+    __asm volatile("lidt        %[region]       \n\t"
+                   "ud2                         \n\t"
+                   : /* No output */
+                   : [region] "m" (region)
+                   );
+
+    halt(); // trick GCC into thinking we don't return
+}
+
+/**
+ * \brief Triggers a debugger breakpoint.
+ */
+void breakpoint(void)
+{
+    if(idt_initialized) {
+        hw_breakpoint();
+    } else {
+        printk(LOG_PANIC,
+               "Cannot trap into debugger -- Interrupts not set up yet!\n");
+    }
+}
+
+/**
+ * \brief Go to user-space at entry point 'entry'.
+ *
+ * This function goes to user-space and starts executing the program at
+ * its entry point at virtual address 'entry'.
+ *
+ * \param entry Entry point address of program to execute.
+ */
+void __attribute__ ((noreturn))
+execute(lvaddr_t entry)
+{
+    // FIXME: make argument
+    uintptr_t arg = get_dispatcher_shared_generic(dcb_current->disp)->udisp;
+
+    /*
+     * Go to user-space using SYSRETQ -- the Q is very important, so operand
+     * size is 64-bit. Otherwise we return to compatibility mode.
+     *
+     * We set the startup contents of the RFLAGS register into R11. RCX is
+     * set to the entry point address of the user-space program. All other
+     * general-purpose registers are zeroed.
+     */
+    __asm volatile ("movq       %[flags], %%r11         \n\t" 
+                    "movq       $0, %%rsi               \n\t"
+                    "movq       $0, %%rdx               \n\t"
+                    "movq       $0, %%r8                \n\t"
+                    "movq       $0, %%r9                \n\t"
+                    "movq       $0, %%r10               \n\t"
+                    "movq       $0, %%r12               \n\t"
+                    "movq       $0, %%r13               \n\t"
+                    "movq       $0, %%r14               \n\t"
+                    "movq       $0, %%r15               \n\t"
+                    "movq       $0, %%rax               \n\t"
+                    "movq       $0, %%rbx               \n\t"
+                    "movq       $0, %%rbp               \n\t"
+                    "movq       $0, %%rsp               \n\t"
+                    "mov        %%dx, %%fs              \n\t"
+                    "mov        %%dx, %%gs              \n\t"
+                    "sysretq                            \n\t"
+                    : /* No output */
+                    :
+                    [entry] "c" (entry),
+                    [disp] "D" (arg),
+                    [flags] "i" (USER_RFLAGS)
+                    );
+
+    // Trick GCC to believe us not to return
+    halt();
+}
+
+/**
+ * \brief Resume the given user-space snapshot.
+ *
+ * This function resumes user-space execution by restoring the CPU
+ * registers with the ones given in the array, pointed to by 'regs'.
+ */
+void __attribute__ ((noreturn)) resume(arch_registers_state_t *state)
+{
+    struct registers_x86_64 *regs = state;
+    __asm volatile ("pushq      %[ss]                   \n\t"
+                    "pushq       7*8(%[regs])           \n\t"   // RSP
+                    "pushq      %[rflags]               \n\t"
+                    "pushq      %[cs]                   \n\t"
+                    "pushq      16*8(%[regs])           \n\t"   // RIP
+                    "mov         %[fs], %%fs            \n\t"
+                    "mov         %[gs], %%gs            \n\t"
+                    "movq        0*8(%[regs]), %%rax    \n\t"
+                    "movq        2*8(%[regs]), %%rcx    \n\t"
+                    "movq        3*8(%[regs]), %%rdx    \n\t"
+                    "movq        4*8(%[regs]), %%rsi    \n\t"
+                    "movq        5*8(%[regs]), %%rdi    \n\t"
+                    "movq        6*8(%[regs]), %%rbp    \n\t"
+                    "movq        8*8(%[regs]), %%r8     \n\t"
+                    "movq        9*8(%[regs]), %%r9     \n\t"
+                    "movq       10*8(%[regs]), %%r10    \n\t"
+                    "movq       11*8(%[regs]), %%r11    \n\t"
+                    "movq       12*8(%[regs]), %%r12    \n\t"
+                    "movq       13*8(%[regs]), %%r13    \n\t"
+                    "movq       14*8(%[regs]), %%r14    \n\t"
+                    "movq       15*8(%[regs]), %%r15    \n\t"
+                    "movq        1*8(%[regs]), %%rbx    \n\t"   // RBX was base register
+                    "iretq                              \n\t"
+                    : /* No output */
+                    :
+                    [regs] "b" (regs),
+                    [ss] "i" (GSEL(USTACK_SEL, SEL_UPL)),
+                    [cs] "i" (GSEL(UCODE_SEL, SEL_UPL)),
+                    [fs] "m" (regs->fs),
+                    [gs] "m" (regs->gs),
+                    [rflags] "r" ((regs->eflags & USER_RFLAGS_MASK)
+                                  | USER_RFLAGS)
+                    );
+
+    // Trick GCC to believe us not to return
+    halt();
+}
+
+/**
+ * \brief Halt processor until an interrupt arrives
+ *
+ * For use in the idle loop when nothing is runnable.
+ */
+void __attribute__ ((noreturn)) wait_for_interrupt(void)
+{
+    __asm volatile("lea x86_64_kernel_stack(%%rip), %%rsp\n\t"
+                   "addq %[stack_size], %%rsp\n\t"
+                   "sti                 \n\t"
+                   // The instruction right after STI is still in interrupt
+                   // shadow. To avoid unecessary calls to HLT we insert a nop
+                   // to make sure pending interrupts are handeled immediately.
+                   "nop                 \n\t"
+                   "hlt                 \n\t"
+                   :: [stack_size] "i" (X86_64_KERNEL_STACK_SIZE) : "rsp" );
+    panic("hlt should not return");
+}
+
+/**
+ * \brief Use MONITOR/MWAIT to block until a given word changes
+ *
+ * \param base      Virtual address of 64-bit word to monitor
+ * \param lastval   Previous value of word
+ * \param extensions Processor-specific extensions (zero for defaults)
+ * \param hints     Processor-specific hints (zero for defaults)
+ *
+ * Returns when the 64-bit word at base is not equal to lastval.
+ */
+// TODO XXX: Where should this propotype live?
+void monitor_mwait(lvaddr_t base, uint64_t lastval, uint32_t extensions,
+                   uint32_t hints);
+
+void monitor_mwait(lvaddr_t base, uint64_t lastval, uint32_t extensions,
+                   uint32_t hints)
+{
+    volatile uint64_t *val = (uint64_t *)base;
+
+    assert(extensions == 0);
+    assert(hints == 0);
+
+    while(*val == lastval) {
+        monitor(base, extensions, hints);
+        if(*val != lastval) {
+            return;
+        }
+        mwait(hints, extensions);
+    }
+}
+
+/// Remember current LDT pointer, so we can avoid reloading it
+lvaddr_t current_ldt_base = -1;
+size_t current_ldt_npages;
+
+void maybe_reload_ldt(struct dcb *dcb, bool force_reload)
+{
+    struct dispatcher_shared_x86_64 *disp =
+        get_dispatcher_shared_x86_64(dcb->disp);
+
+    /* Read fields from user dispatcher once for consistency */
+    lvaddr_t ldt_base = disp->ldt_base;
+    size_t ldt_npages = disp->ldt_npages;
+
+    /* optimize out if this is the same as the previous LDT */
+    if (!force_reload && ldt_base == current_ldt_base
+        && ldt_npages == current_ldt_npages) {
+        return;
+    }
+
+    uint16_t selector = 0;
+
+    if (ldt_base != 0 && ldt_npages != 0) {
+        extern union segment_descriptor *ldt_descriptor;
+        ldt_descriptor[0].sys_lo.lo_base = ldt_base & ((1ul << 24) - 1);
+        ldt_descriptor[0].sys_lo.hi_base = (ldt_base >> 24) & 0xff;
+        ldt_descriptor[1].sys_hi.base = ldt_base >> 32;
+        assert(ldt_descriptor[0].sys_lo.granularity != 0);
+        ldt_descriptor[0].sys_lo.lo_limit = ldt_npages;
+
+        selector = GSEL(LDT_LO_SEL, SEL_UPL);
+    }
+
+    __asm volatile("lldt %%ax"
+                   : /* No output */
+                   : "a" (selector));
+
+    current_ldt_base = ldt_base;
+    current_ldt_npages = ldt_npages;
+}
diff --git a/kernel/arch/k1om/gdb_arch.c b/kernel/arch/k1om/gdb_arch.c
new file mode 100644 (file)
index 0000000..30c0f22
--- /dev/null
@@ -0,0 +1,286 @@
+/** \file
+ * \brief x86-specific parts of in-kernel GDB stub.
+ *
+ * This file implements x86 architecture support for the kernel-side GDB stubs.
+ */
+
+/*
+ * Copyright (c) 2007, 2008, 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <kernel.h>
+#include <stdio.h>
+#include <paging_kernel_arch.h>
+#include <gdb_stub.h>
+#include <arch_gdb_stub.h>
+#include <barrelfish_kpi/cpu.h>
+
+/** \brief GDB register save area / frame.
+ *
+ * Stores pointer to current save frame used by GDB. Used to read/modify
+ * register contents, and reloaded when program execution resumes. */
+uintptr_t *gdb_arch_registers;
+
+/** \brief Separate stack area for the stub to run on */
+static uintptr_t gdb_stack[X86_64_KERNEL_STACK_SIZE/sizeof(uintptr_t)];
+/** \brief Pointer to top of GDB stack area. */
+uintptr_t * SNT gdb_stack_top = &gdb_stack[X86_64_KERNEL_STACK_SIZE/sizeof(uintptr_t)];
+
+/** \brief Converts exception vector to signal number.
+ *
+ * This function takes an x86 exception vector and attempts to
+ * translate this number into a Unix-compatible signal value.
+ */
+static int exception_to_signal(int vector)
+{
+    switch (vector) {
+        case 0:     return 8;   // divide by zero
+        case 1:     return 5;   // debug exception
+        case 3:     return 5;   // breakpoint
+        case 4:     return 16;  // into instruction (overflow)
+        case 5:     return 16;  // bound instruction
+        case 6:     return 4;   // Invalid opcode
+        case 7:     return 8;   // coprocessor not available
+        case 8:     return 7;   // double fault
+        case 9:     return 11;  // coprocessor segment overrun
+        case 10:    return 11;  // Invalid TSS
+        case 11:    return 11;  // Segment not present
+        case 12:    return 11;  // stack exception
+        case 13:    return 11;  // general protection
+        case 14:    return 11;  // page fault
+        case 16:    return 7;   // coprocessor error
+        default:    return 7;   // "software generated"
+    }
+}
+
+__asm__ (
+    ".global gdb_handle_exception       \n"
+    "gdb_handle_exception:              \n"
+    "mov gdb_stack_top(%rip), %rsp      \n"
+    "jmp gdb_handle_exception_onstack   \n"
+);
+
+/** \brief Entry point for an exception; we are now on our own stack.
+ *
+ * This function sets up the GDB-format register save frame, constructs the
+ * initial message to the remote GDB and calls into the generic debugger entry
+ * point.
+ */
+void gdb_handle_exception_onstack(int vector, uintptr_t * NONNULL
+        COUNT(GDB_X86_64_NUM_REGS) save_area) __attribute__((noreturn));
+void gdb_handle_exception_onstack(int vector, uintptr_t * NONNULL
+        COUNT(GDB_X86_64_NUM_REGS) save_area)
+{
+    /* sanity check that we didn't trap inside the debugger...
+     * if we did, we're definitely hosed now! */
+    if (save_area[GDB_X86_64_RSP_REG] >= (lvaddr_t)&gdb_stack &&
+        save_area[GDB_X86_64_RSP_REG] <= (lvaddr_t)gdb_stack_top) {
+        panic("Nested exception within GDB stub");
+    }
+    
+    /* were we in user mode at the time of the trap? */
+    if ((save_area[GDB_X86_64_CS_REG] & 0x3) != 0) {
+        printk(LOG_NOTE,
+               "Entered from user-mode (at least, CPL in CS is non-zero)\n");
+
+    /* while we're checking the stack pointer, sanity check that it's
+     * within the normal kernel stack region */
+    } else if (save_area[GDB_X86_64_RSP_REG] < (lvaddr_t)&x86_64_kernel_stack ||
+              save_area[GDB_X86_64_RSP_REG] > (lvaddr_t)&x86_64_kernel_stack +
+               X86_64_KERNEL_STACK_SIZE) {
+        printk(LOG_WARN, "BIG FAT WARNING: kernel stack pointer (0x%lx) is "
+               "invalid!\n", save_area[GDB_X86_64_RSP_REG]);
+        printk(LOG_WARN, "Boldly attempting to continue into GDB anyway...\n");
+    }
+
+    char buffer[64];
+    int signal = exception_to_signal(vector);
+
+#if 0 // this is broken, because the register data needs to be in LE byte order
+    // T <signal> RSP:<stack ptr>; RIP:<inst ptr>;
+    int r = snprintf(buffer, sizeof(buffer), "T%02hhx%x:%lx;%x:%lx;", signal,
+                     RSP_REG, save_area[RSP_REG],
+                     RIP_REG, save_area[RIP_REG]);
+#else
+    int r = snprintf(buffer, sizeof(buffer), "S%02hhx", signal);
+#endif
+    assert(r < sizeof(buffer));
+    if (r >= sizeof(buffer)) {
+        // ensure termination in the case of overflow
+        buffer[sizeof(buffer) - 1] = '\0';
+    }
+
+    gdb_arch_registers = save_area;
+    gdb_stub_entry(signal, buffer);
+}
+
+/** \brief Get the value of a single register in the frame.
+ * \param regnum register number (as defined by the #gdb_register_nums enum)
+ * \param value pointer to location in which to return current value
+ * \return Zero on success, nonzero on failure (invalid regnum).
+ */
+int gdb_arch_get_register(int regnum, uintptr_t *value)
+{
+    if (regnum < 0 || regnum >= GDB_X86_64_NUM_REGS) {
+        return -1;
+    }
+
+    *value = gdb_arch_registers[regnum];
+    return 0;
+}
+
+/** \brief Set the value of a single register in the frame.
+ * \param regnum register number (as defined by the #gdb_register_nums enum)
+ * \param value new value
+ * \return Zero on success, nonzero on failure (invalid regnum).
+ */
+int gdb_arch_set_register(int regnum, uintptr_t value)
+{
+    if (regnum < 0 || regnum >= GDB_X86_64_NUM_REGS) {
+        return -1;
+    }
+
+    gdb_arch_registers[regnum] = value;
+    return 0;
+}
+
+/** \brief Resume execution.
+ *
+ * Resumes execution with the CPU state stored in the #gdb_arch_registers frame.
+ */
+void gdb_resume(void) __attribute__((noreturn));
+
+__asm__ (
+    ".global gdb_resume                 \n"
+    "gdb_resume:                        \n"
+    /* load address (in PIC manner) of register frame */
+    "movq gdb_arch_registers(%rip), %r15\n"
+    /* setup stack for iretq below */
+    "movq (19*8)(%r15), %rax            \n" // SS
+    "pushq %rax                         \n"
+    "movq (7*8)(%r15), %rax             \n" // RSP
+    "pushq %rax                         \n"
+    "movq (17*8)(%r15), %rax            \n" // EFLAGS
+    "pushq %rax                         \n"
+    "movq (18*8)(%r15), %rax            \n" // CS
+    "pushq %rax                         \n"
+    "movq (16*8)(%r15), %rax            \n" // EIP
+    "pushq %rax                         \n"
+    /* load remaining registers directly */
+    "movq (0*8)(%r15), %rax             \n"
+    "movq (1*8)(%r15), %rbx             \n"
+    "movq (2*8)(%r15), %rcx             \n"
+    "movq (3*8)(%r15), %rdx             \n"
+    "movq (4*8)(%r15), %rsi             \n"
+    "movq (5*8)(%r15), %rdi             \n"
+    "movq (6*8)(%r15), %rbp             \n"
+    "movq (8*8)(%r15), %r8              \n"
+    "movq (9*8)(%r15), %r9              \n"
+    "movq (10*8)(%r15), %r10            \n"
+    "movq (11*8)(%r15), %r11            \n"
+    "movq (12*8)(%r15), %r12            \n"
+    "movq (13*8)(%r15), %r13            \n"
+    "movq (14*8)(%r15), %r14            \n"
+    "movq (15*8)(%r15), %r15            \n"
+    /* return! */
+    "iretq                              \n"
+);
+
+/** \brief Resume program execution.
+ * \param addr Address to resume at, or 0 to continue at last address.
+ */
+void gdb_arch_continue(lvaddr_t addr)
+{
+    if (addr != 0) {
+        gdb_arch_registers[GDB_X86_64_RIP_REG] = addr;
+    }
+
+    /* clear the trace bit */
+    gdb_arch_registers[GDB_X86_64_EFLAGS_REG] &= ~0x100; // XXX
+
+    gdb_resume(); /* doesn't return */
+}
+
+/** \brief Single-step program execution.
+ * \param addr Address to resume at, or 0 to continue at last address.
+ */
+void gdb_arch_single_step(lvaddr_t addr)
+{
+    if (addr != 0) {
+        gdb_arch_registers[GDB_X86_64_RIP_REG] = addr;
+    }
+
+    /* set the trace bit for single-step */
+    gdb_arch_registers[GDB_X86_64_EFLAGS_REG] |= 0x100; // XXX
+
+    gdb_resume(); /* doesn't return */
+}
+
+/** \brief Ensures that the page containing addr is mapped.
+ * \return Zero on success, negative on failure.
+ */
+static int ensure_mapping(lvaddr_t addr)
+{
+    static lpaddr_t lastaddr;
+
+    /* check if address is in kernel image */
+    if (addr >= (lvaddr_t)&_start_kernel && addr < (lvaddr_t)&_end_kernel) {
+        return 0;
+    }
+
+    /* if address is outside "physical" memory region, fail the access */
+    if (addr < X86_64_MEMORY_OFFSET) {
+        return -1;
+    }
+
+    /* we now know we have a valid "physical memory" region address */
+    lpaddr_t paddr = mem_to_local_phys(addr);
+    paddr -= paddr & X86_64_MEM_PAGE_MASK; // page-align
+
+    /* quick and dirty optimisation: if this address is on the same page as
+     * the last time we were called, return immediately */
+    if (lastaddr == paddr && lastaddr != 0) {
+        return 0;
+    }
+
+    int r = paging_x86_64_map_memory(paddr, X86_64_MEM_PAGE_SIZE);
+    if (r < 0) {
+        return r;
+    }
+
+    lastaddr = paddr;
+    return 0;
+}
+
+/** \brief Writes a byte to an arbitrary address in kernel memory.
+ * \return Zero on success, nonzero on error (invalid address)
+ */
+int gdb_arch_write_byte(uint8_t *addr, uint8_t val)
+{
+    int r = ensure_mapping((lvaddr_t)addr);
+    if (r < 0) {
+        return r;
+    }
+    
+    *addr = val;
+    return 0;
+}
+
+/** \brief Reads a byte from an arbitrary address in kernel memory.
+ * \return Zero on success, nonzero on error (invalid address)
+ */
+int gdb_arch_read_byte(uint8_t *addr, uint8_t *val)
+{
+    int r = ensure_mapping((lvaddr_t)addr);
+    if (r < 0) {
+        return r;
+    }
+    
+    *val = *addr;
+    return 0;
+}
diff --git a/kernel/arch/k1om/init.c b/kernel/arch/k1om/init.c
new file mode 100644 (file)
index 0000000..6cb6fb2
--- /dev/null
@@ -0,0 +1,690 @@
+/**
+ * \file
+ * \brief x86-64 architecture initialization.
+ */
+
+/*
+ * Copyright (c) 2007, 2008, 2009, 2010, 2011, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <kernel.h>
+#include <string.h>
+#include <stdio.h>
+#include <paging_kernel_arch.h>
+#include <elf/elf.h>
+#include <init.h>
+#include <irq.h>
+#include <x86.h>
+#include <serial.h>
+#include <kernel_multiboot.h>
+#include <syscall.h>
+#include <getopt/getopt.h>
+#include <exec.h>
+#include <kputchar.h>
+#include <arch/x86/conio.h>
+#include <arch/x86/pic.h>
+#include <arch/x86/apic.h>
+#include <arch/x86/mcheck.h>
+#include <arch/x86/perfmon.h>
+#include <arch/x86/rtc.h>
+#include <target/x86/barrelfish_kpi/coredata_target.h>
+#include <arch/x86/timing.h>
+#include <arch/x86/startup_x86.h>
+#include <arch/x86/ipi_notify.h>
+#include <barrelfish_kpi/cpu_arch.h>
+#include <target/x86_64/barrelfish_kpi/cpu_target.h>
+
+#include <dev/xapic_dev.h> // XXX
+#include <dev/ia32_dev.h>
+#include <dev/amd64_dev.h>
+
+/**
+ * Used to store the address of global struct passed during boot across kernel
+ * relocations.
+ */
+static uint64_t addr_global;
+
+/**
+ * \brief Kernel stack.
+ *
+ * This is the one and only kernel stack for a kernel instance.
+ */
+uintptr_t x86_64_kernel_stack[X86_64_KERNEL_STACK_SIZE/sizeof(uintptr_t)];
+
+/**
+ * \brief Global Task State Segment (TSS).
+ *
+ * This is the global, static and only Task State Segment (TSS). It is used
+ * for interrupt and exception handling (stack setup) while in user-space.
+ */
+static struct task_state_segment tss __attribute__ ((aligned (4)));
+
+/**
+ * \brief Global Descriptor Table (GDT) for processor this kernel is running on.
+ *
+ * This descriptor table is completely static, as segments are basically
+ * turned off in 64-bit mode. They map flat-mode code and stack segments for
+ * both kernel- and user-space and the only Task State Segment (TSS).
+ */
+union segment_descriptor gdt[] __attribute__ ((aligned (4))) = {
+    [NULL_SEL] = {   // Null segment
+        .raw = 0
+    },
+    [KCODE_SEL] = {   // Kernel code segment
+        .d = {
+            .lo_limit = 0xffff,
+            .lo_base = 0,
+            .type = 0xa,
+            .system_desc = 1,
+            .privilege_level = SEL_KPL,
+            .present = 1,
+            .hi_limit = 0xf,
+            .available = 0,
+            .long_mode = 1,
+            .operation_size = 0,
+            .granularity = 1,
+            .hi_base = 0
+        }
+    },
+    [KSTACK_SEL] = {   // Kernel stack segment
+        .d = {
+            .lo_limit = 0xffff,
+            .lo_base = 0,
+            .type = 2,
+            .system_desc = 1,
+            .privilege_level = SEL_KPL,
+            .present = 1,
+            .hi_limit = 0xf,
+            .available = 0,
+            .long_mode = 1,
+            .operation_size = 0,
+            .granularity = 1,
+            .hi_base = 0
+        }
+    },
+    [USTACK_SEL] = {   // User stack segment
+        .d = {
+            .lo_limit = 0xffff,
+            .lo_base = 0,
+            .type = 2,
+            .system_desc = 1,
+            .privilege_level = SEL_UPL,
+            .present = 1,
+            .hi_limit = 0xf,
+            .available = 0,
+            .long_mode = 1,
+            .operation_size = 0,
+            .granularity = 1,
+            .hi_base = 0
+        }
+    },
+    [UCODE_SEL] = {   // User code segment
+        .d = {
+            .lo_limit = 0xffff,
+            .lo_base = 0,
+            .type = 0xa,
+            .system_desc = 1,
+            .privilege_level = SEL_UPL,
+            .present = 1,
+            .hi_limit = 0xf,
+            .available = 0,
+            .long_mode = 1,
+            .operation_size = 0,
+            .granularity = 1,
+            .hi_base = 0
+        }
+    },
+    [TSS_LO_SEL] = {   // Global Task State Segment (TSS), lower 8 bytes
+        .sys_lo = {
+            .lo_limit = sizeof(tss) & 0xffff,
+            .type = SDT_SYSTSS,
+            .privilege_level = SEL_KPL,
+            .present = 1,
+            .hi_limit = (sizeof(tss) >> 16) & 0xf,
+            .available = 0,
+            .granularity = 0,
+        }
+    },
+    [TSS_HI_SEL] = {   // Global Task State Segment (TSS), upper 8 bytes
+        .sys_hi = {
+            .base = 0
+        }
+    },
+    [LDT_LO_SEL] = {    // Local descriptor table (LDT), lower 8 bytes
+        .sys_lo = {
+            .lo_limit = 0, // # 4k pages (since granularity = 1)
+            .lo_base = 0, // changed by context switch path when doing lldt
+            .type = 2, // LDT
+            .privilege_level = SEL_UPL,
+            .present = 1,
+            .hi_limit = 0,
+            .available = 0,
+            .granularity = 1,
+            .hi_base = 0
+        }
+    },
+    [LDT_HI_SEL] = {    // Local descriptor table (LDT), upper 8 bytes
+        .sys_hi = {
+            .base = 0 // changed by context switch path when doing lldt
+        }
+    },
+};
+
+union segment_descriptor *ldt_descriptor = &gdt[LDT_LO_SEL];
+
+/**
+ * Bootup PML4, used to map both low (identity-mapped) memory and relocated
+ * memory at the same time.
+ */
+static union x86_64_pdir_entry boot_pml4[PTABLE_SIZE]
+__attribute__ ((aligned(BASE_PAGE_SIZE)));
+
+/**
+ * Bootup low-map PDPT and hi-map PDPT.
+ */
+static union x86_64_pdir_entry boot_pdpt[PTABLE_SIZE]
+__attribute__ ((aligned(BASE_PAGE_SIZE))),
+    boot_pdpt_hi[PTABLE_SIZE] __attribute__ ((aligned(BASE_PAGE_SIZE)));
+
+/**
+ * Bootup low-map PDIR, hi-map PDIR, and 1GB PDIR.
+ */
+static union x86_64_ptable_entry boot_pdir[PTABLE_SIZE]
+__attribute__ ((aligned(BASE_PAGE_SIZE))),
+    boot_pdir_hi[PTABLE_SIZE] __attribute__ ((aligned(BASE_PAGE_SIZE))),
+    boot_pdir_1GB[PTABLE_SIZE] __attribute__ ((aligned(BASE_PAGE_SIZE)));
+
+/**
+ * This flag is set to true once the IDT is initialized and exceptions can be
+ * caught.
+ */
+bool idt_initialized = false;
+
+/**
+ * \brief Setup bootup page table.
+ *
+ * This function sets up the page table needed to boot the kernel
+ * proper.  The table identity maps the first 1 GByte of physical
+ * memory in order to have access to various data structures and the
+ * first MByte containing bootloader-passed data structures. It also
+ * identity maps the local copy of the kernel in low memory and
+ * aliases it in kernel address space.
+ *
+ * \param base  Start address of kernel image in physical address space.
+ * \param size  Size of kernel image.
+ */
+static void paging_init(lpaddr_t base, size_t size)
+{
+    lvaddr_t vbase = local_phys_to_mem(base);
+
+    // Align base to kernel page size
+    if(base & X86_64_MEM_PAGE_MASK) {
+        size += base & X86_64_MEM_PAGE_MASK;
+        base -= base & X86_64_MEM_PAGE_MASK;
+    }
+
+    // Align vbase to kernel page size
+    if(vbase & X86_64_MEM_PAGE_MASK) {
+        vbase -= vbase & X86_64_MEM_PAGE_MASK;
+    }
+
+    // Align size to kernel page size
+    if(size & X86_64_MEM_PAGE_MASK) {
+        size += X86_64_MEM_PAGE_SIZE - (size & X86_64_MEM_PAGE_MASK);
+    }
+
+    // XXX: Cannot currently map more than one table of pages
+    assert(size <= X86_64_MEM_PAGE_SIZE * X86_64_PTABLE_SIZE);
+/*     assert(size <= MEM_PAGE_SIZE); */
+
+    for(size_t i = 0; i < size; i += X86_64_MEM_PAGE_SIZE,
+            base += X86_64_MEM_PAGE_SIZE, vbase += X86_64_MEM_PAGE_SIZE) {
+        // No kernel image above 4 GByte
+        assert(base < ((lpaddr_t)4 << 30));
+
+        // Identity-map the kernel's physical region, so we don't lose ground
+        paging_x86_64_map_table(&boot_pml4[X86_64_PML4_BASE(base)], (lpaddr_t)boot_pdpt);
+        paging_x86_64_map_table(&boot_pdpt[X86_64_PDPT_BASE(base)], (lpaddr_t)boot_pdir);
+        paging_x86_64_map_large(&boot_pdir[X86_64_PDIR_BASE(base)], base, PTABLE_PRESENT
+                                | PTABLE_READ_WRITE | PTABLE_USER_SUPERVISOR);
+
+        // Alias the same region at MEMORY_OFFSET
+        paging_x86_64_map_table(&boot_pml4[X86_64_PML4_BASE(vbase)], (lpaddr_t)boot_pdpt_hi);
+        paging_x86_64_map_table(&boot_pdpt_hi[X86_64_PDPT_BASE(vbase)], (lpaddr_t)boot_pdir_hi);
+        paging_x86_64_map_large(&boot_pdir_hi[X86_64_PDIR_BASE(vbase)], base, PTABLE_PRESENT
+                                | PTABLE_READ_WRITE | PTABLE_USER_SUPERVISOR);
+    }
+
+    // Identity-map the first 1G of physical memory for bootloader data
+    paging_x86_64_map_table(&boot_pml4[0], (lpaddr_t)boot_pdpt);
+    paging_x86_64_map_table(&boot_pdpt[0], (lpaddr_t)boot_pdir_1GB);
+    for (int i = 0; i < X86_64_PTABLE_SIZE; i++) {
+        paging_x86_64_map_large(&boot_pdir_1GB[X86_64_PDIR_BASE(X86_64_MEM_PAGE_SIZE * i)],
+                                X86_64_MEM_PAGE_SIZE * i, PTABLE_PRESENT
+                                | PTABLE_READ_WRITE | PTABLE_USER_SUPERVISOR);
+    }
+
+    // Activate new page tables
+    paging_x86_64_context_switch((lpaddr_t)boot_pml4);
+}
+
+/**
+ * \brief Setup default GDT.
+ *
+ * Loads the GDT register with the default GDT and reloads CS and SS
+ * to point to the new entries. Resets all other segment registers to null.
+ * Finally, completes setup of GDT to include TSS base address mapping and
+ * loads TSS into task register.
+ */
+static void gdt_reset(void)
+{
+    lvaddr_t                     ptss = (lvaddr_t)&tss;
+    struct region_descriptor    region = {
+        .rd_limit = sizeof(gdt),
+        .rd_base = (uint64_t)&gdt
+    };
+
+    // Load default GDT
+    __asm volatile("lgdt %[region]" :: [region] "m" (region));
+
+    // Reload segments
+    __asm volatile("mov %[null], %%ds      \n\t"
+                   "mov %[null], %%es      \n\t"
+                   "mov %[ss], %%ss        \n\t"
+                   "mov %[null], %%gs      \n\t"
+                   "mov %[null], %%fs      \n\t"
+                   "pushq %[cs]            \n\t"          // new CS
+                   "lea 1f(%%rip), %%rax   \n\t"          // jumps to after lret
+                   "pushq %%rax            \n\t"          // new IP
+                   "lretq                  \n\t"          // fake return
+                   "1:                     \n\t"          // we'll continue here
+                   : /* No Output */
+                   :
+                   [null] "r" (0),
+                   [ss] "r" (GSEL(KSTACK_SEL, SEL_KPL)),
+                   [cs] "i" (GSEL(KCODE_SEL, SEL_KPL))
+                   : "rax"
+                   );
+
+    // Complete setup of TSS descriptor (by inserting base address of TSS)
+    gdt[TSS_LO_SEL].sys_lo.lo_base = ptss & 0xffffff;
+    gdt[TSS_LO_SEL].sys_lo.hi_base = (ptss >> 24) & 0xff;
+    gdt[TSS_HI_SEL].sys_hi.base = ptss >> 32;
+
+    // Complete setup of TSS
+    tss.rsp[0] = (lvaddr_t)&x86_64_kernel_stack[X86_64_KERNEL_STACK_SIZE / sizeof(uintptr_t)];
+
+    // Load task state register
+    __asm volatile("ltr %%ax" :: "a" (GSEL(TSS_LO_SEL, SEL_KPL)));
+}
+
+/**
+ * \brief Relocates the active stack.
+ *
+ * This function relocates the stack, by adding 'offset' to the stack
+ * pointer.
+ *
+ * \param offset        Offset to add to the stack pointer.
+ */
+static inline void __attribute__ ((always_inline))
+relocate_stack(lvaddr_t offset)
+{
+    __asm volatile("add %[stack], %%rsp\n\t"
+                   : /* No output */
+                   : [stack] "er" (offset)
+                   : "rsp"
+                   );
+}
+
+/**
+ * \brief Enable SYSCALL/SYSRET fast system calls.
+ *
+ * This function enables the SYSCALL/SYSRET pair of fast system calls in
+ * long mode. Also sets the IA32_STAR and IA32_FMASK MSRs to point to the
+ * user-space base selector and RFLAGS mask for SYSCALL/SYSRET fast system
+ * calls.
+ */
+static inline void enable_fast_syscalls(void)
+{
+    // Segment selector bases for both kernel- and user-space for fast
+    // system calls 
+    ia32_star_t star = ia32_star_rd(NULL);
+    star = ia32_star_call_insert(star, GSEL(KCODE_SEL,  SEL_KPL));
+    star = ia32_star_ret_insert( star, GSEL(KSTACK_SEL, SEL_UPL));
+    ia32_star_wr(NULL, star);
+
+    // Set ia32_lstar MSR to point to kernel-space system call multiplexer
+    ia32_lstar_wr(NULL, (lvaddr_t)syscall_entry);
+
+    // Set IA32_FMASK MSR for our OSes EFLAGS mask
+    // We mask out everything (including interrupts).
+    ia32_fmask_v_wrf(NULL, ~(RFLAGS_ALWAYS1) );
+
+    // Enable fast system calls
+    ia32_efer_sce_wrf(NULL, 1);
+}
+
+static inline void enable_tlb_flush_filter(void)
+{
+    uint32_t eax, ebx, ecx, edx;
+
+    // Must read "AuthenticAMD"
+    cpuid(0, &eax, &ebx, &ecx, &edx);
+    if(ebx != 0x68747541 || ecx != 0x444d4163 || edx != 0x69746e65) {
+        return;
+    }
+
+    // Is at least family 0fh?
+    cpuid(1, &eax, &ebx, &ecx, &edx);
+    if(((eax >> 8) & 0xf) != 0xf) {
+        return;
+    }
+
+    debug(SUBSYS_STARTUP, "Enabling TLB flush filter\n");
+    ia32_amd_hwcr_ffdis_wrf(NULL, 1);
+}
+
+static inline void enable_monitor_mwait(void)
+{
+    uint32_t eax, ebx, ecx, edx;
+
+    cpuid(1, &eax, &ebx, &ecx, &edx);
+
+    if (ecx & (1 << 3)) {
+        cpuid(5, &eax, &ebx, &ecx, &edx);
+        debug(SUBSYS_STARTUP, "MONITOR/MWAIT supported: "
+              "min size %u bytes, max %u bytes. %s %s\n",
+              eax, ebx, (ecx & 2) ? "IBE" : "", (ecx & 1) ? "EMX" : "");
+    }
+}
+
+/**
+ * \brief Continue kernel initialization in kernel address space.
+ *
+ * This function resets paging to map out low memory and map in physical
+ * address space, relocating all remaining data structures. It resets the
+ * Global Descriptor Table for flat mode and to exclude legacy segments from
+ * boot initialization code. It sets up the IDT for exception and interrupt
+ * handling, initializes the local APIC and enables interrupts. After that it
+ * calls kernel_startup(), which should not return (if it does, this function
+ * halts the kernel).
+ */
+static void  __attribute__ ((noreturn, noinline)) text_init(void)
+{
+    // Reset global and locks to point to the memory in the pristine image
+    global = (struct global*)addr_global;
+
+    /*
+     * Reset paging once more to use relocated data structures and map in
+     * whole of kernel and available physical memory. Map out low memory.
+     */
+    paging_x86_64_reset();
+
+    // Relocate global to "memory"
+    global = (struct global*)local_phys_to_mem((lpaddr_t)global);
+
+    // Relocate glbl_core_data to "memory"
+    glbl_core_data = (struct x86_core_data *)
+        local_phys_to_mem((lpaddr_t)glbl_core_data);
+
+    /*
+     * Use new physical address space for video memory -- no calls to functions
+     * that end up calling a conio.c function may be called between
+     * paging_reset() and conio_relocate_vidmem()!
+     */
+    conio_relocate_vidmem(local_phys_to_mem(VIDEO_MEM));
+
+    // Re-map physical memory
+    /* XXX: Currently we are statically mapping a fixed amount of
+       memory.  We should not map in more memory than the machine
+       actually has.  Or else if the kernel tries to access addresses
+       not backed by real memory, it will experience weird faults
+       instead of a simpler pagefault.
+
+       Ideally, we should use the ACPI information to figure out which
+       memory to map in. Look at ticket #218 for more
+       information. -Akhi
+    */
+    if(paging_x86_64_map_memory(0, X86_64_PADDR_SPACE_LIMIT) != 0) {
+        panic("error while mapping physical memory!");
+    }
+
+    /*
+     * Also reset the global descriptor table (GDT), so we get
+     * segmentation again and can catch interrupts/exceptions (the IDT
+     * needs the GDT).
+     */
+    gdt_reset();
+
+    // Arch-independent early startup
+    kernel_startup_early();
+
+    // XXX: re-init the serial driver, in case the port changed after parsing args
+    serial_console_init();
+
+    // Setup IDT
+    setup_default_idt();
+    idt_initialized = true;
+
+    // Enable machine check reporting
+    mcheck_init();
+
+    // Initialize local APIC
+    apic_init();
+
+    // do not remove/change this printf: needed by regression harness
+    printf("Barrelfish CPU driver starting on x86_64 apic_id %u\n", apic_id);
+
+    if(apic_is_bsp()) {
+        // Initialize classic (8259A) PIC
+        pic_init();
+    }
+
+    // Initialize real-time clock
+    rtc_init();
+
+    // Initialize local APIC timer
+    if (kernel_ticks_enabled) {
+        timing_calibrate();
+        bool periodic = true;
+        #ifdef CONFIG_ONESHOT_TIMER
+        // we probably need a global variable like kernel_ticks_enabled
+        periodic = false;
+        #endif
+        apic_timer_init(false, periodic);
+        timing_apic_timer_set_ms(kernel_timeslice);
+    } else {
+        printk(LOG_WARN, "APIC timer disabled: NO timeslicing\n");
+        apic_mask_timer();
+    }
+
+    // Initialize IPI notification mechanism
+    ipi_notify_init();
+
+    // Enable SYSCALL/SYSRET fast system calls
+    enable_fast_syscalls();
+
+    // Enable "no execute" page-level protection bit
+    ia32_efer_nxe_wrf(NULL, 1);
+
+    // Enable FPU and MMX
+    enable_fpu();
+
+    // Enable user-mode RDPMC opcode
+    amd64_cr4_pce_wrf(NULL, 1);
+
+    // AMD64: Check if TLB flush filter is enabled
+    enable_tlb_flush_filter();
+
+    // Enable global pages
+    amd64_cr4_pge_wrf(NULL, 1);
+
+    // Check/Enable MONITOR/MWAIT opcodes
+    enable_monitor_mwait();
+
+    // Call main kernel startup function -- this should never return
+    kernel_startup();
+
+    halt();
+    // Returning here will crash! -- low pages not mapped anymore!
+}
+
+/**
+ * \brief Architecture-specific initialization function.
+ *
+ * This function is called by the bootup code in boot.S to initialize
+ * architecture-specific stuff. It is expected to call the kernel main
+ * loop. This function never returns.
+ *
+ * The kernel expects one of two magic values in 'magic' that determine how it
+ * has been booted. If 'magic' is #MULTIBOOT_INFO_MAGIC the kernel has been
+ * booted by a (Multiboot-compliant) bootloader and this is the first image on
+ * the boot CPU. It will relocate itself to a default position. If 'magic' is
+ * #KERNEL_BOOT_MAGIC it has been booted by another image of itself and is
+ * running on an (so-called) application CPU.
+ *
+ * This function sets up new page tables to alias the kernel
+ * at #MEMORY_OFFSET. It also does any relocations necessary to the
+ * "position-independent" code to make it run at the new location (e.g.
+ * relocating the GOT). After all relocations, it calls text_init() of
+ * the relocated image, which destroys the lower alias and may never return.
+ *
+ * For bsp kernels, the void pointer is of type multiboot_info, for application
+ * CPUs, it is of type global. Global carries a pointer to multiboot_info.
+ * Global also contains pointers to memory that is shared between kernels.
+ *
+ * \param magic         Boot magic value
+ * \param pointer       Pointer to Multiboot Info or to Global structure
+ */
+void arch_init(uint64_t magic, void *pointer)
+{
+    // Sanitize the screen
+    conio_cls();
+    serial_console_init();
+
+    void __attribute__ ((noreturn)) (*reloc_text_init)(void) =
+        (void *)local_phys_to_mem((lpaddr_t)text_init);
+    struct Elf64_Shdr *rela, *symtab;
+    struct multiboot_info *mb = NULL;
+
+    /*
+     * If this is the boot image, make Multiboot information structure globally
+     * known. Otherwise the passed value should equal the original structure.
+     * If magic value does not match what we expect, we cannot proceed safely.
+     */
+    switch(magic) {
+    case MULTIBOOT_INFO_MAGIC:
+        mb = (struct multiboot_info *)pointer;
+
+        // Construct the global structure and store its address to retrive it
+        // across relocation
+        memset(&global->locks, 0, sizeof(global->locks));
+        addr_global            = (uint64_t)global;
+        break;
+
+    case KERNEL_BOOT_MAGIC:
+        global = (struct global*)pointer;
+        // Store the address of global to retrive it across relocation
+        addr_global = (uint64_t)global;
+        break;
+
+    default:
+        panic("Magic value does not match! (0x%x != 0x%lx != 0x%x)",
+              KERNEL_BOOT_MAGIC, magic, MULTIBOOT_INFO_MAGIC);
+        break;
+    }
+
+    /* determine page-aligned physical address past end of multiboot */
+    lvaddr_t dest = (lvaddr_t)&_start_kernel;
+    if (dest & (BASE_PAGE_SIZE - 1)) {
+        dest &= ~(BASE_PAGE_SIZE - 1);
+        dest += BASE_PAGE_SIZE;
+    }
+
+    // XXX: print kernel address for debugging with gdb
+    printf("Kernel starting at address 0x%"PRIxLVADDR"\n",
+           local_phys_to_mem(dest));
+
+    struct x86_coredata_elf *elf;
+    uint32_t multiboot_flags;
+    if (mb != NULL) { /* Multiboot info was passed */
+        multiboot_flags = mb->flags;
+        elf = (struct x86_coredata_elf *)&mb->syms.elf;
+
+        // We need the ELF section header table for relocation
+        if (!(multiboot_flags & MULTIBOOT_INFO_FLAG_HAS_ELF_SYMS)) {
+            panic("Multiboot information structure does not include ELF section"
+                  "header information -- Relocation impossible!");
+        }
+
+        // Determine where free RAM starts
+        glbl_core_data->start_free_ram =
+            ROUND_UP(max(multiboot_end_addr(mb), (uintptr_t)&_end_kernel),
+                     BASE_PAGE_SIZE);
+
+        glbl_core_data->mods_addr = mb->mods_addr;
+        glbl_core_data->mods_count = mb->mods_count;
+        glbl_core_data->cmdline = mb->cmdline;
+        glbl_core_data->mmap_length = mb->mmap_length;
+        glbl_core_data->mmap_addr = mb->mmap_addr;
+    } else { /* No multiboot info, use the core_data struct */
+        struct x86_core_data *core_data =
+            (struct x86_core_data*)(dest - BASE_PAGE_SIZE);
+        multiboot_flags = core_data->multiboot_flags;
+        elf = &core_data->elf;
+        glbl_core_data = core_data;
+        core_data->cmdline = (lpaddr_t)&core_data->kernel_cmdline;
+        my_core_id = core_data->dst_core_id;
+
+        if (core_data->module_end > 4ul * (1ul << 20)) {
+            panic("The cpu module is outside the initial 4MB mapping."
+                  " Either move the module or increase initial mapping.");
+        }
+    }
+
+    // We're only able to process Elf64_Rela entries
+    if (elf->size != sizeof(struct Elf64_Shdr)) {
+        panic("ELF section header entry size mismatch!");
+    }
+
+    // Find relocation section
+    rela = elf64_find_section_header_type((struct Elf64_Shdr *)
+                                          (lpaddr_t)elf->addr,
+                                          elf->num, SHT_RELA);
+    if (rela == NULL) {
+        panic("Kernel image does not include relocation section!");
+    }
+
+    // Find symbol table section
+    symtab = elf64_find_section_header_type((struct Elf64_Shdr *)
+                                            (lpaddr_t)elf->addr,
+                                            elf->num, SHT_DYNSYM);
+    if (symtab == NULL) {
+        panic("Kernel image does not include symbol table!");
+    }
+
+    // Alias kernel on top of memory, keep low memory
+    paging_init((lpaddr_t)&_start_kernel, SIZE_KERNEL_IMAGE);
+
+    // Relocate kernel image for top of memory
+    elf64_relocate(X86_64_MEMORY_OFFSET + (lvaddr_t)&_start_kernel,
+                   (lvaddr_t)&_start_kernel,
+                   (struct Elf64_Rela *)(rela->sh_addr - X86_64_START_KERNEL_PHYS + &_start_kernel),
+                   rela->sh_size,
+                   (struct Elf64_Sym *)(symtab->sh_addr - X86_64_START_KERNEL_PHYS + &_start_kernel),
+                   symtab->sh_size,
+                   X86_64_START_KERNEL_PHYS, &_start_kernel);
+
+    /*** Aliased kernel available now -- low memory still mapped ***/
+
+    // Relocate stack to aliased location
+    relocate_stack(X86_64_MEMORY_OFFSET);
+
+    // Call aliased text_init() function and continue initialization
+    reloc_text_init();
+}
diff --git a/kernel/arch/k1om/irq.c b/kernel/arch/k1om/irq.c
new file mode 100644 (file)
index 0000000..8b1b75c
--- /dev/null
@@ -0,0 +1,1052 @@
+/**
+ * \file
+ * \brief x86-64 interrupt/exception handling utility functions
+ */
+
+/*
+ * Copyright (c) 2007, 2008, 2009, 2010, 2011, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+/*********************************************************************
+ *
+ * Copyright (C) 2003-2004,  Karlsruhe University
+ *
+ * File path:     glue/v4-amd64/hwirq.h
+ * Description:   Macros to define interrupt handler stubs for AMD64
+ *
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $Id: hwirq.h,v 1.3 2006/10/19 22:57:35 ud3 Exp $
+ *
+ ********************************************************************/
+
+#include <kernel.h>
+#include <stdio.h>
+#include <string.h>
+#include <irq.h>
+#include <exec.h>
+#include <gdb_stub.h>
+#include <arch_gdb_stub.h>
+#include <x86.h>
+#include <dispatch.h>
+#include <wakeup.h>
+#include <arch/x86/perfmon.h>
+#include <arch/x86/barrelfish_kpi/perfmon.h>
+#include <arch/x86/pic.h>
+#include <arch/x86/apic.h>
+#include <barrelfish_kpi/dispatcher_shared_target.h>
+#include <asmoffsets.h>
+#include <trace/trace.h>
+#include <trace_definitions/trace_defs.h>
+#include <arch/x86/timing.h>
+#include <arch/x86/syscall.h>
+#include <arch/x86/ipi_notify.h>
+#include <barrelfish_kpi/cpu_arch.h>
+
+#include <dev/ia32_dev.h>
+
+#ifdef FPU_LAZY_CONTEXT_SWITCH
+#  include <fpu.h>
+#endif
+
+
+/**
+ * \brief Define IRQ handler number 'num'.
+ *
+ * This defines an interrupt handler for vector #num. The way this is done is
+ * quite tricky: A block of assembly is emitted, with a label pointing to
+ * the beginning of that block. The label is made known as a symbol by
+ * having a C function _declaration_ directly in front of the block. The
+ * symbol has to be defined extern, so it is global, but its ELF visibility
+ * is set "hidden", so that the symbol does not end up in the GOT. This is
+ * very important for keeping the code position-independent.
+ *
+ * The NOERR/ERR variants depend on whether the hardware delivers an error code.
+ */
+#define HW_EXCEPTION_NOERR(num)                                         \
+    void __attribute__ ((visibility ("hidden"))) hwexc_##num(void);     \
+    __asm (                                                             \
+           "\t.text                                        \n\t"        \
+           "\t.type hwexc_"#num",@function                 \n\t"        \
+           "hwexc_"#num":                                  \n\t"        \
+           "pushq $0                /* dummy error code */ \n\t"        \
+           "pushq $"#num"           /* vector number */    \n\t"        \
+           "jmp    hwexc_common     /* common stuff */     \n\t"        \
+                                                                        )
+
+#define HW_EXCEPTION_ERR(num)                                           \
+    void __attribute__ ((visibility ("hidden"))) hwexc_##num(void);     \
+    __asm (                                                             \
+           "\t.text                                        \n\t"        \
+           "\t.type hwexc_"#num",@function                 \n\t"        \
+           "hwexc_"#num":                                  \n\t"        \
+           "pushq $"#num"           /* vector number */    \n\t"        \
+           "jmp    hwexc_common     /* common stuff */     \n\t"        \
+                                                                        )
+
+#define XHW_IRQ(num)                                                    \
+    void __attribute__ ((visibility ("hidden"))) hwirq_##num(void);     \
+    __asm (                                                             \
+           "\t.text                                        \n\t"        \
+           "\t.type hwirq_"#num",@function                 \n\t"        \
+           "hwirq_"#num":                                  \n\t"        \
+           "pushq $"#num"           /* vector number */    \n\t"        \
+           "jmp    hwirq_common     /* common stuff */     \n\t"        \
+                                                                        )
+/// Noop wrapper for HW_IRQ to deal with CPP stringification problems
+#define HW_IRQ(num) XHW_IRQ(num)
+
+#define STR(x) #x
+#define XTR(x) STR(x)
+
+__asm (
+    ".text                                              \n\t"
+    "   .type hwexc_common ,@function                   \n\t"
+    "hwexc_common:                                      \n\t"
+    "testb $3, 24(%rsp) /* if CS.CPL == 0 */            \n\t"
+    "jz kernel_fault                                    \n\t"
+
+    /* User exception: save full state and return to the user.
+     * This path could be optimized by only saving the non-volatile
+     * registers (since the kernel's C path will maintain them), and
+     * having the user-mode code save them if needed. Since the
+     * current user code always does need them, we just save the full
+     * set here. */
+
+    /* decide where to save the state, the options are:
+     *    pagefault and enabled -> enabled save area
+     *    pagefault while disabled or any other trap -> trap save area
+     */
+    "pushq %rcx                                         \n\t"
+    "movq dcb_current(%rip), %rcx /* rcx = dcb_current */       \n\t"
+    "movq "XTR(OFFSETOF_DCB_DISP)"(%rcx), %rcx /* rcx = dcb_current->disp */\n\t"
+    "cmpq $14, 8(%rsp)       /* is pagefault? */        \n\t"
+    "jne save_trap                                      \n\t"
+    "cmpl $0, "XTR(OFFSETOF_DISP_DISABLED)"(%rcx) /* disp->disabled ? */\n\t"
+    "jne save_trap                                      \n\t"
+    "pushq %rbx                                         \n\t"
+    "movq 4*8(%rsp), %rbx     /* rbx = faulting IP */   \n\t"
+    "cmpq "XTR(OFFSETOF_DISP_X86_64_CRIT_PC_LOW)"(%rcx), %rbx /* crit_pc_low <= rip? */\n\t"
+    "jae disabled_test                                  \n\t"
+    "\nsave_enabled:                                    \n\t"
+    "popq %rbx                                          \n\t"
+    "addq $"XTR(OFFSETOF_DISP_X86_64_ENABLED_AREA)", %rcx /* rcx = enabled_save_area */\n\t"
+    "jmp do_save                                        \n\t"
+    "\ndisabled_test:                                   \n\t"
+    "cmpq "XTR(OFFSETOF_DISP_X86_64_CRIT_PC_HIGH)"(%rcx), %rbx /* crit_pc_high > rip? */\n\t"
+    "jae save_enabled                                   \n\t"
+    "popq %rbx                                          \n\t"
+    "\nsave_trap:                                       \n\t"
+    "addq $"XTR(OFFSETOF_DISP_X86_64_TRAP_AREA)", %rcx /* trap_save_area */\n\t"
+
+    /* save to the save area. at this point, rcx = save area ptr,
+     * rsp+8 = exception num, rsp+16 = CPU-stacked error and registers */
+    "\ndo_save:                                         \n\t"
+    "movq %rax,  0*8(%rcx)                              \n\t"
+    "popq %rax                    /* original rcx */    \n\t"
+    "movq %rbx,  1*8(%rcx)                              \n\t"
+    "movq %rax,  2*8(%rcx)                              \n\t"
+    "movq %rdx,  3*8(%rcx)                              \n\t"
+    "movq %rsi,  4*8(%rcx)                              \n\t"
+    "movq %rdi,  5*8(%rcx)                              \n\t"
+    "movq %rbp,  6*8(%rcx)                              \n\t"
+    "movq %r8,   8*8(%rcx)                              \n\t"
+    "movq %r9,   9*8(%rcx)                              \n\t"
+    "movq %r10, 10*8(%rcx)                              \n\t"
+    "movq %r11, 11*8(%rcx)                              \n\t"
+    "movq %r12, 12*8(%rcx)                              \n\t"
+    "movq %r13, 13*8(%rcx)                              \n\t"
+    "movq %r14, 14*8(%rcx)                              \n\t"
+    "movq %r15, 15*8(%rcx)                              \n\t"
+    "mov %fs, "XTR(OFFSETOF_FS_REG)"(%rcx)              \n\t"
+    "mov %gs, "XTR(OFFSETOF_GS_REG)"(%rcx)              \n\t"
+    "popq %rdi                    /* vector number */   \n\t"
+    "popq %rsi                    /* error code */      \n\t"
+    "movq %rsp, %rdx              /* CPU save area */   \n\t"
+    "callq generic_handle_user_exception                \n\t"
+    "iretq                                              \n\t"
+
+    /* a kernel fault means something bad happened, so we stack
+     * everything for the debugger to use, in the GDB frame format */
+    "\nkernel_fault:                                    \n\t"
+    "pushq 6*8(%rsp) /* SS */                           \n\t"
+    "pushq 4*8(%rsp) /* CS */                           \n\t"
+    "pushq 7*8(%rsp) /* EFLAGS */                       \n\t"
+    "pushq 5*8(%rsp) /* RIP */                          \n\t"
+    /* TODO: extend frame size and save FS/GS so we can resume afterwards */
+    "pushq %r15                                         \n\t"
+    "pushq %r14                                         \n\t"
+    "pushq %r13                                         \n\t"
+    "pushq %r12                                         \n\t"
+    "pushq %r11                                         \n\t"
+    "pushq %r10                                         \n\t"
+    "pushq %r9                                          \n\t"
+    "pushq %r8                                          \n\t"
+    "pushq 17*8(%rsp) /* RSP */                         \n\t"
+    "pushq %rbp                                         \n\t"
+    "pushq %rdi                                         \n\t"
+    "pushq %rsi                                         \n\t"
+    "pushq %rdx                                         \n\t"
+    "pushq %rcx                                         \n\t"
+    "pushq %rbx                                         \n\t"
+    "pushq %rax                                         \n\t"
+    "movq 20*8(%rsp), %rdi  /* vector number */         \n\t"
+    "movq 21*8(%rsp), %rsi  /* error code   */          \n\t"
+    "movq %rsp, %rdx       /* save area ptr*/           \n\t"
+    "jmp generic_handle_kernel_exception                \n\t"
+
+
+    /* (Device) interrupt. */
+    "   .type hwirq_common ,@function                   \n\t"
+    "hwirq_common:                                      \n\t"
+    /* If it happened in kernel_mode, simply make userspace runnable.
+     * This is a special case, since interrupts are normally disabled when
+     * entering the kernel. However, they are enabled when there is nothing
+     * to do, and the kernel goes to sleep using wait_for_interrupts() */
+    "testb $3, 16(%rsp) /* if CS.CPL == 0 */            \n\t"
+    "jz call_handle_irq                                 \n\t"
+
+    /* Happened in user mode.
+     * we need to save everything to the dispatcher. */
+    /* decide where to save the state, either enabled or disabled save areas */
+    "pushq %rdx                                         \n\t"
+    "movq dcb_current(%rip), %rdx /* rdx = dcb_current */       \n\t"
+    "movq "XTR(OFFSETOF_DCB_DISP)"(%rdx), %rdx /* rdx = dcb_current->disp */\n\t"
+    "cmpl $0, "XTR(OFFSETOF_DISP_DISABLED)"(%rdx) /* disp->disabled ? */\n\t"
+    "jne irq_save_disabled                              \n\t"
+    "pushq %rbx                                         \n\t"
+    "movq 24(%rsp), %rbx     /* rbx = faulting IP */    \n\t"
+    "cmpq "XTR(OFFSETOF_DISP_X86_64_CRIT_PC_LOW)"(%rdx), %rbx /* crit_pc_low <= rip? */\n\t"
+    "jae irq_disabled_test                              \n\t"
+    "\nirq_save_enabled:                                \n\t"
+    "popq %rbx                                          \n\t"
+    "addq $"XTR(OFFSETOF_DISP_X86_64_ENABLED_AREA)", %rdx /* rdx = enabled_save_area */\n\t"
+    "jmp irq_do_save                                    \n\t"
+    "\nirq_disabled_test:                               \n\t"
+    "cmpq "XTR(OFFSETOF_DISP_X86_64_CRIT_PC_HIGH)"(%rdx), %rbx /* crit_pc_high > rip? */\n\t"
+    "jae irq_save_enabled                               \n\t"
+    "popq %rbx                                          \n\t"
+    "\nirq_save_disabled:                               \n\t"
+    "addq $"XTR(OFFSETOF_DISP_X86_64_DISABLED_AREA)", %rdx /* disabled_save_area */\n\t"
+
+    /* save to the save area. at this point, rdx = save area ptr,
+     * rsp+8 = vector number, rsp+16 = CPU-stacked regisers */
+    "\nirq_do_save:                                     \n\t"
+    "movq %rax,  0*8(%rdx)                              \n\t"
+    "movq %rbx,  1*8(%rdx)                              \n\t"
+    "movq %rcx,  2*8(%rdx)                              \n\t"
+    "popq %rax                    /* original rdx */    \n\t"
+    "movq %rax,  3*8(%rdx)                              \n\t"
+    "movq %rsi,  4*8(%rdx)                              \n\t"
+    "movq %rdi,  5*8(%rdx)                              \n\t"
+    "movq %rbp,  6*8(%rdx)                              \n\t"
+    "movq %r8,   8*8(%rdx)                              \n\t"
+    "movq %r9,   9*8(%rdx)                              \n\t"
+    "movq %r10, 10*8(%rdx)                              \n\t"
+    "movq %r11, 11*8(%rdx)                              \n\t"
+    "movq %r12, 12*8(%rdx)                              \n\t"
+    "movq %r13, 13*8(%rdx)                              \n\t"
+    "movq %r14, 14*8(%rdx)                              \n\t"
+    "movq %r15, 15*8(%rdx)                              \n\t"
+    "mov %fs, "XTR(OFFSETOF_FS_REG)"(%rdx)              \n\t"
+    "mov %gs, "XTR(OFFSETOF_GS_REG)"(%rdx)              \n\t"
+    "popq %rdi                    /* vector number */   \n\t"
+    "movq %rsp, %rsi              /* CPU save area */   \n\t"
+    "jmp generic_handle_irq /* NB: rdx = disp save ptr*/\n\t"
+
+    "\ncall_handle_irq:                                 \n\t"
+    "popq %rdi                                          \n\t"
+    "callq handle_irq                                   \n\t"
+);
+
+// CPU exceptions
+HW_EXCEPTION_NOERR(0);
+HW_EXCEPTION_NOERR(1);
+HW_EXCEPTION_NOERR(2);
+HW_EXCEPTION_NOERR(3);
+HW_EXCEPTION_NOERR(4);
+HW_EXCEPTION_NOERR(5);
+HW_EXCEPTION_NOERR(6);
+HW_EXCEPTION_NOERR(7);
+HW_EXCEPTION_ERR(8);
+HW_EXCEPTION_NOERR(9);
+HW_EXCEPTION_ERR(10);
+HW_EXCEPTION_ERR(11);
+HW_EXCEPTION_ERR(12);
+HW_EXCEPTION_ERR(13);
+HW_EXCEPTION_ERR(14);
+HW_EXCEPTION_NOERR(16);
+HW_EXCEPTION_ERR(17);
+HW_EXCEPTION_NOERR(18);
+HW_EXCEPTION_NOERR(19);
+
+// Classic PIC interrupts
+HW_IRQ(32);
+HW_IRQ(33);
+HW_IRQ(34);
+HW_IRQ(35);
+HW_IRQ(36);
+HW_IRQ(37);
+HW_IRQ(38);
+HW_IRQ(39);
+HW_IRQ(40);
+HW_IRQ(41);
+HW_IRQ(42);
+HW_IRQ(43);
+HW_IRQ(44);
+HW_IRQ(45);
+HW_IRQ(46);
+HW_IRQ(47);
+
+// Generic interrupts
+HW_IRQ(48);
+HW_IRQ(49);
+HW_IRQ(50);
+HW_IRQ(51);
+HW_IRQ(52);
+HW_IRQ(53);
+HW_IRQ(54);
+HW_IRQ(55);
+HW_IRQ(56);
+HW_IRQ(57);
+HW_IRQ(58);
+HW_IRQ(59);
+HW_IRQ(60);
+HW_IRQ(61);
+
+// Trace IPIs
+HW_IRQ(62);
+HW_IRQ(63);
+
+// Local APIC interrupts
+HW_IRQ(249);
+HW_IRQ(250);
+HW_IRQ(251);
+HW_IRQ(252);
+HW_IRQ(253);
+HW_IRQ(254);
+
+// Reserved as "unhandled exception" handler
+HW_EXCEPTION_NOERR(666);
+
+#define ERR_PF_PRESENT          (1 << 0)
+#define ERR_PF_READ_WRITE       (1 << 1)
+#define ERR_PF_USER_SUPERVISOR  (1 << 2)
+#define ERR_PF_RESERVED         (1 << 3)
+#define ERR_PF_INSTRUCTION      (1 << 4)
+
+/// Number of (reserved) hardware exceptions
+#define NEXCEPTIONS             32
+
+/// Size of hardware IRQ dispatch table == #NIDT - #NEXCEPTIONS exceptions
+#define NDISPATCH               (NIDT - NEXCEPTIONS)
+
+/**
+ * \brief Interrupt Descriptor Table (IDT) for processor this kernel is running
+ * on.
+ */
+static struct gate_descriptor idt[NIDT] __attribute__ ((aligned (16)));
+
+/**
+ * \brief User-space IRQ dispatch table.
+ *
+ * This is essentially a big CNode holding #NDISPATCH capability
+ * entries to local endpoints of user-space applications listening to
+ * the interrupts.
+ */
+static struct cte irq_dispatch[NDISPATCH];
+
+#if CONFIG_TRACE && NETWORK_STACK_TRACE
+#define TRACE_ETHERSRV_MODE 1
+#endif // CONFIG_TRACE && NETWORK_STACK_TRACE
+
+/**
+ * \brief Send interrupt notification to user-space listener.
+ *
+ * Sends an interrupt notification IDC to a local endpoint that
+ * listens for IRQ notifications.
+ *
+ * \param irq   IRQ# to send in notification.
+ */
+static uint32_t pkt_interrupt_count = 0;
+static void send_user_interrupt(int irq)
+{
+    assert(irq >= 0 && irq < NDISPATCH);
+    struct capability   *cap = &irq_dispatch[irq].cap;
+
+    // Return on null cap (unhandled interrupt)
+    if(cap->type == ObjType_Null) {
+        printk(LOG_WARN, "unhandled IRQ %d\n", irq);
+        return;
+    }
+
+    if (irq == 0) {
+//     printf("packet interrupt: %d: count %"PRIu32"\n", irq, pkt_interrupt_count);
+        ++pkt_interrupt_count;
+#if NETWORK_STACK_TRACE
+    trace_event(TRACE_SUBSYS_NNET, TRACE_EVENT_NNET_UIRQ, pkt_interrupt_count);
+#endif // NETWORK_STACK_TRACE
+/*
+        if (pkt_interrupt_count >= 60){
+            printf("interrupt number %"PRIu32"\n", pkt_interrupt_count);
+        }
+*/
+    }
+//    printf("Interrupt %d\n", irq);
+    // Otherwise, cap needs to be an endpoint
+    assert(cap->type == ObjType_EndPoint);
+
+    // send empty message as notification
+    errval_t err = lmp_deliver_notification(cap);
+    if (err_is_fail(err)) {
+        if (err_no(err) == SYS_ERR_LMP_BUF_OVERFLOW) {
+            struct dispatcher_shared_generic *disp =
+                get_dispatcher_shared_generic(cap->u.endpoint.listener->disp);
+            printk(LOG_DEBUG, "%.*s: IRQ message buffer overflow\n",
+                   DISP_NAME_LEN, disp->name);
+        } else {
+            printk(LOG_ERR, "Unexpected error delivering IRQ\n");
+        }
+    }
+
+#ifdef SCHEDULER_RR
+    /* XXX: run the handler dispatcher immediately
+     * we shouldn't do this (we should let the scheduler decide), but because
+     * our default scheduler is braindead, this is a quick hack to make sure
+     * that mostly-sane things happen
+     */
+    dispatch(cap->u.endpoint.listener);
+#else
+    dispatch(schedule());
+#endif
+}
+
+errval_t irq_table_set(unsigned int nidt, capaddr_t endpoint)
+{
+    errval_t err;
+    struct cte *recv;
+
+    err = caps_lookup_slot(&dcb_current->cspace.cap, endpoint,
+                           CPTR_BITS, &recv, CAPRIGHTS_WRITE);
+    if (err_is_fail(err)) {
+        return err_push(err, SYS_ERR_IRQ_LOOKUP);
+    }
+
+    assert(recv != NULL);
+
+    // Return w/error if cap is not an endpoint
+    if(recv->cap.type != ObjType_EndPoint) {
+        return SYS_ERR_IRQ_NOT_ENDPOINT;
+    }
+
+    // Return w/error if no listener on endpoint
+    if(recv->cap.u.endpoint.listener == NULL) {
+        return SYS_ERR_IRQ_NO_LISTENER;
+    }
+
+    if(nidt < NDISPATCH) {
+        // check that we don't overwrite someone else's handler
+        if (irq_dispatch[nidt].cap.type != ObjType_Null) {
+            printf("kernel: installing new handler for IRQ %d\n", nidt);
+        }
+        err = caps_copy_to_cte(&irq_dispatch[nidt], recv, false, 0, 0);
+
+        printf("kernel: %u: installing handler for IRQ %d\n", my_core_id, nidt);
+#if 0
+        if (err_is_ok(err)) {
+            // Unmask interrupt if on PIC
+            if(nidt < 16) {
+                pic_toggle_irq(nidt, true);
+            }
+        }
+#endif
+        return err;
+    } else {
+        return SYS_ERR_IRQ_INVALID;
+    }
+}
+
+errval_t irq_table_delete(unsigned int nidt)
+{
+    if(nidt < NDISPATCH) {
+        irq_dispatch[nidt].cap.type = ObjType_Null;
+#if 0
+        pic_toggle_irq(nidt, false);
+#endif
+        return SYS_ERR_OK;
+    } else {
+        return SYS_ERR_IRQ_INVALID;
+    }
+}
+
+/**
+ * \brief Handles kernel exceptions
+ *
+ * \param vec   Vector number of exception
+ * \param error Error code from CPU, or 0 for an exception without an error code
+ * \param gdb_save_frame Pointer to save area for registers stacked by trap handler
+ */
+static __attribute__ ((used,noreturn))
+    void generic_handle_kernel_exception(uint64_t vec, uint64_t error,
+                                         uintptr_t *gdb_save_frame)
+{
+    lvaddr_t fault_address;
+    char *descr;
+
+    if (vec == 666) {
+        panic("unhandled kernel exception (vector 666)");
+    }
+
+    assert(vec < NEXCEPTIONS);
+
+    printk(LOG_PANIC, "exception %d (error code 0x%lx): ", (int)vec, error);
+
+    if (vec == ia32_vec_pf) {
+        printf("%s page fault due to %s%s, while in %s mode%s\n",
+               error & ERR_PF_READ_WRITE ? "write" : "read",
+               error & ERR_PF_PRESENT ? "access violation" : "page not present",
+               error & ERR_PF_RESERVED ? ", reserved bits set in page table"
+               : "",
+               error & ERR_PF_USER_SUPERVISOR ? "user" : "supervisor",
+               error & ERR_PF_INSTRUCTION ? ", by instruction fetch" : "");
+
+        __asm volatile("mov %%cr2, %[fault_address]"
+                       : [fault_address] "=r" (fault_address));
+        printf("Address that caused the fault: 0x%lx\n", fault_address);
+
+    } else if ((descr = ia32_exc_vec_describe(vec))) {
+        printf("%s\n", descr);
+    } else {
+        printf("unhandled exception!\n");
+    }
+
+    // Print faulting instruction pointer
+    uintptr_t rip = gdb_save_frame[GDB_X86_64_RIP_REG];
+    printf("Faulting instruction pointer (or next instruction): 0x%lx\n", rip);
+    printf("  => i.e. unrelocated kernel address 0x%lx\n",
+           rip - (uintptr_t)&_start_kernel + X86_64_START_KERNEL_PHYS);
+
+    printf("Registers:\n");
+    printf(" rax: 0x%016lx  r8 : 0x%016lx\n",
+           gdb_save_frame[GDB_X86_64_RAX_REG],
+           gdb_save_frame[GDB_X86_64_R8_REG]);
+    printf(" rbx: 0x%016lx  r9 : 0x%016lx\n",
+           gdb_save_frame[GDB_X86_64_RBX_REG],
+           gdb_save_frame[GDB_X86_64_R9_REG]);
+    printf(" rcx: 0x%016lx  r10: 0x%016lx\n",
+           gdb_save_frame[GDB_X86_64_RCX_REG],
+           gdb_save_frame[GDB_X86_64_R10_REG]);
+    printf(" rdx: 0x%016lx  r11: 0x%016lx\n",
+           gdb_save_frame[GDB_X86_64_RDX_REG],
+           gdb_save_frame[GDB_X86_64_R11_REG]);
+    printf(" rsp: 0x%016lx  r12: 0x%016lx\n",
+           gdb_save_frame[GDB_X86_64_RSP_REG],
+           gdb_save_frame[GDB_X86_64_R12_REG]);
+    printf(" rdi: 0x%016lx  r13: 0x%016lx\n",
+           gdb_save_frame[GDB_X86_64_RDI_REG],
+           gdb_save_frame[GDB_X86_64_R13_REG]);
+    printf(" rsi: 0x%016lx  r14: 0x%016lx\n",
+           gdb_save_frame[GDB_X86_64_RSI_REG],
+           gdb_save_frame[GDB_X86_64_R14_REG]);
+    printf(" rip: 0x%016lx  r15: 0x%016lx\n",
+           gdb_save_frame[GDB_X86_64_RIP_REG],
+           gdb_save_frame[GDB_X86_64_R15_REG]);
+
+    // Print the top 10 stack words
+    printf("Top o' stack:\n");
+    for(int i = 0; i < 10; i++) {
+        unsigned long *p = (unsigned long *)gdb_save_frame[GDB_X86_64_RSP_REG] + i;
+        printf(" %d \t 0x%016lx (%lu)\n", i, *p, *p);
+    }
+
+    // Drop to the debugger
+    gdb_handle_exception(vec, gdb_save_frame);
+    panic("gdb_handle_exception returned");
+}
+
+/**
+ * \brief copies CPU-stacked registers to a dispatcher save area
+ */
+static void copy_cpu_frame_to_dispatcher(
+    uintptr_t * NONNULL COUNT(X86_SAVE_AREA_SIZE) cpu_save_area,
+    struct registers_x86_64 *disp_save_area)
+{
+    // sanity checks
+    assert((cpu_save_area[X86_SAVE_EFLAGS] & USER_EFLAGS) == USER_EFLAGS);
+
+    disp_save_area->rsp = cpu_save_area[X86_SAVE_RSP];
+    disp_save_area->eflags = cpu_save_area[X86_SAVE_EFLAGS];
+    disp_save_area->rip = cpu_save_area[X86_SAVE_RIP];
+}
+
+/**
+ * \brief Handles user-mode exceptions
+ *
+ * \param vec   Vector number of exception
+ * \param error Error code from CPU, or 0 for an exception without an error code
+ * \param cpu_save_area  Pointer to save area for registers stacked by CPU
+ * \param disp_save_area Pointer to save area in dispatcher
+ */
+static __attribute__ ((used))
+    void generic_handle_user_exception(int vec, uint64_t error,
+                uintptr_t * NONNULL COUNT(X86_SAVE_AREA_SIZE) cpu_save_area,
+                struct registers_x86_64 *disp_save_area)
+{
+    assert(dcb_current->disp_cte.cap.type == ObjType_Frame);
+    dispatcher_handle_t handle = dcb_current->disp;
+    struct dispatcher_shared_generic *disp =
+        get_dispatcher_shared_generic(handle);
+    uint64_t rip = cpu_save_area[X86_SAVE_RIP];
+    uint64_t rsp = cpu_save_area[X86_SAVE_RSP];
+    lvaddr_t fault_address, handler = 0, param = 0;
+
+    assert(vec < NEXCEPTIONS);
+    assert((cpu_save_area[X86_SAVE_CS] & 0x3) != 0); // CS.CPL > 0
+
+    copy_cpu_frame_to_dispatcher(cpu_save_area, disp_save_area);
+
+    bool disabled = dispatcher_is_disabled_ip(handle, rip);
+    dcb_current->disabled = disabled;
+
+    if (disabled) {
+        dcb_current->faults_taken++;
+    }
+
+    // Store FPU state if it's used
+    // Do this for every trap when the current domain used the FPU
+    // Do it for FPU not available traps in any case (to save the last FPU user)
+    // XXX: Need to reset fpu_dcb when that DCB is deleted
+    if(fpu_dcb != NULL &&
+       (fpu_dcb == dcb_current || vec == IDT_NM)) {
+        struct dispatcher_shared_generic *dst =
+            get_dispatcher_shared_generic(fpu_dcb->disp);
+
+        // Turn FPU trap off temporarily for saving its state
+        bool trap = fpu_trap_get();
+        fpu_trap_off();
+
+        if(fpu_dcb->disabled) {
+            fpu_save(dispatcher_get_disabled_fpu_save_area(fpu_dcb->disp));
+           dst->fpu_used = 1;
+        } else {
+            assert(!fpu_dcb->disabled);
+            fpu_save(dispatcher_get_enabled_fpu_save_area(fpu_dcb->disp));
+           dst->fpu_used = 2;
+        }
+
+        if(trap) {
+            fpu_trap_on();
+        }
+    }
+
+    if (vec == IDT_PF) { // Page fault
+        // Get fault address
+        __asm volatile("mov %%cr2, %[fault_address]"
+                       : [fault_address] "=r" (fault_address));
+
+        printk(LOG_WARN, "user page fault%s in '%.*s': addr %lx IP %lx SP %lx "
+                         "error 0x%lx\n",
+               disabled ? " WHILE DISABLED" : "", DISP_NAME_LEN,
+               disp->name, fault_address, rip, rsp, error);
+
+        /* sanity-check that the trap handler saved in the right place */
+        assert((disabled && disp_save_area == dispatcher_get_trap_save_area(handle))
+               || (!disabled && disp_save_area == dispatcher_get_enabled_save_area(handle)));
+        if (disabled) {
+            handler = disp->dispatcher_pagefault_disabled;
+        } else {
+            handler = disp->dispatcher_pagefault;
+        }
+        param = fault_address;
+    } else if (vec == IDT_NMI) {
+        printk(LOG_WARN, "NMI - ignoring\n");
+        dispatch(dcb_current);
+    } else if (vec == IDT_NM) {     // device not available (FPU) exception
+        debug(SUBSYS_DISPATCH, "FPU trap in %.*s at 0x%" PRIxPTR "\n",
+              DISP_NAME_LEN, disp->name, rip);
+        assert(!dcb_current->is_vm_guest);
+
+        /* Intel system programming part 1: 2.3.1, 2.5, 11, 12.5.1
+         * clear the TS flag (flag that says, that the FPU is not available)
+         */
+        clts();
+
+        // Remember FPU-using DCB
+        fpu_dcb = dcb_current;
+
+        // Wipe FPU for protection and to initialize it in case we trapped while
+        // disabled
+        fpu_init();
+
+        if(disabled) {
+            // Initialize FPU (done earlier) and ignore trap
+            dispatch(dcb_current);
+        } else {
+            // defer trap to user-space
+            // FPUs are switched eagerly while disabled, there should be no trap
+            assert(disp_save_area == dispatcher_get_trap_save_area(handle));
+            handler = disp->dispatcher_trap;
+            param = vec;
+        }
+    } else if (vec == IDT_MF) {
+        uint16_t fpu_status;
+
+        __asm volatile("fnstsw %0" : "=a" (fpu_status));
+
+        printk(LOG_WARN, "FPU error%s in '%.*s': IP %" PRIxPTR " FPU status %x\n",
+               disabled ? " WHILE DISABLED" : "", DISP_NAME_LEN,
+               disp->name, rip, fpu_status);
+
+        handler = disp->dispatcher_trap;
+        param = vec;
+    } else if (vec == IDT_MC) {
+        // TODO: provide more useful information about the cause
+        panic("machine check exception while in user mode");
+    } else { // All other traps
+        printk(LOG_WARN, "user trap #%d%s in '%.*s': IP %lx, error %lx\n",
+               vec, disabled ? " WHILE DISABLED" : "",
+               DISP_NAME_LEN, disp->name, rip, error);
+        assert(disp_save_area == dispatcher_get_trap_save_area(handle));
+        if (disabled) {
+            if (vec == IDT_DB) { // debug exception: just continue
+                resume(dispatcher_get_trap_save_area(handle));
+            } else {
+
+                // can't handle a trap while disabled: nowhere safe to deliver it
+                scheduler_remove(dcb_current);
+                dispatch(schedule());
+            }
+        } else {
+            handler = disp->dispatcher_trap;
+            param = vec;
+        }
+    }
+
+    // Make unrunnable if it has taken too many faults
+    if (dcb_current->faults_taken > 2) {
+        printk(LOG_WARN, "generic_handle_user_exception: too many faults, "
+               "making domain unrunnable\n");
+        dcb_current->faults_taken = 0; // just in case it gets restarted
+        scheduler_remove(dcb_current);
+        dispatch(schedule());
+    }
+
+    /* resume user to save area */
+    disp->disabled = 1;
+    if(handler == 0) {
+        printk(LOG_WARN, "no suitable handler for this type of fault, "
+               "making domain unrunnable\n");
+        scheduler_remove(dcb_current);
+        dispatch(schedule());
+    } else {
+        cpu_save_area[X86_SAVE_RIP] = handler;
+        cpu_save_area[X86_SAVE_EFLAGS] = USER_EFLAGS;
+    }
+
+    /* XXX: get GCC to load up the argument registers before returning */
+    register uintptr_t arg0 __asm ("%rdi") = disp->udisp;
+    register uintptr_t arg1 __asm ("%rsi") = param;
+    register uintptr_t arg2 __asm ("%rdx") = error;
+    register uintptr_t arg3 __asm ("%rcx") = rip;
+    __asm volatile("" :: "r" (arg0), "r" (arg1), "r" (arg2), "r" (arg3));
+}
+
+static void
+update_kernel_now(void)
+{
+    uint64_t tsc_now = rdtsc();
+    #ifdef CONFIG_ONESHOT_TIMER
+    uint64_t ticks = tsc_now - tsc_lasttime;
+    kernel_now += ticks / timing_get_tsc_per_ms();
+    #else // !CONFIG_ONESHOT_TIMER
+    // maintain compatibility with old behaviour. Not sure if it is
+    // actually needed. -AKK
+    //
+    // Ignore timeslice if it happens too closely (less than half
+    // of the TSC ticks that are supposed to pass) to the last.
+    // In that case we have just synced timers and see a spurious
+    // APIC timer interrupt.
+    if(tsc_now - tsc_lasttime >
+       (kernel_timeslice * timing_get_tsc_per_ms()) / 2) {
+        kernel_now += kernel_timeslice;
+    }
+    #endif // CONFIG_ONESHOT_TIMER
+    tsc_lasttime = tsc_now;
+}
+
+/// Handle an IRQ that arrived, either while in user or kernel mode (HLT)
+static __attribute__ ((used)) void handle_irq(int vector)
+{
+    debug(SUBSYS_DISPATCH, "IRQ vector %d while %s\n", vector,
+          dcb_current ? (dcb_current->disabled ? "disabled": "enabled") : "in kernel");
+
+    int irq = vector - NEXCEPTIONS;
+
+    // if we were in wait_for_interrupt(), unmask timer before running userspace
+    if (dcb_current == NULL && kernel_ticks_enabled) {
+        apic_unmask_timer();
+    }
+
+#if TRACE_ETHERSRV_MODE
+    trace_event(TRACE_SUBSYS_NNET, TRACE_EVENT_NNET_IRQ, vector);
+#endif // TRACE_ETHERSRV_MODE
+
+    // APIC timer interrupt: handle in kernel and reschedule
+    if (vector == APIC_TIMER_INTERRUPT_VECTOR) {
+        apic_eoi();
+        assert(kernel_ticks_enabled);
+        update_kernel_now();
+        trace_event(TRACE_SUBSYS_KERNEL, TRACE_EVENT_KERNEL_TIMER, kernel_now);
+        wakeup_check(kernel_now);
+    } else if (vector == APIC_PERFORMANCE_INTERRUPT_VECTOR) {
+        // Handle performance counter overflow
+        // Reset counters
+        perfmon_measure_reset();
+        if(dcb_current!=NULL) {
+            // Get faulting instruction pointer
+            struct registers_x86_64 *disp_save_area = dcb_current->disabled ?
+                dispatcher_get_disabled_save_area(dcb_current->disp) :
+                dispatcher_get_enabled_save_area(dcb_current->disp);
+            struct dispatcher_shared_generic *disp =
+                get_dispatcher_shared_generic(dcb_current->disp);
+
+            // Setup data structure for LMP transfer to user level handler
+            struct perfmon_overflow_data data = {
+                .ip = disp_save_area->rip
+            };
+            strncpy(data.name, disp->name, PERFMON_DISP_NAME_LEN);
+
+            // Call overflow handler represented by endpoint
+            extern struct capability perfmon_callback_ep;
+            errval_t err;
+            size_t payload_len = sizeof(struct perfmon_overflow_data)/
+                sizeof(uintptr_t)+1;
+            err = lmp_deliver_payload(&perfmon_callback_ep,
+                                      NULL,
+                                      (uintptr_t*) &data,
+                                      payload_len,
+                                      false);
+
+            // Make sure delivery was okay. SYS_ERR_LMP_BUF_OVERFLOW is okay for now
+            assert(err_is_ok(err) || err_no(err)==SYS_ERR_LMP_BUF_OVERFLOW);
+        } else {
+            // This should never happen, as interrupts are disabled in kernel
+            printf("Performance counter overflow interrupt from "
+                   "apic in kernel level\n");
+        }
+        apic_eoi();
+    } else if (vector == APIC_ERROR_INTERRUPT_VECTOR) {
+        printk(LOG_ERR, "APIC error interrupt fired!\n");
+        xapic_esr_t esr = apic_get_esr();
+        char str[256];
+        xapic_esr_prtval(str, 256, esr);
+        printf("%s\n", str);
+        apic_eoi();
+    } else if (vector == APIC_INTER_CORE_VECTOR) {
+        apic_eoi();
+        ipi_handle_notify();
+    }
+#if 0
+ else if (irq >= 0 && irq <= 15) { // classic PIC device interrupt
+     printk(LOG_NOTE, "got interrupt %d!\n", irq);
+
+        apic_eoi();
+
+        // only handle PIC interrupts on the BSP core
+        if (apic_is_bsp()) {
+            if (pic_have_interrupt(irq)) {
+                pic_eoi(irq);
+                send_user_interrupt(irq);
+            } else { // no interrupt pending, check for a different one (!)
+                irq = pic_pending_interrupt();
+                if (irq == -1) { // really nothing pending
+                    printk(LOG_NOTE, "spurious interrupt (IRQ %d)\n", irq);
+                } else { // why does this happen?! -AB
+                    printk(LOG_NOTE, "IRQ %d reported on wrong vector (%d)\n",
+                           irq, vector - NEXCEPTIONS);
+                    pic_eoi(irq);
+                    send_user_interrupt(irq);
+                }
+            }
+        }
+    }
+#endif
+    else { // APIC device interrupt (or IPI)
+        //printk(LOG_NOTE, "interrupt %d vector %d!\n", irq, vector);
+        apic_eoi();
+        send_user_interrupt(irq);
+    }
+
+    // reschedule (because the runnable processes may have changed) and dispatch
+    /* FIXME: the round-robin scheduler doesn't do the best thing here:
+     * it always picks the next task, but we only really want to do that on
+     * a timer tick
+     */
+    dispatch(schedule());
+    panic("dispatch() returned");
+}
+
+/**
+ * \brief Handles device interrupts that arrive while in user mode
+ *
+ * \param vector    Vector number
+ * \param cpu_save_area  Pointer to save area for registers stacked by CPU
+ * \param disp_save_area Pointer to save area in dispatcher
+ */
+static __attribute__ ((used)) void
+generic_handle_irq(int vector,
+                   uintptr_t * NONNULL COUNT(X86_SAVE_AREA_SIZE) cpu_save_area,
+                   struct registers_x86_64 *disp_save_area)
+{
+    assert(dcb_current->disp_cte.cap.type == ObjType_Frame);
+    dispatcher_handle_t handle = dcb_current->disp;
+    uint64_t rip = cpu_save_area[X86_SAVE_RIP];
+    assert(vector < NIDT && vector >= NEXCEPTIONS);
+
+    // Copy CPU-saved registers to dispatcher save area
+    copy_cpu_frame_to_dispatcher(cpu_save_area, disp_save_area);
+
+    /* sanity-check that the trap handler saved in the right place,
+     * and update disabled flag in DCB */
+    if (disp_save_area == dispatcher_get_disabled_save_area(handle)) {
+        assert(dispatcher_is_disabled_ip(handle, rip));
+        dcb_current->disabled = true;
+    } else {
+        assert(disp_save_area == dispatcher_get_enabled_save_area(handle));
+        assert(!dispatcher_is_disabled_ip(handle, rip));
+        dcb_current->disabled = false;
+    }
+
+    handle_irq(vector);
+}
+
+/* Utility function for code below; initialises a gate_descriptor */
+static void setgd(struct gate_descriptor *gd, void (* handler)(void),
+                  int ist, int type, int dpl, int selector)
+{
+    memset(gd, 0, sizeof(struct gate_descriptor));
+    gd->gd_looffset = (uintptr_t)handler & ((1UL << 16) - 1);
+    gd->gd_hioffset = (uintptr_t)handler >> 16;
+    gd->gd_selector = selector;
+    gd->gd_ist = ist;
+    gd->gd_type = type;
+    gd->gd_dpl = dpl;
+    gd->gd_p = 1;
+}
+
+/**
+ * \brief Sets up the default IDT for current CPU.
+ */
+void setup_default_idt(void)
+{
+    struct region_descriptor region = {         // set default IDT
+        .rd_limit = NIDT * sizeof(idt[0]) - 1,
+        .rd_base = (uint64_t)&idt
+    };
+    int i;
+
+    // reset IDT
+    memset((void *)&idt, 0, NIDT * sizeof(idt[0]));
+
+    // initialize IDT with default generic handlers
+    for (i = 0; i < NIDT; i++)
+        setgd(&idt[i], hwexc_666, 0, SDT_SYSIGT, SEL_KPL,
+              GSEL(KCODE_SEL, SEL_KPL));
+
+    /* Setup exception handlers */
+    setgd(&idt[0], hwexc_0, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[1], hwexc_1, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[2], hwexc_2, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[3], hwexc_3, 0, SDT_SYSIGT, SEL_UPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[4], hwexc_4, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[5], hwexc_5, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[6], hwexc_6, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[7], hwexc_7, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[8], hwexc_8, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[9], hwexc_9, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[10], hwexc_10, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[11], hwexc_11, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[12], hwexc_12, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[13], hwexc_13, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[14], hwexc_14, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    // Interrupt 15 is undefined
+    setgd(&idt[16], hwexc_16, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[17], hwexc_17, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[18], hwexc_18, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[19], hwexc_19, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    // Interrupts 20 - 31 are reserved
+
+    /* Setup classic PIC interrupt handlers */
+    setgd(&idt[32], hwirq_32, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[33], hwirq_33, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[34], hwirq_34, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[35], hwirq_35, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[36], hwirq_36, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[37], hwirq_37, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[38], hwirq_38, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[39], hwirq_39, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[40], hwirq_40, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[41], hwirq_41, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[42], hwirq_42, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[43], hwirq_43, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[44], hwirq_44, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[45], hwirq_45, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[46], hwirq_46, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[47], hwirq_47, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+
+    // Setup generic interrupt handlers
+    setgd(&idt[48], hwirq_48, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[49], hwirq_49, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[50], hwirq_50, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[50], hwirq_50, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[51], hwirq_51, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[52], hwirq_52, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[53], hwirq_53, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[54], hwirq_54, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[55], hwirq_55, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[56], hwirq_56, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[57], hwirq_57, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[58], hwirq_58, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[59], hwirq_59, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[60], hwirq_60, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[61], hwirq_61, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+
+    // XXX Interrupts used for TRACE IPIs
+    setgd(&idt[62], hwirq_62, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[63], hwirq_63, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+
+    // Setup local APIC interrupt handlers
+    setgd(&idt[249], hwirq_249, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[250], hwirq_250, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[251], hwirq_251, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[252], hwirq_252, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[253], hwirq_253, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+    setgd(&idt[254], hwirq_254, 0, SDT_SYSIGT, SEL_KPL, GSEL(KCODE_SEL, SEL_KPL));
+
+    /* Load IDT register */
+    __asm volatile("lidt %0" :: "m" (region));
+}
diff --git a/kernel/arch/k1om/linker.lds.in b/kernel/arch/k1om/linker.lds.in
new file mode 100644 (file)
index 0000000..63152dc
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2008, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <target/x86_64/offsets_target.h>
+
+OUTPUT_FORMAT("elf64-x86-64")
+OUTPUT_ARCH("i386:x86-64")
+
+_start_kernel = X86_64_START_KERNEL_PHYS;
+
+SECTIONS {
+        . = ALIGN(4k);
+        .text X86_64_START_KERNEL_PHYS : ALIGN(4k)
+        {
+                *(.text);
+        }
+        _end_kernel_text = .;
+
+        . = ALIGN(4k);
+        .rodata . :
+        {
+                *(.rodata);
+        }
+
+        .bss . :
+        {
+                *(.bss);
+        }
+
+        _end_kernel = .;
+
+        /***** These sections get discarded *****/
+        /DISCARD/ :
+        {
+                /* Discard exception handler frames and headers -- we don't use em */
+                *(.eh_frame);
+                *(.eh_frame_hdr);
+               *(.note.gnu.build-id);
+                *(.interp);
+/*              *(.dynsym); */
+/*              *(.dynstr); */
+/*              *(.hash); */
+/*              *(.gnu.hash); */
+                *(.dynamic);
+        }
+}
diff --git a/kernel/arch/k1om/microbenchmarks.c b/kernel/arch/k1om/microbenchmarks.c
new file mode 100644 (file)
index 0000000..78e94cf
--- /dev/null
@@ -0,0 +1,69 @@
+/**
+ * \file
+ * \brief Architecture-specific microbenchmarks.
+ */
+
+/*
+ * Copyright (c) 2007, 2008, 2009, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <kernel.h>
+#include <microbenchmarks.h>
+#include <apic.h>
+#include <x86.h>
+
+// address space switch (mov to cr3)
+static int asswitch_func(struct microbench *mb)
+{
+    uint64_t start, end;
+    uint64_t asvalue;
+    
+    // Put the cr3 value in the asvalue register for now
+    __asm__ __volatile__("mov %%cr3, %0" : "=r" (asvalue));
+    
+    start = rdtscp();
+    for (int i = 0; i < MICROBENCH_ITERATIONS; i++) {
+        __asm__ __volatile__(
+            "mov %0, %%cr3"
+            :
+            : "r" (asvalue));
+    }
+    end = rdtscp();
+    
+    mb->result = end - start;
+    
+    return 0;
+}
+
+static int wrmsr_func(struct microbench *mb)
+{
+    uint64_t start, end;
+    
+    start = rdtscp();
+    for (int i = 0; i < MICROBENCH_ITERATIONS; i++) {
+        wrmsr(MSR_IA32_FSBASE, 0);
+    }
+    end = rdtscp();
+
+    mb->result = end - start;
+    
+    return 0;
+}
+
+struct microbench arch_benchmarks[] = {
+    {
+        .name = "wrmsr",
+        .run_func = wrmsr_func
+    },
+    {
+        .name = "address space switch (mov to cr3)",
+        .run_func = asswitch_func
+    }
+};
+
+size_t arch_benchmarks_size = sizeof(arch_benchmarks) / sizeof(struct microbench);
diff --git a/kernel/arch/k1om/page_mappings_arch.c b/kernel/arch/k1om/page_mappings_arch.c
new file mode 100644 (file)
index 0000000..3712fcc
--- /dev/null
@@ -0,0 +1,465 @@
+/**
+ * \file
+ * \brief
+ */
+
+/*
+ * Copyright (c) 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <kernel.h>
+#include <dispatch.h>
+#include <target/x86_64/paging_kernel_target.h>
+#include <target/x86_64/offsets_target.h>
+#include <paging_kernel_arch.h>
+#include <mdb/mdb_tree.h>
+#include <string.h>
+#include <barrelfish_kpi/init.h>
+#include <cap_predicates.h>
+
+static inline struct cte *cte_for_cap(struct capability *cap)
+{
+    return (struct cte *) (cap - offsetof(struct cte, cap));
+}
+
+/// Map within a x86_64 non leaf ptable
+static errval_t x86_64_non_ptable(struct capability *dest, cslot_t slot,
+                                  struct capability *src, uintptr_t flags,
+                                  uintptr_t offset, size_t pte_count)
+{
+    if (slot >= X86_64_PTABLE_SIZE) { // Within pagetable
+        return SYS_ERR_VNODE_SLOT_INVALID;
+    }
+
+    if (type_is_vnode(src->type) && pte_count != 1) { // only allow single ptable mappings
+        printf("src type and count mismatch\n");
+        return SYS_ERR_VM_MAP_SIZE;
+    }
+
+    if (slot + pte_count > X86_64_PTABLE_SIZE) { // mapping size ok
+        printf("mapping size invalid (%zd)\n", pte_count);
+        return SYS_ERR_VM_MAP_SIZE;
+    }
+
+    size_t page_size = 0;
+    switch (dest->type) {
+        case ObjType_VNode_x86_64_pml4:
+            if (src->type != ObjType_VNode_x86_64_pdpt) { // Right mapping
+                printf("src type invalid\n");
+                return SYS_ERR_WRONG_MAPPING;
+            }
+            if(slot >= X86_64_PML4_BASE(X86_64_MEMORY_OFFSET)) { // Kernel mapped here
+                return SYS_ERR_VNODE_SLOT_RESERVED;
+            }
+            break;
+        case ObjType_VNode_x86_64_pdpt:
+            // TODO: huge page support, set page_size to HUGE_PAGE_SIZE
+            if (src->type != ObjType_VNode_x86_64_pdir) { // Right mapping
+                printf("src type invalid\n");
+                return SYS_ERR_WRONG_MAPPING;
+            }
+            break;
+        case ObjType_VNode_x86_64_pdir:
+            // TODO: superpage support, set page_size to SUPER_PAGE_SIZE
+            if (src->type != ObjType_VNode_x86_64_ptable) { // Right mapping
+                printf("src type invalid\n");
+                return SYS_ERR_WRONG_MAPPING;
+            }
+            break;
+        default:
+            printf("dest type invalid\n");
+            return SYS_ERR_DEST_TYPE_INVALID;
+    }
+
+    // Convert destination base address
+    genpaddr_t dest_gp   = get_address(dest);
+    lpaddr_t dest_lp     = gen_phys_to_local_phys(dest_gp);
+    lvaddr_t dest_lv     = local_phys_to_mem(dest_lp);
+    // Convert source base address
+    genpaddr_t src_gp   = get_address(src);
+    lpaddr_t src_lp     = gen_phys_to_local_phys(src_gp);
+
+    // set metadata
+    struct cte *src_cte = cte_for_cap(src);
+    src_cte->mapping_info.pte = dest_lp + slot * sizeof(union x86_64_ptable_entry);
+    src_cte->mapping_info.pte_count = pte_count;
+    src_cte->mapping_info.offset = offset;
+
+    cslot_t last_slot = slot + pte_count;
+    for (; slot < last_slot; slot++, offset += page_size) {
+        // Destination
+        union x86_64_pdir_entry *entry = (union x86_64_pdir_entry *)dest_lv + slot;
+
+        if (X86_64_IS_PRESENT(entry)) {
+            // cleanup mapping info
+            // TODO: cleanup already mapped pages
+            memset(&src_cte->mapping_info, 0, sizeof(struct mapping_info));
+            return SYS_ERR_VNODE_SLOT_INUSE;
+        }
+
+        paging_x86_64_map_table(entry, src_lp + offset);
+    }
+
+    return SYS_ERR_OK;
+}
+
+/// Map within a x86_64 ptable
+static errval_t x86_64_ptable(struct capability *dest, cslot_t slot,
+                              struct capability *src, uintptr_t mflags,
+                              uintptr_t offset, size_t pte_count)
+{
+    if (slot >= X86_64_PTABLE_SIZE) { // Within pagetable
+        return SYS_ERR_VNODE_SLOT_INVALID;
+    }
+
+    if (slot + pte_count > X86_64_PTABLE_SIZE) { // mapping size ok
+        printf("mapping size invalid (%zd)\n", pte_count);
+        return SYS_ERR_VM_MAP_SIZE;
+    }
+
+    if (src->type != ObjType_Frame &&
+        src->type != ObjType_DevFrame) { // Right mapping
+        printf("src type invalid\n");
+        return SYS_ERR_WRONG_MAPPING;
+    }
+
+    // check offset within frame
+    genpaddr_t off = offset;
+    if (off + pte_count * X86_64_BASE_PAGE_SIZE > get_size(src)) {
+        printf("frame offset invalid\n");
+        return SYS_ERR_FRAME_OFFSET_INVALID;
+    }
+
+
+    /* Calculate page access protection flags */
+    // Get frame cap rights
+    paging_x86_64_flags_t flags =
+        paging_x86_64_cap_to_page_flags(src->rights);
+    // Mask with provided access rights mask
+    flags = paging_x86_64_mask_attrs(flags, X86_64_PTABLE_ACCESS(mflags));
+    // Add additional arch-specific flags
+    flags |= X86_64_PTABLE_FLAGS(mflags);
+    // Unconditionally mark the page present
+    flags |= X86_64_PTABLE_PRESENT;
+
+    // Convert destination base address
+    genpaddr_t dest_gp   = get_address(dest);
+    lpaddr_t dest_lp     = gen_phys_to_local_phys(dest_gp);
+    lvaddr_t dest_lv     = local_phys_to_mem(dest_lp);
+    // Convert source base address
+    genpaddr_t src_gp   = get_address(src);
+    lpaddr_t src_lp     = gen_phys_to_local_phys(src_gp);
+    // Set metadata
+    struct cte *src_cte = cte_for_cap(src);
+    src_cte->mapping_info.pte = dest_lp + slot * sizeof(union x86_64_ptable_entry);
+    src_cte->mapping_info.pte_count = pte_count;
+    src_cte->mapping_info.offset = offset;
+
+    cslot_t last_slot = slot + pte_count;
+    for (; slot < last_slot; slot++, offset += X86_64_BASE_PAGE_SIZE) {
+        union x86_64_ptable_entry *entry =
+            (union x86_64_ptable_entry *)dest_lv + slot;
+
+        /* FIXME: Flush TLB if the page is already present
+         * in the meantime, since we don't do this, we just fail to avoid
+         * ever reusing a VA mapping */
+        if (X86_64_IS_PRESENT(entry)) {
+            // TODO: cleanup already mapped pages
+            memset(&src_cte->mapping_info, 0, sizeof(struct mapping_info));
+            debug(LOG_WARN, "Trying to remap an already-present page is NYI, but "
+                  "this is most likely a user-space bug!\n");
+            return SYS_ERR_VNODE_SLOT_INUSE;
+        }
+
+        // Carry out the page mapping
+        paging_x86_64_map(entry, src_lp + offset, flags);
+    }
+
+    return SYS_ERR_OK;
+}
+
+typedef errval_t (*mapping_handler_t)(struct capability *dest_cap,
+                                      cslot_t dest_slot,
+                                      struct capability *src_cap,
+                                      uintptr_t flags, uintptr_t offset,
+                                      size_t pte_count);
+
+/// Dispatcher table for the type of mapping to create
+static mapping_handler_t handler[ObjType_Num] = {
+    [ObjType_VNode_x86_64_pml4]   = x86_64_non_ptable,
+    [ObjType_VNode_x86_64_pdpt]   = x86_64_non_ptable,
+    [ObjType_VNode_x86_64_pdir]   = x86_64_non_ptable,
+    [ObjType_VNode_x86_64_ptable] = x86_64_ptable,
+};
+
+
+#define DIAGNOSTIC_ON_ERROR 1
+#define RETURN_ON_ERROR 1
+
+/// Create page mappings
+errval_t caps_copy_to_vnode(struct cte *dest_vnode_cte, cslot_t dest_slot,
+                            struct cte *src_cte, uintptr_t flags,
+                            uintptr_t offset, uintptr_t pte_count)
+{
+    assert(type_is_vnode(dest_vnode_cte->cap.type));
+
+    struct capability *src_cap  = &src_cte->cap;
+    struct capability *dest_cap = &dest_vnode_cte->cap;
+    mapping_handler_t handler_func = handler[dest_cap->type];
+
+    assert(handler_func != NULL);
+
+#if 0
+    genpaddr_t paddr = get_address(&src_cte->cap) + offset;
+    genvaddr_t vaddr;
+    compile_vaddr(dest_vnode_cte, dest_slot, &vaddr);
+    printf("mapping 0x%"PRIxGENPADDR" to 0x%"PRIxGENVADDR"\n", paddr, vaddr);
+#endif
+
+    if (src_cte->mapping_info.pte) {
+        // this cap is already mapped
+#if DIAGNOSTIC_ON_ERROR
+        printf("caps_copy_to_vnode: this copy is already mapped @pte 0x%lx (paddr = 0x%"PRIxGENPADDR")\n", src_cte->mapping_info.pte, get_address(src_cap));
+#endif
+#if RETURN_ON_ERROR
+        return SYS_ERR_VM_ALREADY_MAPPED;
+#endif
+    }
+
+    cslot_t last_slot = dest_slot + pte_count;
+
+    if (last_slot > X86_64_PTABLE_SIZE) {
+        // requested map overlaps leaf page table
+#if DIAGNOSTIC_ON_ERROR
+        printf("caps_copy_to_vnode: requested mapping spans multiple leaf page tables\n");
+#endif
+#if RETURN_ON_ERROR
+        return SYS_ERR_VM_RETRY_SINGLE;
+#endif
+    }
+
+    errval_t r = handler_func(dest_cap, dest_slot, src_cap, flags, offset, pte_count);
+    if (err_is_fail(r)) {
+        printf("caps_copy_to_vnode: handler func returned %ld\n", r);
+    }
+#if 0
+    else {
+        printf("mapping_info.pte       = 0x%lx\n", src_cte->mapping_info.pte);
+        printf("mapping_info.offset    = 0x%lx\n", src_cte->mapping_info.offset);
+        printf("mapping_info.pte_count = %zu\n", src_cte->mapping_info.pte_count);
+    }
+#endif
+    return r;
+}
+
+static inline void read_pt_entry(struct capability *pgtable, size_t slot,
+                                 genpaddr_t *mapped_addr, lpaddr_t *pte,
+                                 void **entry)
+{
+    assert(type_is_vnode(pgtable->type));
+
+    genpaddr_t paddr;
+    lpaddr_t pte_;
+    void *entry_;
+
+    genpaddr_t gp = get_address(pgtable);
+    lpaddr_t lp = gen_phys_to_local_phys(gp);
+    lvaddr_t lv = local_phys_to_mem(lp);
+
+    // get paddr
+    switch (pgtable->type) {
+    case ObjType_VNode_x86_64_pml4:
+    case ObjType_VNode_x86_64_pdpt:
+    case ObjType_VNode_x86_64_pdir: {
+        union x86_64_pdir_entry *e =
+            (union x86_64_pdir_entry *)lv + slot;
+        paddr = (lpaddr_t)e->d.base_addr << BASE_PAGE_BITS;
+        entry_ = e;
+        pte_ = lp + slot * sizeof(union x86_64_pdir_entry);
+        break;
+    }
+    case ObjType_VNode_x86_64_ptable: {
+        union x86_64_ptable_entry *e =
+            (union x86_64_ptable_entry *)lv + slot;
+        paddr = (lpaddr_t)e->base.base_addr << BASE_PAGE_BITS;
+        entry_ = e;
+        pte_ = lp + slot * sizeof(union x86_64_ptable_entry);
+        break;
+    }
+    default:
+        assert(!"Should not get here");
+    }
+
+    if (mapped_addr) {
+        *mapped_addr = paddr;
+    }
+    if (pte) {
+        *pte = pte_;
+    }
+    if (entry) {
+        *entry = entry_;
+    }
+}
+
+static inline void clear_pt_entry(lvaddr_t pte) {
+    ((union x86_64_pdir_entry *)pte)->raw = 0;
+}
+
+static inline lvaddr_t get_leaf_ptable_for_vaddr(genvaddr_t vaddr)
+{
+    lvaddr_t root_pt = local_phys_to_mem(dcb_current->vspace);
+
+    // get pdpt
+    union x86_64_pdir_entry *pdpt = (union x86_64_pdir_entry *)root_pt + X86_64_PML4_BASE(vaddr);
+    if (!pdpt->raw) { return 0; }
+    genpaddr_t pdpt_gp = pdpt->d.base_addr << BASE_PAGE_BITS;
+    lvaddr_t pdpt_lv = local_phys_to_mem(gen_phys_to_local_phys(pdpt_gp));
+    // get pdir
+    union x86_64_pdir_entry *pdir = (union x86_64_pdir_entry *)pdpt_lv + X86_64_PDPT_BASE(vaddr);
+    if (!pdir->raw) { return 0; }
+    genpaddr_t pdir_gp = pdir->d.base_addr << BASE_PAGE_BITS;
+    lvaddr_t pdir_lv = local_phys_to_mem(gen_phys_to_local_phys(pdir_gp));
+    // get ptable
+    union x86_64_ptable_entry *ptable = (union x86_64_ptable_entry *)pdir_lv + X86_64_PDIR_BASE(vaddr);
+    if (!ptable->raw) { return 0; }
+    genpaddr_t ptable_gp = ptable->base.base_addr << BASE_PAGE_BITS;
+    lvaddr_t ptable_lv = local_phys_to_mem(gen_phys_to_local_phys(ptable_gp));
+
+    return ptable_lv;
+}
+
+size_t do_unmap(lvaddr_t pt, cslot_t slot, size_t num_pages)
+{
+    // iterate over affected leaf ptables
+    size_t unmapped_pages = 0;
+    union x86_64_ptable_entry *ptentry = (union x86_64_ptable_entry *)pt + slot;
+    for (int i = 0; i < num_pages; i++) {
+        ptentry++->raw = 0;
+        unmapped_pages++;
+    }
+    return unmapped_pages;
+}
+
+errval_t page_mappings_unmap(struct capability *pgtable, struct cte *mapping,
+                             size_t slot, size_t num_pages)
+{
+    assert(type_is_vnode(pgtable->type));
+    errval_t err;
+    debug(SUBSYS_PAGING, "page_mappings_unmap(%zd pages)\n", num_pages);
+
+    // get page table entry data
+    genpaddr_t paddr;
+
+    read_pt_entry(pgtable, slot, &paddr, NULL, NULL);
+    lvaddr_t pt = local_phys_to_mem(gen_phys_to_local_phys(get_address(pgtable)));
+
+    // get virtual address of first page
+    // TODO: error checking
+    genvaddr_t vaddr;
+    struct cte *leaf_pt = cte_for_cap(pgtable);
+    err = compile_vaddr(leaf_pt, slot, &vaddr);
+    if (err_is_fail(err)) {
+        if (err_no(err) == SYS_ERR_VNODE_NOT_INSTALLED) {
+            debug(SUBSYS_PAGING, "couldn't reconstruct virtual address\n");
+        }
+        else {
+            return err;
+        }
+    }
+
+    if (num_pages != mapping->mapping_info.pte_count) {
+        // want to unmap a different amount of pages than was mapped
+        return SYS_ERR_VM_MAP_SIZE;
+    }
+
+    do_unmap(pt, slot, num_pages);
+
+    // flush TLB for unmapped pages if we got a valid virtual address
+    // TODO: heuristic that decides if selective or full flush is more
+    //       efficient?
+    if (num_pages > 1 && err_is_ok(err)) {
+        do_full_tlb_flush();
+    } else {
+        do_one_tlb_flush(vaddr);
+    }
+
+    // update mapping info
+    memset(&mapping->mapping_info, 0, sizeof(struct mapping_info));
+
+    return SYS_ERR_OK;
+}
+
+errval_t page_mappings_modify_flags(struct capability *frame, size_t offset,
+                                    size_t pages, size_t mflags)
+{
+    struct cte *mapping = cte_for_cap(frame);
+    struct mapping_info *info = &mapping->mapping_info;
+
+    /* Calculate page access protection flags */
+    // Get frame cap rights
+    paging_x86_64_flags_t flags =
+        paging_x86_64_cap_to_page_flags(frame->rights);
+    // Mask with provided access rights mask
+    flags = paging_x86_64_mask_attrs(flags, X86_64_PTABLE_ACCESS(mflags));
+    // Add additional arch-specific flags
+    flags |= X86_64_PTABLE_FLAGS(mflags);
+    // Unconditionally mark the page present
+    flags |= X86_64_PTABLE_PRESENT;
+
+    /* Calculate location of page table entries we need to modify */
+    lvaddr_t base = local_phys_to_mem(info->pte) + offset;
+
+    for (int i = 0; i < pages; i++) {
+        union x86_64_ptable_entry *entry =
+            (union x86_64_ptable_entry *)base + i;
+        paging_x86_64_modify_flags(entry, flags);
+    }
+
+    /* flush affected TLB entries and return */
+    return paging_tlb_flush_range(mapping, pages);
+}
+
+void paging_dump_tables(struct dcb *dispatcher)
+{
+    lvaddr_t root_pt = local_phys_to_mem(dispatcher->vspace);
+
+    // loop over pdpts
+    for (int pdpt_index = 0; pdpt_index < X86_64_PTABLE_SIZE-1; pdpt_index++) {
+
+        union x86_64_pdir_entry *pdpt = (union x86_64_pdir_entry *)root_pt + pdpt_index;
+        if (!pdpt->raw) { continue; }
+        genpaddr_t pdpt_gp = pdpt->d.base_addr << BASE_PAGE_BITS;
+        lvaddr_t pdpt_lv = local_phys_to_mem(gen_phys_to_local_phys(pdpt_gp));
+
+        for (int pdir_index = 0; pdir_index < X86_64_PTABLE_SIZE; pdir_index++) {
+            // get pdir
+            union x86_64_pdir_entry *pdir = (union x86_64_pdir_entry *)pdpt_lv + pdir_index;
+            if (!pdir->raw) { continue; }
+            genpaddr_t pdir_gp = pdir->d.base_addr << BASE_PAGE_BITS;
+            lvaddr_t pdir_lv = local_phys_to_mem(gen_phys_to_local_phys(pdir_gp));
+
+            for (int ptable_index = 0; ptable_index < X86_64_PTABLE_SIZE; ptable_index++) {
+                // get ptable
+                union x86_64_ptable_entry *ptable = (union x86_64_ptable_entry *)pdir_lv + ptable_index;
+                if (!ptable->raw) { continue; }
+                genpaddr_t ptable_gp = ptable->base.base_addr << BASE_PAGE_BITS;
+                lvaddr_t ptable_lv = local_phys_to_mem(gen_phys_to_local_phys(ptable_gp));
+
+                for (int entry = 0; entry < X86_64_PTABLE_SIZE; entry++) {
+                    union x86_64_ptable_entry *e =
+                        (union x86_64_ptable_entry *)ptable_lv + entry;
+                    genpaddr_t paddr = (genpaddr_t)e->base.base_addr << BASE_PAGE_BITS;
+                    if (!paddr) {
+                        continue;
+                    }
+                    printf("%d.%d.%d.%d: 0x%"PRIxGENPADDR"\n", pdpt_index, pdir_index, ptable_index, entry, paddr);
+                }
+            }
+        }
+    }
+}
diff --git a/kernel/arch/k1om/paging.c b/kernel/arch/k1om/paging.c
new file mode 100644 (file)
index 0000000..2a4ad67
--- /dev/null
@@ -0,0 +1,194 @@
+/**
+ * \file
+ * \brief x86-64 kernel page-table setup
+ */
+
+/*
+ * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <kernel.h>
+#include <paging_kernel_arch.h>
+
+/*
+ * Table requirements for various address spaces.
+ */
+#define MEM_PDPT_SIZE           X86_64_PDPT_ENTRIES(X86_64_PADDR_SPACE_LIMIT)
+#define MEM_PDIR_SIZE           X86_64_PDIR_ENTRIES(X86_64_PADDR_SPACE_LIMIT)
+
+/*
+ * Page attribute bitmaps for various address spaces.
+ */
+#define MEM_PAGE_BITMAP                                 \
+    (X86_64_PTABLE_PRESENT | X86_64_PTABLE_READ_WRITE | \
+     X86_64_PTABLE_GLOBAL_PAGE)
+#define DEVICE_PAGE_BITMAP                                      \
+    (X86_64_PTABLE_PRESENT | X86_64_PTABLE_READ_WRITE |         \
+     X86_64_PTABLE_CACHE_DISABLED | X86_64_PTABLE_GLOBAL_PAGE)
+
+/**
+ * Kernel page map level 4 table.
+ */
+static union x86_64_pdir_entry pml4[X86_64_PTABLE_SIZE]
+__attribute__((aligned(X86_64_BASE_PAGE_SIZE)));
+
+/**
+ * Page directory pointer table for physical memory address space.
+ */
+static union x86_64_pdir_entry mem_pdpt[MEM_PDPT_SIZE][X86_64_PTABLE_SIZE]
+__attribute__((aligned(X86_64_BASE_PAGE_SIZE)));
+
+/**
+ * Page directory for physical memory address space.
+ */
+static union x86_64_ptable_entry mem_pdir[MEM_PDPT_SIZE][MEM_PDIR_SIZE][X86_64_PTABLE_SIZE]
+__attribute__((aligned(X86_64_BASE_PAGE_SIZE)));
+
+static inline void mapit(union x86_64_pdir_entry *pml4_base,
+                         union x86_64_pdir_entry *pdpt_base,
+                         union x86_64_ptable_entry *pdir_base, lpaddr_t addr,
+                         uint64_t bitmap)
+{
+    if(!X86_64_IS_PRESENT(pml4_base)) {
+        paging_x86_64_map_table(pml4_base,
+                                mem_to_local_phys((lvaddr_t)pdpt_base));
+    }
+
+    if(!X86_64_IS_PRESENT(pdpt_base)) {
+        paging_x86_64_map_table(pdpt_base,
+                                mem_to_local_phys((lvaddr_t)pdir_base));
+    }
+
+    if(!X86_64_IS_PRESENT(pdir_base)) {
+        debug(SUBSYS_PAGING, "mapped!\n");
+        paging_x86_64_map_large(pdir_base, addr, bitmap);
+    } else {
+//remap the page anyway, this is important for the memory latency benchmark
+        debug(SUBSYS_PAGING, "already existing! remapping it\n");
+        paging_x86_64_map_large(pdir_base, addr, bitmap);
+    }
+}
+
+/**
+ * \brief Map a region of physical memory into physical memory address space.
+ *
+ * Maps the region of physical memory, based at base and sized size bytes
+ * to the same-sized virtual memory region. All pages are flagged according to
+ * bitmap. This function automatically fills the needed page directory entries
+ * in the page hierarchy rooted at pml4. base and size will be made
+ * page-aligned by this function.
+ *
+ * \param base          Physical base address of memory region
+ * \param size          Size in bytes of memory region
+ * \param bitmap        Bitmap of flags for page tables/directories
+ *
+ * \return 0 on success, -1 on error (out of range)
+ */
+static int paging_map_mem(lpaddr_t base, size_t size, uint64_t bitmap)
+{
+    lvaddr_t vaddr, vbase = local_phys_to_mem(base);
+    lpaddr_t addr;
+
+    // Align given physical base address
+    if(base & X86_64_MEM_PAGE_MASK) {
+        base -= base & X86_64_MEM_PAGE_MASK;
+    }
+
+    paging_align(&vbase, &base, &size, X86_64_MEM_PAGE_SIZE);
+
+    // Is mapped region out of range?
+    assert(base + size <= (lpaddr_t)X86_64_PADDR_SPACE_LIMIT);
+    if(base + size > (lpaddr_t)X86_64_PADDR_SPACE_LIMIT) {
+        return -1;
+    }
+
+    // Map pages, tables and directories
+    for(vaddr = vbase, addr = base; vaddr < vbase + size;
+        vaddr += X86_64_MEM_PAGE_SIZE, addr += X86_64_MEM_PAGE_SIZE) {
+        union x86_64_pdir_entry *pml4_base =
+            &pml4[X86_64_PML4_BASE(vaddr)],
+            *pdpt_base = &mem_pdpt[X86_64_PML4_BASE(addr)][X86_64_PDPT_BASE(vaddr)];
+        union x86_64_ptable_entry *pdir_base =
+            &mem_pdir[X86_64_PML4_BASE(addr)][X86_64_PDPT_BASE(addr)][X86_64_PDIR_BASE(vaddr)];
+
+        debug(SUBSYS_PAGING, "Mapping 2M page: vaddr = 0x%"PRIxLVADDR"x, addr = 0x%lx, "
+              "PML4_BASE = %lu, PDPT_BASE = %lu, PDIR_BASE = %lu -- ", vaddr,
+              addr, X86_64_PML4_BASE(vaddr), X86_64_PDPT_BASE(vaddr),
+              X86_64_PDIR_BASE(vaddr));
+
+        mapit(pml4_base, pdpt_base, pdir_base, addr, bitmap);
+    }
+    // XXX FIXME: get rid of this TBL flush code, or move it elsewhere
+    // uint64_t cr3;
+    // __asm__ __volatile__("mov %%cr3,%0" : "=a" (cr3) : );
+    // __asm__ __volatile__("mov %0,%%cr3" :  : "a" (cr3));
+
+    return 0;
+}
+
+lvaddr_t paging_x86_64_map_device(lpaddr_t base, size_t size)
+{
+    if(paging_map_mem(base, size, DEVICE_PAGE_BITMAP) == 0) {
+        return local_phys_to_mem(base);
+    } else {
+        return 0;
+    }
+}
+
+int paging_x86_64_map_memory(lpaddr_t base, size_t size)
+{
+    return paging_map_mem(base, size, MEM_PAGE_BITMAP);
+}
+
+/**
+ * \brief Reset kernel paging.
+ *
+ * This function resets the page maps for kernel and memory-space. It clears out
+ * all other mappings. Use this only at system bootup!
+ */
+void paging_x86_64_reset(void)
+{
+    // Map kernel image so we don't lose ground
+    if(paging_x86_64_map_memory(mem_to_local_phys((lvaddr_t)&_start_kernel),
+                                SIZE_KERNEL_IMAGE) != 0) {
+        panic("error while mapping physical memory!");
+    }
+
+    // Map an initial amount of memory
+    if(paging_x86_64_map_memory(0, X86_64_KERNEL_INIT_MEMORY) != 0) {
+        panic("error while mapping physical memory!");
+    }
+
+    // Switch to new page layout
+    paging_x86_64_context_switch(mem_to_local_phys((lvaddr_t)pml4));
+}
+
+/**
+ * \brief Make a "good" PML4 table out of a page table.
+ *
+ * A "good" PML4 table is one that has all physical address space and
+ * the kernel mapped in. This function modifies the passed PML4, based
+ * at physical address 'base' accordingly. It does this by taking out
+ * the corresponding entries of the kernel's pristine PML4 table.
+ *
+ * \param base  Physical base address of PML4 table to make "good".
+ */
+void paging_x86_64_make_good_pml4(lpaddr_t base)
+{
+    union x86_64_pdir_entry *newpml4 =
+        (union x86_64_pdir_entry *)local_phys_to_mem(base);
+    int                 i;
+
+        // XXX: Disabled till vaddr_t is figured out
+    debug(SUBSYS_PAGING, "Is now a PML4: table = 0x%"PRIxLPADDR"\n", base);
+
+    // Map memory
+    for(i = X86_64_PML4_BASE(X86_64_MEMORY_OFFSET); i < X86_64_PTABLE_SIZE; i++) {
+        newpml4[i] = pml4[i];
+    }
+}
diff --git a/kernel/arch/k1om/startup_arch.c b/kernel/arch/k1om/startup_arch.c
new file mode 100644 (file)
index 0000000..0d268e6
--- /dev/null
@@ -0,0 +1,765 @@
+/**
+ * \file
+ * \brief x86_64 kernel bootup code.
+ */
+
+/*
+ * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <kernel.h>
+#include <string.h>
+#include <paging_kernel_arch.h>
+#include <elf/elf.h>
+#include <kernel_multiboot.h>
+#include <irq.h>
+#include <init.h>
+#include <barrelfish_kpi/cpu.h>
+#include <exec.h>
+#include <getopt/getopt.h>
+#include <dispatch.h>
+#include <barrelfish_kpi/init.h>
+#include <arch/x86/apic.h>
+#include <barrelfish_kpi/paging_arch.h>
+#include <barrelfish_kpi/syscalls.h>
+#include <target/x86/barrelfish_kpi/coredata_target.h>
+#include <kputchar.h>
+#include <startup.h>
+#include <arch/x86/startup_x86.h>
+
+/// Quick way to find the base address of a cnode capability
+#define CNODE(cte)     (cte)->cap.u.cnode.cnode
+
+/**
+ * init's needed boot pages.
+ */
+#define INIT_PDPT_SIZE          X86_64_PDPT_ENTRIES(X86_64_INIT_SPACE_LIMIT)
+#define INIT_PDIR_SIZE          X86_64_PDIR_ENTRIES(X86_64_INIT_SPACE_LIMIT)
+#define INIT_PTABLE_SIZE        X86_64_PTABLE_ENTRIES(X86_64_INIT_SPACE_LIMIT)
+#define INIT_PAGE_BITMAP        X86_64_PTABLE_PRESENT
+
+/// Pointer to bootinfo structure for init
+static struct bootinfo *bootinfo = (struct bootinfo *)BOOTINFO_BASE;
+
+static struct spawn_state spawn_state;
+
+/**
+ * Page map level 4 table for init user address space.
+ */
+static union x86_64_pdir_entry *init_pml4; //[PTABLE_SIZE]
+
+/**
+ * Page directory pointer table for init user address space.
+ */
+static union x86_64_pdir_entry *init_pdpt; //[INIT_PDPT_SIZE][PTABLE_SIZE]
+
+/**
+ * Page directory for init user address space.
+ */
+static union x86_64_pdir_entry *init_pdir; //[INIT_PDPT_SIZE][INIT_PDIR_SIZE][PTABLE_SIZE]
+
+/**
+ * Page tables for init user address space.
+ */
+static union x86_64_ptable_entry *init_ptable; //[INIT_PDPT_SIZE][INIT_PDIR_SIZE][INIT_PTABLE_SIZE][PTABLE_SIZE]
+
+/**
+ * \brief Convert elf flags to page flags
+ *
+ * \param flags ELF64 program segment flags.
+ *
+ * \return page flags.
+ *
+ * Not all combinations may be supported by an architecture
+ */
+static uint64_t paging_elf_to_page_flags(uint32_t flags)
+{
+    uint64_t pageflags = 0;
+
+    pageflags |= flags & PF_R ? PTABLE_USER_SUPERVISOR : 0;
+    pageflags |= flags & PF_W ? PTABLE_READ_WRITE : 0;
+    pageflags |= flags & PF_X ? 0 : PTABLE_EXECUTE_DISABLE;
+
+    return pageflags;
+}
+
+/**
+ * \brief Map init user-space memory.
+ *
+ * This function maps pages of the init user-space module. It expects
+ * the virtual base address 'vbase' of a program segment of the init executable,
+ * its size 'size' and its ELF64 access control flags. It maps pages
+ * to the sequential area of physical memory, given by 'base'. If you
+ * want to allocate physical memory frames as you go, you better use
+ * startup_alloc_init().
+ *
+ * \param vbase Virtual base address of program segment.
+ * \param base  Physical base address of program segment.
+ * \param size  Size of program segment in bytes.
+ * \param flags ELF64 access control flags of program segment.
+ */
+errval_t startup_map_init(lvaddr_t vbase, lpaddr_t base, size_t size,
+                          uint32_t flags)
+{
+    lvaddr_t vaddr;
+
+    paging_align(&vbase, &base, &size, BASE_PAGE_SIZE);
+
+    assert(vbase + size - X86_64_INIT_VBASE < X86_64_INIT_SPACE_LIMIT);
+
+    // Map pages
+    for(vaddr = vbase; vaddr < vbase + size;
+        vaddr += BASE_PAGE_SIZE, base += BASE_PAGE_SIZE) {
+        lvaddr_t baddr = vaddr - X86_64_INIT_VBASE;
+        union x86_64_ptable_entry *ptable_base = &init_ptable[
+                    X86_64_PML4_BASE(baddr) * X86_64_PTABLE_SIZE *
+                    X86_64_PTABLE_SIZE * X86_64_PTABLE_SIZE +
+                    X86_64_PDPT_BASE(baddr) * X86_64_PTABLE_SIZE *
+                    X86_64_PTABLE_SIZE + X86_64_PDIR_BASE(baddr) *
+                    X86_64_PTABLE_SIZE + X86_64_PTABLE_BASE(vaddr)];
+
+        debug(SUBSYS_PAGING, "Mapping 4K page: vaddr = 0x%lx, base = 0x%lx, "
+              "PML4_BASE = %lu, PDPT_BASE = %lu, PDIR_BASE = %lu, "
+              "PTABLE_BASE = %lu -- ", vaddr, base, X86_64_PML4_BASE(baddr),
+              X86_64_PDPT_BASE(baddr), X86_64_PDIR_BASE(baddr),
+              X86_64_PTABLE_BASE(baddr));
+
+        if(!X86_64_IS_PRESENT(ptable_base)) {
+            debug(SUBSYS_PAGING, "mapped!\n");
+            paging_x86_64_map(ptable_base, base,
+                              INIT_PAGE_BITMAP | paging_elf_to_page_flags(flags));
+        } else {
+            debug(SUBSYS_PAGING, "already existing!\n");
+        }
+    }
+
+    return SYS_ERR_OK;
+}
+
+/// Create physical address range or RAM caps to unused physical memory
+static void create_phys_caps(lpaddr_t init_alloc_addr)
+{
+    errval_t err;
+
+    // map first meg of RAM, which contains lots of crazy BIOS tables
+    err = create_caps_to_cnode(0, X86_64_START_KERNEL_PHYS,
+                               RegionType_PlatformData, &spawn_state, bootinfo);
+    assert(err_is_ok(err));
+
+    char *mmap_addr = MBADDR_ASSTRING(glbl_core_data->mmap_addr);
+    lpaddr_t last_end_addr = 0;
+
+#define PRINT_REGIONS(map, map_length) do {\
+        for(char * printcur = map; printcur < map + map_length;) {\
+            struct multiboot_mmap * printcurmmap = (struct multiboot_mmap * SAFE)TC(printcur);\
+            printf("\t0x%08lx - 0x%08lx Type: %d Length: 0x%lx\n", printcurmmap->base_addr, printcurmmap->base_addr + printcurmmap->length, printcurmmap->type, printcurmmap->length);\
+            printcur += printcurmmap->size + 4;\
+        }\
+    } while (0)
+
+    printf("Raw MMAP from BIOS\n");
+    PRINT_REGIONS(mmap_addr, glbl_core_data->mmap_length);
+
+    // normalize memory regions
+    char *clean_mmap_addr = MBADDR_ASSTRING(init_alloc_addr); // FIXME: Hack!!!! TODO: properly get memory form somewhere
+    assert(glbl_core_data->mmap_length < BOOTINFO_SIZE);
+    uint32_t clean_mmap_length = glbl_core_data->mmap_length;
+
+    memcpy(clean_mmap_addr, mmap_addr, glbl_core_data->mmap_length);
+
+    // first of all, sort regions by base address
+    // yes, it's a bubble sort, but the dataset is small and usually in the right order
+    bool swapped;
+    do {
+        swapped = false;
+
+        for(char * cur = clean_mmap_addr; cur < clean_mmap_addr + clean_mmap_length;) {
+            struct multiboot_mmap * curmmap = (struct multiboot_mmap * SAFE)TC(cur);
+            if (cur + curmmap->size + 4 >= clean_mmap_addr + clean_mmap_length)
+                break; // do not try to move this check into the forloop as entries do not have to be the same length
+
+            struct multiboot_mmap * nextmmap = (struct multiboot_mmap * SAFE)TC(cur + curmmap->size + 4);
+
+            if (nextmmap->base_addr < curmmap->base_addr ||
+                (nextmmap->base_addr == curmmap->base_addr && nextmmap->length > curmmap->length)) {
+                // swap
+                assert(curmmap->size == 20); // FIXME: The multiboot specification does not require this size
+                assert(nextmmap->size == 20);
+
+                struct multiboot_mmap tmp;
+                tmp = *curmmap;
+                *curmmap = *nextmmap;
+                *nextmmap = tmp;
+
+                swapped = true;
+            }
+
+            cur += curmmap->size + 4;
+        }
+    } while(swapped);
+
+    printf("Sorted MMAP\n");
+    PRINT_REGIONS(clean_mmap_addr, clean_mmap_length);
+
+    // now merge consecutive memory regions of the same or lower type
+    for(char * cur = clean_mmap_addr; cur < clean_mmap_addr + clean_mmap_length;) {
+        struct multiboot_mmap * curmmap = (struct multiboot_mmap * SAFE)TC(cur);
+        if (cur + curmmap->size + 4 >= clean_mmap_addr + clean_mmap_length)
+            break; // do not try to move this check into the forloop as entries do not have to be the same length
+
+        struct multiboot_mmap * nextmmap = (struct multiboot_mmap * SAFE)TC(cur + curmmap->size + 4);
+
+        /* On some machines (brie1) the IOAPIC region is only 1kB.
+         * Currently we're not able to map regions that are <4kB so we
+         * make sure that every region (if there is no problematic overlap)
+         * is at least BASE_PAGE_SIZEd (==4kB) here.
+         */
+        if ((curmmap->length < BASE_PAGE_SIZE) && (curmmap->base_addr + BASE_PAGE_SIZE <= nextmmap->base_addr)) {
+            curmmap->length = BASE_PAGE_SIZE;
+        }
+
+#define DISCARD_NEXT_MMAP do {\
+    uint32_t discardsize = nextmmap->size + 4;\
+    memmove(cur + curmmap->size + 4, cur + curmmap->size + 4 + discardsize, clean_mmap_length - (cur - clean_mmap_addr) - curmmap->size - 4 - discardsize);\
+    clean_mmap_length -= discardsize;\
+    } while (0)
+
+#define BUBBLE_NEXT_MMAP do {\
+    for (char * bubblecur = cur + curmmap->size + 4; bubblecur < clean_mmap_addr + clean_mmap_length;){\
+        struct multiboot_mmap * bubblecur_mmap = (struct multiboot_mmap * SAFE)TC(bubblecur);\
+        if (bubblecur + bubblecur_mmap->size + 4 >= clean_mmap_addr + clean_mmap_length)\
+            break;\
+        struct multiboot_mmap * bubblenext_mmap = (struct multiboot_mmap * SAFE)TC(bubblecur + bubblecur_mmap->size + 4);\
+        if (bubblenext_mmap->base_addr < bubblecur_mmap->base_addr || (bubblecur_mmap->base_addr == bubblenext_mmap->base_addr && bubblenext_mmap->length > bubblecur_mmap->length)) {\
+            struct multiboot_mmap bubbletmp; bubbletmp = *bubblecur_mmap; *bubblecur_mmap = *bubblenext_mmap; *bubblenext_mmap = bubbletmp;\
+        } else break;\
+    }} while(0)
+
+
+        bool reduced = false;
+        do {
+            reduced = false;
+
+            if (curmmap->base_addr == nextmmap->base_addr) {
+                // regions start at the same location
+                if (curmmap->length == nextmmap->length) {
+                    // trivial case. They are the same. Choose higher type and discard next
+                    curmmap->type = max(curmmap->type, nextmmap->type);
+
+                    DISCARD_NEXT_MMAP;
+
+                    reduced = true;
+                    continue;
+                } else {
+                    // next region is smaller (we sorted that way)
+                    if (nextmmap->type <= curmmap->type) {
+                        // next regions type is the same or smaller. discard
+                        DISCARD_NEXT_MMAP;
+
+                        reduced = true;
+                        continue;
+                    } else {
+                        // next regions type is higher, so it gets priority
+                        // change type of current region and shrink next
+                        uint32_t tmptype = curmmap->type;
+                        uint64_t newlength = curmmap->length - nextmmap->length;
+                        curmmap->type = nextmmap->type;
+                        curmmap->length = nextmmap->length;
+                        nextmmap->type = tmptype;
+                        nextmmap->base_addr += nextmmap->length;
+                        nextmmap->length = newlength;
+
+                        // now we need to bubble next to the right place to restore order
+                        BUBBLE_NEXT_MMAP;
+
+                        reduced = true;
+                        continue;
+                    }
+                }
+            }
+
+            // regions overlap
+            if (nextmmap->base_addr > curmmap->base_addr && nextmmap->base_addr < curmmap->base_addr + curmmap->length) {
+                // same type
+                if (curmmap->type == nextmmap->type) {
+                    // simple. just extend if necessary and discard next
+                    if (nextmmap->base_addr + nextmmap->length > curmmap->base_addr + curmmap->length)
+                        curmmap->length = (nextmmap->base_addr + nextmmap->length) - curmmap->base_addr;
+
+                    DISCARD_NEXT_MMAP;
+
+                    reduced = true;
+                    continue;
+                } else {
+                    // type is not the same
+                    if (nextmmap->base_addr + nextmmap->length < curmmap->base_addr + curmmap->length) {
+                        // there is a chunk at the end. create a new region
+                        struct multiboot_mmap tmpmmap;
+                        tmpmmap.size = 20;
+                        tmpmmap.base_addr = nextmmap->base_addr + nextmmap->length;
+                        tmpmmap.length = (curmmap->base_addr + curmmap->length) - (nextmmap->base_addr + nextmmap->length);
+                        tmpmmap.type = curmmap->type;
+
+                        // move everything to make room
+                        assert(clean_mmap_length + tmpmmap.length + 4 < BOOTINFO_SIZE);
+                        memmove(cur + curmmap->size + 4 + tmpmmap.size + 4, cur + curmmap->size + 4, clean_mmap_length - ((cur - clean_mmap_addr) + curmmap->size + 4));
+                        clean_mmap_length += tmpmmap.size + 4;
+
+                        // insert new
+                        *nextmmap = tmpmmap;
+
+                        // restore order
+                        BUBBLE_NEXT_MMAP;
+
+                        reduced = true;
+                    }
+
+                    // after the previous step, the next region either ends
+                    // at the same location as the current or is longer
+                    uint64_t overlap = (curmmap->base_addr + curmmap->length) - nextmmap->base_addr;
+
+                    if (curmmap-> type > nextmmap->type) {
+                        // current has priority, shrink next and extend current
+                        nextmmap->length -= overlap;
+                        nextmmap->base_addr += overlap;
+                        curmmap->length += overlap;
+
+                        if (nextmmap->length == 0)
+                            DISCARD_NEXT_MMAP;
+
+                        reduced = true;
+                        continue;
+                    } else {
+                        // next has priority, shrink current and extend next
+                        nextmmap->length += overlap;
+                        nextmmap->base_addr -= overlap;
+                        curmmap->length -= overlap;
+
+                        reduced = true;
+                        continue;
+                    }
+                }
+            }
+        } while (reduced);
+
+        cur += curmmap->size + 4;
+
+#undef DISCARD_NEXT_MMAP
+#undef BUBBLE_NEXT_MMAP
+    }
+
+    printf("Preprocessed MMAP\n");
+    PRINT_REGIONS(clean_mmap_addr, clean_mmap_length);
+
+    // we can only map pages. Therefore page align regions
+    for(char * cur = clean_mmap_addr; cur < clean_mmap_addr + clean_mmap_length;) {
+        struct multiboot_mmap * curmmap = (struct multiboot_mmap * SAFE)TC(cur);
+        if (cur + curmmap->size + 4 >= clean_mmap_addr + clean_mmap_length)
+            break; // do not try to move this check into the forloop as entries do not have to be the same length
+
+        struct multiboot_mmap * nextmmap = (struct multiboot_mmap * SAFE)TC(cur + curmmap->size + 4);
+
+        if (nextmmap->base_addr & BASE_PAGE_MASK) {
+            uint64_t offset = nextmmap->base_addr - ((nextmmap->base_addr >> BASE_PAGE_BITS) << BASE_PAGE_BITS);
+
+            // round in favour of higher type
+            if (curmmap->type > nextmmap->type) {
+                curmmap->length += BASE_PAGE_SIZE - offset;
+                nextmmap->base_addr += BASE_PAGE_SIZE - offset;
+                nextmmap->length -= BASE_PAGE_SIZE - offset;
+            } else {
+                curmmap->length -= offset;
+                nextmmap->base_addr -= offset;
+                nextmmap->length += offset;
+            }
+        }
+
+        cur += curmmap->size + 4;
+    }
+
+    printf("Pagealigned MMAP\n");
+    PRINT_REGIONS(clean_mmap_addr, clean_mmap_length);
+
+#undef PRINT_REGIONS
+
+    for(char *m = clean_mmap_addr; m < clean_mmap_addr + clean_mmap_length;) {
+        struct multiboot_mmap *mmap = (struct multiboot_mmap * SAFE)TC(m);
+
+        debug(SUBSYS_STARTUP, "MMAP %lx--%lx Type %u\n",
+              mmap->base_addr, mmap->base_addr + mmap->length,
+              mmap->type);
+
+        if (last_end_addr >= init_alloc_addr
+            && mmap->base_addr > last_end_addr) {
+            /* we have a gap between regions. add this as a physaddr range */
+            debug(SUBSYS_STARTUP, "physical address range %lx--%lx\n",
+                  last_end_addr, mmap->base_addr);
+
+            err = create_caps_to_cnode(last_end_addr,
+                                       mmap->base_addr - last_end_addr,
+                                       RegionType_PhyAddr, &spawn_state, bootinfo);
+            assert(err_is_ok(err));
+        }
+
+        if (mmap->type == MULTIBOOT_MEM_TYPE_RAM) {
+            genpaddr_t base_addr = mmap->base_addr;
+            genpaddr_t end_addr = base_addr + mmap->length;
+
+            // only map the rest of RAM which is greater than init_alloc_addr
+            if (end_addr > local_phys_to_gen_phys(init_alloc_addr)) {
+                if (base_addr < local_phys_to_gen_phys(init_alloc_addr)) {
+                    base_addr = local_phys_to_gen_phys(init_alloc_addr);
+                }
+                debug(SUBSYS_STARTUP, "RAM %lx--%lx\n", base_addr, end_addr);
+                err = create_caps_to_cnode(base_addr, end_addr - base_addr,
+                                           RegionType_Empty, &spawn_state, bootinfo);
+                assert(err_is_ok(err));
+            }
+        } else if (mmap->base_addr > local_phys_to_gen_phys(init_alloc_addr)) {
+            /* XXX: The multiboot spec just says that mapping types other than
+             * RAM are "reserved", but GRUB always maps the ACPI tables as type
+             * 3, and things like the IOAPIC tend to show up as type 2 or 4,
+             * so we map all these regions as platform data
+             */
+            debug(SUBSYS_STARTUP, "platform %lx--%lx\n", mmap->base_addr,
+                  mmap->base_addr + mmap->length);
+            assert(mmap->base_addr > local_phys_to_gen_phys(init_alloc_addr));
+            err = create_caps_to_cnode(mmap->base_addr, mmap->length,
+                                       RegionType_PlatformData, &spawn_state, bootinfo);
+            assert(err_is_ok(err));
+        }
+
+        last_end_addr = mmap->base_addr + mmap->length;
+        m += mmap->size + 4;
+    }
+
+    assert(last_end_addr != 0);
+
+    if (last_end_addr < X86_64_PADDR_SPACE_SIZE) {
+        /*
+         * FIXME: adding the full range results in too many caps to add
+         * to the cnode (and we can't handle such big caps in user-space
+         * yet anyway) so instead we limit it to something much smaller
+         */
+        size_t size = X86_64_PADDR_SPACE_SIZE - last_end_addr;
+        const lpaddr_t phys_region_limit = 1UL << 32; // PCI implementation limit
+        if (last_end_addr > phys_region_limit) {
+            size = 0; // end of RAM is already too high!
+        } else if (last_end_addr + size > phys_region_limit) {
+            size = phys_region_limit - last_end_addr;
+        }
+        debug(SUBSYS_STARTUP, "end physical address range %lx--%lx\n",
+              last_end_addr, last_end_addr + size);
+        err = create_caps_to_cnode(last_end_addr, size,
+                                   RegionType_PhyAddr, &spawn_state, bootinfo);
+        assert(err_is_ok(err));
+    }
+}
+
+#define NEEDED_KERNEL_SPACE \
+    ((SIZE_KERNEL_IMAGE & 0x1000 ) == SIZE_KERNEL_IMAGE ? \
+    SIZE_KERNEL_IMAGE : \
+    (SIZE_KERNEL_IMAGE & 0xfffffffffffff000) + 0x1000)
+
+#define OBJSPERPAGE_CTE         (1UL << (BASE_PAGE_BITS - OBJBITS_CTE))
+
+static void init_page_tables(struct spawn_state *st, alloc_phys_func alloc_phys)
+{
+    /* Allocate memory for init's page tables */
+    init_pml4 = (void *)local_phys_to_mem(
+                alloc_phys(X86_64_PTABLE_SIZE * sizeof(union x86_64_pdir_entry)));
+    init_pdpt = (void *)local_phys_to_mem(
+                alloc_phys(X86_64_PTABLE_SIZE * INIT_PDPT_SIZE
+                           * sizeof(union x86_64_pdir_entry)));
+    init_pdir = (void *)local_phys_to_mem(
+                alloc_phys(X86_64_PTABLE_SIZE * INIT_PDPT_SIZE * INIT_PDIR_SIZE
+                           * sizeof(union x86_64_pdir_entry)));
+    init_ptable = (void *)local_phys_to_mem(
+                alloc_phys(X86_64_PTABLE_SIZE * INIT_PDPT_SIZE * INIT_PDIR_SIZE
+                           * INIT_PTABLE_SIZE * sizeof(union x86_64_ptable_entry)));
+
+    /* Page table setup */
+    /* Initialize init page tables */
+    for(size_t i = 0; i < INIT_PDPT_SIZE; i++) {
+        paging_x86_64_clear_pdir(&init_pdpt[i]);
+        for(size_t j = 0; j < INIT_PDIR_SIZE; j++) {
+            paging_x86_64_clear_pdir(&init_pdir[i * PTABLE_SIZE + j]);
+            for(size_t k = 0; k < INIT_PTABLE_SIZE; k++) {
+                paging_x86_64_clear_ptable(
+                &init_ptable[i * PTABLE_SIZE * PTABLE_SIZE + j * PTABLE_SIZE + k]);
+            }
+        }
+    }
+    /* Map pagetables into pageCN */
+    int     pagecn_pagemap = 0;
+    // Map PML4 (slot 0 in pagecn)
+    caps_create_new(ObjType_VNode_x86_64_pml4, mem_to_local_phys((lvaddr_t)init_pml4),
+                    BASE_PAGE_BITS, 0,
+                    caps_locate_slot(CNODE(st->pagecn), pagecn_pagemap++));
+    // Map PDPT into successive slots in pagecn
+    for(size_t i = 0; i < INIT_PDPT_SIZE; i++) {
+        caps_create_new(ObjType_VNode_x86_64_pdpt,
+                        mem_to_local_phys((lvaddr_t)init_pdpt) + i * BASE_PAGE_SIZE,
+                        BASE_PAGE_BITS, 0,
+                        caps_locate_slot(CNODE(st->pagecn), pagecn_pagemap++));
+    }
+    // Map PDIR into successive slots in pagecn
+    for(size_t i = 0; i < INIT_PDIR_SIZE; i++) {
+        caps_create_new(ObjType_VNode_x86_64_pdir,
+                        mem_to_local_phys((lvaddr_t)init_pdir) + i * BASE_PAGE_SIZE,
+                        BASE_PAGE_BITS, 0,
+                        caps_locate_slot(CNODE(st->pagecn), pagecn_pagemap++));
+    }
+    // Map page tables into successive slots in pagecn
+    for(size_t i = 0; i < INIT_PTABLE_SIZE; i++) {
+        caps_create_new(ObjType_VNode_x86_64_ptable,
+                        mem_to_local_phys((lvaddr_t)init_ptable) + i * BASE_PAGE_SIZE,
+                        BASE_PAGE_BITS, 0,
+                        caps_locate_slot(CNODE(st->pagecn), pagecn_pagemap++));
+    }
+    // Connect all page tables to page directories.
+    // init's memory manager expects page tables within the pagecn to
+    // already be connected to the corresponding directories. To avoid
+    // unneccessary special cases, we connect them here.
+    for(lvaddr_t vaddr = X86_64_INIT_VBASE; vaddr < X86_64_INIT_SPACE_LIMIT;
+        vaddr += BASE_PAGE_SIZE) {
+        lvaddr_t baddr = vaddr - X86_64_INIT_VBASE;
+        union x86_64_pdir_entry *pml4_base, *pdpt_base, *pdir_base;
+        union x86_64_ptable_entry *ptable_base;
+        pml4_base = &init_pml4[X86_64_PML4_BASE(vaddr)];
+        pdpt_base = &init_pdpt[X86_64_PML4_BASE(baddr) * X86_64_PTABLE_SIZE +
+                               X86_64_PDPT_BASE(vaddr)];
+        pdir_base = &init_pdir[X86_64_PML4_BASE(baddr) * X86_64_PTABLE_SIZE *
+                               X86_64_PTABLE_SIZE
+                               + X86_64_PDPT_BASE(baddr) * X86_64_PTABLE_SIZE
+                               + X86_64_PDIR_BASE(vaddr)];
+        ptable_base = &init_ptable[X86_64_PML4_BASE(baddr) * X86_64_PTABLE_SIZE *
+                                   X86_64_PTABLE_SIZE * X86_64_PTABLE_SIZE +
+                                   X86_64_PDPT_BASE(baddr) * X86_64_PTABLE_SIZE *
+                                   X86_64_PTABLE_SIZE + X86_64_PDIR_BASE(baddr) *
+                                   X86_64_PTABLE_SIZE + X86_64_PTABLE_BASE(vaddr)];
+
+        paging_x86_64_map_table(pml4_base, mem_to_local_phys((lvaddr_t)pdpt_base));
+        paging_x86_64_map_table(pdpt_base, mem_to_local_phys((lvaddr_t)pdir_base));
+        paging_x86_64_map_table(pdir_base, mem_to_local_phys((lvaddr_t)ptable_base));
+    }
+
+    /* Initialize and switch to init's PML4 */
+    paging_x86_64_make_good_pml4(mem_to_local_phys((lvaddr_t)init_pml4));
+    paging_x86_64_context_switch(mem_to_local_phys((lvaddr_t)init_pml4));
+
+    /***** VSpace available now *****/
+}
+
+static struct dcb *spawn_init_common(struct spawn_state *st, const char *name,
+                                     int argc, const char *argv[],
+                                     lpaddr_t bootinfo_phys,
+                                     alloc_phys_func alloc_phys)
+{
+    errval_t err;
+
+    /* Perform arch-independent spawn */
+    lvaddr_t paramaddr;
+    struct dcb *init_dcb = spawn_module(st, name, argc, argv, bootinfo_phys,
+                                        ARGS_BASE, alloc_phys, &paramaddr);
+
+    /* Init page tables */
+    init_page_tables(st, alloc_phys);
+
+    /* Map cmdline args R/W into VSpace at ARGS_BASE */
+    paging_x86_64_map_table(&init_pml4[X86_64_PML4_BASE(ARGS_BASE)],
+                            mem_to_local_phys((lvaddr_t)init_pdpt));
+    paging_x86_64_map_table(&init_pdpt[X86_64_PDPT_BASE(ARGS_BASE)],
+                            mem_to_local_phys((lvaddr_t)init_pdir));
+    paging_x86_64_map_table(&init_pdir[X86_64_PDIR_BASE(ARGS_BASE)],
+                            mem_to_local_phys((lvaddr_t)init_ptable));
+    for (int i = 0; i < ARGS_SIZE / BASE_PAGE_SIZE; i++) {
+        paging_x86_64_map(&init_ptable[X86_64_PTABLE_BASE(ARGS_BASE) + i],
+                          st->args_page + i * BASE_PAGE_SIZE,
+                          INIT_PAGE_BITMAP | paging_elf_to_page_flags(PF_R|PF_W));
+    }
+
+    /* Map dispatcher frame R/W into VSpace */
+    paging_x86_64_map_table(&init_pml4[X86_64_PML4_BASE(DISPATCHER_BASE)],
+                            mem_to_local_phys((lvaddr_t)init_pdpt));
+    paging_x86_64_map_table(&init_pdpt[X86_64_PDPT_BASE(DISPATCHER_BASE)],
+                            mem_to_local_phys((lvaddr_t)init_pdir));
+    paging_x86_64_map_table(&init_pdir[X86_64_PDIR_BASE(DISPATCHER_BASE)],
+                            mem_to_local_phys((lvaddr_t)init_ptable));
+    for (int i = 0; i < (1 << DISPATCHER_FRAME_BITS) / BASE_PAGE_SIZE; i++) {
+        paging_x86_64_map(&init_ptable[X86_64_PTABLE_BASE(DISPATCHER_BASE) + i],
+                          mem_to_local_phys(init_dcb->disp) + i * BASE_PAGE_SIZE,
+                          INIT_PAGE_BITMAP | paging_elf_to_page_flags(PF_R|PF_W));
+    }
+
+    struct dispatcher_shared_generic *init_disp =
+        get_dispatcher_shared_generic(init_dcb->disp);
+    struct dispatcher_shared_x86_64 *init_disp_x86_64 =
+        get_dispatcher_shared_x86_64(init_dcb->disp);
+
+    registers_set_param(&init_disp_x86_64->enabled_save_area, paramaddr);
+
+    // Map IO cap in task cnode
+    struct cte *iocap = caps_locate_slot(CNODE(st->taskcn), TASKCN_SLOT_IO);
+    err = caps_create_new(ObjType_IO, 0, 0, 0, iocap);
+    assert(err_is_ok(err));
+
+    /* Set fields in DCB */
+    // Set Vspace
+    init_dcb->vspace = mem_to_local_phys((lvaddr_t)init_pml4);
+
+    // init dispatcher
+    init_disp->disabled = true;
+    strncpy(init_disp->name, argv[0], DISP_NAME_LEN);
+
+    /* tell init the vspace addr of its dispatcher */
+    init_disp->udisp = DISPATCHER_BASE;
+
+    init_disp_x86_64->disabled_save_area.rdi = DISPATCHER_BASE;
+    init_disp_x86_64->disabled_save_area.fs = 0;
+    init_disp_x86_64->disabled_save_area.gs = 0;
+    init_disp_x86_64->disabled_save_area.eflags = USER_EFLAGS;
+
+    return init_dcb;
+}
+
+struct dcb *spawn_bsp_init(const char *name, alloc_phys_func alloc_phys)
+{
+    errval_t err;
+
+    /* Only the first core can run this code */
+    assert(apic_is_bsp());
+
+    /* Allocate bootinfo */
+    lpaddr_t bootinfo_phys = alloc_phys(BOOTINFO_SIZE);
+    memset((void *)local_phys_to_mem(bootinfo_phys), 0, BOOTINFO_SIZE);
+
+    /* Construct cmdline args */
+    char bootinfochar[16];
+    snprintf(bootinfochar, sizeof(bootinfochar), "%lu", BOOTINFO_BASE);
+    const char *argv[] = { "init", bootinfochar };
+
+    struct dcb *init_dcb = spawn_init_common(&spawn_state, name, 
+                                             ARRAY_LENGTH(argv), argv,
+                                             bootinfo_phys, alloc_phys);
+
+    /* Map bootinfo R/W into VSpace at vaddr BOOTINFO_BASE */
+    paging_x86_64_map_table(&init_pml4[0], mem_to_local_phys((lvaddr_t)init_pdpt));
+    paging_x86_64_map_table(&init_pdpt[0], mem_to_local_phys((lvaddr_t)init_pdir));
+    paging_x86_64_map_table(&init_pdir[1], mem_to_local_phys((lvaddr_t)init_ptable));
+    for (int i = 0; i < BOOTINFO_SIZE / BASE_PAGE_SIZE; i++) {
+        paging_x86_64_map(&init_ptable[i], bootinfo_phys + i * BASE_PAGE_SIZE,
+                   INIT_PAGE_BITMAP | paging_elf_to_page_flags(PF_R|PF_W));
+    }
+
+    /* Load init ELF64 binary from multiboot */
+    struct multiboot_modinfo *module = multiboot_find_module(name);
+    if (module == NULL) {
+        panic("Could not find init module!");
+    }
+    lvaddr_t init_ep;
+    err = elf_load(EM_X86_64, startup_alloc_init, &spawn_state,
+                   local_phys_to_mem(module->mod_start),
+                   MULTIBOOT_MODULE_SIZE(*module), &init_ep);
+    if (err_is_fail(err)) {
+        //err_print_calltrace(err);
+        panic("ELF load of init module failed!");
+    }
+
+    struct dispatcher_shared_x86_64 *init_disp_x86_64 =
+        get_dispatcher_shared_x86_64(init_dcb->disp);
+    init_disp_x86_64->disabled_save_area.rip = init_ep;
+
+    /* Create caps for init to use */
+    create_module_caps(&spawn_state);
+    // XXX: temporary fix for trac ticket #253: make it more unlikely that
+    // we run out of root cnode slots by aligning the memory we declare free
+    // to 1MB.
+    lpaddr_t init_alloc_end = alloc_phys(0);
+    lpaddr_t align = 1UL << 20; // 1MB
+    // XXX: No checks are in place to make sure that init_alloc_end_aligned
+    // is actually a valid physical memory address (e.g. a location at which
+    // RAM exists.
+    lpaddr_t init_alloc_end_aligned = (init_alloc_end + align) & ~(align-1);
+    printf("aligning free memory start to 0x%"PRIxLPADDR" (was 0x%"PRIxLPADDR
+           "): wasting %lu kB\n",
+           init_alloc_end_aligned, init_alloc_end,
+           (init_alloc_end_aligned - init_alloc_end) / 1024);
+    create_phys_caps(init_alloc_end_aligned);
+
+    /* Fill bootinfo struct */
+    bootinfo->mem_spawn_core = NEEDED_KERNEL_SPACE; // Size of kernel
+
+    return init_dcb;
+}
+
+struct dcb *spawn_app_init(struct x86_core_data *core_data,
+                           const char *name, alloc_phys_func alloc_phys)
+{
+    errval_t err;
+
+    /* Construct cmdline args */
+    // Core id of the core that booted this core
+    char coreidchar[16];
+    snprintf(coreidchar, sizeof(coreidchar), "%d", core_data->src_core_id);
+
+    // IPI channel id of core that booted this core
+    char chanidchar[30];
+    snprintf(chanidchar, sizeof(chanidchar), "chanid=%d", core_data->chan_id);
+
+    // Arch id of the core that booted this core
+    char archidchar[30];
+    snprintf(archidchar, sizeof(archidchar), "archid=%d",
+             core_data->src_arch_id);
+
+    const char *argv[] = { name, coreidchar, chanidchar, archidchar };
+
+    struct dcb *init_dcb = spawn_init_common(&spawn_state, name, 
+                                             ARRAY_LENGTH(argv), argv,
+                                             0, alloc_phys);
+
+    // Urpc frame cap
+    struct cte *urpc_frame_cte = caps_locate_slot(CNODE(spawn_state.taskcn),
+                                                  TASKCN_SLOT_MON_URPC);
+    // XXX: Create as devframe so the memory is not zeroed out
+    err = caps_create_new(ObjType_DevFrame, core_data->urpc_frame_base,
+                          core_data->urpc_frame_bits,
+                          core_data->urpc_frame_bits, urpc_frame_cte);
+    assert(err_is_ok(err));
+    urpc_frame_cte->cap.type = ObjType_Frame;
+    lpaddr_t urpc_ptr = gen_phys_to_local_phys(urpc_frame_cte->cap.u.frame.base);
+
+    /* Map urpc frame at MON_URPC_BASE */
+    paging_x86_64_map_table(&init_pml4[X86_64_PML4_BASE(MON_URPC_BASE)],
+                            mem_to_local_phys((lvaddr_t)init_pdpt));
+    paging_x86_64_map_table(&init_pdpt[X86_64_PDPT_BASE(MON_URPC_BASE)],
+                            mem_to_local_phys((lvaddr_t)init_pdir));
+    paging_x86_64_map_table(&init_pdir[X86_64_PDIR_BASE(MON_URPC_BASE)],
+                            mem_to_local_phys((lvaddr_t)init_ptable));
+    for (int i = 0; i < MON_URPC_SIZE / BASE_PAGE_SIZE; i++) {
+        paging_x86_64_map(&init_ptable[X86_64_PTABLE_BASE(MON_URPC_BASE) + i],
+                          urpc_ptr + i * BASE_PAGE_SIZE,
+                          INIT_PAGE_BITMAP | paging_elf_to_page_flags(PF_R | PF_W));
+    }
+
+    // elf load the domain
+    genvaddr_t entry_point;
+    err = elf_load(EM_X86_64, startup_alloc_init, &spawn_state,
+                   local_phys_to_mem(core_data->monitor_binary),
+                   core_data->monitor_binary_size, &entry_point);
+    if (err_is_fail(err)) {
+        //err_print_calltrace(err);
+        panic("ELF load of init module failed!");
+    }
+
+    struct dispatcher_shared_x86_64 *init_disp_x86_64 =
+        get_dispatcher_shared_x86_64(init_dcb->disp);
+    init_disp_x86_64->disabled_save_area.rip = entry_point;
+
+    return init_dcb;
+}
diff --git a/kernel/arch/k1om/syscall.c b/kernel/arch/k1om/syscall.c
new file mode 100644 (file)
index 0000000..88fcb68
--- /dev/null
@@ -0,0 +1,1034 @@
+/**
+ * \file
+ * \brief System calls implementation.
+ */
+
+/*
+ * Copyright (c) 2007, 2008, 2009, 2010, 2012, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <kernel.h>
+#include <syscall.h>
+#include <barrelfish_kpi/syscalls.h>
+#include <mdb/mdb.h>
+#include <dispatch.h>
+#include <paging_kernel_arch.h>
+#include <paging_generic.h>
+#include <exec.h>
+#include <arch/x86/apic.h>
+#include <arch/x86/global.h>
+#include <arch/x86/perfmon.h>
+#include <vmkit.h>
+#include <barrelfish_kpi/sys_debug.h>
+#include <barrelfish_kpi/lmp.h>
+#include <barrelfish_kpi/dispatcher_shared_target.h>
+#include <arch/x86/debugregs.h>
+#include <trace/trace.h>
+#include <arch/x86/syscall.h>
+#include <arch/x86/timing.h>
+#include <fpu.h>
+#include <arch/x86/ipi_notify.h>
+
+#define MIN(a,b)        ((a) < (b) ? (a) : (b))
+
+extern uint64_t user_stack_save;
+
+/* FIXME: lots of missing argument checks in this function */
+static struct sysret handle_dispatcher_setup(struct capability *to,
+                                             int cmd, uintptr_t *args)
+{
+    capaddr_t cptr = args[0];
+    int depth    = args[1];
+    capaddr_t vptr = args[2];
+    capaddr_t dptr = args[3];
+    bool run = args[4];
+    capaddr_t odptr = args[5];
+
+    return sys_dispatcher_setup(to, cptr, depth, vptr, dptr, run, odptr);
+}
+
+static struct sysret handle_dispatcher_properties(struct capability *to,
+                                                  int cmd, uintptr_t *args)
+{
+    enum task_type type = args[0];
+    unsigned long deadline = args[1];
+    unsigned long wcet = args[2];
+    unsigned long period = args[3];
+    unsigned long release = args[4];
+    unsigned short weight = args[5];
+
+    return sys_dispatcher_properties(to, type, deadline, wcet, period,
+                                     release, weight);
+}
+
+static struct sysret handle_retype_common(struct capability *root,
+                                          uintptr_t *args,
+                                          bool from_monitor)
+{
+    uint64_t source_cptr     = args[0];
+    uint64_t type            = args[1];
+    uint64_t objbits         = args[2];
+    uint64_t  dest_cnode_cptr = args[3];
+    uint64_t dest_slot       = args[4];
+    uint64_t dest_vbits      = args[5];
+
+    return sys_retype(root, source_cptr, type, objbits, dest_cnode_cptr,
+                      dest_slot, dest_vbits, from_monitor);
+}
+
+static struct sysret handle_retype(struct capability *root,
+                                   int cmd, uintptr_t *args)
+{
+    return handle_retype_common(root, args, false);
+}
+
+static struct sysret handle_create(struct capability *root,
+                                   int cmd, uintptr_t *args)
+{
+    /* Retrieve arguments */
+    enum objtype type         = args[0];
+    uint8_t objbits           = args[1];
+    capaddr_t dest_cnode_cptr = args[2];
+    cslot_t dest_slot         = args[3];
+    uint8_t dest_vbits        = args[4];
+
+    return sys_create(root, type, objbits, dest_cnode_cptr, dest_slot,
+                      dest_vbits);
+}
+
+
+/**
+ * Common code for copying and minting except the mint flag and param passing
+ */
+static struct sysret copy_or_mint(struct capability *root,
+                                  uintptr_t *args, bool mint)
+{
+    /* Retrive arguments */
+    capaddr_t  destcn_cptr   = args[0];
+    uint64_t dest_slot     = args[1];
+    capaddr_t  source_cptr   = args[2];
+    int      destcn_vbits  = args[3];
+    int      source_vbits  = args[4];
+    uint64_t param1, param2;
+    // params only sent if mint operation
+    if (mint) {
+        param1 = args[5];
+        param2 = args[6];
+    } else {
+        param1 = param2 = 0;
+    }
+
+    return sys_copy_or_mint(root, destcn_cptr, dest_slot, source_cptr,
+                            destcn_vbits, source_vbits, param1, param2, mint);
+}
+
+static struct sysret handle_map(struct capability *ptable,
+                                int cmd, uintptr_t *args)
+{
+    /* Retrieve arguments */
+    uint64_t  slot          = args[0];
+    capaddr_t source_cptr   = args[1];
+    int       source_vbits  = args[2];
+    uint64_t  flags         = args[3];
+    uint64_t  offset        = args[4];
+    uint64_t  pte_count     = args[5];
+
+    return sys_map(ptable, slot, source_cptr, source_vbits, flags, offset,
+                   pte_count);
+}
+
+static struct sysret handle_mint(struct capability *root,
+                                 int cmd, uintptr_t *args)
+{
+    return copy_or_mint(root, args, true);
+}
+
+static struct sysret handle_copy(struct capability *root,
+                                 int cmd, uintptr_t *args)
+{
+    return copy_or_mint(root, args, false);
+}
+
+static struct sysret handle_delete_common(struct capability *root,
+                                   uintptr_t *args,
+                                   bool from_monitor)
+{
+    capaddr_t cptr = args[0];
+    int bits     = args[1];
+    return sys_delete(root, cptr, bits, from_monitor);
+}
+
+static struct sysret handle_delete(struct capability *root,
+                                   int cmd, uintptr_t *args)
+{
+    return handle_delete_common(root, args, false);
+}
+
+
+static struct sysret handle_revoke_common(struct capability *root,
+                                          uintptr_t *args,
+                                          bool from_monitor)
+{
+    capaddr_t cptr = args[0];
+    int bits     = args[1];
+    return sys_revoke(root, cptr, bits, from_monitor);
+}
+
+static struct sysret handle_revoke(struct capability *root,
+                                   int cmd, uintptr_t *args) 
+{
+    return handle_revoke_common(root, args, false);
+}
+
+
+static struct sysret handle_unmap(struct capability *pgtable,
+                                  int cmd, uintptr_t *args)
+{
+    capaddr_t cptr = args[0];
+    int bits       = args[1];
+    size_t entry   = args[2];
+    size_t pages   = args[3];
+
+    errval_t err;
+    struct cte *mapping;
+    err = caps_lookup_slot(&dcb_current->cspace.cap, cptr, bits,
+                                    &mapping, CAPRIGHTS_READ_WRITE);
+    if (err_is_fail(err)) {
+        return SYSRET(err_push(err, SYS_ERR_CAP_NOT_FOUND));
+    }
+
+    err = page_mappings_unmap(pgtable, mapping, entry, pages);
+    return SYSRET(err);
+}
+
+/// Different handler for cap operations performed by the monitor
+static struct sysret monitor_handle_retype(struct capability *kernel_cap,
+                                           int cmd, uintptr_t *args)
+{
+    errval_t err;
+
+    capaddr_t root_caddr = args[0];
+    capaddr_t root_vbits = args[1];
+
+    struct capability *root;
+    err = caps_lookup_cap(&dcb_current->cspace.cap, root_caddr, root_vbits,
+                          &root, CAPRIGHTS_READ);
+    if (err_is_fail(err)) {
+        return SYSRET(err_push(err, SYS_ERR_ROOT_CAP_LOOKUP));
+    }
+
+    /* XXX: this hides the first two arguments */
+    return handle_retype_common(root, &args[2], true);
+}
+
+/// Different handler for cap operations performed by the monitor
+static struct sysret monitor_handle_delete(struct capability *kernel_cap,
+                                           int cmd, uintptr_t *args)
+{
+    errval_t err;
+
+    capaddr_t root_caddr = args[0];
+    capaddr_t root_vbits = args[1];
+
+    struct capability *root;
+    err = caps_lookup_cap(&dcb_current->cspace.cap, root_caddr, root_vbits,
+                          &root, CAPRIGHTS_READ);
+    if (err_is_fail(err)) {
+        return SYSRET(err_push(err, SYS_ERR_ROOT_CAP_LOOKUP));
+    }
+
+    /* XXX: this hides the first two arguments */
+    return handle_delete_common(root, &args[2], true);
+}
+
+/// Different handler for cap operations performed by the monitor
+static struct sysret monitor_handle_revoke(struct capability *kernel_cap,
+                                           int cmd, uintptr_t *args)
+{
+    errval_t err;
+
+    capaddr_t root_caddr = args[0];
+    capaddr_t root_vbits = args[1];
+
+    struct capability *root;
+    err = caps_lookup_cap(&dcb_current->cspace.cap, root_caddr, root_vbits,
+                          &root, CAPRIGHTS_READ);
+    if (err_is_fail(err)) {
+        return SYSRET(err_push(err, SYS_ERR_ROOT_CAP_LOOKUP));
+    }
+
+    /* XXX: this hides the first two arguments */
+    return handle_revoke_common(root, &args[2], true);
+}
+
+static struct sysret monitor_handle_register(struct capability *kernel_cap,
+                                             int cmd, uintptr_t *args)
+{
+    capaddr_t ep_caddr = args[0];
+    return sys_monitor_register(ep_caddr);
+}
+
+/**
+ * \brief Spawn a new core and create a kernel cap for it.
+ */
+static struct sysret monitor_spawn_core(struct capability *kernel_cap,
+                                        int cmd, uintptr_t *args)
+{
+    coreid_t core_id       = args[0];
+    enum cpu_type cpu_type = args[1];
+    genvaddr_t entry       = args[2];
+
+    return sys_monitor_spawn_core(core_id, cpu_type, entry);
+}
+
+static struct sysret monitor_get_core_id(struct capability *kernel_cap,
+                                         int cmd, uintptr_t *args)
+{
+    return (struct sysret){.error = SYS_ERR_OK, .value = my_core_id};
+}
+
+static struct sysret monitor_get_arch_id(struct capability *kernel_cap,
+                                         int cmd, uintptr_t *args)
+{
+    return (struct sysret){.error = SYS_ERR_OK, .value = apic_id};
+}
+
+static struct sysret monitor_identify_cap_common(struct capability *kernel_cap,
+                                                 struct capability *root,
+                                                 uintptr_t *args)
+{
+    capaddr_t cptr = args[0];
+    uint8_t bits = args[1];
+    struct capability *retbuf = (void *)args[2];
+
+    return sys_monitor_identify_cap(root, cptr, bits, retbuf);
+}
+
+static struct sysret monitor_identify_cap(struct capability *kernel_cap,
+                                          int cmd, uintptr_t *args)
+{
+    return monitor_identify_cap_common(kernel_cap, &dcb_current->cspace.cap, args);
+}
+
+static struct sysret monitor_identify_domains_cap(struct capability *kernel_cap,
+                                                  int cmd, uintptr_t *args)
+{
+    errval_t err;
+
+    capaddr_t root_caddr = args[0];
+    capaddr_t root_vbits = args[1];
+
+    struct capability *root;
+    err = caps_lookup_cap(&dcb_current->cspace.cap, root_caddr, root_vbits,
+                          &root, CAPRIGHTS_READ);
+
+    if (err_is_fail(err)) {
+        return SYSRET(err_push(err, SYS_ERR_ROOT_CAP_LOOKUP));
+    }
+
+    /* XXX: this hides the first two arguments */
+    return monitor_identify_cap_common(kernel_cap, root, &args[2]);
+}
+
+static struct sysret monitor_remote_cap(struct capability *kernel_cap,
+                                        int cmd, uintptr_t *args)
+{
+    struct capability *root = &dcb_current->cspace.cap;
+    capaddr_t cptr = args[0];
+    int bits = args[1];
+    bool remote = args[2];
+
+    struct cte *cte;
+    errval_t err = caps_lookup_slot(root, cptr, bits, &cte, CAPRIGHTS_WRITE);
+    if (err_is_fail(err)) {
+        return SYSRET(err_push(err, SYS_ERR_IDENTIFY_LOOKUP));
+    }
+
+    set_cap_remote(cte, remote);
+    bool has_desc = has_descendants(cte);
+
+    return (struct sysret){ .error = SYS_ERR_OK, .value = has_desc };
+}
+
+
+static struct sysret monitor_create_cap(struct capability *kernel_cap,
+                                        int cmd, uintptr_t *args)
+{
+    /* XXX: Get the raw metadata of the capability to create */
+    struct capability *src = (struct capability *)args;
+    int pos = sizeof(struct capability) / sizeof(uint64_t);
+
+    /* Certain types cannot be created here */
+    if ((src->type == ObjType_Null) || (src->type == ObjType_EndPoint)
+        || (src->type == ObjType_Dispatcher) || (src->type == ObjType_Kernel)
+        || (src->type == ObjType_IRQTable)) {
+        return SYSRET(SYS_ERR_ILLEGAL_DEST_TYPE);
+    }
+
+    /* Create the cap in the destination */
+    capaddr_t cnode_cptr = args[pos];
+    int cnode_vbits    = args[pos + 1];
+    size_t slot        = args[pos + 2];
+
+    return SYSRET(caps_create_from_existing(&dcb_current->cspace.cap,
+                                            cnode_cptr, cnode_vbits,
+                                            slot, src));
+}
+
+static struct sysret monitor_nullify_cap(struct capability *kernel_cap,
+                                         int cmd, uintptr_t *args)
+{
+    capaddr_t cptr = args[0];
+    uint8_t bits = args[1];
+
+    return sys_monitor_nullify_cap(cptr, bits);
+}
+
+static struct sysret monitor_iden_cnode_get_cap(struct capability *kern_cap,
+                                                int cmd, uintptr_t *args)
+{
+    errval_t err;
+
+    /* XXX: Get the raw metadata of the cnode */
+    int pos = sizeof(struct capability) / sizeof(uint64_t);
+    struct capability *cnode = (struct capability *)args;
+    assert(cnode->type == ObjType_CNode);
+
+    struct capability *cnode_copy;
+    err = mdb_get_copy(cnode, &cnode_copy);
+    if (err_is_fail(err)) {
+        return SYSRET(err);
+    }
+
+    capaddr_t slot = args[pos];
+    struct cte* cte = caps_locate_slot(cnode_copy->u.cnode.cnode, slot);
+
+    // XXX: Write cap data directly back to user-space
+    // FIXME: this should involve a pointer/range check for reliability,
+    // but because the monitor is inherently trusted it's not a security hole
+    struct capability *retbuf = (void *)args[pos + 1];
+    *retbuf = cte->cap;
+
+    return SYSRET(SYS_ERR_OK);
+}
+
+static struct sysret monitor_handle_sync_timer(struct capability *kern_cap,
+                                               int cmd, uintptr_t *args)
+{
+    uint64_t synctime = args[0];
+    return sys_monitor_handle_sync_timer(synctime);
+}
+
+static struct sysret handle_frame_identify(struct capability *to,
+                                           int cmd, uintptr_t *args)
+{
+    // Return with physical base address of frame
+    // XXX: pack size into bottom bits of base address
+    assert(to->type == ObjType_Frame || to->type == ObjType_DevFrame);
+    assert((to->u.frame.base & BASE_PAGE_MASK) == 0);
+    return (struct sysret) {
+        .error = SYS_ERR_OK,
+        .value = to->u.frame.base | to->u.frame.bits,
+    };
+}
+
+static struct sysret handle_frame_modify_flags(struct capability *to,
+                                               int cmd, uintptr_t *args)
+{
+    // Modify flags of (part of) mapped region of frame
+    assert(to->type == ObjType_Frame || to->type == ObjType_DevFrame);
+
+    // unpack arguments
+    size_t offset = args[0]; // in pages; of first page to modify from first
+                             // page in mapped region
+    size_t pages  = args[1]; // #pages to modify
+    size_t flags  = args[2]; // new flags
+
+    page_mappings_modify_flags(to, offset, pages, flags);
+
+    return (struct sysret) {
+        .error = SYS_ERR_OK,
+        .value = 0,
+    };
+}
+
+
+static struct sysret handle_io(struct capability *to, int cmd, uintptr_t *args)
+{
+    uint64_t    port = args[0];
+    uint64_t    data = args[1]; // ignored for input
+
+    return sys_io(to, cmd, port, data);
+}
+
+static struct sysret
+handle_dispatcher_setup_guest (struct capability *to, int cmd, uintptr_t *args)
+{
+    errval_t err;
+    struct dcb *dcb = to->u.dispatcher.dcb;
+
+    capaddr_t epp = args[0];
+    capaddr_t vnodep = args[1];
+    capaddr_t vmcbp = args[2];
+    capaddr_t ctrlp = args[3];
+
+    // 0. Enable VM extensions
+    err = vmkit_enable_virtualization();
+    if (err != SYS_ERR_OK) {
+        return SYSRET(err);
+    }
+
+    // 1. Check arguments
+    // Monitor endpoint for exits of this geust
+    struct cte *ep_cte;
+
+    err = caps_lookup_slot(&dcb_current->cspace.cap, epp, CPTR_BITS,
+                           &ep_cte, CAPRIGHTS_READ_WRITE);
+    if (err_is_fail(err)) {
+        return SYSRET(err);
+    }
+    if (ep_cte->cap.type != ObjType_EndPoint) {
+        return SYSRET(SYS_ERR_VMKIT_ENDPOINT_INVALID);
+    }
+    err = caps_copy_to_cte(&dcb->guest_desc.monitor_ep, ep_cte, false, 0, 0);
+    if (err_is_fail(err)) {
+        return SYSRET(err_push(err, SYS_ERR_VMKIT_ENDPOINT));
+    }
+
+    // Domain vspace
+    struct capability *vnode_cap;
+    err = caps_lookup_cap(&dcb_current->cspace.cap, vnodep, CPTR_BITS,
+                          &vnode_cap, CAPRIGHTS_WRITE);
+    if (err_is_fail(err)) {
+        return SYSRET(err);
+    }
+    if (vnode_cap->type != ObjType_VNode_x86_64_pml4) {
+        return SYSRET(SYS_ERR_DISP_VSPACE_INVALID);
+    }
+
+    assert(vnode_cap->type == ObjType_VNode_x86_64_pml4);
+
+    // VMCB
+    struct cte *vmcb_cte;
+    err = caps_lookup_slot(&dcb_current->cspace.cap, vmcbp, CPTR_BITS,
+                           &vmcb_cte, CAPRIGHTS_READ_WRITE);
+    if (err_is_fail(err)) {
+        return SYSRET(err);
+    }
+    if (vmcb_cte->cap.type != ObjType_Frame ||
+        vmcb_cte->cap.u.frame.bits < BASE_PAGE_BITS) {
+        return SYSRET(SYS_ERR_VMKIT_VMCB_INVALID);
+    }
+    err = caps_copy_to_cte(&dcb->guest_desc.vmcb, vmcb_cte, false, 0, 0);
+    if (err_is_fail(err)) {
+        return SYSRET(err_push(err, SYS_ERR_VMKIT_VMCB));
+    }
+
+    // guest control
+    struct cte *ctrl_cte;
+    err = caps_lookup_slot(&dcb_current->cspace.cap, ctrlp, CPTR_BITS,
+                           &ctrl_cte, CAPRIGHTS_READ_WRITE);
+    if (err_is_fail(err)) {
+        return SYSRET(err);
+    }
+    if (ctrl_cte->cap.type != ObjType_Frame ||
+        ctrl_cte->cap.u.frame.bits < BASE_PAGE_BITS) {
+        return SYSRET(SYS_ERR_VMKIT_CTRL_INVALID);
+    }
+    err = caps_copy_to_cte(&dcb->guest_desc.ctrl, ctrl_cte, false, 0, 0);
+    if (err_is_fail(err)) {
+        return SYSRET(err_push(err, SYS_ERR_VMKIT_CTRL));
+    }
+
+    // 2. Set up the target DCB
+/*     dcb->guest_desc.monitor_ep = ep_cap; */
+    dcb->vspace = vnode_cap->u.vnode_x86_64_pml4.base;
+    dcb->is_vm_guest = true;
+/*     dcb->guest_desc.vmcb = vmcb_cap->u.frame.base; */
+/*     dcb->guest_desc.ctrl = (void *)x86_64_phys_to_mem(ctrl_cap->u.frame.base); */
+
+    return SYSRET(SYS_ERR_OK);
+}
+
+static struct sysret monitor_handle_domain_id(struct capability *monitor_cap,
+                                              int cmd, uintptr_t *args)
+{
+    capaddr_t cptr = args[0];
+    domainid_t domain_id = args[1];
+
+    return sys_monitor_domain_id(cptr, domain_id);
+}
+
+/**
+ * \brief Set up tracing in the kernel
+ */
+static struct sysret handle_trace_setup(struct capability *cap,
+                                        int cmd, uintptr_t *args)
+{
+    struct capability *frame;
+    errval_t err;
+
+    /* lookup passed cap */
+    capaddr_t cptr = args[0];
+    err = caps_lookup_cap(&dcb_current->cspace.cap, cptr, CPTR_BITS, &frame,
+                          CAPRIGHTS_READ_WRITE);
+    if (err_is_fail(err)) {
+        return SYSRET(err);
+    }
+
+    lpaddr_t lpaddr = gen_phys_to_local_phys(frame->u.frame.base);
+    kernel_trace_buf = local_phys_to_mem(lpaddr);
+    //printf("kernel.%u: handle_trace_setup at %lx\n", apic_id, kernel_trace_buf);
+
+    // Copy boot applications.
+    trace_copy_boot_applications();
+
+    return SYSRET(SYS_ERR_OK);
+}
+
+static struct sysret handle_irq_table_set(struct capability *to, int cmd,
+                                          uintptr_t *args)
+{
+    return SYSRET(irq_table_set(args[0], args[1]));
+}
+
+static struct sysret handle_irq_table_delete(struct capability *to, int cmd,
+                                             uintptr_t *args)
+{
+    return SYSRET(irq_table_delete(args[0]));
+}
+
+static struct sysret handle_ipi_notify_send(struct capability *cap,
+                                            int cmd, uintptr_t *args)
+{
+    assert(cap->type == ObjType_Notify_IPI);
+    return ipi_raise_notify(cap->u.notify_ipi.coreid, cap->u.notify_ipi.chanid);
+}
+
+static struct sysret kernel_ipi_register(struct capability *cap,
+                                         int cmd, uintptr_t *args)
+{
+    assert(cap->type == ObjType_Kernel);
+    capaddr_t ep = args[0];
+    int chanid = args[1];
+    return SYSRET(ipi_register_notification(ep, chanid));
+}
+
+static struct sysret kernel_ipi_delete(struct capability *cap,
+                                       int cmd, uintptr_t *args)
+{
+    assert(cap->type == ObjType_Kernel);
+    assert(!"NYI");
+    return SYSRET(SYS_ERR_OK);
+}
+
+static struct sysret dispatcher_dump_ptables(struct capability *cap,
+                                             int cmd, uintptr_t *args)
+{
+    assert(cap->type == ObjType_Dispatcher);
+
+    printf("kernel_dump_ptables\n");
+
+    struct dcb *dispatcher = cap->u.dispatcher.dcb;
+
+    paging_dump_tables(dispatcher);
+
+    return SYSRET(SYS_ERR_OK);
+}
+
+/* 
+ * \brief Activate performance monitoring
+ * 
+ * Activates performance monitoring.
+ * \param xargs Expected parameters in args:
+ * - performance monitoring type
+ * - mask for given type
+ * - Counter id
+ * - Also count in privileged mode
+ * - Number of counts before overflow. This parameter may be used to
+ *   set tradeoff between accuracy and overhead. Set the counter to 0
+ *   to deactivate the usage of APIC.
+ * - Endpoint capability to be invoked when the counter overflows.
+ *   The buffer associated with the endpoint needs to be large enough
+ *   to hold several overflow notifications depending on the overflow 
+ *   frequency.
+ */
+static struct sysret performance_counter_activate(struct capability *cap,
+                                                  int cmd, uintptr_t *args)
+{
+    uint8_t event = args[0];
+    uint8_t umask = args[1];
+    uint8_t counter_id = args[2];
+    bool kernel = args[3];
+    uint64_t counter_value = args[4];
+    capaddr_t ep_addr = args[5];
+
+    errval_t err;
+    struct capability *ep;
+    extern struct capability perfmon_callback_ep;
+
+    // Make sure that 
+    assert(ep_addr!=0 || counter_value==0);
+
+    perfmon_init();
+    perfmon_measure_start(event, umask, counter_id, kernel, counter_value);
+
+    if(ep_addr!=0) {
+        
+        err = caps_lookup_cap(&dcb_current->cspace.cap, ep_addr, CPTR_BITS, &ep,
+                               CAPRIGHTS_READ);
+        if(err_is_fail(err)) {
+            return SYSRET(err);
+        }
+        
+        perfmon_callback_ep = *ep; 
+    }
+
+    return SYSRET(SYS_ERR_OK);
+}
+
+/* 
+ * \brief Write counter values.
+ */
+static struct sysret performance_counter_write(struct capability *cap,
+                                               int cmd, uintptr_t *args)
+{
+    uint8_t counter_id = args[0];
+    uint64_t counter_value = args[1];
+
+    perfmon_measure_write(counter_id, counter_value);
+    return SYSRET(SYS_ERR_OK);
+}
+
+/* 
+ * \brief Deactivate performance counters again.
+ */
+static struct sysret performance_counter_deactivate(struct capability *cap,
+                                                  int cmd, uintptr_t *args)
+{
+    perfmon_measure_stop();
+    return SYSRET(SYS_ERR_OK);
+}
+
+/*
+ * \brief Return system-wide unique ID of this ID cap.
+ */
+static struct sysret handle_idcap_identify(struct capability *cap, int cmd,
+                                           uintptr_t *args)
+{
+    idcap_id_t id;
+    struct sysret sysret = sys_idcap_identify(cap, &id);
+    sysret.value = id;
+
+    return sysret;
+}
+
+typedef struct sysret (*invocation_handler_t)(struct capability *to,
+                                              int cmd, uintptr_t *args);
+
+static invocation_handler_t invocations[ObjType_Num][CAP_MAX_CMD] = {
+    [ObjType_Dispatcher] = {
+        [DispatcherCmd_Setup] = handle_dispatcher_setup,
+        [DispatcherCmd_Properties] = handle_dispatcher_properties,
+        [DispatcherCmd_SetupGuest] = handle_dispatcher_setup_guest,
+        [DispatcherCmd_DumpPTables]  = dispatcher_dump_ptables,
+    },
+    [ObjType_Frame] = {
+        [FrameCmd_Identify] = handle_frame_identify,
+        [FrameCmd_ModifyFlags] = handle_frame_modify_flags,
+    },
+    [ObjType_DevFrame] = {
+        [FrameCmd_Identify] = handle_frame_identify,
+        [FrameCmd_ModifyFlags] = handle_frame_modify_flags,
+    },
+    [ObjType_CNode] = {
+        [CNodeCmd_Copy]   = handle_copy,
+        [CNodeCmd_Mint]   = handle_mint,
+        [CNodeCmd_Retype] = handle_retype,
+        [CNodeCmd_Create] = handle_create,
+        [CNodeCmd_Delete] = handle_delete,
+        [CNodeCmd_Revoke] = handle_revoke,
+    },
+    [ObjType_VNode_x86_64_pml4] = {
+        [VNodeCmd_Map]   = handle_map,
+        [VNodeCmd_Unmap] = handle_unmap,
+    },
+    [ObjType_VNode_x86_64_pdpt] = {
+        [VNodeCmd_Map]   = handle_map,
+        [VNodeCmd_Unmap] = handle_unmap,
+    },
+    [ObjType_VNode_x86_64_pdir] = {
+        [VNodeCmd_Map]   = handle_map,
+        [VNodeCmd_Unmap] = handle_unmap,
+    },
+    [ObjType_VNode_x86_64_ptable] = {
+        [VNodeCmd_Map]   = handle_map,
+        [VNodeCmd_Unmap] = handle_unmap,
+    },
+    [ObjType_Kernel] = {
+        [KernelCmd_Spawn_core]   = monitor_spawn_core,
+        [KernelCmd_Get_core_id]  = monitor_get_core_id,
+        [KernelCmd_Get_arch_id]  = monitor_get_arch_id,
+        [KernelCmd_Identify_cap] = monitor_identify_cap,
+        [KernelCmd_Identify_domains_cap] = monitor_identify_domains_cap,
+        [KernelCmd_Remote_cap]   = monitor_remote_cap,
+        [KernelCmd_Iden_cnode_get_cap] = monitor_iden_cnode_get_cap,
+        [KernelCmd_Create_cap]   = monitor_create_cap,
+        [KernelCmd_Nullify_cap]  = monitor_nullify_cap,
+        [KernelCmd_Setup_trace]  = handle_trace_setup,
+        [KernelCmd_Register]     = monitor_handle_register,
+        [KernelCmd_Domain_Id]    = monitor_handle_domain_id,
+        [MonitorCmd_Retype]      = monitor_handle_retype,
+        [MonitorCmd_Delete]      = monitor_handle_delete,
+        [MonitorCmd_Revoke]      = monitor_handle_revoke,
+        [KernelCmd_Sync_timer]   = monitor_handle_sync_timer,
+        [KernelCmd_IPI_Register] = kernel_ipi_register,
+        [KernelCmd_IPI_Delete]   = kernel_ipi_delete,
+    },
+    [ObjType_IRQTable] = {
+        [IRQTableCmd_Set] = handle_irq_table_set,
+        [IRQTableCmd_Delete] = handle_irq_table_delete
+    },
+    [ObjType_IO] = {
+        [IOCmd_Outb] = handle_io,
+        [IOCmd_Outw] = handle_io,
+        [IOCmd_Outd] = handle_io,
+        [IOCmd_Inb] = handle_io,
+        [IOCmd_Inw] = handle_io,
+        [IOCmd_Ind] = handle_io
+    },
+    [ObjType_Notify_IPI] = {
+        [NotifyCmd_Send] = handle_ipi_notify_send
+    },
+    [ObjType_PerfMon] = {
+        [PerfmonCmd_Activate] = performance_counter_activate,
+        [PerfmonCmd_Deactivate] = performance_counter_deactivate,
+        [PerfmonCmd_Write] = performance_counter_write,
+    },
+    [ObjType_ID] = {
+        [IDCmd_Identify] = handle_idcap_identify,
+    }
+};
+
+/* syscall C entry point; called only from entry.S so no prototype in header */
+struct sysret sys_syscall(uint64_t syscall, uint64_t arg0, uint64_t arg1,
+                          uint64_t *args, uint64_t rflags, uint64_t rip);
+struct sysret sys_syscall(uint64_t syscall, uint64_t arg0, uint64_t arg1,
+                          uint64_t *args, uint64_t rflags, uint64_t rip)
+{
+    struct sysret retval = { .error = SYS_ERR_OK, .value = 0 };
+
+    switch(syscall) {
+    case SYSCALL_INVOKE: /* Handle capability invocation */
+    {
+        // unpack "header" word
+        capaddr_t invoke_cptr = arg0 >> 32;
+        uint8_t send_bits = arg0 >> 24;
+        uint8_t invoke_bits = arg0 >> 16;
+        uint8_t length_words = arg0 >> 8;
+        uint8_t flags = arg0;
+
+        debug(SUBSYS_SYSCALL, "sys_invoke(0x%x(%d), 0x%lx)\n",
+              invoke_cptr, invoke_bits, arg1);
+
+        // Capability to invoke
+        struct capability *to = NULL;
+        retval.error = caps_lookup_cap(&dcb_current->cspace.cap, invoke_cptr,
+                                       invoke_bits, &to, CAPRIGHTS_READ);
+        if (err_is_fail(retval.error)) {
+            break;
+        }
+
+        assert(to != NULL);
+        assert(to->type < ObjType_Num);
+
+        // Endpoint cap, do LMP
+        if (to->type == ObjType_EndPoint) {
+            struct dcb *listener = to->u.endpoint.listener;
+            assert(listener != NULL);
+
+            if (listener->disp == 0) {
+                retval.error = SYS_ERR_LMP_NO_TARGET;
+                break;
+            }
+
+            /* limit length of message from buggy/malicious sender */
+            length_words = MIN(length_words, LMP_MSG_LENGTH);
+
+            // does the sender want to yield their timeslice on success?
+            bool sync = flags & LMP_FLAG_SYNC;
+            // does the sender want to yield to the target if undeliverable?
+            bool yield = flags & LMP_FLAG_YIELD;
+
+            // try to deliver message
+            retval.error = lmp_deliver(to, dcb_current, args, length_words,
+                                       arg1, send_bits);
+
+            /* Switch to reciever upon successful delivery with sync flag,
+             * or (some cases of) unsuccessful delivery with yield flag */
+            enum err_code err_code = err_no(retval.error);
+            if ((sync && err_is_ok(retval.error)) ||
+                (yield && (err_code == SYS_ERR_LMP_BUF_OVERFLOW
+                           || err_code == SYS_ERR_LMP_CAPTRANSFER_DST_CNODE_LOOKUP
+                           || err_code == SYS_ERR_LMP_CAPTRANSFER_DST_CNODE_INVALID
+                           || err_code == SYS_ERR_LMP_CAPTRANSFER_DST_SLOT_OCCUPIED))
+                    ) {
+                if (err_is_fail(retval.error)) {
+                    struct dispatcher_shared_generic *current_disp =
+                        get_dispatcher_shared_generic(dcb_current->disp);
+                    struct dispatcher_shared_generic *listener_disp =
+                        get_dispatcher_shared_generic(listener->disp);
+                    debug(SUBSYS_DISPATCH, "LMP failed; %.*s yields to %.*s: %u\n",
+                          DISP_NAME_LEN, current_disp->name,
+                          DISP_NAME_LEN, listener_disp->name, err_code);
+                }
+
+                // special-case context switch: ensure correct state in current DCB
+                dispatcher_handle_t handle = dcb_current->disp;
+                struct dispatcher_shared_x86_64 *disp =
+                    get_dispatcher_shared_x86_64(handle);
+                dcb_current->disabled = dispatcher_is_disabled_ip(handle, rip);
+                struct registers_x86_64 *save_area;
+                if (dcb_current->disabled) {
+                    save_area = &disp->disabled_save_area;
+                } else {
+                    save_area = &disp->enabled_save_area;
+                }
+
+                // save calling dispatcher's registers, so that when the dispatcher
+                // next runs, it has a valid state in the relevant save area.
+                // Save RIP, RFLAGS, RSP and set RAX (return value) for later resume
+                save_area->rax = retval.error; // XXX: x86 1st return register
+                save_area->rip = rip;
+                save_area->eflags = rflags;
+                save_area->rsp = user_stack_save;
+
+                /* save and zero FS/GS selectors (they're unmodified by the syscall path) */
+                __asm ("mov     %%fs, %[fs]     \n\t"
+                       "mov     %%gs, %[gs]     \n\t"
+                       "mov     %[zero], %%fs   \n\t"
+                       "mov     %[zero], %%gs   \n\t"
+                       : /* No output */
+                       :
+                       [fs] "m" (save_area->fs),
+                       [gs] "m" (save_area->gs),
+                       [zero] "r" (0)
+                       );
+
+                dispatch(to->u.endpoint.listener);
+                panic("dispatch returned");
+            }
+        } else { // not endpoint cap, call kernel handler through dispatch table
+            uint64_t cmd = args[0];
+            if (cmd >= CAP_MAX_CMD) {
+                retval.error = SYS_ERR_ILLEGAL_INVOCATION;
+                break;
+            }
+
+            // Call the invocation
+            invocation_handler_t invocation = invocations[to->type][cmd];
+            if(invocation == NULL) {
+                retval.error = SYS_ERR_ILLEGAL_INVOCATION;
+            } else {
+                retval = invocation(to, cmd, &args[1]);
+            }
+        }
+        break;
+    }
+
+        // Yield the CPU to the next dispatcher
+    case SYSCALL_YIELD:
+        retval = sys_yield((capaddr_t)arg0);
+        break;
+
+        // NOP system call for benchmarking purposes
+    case SYSCALL_NOP:
+        break;
+
+        // Debug print system call
+    case SYSCALL_PRINT:
+        retval.error = sys_print((char *)arg0, arg1);
+        break;
+
+        // Reboot!
+        // FIXME: this should be a kernel cap invocation or similarly restricted
+    case SYSCALL_REBOOT:
+        reboot();
+        break;
+
+    case SYSCALL_X86_FPU_TRAP_ON:
+        fpu_trap_on();
+        break;
+
+    case SYSCALL_X86_RELOAD_LDT:
+        maybe_reload_ldt(dcb_current, true);
+        break;
+
+    case SYSCALL_DEBUG:
+        switch(arg0) {
+        case DEBUG_CONTEXT_COUNTER_RESET:
+            dispatch_csc_reset();
+            break;
+
+        case DEBUG_CONTEXT_COUNTER_READ:
+            retval.value = dispatch_get_csc();
+            break;
+
+        case DEBUG_TIMESLICE_COUNTER_READ:
+            retval.value = kernel_now;
+            break;
+
+        case DEBUG_FLUSH_CACHE:
+            wbinvd();
+            break;
+
+        case DEBUG_SEND_IPI:
+            apic_send_std_ipi(arg1, args[0], args[1]);
+            break;
+
+        case DEBUG_SET_BREAKPOINT:
+            debugregs_set_breakpoint(arg1, args[0], args[1]);
+            break;
+
+        case DEBUG_GET_TSC_PER_MS:
+            retval.value = timing_get_tsc_per_ms();
+            break;
+
+        case DEBUG_GET_APIC_TIMER:
+            retval.value = apic_timer_get_count();
+            break;
+
+        case DEBUG_GET_APIC_TICKS_PER_SEC:
+            retval.value = timing_get_apic_ticks_per_sec();
+            break;
+
+        default:
+            printk(LOG_ERR, "invalid sys_debug msg type\n");
+        }
+        break;
+
+    default:
+        printk(LOG_ERR, "sys_syscall: Illegal system call! "
+               "(0x%lx, 0x%lx, 0x%lx)\n", syscall, arg0, arg1);
+        retval.error = SYS_ERR_ILLEGAL_SYSCALL;
+        break;
+    }
+
+    // If dcb_current got removed, dispatch someone else
+    if (dcb_current == NULL) {
+        assert(err_is_ok(retval.error));
+        dispatch(schedule());
+    }
+
+    if (syscall == SYSCALL_INVOKE) {
+        debug(SUBSYS_SYSCALL, "invoke returning 0x%lx 0x%lx\n",
+              retval.error, retval.value);
+    }
+
+    return retval;
+}
diff --git a/kernel/arch/k1om/vmkit.c b/kernel/arch/k1om/vmkit.c
new file mode 100644 (file)
index 0000000..e9a7310
--- /dev/null
@@ -0,0 +1,276 @@
+/**
+ * \file
+ * \brief VMKit Kernel interface.
+ */
+
+/*
+ * Copyright (c) 2009, 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <string.h>
+#include <kernel.h>
+#include <paging_kernel_arch.h>
+#include <vmkit.h>
+#include <x86.h>
+#include <dispatch.h>
+#include <exec.h>
+#include <barrelfish_kpi/vmkit.h>
+
+#include <amd_vmcb_dev.h>
+
+// SVM relevant CPUID info
+#define CPUID_AMD_EXTFEAT       0x80000001
+#define AMD_EXTFEAT_ECX_SVM     (1 << 2)
+
+// some EXITCODE values
+#define VMEXIT_INTR     0x60
+#define VMEXIT_NMI      0x61
+#define VMEXIT_SMI      0x62
+#define VMEXIT_VMMCALL  0x81
+
+/**
+ * \brief The storage area where SVM puts the host state during guest exec.
+ */
+static uint8_t host_save_area[BASE_PAGE_SIZE]
+__attribute__ ((aligned(BASE_PAGE_SIZE)));
+
+/**
+ * \brief VMCB for the host to save its state.
+ */
+static uint8_t host_vmcb[BASE_PAGE_SIZE]
+__attribute__ ((aligned(BASE_PAGE_SIZE)));
+
+static void
+vmkit_init (void)
+{
+    static bool executed = false;
+
+    if (executed) {
+        return;
+    }
+
+    executed = true;
+    memset(host_save_area, 0x0, BASE_PAGE_SIZE);
+    memset(host_vmcb, 0x0, BASE_PAGE_SIZE);
+}
+
+/**
+ * \brief Tries to enable hardware assisted virtualization.
+ *
+ * Checks whether hardware assisted virtualization is available on the platform
+ * and enables this feature.
+ *
+ * \Return Returns VMKIT_ERR_OK on successful initialization of the subsystem
+ *         or VMKIT_ERR_UNAVAIL if virtualization is unavailable.
+ */
+errval_t
+vmkit_enable_virtualization (void)
+{
+    vmkit_init ();
+
+    // first check what CPUID tells us about SVM support
+    uint32_t cpuid_ecx;
+    cpuid(CPUID_AMD_EXTFEAT, NULL, NULL, &cpuid_ecx, NULL);
+    if (!(cpuid_ecx & AMD_EXTFEAT_ECX_SVM)) {
+        return SYS_ERR_VMKIT_UNAVAIL;
+    }
+
+    // check whether SVM support is deactivated
+    uint64_t msr_vmcr = rdmsr(MSR_AMD_VMCR);
+    if (msr_vmcr & AMD_VMCR_SVMDIS) {
+        return SYS_ERR_VMKIT_UNAVAIL;
+    }
+
+    // from here on we assume that SVM is avail and may be enabled
+
+    // check whether SVM is already enabled
+    uint64_t msr_efer = rdmsr(MSR_IA32_EFER);
+    if (msr_efer & IA32_EFER_SVME) {
+        // SVM is already enabled
+        return SYS_ERR_OK;
+    }
+    // enable SVM
+    addmsr(MSR_IA32_EFER, IA32_EFER_SVME);
+    // check whether SVM is now enabled
+    msr_efer = rdmsr(MSR_IA32_EFER);
+    if (msr_efer & IA32_EFER_SVME) {
+        // SVM enabled
+        // set the host save area
+        wrmsr(MSR_AMD_VM_HSAVE, mem_to_local_phys((lvaddr_t)host_save_area));
+        return SYS_ERR_OK;
+    } else {
+        printk(LOG_WARN, "VMKit: Unable to enable SVM although the hardware "
+               "claims to support it.\n");
+        return SYS_ERR_VMKIT_UNAVAIL;
+    }
+}
+
+static inline void
+vm_exec (struct dcb *dcb)
+{
+    lpaddr_t lpaddr = gen_phys_to_local_phys(dcb->guest_desc.ctrl.cap.u.frame.base);
+    struct guest_control *ctrl = (void *)local_phys_to_mem(lpaddr);
+    register uintptr_t rbx __asm("rbx") = ctrl->regs.rbx;
+    register uintptr_t rcx __asm("rcx") = ctrl->regs.rcx;
+    register uintptr_t rdx __asm("rdx") = ctrl->regs.rdx;
+    register uintptr_t rsi __asm("rsi") = ctrl->regs.rsi;
+    register uintptr_t rdi __asm("rdi") = ctrl->regs.rdi;
+    register uintptr_t r8  __asm("r8")  = ctrl->regs.r8;
+    register uintptr_t r9  __asm("r9")  = ctrl->regs.r9;
+    register uintptr_t r10 __asm("r10") = ctrl->regs.r10;
+    register uintptr_t r11 __asm("r11") = ctrl->regs.r11;
+    register uintptr_t r12 __asm("r12") = ctrl->regs.r12;
+    register uintptr_t r13 __asm("r13") = ctrl->regs.r13;
+    register uintptr_t r14 __asm("r14") = ctrl->regs.r14;
+    register uintptr_t r15 __asm("r15") = ctrl->regs.r15;
+#ifdef NDEBUG
+    register uintptr_t rbp __asm("rbp") = ctrl->regs.rbp;
+
+    __asm volatile ("sti\n\t"       // allow intr to happen inside the host
+                    "vmrun\n\t"     // execute the guest
+                    "cli\n\t"       // disable intr in the host again
+                    "stgi\n\t"      // enable the global intr flag
+        : "+r" (rbx), "+r" (rcx), "+r" (rdx), "+r" (rbp), "+r" (rsi), "+r" (rdi),
+          "+r" (r8), "+r" (r9), "+r" (r10), "+r" (r11), "+r" (r12), "+r" (r13),
+          "+r" (r14), "+r" (r15)
+        : "a" (dcb->guest_desc.vmcb.cap.u.frame.base)
+        : "memory");
+#else
+    static uintptr_t rbp, srbp;
+
+    rbp = ctrl->regs.rbp;
+
+    __asm volatile ("mov %%rbp, %[srbp]\n\t" :: [srbp] "m" (srbp));
+
+    __asm volatile ("mov %[nrbp], %%rbp\n\t"
+                    "sti\n\t"       // allow intr to happen inside the host
+                    "vmrun\n\t"     // execute the guest
+                    "cli\n\t"       // disable intr in the host again
+                    "stgi\n\t"      // enable the global intr flag
+                    "mov %%rbp, %[nrbp]\n\t"
+        : "+r" (rbx), "+r" (rcx), "+r" (rdx), [nrbp] "+m" (rbp),
+                    "+r" (rsi), "+r" (rdi), "+r" (r8), "+r" (r9), "+r" (r10),
+                    "+r" (r11), "+r" (r12), "+r" (r13), "+r" (r14), "+r" (r15)
+        : "a" (dcb->guest_desc.vmcb.cap.u.frame.base)
+        : "memory");
+
+    __asm volatile ("mov %[srbp], %%rbp\n\t"
+                    : [srbp] "+m" (srbp));
+#endif
+
+    ctrl->regs.rbx = rbx;
+    ctrl->regs.rcx = rcx;
+    ctrl->regs.rdx = rdx;
+    ctrl->regs.rbp = rbp;
+    ctrl->regs.rsi = rsi;
+    ctrl->regs.rdi = rdi;
+    ctrl->regs.r8 = r8;
+    ctrl->regs.r9 = r9;
+    ctrl->regs.r10 = r10;
+    ctrl->regs.r11 = r11;
+    ctrl->regs.r12 = r12;
+    ctrl->regs.r13 = r13;
+    ctrl->regs.r14 = r14;
+    ctrl->regs.r15 = r15;
+}
+
+static inline void
+vmload (lpaddr_t vmcb) {
+    __asm volatile ("vmload" : : "a" (vmcb) : "memory");
+}
+
+static inline void
+vmsave (lpaddr_t vmcb) {
+    __asm volatile ("vmsave" : : "a" (vmcb) : "memory");
+}
+
+static inline void
+vmkit_switch_to (struct dcb *dcb)
+{
+    assert(dcb != NULL);
+    assert(dcb->is_vm_guest);
+
+    // save the host state
+    vmsave(mem_to_local_phys((lvaddr_t)host_vmcb));
+    // load the guest state
+    vmload(gen_phys_to_local_phys(dcb->guest_desc.vmcb.cap.u.frame.base));
+}
+
+static inline void
+vmkit_switch_from (struct dcb *dcb)
+{
+    assert(dcb != NULL);
+    assert(dcb->is_vm_guest);
+
+    // save the guest state
+    vmsave(gen_phys_to_local_phys(dcb->guest_desc.vmcb.cap.u.frame.base));
+    // load the host state
+    vmload(mem_to_local_phys((lvaddr_t)host_vmcb));
+}
+
+void __attribute__ ((noreturn))
+vmkit_vmenter (struct dcb *dcb)
+{
+    lpaddr_t lpaddr = gen_phys_to_local_phys(dcb->guest_desc.ctrl.cap.u.frame.base);
+    struct guest_control *ctrl = (void *)local_phys_to_mem(lpaddr);
+
+    assert(dcb != NULL);
+    assert(dcb->vspace != 0);
+    assert(dcb->is_vm_guest);
+
+    lpaddr = gen_phys_to_local_phys(dcb->guest_desc.vmcb.cap.u.frame.base);
+    amd_vmcb_t vmcb;
+    amd_vmcb_initialize(&vmcb, (void *)local_phys_to_mem(lpaddr));
+
+    /* We need to set the page translation mode. If nested paging is disabled
+     * then we need to set the guest cr3 to the value of the domains vspace. If
+     * nested paging is enabled then we need to copy the domains vspace into the
+     * ncr3 field of the vmcb. */
+    if (amd_vmcb_np_rd(&vmcb).enable) {
+        amd_vmcb_ncr3_wr(&vmcb, dcb->vspace);
+    } else {
+        amd_vmcb_cr3_wr(&vmcb, dcb->vspace);
+    }
+
+    // Enter the guest
+    vmkit_switch_to(dcb);
+    vm_exec(dcb);
+    vmkit_switch_from(dcb);
+
+    // Here we exited the guest due to some intercept triggered a vm exit
+    // our state is automatically restored by SVM
+
+    uint64_t ec = amd_vmcb_exitcode_rd(&vmcb);
+    /* We treat exits due to pysical interrupts (INTR, NMI, SMI) specially since
+     * they need to be processed by the kernel interrupt service routines */
+    if (ec == VMEXIT_INTR || ec == VMEXIT_NMI || ec == VMEXIT_SMI) {
+
+        ctrl->num_vm_exits_without_monitor_invocation++;
+        // wait for interrupt will enable interrupts and therefore trigger their
+        // corresponding handlers (which may be the monitor)
+        wait_for_interrupt();
+    } else {
+        ctrl->num_vm_exits_with_monitor_invocation++;
+        /* the guest exited not due to an interrupt but some condition the
+         * monitor has to handle, therefore notify the monitor */
+
+        assert(dcb->is_vm_guest);
+
+        // disable the domain
+        scheduler_remove(dcb);
+
+        // call the monitor
+        errval_t err = lmp_deliver_notification(&dcb->guest_desc.monitor_ep.cap);
+        if (err_is_fail(err)) {
+            printk(LOG_ERR, "Unexpected error delivering VMM call");
+        }
+
+        // run the monitor
+        dispatch(dcb->guest_desc.monitor_ep.cap.u.endpoint.listener);
+    }
+}
diff --git a/lib/barrelfish/arch/k1om/debug.c b/lib/barrelfish/arch/k1om/debug.c
new file mode 100644 (file)
index 0000000..1b28ea7
--- /dev/null
@@ -0,0 +1,106 @@
+/**
+ * \file
+ * \brief Arch specific debugging functions
+ */
+
+/*
+ * Copyright (c) 2010, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <stdio.h>
+#include <barrelfish/barrelfish.h>
+#include <barrelfish/caddr.h>
+#include <barrelfish/debug.h>
+#include <barrelfish/dispatch.h>
+#include <if/monitor_defs.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#define NR_OF_DISPLAYED_RET_ADDRS   10
+
+/**
+ * \brief Dump out various memory regions and a partial backtrace.
+ *
+ * Mainly for debugging traps and faults in the dispatcher handlers.
+ */
+void debug_dump(arch_registers_state_t *archregs)
+{
+    struct registers_x86_64 *regs = archregs;
+
+    debug_printf("Dumping stack (0x%lx)...\n", regs->rsp);
+    debug_dump_mem_around_addr(regs->rsp);
+    // debug_printf("Dumping code (0x%lx)...\n", regs->rip);
+    // debug_dump_mem_around_addr(regs->rip);
+    // debug_printf("Dumping memory around rbp (0x%lx)\n", regs->rbp);
+    // debug_dump_mem_around_addr(regs->rbp);
+}
+
+static void debug_call_chain_rbp(uintptr_t bp)
+{
+    uintptr_t ret_addr;
+    uintptr_t user_rbp = bp;
+
+    for (int it = 0; it < NR_OF_DISPLAYED_RET_ADDRS; it++) {
+        if (user_rbp < BASE_PAGE_SIZE || (user_rbp % sizeof(uintptr_t)) != 0) {
+            break;
+        }
+        // get return address
+        ret_addr = *(uintptr_t *)(user_rbp + sizeof(uintptr_t));
+        debug_printf("return address = 0x%" PRIxPTR "\n", ret_addr);
+        // get next RBP
+        user_rbp = *(uintptr_t *)user_rbp;
+    }
+}
+
+void debug_call_chain(arch_registers_state_t *archregs)
+{
+    debug_call_chain_rbp(archregs->rbp);
+}
+
+/**
+ * \brief Print out the registers in a dispatcher save area, for trap handlers.
+ */
+void debug_print_save_area(arch_registers_state_t *state)
+{
+//#define P(x) debug_printf("%16lx "#x"\n", (uintptr_t)state->x);
+#define P(x) printf("%16lx "#x"\n", (uintptr_t)state->x);
+
+    P(rip);
+    P(rsp);
+    P(rbp);
+    P(rax);
+    P(rbx);
+    P(rcx);
+    P(rdx);
+    P(rdi);
+    P(rsi);
+    P(r8);
+    P(r9);
+    P(r10);
+    P(r11);
+    P(r12);
+    P(r13);
+    P(r14);
+    P(r15);
+    P(eflags);
+    P(fs);
+    P(gs);
+
+#undef P
+}
+
+void debug_return_addresses(void)
+{
+    printf("return address = %p\n", __builtin_return_address(0));
+    printf("return address = %p\n", __builtin_return_address(1));
+    printf("return address = %p\n", __builtin_return_address(2));
+    printf("return address = %p\n", __builtin_return_address(3));
+    printf("return address = %p\n", __builtin_return_address(4));
+}
diff --git a/lib/barrelfish/arch/k1om/dispatch.c b/lib/barrelfish/arch/k1om/dispatch.c
new file mode 100644 (file)
index 0000000..0522ff6
--- /dev/null
@@ -0,0 +1,263 @@
+/**
+ * \file
+ * \brief Dispatcher architecture-specific implementation.
+ */
+
+/*
+ * Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+#include <barrelfish/dispatch.h>
+#include <barrelfish/dispatcher_arch.h>
+#include <barrelfish/curdispatcher_arch.h>
+#include <barrelfish/syscalls.h>
+#include "threads_priv.h"
+#include <arch/ldt.h>
+
+/* entry points defined in assembler code */
+extern void run_entry(void);
+extern void pagefault_entry(void);
+extern void disabled_pagefault_entry(void);
+extern void trap_entry(void);
+extern void lrpc_entry(void);
+
+void __attribute__ ((visibility ("hidden"))) disp_resume_end(void);
+
+/**
+ * \brief Architecture-specific dispatcher initialisation
+ */
+void disp_arch_init(dispatcher_handle_t handle)
+{
+    struct dispatcher_shared_x86_64 *disp =
+        get_dispatcher_shared_x86_64(handle);
+
+    /* Set entry points */
+    disp->d.dispatcher_run = (lvaddr_t)run_entry;
+    disp->d.dispatcher_lrpc = (lvaddr_t)lrpc_entry;
+    disp->d.dispatcher_pagefault = (lvaddr_t)pagefault_entry;
+    disp->d.dispatcher_pagefault_disabled = (lvaddr_t)disabled_pagefault_entry;
+    disp->d.dispatcher_trap = (lvaddr_t)trap_entry;
+
+    disp->crit_pc_low = (lvaddr_t)disp_resume;
+    disp->crit_pc_high = (lvaddr_t)disp_resume_end;
+
+    /* Setup LDT */
+    ldt_init_disabled(handle);
+}
+
+/**
+ * \brief Resume execution of a given register state
+ *
+ * This function resumes the execution of the given register state on the
+ * current dispatcher. It may only be called while the dispatcher is disabled.
+ *
+ * \param disp Current dispatcher pointer
+ * \param regs Register state snapshot
+ */
+void disp_resume(dispatcher_handle_t handle, arch_registers_state_t *archregs)
+{
+    struct dispatcher_shared_generic *disp =
+        get_dispatcher_shared_generic(handle);
+
+    assert_disabled(disp->disabled);
+    assert_disabled(disp->haswork);
+
+    /* sanity check user state */
+    struct registers_x86_64 *regs = archregs;
+    assert_disabled(regs->rip > BASE_PAGE_SIZE);
+    assert_disabled((regs->eflags & USER_EFLAGS) == USER_EFLAGS); // flags
+
+#ifdef CONFIG_DEBUG_DEADLOCKS
+    ((struct disp_priv *)disp)->yieldcount = 0;
+#endif
+
+    // Re-enable dispatcher
+    disp->disabled = false; // doesn't take effect while we're in disp_resume()
+
+    // Resume program execution
+    __asm volatile ("mov        %[fs], %%ax             \n\t"
+                    "mov        %%ax, %%fs              \n\t"
+                    "mov        %[gs], %%ax             \n\t"
+                    "mov        %%ax, %%gs              \n\t"
+                    "movq        0*8(%[regs]), %%rax    \n\t"
+                    "movq        2*8(%[regs]), %%rcx    \n\t"
+                    "movq        3*8(%[regs]), %%rdx    \n\t"
+                    "movq        4*8(%[regs]), %%rsi    \n\t"
+                    "movq        5*8(%[regs]), %%rdi    \n\t"
+                    "movq        6*8(%[regs]), %%rbp    \n\t"
+                    "movq        8*8(%[regs]), %%r8     \n\t"
+                    "movq        9*8(%[regs]), %%r9     \n\t"
+                    "movq       10*8(%[regs]), %%r10    \n\t"
+                    "movq       11*8(%[regs]), %%r11    \n\t"
+                    "movq       12*8(%[regs]), %%r12    \n\t"
+                    "movq       13*8(%[regs]), %%r13    \n\t"
+                    "movq       14*8(%[regs]), %%r14    \n\t"
+                    "movq       15*8(%[regs]), %%r15    \n\t"
+                    "pushq      %[ss]                   \n\t"   // SS
+                    "pushq       7*8(%[regs])           \n\t"   // RSP
+                    "pushq      17*8(%[regs])           \n\t"   // RFLAGS
+                    "pushq      %[cs]                   \n\t"   // CS
+                    "pushq      16*8(%[regs])           \n\t"   // RIP
+                    "movq        1*8(%[regs]), %%rbx    \n\t"   // RBX was base register
+                    "iretq                              \n\t"
+                    : /* No output */
+                    :
+                    [regs] "b" (regs),
+                    [ss] "i" (USER_SS),
+                    [cs] "i" (USER_CS),
+                    [fs] "m" (regs->fs),
+                    [gs] "m" (regs->gs)
+                    );
+
+    __asm volatile ("disp_resume_end:");
+}
+
+/**
+ * \brief Switch execution between two register states, and turn off
+ * disabled activations.
+ *
+ * This function saves as much as necessary of the current register state
+ * (which, when resumed will return to the caller), and switches execution
+ * by resuming the given register state.  It may only be called while the
+ * dispatcher is disabled.  A side effect is that activations are reenabled.
+ * Note that the thread context saved is a voluntary save so only callee
+ * save registers need to be saved, but we dont currently provide any
+ * way to optimise the corresponding resume.
+ *
+ * \param disp Current dispatcher pointer
+ * \param from_regs Location to save current register state
+ * \param to_regs Location from which to resume new register state
+ */
+// XXX: Needs to be compiled with -O2, otherwise we use too many
+// registers. Have to think about how to circumvent this without needing
+// -O2.
+void
+#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC)
+__attribute__((optimize(2)))
+#endif
+disp_switch(dispatcher_handle_t handle, arch_registers_state_t *from_state,
+            arch_registers_state_t *to_state)
+{
+    struct dispatcher_shared_generic *disp =
+        get_dispatcher_shared_generic(handle);
+    assert_disabled(disp->disabled);
+    assert_disabled(disp->haswork);
+
+    struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle);
+
+    struct registers_x86_64 *from_regs = (struct registers_x86_64*)from_state;
+    struct registers_x86_64 *to_regs   = (struct registers_x86_64*)to_state;
+    assert_disabled(to_regs != NULL);
+
+    // Save resume IP, stack and control registers, ...
+    // then switch stacks to dispatcher, and call resume to switch context
+    // Note the embedded call to disp_resume above.
+    /*
+     * NB: we shouldn't have to save RBP here, rather just list it as clobbered
+     * However, GCC without optimisations uses RBP as a frame pointer and won't
+     * let us do that, so instead we manually save and restore it. This is
+     * usually redundant (without optimisation, GCC saves and restores it; with
+     * optimisation the register is used and thus GCC saves it anyway).
+     */
+    __asm volatile ("movq       %%rbp,  6*8(%[regs])    \n\t"
+                    "movq       %%rsp,  7*8(%[regs])    \n\t"
+                    "lea        switch_resume(%%rip), %%rcx\n\t"
+                    "movq       %%rcx, 16*8(%[regs])    \n\t"   // RIP
+                    "pushfq                             \n\t"
+                    "popq       17*8(%[regs])           \n\t"   // RFLAGS
+                    "mov        %%fs, %%bx              \n\t"
+                    "mov        %%bx, %[fs]             \n\t"
+                    "mov        %%gs, %%bx              \n\t"
+                    "mov        %%bx, %[gs]             \n\t"
+                    "movq       %[stack], %%rsp         \n\t"   // Switch stack
+                    "callq      disp_resume             \n\t"
+                    :
+                    : [regs] "a" (from_regs),
+                      [fs] "m" (from_regs->fs),
+                      [gs] "m" (from_regs->gs),
+                      [stack] "d" ((lvaddr_t)&disp_gen->stack[DISPATCHER_STACK_WORDS]),
+                      [disp] "D" (disp),
+                      [to_regs] "S" (to_regs)
+                    : "rbx", "rcx", "rsp",
+                      "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
+                    );
+
+    __asm volatile ("switch_resume:");
+}
+
+/**
+ * \brief Save the current register state and optionally yield the CPU
+ *
+ * This function saves as much as necessary of the current register state
+ * (which, when resumed will return to the caller), and then either
+ * re-enters the thread scheduler or yields the CPU.
+ * It may only be called while the dispatcher is disabled.
+ * Note that the thread context saved is a voluntary save so only callee
+ * save registers need to be saved, but we dont currently provide any
+ * way to optimise the corresponding resume.
+ *
+ * \param disp Current dispatcher pointer
+ * \param regs Location to save current register state
+ * \param yield If true, yield CPU to kernel; otherwise re-run thread scheduler
+ * \param yield_to Endpoint capability for dispatcher to which we want to yield
+ */
+// XXX: Needs to be compiled with -O2, otherwise we use too many
+// registers. Have to think about how to circumvent this without needing
+// -O2.
+void
+#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC)
+__attribute__((optimize(2)))
+#endif
+disp_save(dispatcher_handle_t handle, arch_registers_state_t *state,
+          bool yield, capaddr_t yield_to)
+{
+    struct dispatcher_shared_generic *disp =
+        get_dispatcher_shared_generic(handle);
+    assert_disabled(disp->disabled);
+
+    struct registers_x86_64 *regs = state;
+
+    // Save resume IP, stack and control registers
+    // See disp_switch above for details
+    // XXX: Using the clobber list here to make the compiler save only
+    // used registers. Be very careful when changing the code below
+    // this asm block! If registers in the clobber list are
+    // subsequently used, they won't be restored at save_resume.
+    __asm volatile ("movq       %%rbp,  6*8(%[regs])    \n\t"
+                    "movq       %%rsp,  7*8(%[regs])    \n\t"
+                    "lea        save_resume(%%rip), %%rcx\n\t"
+                    "movq       %%rcx, 16*8(%[regs])    \n\t"   // RIP
+                    "pushfq                             \n\t"
+                    "popq       17*8(%[regs])           \n\t"   // RFLAGS
+