summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2020-07-09 22:44:41 +0200
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2020-07-09 22:45:28 +0200
commit6cd23e1aa4f3557260e0cf75a2de2c142f8d8f48 (patch)
tree5efb48a5772f94a29035634640c41cf5d7915d62
parent4b1bb4b36aafc6391981d88ddcf26eb93b309c59 (diff)
parent2dbf108457d0a0057cc63d5b3b89fd4da48d2a72 (diff)
Merge branch 'master' into master-user_level_drivers
-rw-r--r--Makefile.am1
-rw-r--r--Makefrag.am12
-rw-r--r--configfrag-first.ac29
-rw-r--r--configfrag.ac13
-rw-r--r--configure.ac11
-rw-r--r--ddb/db_examine.c12
-rw-r--r--device/dev_pager.c4
-rw-r--r--device/ds_routines.c1
-rw-r--r--device/io_req.h2
-rw-r--r--device/net_io.h10
-rw-r--r--device/subrs.h3
-rw-r--r--device/tty.h2
-rw-r--r--doc/mach.texi29
-rw-r--r--i386/configfrag.ac19
-rw-r--r--i386/i386/cpu_number.h5
-rw-r--r--i386/i386/db_interface.c28
-rw-r--r--i386/i386/db_machdep.h2
-rw-r--r--i386/i386/db_trace.c8
-rw-r--r--i386/i386/fpu.c2
-rw-r--r--i386/i386/gdt.c12
-rw-r--r--i386/i386/gdt.h59
-rw-r--r--i386/i386/hardclock.c2
-rw-r--r--i386/i386/i386asm.sym11
-rw-r--r--i386/i386/idt.c2
-rw-r--r--i386/i386/ktss.c6
-rw-r--r--i386/i386/ldt.c8
-rw-r--r--i386/i386/ldt.h9
-rw-r--r--i386/i386/locore.S2
-rw-r--r--i386/i386/model_dep.h5
-rw-r--r--i386/i386/mp_desc.c4
-rw-r--r--i386/i386/pcb.c3
-rw-r--r--i386/i386/pic.h4
-rw-r--r--i386/i386/pio.h2
-rw-r--r--i386/i386/pit.h4
-rw-r--r--i386/i386/proc_reg.h43
-rw-r--r--i386/i386/seg.h60
-rw-r--r--i386/i386/setjmp.h4
-rw-r--r--i386/i386/thread.h26
-rw-r--r--i386/i386/trap.c20
-rw-r--r--i386/i386/vm_param.h26
-rw-r--r--i386/i386/xen.h138
-rw-r--r--i386/i386at/biosmem.c5
-rw-r--r--i386/i386at/com.c12
-rw-r--r--i386/i386at/kdasm.S12
-rw-r--r--i386/i386at/model_dep.c29
-rw-r--r--i386/i386at/rtc.c2
-rw-r--r--i386/i386at/rtc.h2
-rw-r--r--i386/include/mach/i386/asm.h27
-rwxr-xr-xi386/include/mach/i386/machine_types.defs5
-rw-r--r--i386/include/mach/i386/multiboot.h17
-rw-r--r--i386/include/mach/i386/vm_param.h4
-rw-r--r--i386/include/mach/i386/vm_types.h12
-rw-r--r--i386/intel/pmap.c137
-rw-r--r--i386/intel/pmap.h40
-rw-r--r--i386/linux/dev/include/linux/autoconf.h2
-rw-r--r--i386/xen/xen.c2
-rw-r--r--include/inttypes.h62
-rw-r--r--include/mach/experimental.defs15
-rw-r--r--include/mach/gnumach.defs24
-rw-r--r--include/mach/mach.defs33
-rw-r--r--include/mach/xen.h4
-rw-r--r--ipc/mach_port.c4
-rw-r--r--kern/boot_script.c4
-rw-r--r--kern/bootstrap.c25
-rw-r--r--kern/cpu_number.h2
-rw-r--r--kern/experimental.srv3
-rw-r--r--kern/ipc_kobject.c2
-rw-r--r--kern/processor.c2
-rw-r--r--kern/syscall_sw.h2
-rw-r--r--kern/time_stamp.c2
-rw-r--r--kern/time_stamp.h2
-rw-r--r--linux/dev/drivers/block/genhd.c251
-rw-r--r--linux/dev/glue/kmem.c4
-rw-r--r--linux/dev/include/linux/genhd.h67
-rw-r--r--linux/pcmcia-cs/modules/pci_fixup.c2
-rw-r--r--linux/src/drivers/scsi/in2000.h2
-rw-r--r--vm/vm_kern.c46
-rw-r--r--vm/vm_kern.h1
-rw-r--r--vm/vm_object.c1
-rw-r--r--vm/vm_user.c56
-rw-r--r--x86_64/Makefrag.am277
-rw-r--r--x86_64/_setjmp.S65
-rw-r--r--x86_64/configfrag.ac58
-rw-r--r--x86_64/cswitch.S150
-rw-r--r--x86_64/debug_trace.S56
-rw-r--r--x86_64/idt_inittab.S146
l---------x86_64/include/mach/x86_641
-rw-r--r--x86_64/interrupt.S84
-rw-r--r--x86_64/kdasm.S133
-rw-r--r--x86_64/ldscript219
-rw-r--r--x86_64/locore.S1458
-rw-r--r--x86_64/spl.S255
l---------x86_64/x86_641
-rw-r--r--x86_64/xen_boothdr.S189
-rw-r--r--x86_64/xen_locore.S146
-rw-r--r--xen/console.c1
-rw-r--r--xen/evt.c7
-rw-r--r--xen/grant.c5
-rw-r--r--xen/net.c20
-rw-r--r--xen/public/io/ring.h6
-rw-r--r--xen/store.c2
-rw-r--r--xen/time.c8
-rw-r--r--xen/xen.h2
103 files changed, 4599 insertions, 257 deletions
diff --git a/Makefile.am b/Makefile.am
index d1968b85..2bfdcee9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -172,6 +172,7 @@ clib_routines := htonl htons ntohl ntohs \
udivdi3 __udivdi3 __udivmoddi4 __umoddi3 \
__divdi3 __moddi3 \
__rel_iplt_start __rel_iplt_end \
+ __rela_iplt_start __rela_iplt_end \
__ffsdi2 ffs \
_START _start etext _edata end _end # actually ld magic, not libc.
gnumach-undef: gnumach.$(OBJEXT)
diff --git a/Makefrag.am b/Makefrag.am
index 73508350..ea612275 100644
--- a/Makefrag.am
+++ b/Makefrag.am
@@ -227,6 +227,7 @@ EXTRA_DIST += \
kern/mach.srv \
kern/mach4.srv \
kern/gnumach.srv \
+ kern/experimental.srv \
kern/mach_debug.srv \
kern/mach_host.srv \
kern/task_notify.cli
@@ -385,6 +386,7 @@ include_mach_HEADERS = \
include/mach/memory_object_default.defs \
include/mach/notify.defs \
include/mach/std_types.defs \
+ include/mach/experimental.defs \
include/mach/alert.h \
include/mach/boolean.h \
include/mach/boot.h \
@@ -535,6 +537,7 @@ nodist_lib_dep_tr_for_defs_a_SOURCES += \
kern/mach.server.defs.c \
kern/mach4.server.defs.c \
kern/gnumach.server.defs.c \
+ kern/experimental.server.defs.c \
kern/mach_debug.server.defs.c \
kern/mach_host.server.defs.c
nodist_libkernel_a_SOURCES += \
@@ -547,6 +550,9 @@ nodist_libkernel_a_SOURCES += \
kern/gnumach.server.h \
kern/gnumach.server.c \
kern/gnumach.server.msgids \
+ kern/experimental.server.h \
+ kern/experimental.server.c \
+ kern/experimental.server.msgids \
kern/mach_debug.server.h \
kern/mach_debug.server.c \
kern/mach_debug.server.msgids \
@@ -556,6 +562,7 @@ nodist_libkernel_a_SOURCES += \
# kern/mach.server.defs
# kern/mach4.server.defs
# kern/gnumach.server.defs
+# kern/experimental.server.defs
# kern/mach_debug.server.defs
# kern/mach_host.server.defs
@@ -604,3 +611,8 @@ endif
if HOST_ix86
include i386/Makefrag.am
endif
+
+# x86_64.
+if HOST_x86_64
+include x86_64/Makefrag.am
+endif
diff --git a/configfrag-first.ac b/configfrag-first.ac
new file mode 100644
index 00000000..5dc0db2c
--- /dev/null
+++ b/configfrag-first.ac
@@ -0,0 +1,29 @@
+dnl Configure fragment for general options.
+
+dnl Copyright (C) 2020 Free Software Foundation, Inc.
+
+dnl Permission to use, copy, modify and distribute this software and its
+dnl documentation is hereby granted, provided that both the copyright
+dnl notice and this permission notice appear in all copies of the
+dnl software, derivative works or modified versions, and any portions
+dnl thereof, and that both notices appear in supporting documentation.
+dnl
+dnl THE FREE SOFTWARE FOUNDATION ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+dnl "AS IS" CONDITION. THE FREE SOFTWARE FOUNDATION DISCLAIMS ANY
+dnl LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE
+dnl USE OF THIS SOFTWARE.
+
+#
+# Common options
+#
+
+ncom=0
+nlpr=0
+
+AC_ARG_ENABLE([pae],
+ AS_HELP_STRING([--enable-pae], [PAE support (ix86-only); on i386-at disabled
+ by default, otherwise enabled by default]))
+
+dnl Local Variables:
+dnl mode: autoconf
+dnl End:
diff --git a/configfrag.ac b/configfrag.ac
index 73c23ffb..91d737ef 100644
--- a/configfrag.ac
+++ b/configfrag.ac
@@ -26,6 +26,19 @@ AC_DEFINE([KERNEL], [1], [KERNEL])
# Formerly in `bogus/'.
#
+# i386/bogus/com.h
+AC_DEFINE_UNQUOTED([NCOM], [$ncom], [NCOM])
+
+# i386/bogus/lpr.h
+AC_DEFINE_UNQUOTED([NLPR], [$nlpr], [NLPR])
+
+[if [ x"$enable_pae" = xyes ]; then]
+ AC_DEFINE([PAE], [1], [PAE support])
+ AM_CONDITIONAL([enable_pae], [true])
+[else]
+ AM_CONDITIONAL([enable_pae], [false])
+[fi]
+
# When set, the bootstrap task symbols are preserved by the kernel debugger.
# Used in `kern/bootstrap.c'.
AC_DEFINE([BOOTSTRAP_SYMBOLS], [0], [BOOTSTRAP_SYMBOLS])
diff --git a/configure.ac b/configure.ac
index d4daa932..806a1da1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -55,7 +55,10 @@ AC_ARG_ENABLE([platform],
case $host_platform:$host_cpu in
default:i?86)
host_platform=at;;
- at:i?86 | xen:i?86)
+ default:x86_64)]
+ AC_MSG_WARN([Platform set to Xen by default, this can not boot on non-Xen systems, you currently need a 32bit build for that.])
+ [host_platform=xen;;
+ at:i?86 | xen:i?86 | at:x86_64 | xen:x86_64)
:;;
*)]
AC_MSG_ERROR([unsupported combination of cpu type `$host_cpu' and platform
@@ -131,6 +134,9 @@ esac]
# PC AT.
# TODO. Currently handled in `i386/configfrag.ac'.
+# General options.
+m4_include([configfrag-first.ac])
+
# Xen.
m4_include([xen/configfrag.ac])
@@ -139,6 +145,9 @@ m4_include([xen/configfrag.ac])
# ix86.
m4_include([i386/configfrag.ac])
+# x86_64
+m4_include([x86_64/configfrag.ac])
+
# General options.
m4_include([configfrag.ac])
diff --git a/ddb/db_examine.c b/ddb/db_examine.c
index 6f94b686..6509a538 100644
--- a/ddb/db_examine.c
+++ b/ddb/db_examine.c
@@ -130,20 +130,24 @@ db_examine(addr, fmt, count, task)
db_examine_prev_addr = addr;
while (--count >= 0) {
fp = fmt;
- size = sizeof(int);
+ size = 4;
width = 4*size;
while ((c = *fp++) != 0) {
switch (c) {
case 'b':
- size = sizeof(char);
+ size = 1;
width = 4*size;
break;
case 'h':
- size = sizeof(short);
+ size = 2;
width = 4*size;
break;
case 'l':
- size = sizeof(long);
+ size = 4;
+ width = 4*size;
+ break;
+ case 'q':
+ size = 8;
width = 4*size;
break;
case 'a': /* address */
diff --git a/device/dev_pager.c b/device/dev_pager.c
index 0680b5aa..4508ad14 100644
--- a/device/dev_pager.c
+++ b/device/dev_pager.c
@@ -328,8 +328,8 @@ kern_return_t device_pager_data_request(
dev_pager_t ds;
if (device_pager_debug)
- printf("(device_pager)data_request: pager=%p, offset=0x%lx, length=0x%x\n",
- pager, offset, length);
+ printf("(device_pager)data_request: pager=%p, offset=0x%lx, length=0x%lx\n",
+ pager, (unsigned long) offset, (unsigned long) length);
ds = dev_pager_hash_lookup(pager);
if (ds == DEV_PAGER_NULL)
diff --git a/device/ds_routines.c b/device/ds_routines.c
index 13c9a63e..1cc38f98 100644
--- a/device/ds_routines.c
+++ b/device/ds_routines.c
@@ -133,6 +133,7 @@ static struct device_emulation_ops *emulation_list[] =
static struct vm_map device_io_map_store;
vm_map_t device_io_map = &device_io_map_store;
+struct kmem_cache io_inband_cache;
#define NUM_EMULATION (sizeof (emulation_list) / sizeof (emulation_list[0]))
diff --git a/device/io_req.h b/device/io_req.h
index 1ad46801..b80b3dde 100644
--- a/device/io_req.h
+++ b/device/io_req.h
@@ -137,6 +137,6 @@ void iodone(io_req_t);
(kfree((vm_offset_t)(ior), sizeof(struct io_req)))
-struct kmem_cache io_inband_cache; /* for inband reads */
+extern struct kmem_cache io_inband_cache; /* for inband reads */
#endif /* _IO_REQ_ */
diff --git a/device/net_io.h b/device/net_io.h
index 5baf0678..9468e34b 100644
--- a/device/net_io.h
+++ b/device/net_io.h
@@ -109,6 +109,14 @@ net_do_filter(
unsigned int data_count,
const char * header); /* CSPF */
+io_return_t
+net_set_filter(
+ struct ifnet *ifp,
+ ipc_port_t rcv_port,
+ int priority,
+ filter_t *filter,
+ unsigned int filter_count);
+
extern int
bpf_do_filter(
net_rcv_port_t infp,
@@ -149,4 +157,6 @@ int bpf_match (
net_hash_entry_t **hash_headpp,
net_hash_entry_t *entpp);
+boolean_t ethernet_priority(const ipc_kmsg_t kmsg);
+
#endif /* _DEVICE_NET_IO_H_ */
diff --git a/device/subrs.h b/device/subrs.h
index 680aaa6f..60ea6518 100644
--- a/device/subrs.h
+++ b/device/subrs.h
@@ -27,6 +27,9 @@
#define _SUBRS_H_
#include <mach/std_types.h>
+#include <device/if_hdr.h>
+
+extern void if_init_queues(struct ifnet *ifp);
extern void sleep (vm_offset_t channel, int priority);
extern void wakeup (vm_offset_t channel);
diff --git a/device/tty.h b/device/tty.h
index ea6f4404..0bdb2db9 100644
--- a/device/tty.h
+++ b/device/tty.h
@@ -125,7 +125,7 @@ extern void ttychars(
#define TTMINBUF 90
-short tthiwat[NSPEEDS], ttlowat[NSPEEDS];
+extern short tthiwat[NSPEEDS], ttlowat[NSPEEDS];
#define TTHIWAT(tp) tthiwat[(tp)->t_ospeed]
#define TTLOWAT(tp) ttlowat[(tp)->t_ospeed]
diff --git a/doc/mach.texi b/doc/mach.texi
index dd1e5edd..91ec96ee 100644
--- a/doc/mach.texi
+++ b/doc/mach.texi
@@ -374,7 +374,7 @@ IPC, currently not available in GNU Mach).
@item it exists
The Mach microkernel is real software that works Right Now.
-It is not a research or a proposal. You don't have to wait at all
+It is not a research project or a proposal. You don't have to wait at all
before you can start using and developing it. Mach has been used in
many operating systems in the past, usually as the base for a single
UNIX server. In the GNU system, Mach is the base of a functional
@@ -3056,6 +3056,30 @@ specified and @code{KERN_NO_SPACE} if there was not enough space left to
satisfy the request.
@end deftypefun
+@deftypefun kern_return_t vm_allocate_contiguous (@w{host_priv_t @var{host_priv}}, @w{vm_task_t @var{target_task}}, @w{vm_address_t *@var{vaddr}}, @w{phys_addr_t *@var{paddr}}, @w{vm_size_t @var{size}}, @w{phys_addr_t @var{pmin}}, @w{phys_addr_t @var{pmax}}, @w{phys_addr_t @var{palign}})
+The function @code{vm_allocate} allocates a region of physical memory,
+placing virtual mapping of the physical pages in the specified @var{task}'s
+address space.
+
+The virtual space will be allocated wherever it is available. The virtual
+address at which the physical memory was mapped will be returned in
+@var{vaddr}. The physical address of the start of the allocated physical
+memory will be returned in @var{paddr}.
+
+@var{size} is the number of bytes to allocate (rounded by the system in
+a machine dependent way to an integral number of virtual pages).
+
+Constraints can be set on the physical address, to cope with hardware physical
+memory access constraints, e.g. DMAs. @var{pmin} is the minimum physical address
+at which the allocated memory should start. @var{pmax} is the maximum physical
+address at which the allocated memory should end. @var{palign} is the alignment
+restriction, which has to be a power of two.
+
+The function returns @code{KERN_SUCCESS} if the memory was successfully
+allocated, @code{KERN_RESOURCE_SHORTAGE} if there was not enough physical memory
+left to satisfy the request, and @code{KERN_NO_SPACE} if there was not enough
+virtual space left to satisfy the request.
+@end deftypefun
@node Memory Deallocation
@section Memory Deallocation
@@ -6793,6 +6817,9 @@ look at by half words(16 bits)
@item l
look at by long words(32 bits)
+@item q
+look at by quad words(64 bits)
+
@item a
print the location being displayed
diff --git a/i386/configfrag.ac b/i386/configfrag.ac
index 3c29bdf9..df5311e5 100644
--- a/i386/configfrag.ac
+++ b/i386/configfrag.ac
@@ -44,8 +44,6 @@ esac
# Formerly in `i386/bogus/'.
#
-ncom=0
-nlpr=0
case $host_platform:$host_cpu in
at:i?86)
ncom=4
@@ -62,12 +60,6 @@ case $host_platform:$host_cpu in
*)
:;;
esac]
-
-# i386/bogus/com.h
-AC_DEFINE_UNQUOTED([NCOM], [$ncom], [NCOM])
-
-# i386/bogus/lpr.h
-AC_DEFINE_UNQUOTED([NLPR], [$nlpr], [NLPR])
#
# Options.
@@ -100,9 +92,6 @@ if [ x"$enable_lpr" = xyes ]; then]
[fi]
-AC_ARG_ENABLE([pae],
- AS_HELP_STRING([--enable-pae], [PAE support (ix86-only); on ix86-at disabled
- by default, on ix86-xen enabled by default]))
[case $host_platform:$host_cpu in
xen:i?86)
enable_pae=${enable_pae-yes};;
@@ -112,13 +101,7 @@ AC_ARG_ENABLE([pae],
if [ x"$enable_pae" = xyes ]; then]
AC_MSG_ERROR([can only enable the `PAE' feature on ix86.])
[fi;;
-esac
-if [ x"$enable_pae" = xyes ]; then]
- AC_DEFINE([PAE], [1], [PAE support])
- AM_CONDITIONAL([enable_pae], [true])
-[else]
- AM_CONDITIONAL([enable_pae], [false])
-[fi]
+esac]
AC_ARG_WITH([_START_MAP],
AS_HELP_STRING([--with-_START_MAP=0x1000000], [specify kernel mapping start address]),
diff --git a/i386/i386/cpu_number.h b/i386/i386/cpu_number.h
index 7808e49c..f32a44b8 100644
--- a/i386/i386/cpu_number.h
+++ b/i386/i386/cpu_number.h
@@ -33,7 +33,12 @@
#if NCPUS > 1
/* More-specific code must define cpu_number() and CPU_NUMBER. */
+#ifdef __i386__
#define CX(addr, reg) addr(,reg,4)
+#endif
+#ifdef __x86_64__
+#define CX(addr, reg) addr(,reg,8)
+#endif
#else /* NCPUS == 1 */
diff --git a/i386/i386/db_interface.c b/i386/i386/db_interface.c
index aac29395..e61d2961 100644
--- a/i386/i386/db_interface.c
+++ b/i386/i386/db_interface.c
@@ -66,6 +66,8 @@ static boolean_t kernel_dr;
/* Whether the current debug registers are zero. */
static boolean_t zero_dr;
+db_regs_t ddb_regs;
+
void db_load_context(pcb_t pcb)
{
#if MACH_KDB
@@ -125,7 +127,7 @@ kern_return_t db_set_debug_state(
struct i386_saved_state *i386_last_saved_statep;
struct i386_saved_state i386_nested_saved_state;
-unsigned i386_last_kdb_sp;
+uintptr_t i386_last_kdb_sp;
extern thread_t db_default_thread;
@@ -289,7 +291,7 @@ kdb_trap(
#endif /* NCPUS > 1 */
{
i386_last_saved_statep = regs;
- i386_last_kdb_sp = (unsigned) &type;
+ i386_last_kdb_sp = (uintptr_t) &type;
/* XXX Should switch to ddb`s own stack here. */
@@ -298,7 +300,7 @@ kdb_trap(
/*
* Kernel mode - esp and ss not saved
*/
- ddb_regs.uesp = (int)&regs->uesp; /* kernel stack pointer */
+ ddb_regs.uesp = (uintptr_t)&regs->uesp; /* kernel stack pointer */
ddb_regs.ss = KERNEL_DS;
}
@@ -347,8 +349,10 @@ kdb_trap(
* instead of those at its call to KDB.
*/
struct int_regs {
+#ifdef __i386__
long edi;
long esi;
+#endif
long ebp;
long ebx;
struct i386_interrupt_state *is;
@@ -366,12 +370,12 @@ kdb_kentry(
#endif /* NCPUS > 1 */
{
if ((is->cs & 0x3) != KERNEL_RING) {
- ddb_regs.uesp = ((int *)(is+1))[0];
- ddb_regs.ss = ((int *)(is+1))[1];
+ ddb_regs.uesp = *(uintptr_t *)(is+1);
+ ddb_regs.ss = *(int *)((uintptr_t *)(is+1)+1);
}
else {
ddb_regs.ss = KERNEL_DS;
- ddb_regs.uesp= (int)(is+1);
+ ddb_regs.uesp= (uintptr_t)(is+1);
}
ddb_regs.efl = is->efl;
ddb_regs.cs = is->cs;
@@ -381,8 +385,14 @@ kdb_kentry(
ddb_regs.edx = is->edx;
ddb_regs.ebx = int_regs->ebx;
ddb_regs.ebp = int_regs->ebp;
+#ifdef __i386__
ddb_regs.esi = int_regs->esi;
ddb_regs.edi = int_regs->edi;
+#endif
+#ifdef __x86_64__
+ ddb_regs.esi = is->rsi;
+ ddb_regs.edi = is->rdi;
+#endif
ddb_regs.ds = is->ds;
ddb_regs.es = is->es;
ddb_regs.fs = is->fs;
@@ -404,8 +414,14 @@ kdb_kentry(
is->edx = ddb_regs.edx;
int_regs->ebx = ddb_regs.ebx;
int_regs->ebp = ddb_regs.ebp;
+#ifdef __i386__
int_regs->esi = ddb_regs.esi;
int_regs->edi = ddb_regs.edi;
+#endif
+#ifdef __x86_64__
+ is->rsi = ddb_regs.esi;
+ is->rdi = ddb_regs.edi;
+#endif
is->ds = ddb_regs.ds & 0xffff;
is->es = ddb_regs.es & 0xffff;
is->fs = ddb_regs.fs & 0xffff;
diff --git a/i386/i386/db_machdep.h b/i386/i386/db_machdep.h
index ae1f9c09..04c874b1 100644
--- a/i386/i386/db_machdep.h
+++ b/i386/i386/db_machdep.h
@@ -41,7 +41,7 @@ typedef vm_offset_t db_addr_t; /* address - unsigned */
typedef long db_expr_t; /* expression - signed */
typedef struct i386_saved_state db_regs_t;
-db_regs_t ddb_regs; /* register state */
+extern db_regs_t ddb_regs; /* register state */
#define DDB_REGS (&ddb_regs)
#define SAVE_DDB_REGS DB_SAVE(db_regs_t, ddb_regs)
#define RESTORE_DDB_REGS DB_RESTORE(ddb_regs)
diff --git a/i386/i386/db_trace.c b/i386/i386/db_trace.c
index 898febad..6c59864a 100644
--- a/i386/i386/db_trace.c
+++ b/i386/i386/db_trace.c
@@ -100,8 +100,16 @@ struct i386_kregs {
{ "ebx", (long)(&((struct i386_kernel_state *)0)->k_ebx) },
{ "esp", (long)(&((struct i386_kernel_state *)0)->k_esp) },
{ "ebp", (long)(&((struct i386_kernel_state *)0)->k_ebp) },
+#ifdef __i386__
{ "edi", (long)(&((struct i386_kernel_state *)0)->k_edi) },
{ "esi", (long)(&((struct i386_kernel_state *)0)->k_esi) },
+#endif
+#ifdef __x86_64__
+ { "r12", (long)(&((struct i386_kernel_state *)0)->k_r12) },
+ { "r13", (long)(&((struct i386_kernel_state *)0)->k_r13) },
+ { "r14", (long)(&((struct i386_kernel_state *)0)->k_r14) },
+ { "r15", (long)(&((struct i386_kernel_state *)0)->k_r15) },
+#endif
{ "eip", (long)(&((struct i386_kernel_state *)0)->k_eip) },
{ 0 },
};
diff --git a/i386/i386/fpu.c b/i386/i386/fpu.c
index 0887a32c..3118e4ca 100644
--- a/i386/i386/fpu.c
+++ b/i386/i386/fpu.c
@@ -874,7 +874,7 @@ fp_state_alloc(void)
}
}
-#if AT386 && !defined(MACH_XEN)
+#if (defined(AT386) || defined(ATX86_64)) && !defined(MACH_XEN)
/*
* Handle a coprocessor error interrupt on the AT386.
* This comes in on line 5 of the slave PIC at SPL1.
diff --git a/i386/i386/gdt.c b/i386/i386/gdt.c
index c895eb3a..fb18360e 100644
--- a/i386/i386/gdt.c
+++ b/i386/i386/gdt.c
@@ -33,6 +33,7 @@
#include <mach/machine/vm_types.h>
#include <mach/xen.h>
+#include <kern/assert.h>
#include <intel/pmap.h>
#include "vm_param.h"
@@ -49,6 +50,14 @@ void
gdt_init(void)
{
/* Initialize the kernel code and data segment descriptors. */
+#ifdef __x86_64__
+ assert(LINEAR_MIN_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS == 0);
+ fill_gdt_descriptor(KERNEL_CS, 0, 0, ACC_PL_K|ACC_CODE_R, SZ_64);
+ fill_gdt_descriptor(KERNEL_DS, 0, 0, ACC_PL_K|ACC_DATA_W, SZ_64);
+#ifndef MACH_PV_DESCRIPTORS
+ fill_gdt_descriptor(LINEAR_DS, 0, 0, ACC_PL_K|ACC_DATA_W, SZ_64);
+#endif /* MACH_PV_DESCRIPTORS */
+#else
fill_gdt_descriptor(KERNEL_CS,
LINEAR_MIN_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS,
LINEAR_MAX_KERNEL_ADDRESS - (LINEAR_MIN_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS) - 1,
@@ -63,6 +72,7 @@ gdt_init(void)
0xffffffff,
ACC_PL_K|ACC_DATA_W, SZ_32);
#endif /* MACH_PV_DESCRIPTORS */
+#endif
#ifdef MACH_PV_DESCRIPTORS
unsigned long frame = kv_to_mfn(gdt);
@@ -94,6 +104,7 @@ gdt_init(void)
We must load ds and es with 0 before loading them with KERNEL_DS
because some processors will "optimize out" the loads
if the previous selector values happen to be the same. */
+#ifndef __x86_64__
asm volatile("ljmp %0,$1f\n"
"1:\n"
"movw %w2,%%ds\n"
@@ -105,6 +116,7 @@ gdt_init(void)
"movw %w1,%%es\n"
"movw %w1,%%ss\n"
: : "i" (KERNEL_CS), "r" (KERNEL_DS), "r" (0));
+#endif
#ifdef MACH_PV_PAGETABLES
#if VM_MIN_KERNEL_ADDRESS != LINEAR_MIN_KERNEL_ADDRESS
/* things now get shifted */
diff --git a/i386/i386/gdt.h b/i386/i386/gdt.h
index d865640b..9879ad3e 100644
--- a/i386/i386/gdt.h
+++ b/i386/i386/gdt.h
@@ -40,28 +40,79 @@
*/
#define KERNEL_CS (0x08 | KERNEL_RING) /* kernel code */
#define KERNEL_DS (0x10 | KERNEL_RING) /* kernel data */
+
+
#ifndef MACH_PV_DESCRIPTORS
#define KERNEL_LDT 0x18 /* master LDT */
#endif /* MACH_PV_DESCRIPTORS */
+
+#ifdef __x86_64__
+/* LDT needs two entries */
+#define KERNEL_TSS 0x40 /* master TSS (uniprocessor) */
+#else
#define KERNEL_TSS 0x20 /* master TSS (uniprocessor) */
+#endif
+
+
#define USER_LDT 0x28 /* place for per-thread LDT */
+
+#ifdef __x86_64__
+/* LDT needs two entries */
+#define USER_TSS 0x58 /* place for per-thread TSS
+ that holds IO bitmap */
+#else
#define USER_TSS 0x30 /* place for per-thread TSS
that holds IO bitmap */
+#endif
+
+
#ifndef MACH_PV_DESCRIPTORS
#define LINEAR_DS 0x38 /* linear mapping */
#endif /* MACH_PV_DESCRIPTORS */
-/* 0x40 was USER_FPREGS, now free */
-#define USER_GDT 0x48 /* user-defined GDT entries */
+/* 0x40 was USER_FPREGS, now used by TSS in 64bit mode */
+
+#define USER_GDT 0x48 /* user-defined 32bit GDT entries */
#define USER_GDT_SLOTS 2
-#define GDTSZ (USER_GDT/8 + USER_GDT_SLOTS)
+/* 0x58 used by user TSS in 64bit mode */
+
+#ifdef __x86_64__
+#define GDTSZ sel_idx(0x60)
+#else
+#define GDTSZ sel_idx(0x58)
+#endif
extern struct real_descriptor gdt[GDTSZ];
/* Fill a segment descriptor in the GDT. */
+#define _fill_gdt_descriptor(_gdt, segment, base, limit, access, sizebits) \
+ fill_descriptor(&_gdt[sel_idx(segment)], base, limit, access, sizebits)
+
#define fill_gdt_descriptor(segment, base, limit, access, sizebits) \
- fill_descriptor(&gdt[segment/8], base, limit, access, sizebits)
+ _fill_gdt_descriptor(gdt, segment, base, limit, access, sizebits)
+
+/* 64bit variant */
+#ifdef __x86_64__
+#define _fill_gdt_descriptor64(_gdt, segment, base, limit, access, sizebits) \
+ fill_descriptor64((struct real_descriptor64 *) &_gdt[sel_idx(segment)], base, limit, access, sizebits)
+
+#define fill_gdt_descriptor64(segment, base, limit, access, sizebits) \
+ _fill_gdt_descriptor64(gdt, segment, base, limit, access, sizebits)
+#endif
+
+/* System descriptor variants */
+#ifdef __x86_64__
+#define _fill_gdt_sys_descriptor(_gdt, segment, base, limit, access, sizebits) \
+ _fill_gdt_descriptor64(_gdt, segment, base, limit, access, sizebits)
+#define fill_gdt_sys_descriptor(segment, base, limit, access, sizebits) \
+ fill_gdt_descriptor64(segment, base, limit, access, sizebits)
+#else
+#define _fill_gdt_sys_descriptor(_gdt, segment, base, limit, access, sizebits) \
+ _fill_gdt_descriptor(_gdt, segment, base, limit, access, sizebits)
+#define fill_gdt_sys_descriptor(segment, base, limit, access, sizebits) \
+ fill_gdt_descriptor(segment, base, limit, access, sizebits)
+#endif
extern void gdt_init(void);
diff --git a/i386/i386/hardclock.c b/i386/i386/hardclock.c
index 82761ec3..eb6ff34f 100644
--- a/i386/i386/hardclock.c
+++ b/i386/i386/hardclock.c
@@ -35,7 +35,7 @@
#include <kern/mach_clock.h>
#include <i386/thread.h>
-#if defined(AT386)
+#if defined(AT386) || defined(ATX86_64)
#include <i386/ipl.h>
#endif
diff --git a/i386/i386/i386asm.sym b/i386/i386/i386asm.sym
index dd1a2edf..0662aea0 100644
--- a/i386/i386/i386asm.sym
+++ b/i386/i386/i386asm.sym
@@ -63,9 +63,17 @@ offset eml_dispatch eml disp_vector DISP_VECTOR
expr &STACK_IKS(0)->k_ebx KSS_EBX
expr &STACK_IKS(0)->k_esp KSS_ESP
expr &STACK_IKS(0)->k_ebp KSS_EBP
+#ifdef __i386__
expr &STACK_IKS(0)->k_esi KSS_ESI
expr &STACK_IKS(0)->k_edi KSS_EDI
+#endif
expr &STACK_IKS(0)->k_eip KSS_EIP
+#ifdef __x86_64__
+expr &STACK_IKS(0)->k_r12 KSS_R12
+expr &STACK_IKS(0)->k_r13 KSS_R13
+expr &STACK_IKS(0)->k_r14 KSS_R14
+expr &STACK_IKS(0)->k_r15 KSS_R15
+#endif
size i386_kernel_state iks
size i386_exception_link iel
@@ -79,6 +87,9 @@ offset i386_saved_state r efl R_EFLAGS
offset i386_saved_state r eip
offset i386_saved_state r cr2
offset i386_saved_state r edi
+#ifdef __x86_64__
+offset i386_saved_state r r15
+#endif
offset i386_interrupt_state i eip
offset i386_interrupt_state i cs
diff --git a/i386/i386/idt.c b/i386/i386/idt.c
index d304ec3e..c6a778f1 100644
--- a/i386/i386/idt.c
+++ b/i386/i386/idt.c
@@ -30,7 +30,7 @@ struct real_gate idt[IDTSZ];
struct idt_init_entry
{
- unsigned entrypoint;
+ unsigned long entrypoint;
unsigned short vector;
unsigned short type;
};
diff --git a/i386/i386/ktss.c b/i386/i386/ktss.c
index 21d00300..917e6305 100644
--- a/i386/i386/ktss.c
+++ b/i386/i386/ktss.c
@@ -52,9 +52,9 @@ ktss_init(void)
panic("couldn't register exception stack\n");
#else /* MACH_RING1 */
/* Initialize the master TSS descriptor. */
- fill_gdt_descriptor(KERNEL_TSS,
- kvtolin(&ktss), sizeof(struct task_tss) - 1,
- ACC_PL_K|ACC_TSS, 0);
+ fill_gdt_sys_descriptor(KERNEL_TSS,
+ kvtolin(&ktss), sizeof(struct task_tss) - 1,
+ ACC_PL_K|ACC_TSS, 0);
/* Initialize the master TSS. */
ktss.tss.ss0 = KERNEL_DS;
diff --git a/i386/i386/ldt.c b/i386/i386/ldt.c
index 0250ee26..261df93a 100644
--- a/i386/i386/ldt.c
+++ b/i386/i386/ldt.c
@@ -53,12 +53,12 @@ ldt_init(void)
#endif /* MACH_PV_PAGETABLES */
#else /* MACH_PV_DESCRIPTORS */
/* Initialize the master LDT descriptor in the GDT. */
- fill_gdt_descriptor(KERNEL_LDT,
- kvtolin(&ldt), sizeof(ldt)-1,
- ACC_PL_K|ACC_LDT, 0);
+ fill_gdt_sys_descriptor(KERNEL_LDT,
+ kvtolin(&ldt), sizeof(ldt)-1,
+ ACC_PL_K|ACC_LDT, 0);
#endif /* MACH_PV_DESCRIPTORS */
- /* Initialize the LDT descriptors. */
+ /* Initialize the 32bit LDT descriptors. */
fill_ldt_gate(USER_SCALL,
(vm_offset_t)&syscall, KERNEL_CS,
ACC_PL_U|ACC_CALL_GATE, 0);
diff --git a/i386/i386/ldt.h b/i386/i386/ldt.h
index f196c74b..1f0d7014 100644
--- a/i386/i386/ldt.h
+++ b/i386/i386/ldt.h
@@ -43,6 +43,9 @@
* User descriptors for Mach - 32-bit flat address space
*/
#define USER_SCALL 0x07 /* system call gate */
+#ifdef __x86_64__
+/* Call gate needs two entries */
+#endif
#define USER_CS 0x17 /* user code segment */
#define USER_DS 0x1f /* user data segment */
@@ -53,12 +56,12 @@
extern struct real_descriptor ldt[LDTSZ];
-/* Fill a segment descriptor in the LDT. */
+/* Fill a 32bit segment descriptor in the LDT. */
#define fill_ldt_descriptor(selector, base, limit, access, sizebits) \
- fill_descriptor(&ldt[selector/8], base, limit, access, sizebits)
+ fill_descriptor(&ldt[sel_idx(selector)], base, limit, access, sizebits)
#define fill_ldt_gate(selector, offset, dest_selector, access, word_count) \
- fill_gate((struct real_gate*)&ldt[selector/8], \
+ fill_gate((struct real_gate*)&ldt[sel_idx(selector)], \
offset, dest_selector, access, word_count)
void ldt_init(void);
diff --git a/i386/i386/locore.S b/i386/i386/locore.S
index ddba2245..a0960a26 100644
--- a/i386/i386/locore.S
+++ b/i386/i386/locore.S
@@ -1075,7 +1075,7 @@ syscall_native:
movb $0xf,%dh
movw %dx,0xb800c
#endif
- shll $4,%eax /* manual indexing */
+ shll $4,%eax /* manual indexing of mach_trap_t */
movl EXT(mach_trap_table)(%eax),%ecx
/* get number of arguments */
jecxz mach_call_call /* skip argument copy if none */
diff --git a/i386/i386/model_dep.h b/i386/i386/model_dep.h
index 54aa1ec7..711f07fd 100644
--- a/i386/i386/model_dep.h
+++ b/i386/i386/model_dep.h
@@ -50,4 +50,9 @@ extern void halt_cpu (void) __attribute__ ((noreturn));
*/
extern void halt_all_cpus (boolean_t reboot) __attribute__ ((noreturn));
+/*
+ * Make cpu pause a bit.
+ */
+extern void machine_relax (void);
+
#endif /* _I386AT_MODEL_DEP_H_ */
diff --git a/i386/i386/mp_desc.c b/i386/i386/mp_desc.c
index 6aa8e664..07cc389a 100644
--- a/i386/i386/mp_desc.c
+++ b/i386/i386/mp_desc.c
@@ -146,11 +146,11 @@ mp_desc_init(int mycpu)
#ifdef MACH_RING1
panic("TODO %s:%d\n",__FILE__,__LINE__);
#else /* MACH_RING1 */
- fill_descriptor(&mpt->gdt[sel_idx(KERNEL_LDT)],
+ _fill_gdt_sys_descriptor(mpt->gdt, KERNEL_LDT,
(unsigned)&mpt->ldt,
LDTSZ * sizeof(struct real_descriptor) - 1,
ACC_P|ACC_PL_K|ACC_LDT, 0);
- fill_descriptor(&mpt->gdt[sel_idx(KERNEL_TSS)],
+ _fill_gdt_sys_descriptor(mpt->gdt, KERNEL_TSS,
(unsigned)&mpt->ktss,
sizeof(struct task_tss) - 1,
ACC_P|ACC_PL_K|ACC_TSS, 0);
diff --git a/i386/i386/pcb.c b/i386/i386/pcb.c
index 743108db..23585323 100644
--- a/i386/i386/pcb.c
+++ b/i386/i386/pcb.c
@@ -169,7 +169,8 @@ void switch_ktss(pcb_t pcb)
#ifdef MACH_PV_DESCRIPTORS
hyp_set_ldt(&ldt, LDTSZ);
#else /* MACH_PV_DESCRIPTORS */
- set_ldt(KERNEL_LDT);
+ if (get_ldt() != KERNEL_LDT)
+ set_ldt(KERNEL_LDT);
#endif /* MACH_PV_DESCRIPTORS */
}
else {
diff --git a/i386/i386/pic.h b/i386/i386/pic.h
index 553c4bcc..f492de5e 100644
--- a/i386/i386/pic.h
+++ b/i386/i386/pic.h
@@ -59,7 +59,7 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
** The following are definitions used to locate the PICs in the system
*/
-#if defined(AT386)
+#if defined(AT386) || defined(ATX86_64)
#define ADDR_PIC_BASE 0x20
#define OFF_ICW 0x00
#define OFF_OCW 0x01
@@ -95,7 +95,7 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
** ICW2
*/
-#if defined(AT386)
+#if defined(AT386) || defined(ATX86_64)
#define PICM_VECTBASE 0x40
#define PICS_VECTBASE PICM_VECTBASE + 0x08
#endif /* defined(AT386) */
diff --git a/i386/i386/pio.h b/i386/i386/pio.h
index f0e5e274..fa0bab9f 100644
--- a/i386/i386/pio.h
+++ b/i386/i386/pio.h
@@ -32,7 +32,7 @@
#endif /* __GNUC__ */
#define inl(y) \
-({ unsigned long _tmp__; \
+({ unsigned int _tmp__; \
asm volatile("inl %1, %0" : "=a" (_tmp__) : "d" ((unsigned short)(y))); \
_tmp__; })
diff --git a/i386/i386/pit.h b/i386/i386/pit.h
index e65aae97..6b682280 100644
--- a/i386/i386/pit.h
+++ b/i386/i386/pit.h
@@ -45,7 +45,7 @@ NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#if defined(AT386)
+#if defined(AT386) || defined(ATX86_64)
/* Definitions for 8254 Programmable Interrupt Timer ports on AT 386 */
#define PITCTR0_PORT 0x40 /* counter 0 port */
#define PITCTR1_PORT 0x41 /* counter 1 port */
@@ -74,7 +74,7 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* Clock speed for the timer in hz divided by the constant HZ
* (defined in param.h)
*/
-#if AT386
+#if defined(AT386) || defined(ATX86_64)
#define CLKNUM 1193167
#endif /* AT386 */
diff --git a/i386/i386/proc_reg.h b/i386/i386/proc_reg.h
index 80835361..c787ef26 100644
--- a/i386/i386/proc_reg.h
+++ b/i386/i386/proc_reg.h
@@ -81,14 +81,22 @@ static inline unsigned long
get_eflags(void)
{
unsigned long eflags;
+#ifdef __x86_64__
+ asm("pushfq; pop %0" : "=r" (eflags));
+#else
asm("pushfd; pop %0" : "=r" (eflags));
+#endif
return eflags;
}
static inline void
set_eflags(unsigned long eflags)
{
+#ifdef __x86_64__
+ asm volatile("push %0; popfq" : : "r" (eflags));
+#else
asm volatile("push %0; popfd" : : "r" (eflags));
+#endif
}
#define get_esp() \
@@ -97,12 +105,21 @@ set_eflags(unsigned long eflags)
_temp__; \
})
+#ifdef __x86_64__
#define get_eflags() \
({ \
register unsigned long _temp__; \
- asm("pushf; pop %0" : "=r" (_temp__)); \
+ asm("pushfq; pop %0" : "=r" (_temp__)); \
_temp__; \
})
+#else
+#define get_eflags() \
+ ({ \
+ register unsigned long _temp__; \
+ asm("pushfd; pop %0" : "=r" (_temp__)); \
+ _temp__; \
+ })
+#endif
#define get_cr0() \
({ \
@@ -240,7 +257,7 @@ extern unsigned long cr3;
#define get_dr0() \
({ \
register unsigned long _temp__; \
- asm volatile("movl %%dr0, %0" : "=r" (_temp__)); \
+ asm volatile("mov %%dr0, %0" : "=r" (_temp__)); \
_temp__; \
})
#endif
@@ -251,7 +268,7 @@ extern unsigned long cr3;
#define set_dr0(value) \
({ \
register unsigned long _temp__ = (value); \
- asm volatile("movl %0,%%dr0" : : "r" (_temp__)); \
+ asm volatile("mov %0,%%dr0" : : "r" (_temp__)); \
})
#endif
@@ -261,7 +278,7 @@ extern unsigned long cr3;
#define get_dr1() \
({ \
register unsigned long _temp__; \
- asm volatile("movl %%dr1, %0" : "=r" (_temp__)); \
+ asm volatile("mov %%dr1, %0" : "=r" (_temp__)); \
_temp__; \
})
#endif
@@ -272,7 +289,7 @@ extern unsigned long cr3;
#define set_dr1(value) \
({ \
register unsigned long _temp__ = (value); \
- asm volatile("movl %0,%%dr1" : : "r" (_temp__)); \
+ asm volatile("mov %0,%%dr1" : : "r" (_temp__)); \
})
#endif
@@ -282,7 +299,7 @@ extern unsigned long cr3;
#define get_dr2() \
({ \
register unsigned long _temp__; \
- asm volatile("movl %%dr2, %0" : "=r" (_temp__)); \
+ asm volatile("mov %%dr2, %0" : "=r" (_temp__)); \
_temp__; \
})
#endif
@@ -293,7 +310,7 @@ extern unsigned long cr3;
#define set_dr2(value) \
({ \
register unsigned long _temp__ = (value); \
- asm volatile("movl %0,%%dr2" : : "r" (_temp__)); \
+ asm volatile("mov %0,%%dr2" : : "r" (_temp__)); \
})
#endif
@@ -303,7 +320,7 @@ extern unsigned long cr3;
#define get_dr3() \
({ \
register unsigned long _temp__; \
- asm volatile("movl %%dr3, %0" : "=r" (_temp__)); \
+ asm volatile("mov %%dr3, %0" : "=r" (_temp__)); \
_temp__; \
})
#endif
@@ -314,7 +331,7 @@ extern unsigned long cr3;
#define set_dr3(value) \
({ \
register unsigned long _temp__ = (value); \
- asm volatile("movl %0,%%dr3" : : "r" (_temp__)); \
+ asm volatile("mov %0,%%dr3" : : "r" (_temp__)); \
})
#endif
@@ -324,7 +341,7 @@ extern unsigned long cr3;
#define get_dr6() \
({ \
register unsigned long _temp__; \
- asm volatile("movl %%dr6, %0" : "=r" (_temp__)); \
+ asm volatile("mov %%dr6, %0" : "=r" (_temp__)); \
_temp__; \
})
#endif
@@ -335,7 +352,7 @@ extern unsigned long cr3;
#define set_dr6(value) \
({ \
register unsigned long _temp__ = (value); \
- asm volatile("movl %0,%%dr6" : : "r" (_temp__)); \
+ asm volatile("mov %0,%%dr6" : : "r" (_temp__)); \
})
#endif
@@ -345,7 +362,7 @@ extern unsigned long cr3;
#define get_dr7() \
({ \
register unsigned long _temp__; \
- asm volatile("movl %%dr7, %0" : "=r" (_temp__)); \
+ asm volatile("mov %%dr7, %0" : "=r" (_temp__)); \
_temp__; \
})
#endif
@@ -356,7 +373,7 @@ extern unsigned long cr3;
#define set_dr7(value) \
({ \
register unsigned long _temp__ = (value); \
- asm volatile("movl %0,%%dr7" : : "r" (_temp__)); \
+ asm volatile("mov %0,%%dr7" : : "r" (_temp__)); \
})
#endif
diff --git a/i386/i386/seg.h b/i386/i386/seg.h
index 6f3d5af9..d2bb3f0d 100644
--- a/i386/i386/seg.h
+++ b/i386/i386/seg.h
@@ -59,12 +59,32 @@ struct real_descriptor {
base_high:8; /* base 24..31 */
};
+#ifdef __x86_64__
+struct real_descriptor64 {
+ unsigned int limit_low:16, /* limit 0..15 */
+ base_low:16, /* base 0..15 */
+ base_med:8, /* base 16..23 */
+ access:8, /* access byte */
+ limit_high:4, /* limit 16..19 */
+ granularity:4, /* granularity */
+ base_high:8, /* base 24..31 */
+ base_ext:32, /* base 32..63 */
+ reserved1:8,
+ zero:5,
+ reserved2:19;
+};
+#endif
+
struct real_gate {
unsigned int offset_low:16, /* offset 0..15 */
selector:16,
word_count:8,
access:8,
offset_high:16; /* offset 16..31 */
+#ifdef __x86_64__
+ unsigned int offset_ext:32, /* offset 32..63 */
+ reserved:32;
+#endif
};
#endif /* !__ASSEMBLER__ */
@@ -185,9 +205,43 @@ fill_descriptor(struct real_descriptor *_desc, unsigned base, unsigned limit,
#endif /* MACH_PV_DESCRIPTORS */
}
+#ifdef __x86_64__
+MACH_INLINE void
+fill_descriptor64(struct real_descriptor64 *_desc, unsigned long base, unsigned limit,
+ unsigned char access, unsigned char sizebits)
+{
+ /* TODO: when !MACH_PV_DESCRIPTORS, setting desc and just memcpy isn't simpler actually */
+#ifdef MACH_PV_DESCRIPTORS
+ struct real_descriptor64 __desc, *desc = &__desc;
+#else /* MACH_PV_DESCRIPTORS */
+ struct real_descriptor64 *desc = _desc;
+#endif /* MACH_PV_DESCRIPTORS */
+ if (limit > 0xfffff)
+ {
+ limit >>= 12;
+ sizebits |= SZ_G;
+ }
+ desc->limit_low = limit & 0xffff;
+ desc->base_low = base & 0xffff;
+ desc->base_med = (base >> 16) & 0xff;
+ desc->access = access | ACC_P;
+ desc->limit_high = limit >> 16;
+ desc->granularity = sizebits;
+ desc->base_high = base >> 24;
+ desc->base_ext = base >> 32;
+ desc->reserved1 = 0;
+ desc->zero = 0;
+ desc->reserved2 = 0;
+#ifdef MACH_PV_DESCRIPTORS
+ if (hyp_do_update_descriptor(kv_to_ma(_desc), *(uint64_t*)desc))
+ panic("couldn't update descriptor(%lu to %08lx%08lx)\n", (vm_offset_t) kv_to_ma(_desc), *(((unsigned long*)desc)+1), *(unsigned long *)desc);
+#endif /* MACH_PV_DESCRIPTORS */
+}
+#endif
+
/* Fill a gate with particular values. */
MACH_INLINE void
-fill_gate(struct real_gate *gate, unsigned offset, unsigned short selector,
+fill_gate(struct real_gate *gate, unsigned long offset, unsigned short selector,
unsigned char access, unsigned char word_count)
{
gate->offset_low = offset & 0xffff;
@@ -195,6 +249,10 @@ fill_gate(struct real_gate *gate, unsigned offset, unsigned short selector,
gate->word_count = word_count;
gate->access = access | ACC_P;
gate->offset_high = (offset >> 16) & 0xffff;
+#ifdef __x86_64__
+ gate->offset_ext = offset >> 32;
+ gate->reserved = 0;
+#endif
}
#endif /* !__ASSEMBLER__ */
diff --git a/i386/i386/setjmp.h b/i386/i386/setjmp.h
index 930a9dd5..eacc8e45 100644
--- a/i386/i386/setjmp.h
+++ b/i386/i386/setjmp.h
@@ -30,7 +30,11 @@
#define _I386_SETJMP_H_
typedef struct jmp_buf {
+#ifdef __i386__
int jmp_buf[6]; /* ebx, esi, edi, ebp, esp, eip */
+#else
+ long jmp_buf[8]; /* rbx, rbp, r12, r13, r14, r15, rsp, rip */
+#endif
} jmp_buf_t;
extern int _setjmp(jmp_buf_t*);
diff --git a/i386/i386/thread.h b/i386/i386/thread.h
index bae61e31..3d4808c7 100644
--- a/i386/i386/thread.h
+++ b/i386/i386/thread.h
@@ -55,6 +55,16 @@ struct i386_saved_state {
unsigned long fs;
unsigned long es;
unsigned long ds;
+#ifdef __x86_64__
+ unsigned long r15;
+ unsigned long r14;
+ unsigned long r13;
+ unsigned long r12;
+ unsigned long r11;
+ unsigned long r10;
+ unsigned long r9;
+ unsigned long r8;
+#endif
unsigned long edi;
unsigned long esi;
unsigned long ebp;
@@ -100,9 +110,17 @@ struct i386_kernel_state {
long k_ebx; /* kernel context */
long k_esp;
long k_ebp;
+#ifdef __i386__
long k_edi;
long k_esi;
+#endif
long k_eip;
+#ifdef __x86_64__
+ long k_r12;
+ long k_r13;
+ long k_r14;
+ long k_r15;
+#endif
};
/*
@@ -148,6 +166,14 @@ struct i386_interrupt_state {
long fs;
long es;
long ds;
+#ifdef __x86_64__
+ long r11;
+ long r10;
+ long r9;
+ long r8;
+ long rdi;
+ long rsi;
+#endif
long edx;
long ecx;
long eax;
diff --git a/i386/i386/trap.c b/i386/i386/trap.c
index d3f61314..51c0f0a5 100644
--- a/i386/i386/trap.c
+++ b/i386/i386/trap.c
@@ -471,6 +471,22 @@ int user_trap(struct i386_saved_state *regs)
return 1;
}
}
+#ifdef __x86_64__
+ {
+ unsigned char opcode, addr[4], seg[2];
+ int i;
+
+ opcode = inst_fetch(regs->eip, regs->cs);
+ for (i = 0; i < 4; i++)
+ addr[i] = inst_fetch(regs->eip+i+1, regs->cs);
+ for (i = 0; i < 2; i++)
+ seg[i] = inst_fetch(regs->eip+i+5, regs->cs);
+ if (opcode == 0x9a && seg[0] == 0x7 && seg[1] == 0) {
+ regs->eip += 7;
+ return 1;
+ }
+ }
+#endif
exc = EXC_BAD_INSTRUCTION;
code = EXC_I386_GPFLT;
subcode = regs->err & 0xffff;
@@ -557,10 +573,10 @@ int user_trap(struct i386_saved_state *regs)
void
i386_astintr(void)
{
- int mycpu = cpu_number();
-
(void) splsched(); /* block interrupts to check reasons */
#ifndef MACH_RING1
+ int mycpu = cpu_number();
+
if (need_ast[mycpu] & AST_I386_FP) {
/*
* AST was for delayed floating-point exception -
diff --git a/i386/i386/vm_param.h b/i386/i386/vm_param.h
index 7051b7af..edd9522c 100644
--- a/i386/i386/vm_param.h
+++ b/i386/i386/vm_param.h
@@ -35,7 +35,11 @@
/* This can be changed freely to separate kernel addresses from user addresses
* for better trace support in kdb; the _START symbol has to be offset by the
* same amount. */
+#ifdef __x86_64__
+#define VM_MIN_KERNEL_ADDRESS 0x40000000UL
+#else
#define VM_MIN_KERNEL_ADDRESS 0xC0000000UL
+#endif
#ifdef MACH_XEN
/* PV kernels can be loaded directly to the target virtual address */
@@ -46,11 +50,15 @@
#endif /* MACH_XEN */
#ifdef MACH_PV_PAGETABLES
+#ifdef __i386__
#if PAE
#define HYP_VIRT_START HYPERVISOR_VIRT_START_PAE
#else /* PAE */
#define HYP_VIRT_START HYPERVISOR_VIRT_START_NONPAE
#endif /* PAE */
+#else
+#define HYP_VIRT_START HYPERVISOR_VIRT_START
+#endif
#define VM_MAX_KERNEL_ADDRESS (HYP_VIRT_START - LINEAR_MIN_KERNEL_ADDRESS + VM_MIN_KERNEL_ADDRESS)
#else /* MACH_PV_PAGETABLES */
#define VM_MAX_KERNEL_ADDRESS (LINEAR_MAX_KERNEL_ADDRESS - LINEAR_MIN_KERNEL_ADDRESS + VM_MIN_KERNEL_ADDRESS)
@@ -62,11 +70,16 @@
*/
#define VM_KERNEL_MAP_SIZE (152 * 1024 * 1024)
-/* The kernel virtual address space is actually located
- at high linear addresses.
- This is the kernel address range in linear addresses. */
+/* This is the kernel address range in linear addresses. */
+#ifdef __x86_64__
+#define LINEAR_MIN_KERNEL_ADDRESS VM_MIN_KERNEL_ADDRESS
+#define LINEAR_MAX_KERNEL_ADDRESS (0x00007fffffffffffUL)
+#else
+/* On x86, the kernel virtual address space is actually located
+ at high linear addresses. */
#define LINEAR_MIN_KERNEL_ADDRESS (VM_MAX_ADDRESS)
#define LINEAR_MAX_KERNEL_ADDRESS (0xffffffffUL)
+#endif
#ifdef MACH_PV_PAGETABLES
/* need room for mmu updates (2*8bytes) */
@@ -109,11 +122,18 @@
#ifdef MACH_XEN
/* TODO Completely check Xen physical/virtual layout */
+#ifdef __LP64__
+#define VM_PAGE_MAX_SEGS 4
+#define VM_PAGE_DMA32_LIMIT DECL_CONST(0x100000000, UL)
+#define VM_PAGE_DIRECTMAP_LIMIT DECL_CONST(0x400000000000, UL)
+#define VM_PAGE_HIGHMEM_LIMIT DECL_CONST(0x10000000000000, ULL)
+#else
#define VM_PAGE_MAX_SEGS 3
#define VM_PAGE_DIRECTMAP_LIMIT (VM_MAX_KERNEL_ADDRESS \
- VM_MIN_KERNEL_ADDRESS \
- VM_KERNEL_MAP_SIZE)
#define VM_PAGE_HIGHMEM_LIMIT DECL_CONST(0x10000000000000, ULL)
+#endif
#else /* MACH_XEN */
#ifdef __LP64__
#define VM_PAGE_MAX_SEGS 4
diff --git a/i386/i386/xen.h b/i386/i386/xen.h
index 4ccde77b..8a17748a 100644
--- a/i386/i386/xen.h
+++ b/i386/i386/xen.h
@@ -46,13 +46,29 @@ MACH_INLINE unsigned long xchgl(volatile unsigned long *ptr, unsigned long x)
#define _TOSTR(x) #x
#define TOSTR(x) _TOSTR (x)
+#ifdef __i386__
+#define _hypcall_ret "=a"
+#define _hypcall_arg1 "ebx"
+#define _hypcall_arg2 "ecx"
+#define _hypcall_arg3 "edx"
+#define _hypcall_arg4 "esi"
+#define _hypcall_arg5 "edi"
+#endif
+#ifdef __x86_64__
+#define _hypcall_ret "=a"
+#define _hypcall_arg1 "rdi"
+#define _hypcall_arg2 "rsi"
+#define _hypcall_arg3 "rdx"
+#define _hypcall_arg4 "r10"
+#define _hypcall_arg5 "r8"
+#endif
/* x86-specific hypercall interface. */
#define _hypcall0(type, name) \
MACH_INLINE type hyp_##name(void) \
{ \
- long __ret; \
+ unsigned long __ret; \
asm volatile ("call hypcalls+("TOSTR(__HYPERVISOR_##name)"*32)" \
: "=a" (__ret) \
: : "memory"); \
@@ -62,85 +78,80 @@ MACH_INLINE type hyp_##name(void) \
#define _hypcall1(type, name, type1, arg1) \
MACH_INLINE type hyp_##name(type1 arg1) \
{ \
- long __ret; \
- long foo1; \
+ unsigned long __ret; \
+ register unsigned long __arg1 asm(_hypcall_arg1) = (unsigned long) arg1; \
asm volatile ("call hypcalls+("TOSTR(__HYPERVISOR_##name)"*32)" \
: "=a" (__ret), \
- "=b" (foo1) \
- : "1" ((long)arg1) \
- : "memory"); \
+ "+r" (__arg1) \
+ : : "memory"); \
return __ret; \
}
#define _hypcall2(type, name, type1, arg1, type2, arg2) \
MACH_INLINE type hyp_##name(type1 arg1, type2 arg2) \
{ \
- long __ret; \
- long foo1, foo2; \
+ unsigned long __ret; \
+ register unsigned long __arg1 asm(_hypcall_arg1) = (unsigned long) arg1; \
+ register unsigned long __arg2 asm(_hypcall_arg2) = (unsigned long) arg2; \
asm volatile ("call hypcalls+("TOSTR(__HYPERVISOR_##name)"*32)" \
: "=a" (__ret), \
- "=b" (foo1), \
- "=c" (foo2) \
- : "1" ((long)arg1), \
- "2" ((long)arg2) \
- : "memory"); \
+ "+r" (__arg1), \
+ "+r" (__arg2) \
+ : : "memory"); \
return __ret; \
}
#define _hypcall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
MACH_INLINE type hyp_##name(type1 arg1, type2 arg2, type3 arg3) \
{ \
- long __ret; \
- long foo1, foo2, foo3; \
+ unsigned long __ret; \
+ register unsigned long __arg1 asm(_hypcall_arg1) = (unsigned long) arg1; \
+ register unsigned long __arg2 asm(_hypcall_arg2) = (unsigned long) arg2; \
+ register unsigned long __arg3 asm(_hypcall_arg3) = (unsigned long) arg3; \
asm volatile ("call hypcalls+("TOSTR(__HYPERVISOR_##name)"*32)" \
: "=a" (__ret), \
- "=b" (foo1), \
- "=c" (foo2), \
- "=d" (foo3) \
- : "1" ((long)arg1), \
- "2" ((long)arg2), \
- "3" ((long)arg3) \
- : "memory"); \
+ "+r" (__arg1), \
+ "+r" (__arg2), \
+ "+r" (__arg3) \
+ : : "memory"); \
return __ret; \
}
#define _hypcall4(type, name, type1, arg1, type2, arg2, type3, arg3, type4, arg4) \
MACH_INLINE type hyp_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
{ \
- long __ret; \
- long foo1, foo2, foo3, foo4; \
+ unsigned long __ret; \
+ register unsigned long __arg1 asm(_hypcall_arg1) = (unsigned long) arg1; \
+ register unsigned long __arg2 asm(_hypcall_arg2) = (unsigned long) arg2; \
+ register unsigned long __arg3 asm(_hypcall_arg3) = (unsigned long) arg3; \
+ register unsigned long __arg4 asm(_hypcall_arg4) = (unsigned long) arg4; \
asm volatile ("call hypcalls+("TOSTR(__HYPERVISOR_##name)"*32)" \
: "=a" (__ret), \
- "=b" (foo1), \
- "=c" (foo2), \
- "=d" (foo3), \
- "=S" (foo4) \
- : "1" ((long)arg1), \
- "2" ((long)arg2), \
- "3" ((long)arg3), \
- "4" ((long)arg4) \
- : "memory"); \
+ "+r" (__arg1), \
+ "+r" (__arg2), \
+ "+r" (__arg3), \
+ "+r" (__arg4) \
+ : : "memory"); \
return __ret; \
}
#define _hypcall5(type, name, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5) \
MACH_INLINE type hyp_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
{ \
- long __ret; \
- long foo1, foo2, foo3, foo4, foo5; \
+ unsigned long __ret; \
+ register unsigned long __arg1 asm(_hypcall_arg1) = (unsigned long) arg1; \
+ register unsigned long __arg2 asm(_hypcall_arg2) = (unsigned long) arg2; \
+ register unsigned long __arg3 asm(_hypcall_arg3) = (unsigned long) arg3; \
+ register unsigned long __arg4 asm(_hypcall_arg4) = (unsigned long) arg4; \
+ register unsigned long __arg5 asm(_hypcall_arg5) = (unsigned long) arg5; \
asm volatile ("call hypcalls+("TOSTR(__HYPERVISOR_##name)"*32)" \
: "=a" (__ret), \
- "=b" (foo1), \
- "=c" (foo2), \
- "=d" (foo3), \
- "=S" (foo4), \
- "=D" (foo5) \
- : "1" ((long)arg1), \
- "2" ((long)arg2), \
- "3" ((long)arg3), \
- "4" ((long)arg4), \
- "5" ((long)arg5) \
- : "memory"); \
+ "+r" (__arg1), \
+ "+r" (__arg2), \
+ "+r" (__arg3), \
+ "+r" (__arg4), \
+ "+r" (__arg5) \
+ : : "memory"); \
return __ret; \
}
@@ -177,8 +188,13 @@ _hypcall2(long, set_gdt, vm_offset_t /* unsigned long * */, frame_list, unsigned
_hypcall2(long, stack_switch, unsigned long, ss, unsigned long, esp);
+#ifdef __i386__
_hypcall4(long, set_callbacks, unsigned long, es, void *, ea,
unsigned long, fss, void *, fsa);
+#endif
+#ifdef __x86_64__
+_hypcall3(long, set_callbacks, void *, ea, void *, fsa, void *, sc);
+#endif
_hypcall1(long, fpu_taskswitch, int, set);
#ifdef PAE
@@ -186,12 +202,22 @@ _hypcall1(long, fpu_taskswitch, int, set);
#else
#define hyp_high(pte) 0
#endif
+#ifdef __i386__
_hypcall4(long, update_descriptor, unsigned long, ma_lo, unsigned long, ma_hi, unsigned long, desc_lo, unsigned long, desc_hi);
#define hyp_do_update_descriptor(ma, desc) ({ \
pt_entry_t __ma = (ma); \
uint64_t __desc = (desc); \
hyp_update_descriptor(__ma & 0xffffffffU, hyp_high(__ma), __desc & 0xffffffffU, __desc >> 32); \
})
+#endif
+#ifdef __x86_64__
+_hypcall2(long, update_descriptor, unsigned long, ma, unsigned long, desc);
+#define hyp_do_update_descriptor(ma, desc) hyp_update_descriptor(ma, desc)
+#endif
+
+#ifdef __x86_64__
+_hypcall2(long, set_segment_base, int, reg, unsigned long, value);
+#endif
#include <xen/public/memory.h>
_hypcall2(long, memory_op, unsigned long, cmd, vm_offset_t /* void * */, arg);
@@ -207,11 +233,17 @@ MACH_INLINE void hyp_free_mfn(unsigned long mfn)
panic("couldn't free page %lu\n", mfn);
}
+#ifdef __i386__
_hypcall4(int, update_va_mapping, unsigned long, va, unsigned long, val_lo, unsigned long, val_hi, unsigned long, flags);
#define hyp_do_update_va_mapping(va, val, flags) ({ \
pt_entry_t __val = (val); \
hyp_update_va_mapping(va, __val & 0xffffffffU, hyp_high(__val), flags); \
})
+#endif
+#ifdef __x86_64__
+_hypcall3(int, update_va_mapping, unsigned long, va, unsigned long, val, unsigned long, flags);
+#define hyp_do_update_va_mapping(va, val, flags) hyp_update_va_mapping(va, val, flags)
+#endif
MACH_INLINE void hyp_free_page(unsigned long pfn, void *va)
{
@@ -270,6 +302,7 @@ MACH_INLINE void hyp_set_ldt(void *ldt, unsigned long nbentries) {
panic("couldn't set LDT\n");
}
#define hyp_set_cr3(value) hyp_mmuext_op_mfn(MMUEXT_NEW_BASEPTR, pa_to_mfn(value))
+#define hyp_set_user_cr3(value) hyp_mmuext_op_mfn(MMUEXT_NEW_USER_BASEPTR, pa_to_mfn(value))
MACH_INLINE void hyp_invlpg(vm_offset_t lin) {
struct mmuext_op ops;
int n;
@@ -281,11 +314,17 @@ MACH_INLINE void hyp_invlpg(vm_offset_t lin) {
}
#endif
+#ifdef __i386__
_hypcall2(long, set_timer_op, unsigned long, absolute_lo, unsigned long, absolute_hi);
#define hyp_do_set_timer_op(absolute_nsec) ({ \
uint64_t __absolute = (absolute_nsec); \
hyp_set_timer_op(__absolute & 0xffffffffU, __absolute >> 32); \
})
+#endif
+#ifdef __x86_64__
+_hypcall1(long, set_timer_op, unsigned long, absolute);
+#define hyp_do_set_timer_op(absolute_nsec) hyp_set_timer_op(absolute_nsec)
+#endif
#include <xen/public/event_channel.h>
_hypcall1(int, event_channel_op, vm_offset_t /* evtchn_op_t * */, op);
@@ -357,15 +396,16 @@ _hypcall1(unsigned long, get_debugreg, int, reg);
/* x86-specific */
MACH_INLINE uint64_t hyp_cpu_clock(void) {
- uint64_t tsc;
- asm volatile("rdtsc":"=A"(tsc));
- return tsc;
+ uint32_t hi, lo;
+ asm volatile("rdtsc" : "=d"(hi), "=a"(lo));
+ return (((uint64_t) hi) << 32) | lo;
}
#else /* __ASSEMBLER__ */
/* TODO: SMP */
#define cli movb $0xff,hyp_shared_info+CPU_CLI
#define sti call hyp_sti
+#define iretq jmp hyp_iretq
#endif /* ASSEMBLER */
#endif /* MACH_XEN */
diff --git a/i386/i386at/biosmem.c b/i386/i386at/biosmem.c
index 28b6fb83..9f86b66a 100644
--- a/i386/i386at/biosmem.c
+++ b/i386/i386at/biosmem.c
@@ -16,6 +16,7 @@
*/
#include <string.h>
+#include <inttypes.h>
#include <i386/model_dep.h>
#include <i386at/biosmem.h>
#include <kern/assert.h>
@@ -829,7 +830,7 @@ biosmem_map_show(void)
for (entry = biosmem_map, end = entry + biosmem_map_size;
entry < end;
entry++)
- printf("biosmem: %018llx:%018llx, %s\n", entry->base_addr,
+ printf("biosmem: %018"PRIx64":%018"PRIx64", %s\n", entry->base_addr,
entry->base_addr + entry->length,
biosmem_type_desc(entry->type));
@@ -857,7 +858,7 @@ biosmem_load_segment(struct biosmem_segment *seg, uint64_t max_phys_end)
return;
}
- printf("biosmem: warning: segment %s truncated to %#llx\n",
+ printf("biosmem: warning: segment %s truncated to %#"PRIx64"\n",
vm_page_seg_name(seg_index), max_phys_end);
phys_end = max_phys_end;
}
diff --git a/i386/i386at/com.c b/i386/i386at/com.c
index 4689e30d..2bdbc0d0 100644
--- a/i386/i386at/com.c
+++ b/i386/i386at/com.c
@@ -368,7 +368,7 @@ io_return_t comopen(
/*rvb tp->t_state |= TS_WOPEN; */
if ((tp->t_state & TS_ISOPEN) == 0)
comparam(unit);
- addr = (int)tp->t_addr;
+ addr = (uintptr_t)tp->t_addr;
s = spltty();
if (!comcarrier[unit]) /* not originating */
@@ -405,7 +405,7 @@ dev_t dev;
int flag;
{
struct tty *tp = &com_tty[minor(dev)];
- u_short addr = (int)tp->t_addr;
+ u_short addr = (uintptr_t)tp->t_addr;
ttyclose(tp);
if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) {
@@ -572,7 +572,7 @@ static void
comparam(int unit)
{
struct tty *tp = &com_tty[unit];
- u_short addr = (int)tp->t_addr;
+ u_short addr = (uintptr_t)tp->t_addr;
spl_t s = spltty();
int mode;
@@ -672,7 +672,7 @@ comst_3++;
comst_4++;
return(0);
}
- outb(TXRX((int)tp->t_addr), nch);
+ outb(TXRX((uintptr_t)tp->t_addr), nch);
}
#else
nch = getc(&tp->t_outq);
@@ -684,7 +684,7 @@ comst_4++;
comst_4++;
return;
}
- outb(TXRX((int)tp->t_addr), nch);
+ outb(TXRX((uintptr_t)tp->t_addr), nch);
tp->t_state |= TS_BUSY;
#endif
}
@@ -709,7 +709,7 @@ comtimer(void * param)
/* Its stuck */
printf("Tty %p was stuck\n", tp);
nch = getc(&tp->t_outq);
- outb(TXRX((int)tp->t_addr), nch);
+ outb(TXRX((uintptr_t)tp->t_addr), nch);
}
splx(s);
diff --git a/i386/i386at/kdasm.S b/i386/i386at/kdasm.S
index 46b1ee6b..fd0e1c86 100644
--- a/i386/i386at/kdasm.S
+++ b/i386/i386at/kdasm.S
@@ -69,9 +69,9 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
-#define start 0x08(%ebp)
-#define count 0x0c(%ebp)
-#define value 0x10(%ebp)
+#define start B_ARG0
+#define count B_ARG1
+#define value B_ARG2
ENTRY(kd_slmwd)
pushl %ebp
@@ -96,9 +96,9 @@ ENTRY(kd_slmwd)
* "slam up"
*/
-#define from 0x08(%ebp)
-#define to 0x0c(%ebp)
-#define count 0x10(%ebp)
+#define from B_ARG0
+#define to B_ARG1
+#define count B_ARG2
ENTRY(kd_slmscu)
pushl %ebp
movl %esp, %ebp
diff --git a/i386/i386at/model_dep.c b/i386/i386at/model_dep.c
index 04660a6d..aaeed807 100644
--- a/i386/i386at/model_dep.c
+++ b/i386/i386at/model_dep.c
@@ -340,8 +340,7 @@ i386at_init(void)
{
/* XXX move to intel/pmap.h */
extern pt_entry_t *kernel_page_dir;
- int nb_direct, i;
- vm_offset_t addr, delta;
+ int i;
/*
* Initialize the PIC prior to any possible call to an spl.
@@ -365,6 +364,8 @@ i386at_init(void)
#ifdef MACH_XEN
kernel_cmdline = (char*) boot_info.cmd_line;
#else /* MACH_XEN */
+ vm_offset_t addr;
+
/* Copy content pointed by boot_info before losing access to it when it
* is too far in physical memory.
* Also avoids leaving them in precious areas such as DMA memory. */
@@ -428,10 +429,10 @@ i386at_init(void)
* until we start using our new kernel segment descriptors.
*/
#if INIT_VM_MIN_KERNEL_ADDRESS != LINEAR_MIN_KERNEL_ADDRESS
- delta = INIT_VM_MIN_KERNEL_ADDRESS - LINEAR_MIN_KERNEL_ADDRESS;
+ vm_offset_t delta = INIT_VM_MIN_KERNEL_ADDRESS - LINEAR_MIN_KERNEL_ADDRESS;
if ((vm_offset_t)(-delta) < delta)
delta = (vm_offset_t)(-delta);
- nb_direct = delta >> PDESHIFT;
+ int nb_direct = delta >> PDESHIFT;
for (i = 0; i < nb_direct; i++)
kernel_page_dir[lin2pdenum_cont(INIT_VM_MIN_KERNEL_ADDRESS) + i] =
kernel_page_dir[lin2pdenum_cont(LINEAR_MIN_KERNEL_ADDRESS) + i];
@@ -452,14 +453,18 @@ i386at_init(void)
#endif /* PAE */
#endif /* MACH_PV_PAGETABLES */
#if PAE
- set_cr3((unsigned)_kvtophys(kernel_pmap->pdpbase));
+#ifdef __x86_64__
+ set_cr3((unsigned long)_kvtophys(kernel_pmap->l4base));
+#else
+ set_cr3((unsigned long)_kvtophys(kernel_pmap->pdpbase));
+#endif
#ifndef MACH_HYP
if (!CPU_HAS_FEATURE(CPU_FEATURE_PAE))
panic("CPU doesn't have support for PAE.");
set_cr4(get_cr4() | CR4_PAE);
#endif /* MACH_HYP */
#else
- set_cr3((unsigned)_kvtophys(kernel_page_dir));
+ set_cr3((unsigned long)_kvtophys(kernel_page_dir));
#endif /* PAE */
#ifndef MACH_HYP
/* Turn paging on.
@@ -527,7 +532,7 @@ i386at_init(void)
/*
* C boot entrypoint - called by boot_entry in boothdr.S.
- * Running in 32-bit flat mode, but without paging yet.
+ * Running in flat mode, but without paging yet.
*/
void c_boot_entry(vm_offset_t bi)
{
@@ -570,9 +575,9 @@ void c_boot_entry(vm_offset_t bi)
strtab_size = (vm_offset_t)phystokv(boot_info.syms.a.strsize);
kern_sym_end = kern_sym_start + 4 + symtab_size + strtab_size;
- printf("kernel symbol table at %08lx-%08lx (%d,%d)\n",
+ printf("kernel symbol table at %08lx-%08lx (%ld,%ld)\n",
kern_sym_start, kern_sym_end,
- symtab_size, strtab_size);
+ (unsigned long) symtab_size, (unsigned long) strtab_size);
}
if ((boot_info.flags & MULTIBOOT_ELF_SHDR)
@@ -669,12 +674,12 @@ void
inittodr(void)
{
time_value_t new_time;
+ uint64_t newsecs;
- new_time.seconds = 0;
+ (void) readtodc(&newsecs);
+ new_time.seconds = newsecs;
new_time.microseconds = 0;
- (void) readtodc((u_int *)&new_time.seconds);
-
{
spl_t s = splhigh();
time = new_time;
diff --git a/i386/i386at/rtc.c b/i386/i386at/rtc.c
index 6e5cdeb3..4187cbf5 100644
--- a/i386/i386at/rtc.c
+++ b/i386/i386at/rtc.c
@@ -146,7 +146,7 @@ dectohexdec(int n)
}
int
-readtodc(u_int *tp)
+readtodc(uint64_t *tp)
{
struct rtc_st rtclk;
time_t n;
diff --git a/i386/i386at/rtc.h b/i386/i386at/rtc.h
index 97eabe95..53797221 100644
--- a/i386/i386at/rtc.h
+++ b/i386/i386at/rtc.h
@@ -137,7 +137,7 @@ struct rtc_st {
} \
}
-extern int readtodc(u_int *tp);
+extern int readtodc(uint64_t *tp);
extern int writetodc(void);
#endif /* _RTC_H_ */
diff --git a/i386/include/mach/i386/asm.h b/i386/include/mach/i386/asm.h
index 45b848df..8ceae8ca 100644
--- a/i386/include/mach/i386/asm.h
+++ b/i386/include/mach/i386/asm.h
@@ -27,6 +27,7 @@
#ifndef _MACH_I386_ASM_H_
#define _MACH_I386_ASM_H_
+#ifdef __i386__
#define S_ARG0 4(%esp)
#define S_ARG1 8(%esp)
#define S_ARG2 12(%esp)
@@ -39,6 +40,32 @@
#define B_ARG1 12(%ebp)
#define B_ARG2 16(%ebp)
#define B_ARG3 20(%ebp)
+#endif
+
+#ifdef __x86_64__
+#define S_ARG0 %rdi
+#define S_ARG1 %rsi
+#define S_ARG2 %rdx
+#define S_ARG3 %rcx
+#define S_ARG4 %r8
+#define S_ARG5 %r9
+
+#define FRAME pushq %rbp; movq %rsp, %rbp
+#define EMARF leave
+
+#define B_ARG0 S_ARG0
+#define B_ARG1 S_ARG1
+#define B_ARG2 S_ARG2
+#define B_ARG3 S_ARG3
+
+#ifdef MACH_XEN
+#define INT_FIX \
+ popq %rcx ;\
+ popq %r11
+#else
+#define INT_FIX
+#endif
+#endif
#ifdef i486
#define TEXT_ALIGN 4
diff --git a/i386/include/mach/i386/machine_types.defs b/i386/include/mach/i386/machine_types.defs
index 6ff93dbd..dfbc521e 100755
--- a/i386/include/mach/i386/machine_types.defs
+++ b/i386/include/mach/i386/machine_types.defs
@@ -58,4 +58,9 @@ type natural_t = uint32_t;
*/
type integer_t = int32_t;
+/*
+ * Physical address size
+ */
+type rpc_phys_addr_t = uint64_t;
+
#endif /* _MACHINE_MACHINE_TYPES_DEFS_ */
diff --git a/i386/include/mach/i386/multiboot.h b/i386/include/mach/i386/multiboot.h
index c66ca032..5a532576 100644
--- a/i386/include/mach/i386/multiboot.h
+++ b/i386/include/mach/i386/multiboot.h
@@ -158,6 +158,23 @@ struct multiboot_module
unsigned reserved;
};
+#ifdef __x86_64__
+/* The mods_addr field above contains the physical address of the first
+ of 'mods_count' multiboot_module structures. */
+struct multiboot32_module
+{
+ /* Physical start and end addresses of the module data itself. */
+ unsigned mod_start;
+ unsigned mod_end;
+
+ /* Arbitrary ASCII string associated with the module. */
+ unsigned string;
+
+ /* Boot loader must set to 0; OS must ignore. */
+ unsigned reserved;
+};
+#endif
+
/* The mmap_addr field above contains the physical address of the first
of the AddrRangeDesc structure. "size" represents the size of the
diff --git a/i386/include/mach/i386/vm_param.h b/i386/include/mach/i386/vm_param.h
index 3a209b83..a684ed97 100644
--- a/i386/include/mach/i386/vm_param.h
+++ b/i386/include/mach/i386/vm_param.h
@@ -73,6 +73,10 @@
with that.
*/
#define VM_MIN_ADDRESS (0)
+#ifdef __x86_64__
+#define VM_MAX_ADDRESS (0x40000000UL)
+#else
#define VM_MAX_ADDRESS (0xc0000000UL)
+#endif
#endif /* _MACH_I386_VM_PARAM_H_ */
diff --git a/i386/include/mach/i386/vm_types.h b/i386/include/mach/i386/vm_types.h
index 4e259f9b..29b9e1e6 100644
--- a/i386/include/mach/i386/vm_types.h
+++ b/i386/include/mach/i386/vm_types.h
@@ -48,6 +48,9 @@
* a port in user space as an integer and
* in kernel space as a pointer.
*/
+#ifdef __x86_64__
+// unsigned long ?
+#endif
typedef unsigned int natural_t;
/*
@@ -69,18 +72,27 @@ typedef vm_offset_t * vm_offset_array_t;
/*
* A type for physical addresses.
*/
+#ifdef MACH_KERNEL
#ifdef PAE
typedef unsigned long long phys_addr_t;
#else /* PAE */
typedef unsigned long phys_addr_t;
#endif /* PAE */
+#else
+typedef unsigned long long phys_addr_t;
+#endif
+typedef unsigned long long rpc_phys_addr_t;
/*
* A vm_size_t is the proper type for e.g.
* expressing the difference between two
* vm_offset_t entities.
*/
+#ifdef __x86_64__
+typedef unsigned long vm_size_t;
+#else
typedef natural_t vm_size_t;
+#endif
#endif /* __ASSEMBLER__ */
diff --git a/i386/intel/pmap.c b/i386/intel/pmap.c
index c55b8f2d..0f650f2a 100644
--- a/i386/intel/pmap.c
+++ b/i386/intel/pmap.c
@@ -642,14 +642,31 @@ void pmap_bootstrap(void)
kernel_page_dir = (pt_entry_t*)phystokv(addr);
}
kernel_pmap->pdpbase = (pt_entry_t*)phystokv(pmap_grab_page());
+ memset(kernel_pmap->pdpbase, 0, INTEL_PGBYTES);
{
int i;
for (i = 0; i < PDPNUM; i++)
WRITE_PTE(&kernel_pmap->pdpbase[i],
pa_to_pte(_kvtophys((void *) kernel_page_dir
+ i * INTEL_PGBYTES))
- | INTEL_PTE_VALID);
+ | INTEL_PTE_VALID
+#ifdef MACH_PV_PAGETABLES
+ | INTEL_PTE_WRITE
+#endif
+ );
}
+#ifdef __x86_64__
+#ifdef MACH_HYP
+ kernel_pmap->user_l4base = NULL;
+ kernel_pmap->user_pdpbase = NULL;
+#endif
+ kernel_pmap->l4base = (pt_entry_t*)phystokv(pmap_grab_page());
+ memset(kernel_pmap->l4base, 0, INTEL_PGBYTES);
+ WRITE_PTE(&kernel_pmap->l4base[0], pa_to_pte(_kvtophys(kernel_pmap->pdpbase)) | INTEL_PTE_VALID | INTEL_PTE_WRITE);
+#ifdef MACH_PV_PAGETABLES
+ pmap_set_page_readonly_init(kernel_pmap->l4base);
+#endif
+#endif /* x86_64 */
#else /* PAE */
kernel_pmap->dirbase = kernel_page_dir = (pt_entry_t*)phystokv(pmap_grab_page());
#endif /* PAE */
@@ -676,11 +693,14 @@ void pmap_bootstrap(void)
#endif
pt_entry_t *l1_map[NSUP_L1];
{
- pt_entry_t *base = (pt_entry_t*) boot_info.pt_base;
vm_offset_t la;
int n_l1map;
for (n_l1map = 0, la = VM_MIN_KERNEL_ADDRESS; la >= VM_MIN_KERNEL_ADDRESS; la += NPTES * PAGE_SIZE) {
+ pt_entry_t *base = (pt_entry_t*) boot_info.pt_base;
#ifdef PAE
+#ifdef __x86_64__
+ base = (pt_entry_t*) ptetokv(base[0]);
+#endif /* x86_64 */
pt_entry_t *l2_map = (pt_entry_t*) ptetokv(base[lin2pdpnum(la)]);
#else /* PAE */
pt_entry_t *l2_map = base;
@@ -848,6 +868,9 @@ void pmap_set_page_readonly_init(void *_vaddr) {
vm_offset_t vaddr = (vm_offset_t) _vaddr;
#if PAE
pt_entry_t *pdpbase = (void*) boot_info.pt_base;
+#ifdef __x86_64__
+ pdpbase = (pt_entry_t *) ptetokv(pdpbase[lin2l4num(vaddr)]);
+#endif
/* The bootstrap table does not necessarily use contiguous pages for the pde tables */
pt_entry_t *dirbase = (void*) ptetokv(pdpbase[lin2pdpnum(vaddr)]);
#else
@@ -870,38 +893,68 @@ void pmap_clear_bootstrap_pagetable(pt_entry_t *base) {
unsigned i;
pt_entry_t *dir;
vm_offset_t va = 0;
+#ifdef __x86_64__
+ int l4i, l3i;
+#else
#if PAE
unsigned j;
#endif /* PAE */
+#endif
if (!hyp_mmuext_op_mfn (MMUEXT_UNPIN_TABLE, kv_to_mfn(base)))
panic("pmap_clear_bootstrap_pagetable: couldn't unpin page %p(%lx)\n", base, (vm_offset_t) kv_to_ma(base));
+#ifdef __x86_64__
+ /* 4-level page table */
+ for (l4i = 0; l4i < NPTES && va < HYP_VIRT_START && va < 0x0000800000000000UL; l4i++) {
+ pt_entry_t l4e = base[l4i];
+ pt_entry_t *l3;
+ if (!(l4e & INTEL_PTE_VALID)) {
+ va += NPTES * NPTES * NPTES * INTEL_PGBYTES;
+ continue;
+ }
+ l3 = (pt_entry_t *) ptetokv(l4e);
+
+ for (l3i = 0; l3i < NPTES && va < HYP_VIRT_START; l3i++) {
+ pt_entry_t l3e = l3[l3i];
+ if (!(l3e & INTEL_PTE_VALID)) {
+ va += NPTES * NPTES * INTEL_PGBYTES;
+ continue;
+ }
+ dir = (pt_entry_t *) ptetokv(l3e);
+#else
#if PAE
- for (j = 0; j < PDPNUM; j++)
+ /* 3-level page table */
+ for (j = 0; j < PDPNUM && va < HYP_VIRT_START; j++)
{
- pt_entry_t pdpe = base[j];
- if (pdpe & INTEL_PTE_VALID) {
+ pt_entry_t pdpe = base[j];
+ if (!(pdpe & INTEL_PTE_VALID)) {
+ va += NPTES * NPTES * INTEL_PGBYTES;
+ continue;
+ }
dir = (pt_entry_t *) ptetokv(pdpe);
#else /* PAE */
+ /* 2-level page table */
dir = base;
#endif /* PAE */
- for (i = 0; i < NPTES; i++) {
+#endif
+ for (i = 0; i < NPTES && va < HYP_VIRT_START; i++) {
pt_entry_t pde = dir[i];
unsigned long pfn = atop(pte_to_pa(pde));
void *pgt = (void*) phystokv(ptoa(pfn));
if (pde & INTEL_PTE_VALID)
hyp_free_page(pfn, pgt);
va += NPTES * INTEL_PGBYTES;
- if (va >= HYP_VIRT_START)
- break;
}
+#ifndef __x86_64__
#if PAE
hyp_free_page(atop(_kvtophys(dir)), dir);
- } else
- va += NPTES * NPTES * INTEL_PGBYTES;
- if (va >= HYP_VIRT_START)
- break;
}
#endif /* PAE */
+#else
+ hyp_free_page(atop(_kvtophys(dir)), dir);
+ }
+ hyp_free_page(atop(_kvtophys(l3)), l3);
+ }
+#endif
hyp_free_page(atop(_kvtophys(base)), base);
}
#endif /* MACH_PV_PAGETABLES */
@@ -1235,13 +1288,52 @@ pmap_t pmap_create(vm_size_t size)
return PMAP_NULL;
}
+ memset(p->pdpbase, 0, INTEL_PGBYTES);
{
for (i = 0; i < PDPNUM; i++)
WRITE_PTE(&p->pdpbase[i],
pa_to_pte(kvtophys((vm_offset_t) page_dir[i]))
- | INTEL_PTE_VALID);
+ | INTEL_PTE_VALID
+#ifdef MACH_PV_PAGETABLES
+ | INTEL_PTE_WRITE
+#endif
+ );
}
+#ifdef __x86_64__
+ // FIXME: use kmem_cache_alloc instead
+ if (kmem_alloc_wired(kernel_map,
+ (vm_offset_t *)&p->l4base, INTEL_PGBYTES)
+ != KERN_SUCCESS)
+ panic("pmap_create");
+ memset(p->l4base, 0, INTEL_PGBYTES);
+ WRITE_PTE(&p->l4base[0], pa_to_pte(kvtophys((vm_offset_t) p->pdpbase)) | INTEL_PTE_VALID | INTEL_PTE_WRITE);
#ifdef MACH_PV_PAGETABLES
+ // FIXME: use kmem_cache_alloc instead
+ if (kmem_alloc_wired(kernel_map,
+ (vm_offset_t *)&p->user_pdpbase, INTEL_PGBYTES)
+ != KERN_SUCCESS)
+ panic("pmap_create");
+ memset(p->user_pdpbase, 0, INTEL_PGBYTES);
+ {
+ int i;
+ for (i = 0; i < lin2pdpnum(VM_MAX_ADDRESS); i++)
+ WRITE_PTE(&p->user_pdpbase[i], pa_to_pte(kvtophys((vm_offset_t) page_dir[i])) | INTEL_PTE_VALID | INTEL_PTE_WRITE);
+ }
+ // FIXME: use kmem_cache_alloc instead
+ if (kmem_alloc_wired(kernel_map,
+ (vm_offset_t *)&p->user_l4base, INTEL_PGBYTES)
+ != KERN_SUCCESS)
+ panic("pmap_create");
+ memset(p->user_l4base, 0, INTEL_PGBYTES);
+ WRITE_PTE(&p->user_l4base[0], pa_to_pte(kvtophys((vm_offset_t) p->user_pdpbase)) | INTEL_PTE_VALID | INTEL_PTE_WRITE);
+#endif /* MACH_PV_PAGETABLES */
+#endif /* _x86_64 */
+#ifdef MACH_PV_PAGETABLES
+#ifdef __x86_64__
+ pmap_set_page_readonly(p->l4base);
+ pmap_set_page_readonly(p->user_l4base);
+ pmap_set_page_readonly(p->user_pdpbase);
+#endif
pmap_set_page_readonly(p->pdpbase);
#endif /* MACH_PV_PAGETABLES */
#else /* PAE */
@@ -1304,6 +1396,9 @@ void pmap_destroy(pmap_t p)
page_dir = p->dirbase;
#endif
+#ifdef __x86_64__
+#warning FIXME 64bit need to free l3
+#endif
/*
* Free the memory maps, then the
* pmap structure.
@@ -1339,8 +1434,20 @@ void pmap_destroy(pmap_t p)
}
#ifdef MACH_PV_PAGETABLES
+#ifdef __x86_64__
+ pmap_set_page_readwrite(p->l4base);
+ pmap_set_page_readwrite(p->user_l4base);
+ pmap_set_page_readwrite(p->user_pdpbase);
+#endif
pmap_set_page_readwrite(p->pdpbase);
#endif /* MACH_PV_PAGETABLES */
+#ifdef __x86_64__
+ kmem_free(kernel_map, (vm_offset_t)p->l4base, INTEL_PGBYTES);
+#ifdef MACH_PV_PAGETABLES
+ kmem_free(kernel_map, (vm_offset_t)p->user_l4base, INTEL_PGBYTES);
+ kmem_free(kernel_map, (vm_offset_t)p->user_pdpbase, INTEL_PGBYTES);
+#endif
+#endif
kmem_cache_free(&pdpt_cache, (vm_offset_t) p->pdpbase);
#endif /* PAE */
kmem_cache_free(&pmap_cache, (vm_offset_t) p);
@@ -1867,7 +1974,7 @@ void pmap_enter(
#if !MACH_KDB
if (pmap == kernel_pmap && (v < kernel_virtual_start || v >= kernel_virtual_end))
- panic("pmap_enter(%p, %p) falls in physical memory area!\n", v, pa);
+ panic("pmap_enter(%lx, %llx) falls in physical memory area!\n", v, (unsigned long long) pa);
#endif
if (pmap == kernel_pmap && (prot & VM_PROT_WRITE) == 0
&& !wired /* hack for io_wire */ ) {
@@ -2904,7 +3011,7 @@ void pmap_update_interrupt(void)
}
#endif /* NCPUS > 1 */
-#if defined(__i386__)
+#if defined(__i386__) || defined (__x86_64__)
/* Unmap page 0 to trap NULL references. */
void
pmap_unmap_page_zero (void)
diff --git a/i386/intel/pmap.h b/i386/intel/pmap.h
index 5fa2a0c4..d6224d87 100644
--- a/i386/intel/pmap.h
+++ b/i386/intel/pmap.h
@@ -48,7 +48,7 @@
* Define the generic in terms of the specific
*/
-#if defined(__i386__)
+#if defined(__i386__) || defined(__x86_64__)
#define INTEL_PGBYTES I386_PGBYTES
#define INTEL_PGSHIFT I386_PGSHIFT
#define intel_btop(x) i386_btop(x)
@@ -71,9 +71,19 @@ typedef phys_addr_t pt_entry_t;
#define INTEL_OFFMASK 0xfff /* offset within page */
#if PAE
+#ifdef __x86_64__
+#define L4SHIFT 39 /* L4 shift */
+#define L4MASK 0x1ff /* mask for L4 index */
+#endif
#define PDPSHIFT 30 /* page directory pointer */
+#ifdef __x86_64__
+/* Enough for 8GiB addressing space. */
+#define PDPNUM 8 /* number of page directory pointers */
+#define PDPMASK 0x1ff /* mask for page directory pointer index */
+#else
#define PDPNUM 4 /* number of page directory pointers */
#define PDPMASK 3 /* mask for page directory pointer index */
+#endif
#define PDESHIFT 21 /* page descriptor shift */
#define PDEMASK 0x1ff /* mask for page descriptor index */
#define PTESHIFT 12 /* page table shift */
@@ -87,6 +97,13 @@ typedef phys_addr_t pt_entry_t;
#endif /* PAE */
/*
+ * Convert linear offset to L4 pointer index
+ */
+#ifdef __x86_64__
+#define lin2l4num(a) (((a) >> L4SHIFT) & L4MASK)
+#endif
+
+/*
* Convert linear offset to page descriptor index
*/
#define lin2pdenum(a) (((a) >> PDESHIFT) & PDEMASK)
@@ -167,6 +184,13 @@ struct pmap {
#else
pt_entry_t *pdpbase; /* page directory pointer table */
#endif /* ! PAE */
+#ifdef __x86_64__
+ pt_entry_t *l4base; /* l4 table */
+#ifdef MACH_HYP
+ pt_entry_t *user_l4base; /* Userland l4 table */
+ pt_entry_t *user_pdpbase; /* Userland l4 table */
+#endif /* MACH_HYP */
+#endif /* x86_64 */
int ref_count; /* reference count */
decl_simple_lock_data(,lock)
/* lock on map */
@@ -187,7 +211,21 @@ extern void pmap_clear_bootstrap_pagetable(pt_entry_t *addr);
#endif /* MACH_PV_PAGETABLES */
#if PAE
+#ifdef __x86_64__
+#ifdef MACH_HYP
+#define set_pmap(pmap) \
+ MACRO_BEGIN \
+ set_cr3(kvtophys((vm_offset_t)(pmap)->l4base)); \
+ if (pmap->user_l4base) \
+ if (!hyp_set_user_cr3(kvtophys((vm_offset_t)(pmap)->user_l4base))) \
+ panic("set_user_cr3"); \
+ MACRO_END
+#else /* MACH_HYP */
+#define set_pmap(pmap) set_cr3(kvtophys((vm_offset_t)(pmap)->l4base))
+#endif /* MACH_HYP */
+#else /* x86_64 */
#define set_pmap(pmap) set_cr3(kvtophys((vm_offset_t)(pmap)->pdpbase))
+#endif /* x86_64 */
#else /* PAE */
#define set_pmap(pmap) set_cr3(kvtophys((vm_offset_t)(pmap)->dirbase))
#endif /* PAE */
diff --git a/i386/linux/dev/include/linux/autoconf.h b/i386/linux/dev/include/linux/autoconf.h
index 75ff2aad..bd035d4e 100644
--- a/i386/linux/dev/include/linux/autoconf.h
+++ b/i386/linux/dev/include/linux/autoconf.h
@@ -246,6 +246,8 @@
#undef CONFIG_BSD_DISKLABEL
#undef CONFIG_SMD_DISKLABEL
+#define CONFIG_GPT_DISKLABEL 1
+
/*
* Character devices
*/
diff --git a/i386/xen/xen.c b/i386/xen/xen.c
index d10ecf39..f2dedfb9 100644
--- a/i386/xen/xen.c
+++ b/i386/xen/xen.c
@@ -44,7 +44,7 @@ void hyp_failsafe_c_callback(struct failsafe_callback_regs *regs) {
panic("failsafe");
}
-extern void return_to_iret;
+extern char return_to_iret[];
void hypclock_machine_intr(int old_ipl, void *ret_addr, struct i386_interrupt_state *regs, uint64_t delta) {
if (ret_addr == &return_to_iret) {
diff --git a/include/inttypes.h b/include/inttypes.h
new file mode 100644
index 00000000..ebafb67a
--- /dev/null
+++ b/include/inttypes.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Mach.
+ *
+ * GNU Mach is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _INTTYPES_H_
+#define _INTTYPES_H_
+
+#include <stdint.h>
+
+#ifdef __x86_64__
+#define __64PREFIX "l"
+#else
+#define __64PREFIX "ll"
+#endif
+
+#define PRId8 "d"
+#define PRId16 "d"
+#define PRId32 "d"
+#define PRId64 __64PREFIX"d"
+#define PRIdPTR __64PREFIX"d"
+
+#define PRIi8 "i"
+#define PRIi16 "i"
+#define PRIi32 "i"
+#define PRIi64 __64PREFIX"i"
+#define PRIiPTR __64PREFIX"i"
+
+#define PRIu8 "u"
+#define PRIu16 "u"
+#define PRIu32 "u"
+#define PRIu64 __64PREFIX"u"
+#define PRIuPTR __64PREFIX"u"
+
+#define PRIx8 "x"
+#define PRIx16 "x"
+#define PRIx32 "x"
+#define PRIx64 __64PREFIX"x"
+#define PRIxPTR __64PREFIX"x"
+
+#define PRIx8 "x"
+#define PRIx16 "x"
+#define PRIx32 "x"
+#define PRIx64 __64PREFIX"x"
+#define PRIxPTR __64PREFIX"x"
+
+#endif /* _INTTYPES_H_ */
diff --git a/include/mach/experimental.defs b/include/mach/experimental.defs
new file mode 100644
index 00000000..ddcbea5f
--- /dev/null
+++ b/include/mach/experimental.defs
@@ -0,0 +1,15 @@
+subsystem
+#if KERNEL_USER
+ KernelUser
+#endif /* KERNEL_USER */
+#if KERNEL_SERVER
+ KernelServer
+#endif /* KERNEL_SERVER */
+ experimental 424242;
+
+#include <mach/std_types.defs>
+#include <mach/mach_types.defs>
+
+serverprefix experimental_;
+
+/* This is free for experimenting RPCs, with no backward compatibility guarantees. */
diff --git a/include/mach/gnumach.defs b/include/mach/gnumach.defs
index 97ab573c..d423a10a 100644
--- a/include/mach/gnumach.defs
+++ b/include/mach/gnumach.defs
@@ -165,3 +165,27 @@ routine vm_msync(
address : vm_address_t;
size : vm_size_t;
sync_flags : vm_sync_t);
+
+/*
+ * This routine is created for allocating DMA buffers.
+ * We are going to get a contiguous physical memory
+ * and its physical address in addition to the virtual address.
+ * We can specify physical memory range limits and alignment.
+ * NB:
+ * pmax is defined as the byte after the maximum address,
+ * eg 0x100000000 for 4GiB limit.
+ */
+/* XXX
+ * Future work: the RPC should return a special
+ * memory object (similar to device_map() ), which can then be mapped into
+ * the process address space with vm_map() like any other memory object.
+ */
+routine vm_allocate_contiguous(
+ host_priv : host_priv_t;
+ target_task : vm_task_t;
+ out vaddr : vm_address_t;
+ out paddr : rpc_phys_addr_t;
+ size : vm_size_t;
+ pmin : rpc_phys_addr_t;
+ pmax : rpc_phys_addr_t;
+ palign : rpc_phys_addr_t);
diff --git a/include/mach/mach.defs b/include/mach/mach.defs
index a4e23db6..c6ad0770 100644
--- a/include/mach/mach.defs
+++ b/include/mach/mach.defs
@@ -720,38 +720,5 @@ skip; /* old host_fpa_counters_reset */
#endif /* ! KERNEL_USER */
/*
- * This routine is created for allocating DMA buffers.
- * We are going to get a contiguous physical memory
- * and its physical address in addition to the virtual address.
- */
-
- /* XXX
- This RPC lacks a few additional constraints like boundaries, alignment
-and maybe phase. We may not use them now, but they're important for
-portability (e.g. if GNU Mach supports PAE, drivers that can't use
-physical memory beyond the 4 GiB limit must be able to express it).
-
-> What do you mean by "phase"?
-
-Offset from the alignment. But I don't think it's useful at all in this
-case. Minimum and maximum addresses and alignment should do. Maybe
-boundary crossing but usually, specifying the right alignment and size
-is enough.
-
-Ideally we could make the RPC should return a special
-memory object (similar to device_map() ), which can then be mapped into
-the process address space with vm_map() like any other memory object.
-But we currently do not need it, if we really do we can introduce another RPC.
-
-FIXME: use phys_address_t
- */
-routine vm_allocate_contiguous(
- host_priv : host_priv_t;
- target_task : vm_task_t;
- out vaddr : vm_address_t;
- out paddr : vm_address_t;
- size : vm_size_t);
-
-/*
* There is no more room in this interface for additional calls.
*/
diff --git a/include/mach/xen.h b/include/mach/xen.h
index 6fc626f2..44620820 100644
--- a/include/mach/xen.h
+++ b/include/mach/xen.h
@@ -48,11 +48,15 @@ extern unsigned long la_shift;
#define la_to_kv(a) phystokv(la_to_pa(a))
#ifdef MACH_PSEUDO_PHYS
+#ifdef __i386__
#if PAE
#define PFN_LIST MACH2PHYS_VIRT_START_PAE
#else
#define PFN_LIST MACH2PHYS_VIRT_START_NONPAE
#endif
+#else
+#define PFN_LIST MACH2PHYS_VIRT_START
+#endif
#if VM_MIN_KERNEL_ADDRESS != LINEAR_MIN_KERNEL_ADDRESS
extern unsigned long *pfn_list;
#else
diff --git a/ipc/mach_port.c b/ipc/mach_port.c
index b1379b79..0757bb84 100644
--- a/ipc/mach_port.c
+++ b/ipc/mach_port.c
@@ -550,7 +550,7 @@ mach_port_destroy(
kr = ipc_right_lookup_write(space, name, &entry);
if (kr != KERN_SUCCESS) {
if (MACH_PORT_VALID (name) && space == current_space()) {
- printf("task %.*s destroying a bogus port %lu, most probably a bug.\n", sizeof current_task()->name, current_task()->name, (unsigned long) name);
+ printf("task %.*s destroying a bogus port %lu, most probably a bug.\n", (int) sizeof current_task()->name, current_task()->name, (unsigned long) name);
if (mach_port_deallocate_debug)
SoftDebugger("mach_port_deallocate");
}
@@ -594,7 +594,7 @@ mach_port_deallocate(
kr = ipc_right_lookup_write(space, name, &entry);
if (kr != KERN_SUCCESS) {
if (MACH_PORT_VALID (name) && space == current_space()) {
- printf("task %.*s deallocating a bogus port %lu, most probably a bug.\n", sizeof current_task()->name, current_task()->name, (unsigned long) name);
+ printf("task %.*s deallocating a bogus port %lu, most probably a bug.\n", (int) sizeof current_task()->name, current_task()->name, (unsigned long) name);
if (mach_port_deallocate_debug)
SoftDebugger("mach_port_deallocate");
}
diff --git a/kern/boot_script.c b/kern/boot_script.c
index b2ae901c..9e8f60a7 100644
--- a/kern/boot_script.c
+++ b/kern/boot_script.c
@@ -4,6 +4,7 @@
#include <mach/mach_types.h>
#include <string.h>
+#include <kern/printf.h>
#include "boot_script.h"
@@ -172,7 +173,7 @@ add_list (void *ptr, void ***ptr_list, int *alloc, int *index, int incr)
/* Create an argument with TEXT, value type TYPE, and value VAL.
Add the argument to the argument list of CMD. */
static struct arg *
-add_arg (struct cmd *cmd, char *text, int type, int val)
+add_arg (struct cmd *cmd, char *text, int type, long val)
{
struct arg *arg;
@@ -558,6 +559,7 @@ boot_script_exec (void)
if (sym->type == VAL_NONE)
{
error = BOOT_SCRIPT_UNDEF_SYM;
+ printf("bootstrap script missing symbol '%s'\n", sym->name);
goto done;
}
arg->type = sym->type;
diff --git a/kern/bootstrap.c b/kern/bootstrap.c
index 8b88d17d..00064cef 100644
--- a/kern/bootstrap.c
+++ b/kern/bootstrap.c
@@ -126,14 +126,32 @@ void bootstrap_create(void)
int compat;
unsigned n = 0;
#ifdef MACH_XEN
- struct multiboot_module *bmods = ((struct multiboot_module *)
- boot_info.mod_start);
+#ifdef __x86_64__ // 32_ON_64 actually
+ struct multiboot32_module *bmods32 = (struct multiboot32_module *)
+ boot_info.mod_start;
+ struct multiboot_module *bmods;
+ if (bmods32) {
+ int i;
+ for (n = 0; bmods32[n].mod_start; n++)
+ ;
+ bmods = alloca(n * sizeof(*bmods));
+ for (i = 0; i < n ; i++)
+ {
+ bmods[i].mod_start = kvtophys(bmods32[i].mod_start + (vm_offset_t) bmods32);
+ bmods[i].mod_end = kvtophys(bmods32[i].mod_end + (vm_offset_t) bmods32);
+ bmods[i].string = kvtophys(bmods32[i].string + (vm_offset_t) bmods32);
+ }
+ }
+#else
+ struct multiboot_module *bmods = (struct multiboot_module *)
+ boot_info.mod_start;
if (bmods)
for (n = 0; bmods[n].mod_start; n++) {
bmods[n].mod_start = kvtophys(bmods[n].mod_start + (vm_offset_t) bmods);
bmods[n].mod_end = kvtophys(bmods[n].mod_end + (vm_offset_t) bmods);
bmods[n].string = kvtophys(bmods[n].string + (vm_offset_t) bmods);
}
+#endif
boot_info.mods_count = n;
boot_info.flags |= MULTIBOOT_MODS;
#else /* MACH_XEN */
@@ -880,6 +898,7 @@ boot_script_insert_right (struct cmd *cmd, mach_port_t port, mach_port_t *name)
int
boot_script_insert_task_port (struct cmd *cmd, task_t task, mach_port_t *name)
{
- *name = task_insert_send_right (cmd->task, task->itk_sself);
+ *name = task_insert_send_right (cmd->task,
+ ipc_port_make_send(task->itk_sself));
return 0;
}
diff --git a/kern/cpu_number.h b/kern/cpu_number.h
index 5d3e4bd1..e7b65324 100644
--- a/kern/cpu_number.h
+++ b/kern/cpu_number.h
@@ -31,7 +31,7 @@
* Definitions for cpu identification in multi-processors.
*/
-int master_cpu; /* 'master' processor - keeps time */
+extern int master_cpu; /* 'master' processor - keeps time */
#if (NCPUS == 1)
/* cpu number is always 0 on a single processor system */
diff --git a/kern/experimental.srv b/kern/experimental.srv
new file mode 100644
index 00000000..2ccfd783
--- /dev/null
+++ b/kern/experimental.srv
@@ -0,0 +1,3 @@
+#define KERNEL_SERVER 1
+
+#include <mach/experimental.defs>
diff --git a/kern/ipc_kobject.c b/kern/ipc_kobject.c
index 709ec9ec..5ced4037 100644
--- a/kern/ipc_kobject.c
+++ b/kern/ipc_kobject.c
@@ -56,6 +56,7 @@
#include <device/device_pager.server.h>
#include <kern/mach4.server.h>
#include <kern/gnumach.server.h>
+#include <kern/experimental.server.h>
#if MACH_DEBUG
#include <kern/mach_debug.server.h>
@@ -170,6 +171,7 @@ ipc_kobject_server(request)
#endif /* MACH_DEBUG */
|| (routine = mach4_server_routine(&request->ikm_header)) != 0
|| (routine = gnumach_server_routine(&request->ikm_header)) != 0
+ || (routine = experimental_server_routine(&request->ikm_header)) != 0
#if MACH_MACHINE_ROUTINES
|| (routine = MACHINE_SERVER_ROUTINE(&request->ikm_header)) != 0
#endif /* MACH_MACHINE_ROUTINES */
diff --git a/kern/processor.c b/kern/processor.c
index dffd7d0b..6ed716d3 100644
--- a/kern/processor.c
+++ b/kern/processor.c
@@ -55,6 +55,8 @@ struct kmem_cache pset_cache;
/*
* Exported variables.
*/
+int master_cpu;
+
struct processor_set default_pset;
struct processor processor_array[NCPUS];
diff --git a/kern/syscall_sw.h b/kern/syscall_sw.h
index 1edf1c7f..80b1810b 100644
--- a/kern/syscall_sw.h
+++ b/kern/syscall_sw.h
@@ -31,6 +31,8 @@
* mach_trap_stack indicates the trap may discard
* its kernel stack. Some architectures may need
* to save more state in the pcb for these traps.
+ *
+ * Note: this is indexed manually by locore.S!
*/
typedef struct {
diff --git a/kern/time_stamp.c b/kern/time_stamp.c
index ee141a0e..b8ac9d82 100644
--- a/kern/time_stamp.c
+++ b/kern/time_stamp.c
@@ -29,6 +29,8 @@
#include <sys/time.h>
#include <kern/time_stamp.h>
+unsigned ts_tick_count;
+
/*
* ts.c - kern_timestamp system call.
*/
diff --git a/kern/time_stamp.h b/kern/time_stamp.h
index becaae1b..2492e522 100644
--- a/kern/time_stamp.h
+++ b/kern/time_stamp.h
@@ -52,7 +52,7 @@ struct tsval {
#define TS_FORMAT 1
#if KERNEL
-unsigned ts_tick_count;
+extern unsigned ts_tick_count;
#endif /* KERNEL */
#endif /* TS_FORMAT */
diff --git a/linux/dev/drivers/block/genhd.c b/linux/dev/drivers/block/genhd.c
index ee1ac32b..44ba6533 100644
--- a/linux/dev/drivers/block/genhd.c
+++ b/linux/dev/drivers/block/genhd.c
@@ -29,6 +29,11 @@
#endif
#include <linux/hdreg.h>
#include <alloca.h>
+#ifdef CONFIG_GPT_DISKLABEL
+#include <linux/blkdev.h>
+#include <kern/kalloc.h>
+#include <stddef.h>
+#endif
#include <asm/system.h>
@@ -276,6 +281,246 @@ static void bsd_disklabel_partition(struct gendisk *hd, kdev_t dev)
}
#endif
+#ifdef CONFIG_GPT_DISKLABEL
+/*
+ * Compute a CRC32 but treat some range as if it were zeros.
+ *
+ * Straight copy of ether_crc_le() from linux/pcmcia-cs/include/linux/crc32.h, except for the first if/else
+ */
+static inline unsigned ether_crc_le_hole(int length, unsigned char *data, unsigned int skip_offset, unsigned int skip_length)
+{
+ static unsigned const ethernet_polynomial_le = 0xedb88320U;
+ unsigned int crc = 0xffffffff; /* Initial value. */
+ while(--length >= 0) {
+ unsigned char current_octet = *data++;
+ if(skip_offset == 0 && skip_length-- != 0)
+ current_octet = 0;
+ else
+ --skip_offset;
+ int bit;
+ for (bit = 8; --bit >= 0; current_octet >>= 1) {
+ if ((crc ^ current_octet) & 1) {
+ crc >>= 1;
+ crc ^= ethernet_polynomial_le;
+ } else
+ crc >>= 1;
+ }
+ }
+ return crc;
+}
+
+/*
+ * Read in a full GPT array into a contiguous chunk, allocates *PP_S bytes into *PP.
+ *
+ * An attempt to do as few round-trips as possible is made by reading a PAGE_SIZE at a time,
+ * since that's the bread() maximum.
+ */
+static int gpt_read_part_table(void **pp, vm_size_t *pp_s, kdev_t dev, int bsize, __u64 first_sector, struct gpt_disklabel_header *h)
+{
+ __u64 lba = first_sector + h->h_part_table_lba;
+ __u32 bytes_left = *pp_s = h->h_part_table_len * h->h_part_table_entry_size;
+ struct buffer_head *bh;
+ void *cur = *pp = (void *)kalloc(*pp_s);
+ if (!cur) {
+ printk(" unable to allocate GPT partition table buffer");
+ return -2;
+ }
+
+ while (bytes_left) {
+ unsigned bytes_to_read = MIN(bytes_left, PAGE_SIZE);
+ if(!(bh = bread(dev, lba, bytes_to_read))) {
+ printk(" unable to read partition table array");
+ return -3;
+ }
+
+ memcpy(cur, bh->b_data, bytes_to_read);
+ cur += bytes_to_read;
+ bytes_left -= bytes_to_read;
+ lba += PAGE_SIZE / bsize;
+
+ brelse(bh);
+ }
+
+ return 0;
+}
+
+/*
+ * Sequence from section 5.3.2 of spec 2.8A:
+ * signature, CRC, lba_current matches, partition table CRC, primary: check backup for validity
+ */
+static int gpt_verify_header(void **pp, vm_size_t *pp_s, kdev_t dev, int bsize, __u64 first_sector, __u64 lba, struct gpt_disklabel_header *h)
+{
+ int res;
+ __u32 crc;
+
+ if (memcmp(h->h_signature, GPT_SIGNATURE, strlen(GPT_SIGNATURE)) != 0) {
+ printk(" bad GPT signature \"%c%c%c%c%c%c%c%c\";",
+ h->h_signature[0], h->h_signature[1], h->h_signature[2], h->h_signature[3],
+ h->h_signature[4], h->h_signature[5], h->h_signature[6], h->h_signature[7]);
+ return 1;
+ }
+
+ crc = ether_crc_le_hole(h->h_header_size, (void *)h,
+ offsetof(struct gpt_disklabel_header, h_header_crc), sizeof(h->h_header_crc)) ^ ~0;
+ if (crc != h->h_header_crc) {
+ printk(" bad header CRC: %x != %x;", crc, h->h_header_crc);
+ return 2;
+ }
+
+ if (h->h_lba_current != lba) {
+ printk(" current LBA mismatch: %lld != %lld;", h->h_lba_current, lba);
+ return 3;
+ }
+
+ if (*pp) {
+ kfree((vm_offset_t)*pp, *pp_s);
+ *pp = NULL;
+ }
+ if ((res = gpt_read_part_table(pp, pp_s, dev, bsize, first_sector, h)))
+ return res;
+
+ crc = ether_crc_le_hole(*pp_s, *pp, 0, 0) ^ ~0;
+ if (crc != h->h_part_table_crc) {
+ printk(" bad partition table CRC: %x != %x;", crc, h->h_part_table_crc);
+ return 4;
+ }
+
+ for (int i = h->h_header_size; i < bsize; ++i)
+ res |= ((char*)h)[i];
+ if (res) {
+ printk(" rest of GPT block dirty;");
+ return 5;
+ }
+
+ return 0;
+}
+
+static void gpt_print_part_name(struct gpt_disklabel_part *p)
+{
+ for(int n = 0; n < sizeof(p->p_name) / sizeof(*p->p_name) && p->p_name[n]; ++n)
+ if(p->p_name[n] & ~0xFF)
+ printk("?"); /* Can't support all of Unicode, but don't print garbage at least... */
+ else
+ printk("%c", p->p_name[n]);
+}
+
+#ifdef DEBUG
+static void gpt_print_guid(struct gpt_guid *guid)
+{
+ printk("%08X-%04X-%04X-%02X%02X-", guid->g_time_low, guid->g_time_mid, guid->g_time_high_version, guid->g_clock_sec_high, guid->g_clock_sec_low);
+ for (int i = 0; i < sizeof(guid->g_node_id); ++i)
+ printk("%02X", guid->g_node_id[i]);
+}
+
+static void gpt_dump_header(struct gpt_disklabel_header *h)
+{
+ printk(" [h_signature: \"%c%c%c%c%c%c%c%c\"; ",
+ h->h_signature[0], h->h_signature[1], h->h_signature[2], h->h_signature[3],
+ h->h_signature[4], h->h_signature[5], h->h_signature[6], h->h_signature[7]);
+ printk("h_revision: %x; ", h->h_revision);
+ printk("h_header_size: %u; ", h->h_header_size);
+ printk("h_header_crc: %x; ", h->h_header_crc);
+ printk("h_reserved: %u; ", h->h_reserved);
+ printk("h_lba_current: %llu; ", h->h_lba_current);
+ printk("h_lba_backup: %llu; ", h->h_lba_backup);
+ printk("h_lba_usable_first: %llu; ", h->h_lba_usable_first);
+ printk("h_lba_usable_last: %llu; ", h->h_lba_usable_last);
+ printk("h_guid: "); gpt_print_guid(&h->h_guid); printk("; ");
+ printk("h_part_table_lba: %llu; ", h->h_part_table_lba);
+ printk("h_part_table_len: %u; ", h->h_part_table_len);
+ printk("h_part_table_crc: %x]", h->h_part_table_crc);
+}
+
+static void gpt_dump_part(struct gpt_disklabel_part *p, int i)
+{
+ printk(" part#%d:[", i);
+ printk("p_type: "); gpt_print_guid(&p->p_type);
+ printk("; p_guid:"); gpt_print_guid(&p->p_guid);
+ printk("; p_lba_first: %llu", p->p_lba_first);
+ printk("; p_lba_last: %llu", p->p_lba_last);
+ printk("; p_attrs: %llx", p->p_attrs);
+ printk("; p_name: \""); gpt_print_part_name(p); printk("\"]");
+}
+#else
+static void gpt_dump_header(struct gpt_disklabel_header *h) {}
+static void gpt_dump_part(struct gpt_disklabel_part *p, int i) {}
+#endif
+
+static int gpt_partition(struct gendisk *hd, kdev_t dev, __u64 first_sector, int minor)
+{
+ struct buffer_head *bh;
+ struct gpt_disklabel_header *h;
+ void *pp = NULL; vm_size_t pp_s = 0;
+ int res, bsize = 512;
+ /* Note: this must be set by the driver; SCSI does --
+ * only, in practice, it always sets this to 512, see sd_init() in sd.c */
+ if (hardsect_size[MAJOR(dev)] && hardsect_size[MAJOR(dev)][MINOR(dev)])
+ bsize = hardsect_size[MAJOR(dev)][MINOR(dev)];
+ set_blocksize(dev,bsize); /* Must override read block size since GPT has pointers, stolen from amiga_partition(). */
+ if (!(bh = bread(dev, first_sector + 1, bsize))) {
+ printk("unable to read GPT");
+ res = -1;
+ goto done;
+ }
+
+ h = (struct gpt_disklabel_header *)bh->b_data;
+ gpt_dump_header(h);
+
+ res = gpt_verify_header(&pp, &pp_s, dev, bsize, first_sector, 1, h);
+ if (res < 0)
+ goto done;
+ else if (res > 0) {
+ printk(" main GPT dirty, trying backup at %llu;", h->h_lba_backup);
+ __u64 lba = h->h_lba_backup;
+ brelse(bh);
+
+ if (!(bh = bread(dev, first_sector + lba, bsize))) {
+ printk("unable to read backup GPT");
+ res = -4;
+ goto done;
+ }
+
+ h = (struct gpt_disklabel_header *)bh->b_data;
+ gpt_dump_header(h);
+
+ res = gpt_verify_header(&pp, &pp_s, dev, bsize, first_sector, lba, h);
+ if (res < 0)
+ goto done;
+ else if (res > 0) {
+ printk(" backup GPT dirty as well; cowardly refusing to continue");
+ res = -5;
+ goto done;
+ }
+ }
+
+ /* At least one good GPT+array */
+
+ for(int i = 0; i < h->h_part_table_len; ++i, ++minor) {
+ struct gpt_disklabel_part *p =
+ (struct gpt_disklabel_part *) (pp + i * h->h_part_table_entry_size);
+ if(memcmp(&p->p_type, &GPT_GUID_TYPE_UNUSED, sizeof(struct gpt_guid)) == 0)
+ continue;
+ gpt_dump_part(p, i);
+
+ if (minor > hd->max_nr * hd->max_p) {
+ printk(" [ignoring GPT partition %d \"", i); gpt_print_part_name(p); printk("\": too many partitions (max %d)]", hd->max_p);
+ } else {
+ add_partition(hd, minor, first_sector + p->p_lba_first, p->p_lba_last - p->p_lba_first + 1);
+ if(p->p_name[0]) {
+ printk(" ("); gpt_print_part_name(p); printk(")");
+ }
+ }
+ }
+
+done:
+ brelse(bh);
+ set_blocksize(dev,BLOCK_SIZE);
+ kfree((vm_offset_t)pp, pp_s);
+ printk("\n");
+ return !res;
+}
+#endif
+
static int msdos_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector)
{
int i, minor = current_minor;
@@ -381,6 +626,12 @@ check_table:
for (i=1 ; i<=4 ; minor++,i++,p++) {
if (!NR_SECTS(p))
continue;
+#ifdef CONFIG_GPT_DISKLABEL
+ if (SYS_IND(p) == GPT_PARTITION) {
+ brelse(bh);
+ return gpt_partition(hd, dev, first_sector, minor);
+ } else
+#endif
add_partition(hd, minor, first_sector+START_SECT(p), NR_SECTS(p));
if (is_extended_partition(p)) {
printk(" <");
diff --git a/linux/dev/glue/kmem.c b/linux/dev/glue/kmem.c
index 8e0b5425..509229d1 100644
--- a/linux/dev/glue/kmem.c
+++ b/linux/dev/glue/kmem.c
@@ -574,8 +574,10 @@ vremap (unsigned long offset, unsigned long size)
{
vm_offset_t addr;
kern_return_t ret;
+
+ assert(page_aligned(offset));
- ret = kmem_alloc_wired (kernel_map, &addr, round_page (size));
+ ret = kmem_valloc (kernel_map, &addr, round_page (size));
if (ret != KERN_SUCCESS)
return NULL;
diff --git a/linux/dev/include/linux/genhd.h b/linux/dev/include/linux/genhd.h
index 20a6c978..f19015d4 100644
--- a/linux/dev/include/linux/genhd.h
+++ b/linux/dev/include/linux/genhd.h
@@ -128,6 +128,73 @@ struct bsd_disklabel {
#endif /* CONFIG_BSD_DISKLABEL */
+#ifdef CONFIG_GPT_DISKLABEL
+/*
+ * GPT disklabel support by наб <nabijaczleweli@gmail.com>
+ *
+ * Based on UEFI specification 2.8A (current as of May 2020):
+ * https://uefi.org/specifications
+ * https://uefi.org/sites/default/files/resources/UEFI_Spec_2_8_A_Feb14.pdf
+ *
+ * CRC32 behaviour (final ^ ~0) courtesy of util-linux documentation:
+ * https://git.kernel.org/pub/scm/utils/util-linux/util-linux.git/tree/libblkid/src/partitions/gpt.c?id=042f62dfc514da177c148c257e4dcb32e5f8379d#n104
+ */
+
+#define GPT_PARTITION 0xee /* Partition ID in MBR */
+
+#define GPT_GUID_SIZE 16
+struct gpt_guid {
+ __u32 g_time_low; /* Low field of timestamp */
+ __u16 g_time_mid; /* Medium field of timestamp */
+ __u16 g_time_high_version; /* High field of timestamp and version */
+ __u8 g_clock_sec_high; /* High field of clock sequence and variant */
+ __u8 g_clock_sec_low; /* Low field of clock sequence */
+ __u8 g_node_id[6]; /* Spatially unique node identifier (MAC address or urandom) */
+} __attribute((packed));
+typedef char __gpt_guid_right_size[(sizeof(struct gpt_guid) == GPT_GUID_SIZE) ? 1 : -1];
+
+static const struct gpt_guid GPT_GUID_TYPE_UNUSED = {0,0,0,0,0,{0,0,0,0,0,0}};
+
+#define GPT_SIGNATURE "EFI PART" /* The header signauture */
+#define GPT_REVISION (0x00010000UL) /* Little-endian on disk */
+#define GPT_HEADER_SIZE 92
+#define GPT_MAXPARTITIONS 128
+struct gpt_disklabel_header {
+ char h_signature[8]; /* Must match GPT_SIGNATURE */
+ __u32 h_revision; /* Disklabel revision, must match GPT_REVISION */
+ __u32 h_header_size; /* Must match GPT_HEADER_SIZE */
+ __u32 h_header_crc; /* CRC32 of header, zero for calculation */
+ __u32 h_reserved; /* Must be zero */
+ __u64 h_lba_current; /* LBA of this copy of the header */
+ __u64 h_lba_backup; /* LBA of the second (backup) copy of the header */
+ __u64 h_lba_usable_first; /* First usable LBA for partitions (last LBA of primary table + 1) */
+ __u64 h_lba_usable_last; /* Last usable LBA for partitions (first LBA of secondary table - 1) */
+ struct gpt_guid h_guid; /* ID of the disk */
+ __u64 h_part_table_lba; /* First LBA of the partition table (usually 2 in primary header) */
+ __u32 h_part_table_len; /* Amount of entries in the partition table */
+ __u32 h_part_table_entry_size; /* Size of each partition entry (usually 128) */
+ __u32 h_part_table_crc; /* CRC32 of entire partition table, starts at h_part_table_lba, is h_part_table_len*h_part_table_entry_size long */
+ /* Rest of block must be zero */
+} __attribute((packed));
+typedef char __gpt_header_right_size[(sizeof(struct gpt_disklabel_header) == GPT_HEADER_SIZE) ? 1 : -1];
+
+/* 3-47: reserved; 48-63: defined for individual partition types. */
+#define GPT_PARTITION_ATTR_PLATFORM_REQUIRED (1ULL << 0) /* Required by the platform to function */
+#define GPT_PARTITION_ATTR_EFI_IGNORE (1ULL << 1) /* To be ignored by the EFI firmware */
+#define GPT_PARTITION_ATTR_BIOS_BOOTABLE (1ULL << 2) /* Equivalent to MBR active flag */
+
+#define GPT_PARTITION_ENTRY_SIZE 128 /* Minimum size, implementations must respect bigger vendor-specific entries */
+struct gpt_disklabel_part {
+ struct gpt_guid p_type; /* Partition type GUID */
+ struct gpt_guid p_guid; /* ID of the partition */
+ __u64 p_lba_first; /* First LBA of the partition */
+ __u64 p_lba_last; /* Last LBA of the partition */
+ __u64 p_attrs; /* Partition attribute bitfield, see above */
+ __u16 p_name[36]; /* Display name of partition, UTF-16 */
+} __attribute((packed));
+typedef char __gpt_part_entry_right_size[(sizeof(struct gpt_disklabel_part) == GPT_PARTITION_ENTRY_SIZE) ? 1 : -1];
+#endif /* CONFIG_GPT_DISKLABEL */
+
extern struct gendisk *gendisk_head; /* linked list of disks */
/*
diff --git a/linux/pcmcia-cs/modules/pci_fixup.c b/linux/pcmcia-cs/modules/pci_fixup.c
index 3b5551ad..6cbcd03e 100644
--- a/linux/pcmcia-cs/modules/pci_fixup.c
+++ b/linux/pcmcia-cs/modules/pci_fixup.c
@@ -51,7 +51,6 @@ u32 pci_irq_mask = 0;
#ifndef MACH
/* Already defined in drivers/pci/pci.c. */
struct pci_dev *pci_devices = NULL;
-#endif
struct pci_bus pci_root = {
parent: NULL,
children: NULL,
@@ -61,6 +60,7 @@ struct pci_bus pci_root = {
number: 0
};
#endif
+#endif
#if (LINUX_VERSION_CODE < VERSION(2,1,93))
diff --git a/linux/src/drivers/scsi/in2000.h b/linux/src/drivers/scsi/in2000.h
index 52a86e06..732bab86 100644
--- a/linux/src/drivers/scsi/in2000.h
+++ b/linux/src/drivers/scsi/in2000.h
@@ -406,7 +406,7 @@ int in2000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int in2000_abort(Scsi_Cmnd *);
void in2000_setup(char *, int *) in2000__INIT;
int in2000_proc_info(char *, char **, off_t, int, int, int);
-struct proc_dir_entry proc_scsi_in2000;
+extern struct proc_dir_entry proc_scsi_in2000;
int in2000_biosparam(struct scsi_disk *, kdev_t, int *);
int in2000_reset(Scsi_Cmnd *, unsigned int);
diff --git a/vm/vm_kern.c b/vm/vm_kern.c
index a84553d6..2e333ee1 100644
--- a/vm/vm_kern.c
+++ b/vm/vm_kern.c
@@ -432,17 +432,14 @@ retry:
}
/*
- * kmem_alloc_wired:
+ * kmem_valloc:
*
- * Allocate wired-down memory in the kernel's address map
- * or a submap. The memory is not zero-filled.
- *
- * The memory is allocated in the kernel_object.
- * It may not be copied with vm_map_copy.
+ * Allocate addressing space in the kernel's address map
+ * or a submap. The adressing space does not map anything.
*/
kern_return_t
-kmem_alloc_wired(
+kmem_valloc(
vm_map_t map,
vm_offset_t *addrp,
vm_size_t size)
@@ -476,7 +473,7 @@ retry:
goto retry;
}
- printf_once("no more room for kmem_alloc_wired in %p (%s)\n",
+ printf_once("no more room for kmem_valloc in %p (%s)\n",
map, map->name);
return kr;
}
@@ -504,6 +501,39 @@ retry:
vm_map_unlock(map);
/*
+ * Return the memory, not mapped.
+ */
+ *addrp = addr;
+ return KERN_SUCCESS;
+}
+
+/*
+ * kmem_alloc_wired:
+ *
+ * Allocate wired-down memory in the kernel's address map
+ * or a submap. The memory is not zero-filled.
+ *
+ * The memory is allocated in the kernel_object.
+ * It may not be copied with vm_map_copy.
+ */
+
+kern_return_t
+kmem_alloc_wired(
+ vm_map_t map,
+ vm_offset_t *addrp,
+ vm_size_t size)
+{
+ vm_offset_t offset;
+ vm_offset_t addr;
+ kern_return_t kr;
+
+ kr = kmem_valloc(map, &addr, size);
+ if (kr != KERN_SUCCESS)
+ return kr;
+
+ offset = addr - VM_MIN_KERNEL_ADDRESS;
+
+ /*
* Allocate wired-down memory in the kernel_object,
* for this entry, and enter it in the kernel pmap.
*/
diff --git a/vm/vm_kern.h b/vm/vm_kern.h
index 4bd89c49..0cdb19db 100644
--- a/vm/vm_kern.h
+++ b/vm/vm_kern.h
@@ -52,6 +52,7 @@ extern void kmem_init(vm_offset_t, vm_offset_t);
extern kern_return_t kmem_alloc(vm_map_t, vm_offset_t *, vm_size_t);
extern kern_return_t kmem_alloc_pageable(vm_map_t, vm_offset_t *,
vm_size_t);
+extern kern_return_t kmem_valloc(vm_map_t, vm_offset_t *, vm_size_t);
extern kern_return_t kmem_alloc_wired(vm_map_t, vm_offset_t *, vm_size_t);
extern kern_return_t kmem_alloc_aligned(vm_map_t, vm_offset_t *, vm_size_t);
extern void kmem_free(vm_map_t, vm_offset_t, vm_size_t);
diff --git a/vm/vm_object.c b/vm/vm_object.c
index a68e5209..bbc1d6e2 100644
--- a/vm/vm_object.c
+++ b/vm/vm_object.c
@@ -1368,6 +1368,7 @@ kern_return_t vm_object_copy_call(
*/
new_object = vm_object_enter(new_memory_object, size, FALSE);
+ assert(new_object);
new_object->shadow = src_object;
new_object->shadow_offset = src_offset;
diff --git a/vm/vm_user.c b/vm/vm_user.c
index 1789dbfa..4d5728c8 100644
--- a/vm/vm_user.c
+++ b/vm/vm_user.c
@@ -242,7 +242,7 @@ kern_return_t vm_read(
vm_address_t address,
vm_size_t size,
pointer_t *data,
- vm_size_t *data_size)
+ mach_msg_type_number_t *data_size)
{
kern_return_t error;
vm_map_copy_t ipc_address;
@@ -265,7 +265,7 @@ kern_return_t vm_write(
vm_map_t map,
vm_address_t address,
pointer_t data,
- vm_size_t size)
+ mach_msg_type_number_t size)
{
if (map == VM_MAP_NULL)
return KERN_INVALID_ARGUMENT;
@@ -345,14 +345,16 @@ kern_return_t vm_map(
object = VM_OBJECT_NULL;
offset = 0;
copy = FALSE;
- } else if ((object = vm_object_enter(memory_object, size, FALSE))
- == VM_OBJECT_NULL)
+ } else if ((object = vm_object_lookup_name (memory_object)) == VM_OBJECT_NULL &&
+ (object = vm_object_enter(memory_object, size, FALSE)) == VM_OBJECT_NULL)
{
ipc_port_t real_memobj;
vm_prot_t prot;
+
result = memory_object_proxy_lookup (memory_object, &real_memobj,
&prot);
if (result != KERN_SUCCESS)
+ /* Really no luck */
return result;
/* Reduce the allowed access to the memory object. */
@@ -532,17 +534,28 @@ kern_return_t vm_msync(
return vm_map_msync(map, (vm_offset_t) address, size, sync_flags);
}
-kern_return_t vm_allocate_contiguous(host_priv, map, result_vaddr, result_paddr, size)
- host_t host_priv;
- vm_map_t map;
- vm_address_t *result_vaddr;
- vm_address_t *result_paddr;
- vm_size_t size;
+/*
+ * vm_allocate_contiguous allocates "zero fill" physical memory and maps
+ * it into in the specfied map.
+ */
+/* TODO: respect physical alignment (palign)
+ * and minimum physical address (pmin)
+ */
+kern_return_t vm_allocate_contiguous(
+ host_t host_priv,
+ vm_map_t map,
+ vm_address_t *result_vaddr,
+ rpc_phys_addr_t *result_paddr,
+ vm_size_t size,
+ rpc_phys_addr_t pmin,
+ rpc_phys_addr_t pmax,
+ rpc_phys_addr_t palign)
{
vm_size_t alloc_size;
unsigned int npages;
unsigned int i;
unsigned int order;
+ unsigned int selector;
vm_page_t pages;
vm_object_t object;
kern_return_t kr;
@@ -554,6 +567,27 @@ kern_return_t vm_allocate_contiguous(host_priv, map, result_vaddr, result_paddr,
if (map == VM_MAP_NULL)
return KERN_INVALID_TASK;
+ /* FIXME */
+ if (pmin != 0)
+ return KERN_INVALID_ARGUMENT;
+
+ if (palign == 0)
+ palign = PAGE_SIZE;
+
+ /* FIXME */
+ if (palign != PAGE_SIZE)
+ return KERN_INVALID_ARGUMENT;
+
+ selector = VM_PAGE_SEL_DMA;
+ if (pmax > VM_PAGE_DMA_LIMIT)
+#ifdef VM_PAGE_DMA32_LIMIT
+ selector = VM_PAGE_SEL_DMA32;
+ if (pmax > VM_PAGE_DMA32_LIMIT)
+#endif
+ selector = VM_PAGE_SEL_DIRECTMAP;
+ if (pmax > VM_PAGE_DIRECTMAP_LIMIT)
+ selector = VM_PAGE_SEL_HIGHMEM;
+
size = vm_page_round(size);
if (size == 0)
@@ -573,7 +607,7 @@ kern_return_t vm_allocate_contiguous(host_priv, map, result_vaddr, result_paddr,
alloc_size = (1 << (order + PAGE_SHIFT));
npages = vm_page_atop(alloc_size);
- pages = vm_page_grab_contig(alloc_size, VM_PAGE_SEL_DIRECTMAP);
+ pages = vm_page_grab_contig(alloc_size, selector);
if (pages == NULL) {
vm_object_deallocate(object);
diff --git a/x86_64/Makefrag.am b/x86_64/Makefrag.am
new file mode 100644
index 00000000..89d3302b
--- /dev/null
+++ b/x86_64/Makefrag.am
@@ -0,0 +1,277 @@
+# Makefile fragment for x86_64.
+
+# Copyright (C) 1997, 1999, 2006, 2007 Free Software Foundation, Inc.
+
+# Permission to use, copy, modify and distribute this software and its
+# documentation is hereby granted, provided that both the copyright
+# notice and this permission notice appear in all copies of the
+# software, derivative works or modified versions, and any portions
+# thereof, and that both notices appear in supporting documentation.
+#
+# THE FREE SOFTWARE FOUNDATION ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+# "AS IS" CONDITION. THE FREE SOFTWARE FOUNDATION DISCLAIMS ANY
+# LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE
+# USE OF THIS SOFTWARE.
+
+#
+# Source files for any x86_64 kernel.
+#
+
+libkernel_a_SOURCES += \
+ i386/i386at/autoconf.c \
+ i386/i386at/autoconf.h \
+ i386/i386at/biosmem.c \
+ i386/i386at/biosmem.h \
+ i386/i386at/conf.c \
+ i386/i386at/cons_conf.c \
+ i386/i386at/elf.h \
+ i386/i386at/idt.h \
+ i386/i386at/model_dep.c \
+ i386/i386at/model_dep.h \
+ i386/include/mach/sa/stdarg.h
+
+if PLATFORM_at
+libkernel_a_SOURCES += \
+ x86_64/boothdr.S \
+ i386/i386at/com.c \
+ i386/i386at/com.h \
+ i386/i386at/comreg.h \
+ i386/i386at/cram.h \
+ i386/i386at/disk.h \
+ i386/i386at/i8250.h \
+ i386/i386at/immc.c \
+ i386/i386at/int_init.c \
+ i386/i386at/int_init.h \
+ x86_64/interrupt.S \
+ i386/i386at/kd.c \
+ i386/i386at/kd.h \
+ i386/i386at/kd_event.c \
+ i386/i386at/kd_event.h \
+ i386/i386at/kd_queue.c \
+ i386/i386at/kd_queue.h \
+ i386/i386at/kd_mouse.c \
+ i386/i386at/kd_mouse.h \
+ x86_64/kdasm.S \
+ i386/i386at/kdsoft.h \
+ i386/i386at/mem.c \
+ i386/i386at/mem.h \
+ i386/i386at/pic_isa.c \
+ i386/i386at/rtc.c \
+ i386/i386at/rtc.h
+endif
+
+#
+# `lpr' device support.
+#
+
+if enable_lpr
+libkernel_a_SOURCES += \
+ i386/i386at/lpr.c \
+ i386/i386at/lpr.h
+endif
+
+
+#
+# Further source files for any x86_64 kernel.
+#
+
+libkernel_a_SOURCES += \
+ i386/i386/ast.h \
+ i386/i386/ast_check.c \
+ i386/i386/ast_types.h \
+ i386/i386/cpu.h \
+ i386/i386/cpu_number.h \
+ x86_64/cswitch.S \
+ i386/i386/db_disasm.c \
+ i386/i386/db_interface.c \
+ i386/i386/db_interface.h \
+ i386/i386/db_machdep.h \
+ i386/i386/db_trace.c \
+ i386/i386/db_trace.h \
+ i386/i386/debug.h \
+ i386/i386/debug_i386.c \
+ x86_64/debug_trace.S \
+ i386/i386/eflags.h \
+ i386/i386/fpu.c \
+ i386/i386/fpu.h \
+ i386/i386/gdt.c \
+ i386/i386/gdt.h \
+ i386/i386/idt-gen.h \
+ i386/i386/idt.c \
+ x86_64/idt_inittab.S \
+ i386/i386/io_perm.c \
+ i386/i386/io_perm.h \
+ i386/i386/ipl.h \
+ i386/i386/ktss.c \
+ i386/i386/ktss.h \
+ i386/i386/kttd_interface.c \
+ i386/i386/kttd_machdep.h \
+ i386/i386/ldt.c \
+ i386/i386/ldt.h \
+ i386/i386/lock.h \
+ x86_64/locore.S \
+ i386/i386/locore.h \
+ i386/i386/loose_ends.c \
+ i386/i386/loose_ends.h \
+ i386/i386/mach_param.h \
+ i386/i386/machine_routines.h \
+ i386/i386/machine_task.c \
+ i386/i386/machspl.h \
+ i386/i386/model_dep.h \
+ i386/i386/mp_desc.c \
+ i386/i386/mp_desc.h \
+ i386/i386/pcb.c \
+ i386/i386/pcb.h \
+ i386/i386/phys.c \
+ i386/i386/pio.h \
+ i386/i386/pmap.h \
+ i386/i386/proc_reg.h \
+ i386/i386/sched_param.h \
+ i386/i386/seg.c \
+ i386/i386/seg.h \
+ i386/i386/setjmp.h \
+ x86_64/spl.S \
+ i386/i386/spl.h \
+ i386/i386/strings.c \
+ i386/i386/task.h \
+ i386/i386/thread.h \
+ i386/i386/time_stamp.h \
+ i386/i386/trap.c \
+ i386/i386/trap.h \
+ i386/i386/tss.h \
+ i386/i386/user_ldt.c \
+ i386/i386/user_ldt.h \
+ i386/i386/vm_param.h \
+ i386/i386/xpr.h \
+ i386/intel/pmap.c \
+ i386/intel/pmap.h \
+ i386/intel/read_fault.c \
+ i386/intel/read_fault.h
+EXTRA_DIST += \
+ i386/i386/mach_i386.srv
+
+if PLATFORM_at
+libkernel_a_SOURCES += \
+ i386/i386/hardclock.c \
+ i386/i386/hardclock.h \
+ i386/i386/io_map.c \
+ i386/i386/pic.c \
+ i386/i386/pic.h \
+ i386/i386/pit.c \
+ i386/i386/pit.h
+endif
+
+#
+# KDB support.
+#
+
+if enable_kdb
+libkernel_a_SOURCES += \
+ x86_64/_setjmp.S
+endif
+
+
+#
+# Files from the generic sources that we want.
+#
+
+libkernel_a_SOURCES += \
+ chips/busses.c \
+ chips/busses.h \
+ device/cirbuf.c
+
+#
+# Automatically generated source files.
+#
+# See Makerules.mig.am.
+#
+
+nodist_lib_dep_tr_for_defs_a_SOURCES += \
+ i386/i386/mach_i386.server.defs.c
+nodist_libkernel_a_SOURCES += \
+ i386/i386/mach_i386.server.h \
+ i386/i386/mach_i386.server.c \
+ i386/i386/mach_i386.server.msgids
+# i386/i386/mach_i386.server.defs
+
+EXTRA_DIST += \
+ i386/i386/i386asm.sym
+nodist_libkernel_a_SOURCES += \
+ i386/i386/i386asm.h
+
+#
+# Architecture specialities.
+#
+
+EXTRA_DIST += \
+ x86_64/ldscript
+if PLATFORM_at
+gnumach_LINKFLAGS += \
+ --defsym _START_MAP=$(_START_MAP) \
+ --defsym _START=_START_MAP+0x40000000 \
+ -T '$(srcdir)'/x86_64/ldscript
+endif
+
+AM_CPPFLAGS += \
+ -I$(top_srcdir)/i386 \
+ -I$(top_srcdir)/i386/i386 \
+ -I$(top_srcdir)/i386/include/mach/sa
+
+AM_CFLAGS += \
+ -mno-red-zone \
+ -mcmodel=kernel \
+ -mno-3dnow \
+ -mno-mmx \
+ -mno-sse \
+ -mno-sse2
+
+#
+# Installation.
+#
+
+include_mach_i386dir = $(includedir)/mach/i386
+include_mach_i386_HEADERS = \
+ i386/include/mach/i386/asm.h \
+ i386/include/mach/i386/boolean.h \
+ i386/include/mach/i386/eflags.h \
+ i386/include/mach/i386/exception.h \
+ i386/include/mach/i386/fp_reg.h \
+ i386/include/mach/i386/ioccom.h \
+ i386/include/mach/i386/kern_return.h \
+ i386/include/mach/i386/mach_i386.defs \
+ i386/include/mach/i386/mach_i386_types.h \
+ i386/include/mach/i386/machine_types.defs \
+ i386/include/mach/i386/multiboot.h \
+ i386/include/mach/i386/syscall_sw.h \
+ i386/include/mach/i386/thread_status.h \
+ i386/include/mach/i386/trap.h \
+ i386/include/mach/i386/vm_param.h \
+ i386/include/mach/i386/vm_types.h
+
+#
+# Building a distribution.
+#
+
+EXTRA_DIST += \
+ i386/README-Drivers
+
+# Instead of listing each file individually...
+EXTRA_DIST += \
+ i386/include
+
+#
+# Platform specific parts.
+#
+
+if PLATFORM_xen
+libkernel_a_SOURCES += \
+ x86_64/xen_locore.S \
+ x86_64/xen_boothdr.S \
+ i386/xen/xen.c \
+ i386/i386/xen.h
+
+gnumach_LINKFLAGS += \
+ --defsym _START=0x40000000 \
+ --defsym _START_MAP=0x40000000 \
+ -T '$(srcdir)'/x86_64/ldscript
+endif
diff --git a/x86_64/_setjmp.S b/x86_64/_setjmp.S
new file mode 100644
index 00000000..5714f435
--- /dev/null
+++ b/x86_64/_setjmp.S
@@ -0,0 +1,65 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * C library -- _setjmp, _longjmp
+ *
+ * _longjmp(a,v)
+ * will generate a "return(v)" from
+ * the last call to
+ * _setjmp(a)
+ * by restoring registers from the stack,
+ * The previous signal state is NOT restored.
+ *
+ */
+
+#include <mach/machine/asm.h>
+
+ENTRY(_setjmp)
+ movq %rbx,0(%rdi)
+ movq %rbp,8(%rdi) /* save frame pointer of caller */
+ movq %r12,16(%rdi)
+ movq %r13,24(%rdi)
+ movq %r14,32(%rdi)
+ movq %r15,40(%rdi)
+ popq %rdx
+ movq %rsp,48(%rdi) /* save stack pointer of caller */
+ movq %rdx,56(%rdi) /* save pc of caller */
+ xorq %rax,%rax
+ jmp *%rdx
+
+ENTRY(_longjmp)
+ movq %rsi,%rax /* return(v) */
+ movq 0(%rdi),%rbx
+ movq 8(%rdi),%rbp
+ movq 16(%rdi),%r12
+ movq 24(%rdi),%r13
+ movq 32(%rdi),%r14
+ movq 40(%rdi),%r15
+ movq 48(%rdi),%rsp
+ orq %rax,%rax
+ jnz 0f
+ incq %rax
+0: jmp *56(%rdi) /* done, return.... */
diff --git a/x86_64/configfrag.ac b/x86_64/configfrag.ac
new file mode 100644
index 00000000..817eff3d
--- /dev/null
+++ b/x86_64/configfrag.ac
@@ -0,0 +1,58 @@
+dnl Configure fragment for x86_64.
+
+dnl Copyright (C) 1999, 2004, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+dnl Permission to use, copy, modify and distribute this software and its
+dnl documentation is hereby granted, provided that both the copyright
+dnl notice and this permission notice appear in all copies of the
+dnl software, derivative works or modified versions, and any portions
+dnl thereof, and that both notices appear in supporting documentation.
+dnl
+dnl THE FREE SOFTWARE FOUNDATION ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+dnl "AS IS" CONDITION. THE FREE SOFTWARE FOUNDATION DISCLAIMS ANY
+dnl LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE
+dnl USE OF THIS SOFTWARE.
+
+#
+# Definitions.
+#
+
+[case $host_cpu in
+ x86_64)]
+ AM_CONDITIONAL([HOST_x86_64], [true])
+
+ # Some of the x86_64-specific code checks for these.
+ AC_DEFINE([__ELF__], [1], [__ELF__])
+
+ # Determines the size of the CPU cache line.
+ AC_DEFINE([CPU_L1_SHIFT], [6], [CPU_L1_SHIFT])
+
+ [# Does the architecture provide machine-specific interfaces?
+ mach_machine_routines=1
+
+ enable_pae=yes;;
+ *)]
+ AM_CONDITIONAL([HOST_x86_64], [false])[;;
+esac
+
+case $host_platform in
+ at)]
+ AM_CONDITIONAL([PLATFORM_at], [true])[;;
+ *)]
+ AM_CONDITIONAL([PLATFORM_at], [false])[;;
+esac]
+
+[case $host_platform:$host_cpu in
+ at:x86_64)]
+ ncom=4
+ nlpr=1
+ AC_DEFINE([ATX86_64], [1], [ATX86_64])[;;
+ xen:x86_64)]
+ AC_DEFINE([ATX86_64], [1], [ATX86_64])[;;
+ *)
+ :;;
+esac]
+
+dnl Local Variables:
+dnl mode: autoconf
+dnl End:
diff --git a/x86_64/cswitch.S b/x86_64/cswitch.S
new file mode 100644
index 00000000..1a7471c3
--- /dev/null
+++ b/x86_64/cswitch.S
@@ -0,0 +1,150 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include <mach/machine/asm.h>
+
+#include <i386/i386/proc_reg.h>
+#include <i386/i386/i386asm.h>
+#include <i386/i386/cpu_number.h>
+
+/*
+ * Context switch routines for x86_64.
+ */
+
+ENTRY(Load_context)
+ movq S_ARG0,%rcx /* get thread */
+ movq TH_KERNEL_STACK(%rcx),%rcx /* get kernel stack */
+ lea KERNEL_STACK_SIZE-IKS_SIZE-IEL_SIZE(%rcx),%rdx
+ /* point to stack top */
+ CPU_NUMBER(%eax)
+ movq %rcx,CX(EXT(active_stacks),%eax) /* store stack address */
+ movq %rdx,CX(EXT(kernel_stack),%eax) /* store stack top */
+
+/* XXX complete */
+
+ movq KSS_ESP(%rcx),%rsp /* switch stacks */
+ movq KSS_EBP(%rcx),%rbp /* restore registers */
+ movq KSS_EBX(%rcx),%rbx
+ movq KSS_R12(%rcx),%r12
+ movq KSS_R13(%rcx),%r13
+ movq KSS_R14(%rcx),%r14
+ movq KSS_R15(%rcx),%r15
+ xorq %rax,%rax /* return zero (no old thread) */
+ jmp *KSS_EIP(%rcx) /* resume thread */
+
+/*
+ * This really only has to save registers
+ * when there is no explicit continuation.
+ */
+
+ENTRY(Switch_context)
+ CPU_NUMBER(%eax)
+ movq CX(EXT(active_stacks),%eax),%rcx /* get old kernel stack */
+
+ movq %r12,KSS_R12(%rcx) /* save registers */
+ movq %r13,KSS_R13(%rcx)
+ movq %r14,KSS_R14(%rcx)
+ movq %r15,KSS_R15(%rcx)
+ movq %rbx,KSS_EBX(%rcx)
+ movq %rbp,KSS_EBP(%rcx)
+ popq KSS_EIP(%rcx) /* save return PC */
+ movq %rsp,KSS_ESP(%rcx) /* save SP */
+
+ movq S_ARG0,%rax /* get old thread */
+ movq %rcx,TH_KERNEL_STACK(%rax) /* save old stack */
+ movq S_ARG1,%rbx /* get continuation */
+ movq %rbx,TH_SWAP_FUNC(%rax) /* save continuation */
+
+ movq S_ARG2,%rsi /* get new thread */
+
+ movq TH_KERNEL_STACK(%rsi),%rcx /* get its kernel stack */
+ lea KERNEL_STACK_SIZE-IKS_SIZE-IEL_SIZE(%rcx),%rbx
+ /* point to stack top */
+
+ CPU_NUMBER(%eax)
+ movq %rsi,CX(EXT(active_threads),%eax) /* new thread is active */
+ movq %rcx,CX(EXT(active_stacks),%eax) /* set current stack */
+ movq %rbx,CX(EXT(kernel_stack),%eax) /* set stack top */
+
+ movq KSS_ESP(%rcx),%rsp /* switch stacks */
+ movq KSS_EBP(%rcx),%rbp /* restore registers */
+ movq KSS_EBX(%rcx),%rbx
+ movq KSS_R12(%rcx),%r12
+ movq KSS_R13(%rcx),%r13
+ movq KSS_R14(%rcx),%r14
+ movq KSS_R15(%rcx),%r15
+ jmp *KSS_EIP(%rcx) /* return old thread */
+
+ENTRY(Thread_continue)
+ movq %rax,%rdi /* push the thread argument */
+ xorq %rbp,%rbp /* zero frame pointer */
+ call *%rbx /* call real continuation */
+
+#if NCPUS > 1
+/*
+ * void switch_to_shutdown_context(thread_t thread,
+ * void (*routine)(processor_t),
+ * processor_t processor)
+ *
+ * saves the kernel context of the thread,
+ * switches to the interrupt stack,
+ * continues the thread (with thread_continue),
+ * then runs routine on the interrupt stack.
+ *
+ * Assumes that the thread is a kernel thread (thus
+ * has no FPU state)
+ */
+ENTRY(switch_to_shutdown_context)
+ud2
+ CPU_NUMBER(%eax)
+ movq EXT(active_stacks)(,%eax,8),%rcx /* get old kernel stack */
+ movq %r12,KSS_R12(%rcx) /* save registers */
+ movq %r13,KSS_R13(%rcx)
+ movq %r14,KSS_R14(%rcx)
+ movq %r15,KSS_R15(%rcx)
+ movq %rbx,KSS_EBX(%rcx)
+ movq %rbp,KSS_EBP(%rcx)
+ popq KSS_EIP(%rcx) /* save return PC */
+ movq %rsp,KSS_ESP(%rcx) /* save SP */
+
+ movq S_ARG0,%rax /* get old thread */
+ movq %rcx,TH_KERNEL_STACK(%rax) /* save old stack */
+ movq $0,TH_SWAP_FUNC(%rax) /* clear continuation */
+ movq S_ARG1,%rbx /* get routine to run next */
+ movq S_ARG2,%rsi /* get its argument */
+
+ CPU_NUMBER(%eax)
+ movq EXT(interrupt_stack)(,%eax,8),%rcx /* point to its interrupt stack */
+ lea INTSTACK_SIZE(%rcx),%rsp /* switch to it (top) */
+
+ movq %rax,%rdi /* push thread */
+ call EXT(thread_dispatch) /* reschedule thread */
+
+ movq %rsi,%rdi /* push argument */
+ call *%rbx /* call routine to run */
+ hlt /* (should never return) */
+
+#endif /* NCPUS > 1 */
diff --git a/x86_64/debug_trace.S b/x86_64/debug_trace.S
new file mode 100644
index 00000000..7bed5ccc
--- /dev/null
+++ b/x86_64/debug_trace.S
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1994 The University of Utah and
+ * the Computer Systems Laboratory at the University of Utah (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-dist@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ * Author: Bryan Ford, University of Utah CSL
+ */
+
+#ifdef DEBUG
+
+#include <mach/machine/asm.h>
+#include <i386/xen.h>
+
+#include "debug.h"
+
+ .text
+ENTRY(_debug_trace)
+ pushf
+ cli
+ pushq %rax
+ pushq %rbx
+ .byte 0x36 /* SS: bug in gas? */
+ movl %ss:EXT(debug_trace_pos),%eax
+ movq S_ARG0,%rbx
+ movq %rbx,%ss:EXT(debug_trace_buf)(,%eax,16)
+ movl S_ARG1,%ebx
+ movl %ebx,%ss:EXT(debug_trace_buf)+8(,%eax,16)
+ incl %eax
+ andl $DEBUG_TRACE_LEN-1,%eax
+ .byte 0x36 /* SS: bug in gas? */
+ movl %eax,%ss:EXT(debug_trace_pos)
+ popq %rbx
+ popq %rax
+ popf
+ ret
+
+#endif /* DEBUG */
+
+/* XXX gas bug? need at least one symbol... */
+foo:
+
diff --git a/x86_64/idt_inittab.S b/x86_64/idt_inittab.S
new file mode 100644
index 00000000..f021b56d
--- /dev/null
+++ b/x86_64/idt_inittab.S
@@ -0,0 +1,146 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+#include <mach/machine/asm.h>
+
+#include <i386/i386/seg.h>
+#include <i386/i386/i386asm.h>
+
+#include <xen/public/arch-x86/xen-x86_64.h>
+
+/* We'll be using macros to fill in a table in data hunk 2
+ while writing trap entrypoint routines at the same time.
+ Here's the header that comes before everything else. */
+ .data 2
+ENTRY(idt_inittab)
+ .text
+
+/*
+ * Interrupt descriptor table and code vectors for it.
+ */
+#ifdef MACH_PV_DESCRIPTORS
+#define IDT_ENTRY(n,entry,type) \
+ .data 2 ;\
+ .byte n ;\
+ .byte (((type)&ACC_PL)>>5)|((((type)&(ACC_TYPE|ACC_A))==ACC_INTR_GATE)<<2) ;\
+ .word FLAT_KERNEL_CS ;\
+ .long 0 /*pad*/ ;\
+ .quad entry ;\
+ .text
+#else /* MACH_PV_DESCRIPTORS */
+#define IDT_ENTRY(n,entry,type) \
+ .data 2 ;\
+ .quad entry ;\
+ .word n ;\
+ .word type ;\
+ .long 0 /*pad*/ ;\
+ .text
+#endif /* MACH_PV_DESCRIPTORS */
+
+/*
+ * No error code. Clear error code and push trap number.
+ */
+#define EXCEPTION(n,name) \
+ IDT_ENTRY(n,EXT(name),ACC_PL_K|ACC_TRAP_GATE);\
+ENTRY(name) ;\
+ INT_FIX ;\
+ pushq $(0) ;\
+ pushq $(n) ;\
+ jmp EXT(alltraps)
+
+/*
+ * User-accessible exception. Otherwise, same as above.
+ */
+#define EXCEP_USR(n,name) \
+ IDT_ENTRY(n,EXT(name),ACC_PL_U|ACC_TRAP_GATE);\
+ENTRY(name) ;\
+ INT_FIX ;\
+ pushq $(0) ;\
+ pushq $(n) ;\
+ jmp EXT(alltraps)
+
+/*
+ * Error code has been pushed. Just push trap number.
+ */
+#define EXCEP_ERR(n,name) \
+ IDT_ENTRY(n,EXT(name),ACC_PL_K|ACC_INTR_GATE);\
+ENTRY(name) ;\
+ INT_FIX ;\
+ pushq $(n) ;\
+ jmp EXT(alltraps)
+
+/*
+ * Special interrupt code: dispatches to a unique entrypoint,
+ * not defined automatically here.
+ */
+#define EXCEP_SPC(n,name) \
+ IDT_ENTRY(n,EXT(name),ACC_PL_K|ACC_TRAP_GATE)
+
+
+EXCEPTION(0x00,t_zero_div)
+EXCEP_SPC(0x01,t_debug)
+/* skip NMI interrupt - let more specific code figure that out. */
+EXCEP_USR(0x03,t_int3)
+EXCEP_USR(0x04,t_into)
+EXCEP_USR(0x05,t_bounds)
+EXCEPTION(0x06,t_invop)
+EXCEPTION(0x07,t_nofpu)
+EXCEPTION(0x08,a_dbl_fault)
+EXCEPTION(0x09,a_fpu_over)
+EXCEPTION(0x0a,a_inv_tss)
+EXCEP_SPC(0x0b,t_segnp)
+EXCEP_ERR(0x0c,t_stack_fault)
+EXCEP_SPC(0x0d,t_gen_prot)
+EXCEP_SPC(0x0e,t_page_fault)
+#ifdef MACH_PV_DESCRIPTORS
+EXCEP_ERR(0x0f,t_trap_0f)
+#else
+EXCEPTION(0x0f,t_trap_0f)
+#endif
+EXCEPTION(0x10,t_fpu_err)
+EXCEPTION(0x11,t_trap_11)
+EXCEPTION(0x12,t_trap_12)
+EXCEPTION(0x13,t_trap_13)
+EXCEPTION(0x14,t_trap_14)
+EXCEPTION(0x15,t_trap_15)
+EXCEPTION(0x16,t_trap_16)
+EXCEPTION(0x17,t_trap_17)
+EXCEPTION(0x18,t_trap_18)
+EXCEPTION(0x19,t_trap_19)
+EXCEPTION(0x1a,t_trap_1a)
+EXCEPTION(0x1b,t_trap_1b)
+EXCEPTION(0x1c,t_trap_1c)
+EXCEPTION(0x1d,t_trap_1d)
+EXCEPTION(0x1e,t_trap_1e)
+EXCEPTION(0x1f,t_trap_1f)
+
+/* Terminator */
+ .data 2
+ .long 0
+#ifdef MACH_PV_DESCRIPTORS
+ .long 0
+ .quad 0
+#endif /* MACH_PV_DESCRIPTORS */
+
diff --git a/x86_64/include/mach/x86_64 b/x86_64/include/mach/x86_64
new file mode 120000
index 00000000..698e9fbe
--- /dev/null
+++ b/x86_64/include/mach/x86_64
@@ -0,0 +1 @@
+../../../i386/include/mach/i386 \ No newline at end of file
diff --git a/x86_64/interrupt.S b/x86_64/interrupt.S
new file mode 100644
index 00000000..e634e34b
--- /dev/null
+++ b/x86_64/interrupt.S
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1995 Shantanu Goel
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * THE AUTHOR ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. THE AUTHOR DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ */
+
+#include <mach/machine/asm.h>
+
+#include <i386/ipl.h>
+#include <i386/pic.h>
+#include <i386/i386asm.h>
+
+#define READ_ISR (OCW_TEMPLATE|READ_NEXT_RD|READ_IS_ONRD)
+
+/*
+ * Generic interrupt handler.
+ *
+ * On entry, %rax contains the irq number.
+ */
+ENTRY(interrupt)
+ pushq %rax /* save irq number */
+ call spl7 /* set ipl */
+ pushq %rax /* save previous ipl */
+ movl 8(%esp),%edx /* set irq number as 3rd arg */
+ movl %edx,%ebx /* copy irq number */
+ shll $2,%ebx /* irq * 4 */
+ movl EXT(iunit)(%ebx),%edi /* get device unit number as 1st arg */
+ movl %eax, %esi /* previous ipl as 2nd arg */
+ movq 16(%esp), %rcx /* return address as 4th arg */
+ movq 24(%esp), %r8 /* address of interrupted registers as 5th arg */
+ shll $1,%ebx /* irq * 8 */
+ call *EXT(ivect)(%ebx) /* call interrupt handler */
+ popq %rdi /* restore previous ipl */
+ call splx_cli /* restore previous ipl */
+
+ cli /* XXX no more nested interrupts */
+ popq %rcx /* restore irq number */
+
+ movl $1,%eax
+ shll %cl,%eax /* get corresponding IRQ mask */
+ orl EXT(curr_pic_mask),%eax /* add current mask */
+
+ cmpl $8,%ecx /* do we need to ack slave? */
+ jl 1f /* no, only master */
+
+ /* EOI on slave */
+ movb %ah,%al
+ outb %al,$(PIC_SLAVE_OCW) /* mask slave out */
+
+ movb $(SPECIFIC_EOI),%al /* specific EOI for this irq */
+ andb $7,%cl /* irq number for the slave */
+ orb %cl,%al /* combine them */
+ outb %al,$(PIC_SLAVE_ICW) /* ack interrupt to slave */
+
+ movb $(SPECIFIC_EOI + I_AM_SLAVE_2),%al /* specific master EOI for cascaded slave */
+ outb %al,$(PIC_MASTER_ICW) /* ack interrupt to master */
+
+ movl EXT(curr_pic_mask),%eax /* restore original mask */
+ movb %ah,%al
+ outb %al,$(PIC_SLAVE_OCW) /* unmask slave */
+ jmp 2f
+
+1:
+ /* EOI on master */
+ outb %al,$(PIC_MASTER_OCW) /* mask master out */
+
+ movb $(SPECIFIC_EOI),%al /* specific EOI for this irq */
+ orb %cl,%al /* combine with irq number */
+ outb %al,$(PIC_MASTER_ICW) /* ack interrupt to master */
+
+ movl EXT(curr_pic_mask),%eax /* restore original mask */
+ outb %al,$(PIC_MASTER_OCW) /* unmask master */
+2:
+ ret
+END(interrupt)
diff --git a/x86_64/kdasm.S b/x86_64/kdasm.S
new file mode 100644
index 00000000..e1acf399
--- /dev/null
+++ b/x86_64/kdasm.S
@@ -0,0 +1,133 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Some inline code to speed up major block copies to and from the
+ * screen buffer.
+ *
+ * Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989.
+ * All rights reserved.
+ *
+ * orc!eugene 28 Oct 1988
+ *
+ */
+/*
+ Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
+Cupertino, California.
+
+ All Rights Reserved
+
+ Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Olivetti
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+ OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/* $ Header: $ */
+
+
+#include <mach/machine/asm.h>
+
+/*
+ * Function: kd_slmwd()
+ *
+ * This function "slams" a word (char/attr) into the screen memory using
+ * a block fill operation on the 386.
+ *
+ */
+
+#define start B_ARG0
+#define count B_ARG1
+#define value %dx // B_ARG2
+
+ENTRY(kd_slmwd)
+ pushq %rbp
+ movq %rsp, %rbp
+
+ # start already in %rdi
+ movq count, %rcx
+ movw value, %ax
+ cld
+ rep
+ stosw
+
+ leave
+ ret
+#undef start
+#undef count
+#undef value
+
+/*
+ * "slam up"
+ */
+
+#define from B_ARG0
+#define to B_ARG1
+#define count %edx // B_ARG2
+ENTRY(kd_slmscu)
+ pushq %rbp
+ movq %rsp, %rbp
+
+ xchgq %rsi, %rdi
+ movl count, %ecx
+ cmpq %rdi, %rsi
+ cld
+ rep
+ movsw
+
+ leave
+ ret
+
+/*
+ * "slam down"
+ */
+ENTRY(kd_slmscd)
+ pushq %rbp
+ movq %rsp, %rbp
+
+ xchgq %rsi, %rdi
+ movl count, %ecx
+ cmpq %rdi, %rsi
+ std
+ rep
+ movsw
+ cld
+
+ leave
+ ret
+#undef from
+#undef to
+#undef count
diff --git a/x86_64/ldscript b/x86_64/ldscript
new file mode 100644
index 00000000..375e8104
--- /dev/null
+++ b/x86_64/ldscript
@@ -0,0 +1,219 @@
+/* Default linker script, for normal executables */
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
+ "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+ENTRY(_start)
+SECTIONS
+{
+ /*
+ * There are specific requirements about entry points, so we have it
+ * configurable via `_START': `.text' will begin there and `.text.start' will
+ * be first in there. See also `i386/i386at/boothdr.S' and
+ * `gnumach_LINKFLAGS' in `i386/Makefrag.am'.
+ */
+ . = _START;
+ .text :
+ AT (_START_MAP)
+ {
+ *(.text.start)
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ *(.text.unlikely .text.*_unlikely)
+ KEEP (*(.text.*personality*))
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ } =0x90909090
+ .init :
+ {
+ KEEP (*(.init))
+ } =0x90909090
+ .fini :
+ {
+ KEEP (*(.fini))
+ } =0x90909090
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+
+ /* Read-only sections, merged into text segment: */
+ PROVIDE (__executable_start = .);
+ .interp : { *(.interp) }
+ .note.gnu.build-id : { *(.note.gnu.build-id) }
+ .hash : { *(.hash) }
+ .gnu.hash : { *(.gnu.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .rela.init : { *(.rela.init) }
+ .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
+ .rela.fini : { *(.rela.fini) }
+ .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
+ .rela.data.rel.ro : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) }
+ .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
+ .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
+ .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
+ .rela.ctors : { *(.rela.ctors) }
+ .rela.dtors : { *(.rela.dtors) }
+ .rela.got : { *(.rela.got) }
+ .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
+ .rela.ldata : { *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) }
+ .rela.lbss : { *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) }
+ .rela.lrodata : { *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) }
+ .rela.ifunc : { *(.rela.ifunc) }
+ .rela.plt :
+ {
+ *(.rela.plt)
+ PROVIDE_HIDDEN (__rela_iplt_start = .);
+ *(.rela.iplt)
+ PROVIDE_HIDDEN (__rela_iplt_end = .);
+ }
+ .plt : { *(.plt) *(.iplt) }
+ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+ .rodata1 : { *(.rodata1) }
+ .eh_frame_hdr : { *(.eh_frame_hdr) }
+ .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
+ .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table
+ .gcc_except_table.*) }
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. */
+ . = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
+ /* Exception handling */
+ .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }
+ .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+ /* Thread Local Storage sections */
+ .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+ .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+ .preinit_array :
+ {
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ }
+ .init_array :
+ {
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ }
+ .fini_array :
+ {
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(SORT(.fini_array.*)))
+ KEEP (*(.fini_array))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ }
+ .ctors :
+ {
+ /* gcc uses crtbegin.o to find the start of
+ the constructors, so we make sure it is
+ first. Because this is a wildcard, it
+ doesn't matter if the user does not
+ actually link against crtbegin.o; the
+ linker won't look for a file to match a
+ wildcard. The wildcard also means that it
+ doesn't matter which directory crtbegin.o
+ is in. */
+ KEEP (*crtbegin.o(.ctors))
+ KEEP (*crtbegin?.o(.ctors))
+ /* We don't want to include the .ctor section from
+ the crtend.o file until after the sorted ctors.
+ The .ctor section from the crtend file contains the
+ end of ctors marker and it must be last */
+ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ }
+ .dtors :
+ {
+ KEEP (*crtbegin.o(.dtors))
+ KEEP (*crtbegin?.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ }
+ .jcr : { KEEP (*(.jcr)) }
+ .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
+ .dynamic : { *(.dynamic) }
+ .got : { *(.got) *(.igot) }
+ . = DATA_SEGMENT_RELRO_END (24, .);
+ .got.plt : { *(.got.plt) *(.igot.plt) }
+ .data :
+ {
+ *(.data .data.* .gnu.linkonce.d.*)
+ SORT(CONSTRUCTORS)
+ }
+ .data1 : { *(.data1) }
+ _edata = .; PROVIDE (edata = .);
+ __bss_start = .;
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections.
+ FIXME: Why do we need it? When there is no .bss section, we don't
+ pad the .data section. */
+ . = ALIGN(. != 0 ? 64 / 8 : 1);
+ }
+ .lbss :
+ {
+ *(.dynlbss)
+ *(.lbss .lbss.* .gnu.linkonce.lb.*)
+ *(LARGE_COMMON)
+ }
+ . = ALIGN(64 / 8);
+ .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
+ {
+ *(.lrodata .lrodata.* .gnu.linkonce.lr.*)
+ }
+ .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
+ {
+ *(.ldata .ldata.* .gnu.linkonce.l.*)
+ . = ALIGN(. != 0 ? 64 / 8 : 1);
+ }
+ . = ALIGN(64 / 8);
+ _end = .; PROVIDE (end = .);
+ . = DATA_SEGMENT_END (.);
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ /* DWARF 3 */
+ .debug_pubtypes 0 : { *(.debug_pubtypes) }
+ .debug_ranges 0 : { *(.debug_ranges) }
+ .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
+ /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
+}
diff --git a/x86_64/locore.S b/x86_64/locore.S
new file mode 100644
index 00000000..fd3617c5
--- /dev/null
+++ b/x86_64/locore.S
@@ -0,0 +1,1458 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
+ * Copyright (c) 1991 IBM Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation,
+ * and that the nema IBM not be used in advertising or publicity
+ * pertaining to distribution of the software without specific, written
+ * prior permission.
+ *
+ * CARNEGIE MELLON AND IBM ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND IBM DISCLAIM ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include <mach/machine/asm.h>
+#include <mach/machine/eflags.h>
+#include <i386/i386/proc_reg.h>
+#include <i386/i386/trap.h>
+#include <i386/i386/seg.h>
+#include <i386/i386/ldt.h>
+#include <i386/i386/i386asm.h>
+#include <i386/i386/cpu_number.h>
+#include <i386/i386/xen.h>
+
+#define pusha pushq %rax ; pushq %rcx ; pushq %rdx ; pushq %rbx ; subq $8,%rsp ; pushq %rbp ; pushq %rsi ; pushq %rdi ; pushq %r8 ; pushq %r9 ; pushq %r10 ; pushq %r11 ; pushq %r12 ; pushq %r13 ; pushq %r14 ; pushq %r15
+#define popa popq %r15 ; popq %r14 ; popq %r13 ; popq %r12 ; popq %r11 ; popq %r10 ; popq %r9 ; popq %r8 ; popq %rdi ; popq %rsi ; popq %rbp ; addq $8,%rsp ; popq %rbx ; popq %rdx ; popq %rcx ; popq %rax
+
+/*
+ * Fault recovery.
+ */
+#define RECOVER_TABLE_START \
+ .text 2 ;\
+DATA(recover_table) ;\
+ .text
+
+#define RECOVER(addr) \
+ .text 2 ;\
+ .quad 9f ;\
+ .quad addr ;\
+ .text ;\
+9:
+
+#define RECOVER_TABLE_END \
+ .text 2 ;\
+ .globl EXT(recover_table_end) ;\
+LEXT(recover_table_end) ;\
+ .text
+
+/*
+ * Retry table for certain successful faults.
+ */
+#define RETRY_TABLE_START \
+ .text 3 ;\
+DATA(retry_table) ;\
+ .text
+
+#define RETRY(addr) \
+ .text 3 ;\
+ .quad 9f ;\
+ .quad addr ;\
+ .text ;\
+9:
+
+#define RETRY_TABLE_END \
+ .text 3 ;\
+ .globl EXT(retry_table_end) ;\
+LEXT(retry_table_end) ;\
+ .text
+
+/*
+ * Allocate recovery and retry tables.
+ */
+ RECOVER_TABLE_START
+ RETRY_TABLE_START
+
+/*
+ * Timing routines.
+ */
+#if STAT_TIME
+
+#define TIME_TRAP_UENTRY
+#define TIME_TRAP_SENTRY
+#define TIME_TRAP_UEXIT
+#define TIME_INT_ENTRY
+#define TIME_INT_EXIT
+
+#else /* microsecond timing */
+
+/*
+ * Microsecond timing.
+ * Assumes a free-running microsecond counter.
+ * no TIMER_MAX check needed.
+ */
+
+/*
+ * There is only one current time-stamp per CPU, since only
+ * the time-stamp in the current timer is used.
+ * To save time, we allocate the current time-stamps here.
+ */
+ .comm EXT(current_tstamp), 4*NCPUS
+
+/*
+ * Update time on user trap entry.
+ * 11 instructions (including cli on entry)
+ * Assumes CPU number in %edx.
+ * Uses %eax, %ebx, %ecx.
+ */
+#define TIME_TRAP_UENTRY \
+ cli /* block interrupts */ ;\
+ movl VA_ETC,%ebx /* get timer value */ ;\
+ movl CX(EXT(current_tstamp),%edx),%ecx /* get old time stamp */;\
+ movl %ebx,CX(EXT(current_tstamp),%edx) /* set new time stamp */;\
+ subl %ecx,%ebx /* elapsed = new-old */ ;\
+ movl CX(EXT(current_timer),%edx),%ecx /* get current timer */ ;\
+ addl %ebx,LOW_BITS(%ecx) /* add to low bits */ ;\
+ jns 0f /* if overflow, */ ;\
+ call timer_normalize /* normalize timer */ ;\
+0: addl $(TH_SYSTEM_TIMER-TH_USER_TIMER),%ecx ;\
+ /* switch to sys timer */;\
+ movl %ecx,CX(EXT(current_timer),%edx) /* make it current */ ;\
+ sti /* allow interrupts */
+
+/*
+ * Update time on system call entry.
+ * 11 instructions (including cli on entry)
+ * Assumes CPU number in %edx.
+ * Uses %ebx, %ecx.
+ * Same as TIME_TRAP_UENTRY, but preserves %eax.
+ */
+#define TIME_TRAP_SENTRY \
+ cli /* block interrupts */ ;\
+ movl VA_ETC,%ebx /* get timer value */ ;\
+ movl CX(EXT(current_tstamp),%edx),%ecx /* get old time stamp */;\
+ movl %ebx,CX(EXT(current_tstamp),%edx) /* set new time stamp */;\
+ subl %ecx,%ebx /* elapsed = new-old */ ;\
+ movl CX(EXT(current_timer),%edx),%ecx /* get current timer */ ;\
+ addl %ebx,LOW_BITS(%ecx) /* add to low bits */ ;\
+ jns 0f /* if overflow, */ ;\
+ pushq %rax /* save %rax */ ;\
+ call timer_normalize /* normalize timer */ ;\
+ popq %rax /* restore %rax */ ;\
+0: addl $(TH_SYSTEM_TIMER-TH_USER_TIMER),%ecx ;\
+ /* switch to sys timer */;\
+ movl %ecx,CX(EXT(current_timer),%edx) /* make it current */ ;\
+ sti /* allow interrupts */
+
+/*
+ * update time on user trap exit.
+ * 10 instructions.
+ * Assumes CPU number in %edx.
+ * Uses %ebx, %ecx.
+ */
+#define TIME_TRAP_UEXIT \
+ cli /* block interrupts */ ;\
+ movl VA_ETC,%ebx /* get timer */ ;\
+ movl CX(EXT(current_tstamp),%edx),%ecx /* get old time stamp */;\
+ movl %ebx,CX(EXT(current_tstamp),%edx) /* set new time stamp */;\
+ subl %ecx,%ebx /* elapsed = new-old */ ;\
+ movl CX(EXT(current_timer),%edx),%ecx /* get current timer */ ;\
+ addl %ebx,LOW_BITS(%ecx) /* add to low bits */ ;\
+ jns 0f /* if overflow, */ ;\
+ call timer_normalize /* normalize timer */ ;\
+0: addl $(TH_USER_TIMER-TH_SYSTEM_TIMER),%ecx ;\
+ /* switch to user timer */;\
+ movl %ecx,CX(EXT(current_timer),%edx) /* make it current */
+
+/*
+ * update time on interrupt entry.
+ * 9 instructions.
+ * Assumes CPU number in %edx.
+ * Leaves old timer in %ebx.
+ * Uses %ecx.
+ */
+#define TIME_INT_ENTRY \
+ movl VA_ETC,%ecx /* get timer */ ;\
+ movl CX(EXT(current_tstamp),%edx),%ebx /* get old time stamp */;\
+ movl %ecx,CX(EXT(current_tstamp),%edx) /* set new time stamp */;\
+ subl %ebx,%ecx /* elapsed = new-old */ ;\
+ movl CX(EXT(current_timer),%edx),%ebx /* get current timer */ ;\
+ addl %ecx,LOW_BITS(%ebx) /* add to low bits */ ;\
+ leal CX(0,%edx),%ecx /* timer is 16 bytes */ ;\
+ lea CX(EXT(kernel_timer),%edx),%ecx /* get interrupt timer*/;\
+ movl %ecx,CX(EXT(current_timer),%edx) /* set timer */
+
+/*
+ * update time on interrupt exit.
+ * 11 instructions
+ * Assumes CPU number in %edx, old timer in %ebx.
+ * Uses %eax, %ecx.
+ */
+#define TIME_INT_EXIT \
+ movl VA_ETC,%eax /* get timer */ ;\
+ movl CX(EXT(current_tstamp),%edx),%ecx /* get old time stamp */;\
+ movl %eax,CX(EXT(current_tstamp),%edx) /* set new time stamp */;\
+ subl %ecx,%eax /* elapsed = new-old */ ;\
+ movl CX(EXT(current_timer),%edx),%ecx /* get current timer */ ;\
+ addl %eax,LOW_BITS(%ecx) /* add to low bits */ ;\
+ jns 0f /* if overflow, */ ;\
+ call timer_normalize /* normalize timer */ ;\
+0: testb $0x80,LOW_BITS+3(%ebx) /* old timer overflow? */;\
+ jz 0f /* if overflow, */ ;\
+ movl %ebx,%ecx /* get old timer */ ;\
+ call timer_normalize /* normalize timer */ ;\
+0: movl %ebx,CX(EXT(current_timer),%edx) /* set timer */
+
+
+/*
+ * Normalize timer in ecx.
+ * Preserves edx; clobbers eax.
+ */
+ .align 2
+timer_high_unit:
+ .long TIMER_HIGH_UNIT /* div has no immediate opnd */
+
+timer_normalize:
+ pushq %rdx /* save register */
+ xorl %edx,%edx /* clear divisor high */
+ movl LOW_BITS(%ecx),%eax /* get divisor low */
+ divl timer_high_unit,%eax /* quotient in eax */
+ /* remainder in edx */
+ addl %eax,HIGH_BITS_CHECK(%ecx) /* add high_inc to check */
+ movl %edx,LOW_BITS(%ecx) /* remainder to low_bits */
+ addl %eax,HIGH_BITS(%ecx) /* add high_inc to high bits */
+ popq %rdx /* restore register */
+ ret
+
+/*
+ * Switch to a new timer.
+ */
+ENTRY(timer_switch)
+ CPU_NUMBER(%edx) /* get this CPU */
+ movl VA_ETC,%ecx /* get timer */
+ movl CX(EXT(current_tstamp),%edx),%eax /* get old time stamp */
+ movl %ecx,CX(EXT(current_tstamp),%edx) /* set new time stamp */
+ subl %ecx,%eax /* elapsed = new - old */
+ movl CX(EXT(current_timer),%edx),%ecx /* get current timer */
+ addl %eax,LOW_BITS(%ecx) /* add to low bits */
+ jns 0f /* if overflow, */
+ call timer_normalize /* normalize timer */
+0:
+ movl S_ARG0,%ecx /* get new timer */
+ movl %ecx,CX(EXT(current_timer),%edx) /* set timer */
+ ret
+
+/*
+ * Initialize the first timer for a CPU.
+ */
+ENTRY(start_timer)
+ CPU_NUMBER(%edx) /* get this CPU */
+ movl VA_ETC,%ecx /* get timer */
+ movl %ecx,CX(EXT(current_tstamp),%edx) /* set initial time stamp */
+ movl S_ARG0,%ecx /* get timer */
+ movl %ecx,CX(EXT(current_timer),%edx) /* set initial timer */
+ ret
+
+#endif /* accurate timing */
+
+/* */
+
+/*
+ * Trap/interrupt entry points.
+ *
+ * All traps must create the following save area on the kernel stack:
+ *
+ * gs
+ * fs
+ * es
+ * ds
+ * edi
+ * esi
+ * ebp
+ * cr2 if page fault - otherwise unused
+ * ebx
+ * edx
+ * ecx
+ * eax
+ * trap number
+ * error code
+ * eip
+ * cs
+ * eflags
+ * user rsp - if from user
+ * user ss - if from user
+ * es - if from V86 thread
+ * ds - if from V86 thread
+ * fs - if from V86 thread
+ * gs - if from V86 thread
+ *
+ */
+
+/*
+ * General protection or segment-not-present fault.
+ * Check for a GP/NP fault in the kernel_return
+ * sequence; if there, report it as a GP/NP fault on the user's instruction.
+ *
+ * rsp-> 0: trap code (NP or GP)
+ * 8: segment number in error
+ * 16 eip
+ * 24 cs
+ * 32 eflags
+ * 40 old registers (trap is from kernel)
+ */
+ENTRY(t_gen_prot)
+ INT_FIX
+ pushq $(T_GENERAL_PROTECTION) /* indicate fault type */
+ jmp trap_check_kernel_exit /* check for kernel exit sequence */
+
+ENTRY(t_segnp)
+ INT_FIX
+ pushq $(T_SEGMENT_NOT_PRESENT)
+ /* indicate fault type */
+
+trap_check_kernel_exit:
+ testq $(EFL_VM),32(%rsp) /* is trap from V86 mode? */
+ jnz EXT(alltraps) /* isn`t kernel trap if so */
+ /* Note: handling KERNEL_RING value by hand */
+ testq $2,24(%rsp) /* is trap from kernel mode? */
+ jnz EXT(alltraps) /* if so: */
+ /* check for the kernel exit sequence */
+ cmpq $_kret_iret,16(%rsp) /* on IRET? */
+ je fault_iret
+#if 0
+ cmpq $_kret_popl_ds,16(%rsp) /* popping DS? */
+ je fault_popl_ds
+ cmpq $_kret_popl_es,16(%rsp) /* popping ES? */
+ je fault_popl_es
+#endif
+ cmpq $_kret_popl_fs,16(%rsp) /* popping FS? */
+ je fault_popl_fs
+ cmpq $_kret_popl_gs,16(%rsp) /* popping GS? */
+ je fault_popl_gs
+take_fault: /* if none of the above: */
+ jmp EXT(alltraps) /* treat as normal trap. */
+
+/*
+ * GP/NP fault on IRET: CS or SS is in error.
+ * All registers contain the user's values.
+ *
+ * on SP is
+ * 0 trap number
+ * 8 errcode
+ * 16 eip
+ * 24 cs --> trapno
+ * 32 efl --> errcode
+ * 40 user eip
+ * 48 user cs
+ * 56 user eflags
+ * 64 user rsp
+ * 72 user ss
+ */
+fault_iret:
+ movq %rax,16(%rsp) /* save eax (we don`t need saved eip) */
+ popq %rax /* get trap number */
+ movq %rax,24-8(%rsp) /* put in user trap number */
+ popq %rax /* get error code */
+ movq %rax,32-16(%rsp) /* put in user errcode */
+ popq %rax /* restore eax */
+ jmp EXT(alltraps) /* take fault */
+
+/*
+ * Fault restoring a segment register. The user's registers are still
+ * saved on the stack. The offending segment register has not been
+ * popped.
+ */
+fault_popl_ds:
+ popq %rax /* get trap number */
+ popq %rdx /* get error code */
+ addq $24,%rsp /* pop stack to user regs */
+ jmp push_es /* (DS on top of stack) */
+fault_popl_es:
+ popq %rax /* get trap number */
+ popq %rdx /* get error code */
+ addq $24,%rsp /* pop stack to user regs */
+ jmp push_fs /* (ES on top of stack) */
+fault_popl_fs:
+ popq %rax /* get trap number */
+ popq %rdx /* get error code */
+ addq $24,%rsp /* pop stack to user regs */
+ jmp push_gs /* (FS on top of stack) */
+fault_popl_gs:
+ popq %rax /* get trap number */
+ popq %rdx /* get error code */
+ addq $24,%rsp /* pop stack to user regs */
+ jmp push_segregs /* (GS on top of stack) */
+
+push_es:
+ //pushq %es /* restore es, */
+push_fs:
+ pushq %fs /* restore fs, */
+push_gs:
+ pushq %gs /* restore gs. */
+push_segregs:
+ movq %rax,R_TRAPNO(%rsp) /* set trap number */
+ movq %rdx,R_ERR(%rsp) /* set error code */
+ jmp trap_set_segs /* take trap */
+
+/*
+ * Debug trap. Check for single-stepping across system call into
+ * kernel. If this is the case, taking the debug trap has turned
+ * off single-stepping - save the flags register with the trace
+ * bit set.
+ */
+ENTRY(t_debug)
+ INT_FIX
+ testq $(EFL_VM),16(%rsp) /* is trap from V86 mode? */
+ jnz 0f /* isn`t kernel trap if so */
+ /* Note: handling KERNEL_RING value by hand */
+ testq $2,8(%rsp) /* is trap from kernel mode? */
+ jnz 0f /* if so: */
+ cmpq $syscall_entry,(%rsp) /* system call entry? */
+ jne 0f /* if so: */
+ /* flags are sitting where syscall */
+ /* wants them */
+ addq $32,%rsp /* remove eip/cs */
+ jmp syscall_entry_2 /* continue system call entry */
+
+0: pushq $0 /* otherwise: */
+ pushq $(T_DEBUG) /* handle as normal */
+ jmp EXT(alltraps) /* debug fault */
+
+/*
+ * Page fault traps save cr2.
+ */
+ENTRY(t_page_fault)
+ INT_FIX
+ pushq $(T_PAGE_FAULT) /* mark a page fault trap */
+ pusha /* save the general registers */
+#ifdef MACH_XEN
+ movq %ss:hyp_shared_info+CR2,%rax
+#else /* MACH_XEN */
+ movq %cr2,%rax /* get the faulting address */
+#endif /* MACH_XEN */
+ movq %rax,R_CR2-R_R15(%rsp) /* save in rsp save slot */
+ jmp trap_push_segs /* continue fault */
+
+/*
+ * All 'exceptions' enter here with:
+ * rsp-> trap number
+ * error code
+ * old eip
+ * old cs
+ * old eflags
+ * old rsp if trapped from user
+ * old ss if trapped from user
+ */
+ENTRY(alltraps)
+ pusha /* save the general registers */
+trap_push_segs:
+ movq %ds,%rax /* and the segment registers */
+ pushq %rax
+ movq %es,%rax /* and the segment registers */
+ pushq %rax
+ pushq %fs
+ pushq %gs
+
+ /* Note that we have to load the segment registers
+ even if this is a trap from the kernel,
+ because the kernel uses user segment registers for copyin/copyout.
+ (XXX Would it be smarter just to use fs or gs for that?) */
+ mov %ss,%ax /* switch to kernel data segment */
+ mov %ax,%ds /* (same as kernel stack segment) */
+ mov %ax,%es
+ mov %ax,%fs
+ mov %ax,%gs
+
+trap_set_segs:
+ cld /* clear direction flag */
+ testl $(EFL_VM),R_EFLAGS(%rsp) /* in V86 mode? */
+ jnz trap_from_user /* user mode trap if so */
+ /* Note: handling KERNEL_RING value by hand */
+ testb $2,R_CS(%rsp) /* user mode trap? */
+ jz trap_from_kernel /* kernel trap if not */
+trap_from_user:
+
+ CPU_NUMBER(%edx)
+ TIME_TRAP_UENTRY
+
+ movq CX(EXT(kernel_stack),%edx),%rbx
+ xchgq %rbx,%rsp /* switch to kernel stack */
+ /* user regs pointer already set */
+_take_trap:
+ movq %rbx,%rdi /* pass register save area to trap */
+ call EXT(user_trap) /* call user trap routine */
+
+ orq %rax,%rax /* emulated syscall? */
+ jz 1f /* no, just return */
+ movq R_EAX(%rbx),%rax /* yes, get syscall number */
+ jmp syscall_entry_3 /* and emulate it */
+
+1:
+ movq (%rsp),%rsp /* switch back to PCB stack */
+
+/*
+ * Return from trap or system call, checking for ASTs.
+ * On PCB stack.
+ */
+
+_return_from_trap:
+ CPU_NUMBER(%edx)
+ cmpl $0,CX(EXT(need_ast),%edx)
+ jz _return_to_user /* if we need an AST: */
+
+ movq CX(EXT(kernel_stack),%edx),%rsp
+ /* switch to kernel stack */
+ call EXT(i386_astintr) /* take the AST */
+ popq %rsp /* switch back to PCB stack */
+ jmp _return_from_trap /* and check again (rare) */
+ /* ASTs after this point will */
+ /* have to wait */
+
+_return_to_user:
+ TIME_TRAP_UEXIT
+
+/*
+ * Return from kernel mode to interrupted thread.
+ */
+
+_return_from_kernel:
+_kret_popl_gs:
+ popq %gs /* restore segment registers */
+_kret_popl_fs:
+ popq %fs
+_kret_popl_es:
+ popq %rax
+ movq %rax,%es
+_kret_popl_ds:
+ popq %rax
+ movq %rax,%ds
+ popa /* restore general registers */
+ addq $16,%rsp /* discard trap number and error code */
+_kret_iret:
+ iretq /* return from interrupt */
+
+
+/*
+ * Trap from kernel mode. No need to switch stacks.
+ */
+trap_from_kernel:
+#if MACH_KDB || MACH_TTD
+ movq %rsp,%rbx /* save current stack */
+
+ movq %rsp,%rdx /* on an interrupt stack? */
+ and $(~(KERNEL_STACK_SIZE-1)),%rdx
+ cmpq EXT(int_stack_base),%rdx
+ je 1f /* OK if so */
+
+ CPU_NUMBER(%edx) /* get CPU number */
+ cmpq CX(EXT(kernel_stack),%edx),%rsp
+ /* already on kernel stack? */
+ ja 0f
+ cmpq CX(EXT(active_stacks),%edx),%rsp
+ ja 1f /* switch if not */
+0:
+ movq CX(EXT(kernel_stack),%edx),%rsp
+1:
+ pushq %rbx /* save old stack */
+ movq %rbx,%rdi /* pass as parameter */
+ call EXT(kernel_trap) /* to kernel trap routine */
+ popq %rsp /* return to old stack */
+#else /* MACH_KDB || MACH_TTD */
+
+ movq %rsp,%rdi /* pass parameter */
+ call EXT(kernel_trap) /* to kernel trap routine */
+#endif /* MACH_KDB || MACH_TTD */
+
+ jmp _return_from_kernel
+
+
+/*
+ * Called as a function, makes the current thread
+ * return from the kernel as if from an exception.
+ */
+
+ENTRY(thread_exception_return)
+ENTRY(thread_bootstrap_return)
+ movq %rsp,%rcx /* get kernel stack */
+ or $(KERNEL_STACK_SIZE-1),%ecx
+ movq -7-IKS_SIZE(%rcx),%rsp /* switch back to PCB stack */
+ jmp _return_from_trap
+
+/*
+ * Called as a function, makes the current thread
+ * return from the kernel as if from a syscall.
+ * Takes the syscall's return code as an argument.
+ */
+
+ENTRY(thread_syscall_return)
+ movq S_ARG0,%rax /* get return value */
+ movq %rsp,%rcx /* get kernel stack */
+ or $(KERNEL_STACK_SIZE-1),%ecx
+ movq -7-IKS_SIZE(%rcx),%rsp /* switch back to PCB stack */
+ movq %rax,R_EAX(%rsp) /* save return value */
+ jmp _return_from_trap
+
+ENTRY(call_continuation)
+ movq S_ARG0,%rax /* get continuation */
+ movq %rsp,%rcx /* get kernel stack */
+ or $(KERNEL_STACK_SIZE-1),%rcx
+ addq $(-7-IKS_SIZE),%rcx
+ movq %rcx,%rsp /* pop the stack */
+ xorq %rbp,%rbp /* zero frame pointer */
+ pushq $0 /* Dummy return address */
+ jmp *%rax /* goto continuation */
+
+
+#define INTERRUPT(n) \
+ .data 2 ;\
+ .quad 0f ;\
+ .text ;\
+ P2ALIGN(TEXT_ALIGN) ;\
+0: ;\
+ INT_FIX ;\
+ pushq %rax ;\
+ movq $(n),%rax ;\
+ jmp EXT(all_intrs)
+
+ .data 2
+DATA(int_entry_table)
+ .text
+INTERRUPT(0)
+INTERRUPT(1)
+INTERRUPT(2)
+INTERRUPT(3)
+INTERRUPT(4)
+INTERRUPT(5)
+INTERRUPT(6)
+INTERRUPT(7)
+INTERRUPT(8)
+INTERRUPT(9)
+INTERRUPT(10)
+INTERRUPT(11)
+INTERRUPT(12)
+INTERRUPT(13)
+INTERRUPT(14)
+INTERRUPT(15)
+
+/* XXX handle NMI - at least print a warning like Linux does. */
+
+/*
+ * All interrupts enter here.
+ * old %eax on stack; interrupt number in %eax.
+ */
+ENTRY(all_intrs)
+ pushq %rcx /* save registers */
+ pushq %rdx
+ pushq %rsi
+ pushq %rdi
+ pushq %r8
+ pushq %r9
+ pushq %r10
+ pushq %r11
+ cld /* clear direction flag */
+
+ movq %rsp,%rdx /* on an interrupt stack? */
+ and $(~(KERNEL_STACK_SIZE-1)),%rdx
+ cmpq %ss:EXT(int_stack_base),%rdx
+ je int_from_intstack /* if not: */
+
+ movq %ds,%rdx /* save segment registers */
+ pushq %rdx
+ movq %es,%rdx
+ pushq %rdx
+ pushq %fs
+ pushq %gs
+ mov %ss,%dx /* switch to kernel segments */
+ mov %dx,%ds
+ mov %dx,%es
+ mov %dx,%fs
+ mov %dx,%gs
+
+ CPU_NUMBER(%edx)
+
+ movq CX(EXT(int_stack_top),%edx),%rcx
+
+ xchgq %rcx,%rsp /* switch to interrupt stack */
+
+#if STAT_TIME
+ pushq %rcx /* save pointer to old stack */
+#else
+ pushq %rbx /* save %ebx - out of the way */
+ /* so stack looks the same */
+ pushq %rcx /* save pointer to old stack */
+ TIME_INT_ENTRY /* do timing */
+#endif
+
+ call EXT(interrupt) /* call generic interrupt routine */
+
+ .globl EXT(return_to_iret)
+LEXT(return_to_iret) /* ( label for kdb_kintr and hardclock) */
+
+ CPU_NUMBER(%edx)
+#if STAT_TIME
+#else
+ TIME_INT_EXIT /* do timing */
+ movq 8(%rsp),%rbx /* restore the extra reg we saved */
+#endif
+
+ popq %rsp /* switch back to old stack */
+
+ testl $(EFL_VM),I_EFL(%rsp) /* if in V86 */
+ jnz 0f /* or */
+ /* Note: handling KERNEL_RING value by hand */
+ testb $2,I_CS(%rsp) /* user mode, */
+ jz 1f /* check for ASTs */
+0:
+ cmpq $0,CX(EXT(need_ast),%edx)
+ jnz ast_from_interrupt /* take it if so */
+1:
+ pop %gs /* restore segment regs */
+ pop %fs
+ pop %rdx
+ mov %rdx,%es
+ pop %rdx
+ mov %rdx,%ds
+ pop %r11
+ pop %r10
+ pop %r9
+ pop %r8
+ pop %rdi
+ pop %rsi
+ pop %rdx
+ pop %rcx
+ pop %rax
+
+ iretq /* return to caller */
+
+int_from_intstack:
+ cmpq EXT(int_stack_base),%rsp /* seemingly looping? */
+ jb stack_overflowed /* if not: */
+ call EXT(interrupt) /* call interrupt routine */
+_return_to_iret_i: /* ( label for kdb_kintr) */
+ pop %r11
+ pop %r10
+ pop %r9
+ pop %r8
+ pop %rdi
+ pop %rsi
+ pop %rdx /* must have been on kernel segs */
+ pop %rcx
+ pop %rax /* no ASTs */
+
+ iretq
+
+stack_overflowed:
+ ud2
+
+/*
+ * Take an AST from an interrupt.
+ * On PCB stack.
+ * sp-> gs -> edx
+ * fs -> ecx
+ * es -> eax
+ * ds -> trapno
+ * edx -> code
+ * ecx
+ * eax
+ * eip
+ * cs
+ * efl
+ * rsp
+ * ss
+ */
+ast_from_interrupt:
+ pop %gs /* restore all registers ... */
+ pop %fs
+ pop %rdx
+ mov %rdx,%es
+ pop %rdx
+ mov %rdx,%ds
+ popq %r11
+ popq %r10
+ popq %r9
+ popq %r8
+ popq %rdi
+ popq %rsi
+ popq %rdx
+ popq %rcx
+ popq %rax
+ pushq $0 /* zero code */
+ pushq $0 /* zero trap number */
+ pusha /* save general registers */
+ mov %ds,%rdx /* save segment registers */
+ push %rdx
+ mov %es,%rdx
+ push %rdx
+ push %fs
+ push %gs
+ mov %ss,%dx /* switch to kernel segments */
+ mov %dx,%ds
+ mov %dx,%es
+ mov %dx,%fs
+ mov %dx,%gs
+
+ CPU_NUMBER(%edx)
+ TIME_TRAP_UENTRY
+
+ movq CX(EXT(kernel_stack),%edx),%rsp
+ /* switch to kernel stack */
+ call EXT(i386_astintr) /* take the AST */
+ popq %rsp /* back to PCB stack */
+ jmp _return_from_trap /* return */
+
+#if MACH_KDB
+/*
+ * kdb_kintr: enter kdb from keyboard interrupt.
+ * Chase down the stack frames until we find one whose return
+ * address is the interrupt handler. At that point, we have:
+ *
+ * frame-> saved %rbp
+ * return address in interrupt handler
+ * return address == return_to_iret_i
+ * saved %r11
+ * saved %r10
+ * saved %r9
+ * saved %r8
+ * saved %rdx
+ * saved %rcx
+ * saved %rax
+ * saved %rip
+ * saved %cs
+ * saved %rfl
+ *
+ * OR:
+ * frame-> saved %rbp
+ * return address in interrupt handler
+ * return address == return_to_iret
+ * pointer to save area on old stack
+ * [ saved %ebx, if accurate timing ]
+ *
+ * old stack: saved %gs
+ * saved %fs
+ * saved %es
+ * saved %ds
+ * saved %r11
+ * saved %r10
+ * saved %r9
+ * saved %r8
+ * saved %rdi
+ * saved %rsi
+ * saved %rdx
+ * saved %rcx
+ * saved %eax
+ * saved %rip
+ * saved %cs
+ * saved %rfl
+ *
+ * Call kdb, passing it that register save area.
+ */
+
+#define RET_OFFSET 16
+
+
+ENTRY(kdb_kintr)
+ movq %rbp,%rax /* save caller`s frame pointer */
+ movq $EXT(return_to_iret),%rcx /* interrupt return address 1 */
+ movq $_return_to_iret_i,%rdx /* interrupt return address 2 */
+
+0: cmpq RET_OFFSET(%rax),%rcx /* does this frame return to */
+ /* interrupt handler (1)? */
+ je 1f
+ cmpq RET_OFFSET(%rax),%rdx /* interrupt handler (2)? */
+ je 2f /* if not: */
+ movq (%rax),%rax /* try next frame */
+ jmp 0b
+
+1: movq $kdb_from_iret,RET_OFFSET(%rax)
+ ret /* returns to kernel/user stack */
+
+2: movq $kdb_from_iret_i,RET_OFFSET(%rax)
+ /* returns to interrupt stack */
+ ret
+
+/*
+ * On return from keyboard interrupt, we will execute
+ * kdb_from_iret_i
+ * if returning to an interrupt on the interrupt stack
+ * kdb_from_iret
+ * if returning to an interrupt on the user or kernel stack
+ */
+kdb_from_iret:
+ /* save regs in known locations */
+#if STAT_TIME
+ pushq %rbx /* caller`s %ebx is in reg */
+#else
+ movq 8(%rsp),%rax /* get caller`s %ebx */
+ pushq %rax /* push on stack */
+#endif
+ pushq %rbp
+ movq %rsp,%rdi /* pass regs */
+ call EXT(kdb_kentry) /* to kdb */
+ popq %rbp
+#if STAT_TIME
+ popq %rbx
+#else
+ popq %rax
+ movq %rax,8(%rsp)
+#endif
+ jmp EXT(return_to_iret) /* normal interrupt return */
+
+kdb_from_iret_i: /* on interrupt stack */
+ pop %rdx /* restore saved registers */
+ pop %rcx
+ pop %rax
+ pushq $0 /* zero error code */
+ pushq $0 /* zero trap number */
+ pusha /* save general registers */
+ mov %ds,%rdx /* save segment registers */
+ push %rdx
+ mov %es,%rdx
+ push %rdx
+ push %fs
+ push %gs
+ movq %rsp,%rdx /* pass regs, */
+ movq $0,%rsi /* code, */
+ movq $-1,%rdi /* type to kdb */
+ call EXT(kdb_trap)
+ pop %gs /* restore segment registers */
+ pop %fs
+ pop %rdx
+ mov %rdx,%es
+ pop %rdx
+ mov %rdx,%ds
+ popa /* restore general registers */
+ addq $16,%rsp
+
+// TODO: test it before dropping ud2
+movq (%rsp),%rax
+ud2
+ iretq
+
+#endif /* MACH_KDB */
+
+#if MACH_TTD
+/*
+ * Same code as that above for the keyboard entry into kdb.
+ */
+ENTRY(kttd_intr)
+// TODO: test it before dropping ud2
+ud2
+ movq %rbp,%rax /* save caller`s frame pointer */
+ movq $EXT(return_to_iret),%rcx /* interrupt return address 1 */
+ movq $_return_to_iret_i,%rdx /* interrupt return address 2 */
+
+0: cmpq 32(%rax),%rcx /* does this frame return to */
+ /* interrupt handler (1)? */
+ je 1f
+ cmpq 32(%rax),%rdx /* interrupt handler (2)? */
+ je 2f /* if not: */
+ movq (%rax),%rax /* try next frame */
+ jmp 0b
+
+1: movq $ttd_from_iret,32(%rax) /* returns to kernel/user stack */
+ ret
+
+2: movq $ttd_from_iret_i,32(%rax)
+ /* returns to interrupt stack */
+ ret
+
+/*
+ * On return from keyboard interrupt, we will execute
+ * ttd_from_iret_i
+ * if returning to an interrupt on the interrupt stack
+ * ttd_from_iret
+ * if returning to an interrupt on the user or kernel stack
+ */
+ttd_from_iret:
+ /* save regs in known locations */
+#if STAT_TIME
+ pushq %rbx /* caller`s %ebx is in reg */
+#else
+ movq 8(%rsp),%rax /* get caller`s %ebx */
+ pushq %rax /* push on stack */
+#endif
+ pushq %rbp
+ pushq %rsi
+ pushq %rdi
+ movq %rsp,%rdi /* pass regs */
+ call _kttd_netentry /* to kdb */
+ popq %rdi /* restore registers */
+ popq %rsi
+ popq %rbp
+#if STAT_TIME
+ popq %rbx
+#else
+ popq %rax
+ movq %rax,8(%rsp)
+#endif
+ jmp EXT(return_to_iret) /* normal interrupt return */
+
+ttd_from_iret_i: /* on interrupt stack */
+ pop %rdx /* restore saved registers */
+ pop %rcx
+ pop %rax
+ pushq $0 /* zero error code */
+ pushq $0 /* zero trap number */
+ pusha /* save general registers */
+ mov %ds,%rdx /* save segment registers */
+ push %rdx
+ mov %es,%rdx
+ push %rdx
+ push %fs
+ push %gs
+ movq %rsp,%rdx /* pass regs, */
+ movq $0,%rsi /* code, */
+ movq $-1,%rdi /* type to kdb */
+ call _kttd_trap
+ pop %gs /* restore segment registers */
+ pop %fs
+ pop %rdx
+ mov %rdx,%es
+ pop %rdx
+ mov %rdx,%ds
+ popa /* restore general registers */
+ addq $16,%rsp
+
+// TODO: test it before dropping ud2
+movq (%rsp),%rax
+ud2
+ iretq
+
+#endif /* MACH_TTD */
+
+/*
+ * System call enters through a call gate. Flags are not saved -
+ * we must shuffle stack to look like trap save area.
+ *
+ * rsp-> old eip
+ * old cs
+ * old rsp
+ * old ss
+ *
+ * eax contains system call number.
+ */
+ENTRY(syscall)
+syscall_entry:
+ pushf /* save flags as soon as possible */
+syscall_entry_2:
+ cld /* clear direction flag */
+
+ pushq %rax /* save system call number */
+ pushq $0 /* clear trap number slot */
+
+// TODO: test it before dropping ud2
+ ud2
+
+ pusha /* save the general registers */
+ movq %ds,%rdx /* and the segment registers */
+ pushq %rdx
+ movq %es,%rdx
+ pushq %rdx
+ pushq %fs
+ pushq %gs
+
+ mov %ss,%dx /* switch to kernel data segment */
+ mov %dx,%ds
+ mov %dx,%es
+ mov %dx,%fs
+ mov %dx,%gs
+
+/*
+ * Shuffle eflags,eip,cs into proper places
+ */
+
+ movq R_EIP(%rsp),%rbx /* eflags are in EIP slot */
+ movq R_CS(%rsp),%rcx /* eip is in CS slot */
+ movq R_EFLAGS(%rsp),%rdx /* cs is in EFLAGS slot */
+ movq %rcx,R_EIP(%rsp) /* fix eip */
+ movq %rdx,R_CS(%rsp) /* fix cs */
+ movq %rbx,R_EFLAGS(%rsp) /* fix eflags */
+
+ CPU_NUMBER(%edx)
+ TIME_TRAP_SENTRY
+
+ movq CX(EXT(kernel_stack),%edx),%rbx
+ /* get current kernel stack */
+ xchgq %rbx,%rsp /* switch stacks - %ebx points to */
+ /* user registers. */
+ /* user regs pointer already set */
+
+/*
+ * Check for MACH or emulated system call
+ */
+syscall_entry_3:
+ movq CX(EXT(active_threads),%edx),%rdx
+ /* point to current thread */
+ movq TH_TASK(%rdx),%rdx /* point to task */
+ movq TASK_EMUL(%rdx),%rdx /* get emulation vector */
+ orq %rdx,%rdx /* if none, */
+ je syscall_native /* do native system call */
+ movq %rax,%rcx /* copy system call number */
+ subq DISP_MIN(%rdx),%rcx /* get displacement into syscall */
+ /* vector table */
+ jl syscall_native /* too low - native system call */
+ cmpq DISP_COUNT(%rdx),%rcx /* check range */
+ jnl syscall_native /* too high - native system call */
+ movq DISP_VECTOR(%rdx,%rcx,4),%rdx
+ /* get the emulation vector */
+ orq %rdx,%rdx /* emulated system call if not zero */
+ jnz syscall_emul
+
+/*
+ * Native system call.
+ */
+syscall_native:
+ negl %eax /* get system call number */
+ jl mach_call_range /* out of range if it was positive */
+ cmpl EXT(mach_trap_count),%eax /* check system call table bounds */
+ jg mach_call_range /* error if out of range */
+#if 0 /* debug hack to show the syscall number on the screen */
+ movb %al,%dl
+ shrb $4,%dl
+ orb $0x30,%dl
+ movb $0x0f,%dh
+ movw %dx,0xb800a
+ movb %al,%dl
+ andb $0xf,%dl
+ orb $0x30,%dl
+ movb $0xf,%dh
+ movw %dx,0xb800c
+#endif
+ shll $5,%eax /* manual indexing of mach_trap_t */
+ xorq %r10,%r10
+ movl EXT(mach_trap_table)(%eax),%r10d
+ /* get number of arguments */
+ andq %r10,%r10
+ jz mach_call_call /* skip argument copy if none */
+
+ movq R_UESP(%rbx),%rbx /* get user stack pointer */
+ addq $4,%rbx /* Skip user return address */
+
+ movq $USER_DS,%rdx /* use user data segment for accesses */
+ mov %dx,%fs
+ movq %rsp,%r11 /* save kernel ESP for error recovery */
+
+#define PARAM(reg,ereg) \
+ RECOVER(mach_call_addr_push) \
+ xorq %reg,%reg ;\
+ movl %fs:(%rbx),%ereg /* 1st parameter */ ;\
+ addq $4,%rbx ;\
+ dec %r10 ;\
+ jz mach_call_call
+
+ PARAM(rdi,edi) /* 1st parameter */
+ PARAM(rsi,esi) /* 2nd parameter */
+ PARAM(rdx,edx) /* 3rd parameter */
+ PARAM(rcx,ecx) /* 4th parameter */
+ PARAM(r8,r8d) /* 5th parameter */
+ PARAM(r9,r9d) /* 6th parameter */
+
+ lea (%rbx,%r10,4),%rbx /* point past last argument */
+ xorq %r12,%r12
+
+0: subq $4,%rbx
+ RECOVER(mach_call_addr_push)
+ movl %fs:(%rbx),%r12d
+ pushq %r12 /* push argument on stack */
+ dec %r10
+ jnz 0b /* loop for all arguments */
+
+mach_call_call:
+
+#ifdef DEBUG
+ testb $0xff,EXT(syscall_trace)
+ jz 0f
+ movq %rax,%rdi
+ call EXT(syscall_trace_print)
+ /* will return with syscallofs still (or again) in eax */
+0:
+#endif /* DEBUG */
+
+ call *EXT(mach_trap_table)+8(%eax)
+ /* call procedure */
+ movq %rsp,%rcx /* get kernel stack */
+ or $(KERNEL_STACK_SIZE-1),%rcx
+ movq -7-IKS_SIZE(%rcx),%rsp /* switch back to PCB stack */
+ movq %rax,R_EAX(%rsp) /* save return value */
+ jmp _return_from_trap /* return to user */
+
+/*
+ * Address out of range. Change to page fault.
+ * %esi holds failing address.
+ */
+mach_call_addr_push:
+ movq %r11,%rsp /* clean parameters from stack */
+mach_call_addr:
+ movq %rsi,R_CR2(%rbx) /* set fault address */
+ movq $(T_PAGE_FAULT),R_TRAPNO(%rbx)
+ /* set page-fault trap */
+ movq $(T_PF_USER),R_ERR(%rbx)
+ /* set error code - read user space */
+ jmp _take_trap /* treat as a trap */
+
+/*
+ * System call out of range. Treat as invalid-instruction trap.
+ * (? general protection?)
+ */
+mach_call_range:
+ movq $(T_INVALID_OPCODE),R_TRAPNO(%rbx)
+ /* set invalid-operation trap */
+ movq $0,R_ERR(%rbx) /* clear error code */
+ jmp _take_trap /* treat as a trap */
+
+/*
+ * User space emulation of system calls.
+ * edx - user address to handle syscall
+ *
+ * User stack will become:
+ * ursp-> eflags
+ * eip
+ * eax still contains syscall number.
+ */
+syscall_emul:
+ movq $USER_DS,%rdi /* use user data segment for accesses */
+ mov %di,%fs
+
+/* XXX what about write-protected pages? */
+ movq R_UESP(%rbx),%rdi /* get user stack pointer */
+ subq $16,%rdi /* push space for new arguments */
+ movq R_EFLAGS(%rbx),%rax /* move flags */
+ RECOVER(syscall_addr)
+ movl %eax,%fs:0(%rdi) /* to user stack */
+ movl R_EIP(%rbx),%eax /* move eip */
+ RECOVER(syscall_addr)
+ movl %eax,%fs:4(%rdi) /* to user stack */
+ movq %rdi,R_UESP(%rbx) /* set new user stack pointer */
+ movq %rdx,R_EIP(%rbx) /* change return address to trap */
+ movq %rbx,%rsp /* back to PCB stack */
+// TODO: test it before dropping ud2
+ud2
+ jmp _return_from_trap /* return to user */
+
+/*
+ * Address error - address is in %edi.
+ */
+syscall_addr:
+ movq %rdi,R_CR2(%rbx) /* set fault address */
+ movq $(T_PAGE_FAULT),R_TRAPNO(%rbx)
+ /* set page-fault trap */
+ movq $(T_PF_USER),R_ERR(%rbx)
+ /* set error code - read user space */
+ jmp _take_trap /* treat as a trap */
+
+
+ .data
+DATA(cpu_features)
+ .long 0
+ .text
+
+END(syscall)
+
+/* Discover what kind of cpu we have; return the family number
+ (3, 4, 5, 6, for 386, 486, 586, 686 respectively). */
+ENTRY(discover_x86_cpu_type)
+ /* We are a modern enough processor to have the CPUID instruction;
+ use it to find out what we are. */
+ movl $1,%eax /* Fetch CPU type info ... */
+ cpuid /* ... into eax */
+ movl %edx,cpu_features /* Keep a copy */
+ shrl $8,%eax /* Slide family bits down */
+ andl $15,%eax /* And select them */
+ ret /* And return */
+
+
+/* */
+/*
+ * Utility routines.
+ */
+
+ENTRY(copyin)
+ xchgq %rsi,%rdi /* Get user source and kernel destination */
+
+copyin_remainder:
+ /*cld*/ /* count up: default mode in all GCC code */
+ movq %rdx,%rcx /* move by longwords first */
+ shrq $3,%rcx
+ RECOVER(copyin_fail)
+ rep
+ movsq /* move longwords */
+ movq %rdx,%rcx /* now move remaining bytes */
+ andq $7,%rcx
+ RECOVER(copyin_fail)
+ rep
+ movsb
+ xorq %rax,%rax /* return 0 for success */
+
+copyin_ret:
+ ret /* and return */
+
+copyin_fail:
+ movq $1,%rax /* return 1 for failure */
+ jmp copyin_ret /* pop frame and return */
+
+/*
+ * Copy from user address space - version for copying messages.
+ * arg0: user address
+ * arg1: kernel address
+ * arg2: byte count
+ */
+ENTRY(copyinmsg)
+ xchgq %rsi,%rdi /* Get user source and kernel destination */
+
+/* 32 on 64 conversion */
+ subq $32,%rdx
+ js bogus
+
+ /* Copy msgh_bits */
+ RECOVER(copyin_fail)
+ movsl
+
+ /* Copy msgh_size */
+ RECOVER(copyin_fail)
+ lodsl
+ addl $8,%eax
+ stosl
+
+ xorq %rax,%rax
+ /* Copy msgh_remote_port */
+ RECOVER(copyin_fail)
+ lodsl
+ stosq
+
+ /* Copy msgh_local_port */
+ RECOVER(copyin_fail)
+ lodsl
+ stosq
+
+ /* Copy msgh_seqno and msgh_id */
+ RECOVER(copyin_fail)
+ movsq
+
+ jmp copyin_remainder
+
+bogus:
+ ud2
+
+ENTRY(copyout)
+ xchgq %rsi,%rdi /* Get user source and kernel destination */
+
+copyout_remainder:
+ movq %rdx,%rax /* use count */
+ /*cld*/ /* count up: always this way in GCC code */
+ movq %rax,%rcx /* move by longwords first */
+ shrq $3,%rcx
+ RECOVER(copyout_fail)
+ rep
+ movsq
+ movq %rax,%rcx /* now move remaining bytes */
+ andq $7,%rcx
+ RECOVER(copyout_fail)
+ rep
+ movsb /* move */
+ xorq %rax,%rax /* return 0 for success */
+
+copyout_ret:
+ ret /* and return */
+
+copyout_fail:
+ movq $1,%rax /* return 1 for failure */
+ jmp copyout_ret /* pop frame and return */
+
+/*
+ * Copy to user address space.
+ * arg0: kernel address
+ * arg1: user address
+ * arg2: byte count
+ */
+ENTRY(copyoutmsg)
+ xchgq %rsi,%rdi /* Get user source and kernel destination */
+
+/* 32 on 64 conversion */
+ subq $32,%rdx
+ js bogus
+
+ /* Copy msgh_bits */
+ RECOVER(copyout_fail)
+ movsl
+
+ /* Copy msgh_size */
+ lodsl
+ subl $8,%eax
+ RECOVER(copyout_fail)
+ stosl
+
+ /* Copy msgh_remote_port */
+ lodsq
+ RECOVER(copyout_fail)
+ stosl
+
+ /* Copy msgh_local_port */
+ lodsq
+ RECOVER(copyout_fail)
+ stosl
+
+ /* Copy msgh_seqno and msgh_id */
+ RECOVER(copyout_fail)
+ movsq
+
+ jmp copyin_remainder
+
+/*
+ * int inst_fetch(int eip, int cs);
+ *
+ * Fetch instruction byte. Return -1 if invalid address.
+ */
+ENTRY(inst_fetch)
+ movq S_ARG1, %rax /* get segment */
+ movw %ax,%fs /* into FS */
+ movq S_ARG0, %rax /* get offset */
+ RETRY(EXT(inst_fetch)) /* re-load FS on retry */
+ RECOVER(_inst_fetch_fault)
+ movzbq %fs:(%rax),%rax /* load instruction byte */
+ ret
+
+_inst_fetch_fault:
+ movq $-1,%rax /* return -1 if error */
+ ret
+
+
+/*
+ * Done with recovery and retry tables.
+ */
+ RECOVER_TABLE_END
+ RETRY_TABLE_END
+
+
+
+/*
+ * cpu_shutdown()
+ * Force reboot
+ */
+null_idt:
+ .space 8 * 32
+
+null_idtr:
+ .word 8 * 32 - 1
+ .quad null_idt
+
+Entry(cpu_shutdown)
+ lidt null_idtr /* disable the interrupt handler */
+ xor %rcx,%rcx /* generate a divide by zero */
+ div %rcx,%rax /* reboot now */
+ ret /* this will "never" be executed */
diff --git a/x86_64/spl.S b/x86_64/spl.S
new file mode 100644
index 00000000..0c2c50cb
--- /dev/null
+++ b/x86_64/spl.S
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 1995 Shantanu Goel
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * THE AUTHOR ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. THE AUTHOR DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ */
+
+/*
+ * spl routines for the i386at.
+ */
+
+#include <mach/machine/asm.h>
+#include <i386/i386/ipl.h>
+#include <i386/i386/i386asm.h>
+#include <i386/i386/xen.h>
+
+#if NCPUS > 1
+#define mb lock; addl $0,(%esp)
+#else
+#define mb
+#endif
+
+/*
+ * Program XEN evt masks from %eax.
+ */
+#define XEN_SETMASK() \
+ pushq %rbx; \
+ movl %eax,%ebx; \
+ xchgl %eax,hyp_shared_info+EVTMASK; \
+ notl %ebx; \
+ andl %eax,%ebx; /* Get unmasked events */ \
+ testl hyp_shared_info+PENDING, %ebx; \
+ popq %rbx; \
+ jz 9f; /* Check whether there was some pending */ \
+lock orl $1,hyp_shared_info+CPU_PENDING_SEL; /* Yes, activate it */ \
+ movb $1,hyp_shared_info+CPU_PENDING; \
+9:
+
+ENTRY(spl0)
+ mb;
+ movl EXT(curr_ipl),%eax /* save current ipl */
+ pushq %rax
+ cli /* disable interrupts */
+#ifdef LINUX_DEV
+ movl EXT(bh_active),%eax
+ /* get pending mask */
+ andl EXT(bh_mask),%eax /* any pending unmasked interrupts? */
+ jz 1f /* no, skip */
+ call EXT(spl1) /* block further interrupts */
+ incl EXT(intr_count) /* set interrupt flag */
+ call EXT(linux_soft_intr) /* go handle interrupt */
+ decl EXT(intr_count) /* decrement interrupt flag */
+ cli /* disable interrupts */
+1:
+#endif
+ cmpl $0,softclkpending /* softclock pending? */
+ je 1f /* no, skip */
+ movl $0,softclkpending /* clear flag */
+ call EXT(spl1) /* block further interrupts */
+#ifdef LINUX_DEV
+ incl EXT(intr_count) /* set interrupt flag */
+#endif
+ call EXT(softclock) /* go handle interrupt */
+#ifdef LINUX_DEV
+ decl EXT(intr_count) /* decrement interrupt flag */
+#endif
+ cli /* disable interrupts */
+1:
+ cmpl $(SPL0),EXT(curr_ipl) /* are we at spl0? */
+ je 1f /* yes, all done */
+ movl $(SPL0),EXT(curr_ipl) /* set ipl */
+#ifdef MACH_XEN
+ movl EXT(int_mask)+SPL0*4,%eax
+ /* get xen mask */
+ XEN_SETMASK() /* program xen evts */
+#endif
+1:
+ sti /* enable interrupts */
+ popq %rax /* return previous mask */
+ ret
+
+
+/*
+ * Historically, SETIPL(level) was called
+ * for spl levels 1-6, now we have combined
+ * all the intermediate levels into the highest level
+ * such that interrupts are either on or off,
+ * since modern hardware can handle it.
+ * This simplifies the interrupt handling
+ * especially for the linux drivers.
+ */
+Entry(splsoftclock)
+ENTRY(spl1)
+ENTRY(spl2)
+ENTRY(spl3)
+Entry(splnet)
+Entry(splhdw)
+ENTRY(spl4)
+Entry(splbio)
+Entry(spldcm)
+ENTRY(spl5)
+Entry(spltty)
+Entry(splimp)
+Entry(splvm)
+ENTRY(spl6)
+Entry(splclock)
+Entry(splsched)
+Entry(splhigh)
+Entry(splhi)
+ENTRY(spl7)
+ mb;
+ /* just clear IF */
+ cli
+ movl $SPL7,%eax
+ xchgl EXT(curr_ipl),%eax
+ ret
+
+ENTRY(splx)
+ movq S_ARG0,%rdx /* get ipl */
+
+#if (MACH_KDB || MACH_TTD) && !defined(MACH_XEN)
+ /* First make sure that if we're exitting from ipl7, IF is still cleared */
+ cmpl $SPL7,EXT(curr_ipl) /* from ipl7? */
+ jne 0f
+ pushfq
+ popq %rax
+ testl $0x200,%eax /* IF? */
+ jz 0f
+ int3 /* Oops, interrupts got enabled?! */
+
+0:
+#endif /* (MACH_KDB || MACH_TTD) && !MACH_XEN */
+ testl %edx,%edx /* spl0? */
+ jz EXT(spl0) /* yes, handle specially */
+ cmpl EXT(curr_ipl),%edx /* same ipl as current? */
+ jne spl /* no */
+ cmpl $SPL7,%edx /* spl7? */
+ je 1f /* to ipl7, don't enable interrupts */
+ sti /* ensure interrupts are enabled */
+1:
+ movl %edx,%eax /* return previous ipl */
+ ret
+
+/*
+ * Like splx() but returns with interrupts disabled and does
+ * not return the previous ipl. This should only be called
+ * when returning from an interrupt.
+ */
+ .align TEXT_ALIGN
+ .globl splx_cli
+splx_cli:
+ movq S_ARG0,%rdx /* get ipl */
+ cli /* disable interrupts */
+ testl %edx,%edx /* spl0? */
+ jnz 2f /* no, skip */
+#ifdef LINUX_DEV
+ movl EXT(bh_active),%eax
+ /* get pending mask */
+ andl EXT(bh_mask),%eax /* any pending unmasked interrupts? */
+ jz 1f /* no, skip */
+ call EXT(spl1) /* block further interrupts */
+ incl EXT(intr_count) /* set interrupt flag */
+ call EXT(linux_soft_intr) /* go handle interrupt */
+ decl EXT(intr_count) /* decrement interrupt flag */
+ cli /* disable interrupts */
+1:
+#endif
+ cmpl $0,softclkpending /* softclock pending? */
+ je 1f /* no, skip */
+ movl $0,softclkpending /* clear flag */
+ call EXT(spl1) /* block further interrupts */
+#ifdef LINUX_DEV
+ incl EXT(intr_count) /* set interrupt flag */
+#endif
+ call EXT(softclock) /* go handle interrupt */
+#ifdef LINUX_DEV
+ decl EXT(intr_count) /* decrement interrupt flag */
+#endif
+ cli /* disable interrupts */
+1:
+ xorl %edx,%edx /* edx = ipl 0 */
+2:
+ cmpl EXT(curr_ipl),%edx /* same ipl as current? */
+ je 1f /* yes, all done */
+ movl %edx,EXT(curr_ipl) /* set ipl */
+#ifdef MACH_XEN
+ movl EXT(int_mask)(,%edx,4),%eax
+ /* get int mask */
+ XEN_SETMASK() /* program xen evts with new mask */
+#endif
+1:
+ ret
+
+/*
+ * NOTE: This routine must *not* use %ecx, otherwise
+ * the interrupt code will break.
+ */
+ .align TEXT_ALIGN
+ .globl spl
+spl:
+#if (MACH_KDB || MACH_TTD) && !defined(MACH_XEN)
+ /* First make sure that if we're exitting from ipl7, IF is still cleared */
+ cmpl $SPL7,EXT(curr_ipl) /* from ipl7? */
+ jne 0f
+ pushfq
+ popq %rax
+ testl $0x200,%eax /* IF? */
+ jz 0f
+ int3 /* Oops, interrupts got enabled?! */
+
+0:
+#endif /* (MACH_KDB || MACH_TTD) && !MACH_XEN */
+ cmpl $SPL7,%edx /* spl7? */
+ je EXT(spl7) /* yes, handle specially */
+#ifdef MACH_XEN
+ movl EXT(int_mask)(,%edx,4),%eax
+ /* get int mask */
+#endif
+ cli /* disable interrupts */
+ xchgl EXT(curr_ipl),%edx /* set ipl */
+#ifdef MACH_XEN
+ XEN_SETMASK() /* program PICs with new mask */
+#endif
+ sti /* enable interrupts */
+ movl %edx,%eax /* return previous ipl */
+ ret
+
+ENTRY(sploff)
+ pushfq
+ popq %rax
+ cli
+ ret
+
+ENTRY(splon)
+ pushq S_ARG0
+ popfq
+ ret
+
+ .data
+ .align DATA_ALIGN
+softclkpending:
+ .long 0
+ .text
+
+ENTRY(setsoftclock)
+ incl softclkpending
+ ret
diff --git a/x86_64/x86_64 b/x86_64/x86_64
new file mode 120000
index 00000000..ee8aacf0
--- /dev/null
+++ b/x86_64/x86_64
@@ -0,0 +1 @@
+../i386/i386 \ No newline at end of file
diff --git a/x86_64/xen_boothdr.S b/x86_64/xen_boothdr.S
new file mode 100644
index 00000000..5208f627
--- /dev/null
+++ b/x86_64/xen_boothdr.S
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2006-2011 Free Software Foundation
+ *
+ * This program is free software ; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation ; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY ; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the program ; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <xen/public/elfnote.h>
+
+.section __xen_guest
+ .ascii "GUEST_OS=GNU Mach"
+ .ascii ",GUEST_VERSION=1.3"
+ .ascii ",XEN_VER=xen-3.0"
+ .ascii ",VIRT_BASE=0x40000000"
+ .ascii ",ELF_PADDR_OFFSET=0x40000000"
+ .ascii ",HYPERCALL_PAGE=0x2"
+ .ascii ",LOADER=generic"
+#ifndef MACH_PSEUDO_PHYS
+ .ascii ",FEATURES=!auto_translated_physmap"
+#endif
+#ifndef MACH_PV_PAGETABLES
+ .ascii "|!writable_page_tables"
+#endif /* MACH_PV_PAGETABLES */
+#ifndef MACH_PV_DESCRIPTORS
+ .ascii "|!writable_descriptor_tables"
+#endif /* MACH_PV_DESCRIPTORS */
+ .byte 0
+
+/* Macro taken from linux/include/linux/elfnote.h */
+#define ELFNOTE(name, type, desctype, descdata) \
+.pushsection .note.name ; \
+ .align 4 ; \
+ .long 2f - 1f /* namesz */ ; \
+ .long 4f - 3f /* descsz */ ; \
+ .long type ; \
+1:.asciz "name" ; \
+2:.align 4 ; \
+3:desctype descdata ; \
+4:.align 4 ; \
+.popsection ;
+
+ ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz, "GNU Mach")
+ ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION, .asciz, "1.3")
+ ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION, .asciz, "xen-3.0")
+ ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE, .quad, _START)
+ ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET, .quad, _START)
+ ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, .quad, start)
+ ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, .quad, hypcalls)
+ ELFNOTE(Xen, XEN_ELFNOTE_LOADER, .asciz, "generic")
+ ELFNOTE(Xen, XEN_ELFNOTE_FEATURES, .asciz, ""
+#ifndef MACH_PSEUDO_PHYS
+ "!auto_translated_physmap"
+#endif
+#ifndef MACH_PV_PAGETABLES
+ "|!writable_page_tables"
+#endif /* MACH_PV_PAGETABLES */
+#ifndef MACH_PV_DESCRIPTORS
+ "|!writable_descriptor_tables"
+#endif /* MACH_PV_DESCRIPTORS */
+ )
+
+#include <mach/machine/asm.h>
+
+#include <i386/i386/i386asm.h>
+
+ .text
+ .globl gdt, ldt
+ .globl start, _start, gdt
+start:
+_start:
+
+ /* Switch to our own interrupt stack. */
+ movq $(_intstack+INTSTACK_SIZE),%rax
+ andq $(~15),%rax
+ movq %rax,%rsp
+
+ /* Reset EFLAGS to a known state. */
+ pushq $0
+ popf
+
+ /* Push the start_info pointer to be the argument. */
+ movabs $KERNELBASE,%rax
+ subq %rax,%rsi
+ movq %rsi,%r8
+
+ /* Fix ifunc entries */
+ movq $__rela_iplt_start,%rsi
+ movq $__rela_iplt_end,%rdi
+iplt_cont:
+ cmpq %rdi,%rsi
+ jae iplt_done
+ movq (%rsi),%rbx /* r_offset */
+ movb 4(%rsi),%al /* info */
+ cmpb $42,%al /* IRELATIVE */
+ jnz iplt_next
+ call *(%ebx) /* call ifunc */
+ movq %rax,(%rbx) /* fixed address */
+iplt_next:
+ addq $8,%rsi
+ jmp iplt_cont
+iplt_done:
+
+ movq %r8,%rdi
+ /* Jump into C code. */
+ call EXT(c_boot_entry)
+
+/* Those need to be aligned on page boundaries. */
+.global hyp_shared_info, hypcalls
+
+ .org (start + 0x1000)
+hyp_shared_info:
+ .org hyp_shared_info + 0x1000
+
+/* Labels just for debuggers */
+#define hypcall(name, n) \
+ .org hypcalls + n*32 ; \
+.globl __hyp_##name ; \
+__hyp_##name:
+
+hypcalls:
+ hypcall(set_trap_table, 0)
+ hypcall(mmu_update, 1)
+ hypcall(set_gdt, 2)
+ hypcall(stack_switch, 3)
+ hypcall(set_callbacks, 4)
+ hypcall(fpu_taskswitch, 5)
+ hypcall(sched_op_compat, 6)
+ hypcall(platform_op, 7)
+ hypcall(set_debugreg, 8)
+ hypcall(get_debugreg, 9)
+ hypcall(update_descriptor, 10)
+ hypcall(memory_op, 12)
+ hypcall(multicall, 13)
+ hypcall(update_va_mapping, 14)
+ hypcall(set_timer_op, 15)
+ hypcall(event_channel_op_compat, 16)
+ hypcall(xen_version, 17)
+ hypcall(console_io, 18)
+ hypcall(physdev_op_compat, 19)
+ hypcall(grant_table_op, 20)
+ hypcall(vm_assist, 21)
+ hypcall(update_va_mapping_otherdomain, 22)
+ hypcall(iret, 23)
+ hypcall(vcpu_op, 24)
+ hypcall(set_segment_base, 25)
+ hypcall(mmuext_op, 26)
+ hypcall(acm_op, 27)
+ hypcall(nmi_op, 28)
+ hypcall(sched_op, 29)
+ hypcall(callback_op, 30)
+ hypcall(xenoprof_op, 31)
+ hypcall(event_channel_op, 32)
+ hypcall(physdev_op, 33)
+ hypcall(hvm_op, 34)
+ hypcall(sysctl, 35)
+ hypcall(domctl, 36)
+ hypcall(kexec_op, 37)
+
+ hypcall(arch_0, 48)
+ hypcall(arch_1, 49)
+ hypcall(arch_2, 50)
+ hypcall(arch_3, 51)
+ hypcall(arch_4, 52)
+ hypcall(arch_5, 53)
+ hypcall(arch_6, 54)
+ hypcall(arch_7, 55)
+
+ .org hypcalls + 0x1000
+
+gdt:
+ .org gdt + 0x1000
+
+ldt:
+ .org ldt + 0x1000
+
+stack:
+ .comm _intstack,INTSTACK_SIZE
+
diff --git a/x86_64/xen_locore.S b/x86_64/xen_locore.S
new file mode 100644
index 00000000..967c8904
--- /dev/null
+++ b/x86_64/xen_locore.S
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2006-2009 Free Software Foundation
+ *
+ * This program is free software ; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation ; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY ; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the program ; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <mach/machine/asm.h>
+
+#include <i386/i386/i386asm.h>
+#include <i386/i386/cpu_number.h>
+#include <i386/i386/xen.h>
+
+ .data 2
+int_active:
+ .long 0
+
+
+ .text
+ .globl hyp_callback, hyp_failsafe_callback
+ P2ALIGN(TEXT_ALIGN)
+hyp_callback:
+ popq %rcx
+ popq %r11
+ pushq %rax
+ jmp EXT(all_intrs)
+
+ENTRY(interrupt)
+ incl int_active /* currently handling interrupts */
+ call EXT(hyp_c_callback) /* call generic interrupt routine */
+ decl int_active /* stopped handling interrupts */
+ sti
+ ret
+
+/* FIXME: if we're _very_ unlucky, we may be re-interrupted, filling stack
+ *
+ * Far from trivial, see mini-os. That said, maybe we could just, before poping
+ * everything (which is _not_ destructive), save sp into a known place and use
+ * it+jmp back?
+ *
+ * Mmm, there seems to be an iret hypcall that does exactly what we want:
+ * perform iret, and if IF is set, clear the interrupt mask.
+ */
+
+/* Pfff, we have to check pending interrupts ourselves. Some other DomUs just make an hypercall for retriggering the irq. Not sure it's really easier/faster */
+ENTRY(hyp_sti)
+ pushq %rbp
+ movq %rsp, %rbp
+_hyp_sti:
+ movb $0,hyp_shared_info+CPU_CLI /* Enable interrupts */
+ cmpl $0,int_active /* Check whether we were already checking pending interrupts */
+ jz 0f
+ popq %rbp
+ ret /* Already active, just return */
+0:
+ /* Not active, check pending interrupts by hand */
+ /* no memory barrier needed on x86 */
+ cmpb $0,hyp_shared_info+CPU_PENDING
+ jne 0f
+ popq %rbp
+ ret
+0:
+ movb $0xff,hyp_shared_info+CPU_CLI
+1:
+ pushq %rax
+ pushq %rcx
+ pushq %rdx
+ pushq %rdi
+ pushq %rsi
+ pushq %r8
+ pushq %r9
+ pushq %r10
+ pushq %r11
+ incl int_active /* currently handling interrupts */
+
+ xorq %rdi,%rdi
+ xorq %rsi,%rsi
+ call EXT(hyp_c_callback)
+
+ popq %r11
+ popq %r10
+ popq %r9
+ popq %r8
+ popq %rsi
+ popq %rdi
+ popq %rdx
+ popq %rcx
+ popq %rax
+ decl int_active /* stopped handling interrupts */
+ cmpb $0,hyp_shared_info+CPU_PENDING
+ jne 1b
+ jmp _hyp_sti
+
+/* Hypervisor failed to reload segments. Dump them. */
+hyp_failsafe_callback:
+ud2
+#if 1
+/* TODO: FIXME */
+ /* load sane segments */
+ mov %ss, %ax
+#if 0
+ mov %ax, %ds
+ mov %ax, %es
+#endif
+ mov %ax, %fs
+ mov %ax, %gs
+ movq %rsp, %rdi
+ call EXT(hyp_failsafe_c_callback)
+#else
+ popq %rdx
+ movq %rdx,%ds
+ popq %rdx
+ movq %rdx,%es
+ popq %fs
+ popq %gs
+
+movq (%rsp),%rax
+ud2
+ iretq
+#endif
+
+#undef iretq
+ENTRY(hyp_iretq)
+ testb $2,1*8(%rsp)
+ jnz slow
+ /* There is no ring1 on x86_64, we have to force ring 3 */
+ orb $3,1*8(%rsp)
+ orb $3,4*8(%rsp)
+ iretq
+
+slow:
+/* There is no ring 1/2 on x86_64, so going back to user needs to go through
+ * hypervisor */
+ pushq $0
+ jmp __hyp_iret
diff --git a/xen/console.c b/xen/console.c
index e5aeb186..4907903e 100644
--- a/xen/console.c
+++ b/xen/console.c
@@ -16,6 +16,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <i386at/kd.h>
#include <sys/types.h>
#include <device/tty.h>
#include <device/cons.h>
diff --git a/xen/evt.c b/xen/evt.c
index 2a84ef77..296101aa 100644
--- a/xen/evt.c
+++ b/xen/evt.c
@@ -95,13 +95,18 @@ void hyp_intrinit() {
form_int_mask();
curr_ipl = SPLHI;
hyp_shared_info.evtchn_mask[0] = int_mask[SPLHI];
+#ifdef __i386__
hyp_set_callbacks(KERNEL_CS, hyp_callback,
KERNEL_CS, hyp_failsafe_callback);
+#endif
+#ifdef __x86_64__
+ hyp_set_callbacks(hyp_callback, hyp_failsafe_callback, NULL);
+#endif
}
void hyp_evt_handler(evtchn_port_t port, void (*handler)(), int unit, spl_t spl) {
if (port > NEVNT)
- panic("event channel port %d > %d not supported\n", port, NEVNT);
+ panic("event channel port %d > %d not supported\n", port, (int) NEVNT);
intpri[port] = spl;
iunit[port] = unit;
form_int_mask();
diff --git a/xen/grant.c b/xen/grant.c
index ae3a7bfc..1d6e607b 100644
--- a/xen/grant.c
+++ b/xen/grant.c
@@ -16,6 +16,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <machine/model_dep.h>
#include <sys/types.h>
#include <mach/vm_param.h>
#include <machine/spl.h>
@@ -99,7 +100,7 @@ void hyp_grant_takeback(grant_ref_t grant) {
simple_lock(&lock);
if (grants[grant].flags & (GTF_reading|GTF_writing))
- panic("grant %d still in use (%lx)\n", grant, grants[grant].flags);
+ panic("grant %d still in use (%x)\n", grant, grants[grant].flags);
/* Note: this is not safe, a cmpxchg is needed, see grant_table.h */
grants[grant].flags = 0;
@@ -128,7 +129,7 @@ void hyp_grant_init(void) {
ret = hyp_grant_table_op(GNTTABOP_setup_table, kvtolin(&setup), 1);
if (ret)
- panic("setup grant table error %d", ret);
+ panic("setup grant table error %ld", ret);
if (setup.status)
panic("setup grant table: %d\n", setup.status);
diff --git a/xen/net.c b/xen/net.c
index 11121387..ac8c9b1f 100644
--- a/xen/net.c
+++ b/xen/net.c
@@ -30,6 +30,7 @@
#include <device/device_reply.user.h>
#include <device/device_emul.h>
#include <device/ds_routines.h>
+#include <device/subrs.h>
#include <intel/pmap.h>
#include <xen/public/io/netif.h>
#include <xen/public/memory.h>
@@ -46,10 +47,7 @@
/* Hypervisor part */
#define ADDRESS_SIZE 6
-#define WINDOW __RING_SIZE((netif_rx_sring_t*)0, PAGE_SIZE)
-
-/* Are we paranoid enough to not leak anything to backend? */
-static const int paranoia = 0;
+#define WINDOW __CONST_RING_SIZE(netif_rx, PAGE_SIZE)
struct net_data {
struct device device;
@@ -186,7 +184,7 @@ static void hyp_net_intr(int unit) {
simple_lock(&nd->lock);
if ((nd->rx.sring->rsp_prod - nd->rx.rsp_cons) >= (WINDOW*3)/4)
- printf("window %ld a bit small!\n", WINDOW);
+ printf("window %ld a bit small!\n", (long) WINDOW);
more = RING_HAS_UNCONSUMED_RESPONSES(&nd->rx);
while (more) {
@@ -458,7 +456,7 @@ void hyp_net_init(void) {
c = hyp_store_write(0, hyp_store_state_connected, 5, VIF_PATH, "/", nd->vif, "/", "state");
if (!c)
- panic("couldn't store state for eth%d (%s)", nd - vif_data, hyp_store_error);
+ panic("couldn't store state for eth%d (%s)", (int) (nd - vif_data), hyp_store_error);
kfree((vm_offset_t) c, strlen(c)+1);
while(1) {
@@ -478,7 +476,7 @@ void hyp_net_init(void) {
nd->rx_buf_pfn[i] = atop(addr);
if (!nd->rx_copy) {
if (hyp_do_update_va_mapping(kvtolin(nd->rx_buf[i]), 0, UVMF_INVLPG|UVMF_ALL))
- panic("eth: couldn't clear rx kv buf %d at %p", i, addr);
+ panic("eth: couldn't clear rx kv buf %d at %lx", i, addr);
}
/* and enqueue it to backend. */
enqueue_rx_buf(nd, i);
@@ -526,8 +524,8 @@ device_close(void *devp)
{
struct net_data *nd = devp;
if (--nd->open_count < 0)
- panic("too many closes on eth%d", nd - vif_data);
- printf("close, eth%d count %d\n",nd-vif_data,nd->open_count);
+ panic("too many closes on eth%d", (int) (nd - vif_data));
+ printf("close, eth%d count %d\n", (int) (nd - vif_data), nd->open_count);
if (nd->open_count)
return 0;
ipc_kobject_set(nd->port, IKO_NULL, IKOT_NONE);
@@ -560,12 +558,12 @@ device_open (ipc_port_t reply_port, mach_msg_type_name_t reply_port_type,
if (nd->open_count >= 0) {
*devp = &nd->device ;
nd->open_count++ ;
- printf("re-open, eth%d count %d\n",nd-vif_data,nd->open_count);
+ printf("re-open, eth%d count %d\n", (int) (nd - vif_data), nd->open_count);
return D_SUCCESS;
}
nd->open_count = 1;
- printf("eth%d count %d\n",nd-vif_data,nd->open_count);
+ printf("eth%d count %d\n", (int) (nd - vif_data), nd->open_count);
port = ipc_port_alloc_kernel();
if (port == IP_NULL) {
diff --git a/xen/public/io/ring.h b/xen/public/io/ring.h
index 6ce1d0d4..8669564b 100644
--- a/xen/public/io/ring.h
+++ b/xen/public/io/ring.h
@@ -50,6 +50,12 @@ typedef unsigned int RING_IDX;
* A ring contains as many entries as will fit, rounded down to the nearest
* power of two (so we can mask with (size-1) to loop around).
*/
+#define __CONST_RING_SIZE(_s, _sz) \
+ (__RD32(((_sz) - offsetof(struct _s##_sring, ring)) / \
+ sizeof(((struct _s##_sring *)0)->ring[0])))
+/*
+ * The same for passing in an actual pointer instead of a name tag.
+ */
#define __RING_SIZE(_s, _sz) \
(__RD32(((_sz) - (long)(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0])))
diff --git a/xen/store.c b/xen/store.c
index 659a70c7..23cbc223 100644
--- a/xen/store.c
+++ b/xen/store.c
@@ -62,7 +62,7 @@ static void store_put(hyp_store_transaction_t t, uint32_t type, struct store_req
totlen += sizeof(head);
if (totlen > sizeof(store->req) - 1)
- panic("too big store message %d, max %d", totlen, sizeof(store->req));
+ panic("too big store message %d, max %d", totlen, (int) sizeof(store->req));
while (hyp_ring_available(store->req, store->req_prod, store->req_cons) < totlen)
hyp_yield();
diff --git a/xen/time.c b/xen/time.c
index d483405a..e8abd56b 100644
--- a/xen/time.c
+++ b/xen/time.c
@@ -25,6 +25,7 @@
#include <machine/ipl.h>
#include <mach/machine/eflags.h>
#include <xen/evt.h>
+#include "xen.h"
#include "time.h"
#include "store.h"
@@ -110,14 +111,11 @@ static void hypclock_intr(int unit, int old_ipl, void *ret_addr, struct i386_int
#endif
}
-extern struct timeval time;
-
int
-readtodc(tp)
- u_int *tp;
+readtodc(uint64_t *tp)
{
uint64_t t = hyp_get_time();
- u_int n = t / 1000000000;
+ uint64_t n = t / 1000000000;
*tp = n;
diff --git a/xen/xen.h b/xen/xen.h
index f0a3abb9..cbb793e2 100644
--- a/xen/xen.h
+++ b/xen/xen.h
@@ -24,4 +24,6 @@ void hyp_dev_init(void);
void hyp_idle(void);
void hyp_p2m_init(void);
+void hypclock_machine_intr(int old_ipl, void *ret_addr, struct i386_interrupt_state *regs, uint64_t delta);
+
#endif /* XEN_XEN_H */