bitkeeper revision 1.478.1.1 (3f815149k7sE-z_IK6MG5eHi34m-Qg)

Minimal guest OS (based on some old code from Keir)
This commit is contained in:
rneugeba@wyvis.research committed 2003-10-06 11:26:01 +00:00
1 parent 922fddb035
commit f2c4c1d4e8
26 files changed
+9357

No files matched your search

+8
View File
@@ -1,5 +1,13 @@
#!/bin/sh -x
set -e
test -L mini-os/h/hypervisor-ifs/block.h
rm mini-os/h/hypervisor-ifs/block.h
test -L mini-os/h/hypervisor-ifs/hypervisor-if.h
rm mini-os/h/hypervisor-ifs/hypervisor-if.h
test -L mini-os/h/hypervisor-ifs/kbd.h
rm mini-os/h/hypervisor-ifs/kbd.h
test -L mini-os/h/hypervisor-ifs/network.h
rm mini-os/h/hypervisor-ifs/network.h
test -L xenolinux-sparse
rm xenolinux-sparse
(find -depth -type d -print | xargs -r rmdir 2>/dev/null) || true
+7
View File
@@ -1,5 +1,12 @@
#!/bin/sh -x
set -e
mkdir -p mini-os
mkdir -p mini-os/h
mkdir -p mini-os/h/hypervisor-ifs
ln -s ../../../xen/include/hypervisor-ifs/block.h mini-os/h/hypervisor-ifs/block.h
ln -s ../../../xen/include/hypervisor-ifs/hypervisor-if.h mini-os/h/hypervisor-ifs/hypervisor-if.h
ln -s ../../../xen/include/hypervisor-ifs/kbd.h mini-os/h/hypervisor-ifs/kbd.h
ln -s ../../../xen/include/hypervisor-ifs/network.h mini-os/h/hypervisor-ifs/network.h
ln -s xenolinux-2.4.22-sparse xenolinux-sparse
(find -depth -type d -print | xargs -r rmdir 2>/dev/null) || true
exit 0
+27
View File
@@ -6,6 +6,33 @@
3f5ef5a24IaQasQE2tyMxrfxskMmvw README
3f5ef5a2l4kfBYSQTUaOyyD76WROZQ README.CD
3f69d8abYB1vMyD_QVDvzxy5Zscf1A TODO
3f815144d1vI2777JI-dO4wk49Iw7g mini-os/Makefile
3f815144zTnCV5591ulIJQrpe5b-5Q mini-os/README
3f815144wiiDekmfMl9LIPIvhR83Uw mini-os/entry.S
3f815144r7AHj8GPvc3Nl1L9OSsWIg mini-os/events.c
3f815144h-Chna6E38yo40jqU95G1Q mini-os/h/events.h
3f815144oqr2OlUDzE2GfkKX5Hcxqg mini-os/h/hypervisor-ifs/block.h
3f8151443nGXvfUTFG67VXOIH8P4lg mini-os/h/hypervisor-ifs/hypervisor-if.h
3f81514417ZlYqiRdM_AHPy7G11htA mini-os/h/hypervisor-ifs/kbd.h
3f815144J3ZfU5am03Td7Wjfrz30qQ mini-os/h/hypervisor-ifs/network.h
3f8151445bYdgThGHQPeOW49PsrJ_A mini-os/h/hypervisor.h
3f815144f2Vg3qb6tiwt2VZad-DWsg mini-os/h/lib.h
3f815144iqXtdYup_pyfPSmDZuvZcg mini-os/h/list.h
3f81514437EzzRWAnZl4_Ej1oznMjg mini-os/h/mm.h
3f815144nbSjjT1h4m99-QPbeSWY0Q mini-os/h/os.h
3f815144L1t0AevJt2JDXPegv6JTrw mini-os/h/time.h
3f815144UxddtL0ICCKisN-NDHNFaA mini-os/h/types.h
3f815145W2mamPMclRLOzm5B38vWUQ mini-os/head.S
3f815145LqcH11TCEZbAvcjarckkJw mini-os/hypervisor.c
3f815145vwnmxhCwN7dMRWv_XFtXbg mini-os/kernel.c
3f8151451k5emQAlRe80JdIvfSN4VA mini-os/lib/malloc.c
3f815145Mb9WSKjOPsYTLsPIvPyy4Q mini-os/lib/math.c
3f8151454rEuPjN74V2Bcu65RLnM-Q mini-os/lib/printf.c
3f815145MQZrUJV0iRmTK2KIhwB2wg mini-os/lib/string.c
3f815145CB8XdPUqsmhAjSDFuwOoqA mini-os/mm.c
3f815145vGYx1WY79voKkZB9yKwJKQ mini-os/time.c
3f815145xlKBAQmal9oces3G_Mvxqw mini-os/traps.c
3f815145AYE58Kpmsj5U7oHDpVDZJA mini-os/vmlinux.lds
3f776bd1Hy9rn69ntXBhPReUFw9IEA tools/Makefile
3e6377b24eQqYMsDi9XrFkIgTzZ47A tools/balloon/Makefile
3e6377d6eiFjF1hHIS6JEIOFk62xSA tools/balloon/README
+40
View File
@@ -0,0 +1,40 @@
CC := gcc
LD := ld
# Linker should relocate monitor to this address
MONITOR_BASE := 0xE0100000
CFLAGS := -fno-builtin -O3 -Wall -Ih/
TARGET := image.final
LOBJS:= lib/malloc.o lib/math.o lib/printf.o lib/string.o
OBJS := entry.o kernel.o traps.o hypervisor.o mm.o events.o time.o ${LOBJS}
HINTF := h/hypervisor-ifs/hypervisor-if.h
HDRS := h/os.h h/types.h h/hypervisor.h h/mm.h h/events.h h/time.h h/lib.h $(HINTF)
default: $(TARGET)
$(TARGET): head.o $(OBJS)
# Image will load at 0xC0000000. First bytes from head.o
#$(LD) -N -Ttext 0xC0000000 head.o $(OBJS) -o image.elf
$(LD) -N -T vmlinux.lds head.o $(OBJS) -o image.elf
# Guest OS header -- first 8 bytes are identifier 'XenoGues'.
echo -e -n 'XenoGues' >$@
# Guest OS header -- next 4 bytes are load address (0xC0000000).
echo -e -n '\000\000\000\300' >>$@
# Create a raw bag of bytes from the ELF image.
objcopy -O binary -R .note -R .comment image.elf image.raw
# Guest OS header is immediately followed by raw OS image.
cat image.raw >>$@
#gzip -f -9 $@
clean:
rm -f *.o *~ core image.elf image.raw image.final image.final.gz
%.o: %.c $(HDRS) Makefile
$(CC) $(CFLAGS) -c $< -o $@
%.o: %.S $(HDRS) Makefile
$(CC) $(CFLAGS) -D__ASSEMBLY__ -c $< -o $@
+35
View File
@@ -0,0 +1,35 @@
Minimal OS
----------
This shows some of the stuff that any guest OS will have to set up.
This includes:
* installing a virtual exception table
* handling virtual exceptions
* handling asynchronous events
* enabling/disabling async events
* parsing start_info struct at start-of-day
* registering virtual interrupt handlers (for timer interrupts)
* a simple page and memory allocator
* minimal libc support
Stuff it doesn't show:
* modifying page tables
* network code
* block-device code
- to build it just type make.
- copy image.final somewhere where dom0 can access it
- in dom0
# xi_create 16000 test
<domid>
# xi_build <domid> image.final 0
# xi_start <domid>
this prints out a bunch of stuff and then every 1000 timer interrupts the
system time.
+348
View File
@@ -0,0 +1,348 @@
/*
* linux/arch/i386/entry.S
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* Adjusted for XenoLinux use by K A Frasier
* Adjusted for Xen minimal os by R Neugebauer
*/
#include <os.h>
EBX = 0x00
ECX = 0x04
EDX = 0x08
ESI = 0x0C
EDI = 0x10
EBP = 0x14
EAX = 0x18
DS = 0x1C
ES = 0x20
ORIG_EAX = 0x24
EIP = 0x28
CS = 0x2C
EFLAGS = 0x30
OLDESP = 0x34
OLDSS = 0x38
CF_MASK = 0x00000001
IF_MASK = 0x00000200
NT_MASK = 0x00004000
/* Declare a globally-visible label */
#define ENTRY(X) .globl X ; X :
/* A Linux hangover. Just ignore it. */
#define SYMBOL_NAME(X) X
#define SAVE_ALL \
cld; \
pushl %es; \
pushl %ds; \
pushl %eax; \
pushl %ebp; \
pushl %edi; \
pushl %esi; \
pushl %edx; \
pushl %ecx; \
pushl %ebx; \
movl $(__KERNEL_DS),%edx; \
movl %edx,%ds; \
movl %edx,%es;
#define RESTORE_ALL \
popl %ebx; \
popl %ecx; \
popl %edx; \
popl %esi; \
popl %edi; \
popl %ebp; \
popl %eax; \
1: popl %ds; \
2: popl %es; \
addl $4,%esp; \
3: iret; \
.section .fixup,"ax"; \
4: movl $0,(%esp); \
jmp 1b; \
5: movl $0,(%esp); \
jmp 2b; \
6: pushl %ss; \
popl %ds; \
pushl %ss; \
popl %es; \
pushl $11; \
call do_exit; \
.previous; \
.section __ex_table,"a";\
.align 4; \
.long 1b,4b; \
.long 2b,5b; \
.long 3b,6b; \
.previous
ENTRY(divide_error)
pushl $0 # no error code
pushl $ SYMBOL_NAME(do_divide_error)
.align 4
error_code:
pushl %ds
pushl %eax
xorl %eax,%eax
pushl %ebp
pushl %edi
pushl %esi
pushl %edx
decl %eax # eax = -1
pushl %ecx
pushl %ebx
cld
movl %es,%ecx
movl ORIG_EAX(%esp), %esi # get the error code
movl ES(%esp), %edi # get the function address
movl %eax, ORIG_EAX(%esp)
movl %ecx, ES(%esp)
movl %esp,%edx
pushl %esi # push the error code
pushl %edx # push the pt_regs pointer
movl $(__KERNEL_DS),%edx
movl %edx,%ds
movl %edx,%es
call *%edi
addl $8,%esp
# These are the tests Linux makes before exiting the OS back to userland.
# At these point preeemption may occur, or signals may get delivered.
ret_to_user_tests:
# cmpl $0,need_resched(%ebx)
# jne reschedule
# cmpl $0,sigpending(%ebx)
# je safesti
jmp safesti
ret_from_exception:
movb CS(%esp),%cl
test $2,%cl # slow return to ring 2 or 3
jne ret_to_user_tests
RESTORE_ALL
# A note on the "critical region" in our callback handler.
# We want to avoid stacking callback handlers due to events occurring
# during handling of the last event. To do this, we keep events disabled
# until weve done all processing. HOWEVER, we must enable events before
# popping the stack frame (cant be done atomically) and so it would still
# be possible to get enough handler activations to overflow the stack.
# Although unlikely, bugs of that kind are hard to track down, so wed
# like to avoid the possibility.
# So, on entry to the handler we detect whether we interrupted an
# existing activation in its critical region -- if so, we pop the current
# activation and restart the handler using the previous one.
ENTRY(hypervisor_callback)
pushl %eax
SAVE_ALL
movl EIP(%esp),%eax
cmpl $scrit,%eax
jb 11f
cmpl $ecrit,%eax
jb critical_region_fixup
11: push %esp
call do_hypervisor_callback
add $4,%esp
movl SYMBOL_NAME(HYPERVISOR_shared_info),%esi
xorl %eax,%eax
movb CS(%esp),%cl
test $2,%cl # slow return to ring 2 or 3
jne ret_to_user_tests
safesti:btsl $31,4(%esi) # reenable event callbacks
scrit: /**** START OF CRITICAL REGION ****/
cmpl %eax,(%esi)
jne 14f # process more events if necessary...
RESTORE_ALL
14: btrl %eax,4(%esi)
jmp 11b
ecrit: /**** END OF CRITICAL REGION ****/
# [How we do the fixup]. We want to merge the current stack frame with the
# just-interrupted frame. How we do this depends on where in the critical
# region the interrupted handler was executing, and so how many saved
# registers are in each frame. We do this quickly using the lookup table
# 'critical_fixup_table'. For each byte offset in the critical region, it
# provides the number of bytes which have already been popped from the
# interrupted stack frame.
critical_region_fixup:
addl $critical_fixup_table-scrit,%eax
movzbl (%eax),%eax # %eax contains num bytes popped
mov %esp,%esi
add %eax,%esi # %esi points at end of src region
mov %esp,%edi
add $0x34,%edi # %edi points at end of dst region
mov %eax,%ecx
shr $2,%ecx # convert words to bytes
je 16f # skip loop if nothing to copy
15: subl $4,%esi # pre-decrementing copy loop
subl $4,%edi
movl (%esi),%eax
movl %eax,(%edi)
loop 15b
16: movl %edi,%esp # final %edi is top of merged stack
jmp 11b
critical_fixup_table:
.byte 0x00,0x00 # cmpl %eax,(%esi)
.byte 0x00,0x00 # jne 14f
.byte 0x00 # pop %ebx
.byte 0x04 # pop %ecx
.byte 0x08 # pop %edx
.byte 0x0c # pop %esi
.byte 0x10 # pop %edi
.byte 0x14 # pop %ebp
.byte 0x18 # pop %eax
.byte 0x1c # pop %ds
.byte 0x20 # pop %es
.byte 0x24,0x24,0x24 # add $4,%esp
.byte 0x28 # iret
.byte 0x00,0x00,0x00,0x00,0x00 # btrl $31,4(%esi)
.byte 0x00,0x00 # jmp 11b
# Hypervisor uses this for application faults while it executes.
ENTRY(failsafe_callback)
1: pop %ds
2: pop %es
3: pop %fs
4: pop %gs
5: iret
.section .fixup,"ax"; \
6: movl $0,(%esp); \
jmp 1b; \
7: movl $0,(%esp); \
jmp 2b; \
8: movl $0,(%esp); \
jmp 3b; \
9: movl $0,(%esp); \
jmp 4b; \
10: pushl %ss; \
popl %ds; \
pushl %ss; \
popl %es; \
pushl $11; \
call do_exit; \
.previous; \
.section __ex_table,"a";\
.align 4; \
.long 1b,6b; \
.long 2b,7b; \
.long 3b,8b; \
.long 4b,9b; \
.long 5b,10b; \
.previous
ENTRY(coprocessor_error)
pushl $0
pushl $ SYMBOL_NAME(do_coprocessor_error)
jmp error_code
ENTRY(simd_coprocessor_error)
pushl $0
pushl $ SYMBOL_NAME(do_simd_coprocessor_error)
jmp error_code
ENTRY(device_not_available)
pushl $-1 # mark this as an int
SAVE_ALL
#call SYMBOL_NAME(math_state_restore)
jmp ret_from_exception
ENTRY(debug)
pushl $0
pushl $ SYMBOL_NAME(do_debug)
jmp error_code
ENTRY(int3)
pushl $0
pushl $ SYMBOL_NAME(do_int3)
jmp error_code
ENTRY(overflow)
pushl $0
pushl $ SYMBOL_NAME(do_overflow)
jmp error_code
ENTRY(bounds)
pushl $0
pushl $ SYMBOL_NAME(do_bounds)
jmp error_code
ENTRY(invalid_op)
pushl $0
pushl $ SYMBOL_NAME(do_invalid_op)
jmp error_code
ENTRY(coprocessor_segment_overrun)
pushl $0
pushl $ SYMBOL_NAME(do_coprocessor_segment_overrun)
jmp error_code
ENTRY(double_fault)
pushl $ SYMBOL_NAME(do_double_fault)
jmp error_code
ENTRY(invalid_TSS)
pushl $ SYMBOL_NAME(do_invalid_TSS)
jmp error_code
ENTRY(segment_not_present)
pushl $ SYMBOL_NAME(do_segment_not_present)
jmp error_code
ENTRY(stack_segment)
pushl $ SYMBOL_NAME(do_stack_segment)
jmp error_code
ENTRY(general_protection)
pushl $ SYMBOL_NAME(do_general_protection)
jmp error_code
ENTRY(alignment_check)
pushl $ SYMBOL_NAME(do_alignment_check)
jmp error_code
# This handler is special, because it gets an extra value on its stack,
# which is the linear faulting address.
ENTRY(page_fault)
pushl %ds
pushl %eax
xorl %eax,%eax
pushl %ebp
pushl %edi
pushl %esi
pushl %edx
decl %eax # eax = -1
pushl %ecx
pushl %ebx
cld
movl %es,%ecx
movl ORIG_EAX(%esp), %esi # get the error code
movl ES(%esp), %edi # get the faulting address
movl %eax, ORIG_EAX(%esp)
movl %ecx, ES(%esp)
movl %esp,%edx
pushl %edi # push the faulting address
pushl %esi # push the error code
pushl %edx # push the pt_regs pointer
movl $(__KERNEL_DS),%edx
movl %edx,%ds
movl %edx,%es
call SYMBOL_NAME(do_page_fault)
addl $12,%esp
jmp ret_from_exception
ENTRY(machine_check)
pushl $0
pushl $ SYMBOL_NAME(do_machine_check)
jmp error_code
ENTRY(spurious_interrupt_bug)
pushl $0
pushl $ SYMBOL_NAME(do_spurious_interrupt_bug)
jmp error_code
+106
View File
@@ -0,0 +1,106 @@
/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
****************************************************************************
* (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
****************************************************************************
*
* File: events.c
* Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
* Changes:
*
* Date: Jul 2003
*
* Environment: Xen Minimal OS
* Description: Deal with events
*
****************************************************************************
* $Id: c-insert.c,v 1.7 2002/11/08 16:04:34 rn Exp $
****************************************************************************
*/
#include <os.h>
#include <hypervisor.h>
#include <events.h>
#include <lib.h>
static ev_action_t ev_actions[NR_EVS];
void default_handler(int ev, struct pt_regs *regs);
/*
* demux events to different handlers
*/
asmlinkage unsigned int do_event(int ev, struct pt_regs *regs)
{
ev_action_t *action;
if (ev >= NR_EVS) {
printk("Large event number %d\n", ev);
return 0;
}
action = &ev_actions[ev];
action->count++;
ack_hypervisor_event(ev);
if (!action->handler)
goto out;
if (action->status & EVS_DISABLED)
goto out;
/* call the handler */
action->handler(ev, regs);
out:
return 1;
}
/*
* add a handler
*/
unsigned int add_ev_action( int ev, void (*handler)(int, struct pt_regs *) )
{
if (ev_actions[ev].handler) {
printk ("event[%d] already handled by %p", ev, ev_actions[ev].handler);
return 0;
}
ev_actions[ev].handler = handler;
return 1;
}
unsigned int enable_ev_action( int ev )
{
if (!ev_actions[ev].handler) {
printk ("enable event[%d], no handler installed", ev);
return 0;
}
ev_actions[ev].status &= ~EVS_DISABLED;
return 1;
}
unsigned int disable_ev_action( int ev )
{
ev_actions[ev].status |= EVS_DISABLED;
return 1;
}
/*
* initially all events are without a handler and disabled
*/
void init_events(void)
{
int i;
/* inintialise event handler */
for ( i = 0; i < NR_EVS; i++ )
{
ev_actions[i].status = EVS_DISABLED;
ev_actions[i].handler = NULL;
}
}
void default_handler(int ev, struct pt_regs *regs) {
printk("X[%d] ", ev);
}
+53
View File
@@ -0,0 +1,53 @@
/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
****************************************************************************
* (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
****************************************************************************
*
* File: events.h
* Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
* Changes:
*
* Date: Jul 2003
*
* Environment: Xen Minimal OS
* Description: deal with events
*
****************************************************************************
* $Id: h-insert.h,v 1.4 2002/11/08 16:03:55 rn Exp $
****************************************************************************
*/
#ifndef _EVENTS_H_
#define _EVENTS_H_
/* _EVENT_* are defined in hypervisor-if.h */
#define EV_BLKDEV _EVENT_BLKDEV
#define EV_TIMER _EVENT_TIMER
#define EV_DIE _EVENT_DIE
#define EV_DEBUG _EVENT_DEBUG
#define EV_NET _EVENT_NET
#define EV_PS2 _EVENT_PS2
#define NR_EVS (sizeof(HYPERVISOR_shared_info->events) * 8)
/* ev handler status */
#define EVS_INPROGRESS 1 /* Event handler active - do not enter! */
#define EVS_DISABLED 2 /* Event disabled - do not enter! */
#define EVS_PENDING 4 /* Event pending - replay on enable */
#define EVS_REPLAY 8 /* Event has been replayed but not acked yet */
/* this represents a event handler. Chaining or sharing is not allowed */
typedef struct _ev_action_t {
void (*handler)(int, struct pt_regs *);
unsigned int status; /* IRQ status */
u32 count;
} ev_action_t;
/* prototypes */
unsigned int do_event(int ev, struct pt_regs *regs);
unsigned int add_ev_action( int ev, void (*handler)(int, struct pt_regs *) );
unsigned int enable_ev_action( int ev );
unsigned int disable_ev_action( int ev );
void init_events(void);
#endif /* _EVENTS_H_ */
+266
View File
@@ -0,0 +1,266 @@
/******************************************************************************
* hypervisor.h
*
* Linux-specific hypervisor handling.
*
* Adjusted by R Neugebauer for Xen minimal OS
*
* Copyright (c) 2002, K A Fraser
*/
#ifndef _HYPERVISOR_H_
#define _HYPERVISOR_H_
#include <types.h>
/* include the hypervisor interface */
#include <hypervisor-ifs/network.h>
#include <hypervisor-ifs/block.h>
#include <hypervisor-ifs/hypervisor-if.h>
/*
* a placeholder for the start of day information passed up from the hypervisor
*/
union start_info_union
{
start_info_t start_info;
char padding[512];
};
extern union start_info_union start_info_union;
#define start_info (start_info_union.start_info)
/* hypervisor.c */
void do_hypervisor_callback(struct pt_regs *regs);
void enable_hypervisor_event(unsigned int ev);
void disable_hypervisor_event(unsigned int ev);
void ack_hypervisor_event(unsigned int ev);
/*
* Assembler stubs for hyper-calls.
*/
static inline int HYPERVISOR_set_trap_table(trap_info_t *table)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_set_trap_table),
"b" (table) );
return ret;
}
static inline int HYPERVISOR_pt_update(page_update_request_t *req, int count)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_pt_update),
"b" (req), "c" (count) );
return ret;
}
static inline int HYPERVISOR_console_write(const char *str, int count)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_console_write),
"b" (str), "c" (count) );
return ret;
}
static inline int HYPERVISOR_set_gdt(unsigned long *frame_list, int entries)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_set_gdt),
"b" (frame_list), "c" (entries) );
return ret;
}
static inline int HYPERVISOR_stack_switch(unsigned long ss, unsigned long esp)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_stack_switch),
"b" (ss), "c" (esp) : "memory" );
return ret;
}
static inline int HYPERVISOR_set_callbacks(
unsigned long event_selector, unsigned long event_address,
unsigned long failsafe_selector, unsigned long failsafe_address)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_set_callbacks),
"b" (event_selector), "c" (event_address),
"d" (failsafe_selector), "S" (failsafe_address) : "memory" );
return ret;
}
static inline int HYPERVISOR_net_update(void)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_net_update) );
return ret;
}
static inline int HYPERVISOR_fpu_taskswitch(void)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_fpu_taskswitch) );
return ret;
}
static inline int HYPERVISOR_yield(void)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_yield) );
return ret;
}
static inline int HYPERVISOR_exit(void)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_exit) );
return ret;
}
static inline int HYPERVISOR_dom0_op(void *dom0_op)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_dom0_op),
"b" (dom0_op) : "memory" );
return ret;
}
static inline int HYPERVISOR_network_op(void *network_op)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_network_op),
"b" (network_op) );
return ret;
}
static inline int HYPERVISOR_block_io_op(void)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_block_io_op) );
return ret;
}
static inline int HYPERVISOR_set_debugreg(int reg, unsigned long value)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_set_debugreg),
"b" (reg), "c" (value) );
return ret;
}
static inline unsigned long HYPERVISOR_get_debugreg(int reg)
{
unsigned long ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_get_debugreg),
"b" (reg) );
return ret;
}
static inline int HYPERVISOR_update_descriptor(
unsigned long pa, unsigned long word1, unsigned long word2)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_update_descriptor),
"b" (pa), "c" (word1), "d" (word2) );
return ret;
}
static inline int HYPERVISOR_set_fast_trap(int idx)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_set_fast_trap),
"b" (idx) );
return ret;
}
static inline int HYPERVISOR_dom_mem_op(void *dom_mem_op)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_dom_mem_op),
"b" (dom_mem_op) : "memory" );
return ret;
}
static inline int HYPERVISOR_multicall(void *call_list, int nr_calls)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_multicall),
"b" (call_list), "c" (nr_calls) : "memory" );
return ret;
}
static inline long HYPERVISOR_kbd_op(unsigned char op, unsigned char val)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_kbd_op),
"b" (op), "c" (val) );
return ret;
}
#endif /* __HYPERVISOR_H__ */
+129
View File
@@ -0,0 +1,129 @@
/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
****************************************************************************
* (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
****************************************************************************
*
* File: lib.h
* Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
* Changes:
*
* Date: Aug 2003
*
* Environment: Xen Minimal OS
* Description: Random useful library functions, contains some freebsd stuff
*
****************************************************************************
* $Id: h-insert.h,v 1.4 2002/11/08 16:03:55 rn Exp $
****************************************************************************
*
*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)stdarg.h 8.1 (Berkeley) 6/10/93
* $FreeBSD: src/sys/i386/include/stdarg.h,v 1.10 1999/08/28 00:44:26 peter Exp $
*/
#ifndef _LIB_H_
#define _LIB_H_
/* variadic function support */
typedef char *va_list;
#define __va_size(type) \
(((sizeof(type) + sizeof(int) - 1) / sizeof(int)) * sizeof(int))
#ifdef __GNUC__
#define va_start(ap, last) \
((ap) = (va_list)__builtin_next_arg(last))
#else
#define va_start(ap, last) \
((ap) = (va_list)&(last) + __va_size(last))
#endif
#define va_arg(ap, type) \
(*(type *)((ap) += __va_size(type), (ap) - __va_size(type)))
#define va_end(ap)
/* printing */
#define printk printf
#define kprintf printf
int printf(const char *fmt, ...);
int vprintf(const char *fmt, va_list ap);
int sprintf(char *buf, const char *cfmt, ...);
int vsprintf(char *buf, const char *cfmt, va_list ap);
/* string and memory manipulation */
int memcmp(const void *cs, const void *ct, size_t count);
void *memcpy(void *dest, const void *src, size_t count);
int strncmp(const char *cs, const char *ct, size_t count);
int strcmp(const char *cs, const char *ct);
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t count);
void *memset(void *s,int c, size_t count);
size_t strnlen(const char *s, size_t count);
size_t strlen(const char *s);
char *strchr(const char *s, int c);
char *strstr(const char *s1, const char *s2);
/* dlmalloc functions */
struct mallinfo {
int arena; /* non-mmapped space allocated from system */
int ordblks; /* number of free chunks */
int smblks; /* number of fastbin blocks */
int hblks; /* number of mmapped regions */
int hblkhd; /* space in mmapped regions */
int usmblks; /* maximum total allocated space */
int fsmblks; /* space available in freed fastbin blocks */
int uordblks; /* total allocated space */
int fordblks; /* total free space */
int keepcost; /* top-most, releasable (via malloc_trim) space */
};
void *malloc(size_t n);
void *calloc(size_t n_elements, size_t element_size);
void free(void* p);
void *realloc(void* p, size_t n);
void *memalign(size_t alignment, size_t n);
void *valloc(size_t n);
struct mallinfo mallinfo();
int mallopt(int parameter_number, int parameter_value);
void **independent_calloc(size_t n_elements, size_t size, void* chunks[]);
void **independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
void *pvalloc(size_t n);
void cfree(void* p);
int malloc_trim(size_t pad);
size_t malloc_usable_size(void* p);
void malloc_stats();
#endif /* _LIB_H_ */
+164
View File
@@ -0,0 +1,164 @@
#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H
#define ASSERT(x) ((void)0)
/*
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static __inline__ void __list_add(struct list_head * new,
struct list_head * prev,
struct list_head * next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static __inline__ void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static __inline__ void __list_del(struct list_head * prev,
struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty on entry does not return true after this, the entry is in an undefined state.
*/
static __inline__ void list_del(struct list_head *entry)
{
ASSERT(entry->next->prev == entry);
ASSERT(entry->prev->next == entry);
__list_del(entry->prev, entry->next);
}
/**
* list_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
static __inline__ void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static __inline__ int list_empty(struct list_head *head)
{
return head->next == head;
}
/**
* list_splice - join two lists
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
static __inline__ void list_splice(struct list_head *list, struct list_head *head)
{
struct list_head *first = list->next;
if (first != list) {
struct list_head *last = list->prev;
struct list_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
}
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
/**
* list_for_each_safe - iterate over a list safe against removal of list entry
* @pos: the &struct list_head to use as a loop counter.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
#endif
+107
View File
@@ -0,0 +1,107 @@
/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
****************************************************************************
* (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
****************************************************************************
*
* File: mm.h
* Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
* Changes:
*
* Date: Aug 2003
*
* Environment:
* Description:
*
****************************************************************************
* $Id: h-insert.h,v 1.4 2002/11/08 16:03:55 rn Exp $
****************************************************************************
*/
#ifndef _MM_H_
#define _MM_H_
/* PAGE_SHIFT determines the page size */
#define PAGE_SHIFT 12
#define PAGE_SIZE (1UL << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
#define PFN_DOWN(x) ((x) >> PAGE_SHIFT)
#define PFN_PHYS(x) ((x) << PAGE_SHIFT)
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
extern unsigned long *phys_to_machine_mapping;
#define pfn_to_mfn(_pfn) (phys_to_machine_mapping[(_pfn)])
#define mfn_to_pfn(_mfn) (machine_to_phys_mapping[(_mfn)])
static inline unsigned long phys_to_machine(unsigned long phys)
{
unsigned long machine = pfn_to_mfn(phys >> PAGE_SHIFT);
machine = (machine << PAGE_SHIFT) | (phys & ~PAGE_MASK);
return machine;
}
static inline unsigned long machine_to_phys(unsigned long machine)
{
unsigned long phys = mfn_to_pfn(machine >> PAGE_SHIFT);
phys = (phys << PAGE_SHIFT) | (machine & ~PAGE_MASK);
return phys;
}
/* VIRT <-> MACHINE conversion */
#define virt_to_machine(_a) (phys_to_machine(__pa(_a)))
#define machine_to_virt(_m) (__va(machine_to_phys(_m)))
/*
* This handles the memory map.. We could make this a config
* option, but too many people screw it up, and too few need
* it.
*
* A __PAGE_OFFSET of 0xC0000000 means that the kernel has
* a virtual address space of one gigabyte, which limits the
* amount of physical memory you can use to about 950MB.
*
* If you want more physical memory than this then see the CONFIG_HIGHMEM4G
* and CONFIG_HIGHMEM64G options in the kernel configuration.
*/
#define __PAGE_OFFSET (0xC0000000)
#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
#define virt_to_page(kaddr) (mem_map + (__pa(kaddr) >> PAGE_SHIFT))
#define VALID_PAGE(page) ((page - mem_map) < max_mapnr)
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
/* prototypes */
void init_mm();
void release_bytes_to_allocator(unsigned long min, unsigned long max);
unsigned long __get_free_pages(int order);
void __free_pages(unsigned long p, int order);
#define get_free_pages(_o) (__get_free_pages(_o))
#define get_free_page() (__get_free_pages(0))
#define free_pages(_p,_o) (__free_pages(_p,_o))
#define free_page(_p) (__free_pages(_p,0))
static __inline__ int get_order(unsigned long size)
{
int order;
size = (size-1) >> (PAGE_SHIFT-1);
order = -1;
do {
size >>= 1;
order++;
} while (size);
return order;
}
#endif /* _MM_H_ */
+270
View File
@@ -0,0 +1,270 @@
/******************************************************************************
* os.h
*
* random collection of macros and definition
*/
#ifndef _OS_H_
#define _OS_H_
#define NULL 0
/*
* These are the segment descriptors provided for us by the hypervisor.
* For now, these are hardwired -- guest OSes cannot update the GDT
* or LDT.
*
* It shouldn't be hard to support descriptor-table frobbing -- let me
* know if the BSD or XP ports require flexibility here.
*/
/*
* these are also defined in hypervisor-if.h but can't be pulled in as
* they are used in start of day assembly. Need to clean up the .h files
* a bit more...
*/
#ifndef FLAT_RING1_CS
#define FLAT_RING1_CS 0x0819
#define FLAT_RING1_DS 0x0821
#define FLAT_RING3_CS 0x082b
#define FLAT_RING3_DS 0x0833
#endif
#define __KERNEL_CS FLAT_RING1_CS
#define __KERNEL_DS FLAT_RING1_DS
/* Everything below this point is not included by assembler (.S) files. */
#ifndef __ASSEMBLY__
#include <types.h>
#include <hypervisor-ifs/hypervisor-if.h>
/* this struct defines the way the registers are stored on the
stack during an exception or interrupt. */
struct pt_regs {
long ebx;
long ecx;
long edx;
long esi;
long edi;
long ebp;
long eax;
int xds;
int xes;
long orig_eax;
long eip;
int xcs;
long eflags;
long esp;
int xss;
};
/*
* STI/CLI equivalents. These basically set and clear the virtual
* event_enable flag in teh shared_info structure. Note that when
* the enable bit is set, there may be pending events to be handled.
* We may therefore call into do_hypervisor_callback() directly.
*/
#define unlikely(x) __builtin_expect((x),0)
#define __save_flags(x) \
do { \
(x) = test_bit(EVENTS_MASTER_ENABLE_BIT, \
&HYPERVISOR_shared_info->events_mask); \
barrier(); \
} while (0)
#define __restore_flags(x) \
do { \
shared_info_t *_shared = HYPERVISOR_shared_info; \
if (x) set_bit(EVENTS_MASTER_ENABLE_BIT, &_shared->events_mask); \
barrier(); \
if ( unlikely(_shared->events) && (x) ) do_hypervisor_callback(NULL); \
} while (0)
#define __cli() \
do { \
clear_bit(EVENTS_MASTER_ENABLE_BIT, &HYPERVISOR_shared_info->events_mask);\
barrier(); \
} while (0)
#define __sti() \
do { \
shared_info_t *_shared = HYPERVISOR_shared_info; \
set_bit(EVENTS_MASTER_ENABLE_BIT, &_shared->events_mask); \
barrier(); \
if ( unlikely(_shared->events) ) do_hypervisor_callback(NULL); \
} while (0)
#define cli() __cli()
#define sti() __sti()
#define save_flags(x) __save_flags(x)
#define restore_flags(x) __restore_flags(x)
#define save_and_cli(x) __save_and_cli(x)
#define save_and_sti(x) __save_and_sti(x)
/* This is a barrier for the compiler only, NOT the processor! */
#define barrier() __asm__ __volatile__("": : :"memory")
#define LOCK_PREFIX ""
#define LOCK ""
#define ADDR (*(volatile long *) addr)
/*
* Make sure gcc doesn't try to be clever and move things around
* on us. We need to use _exactly_ the address the user gave us,
* not some alias that contains the same information.
*/
typedef struct { volatile int counter; } atomic_t;
/*
* This XCHG macro is straight from Linux. It is gross.
*/
#define xchg(ptr,v) \
((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
struct __xchg_dummy { unsigned long a[100]; };
#define __xg(x) ((struct __xchg_dummy *)(x))
static inline unsigned long __xchg(unsigned long x, volatile void * ptr,
int size)
{
switch (size) {
case 1:
__asm__ __volatile__("xchgb %b0,%1"
:"=q" (x)
:"m" (*__xg(ptr)), "0" (x)
:"memory");
break;
case 2:
__asm__ __volatile__("xchgw %w0,%1"
:"=r" (x)
:"m" (*__xg(ptr)), "0" (x)
:"memory");
break;
case 4:
__asm__ __volatile__("xchgl %0,%1"
:"=r" (x)
:"m" (*__xg(ptr)), "0" (x)
:"memory");
break;
}
return x;
}
/**
* test_and_clear_bit - Clear a bit and return its old value
* @nr: Bit to set
* @addr: Address to count from
*
* This operation is atomic and cannot be reordered.
* It also implies a memory barrier.
*/
static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
{
int oldbit;
__asm__ __volatile__( LOCK_PREFIX
"btrl %2,%1\n\tsbbl %0,%0"
:"=r" (oldbit),"=m" (ADDR)
:"Ir" (nr) : "memory");
return oldbit;
}
static __inline__ int constant_test_bit(int nr, const volatile void * addr)
{
return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0;
}
static __inline__ int variable_test_bit(int nr, volatile void * addr)
{
int oldbit;
__asm__ __volatile__(
"btl %2,%1\n\tsbbl %0,%0"
:"=r" (oldbit)
:"m" (ADDR),"Ir" (nr));
return oldbit;
}
#define test_bit(nr,addr) \
(__builtin_constant_p(nr) ? \
constant_test_bit((nr),(addr)) : \
variable_test_bit((nr),(addr)))
/**
* set_bit - Atomically set a bit in memory
* @nr: the bit to set
* @addr: the address to start counting from
*
* This function is atomic and may not be reordered. See __set_bit()
* if you do not require the atomic guarantees.
* Note that @nr may be almost arbitrarily large; this function is not
* restricted to acting on a single-word quantity.
*/
static __inline__ void set_bit(int nr, volatile void * addr)
{
__asm__ __volatile__( LOCK_PREFIX
"btsl %1,%0"
:"=m" (ADDR)
:"Ir" (nr));
}
/**
* clear_bit - Clears a bit in memory
* @nr: Bit to clear
* @addr: Address to start counting from
*
* clear_bit() is atomic and may not be reordered. However, it does
* not contain a memory barrier, so if it is used for locking purposes,
* you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
* in order to ensure changes are visible on other processors.
*/
static __inline__ void clear_bit(int nr, volatile void * addr)
{
__asm__ __volatile__( LOCK_PREFIX
"btrl %1,%0"
:"=m" (ADDR)
:"Ir" (nr));
}
/**
* atomic_inc - increment atomic variable
* @v: pointer of type atomic_t
*
* Atomically increments @v by 1. Note that the guaranteed
* useful range of an atomic_t is only 24 bits.
*/
static __inline__ void atomic_inc(atomic_t *v)
{
__asm__ __volatile__(
LOCK "incl %0"
:"=m" (v->counter)
:"m" (v->counter));
}
/* useful hypervisor macros */
struct desc_struct {
unsigned long a,b;
};
extern struct desc_struct default_ldt[];
#define asmlinkage __attribute__((regparm(0)))
/*
* some random linux macros
*/
#define rdtscll(val) \
__asm__ __volatile__("rdtsc" : "=A" (val))
#endif /* !__ASSEMBLY__ */
#endif /* _OS_H_ */
+59
View File
@@ -0,0 +1,59 @@
/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
****************************************************************************
* (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
****************************************************************************
*
* File: time.h
* Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
* Changes:
*
* Date: Jul 2003
*
* Environment: Xen Minimal OS
* Description: Time and timer functions
*
****************************************************************************
* $Id: h-insert.h,v 1.4 2002/11/08 16:03:55 rn Exp $
****************************************************************************
*/
#ifndef _TIME_H_
#define _TIME_H_
#include <list.h>
/*
* System Time
* 64 bit value containing the nanoseconds elapsed since boot time.
* This value is adjusted by frequency drift.
* NOW() returns the current time.
* The other macros are for convenience to approximate short intervals
* of real time into system time
*/
typedef s64 s_time_t;
#define NOW() ((s_time_t)get_s_time())
#define SECONDS(_s) (((s_time_t)(_s)) * 1000000000UL )
#define TENTHS(_ts) (((s_time_t)(_ts)) * 100000000UL )
#define HUNDREDTHS(_hs) (((s_time_t)(_hs)) * 10000000UL )
#define MILLISECS(_ms) (((s_time_t)(_ms)) * 1000000UL )
#define MICROSECS(_us) (((s_time_t)(_us)) * 1000UL )
#define Time_Max ((s_time_t) 0x7fffffffffffffffLL)
#define FOREVER Time_Max
/* wall clock time */
typedef long time_t;
typedef long suseconds_t;
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
/* prototypes */
void init_time(void);
s_time_t get_s_time(void);
s_time_t get_v_time(void);
void gettimeofday(struct timeval *tv);
#endif /* _TIME_H_ */
+41
View File
@@ -0,0 +1,41 @@
/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
****************************************************************************
* (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
****************************************************************************
*
* File: types.h
* Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
* Changes:
*
* Date: May 2003
*
* Environment: Xeno Minimal OS
* Description: a random collection of type definitions
*
****************************************************************************
* $Id: h-insert.h,v 1.4 2002/11/08 16:03:55 rn Exp $
****************************************************************************
*/
#ifndef _TYPES_H_
#define _TYPES_H_
typedef signed char s8;
typedef unsigned char u8;
typedef signed short s16;
typedef unsigned short u16;
typedef signed int s32;
typedef unsigned int u32;
typedef signed long long s64;
typedef unsigned long long u64;
typedef unsigned int size_t;
/* FreeBSD compat types */
typedef unsigned char u_char;
typedef unsigned int u_int;
typedef unsigned long u_long;
typedef long long quad_t;
typedef unsigned long long u_quad_t;
typedef unsigned int uintptr_t;
#endif /* _TYPES_H_ */
+46
View File
@@ -0,0 +1,46 @@
#include <os.h>
/* Offsets in start_info structure */
#define SHARED_INFO 4
#define MOD_START 12
#define MOD_LEN 16
#define ENTRY(X) .globl X ; X :
.globl _start
_start:
cld
lss stack_start,%esp
/* Copy any module somewhere safe before it's clobbered by BSS. */
mov MOD_LEN(%esi),%ecx
shr $2,%ecx
jz 2f /* bail from copy loop if no module */
mov $_end,%edi
add MOD_LEN(%esi),%edi
mov MOD_START(%esi),%eax
add MOD_LEN(%esi),%eax
1: sub $4,%eax
sub $4,%edi
mov (%eax),%ebx
mov %ebx,(%edi)
loop 1b
mov %edi,MOD_START(%esi)
/* Clear BSS first so that there are no surprises... */
2: xorl %eax,%eax
movl $__bss_start,%edi
movl $_end,%ecx
subl %edi,%ecx
rep stosb
push %esi
call start_kernel
stack_start:
.long stack+8192, __KERNEL_DS
+83
View File
@@ -0,0 +1,83 @@
/******************************************************************************
* hypervisor.c
*
* Communication to/from hypervisor.
*
* Copied from XenoLinux and adjusted by Rolf.Neugebauer@intel.com
*
* Copyright (c) 2002, K A Fraser
*/
#include <os.h>
#include <hypervisor.h>
static unsigned long event_mask = 0;
static unsigned long ev_err_count;
void do_hypervisor_callback(struct pt_regs *regs)
{
unsigned long events, flags;
shared_info_t *shared = HYPERVISOR_shared_info;
do {
/* Specialised local_irq_save(). */
flags = test_and_clear_bit(EVENTS_MASTER_ENABLE_BIT,
&shared->events_mask);
barrier();
events = xchg(&shared->events, 0);
events &= event_mask;
/* 'events' now contains some pending events to handle. */
__asm__ __volatile__ (
" push %1 ;"
" sub $4,%%esp ;"
" jmp 2f ;"
"1: btrl %%eax,%0 ;" /* clear bit */
" mov %%eax,(%%esp) ;"
" call do_event ;" /* do_event(event) */
"2: bsfl %0,%%eax ;" /* %eax == bit # */
" jnz 1b ;"
" add $8,%%esp ;"
/* we use %ebx because it is callee-saved */
: : "b" (events), "r" (regs)
/* clobbered by callback function calls */
: "eax", "ecx", "edx", "memory" );
/* Specialised local_irq_restore(). */
if ( flags ) set_bit(EVENTS_MASTER_ENABLE_BIT, &shared->events_mask);
barrier();
}
while ( shared->events );
}
/*
* Define interface to generic handling in irq.c
*/
void enable_hypervisor_event(unsigned int ev)
{
set_bit(ev, &event_mask);
set_bit(ev, &HYPERVISOR_shared_info->events_mask);
if ( test_bit(EVENTS_MASTER_ENABLE_BIT,
&HYPERVISOR_shared_info->events_mask) )
do_hypervisor_callback(NULL);
}
void disable_hypervisor_event(unsigned int ev)
{
clear_bit(ev, &event_mask);
clear_bit(ev, &HYPERVISOR_shared_info->events_mask);
}
void ack_hypervisor_event(unsigned int ev)
{
if ( !(event_mask & (1<<ev)) )
{
//printk("Unexpected hypervisor event %d\n", ev);
atomic_inc((atomic_t *)&ev_err_count);
}
set_bit(ev, &HYPERVISOR_shared_info->events_mask);
}
+115
View File
@@ -0,0 +1,115 @@
/******************************************************************************
* kernel.c
*
* Assorted crap goes here, including the initial C entry point, jumped at
* from head.S.
*/
#include <os.h>
#include <hypervisor.h>
#include <mm.h>
#include <events.h>
#include <time.h>
#include <types.h>
#include <lib.h>
/*
* Shared page for communicating with the hypervisor.
* Events flags go here, for example.
*/
shared_info_t *HYPERVISOR_shared_info;
/*
* This structure contains start-of-day info, such as pagetable base pointer,
* address of the shared_info structure, and things like that.
*/
union start_info_union start_info_union;
/*
* Just allocate the kernel stack here. SS:ESP is set up to point here
* in head.S.
*/
char stack[8192];
/* Assembler interface fns in entry.S. */
void hypervisor_callback(void);
void failsafe_callback(void);
/* default exit event handler */
static void exit_handler(int ev, struct pt_regs *regs);
/*
* INITIAL C ENTRY POINT.
*/
void start_kernel(start_info_t *si)
{
int i;
/* Copy the start_info struct to a globally-accessible area. */
memcpy(&start_info, si, sizeof(*si));
/* Grab the shared_info pointer and put it in a safe place. */
HYPERVISOR_shared_info = start_info.shared_info;
/* Set up event and failsafe callback addresses. */
HYPERVISOR_set_callbacks(
__KERNEL_CS, (unsigned long)hypervisor_callback,
__KERNEL_CS, (unsigned long)failsafe_callback);
/* ENABLE EVENT DELIVERY. This is disabled at start of day. */
__sti();
/* print out some useful information */
printk("Xeno Minimal OS!\n");
printk("start_info: %p\n", si);
printk(" nr_pages: %lu", si->nr_pages);
printk(" shared_inf: %p\n", si->shared_info);
printk(" pt_base: %p", (void *)si->pt_base);
printk(" mod_start: 0x%lx\n", si->mod_start);
printk(" mod_len: %lu\n", si->mod_len);
printk(" net_rings: ");
for (i = 0; i < MAX_DOMAIN_VIFS; i++) {
printk(" %lx", si->net_rings[i]);
}; printk("\n");
printk(" blk_ring: 0x%lx\n", si->blk_ring);
printk(" dom_id: %d\n", si->dom_id);
printk(" flags: 0x%lx\n", si->flags);
printk(" cmd_line: %s\n", si->cmd_line ? (const char *)si->cmd_line : "NULL");
/* init memory management */
init_mm();
/* set up events */
init_events();
/* install some handlers */
add_ev_action(EV_DIE, &exit_handler);
enable_ev_action(EV_DIE);
enable_hypervisor_event(EV_DIE);
/* init time and timers */
init_time();
/* do nothing */
for ( ; ; ) HYPERVISOR_yield();
}
/*
* do_exit: This is called whenever an IRET fails in entry.S.
* This will generally be because an application has got itself into
* a really bad state (probably a bad CS or SS). It must be killed.
* Of course, minimal OS doesn't have applications :-)
*/
void do_exit(void)
{
printk("do_exit called!\n");
for ( ;; ) ;
}
static void exit_handler(int ev, struct pt_regs *regs) {
do_exit();
}
+5700
View File
File diff suppressed because it is too large. Load diff
+385
View File
@@ -0,0 +1,385 @@
/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
****************************************************************************
* (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
****************************************************************************
*
* File: math.c
* Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
* Changes:
*
* Date: Aug 2003
*
* Environment: Xen Minimal OS
* Description: Library functions for 64bit arith and other
* from freebsd, files in sys/libkern/ (qdivrem.c, etc)
*
****************************************************************************
* $Id: c-insert.c,v 1.7 2002/11/08 16:04:34 rn Exp $
****************************************************************************
*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD: src/sys/libkern/divdi3.c,v 1.6 1999/08/28 00:46:31 peter Exp $
*/
#include <types.h>
/*
* Depending on the desired operation, we view a `long long' (aka quad_t) in
* one or more of the following formats.
*/
union uu {
s64 q; /* as a (signed) quad */
s64 uq; /* as an unsigned quad */
long sl[2]; /* as two signed longs */
unsigned long ul[2]; /* as two unsigned longs */
};
/* XXX RN: Yuck hardcoded endianess :) */
#define _QUAD_HIGHWORD 1
#define _QUAD_LOWWORD 0
/*
* Define high and low longwords.
*/
#define H _QUAD_HIGHWORD
#define L _QUAD_LOWWORD
/*
* Total number of bits in a quad_t and in the pieces that make it up.
* These are used for shifting, and also below for halfword extraction
* and assembly.
*/
#define CHAR_BIT 8 /* number of bits in a char */
#define QUAD_BITS (sizeof(s64) * CHAR_BIT)
#define LONG_BITS (sizeof(long) * CHAR_BIT)
#define HALF_BITS (sizeof(long) * CHAR_BIT / 2)
/*
* Extract high and low shortwords from longword, and move low shortword of
* longword to upper half of long, i.e., produce the upper longword of
* ((quad_t)(x) << (number_of_bits_in_long/2)). (`x' must actually be u_long.)
*
* These are used in the multiply code, to split a longword into upper
* and lower halves, and to reassemble a product as a quad_t, shifted left
* (sizeof(long)*CHAR_BIT/2).
*/
#define HHALF(x) ((x) >> HALF_BITS)
#define LHALF(x) ((x) & ((1 << HALF_BITS) - 1))
#define LHUP(x) ((x) << HALF_BITS)
/*
* Multiprecision divide. This algorithm is from Knuth vol. 2 (2nd ed),
* section 4.3.1, pp. 257--259.
*/
#define B (1 << HALF_BITS) /* digit base */
/* Combine two `digits' to make a single two-digit number. */
#define COMBINE(a, b) (((u_long)(a) << HALF_BITS) | (b))
/* select a type for digits in base B: use unsigned short if they fit */
#if ULONG_MAX == 0xffffffff && USHRT_MAX >= 0xffff
typedef unsigned short digit;
#else
typedef u_long digit;
#endif
/*
* Shift p[0]..p[len] left `sh' bits, ignoring any bits that
* `fall out' the left (there never will be any such anyway).
* We may assume len >= 0. NOTE THAT THIS WRITES len+1 DIGITS.
*/
static void
shl(register digit *p, register int len, register int sh)
{
register int i;
for (i = 0; i < len; i++)
p[i] = LHALF(p[i] << sh) | (p[i + 1] >> (HALF_BITS - sh));
p[i] = LHALF(p[i] << sh);
}
/*
* __qdivrem(u, v, rem) returns u/v and, optionally, sets *rem to u%v.
*
* We do this in base 2-sup-HALF_BITS, so that all intermediate products
* fit within u_long. As a consequence, the maximum length dividend and
* divisor are 4 `digits' in this base (they are shorter if they have
* leading zeros).
*/
u64
__qdivrem(uq, vq, arq)
u64 uq, vq, *arq;
{
union uu tmp;
digit *u, *v, *q;
register digit v1, v2;
u_long qhat, rhat, t;
int m, n, d, j, i;
digit uspace[5], vspace[5], qspace[5];
/*
* Take care of special cases: divide by zero, and u < v.
*/
if (vq == 0) {
/* divide by zero. */
static volatile const unsigned int zero = 0;
tmp.ul[H] = tmp.ul[L] = 1 / zero;
if (arq)
*arq = uq;
return (tmp.q);
}
if (uq < vq) {
if (arq)
*arq = uq;
return (0);
}
u = &uspace[0];
v = &vspace[0];
q = &qspace[0];
/*
* Break dividend and divisor into digits in base B, then
* count leading zeros to determine m and n. When done, we
* will have:
* u = (u[1]u[2]...u[m+n]) sub B
* v = (v[1]v[2]...v[n]) sub B
* v[1] != 0
* 1 < n <= 4 (if n = 1, we use a different division algorithm)
* m >= 0 (otherwise u < v, which we already checked)
* m + n = 4
* and thus
* m = 4 - n <= 2
*/
tmp.uq = uq;
u[0] = 0;
u[1] = HHALF(tmp.ul[H]);
u[2] = LHALF(tmp.ul[H]);
u[3] = HHALF(tmp.ul[L]);
u[4] = LHALF(tmp.ul[L]);
tmp.uq = vq;
v[1] = HHALF(tmp.ul[H]);
v[2] = LHALF(tmp.ul[H]);
v[3] = HHALF(tmp.ul[L]);
v[4] = LHALF(tmp.ul[L]);
for (n = 4; v[1] == 0; v++) {
if (--n == 1) {
u_long rbj; /* r*B+u[j] (not root boy jim) */
digit q1, q2, q3, q4;
/*
* Change of plan, per exercise 16.
* r = 0;
* for j = 1..4:
* q[j] = floor((r*B + u[j]) / v),
* r = (r*B + u[j]) % v;
* We unroll this completely here.
*/
t = v[2]; /* nonzero, by definition */
q1 = u[1] / t;
rbj = COMBINE(u[1] % t, u[2]);
q2 = rbj / t;
rbj = COMBINE(rbj % t, u[3]);
q3 = rbj / t;
rbj = COMBINE(rbj % t, u[4]);
q4 = rbj / t;
if (arq)
*arq = rbj % t;
tmp.ul[H] = COMBINE(q1, q2);
tmp.ul[L] = COMBINE(q3, q4);
return (tmp.q);
}
}
/*
* By adjusting q once we determine m, we can guarantee that
* there is a complete four-digit quotient at &qspace[1] when
* we finally stop.
*/
for (m = 4 - n; u[1] == 0; u++)
m--;
for (i = 4 - m; --i >= 0;)
q[i] = 0;
q += 4 - m;
/*
* Here we run Program D, translated from MIX to C and acquiring
* a few minor changes.
*
* D1: choose multiplier 1 << d to ensure v[1] >= B/2.
*/
d = 0;
for (t = v[1]; t < B / 2; t <<= 1)
d++;
if (d > 0) {
shl(&u[0], m + n, d); /* u <<= d */
shl(&v[1], n - 1, d); /* v <<= d */
}
/*
* D2: j = 0.
*/
j = 0;
v1 = v[1]; /* for D3 -- note that v[1..n] are constant */
v2 = v[2]; /* for D3 */
do {
register digit uj0, uj1, uj2;
/*
* D3: Calculate qhat (\^q, in TeX notation).
* Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and
* let rhat = (u[j]*B + u[j+1]) mod v[1].
* While rhat < B and v[2]*qhat > rhat*B+u[j+2],
* decrement qhat and increase rhat correspondingly.
* Note that if rhat >= B, v[2]*qhat < rhat*B.
*/
uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */
uj1 = u[j + 1]; /* for D3 only */
uj2 = u[j + 2]; /* for D3 only */
if (uj0 == v1) {
qhat = B;
rhat = uj1;
goto qhat_too_big;
} else {
u_long nn = COMBINE(uj0, uj1);
qhat = nn / v1;
rhat = nn % v1;
}
while (v2 * qhat > COMBINE(rhat, uj2)) {
qhat_too_big:
qhat--;
if ((rhat += v1) >= B)
break;
}
/*
* D4: Multiply and subtract.
* The variable `t' holds any borrows across the loop.
* We split this up so that we do not require v[0] = 0,
* and to eliminate a final special case.
*/
for (t = 0, i = n; i > 0; i--) {
t = u[i + j] - v[i] * qhat - t;
u[i + j] = LHALF(t);
t = (B - HHALF(t)) & (B - 1);
}
t = u[j] - t;
u[j] = LHALF(t);
/*
* D5: test remainder.
* There is a borrow if and only if HHALF(t) is nonzero;
* in that (rare) case, qhat was too large (by exactly 1).
* Fix it by adding v[1..n] to u[j..j+n].
*/
if (HHALF(t)) {
qhat--;
for (t = 0, i = n; i > 0; i--) { /* D6: add back. */
t += u[i + j] + v[i];
u[i + j] = LHALF(t);
t = HHALF(t);
}
u[j] = LHALF(u[j] + t);
}
q[j] = qhat;
} while (++j <= m); /* D7: loop on j. */
/*
* If caller wants the remainder, we have to calculate it as
* u[m..m+n] >> d (this is at most n digits and thus fits in
* u[m+1..m+n], but we may need more source digits).
*/
if (arq) {
if (d) {
for (i = m + n; i > m; --i)
u[i] = (u[i] >> d) |
LHALF(u[i - 1] << (HALF_BITS - d));
u[i] = 0;
}
tmp.ul[H] = COMBINE(uspace[1], uspace[2]);
tmp.ul[L] = COMBINE(uspace[3], uspace[4]);
*arq = tmp.q;
}
tmp.ul[H] = COMBINE(qspace[1], qspace[2]);
tmp.ul[L] = COMBINE(qspace[3], qspace[4]);
return (tmp.q);
}
/*
* Divide two signed quads.
* ??? if -1/2 should produce -1 on this machine, this code is wrong
*/
s64
__divdi3(s64 a, s64 b)
{
u64 ua, ub, uq;
int neg;
if (a < 0)
ua = -(u64)a, neg = 1;
else
ua = a, neg = 0;
if (b < 0)
ub = -(u64)b, neg ^= 1;
else
ub = b;
uq = __qdivrem(ua, ub, (u64 *)0);
return (neg ? -uq : uq);
}
/*
* Divide two unsigned quads.
*/
u64
__udivdi3(a, b)
u64 a, b;
{
return (__qdivrem(a, b, (u64 *)0));
}
/*
* Return remainder after dividing two unsigned quads.
*/
u_quad_t
__umoddi3(a, b)
u_quad_t a, b;
{
u_quad_t r;
(void)__qdivrem(a, b, &r);
return (r);
}
+470
View File
@@ -0,0 +1,470 @@
/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
****************************************************************************
* (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
****************************************************************************
*
* File: printf.c
* Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
* Changes:
*
* Date: Aug 2003
*
* Environment: Xen Minimal OS
* Description: Library functions for printing
* (freebsd port, mainly sys/subr_prf.c)
*
****************************************************************************
* $Id: c-insert.c,v 1.7 2002/11/08 16:04:34 rn Exp $
****************************************************************************
*
*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD: src/sys/libkern/divdi3.c,v 1.6 1999/08/28 00:46:31 peter Exp $
*/
#include <os.h>
#include <types.h>
#include <hypervisor.h>
#include <lib.h>
/****************************************************************************
* RN: printf family of routines
* taken mainly from sys/subr_prf.c
****************************************************************************/
char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz";
#define hex2ascii(hex) (hex2ascii_data[hex])
#define NBBY 8 /* number of bits in a byte */
#define MAXNBUF (sizeof(quad_t) * NBBY + 1)
static int kvprintf(char const *fmt, void *arg, int radix, va_list ap);
int
printf(const char *fmt, ...)
{
va_list ap;
int retval;
static char printk_buf[1024];
va_start(ap, fmt);
retval = kvprintf(fmt, printk_buf, 10, ap);
printk_buf[retval] = '\0';
va_end(ap);
(void)HYPERVISOR_console_write(printk_buf, strlen(printk_buf));
return retval;
}
int
vprintf(const char *fmt, va_list ap)
{
int retval;
static char printk_buf[1024];
retval = kvprintf(fmt, printk_buf, 10, ap);
printk_buf[retval] = '\0';
(void)HYPERVISOR_console_write(printk_buf, strlen(printk_buf));
return retval;
}
int
sprintf(char *buf, const char *cfmt, ...)
{
int retval;
va_list ap;
va_start(ap, cfmt);
retval = kvprintf(cfmt, (void *)buf, 10, ap);
buf[retval] = '\0';
va_end(ap);
return retval;
}
int
vsprintf(char *buf, const char *cfmt, va_list ap)
{
int retval;
retval = kvprintf(cfmt, (void *)buf, 10, ap);
buf[retval] = '\0';
return retval;
}
/*
* Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
* order; return an optional length and a pointer to the last character
* written in the buffer (i.e., the first character of the string).
* The buffer pointed to by `nbuf' must have length >= MAXNBUF.
*/
static char *
ksprintn(nbuf, ul, base, lenp)
char *nbuf;
u_long ul;
int base, *lenp;
{
char *p;
p = nbuf;
*p = '\0';
do {
*++p = hex2ascii(ul % base);
} while (ul /= base);
if (lenp)
*lenp = p - nbuf;
return (p);
}
/* ksprintn, but for a quad_t. */
static char *
ksprintqn(nbuf, uq, base, lenp)
char *nbuf;
u_quad_t uq;
int base, *lenp;
{
char *p;
p = nbuf;
*p = '\0';
do {
*++p = hex2ascii(uq % base);
} while (uq /= base);
if (lenp)
*lenp = p - nbuf;
return (p);
}
/*
* Scaled down version of printf(3).
*
* Two additional formats:
*
* The format %b is supported to decode error registers.
* Its usage is:
*
* printf("reg=%b\n", regval, "<base><arg>*");
*
* where <base> is the output base expressed as a control character, e.g.
* \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
* the first of which gives the bit number to be inspected (origin 1), and
* the next characters (up to a control character, i.e. a character <= 32),
* give the name of the register. Thus:
*
* kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
*
* would produce output:
*
* reg=3<BITTWO,BITONE>
*
* XXX: %D -- Hexdump, takes pointer and separator string:
* ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
* ("%*D", len, ptr, " " -> XX XX XX XX ...
*/
/* RN: This normally takes a function for output.
* we always print to a string and the use HYPERCALL for write to console */
static int
kvprintf(char const *fmt, void *arg, int radix, va_list ap)
{
#define PCHAR(c) {int cc=(c); *d++ = cc; retval++; }
char nbuf[MAXNBUF];
char *p, *q, *d;
u_char *up;
int ch, n;
u_long ul;
u_quad_t uq;
int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
int dwidth;
char padc;
int retval = 0;
ul = 0;
uq = 0;
d = (char *) arg;
if (fmt == NULL)
fmt = "(fmt null)\n";
if (radix < 2 || radix > 36)
radix = 10;
for (;;) {
padc = ' ';
width = 0;
while ((ch = (u_char)*fmt++) != '%') {
if (ch == '\0')
return retval;
PCHAR(ch);
}
qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
sign = 0; dot = 0; dwidth = 0;
reswitch: switch (ch = (u_char)*fmt++) {
case '.':
dot = 1;
goto reswitch;
case '#':
sharpflag = 1;
goto reswitch;
case '+':
sign = 1;
goto reswitch;
case '-':
ladjust = 1;
goto reswitch;
case '%':
PCHAR(ch);
break;
case '*':
if (!dot) {
width = va_arg(ap, int);
if (width < 0) {
ladjust = !ladjust;
width = -width;
}
} else {
dwidth = va_arg(ap, int);
}
goto reswitch;
case '0':
if (!dot) {
padc = '0';
goto reswitch;
}
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
for (n = 0;; ++fmt) {
n = n * 10 + ch - '0';
ch = *fmt;
if (ch < '0' || ch > '9')
break;
}
if (dot)
dwidth = n;
else
width = n;
goto reswitch;
case 'b':
ul = va_arg(ap, int);
p = va_arg(ap, char *);
for (q = ksprintn(nbuf, ul, *p++, NULL); *q;)
PCHAR(*q--);
if (!ul)
break;
for (tmp = 0; *p;) {
n = *p++;
if (ul & (1 << (n - 1))) {
PCHAR(tmp ? ',' : '<');
for (; (n = *p) > ' '; ++p)
PCHAR(n);
tmp = 1;
} else
for (; *p > ' '; ++p)
continue;
}
if (tmp)
PCHAR('>');
break;
case 'c':
PCHAR(va_arg(ap, int));
break;
case 'D':
up = va_arg(ap, u_char *);
p = va_arg(ap, char *);
if (!width)
width = 16;
while(width--) {
PCHAR(hex2ascii(*up >> 4));
PCHAR(hex2ascii(*up & 0x0f));
up++;
if (width)
for (q=p;*q;q++)
PCHAR(*q);
}
break;
case 'd':
if (qflag)
uq = va_arg(ap, quad_t);
else if (lflag)
ul = va_arg(ap, long);
else
ul = va_arg(ap, int);
sign = 1;
base = 10;
goto number;
case 'l':
if (lflag) {
lflag = 0;
qflag = 1;
} else
lflag = 1;
goto reswitch;
case 'o':
if (qflag)
uq = va_arg(ap, u_quad_t);
else if (lflag)
ul = va_arg(ap, u_long);
else
ul = va_arg(ap, u_int);
base = 8;
goto nosign;
case 'p':
ul = (uintptr_t)va_arg(ap, void *);
base = 16;
sharpflag = (width == 0);
goto nosign;
case 'q':
qflag = 1;
goto reswitch;
case 'n':
case 'r':
if (qflag)
uq = va_arg(ap, u_quad_t);
else if (lflag)
ul = va_arg(ap, u_long);
else
ul = sign ?
(u_long)va_arg(ap, int) : va_arg(ap, u_int);
base = radix;
goto number;
case 's':
p = va_arg(ap, char *);
if (p == NULL)
p = "(null)";
if (!dot)
n = strlen (p);
else
for (n = 0; n < dwidth && p[n]; n++)
continue;
width -= n;
if (!ladjust && width > 0)
while (width--)
PCHAR(padc);
while (n--)
PCHAR(*p++);
if (ladjust && width > 0)
while (width--)
PCHAR(padc);
break;
case 'u':
if (qflag)
uq = va_arg(ap, u_quad_t);
else if (lflag)
ul = va_arg(ap, u_long);
else
ul = va_arg(ap, u_int);
base = 10;
goto nosign;
case 'x':
case 'X':
if (qflag)
uq = va_arg(ap, u_quad_t);
else if (lflag)
ul = va_arg(ap, u_long);
else
ul = va_arg(ap, u_int);
base = 16;
goto nosign;
case 'z':
if (qflag)
uq = va_arg(ap, u_quad_t);
else if (lflag)
ul = va_arg(ap, u_long);
else
ul = sign ?
(u_long)va_arg(ap, int) : va_arg(ap, u_int);
base = 16;
goto number;
nosign: sign = 0;
number:
if (qflag) {
if (sign && (quad_t)uq < 0) {
neg = 1;
uq = -(quad_t)uq;
}
p = ksprintqn(nbuf, uq, base, &tmp);
} else {
if (sign && (long)ul < 0) {
neg = 1;
ul = -(long)ul;
}
p = ksprintn(nbuf, ul, base, &tmp);
}
if (sharpflag && (qflag ? uq != 0 : ul != 0)) {
if (base == 8)
tmp++;
else if (base == 16)
tmp += 2;
}
if (neg)
tmp++;
if (!ladjust && width && (width -= tmp) > 0)
while (width--)
PCHAR(padc);
if (neg)
PCHAR('-');
if (sharpflag && (qflag ? uq != 0 : ul != 0)) {
if (base == 8) {
PCHAR('0');
} else if (base == 16) {
PCHAR('0');
PCHAR('x');
}
}
while (*p)
PCHAR(*p--);
if (ladjust && width && (width -= tmp) > 0)
while (width--)
PCHAR(padc);
break;
default:
PCHAR('%');
if (lflag)
PCHAR('l');
PCHAR(ch);
break;
}
}
#undef PCHAR
}
+142
View File
@@ -0,0 +1,142 @@
/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
****************************************************************************
* (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
****************************************************************************
*
* File: string.c
* Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
* Changes:
*
* Date: Aug 2003
*
* Environment: Xen Minimal OS
* Description: Library function for string and memory manipulation
* Origin unknown
*
****************************************************************************
* $Id: c-insert.c,v 1.7 2002/11/08 16:04:34 rn Exp $
****************************************************************************
*/
#include <os.h>
#include <types.h>
#include <lib.h>
int memcmp(const void * cs,const void * ct,size_t count)
{
const unsigned char *su1, *su2;
signed char res = 0;
for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
if ((res = *su1 - *su2) != 0)
break;
return res;
}
void * memcpy(void * dest,const void *src,size_t count)
{
char *tmp = (char *) dest, *s = (char *) src;
while (count--)
*tmp++ = *s++;
return dest;
}
int strncmp(const char * cs,const char * ct,size_t count)
{
register signed char __res = 0;
while (count) {
if ((__res = *cs - *ct++) != 0 || !*cs++)
break;
count--;
}
return __res;
}
int strcmp(const char * cs,const char * ct)
{
register signed char __res;
while (1) {
if ((__res = *cs - *ct++) != 0 || !*cs++)
break;
}
return __res;
}
char * strcpy(char * dest,const char *src)
{
char *tmp = dest;
while ((*dest++ = *src++) != '\0')
/* nothing */;
return tmp;
}
char * strncpy(char * dest,const char *src,size_t count)
{
char *tmp = dest;
while (count-- && (*dest++ = *src++) != '\0')
/* nothing */;
return tmp;
}
void * memset(void * s,int c,size_t count)
{
char *xs = (char *) s;
while (count--)
*xs++ = c;
return s;
}
size_t strnlen(const char * s, size_t count)
{
const char *sc;
for (sc = s; count-- && *sc != '\0'; ++sc)
/* nothing */;
return sc - s;
}
size_t strlen(const char * s)
{
const char *sc;
for (sc = s; *sc != '\0'; ++sc)
/* nothing */;
return sc - s;
}
char * strchr(const char * s, int c)
{
for(; *s != (char) c; ++s)
if (*s == '\0')
return NULL;
return (char *) s;
}
char * strstr(const char * s1,const char * s2)
{
int l1, l2;
l2 = strlen(s2);
if (!l2)
return (char *) s1;
l1 = strlen(s1);
while (l1 >= l2) {
l1--;
if (!memcmp(s1,s2,l2))
return (char *) s1;
s1++;
}
return NULL;
}
+375
View File
@@ -0,0 +1,375 @@
/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
****************************************************************************
* (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
****************************************************************************
*
* File: mm.c
* Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
* Changes:
*
* Date: Aug 2003
*
* Environment: Xen Minimal OS
* Description: memory management related functions
* contains buddy page allocator from Xen.
*
****************************************************************************
* $Id: c-insert.c,v 1.7 2002/11/08 16:04:34 rn Exp $
****************************************************************************
*/
#include <os.h>
#include <hypervisor.h>
#include <mm.h>
#include <types.h>
#include <lib.h>
unsigned long *phys_to_machine_mapping;
extern char *stack;
extern char _text, _etext, _edata, _end;
static void init_page_allocator(unsigned long min, unsigned long max);
void init_mm(void)
{
unsigned long start_pfn, max_pfn, max_free_pfn;
unsigned long *pgd = (unsigned long *)start_info.pt_base;
printk("MM: Init\n");
printk(" _text: %p\n", &_text);
printk(" _etext: %p\n", &_etext);
printk(" _edata: %p\n", &_edata);
printk(" stack start: %p\n", &stack);
printk(" _end: %p\n", &_end);
/* set up minimal memory infos */
start_pfn = PFN_UP(__pa(&_end));
max_pfn = start_info.nr_pages;
printk(" start_pfn: %lx\n", start_pfn);
printk(" max_pfn: %lx\n", max_pfn);
/*
* we know where free tables start (start_pfn) and how many we
* have (max_pfn).
*
* Currently the hypervisor stores page tables it providesin the
* high region of the this memory range.
*
* next we work out how far down this goes (max_free_pfn)
*
* XXX this assumes the hypervisor provided page tables to be in
* the upper region of our initial memory. I don't know if this
* is always true.
*/
max_free_pfn = PFN_DOWN(__pa(pgd));
{
unsigned long *pgd = (unsigned long *)start_info.pt_base;
unsigned long pte;
int i;
printk(" pgd(pa(pgd)): %lx(%lx)", (u_long)pgd, __pa(pgd));
for ( i = 0; i < (HYPERVISOR_VIRT_START>>22); i++ )
{
unsigned long pgde = *pgd++;
if ( !(pgde & 1) ) continue;
pte = machine_to_phys(pgde & PAGE_MASK);
printk(" PT(%x): %lx(%lx)", i, (u_long)__va(pte), pte);
if (PFN_DOWN(pte) <= max_free_pfn)
max_free_pfn = PFN_DOWN(pte);
}
}
max_free_pfn--;
printk(" max_free_pfn: %lx\n", max_free_pfn);
/*
* now we can initialise the page allocator
*/
printk("MM: Initialise page allocator for %lx(%lx)-%lx(%lx)\n",
(u_long)__va(PFN_PHYS(start_pfn)), PFN_PHYS(start_pfn),
(u_long)__va(PFN_PHYS(max_free_pfn)), PFN_PHYS(max_free_pfn));
init_page_allocator(PFN_PHYS(start_pfn), PFN_PHYS(max_free_pfn));
/* Now initialise the physical->machine mapping table. */
printk("MM: done\n");
}
/*********************
* ALLOCATION BITMAP
* One bit per page of memory. Bit set => page is allocated.
*/
static unsigned long *alloc_bitmap;
#define PAGES_PER_MAPWORD (sizeof(unsigned long) * 8)
#define allocated_in_map(_pn) \
(alloc_bitmap[(_pn)/PAGES_PER_MAPWORD] & (1<<((_pn)&(PAGES_PER_MAPWORD-1))))
/*
* Hint regarding bitwise arithmetic in map_{alloc,free}:
* -(1<<n) sets all bits >= n.
* (1<<n)-1 sets all bits < n.
* Variable names in map_{alloc,free}:
* *_idx == Index into `alloc_bitmap' array.
* *_off == Bit offset within an element of the `alloc_bitmap' array.
*/
static void map_alloc(unsigned long first_page, unsigned long nr_pages)
{
unsigned long start_off, end_off, curr_idx, end_idx;
curr_idx = first_page / PAGES_PER_MAPWORD;
start_off = first_page & (PAGES_PER_MAPWORD-1);
end_idx = (first_page + nr_pages) / PAGES_PER_MAPWORD;
end_off = (first_page + nr_pages) & (PAGES_PER_MAPWORD-1);
if ( curr_idx == end_idx )
{
alloc_bitmap[curr_idx] |= ((1<<end_off)-1) & -(1<<start_off);
}
else
{
alloc_bitmap[curr_idx] |= -(1<<start_off);
while ( ++curr_idx < end_idx ) alloc_bitmap[curr_idx] = ~0L;
alloc_bitmap[curr_idx] |= (1<<end_off)-1;
}
}
static void map_free(unsigned long first_page, unsigned long nr_pages)
{
unsigned long start_off, end_off, curr_idx, end_idx;
curr_idx = first_page / PAGES_PER_MAPWORD;
start_off = first_page & (PAGES_PER_MAPWORD-1);
end_idx = (first_page + nr_pages) / PAGES_PER_MAPWORD;
end_off = (first_page + nr_pages) & (PAGES_PER_MAPWORD-1);
if ( curr_idx == end_idx )
{
alloc_bitmap[curr_idx] &= -(1<<end_off) | ((1<<start_off)-1);
}
else
{
alloc_bitmap[curr_idx] &= (1<<start_off)-1;
while ( ++curr_idx != end_idx ) alloc_bitmap[curr_idx] = 0;
alloc_bitmap[curr_idx] &= -(1<<end_off);
}
}
/*************************
* BINARY BUDDY ALLOCATOR
*/
typedef struct chunk_head_st chunk_head_t;
typedef struct chunk_tail_st chunk_tail_t;
struct chunk_head_st {
chunk_head_t *next;
chunk_head_t **pprev;
int level;
};
struct chunk_tail_st {
int level;
};
/* Linked lists of free chunks of different powers-of-two in size. */
#define FREELIST_SIZE ((sizeof(void*)<<3)-PAGE_SHIFT)
static chunk_head_t *free_head[FREELIST_SIZE];
static chunk_head_t free_tail[FREELIST_SIZE];
#define FREELIST_EMPTY(_l) ((_l)->next == NULL)
#define round_pgdown(_p) ((_p)&PAGE_MASK)
#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
/*
* Initialise allocator, placing addresses [@min,@max] in free pool.
* @min and @max are PHYSICAL addresses.
*/
static void init_page_allocator(unsigned long min, unsigned long max)
{
int i;
unsigned long range, bitmap_size;
chunk_head_t *ch;
chunk_tail_t *ct;
for ( i = 0; i < FREELIST_SIZE; i++ )
{
free_head[i] = &free_tail[i];
free_tail[i].pprev = &free_head[i];
free_tail[i].next = NULL;
}
min = round_pgup (min);
max = round_pgdown(max);
/* Allocate space for the allocation bitmap. */
bitmap_size = (max+1) >> (PAGE_SHIFT+3);
bitmap_size = round_pgup(bitmap_size);
alloc_bitmap = (unsigned long *)__va(min);
min += bitmap_size;
range = max - min;
/* All allocated by default. */
memset(alloc_bitmap, ~0, bitmap_size);
/* Free up the memory we've been given to play with. */
map_free(min>>PAGE_SHIFT, range>>PAGE_SHIFT);
/* The buddy lists are addressed in high memory. */
min += PAGE_OFFSET;
max += PAGE_OFFSET;
while ( range != 0 )
{
/*
* Next chunk is limited by alignment of min, but also
* must not be bigger than remaining range.
*/
for ( i = PAGE_SHIFT; (1<<(i+1)) <= range; i++ )
if ( min & (1<<i) ) break;
ch = (chunk_head_t *)min;
min += (1<<i);
range -= (1<<i);
ct = (chunk_tail_t *)min-1;
i -= PAGE_SHIFT;
ch->level = i;
ch->next = free_head[i];
ch->pprev = &free_head[i];
ch->next->pprev = &ch->next;
free_head[i] = ch;
ct->level = i;
}
}
/* Release a PHYSICAL address range to the allocator. */
void release_bytes_to_allocator(unsigned long min, unsigned long max)
{
min = round_pgup (min) + PAGE_OFFSET;
max = round_pgdown(max) + PAGE_OFFSET;
while ( min < max )
{
__free_pages(min, 0);
min += PAGE_SIZE;
}
}
/* Allocate 2^@order contiguous pages. Returns a VIRTUAL address. */
unsigned long __get_free_pages(int order)
{
int i;
chunk_head_t *alloc_ch, *spare_ch;
chunk_tail_t *spare_ct;
/* Find smallest order which can satisfy the request. */
for ( i = order; i < FREELIST_SIZE; i++ ) {
if ( !FREELIST_EMPTY(free_head[i]) )
break;
}
if ( i == FREELIST_SIZE ) goto no_memory;
/* Unlink a chunk. */
alloc_ch = free_head[i];
free_head[i] = alloc_ch->next;
alloc_ch->next->pprev = alloc_ch->pprev;
/* We may have to break the chunk a number of times. */
while ( i != order )
{
/* Split into two equal parts. */
i--;
spare_ch = (chunk_head_t *)((char *)alloc_ch + (1<<(i+PAGE_SHIFT)));
spare_ct = (chunk_tail_t *)((char *)spare_ch + (1<<(i+PAGE_SHIFT)))-1;
/* Create new header for spare chunk. */
spare_ch->level = i;
spare_ch->next = free_head[i];
spare_ch->pprev = &free_head[i];
spare_ct->level = i;
/* Link in the spare chunk. */
spare_ch->next->pprev = &spare_ch->next;
free_head[i] = spare_ch;
}
map_alloc(__pa(alloc_ch)>>PAGE_SHIFT, 1<<order);
return((unsigned long)alloc_ch);
no_memory:
printk("Cannot handle page request order %d!\n", order);
return 0;
}
/* Free 2^@order pages at VIRTUAL address @p. */
void __free_pages(unsigned long p, int order)
{
unsigned long size = 1 << (order + PAGE_SHIFT);
chunk_head_t *ch;
chunk_tail_t *ct;
unsigned long pagenr = __pa(p) >> PAGE_SHIFT;
map_free(pagenr, 1<<order);
/* Merge chunks as far as possible. */
for ( ; ; )
{
if ( (p & size) )
{
/* Merge with predecessor block? */
if ( allocated_in_map(pagenr-1) ) break;
ct = (chunk_tail_t *)p - 1;
if ( ct->level != order ) break;
ch = (chunk_head_t *)(p - size);
p -= size;
}
else
{
/* Merge with successor block? */
if ( allocated_in_map(pagenr+(1<<order)) ) break;
ch = (chunk_head_t *)(p + size);
if ( ch->level != order ) break;
}
/* Okay, unlink the neighbour. */
*ch->pprev = ch->next;
ch->next->pprev = ch->pprev;
order++;
size <<= 1;
}
/* Okay, add the final chunk to the appropriate free list. */
ch = (chunk_head_t *)p;
ct = (chunk_tail_t *)(p+size)-1;
ct->level = order;
ch->level = order;
ch->pprev = &free_head[order];
ch->next = free_head[order];
ch->next->pprev = &ch->next;
free_head[order] = ch;
}
+149
View File
@@ -0,0 +1,149 @@
/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
****************************************************************************
* (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
****************************************************************************
*
* File: time.c
* Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
* Changes:
*
* Date: Jul 2003
*
* Environment: Xen Minimal OS
* Description: Simple time and timer functions
*
****************************************************************************
* $Id: c-insert.c,v 1.7 2002/11/08 16:04:34 rn Exp $
****************************************************************************
*/
#include <os.h>
#include <types.h>
#include <hypervisor.h>
#include <events.h>
#include <time.h>
#include <lib.h>
/************************************************************************
* Time functions
*************************************************************************/
static unsigned int rdtsc_bitshift;
static u32 st_scale_f;
static u32 st_scale_i;
static u32 shadow_st_pcc;
static s_time_t shadow_st;
static u32 shadow_wc_version=0;
static long shadow_tv_sec;
static long shadow_tv_usec;
static s_time_t shadow_wc_timestamp;
/*
* System time.
* We need to read the values from the shared info page "atomically"
* and use the cycle counter value as the "version" number. Clashes
* should be very rare.
*/
inline s_time_t get_s_time(void)
{
s32 delta_tsc;
u32 low;
u64 delta, tsc;
u32 version;
u64 cpu_freq, scale;
/* check if our values are still up-to-date */
while ( (version = HYPERVISOR_shared_info->wc_version) !=
shadow_wc_version )
{
barrier();
shadow_wc_version = version;
shadow_tv_sec = HYPERVISOR_shared_info->tv_sec;
shadow_tv_usec = HYPERVISOR_shared_info->tv_usec;
shadow_wc_timestamp = HYPERVISOR_shared_info->wc_timestamp;
shadow_st_pcc = HYPERVISOR_shared_info->st_timestamp;
shadow_st = HYPERVISOR_shared_info->system_time;
rdtsc_bitshift = HYPERVISOR_shared_info->rdtsc_bitshift;
cpu_freq = HYPERVISOR_shared_info->cpu_freq;
/* XXX cpu_freq as u32 limits it to 4.29 GHz. Get a better do_div! */
scale = 1000000000LL << (32 + rdtsc_bitshift);
scale /= cpu_freq;
st_scale_f = scale & 0xffffffff;
st_scale_i = scale >> 32;
barrier();
}
rdtscll(tsc);
low = (u32)(tsc >> rdtsc_bitshift);
delta_tsc = (s32)(low - shadow_st_pcc);
if ( unlikely(delta_tsc < 0) ) delta_tsc = 0;
delta = ((u64)delta_tsc * st_scale_f);
delta >>= 32;
delta += ((u64)delta_tsc * st_scale_i);
return shadow_st + delta;
}
/*
* Wallclock time.
* Based on what the hypervisor tells us, extrapolated using system time.
* Again need to read a number of values from the shared page "atomically".
* this time using a version number.
*/
void gettimeofday(struct timeval *tv)
{
long usec, sec;
u64 now;
now = get_s_time();
usec = ((unsigned long)(now-shadow_wc_timestamp))/1000;
sec = shadow_tv_sec;
usec += shadow_tv_usec;
while ( usec >= 1000000 )
{
usec -= 1000000;
sec++;
}
tv->tv_sec = sec;
tv->tv_usec = usec;
}
static void timer_handler(int ev, struct pt_regs *regs)
{
static int i;
s_time_t now;
i++;
if (i >= 1000) {
now = get_s_time();
printf("T(%lld)\n", now);
i = 0;
}
}
void init_time(void)
{
u64 __cpu_khz;
unsigned long cpu_khz;
__cpu_khz = HYPERVISOR_shared_info->cpu_freq;
cpu_khz = (u32) (__cpu_khz/1000);
printk("Xen reported: %lu.%03lu MHz processor.\n",
cpu_khz / 1000, cpu_khz % 1000);
add_ev_action(EV_TIMER, &timer_handler);
enable_ev_action(EV_TIMER);
enable_hypervisor_event(EV_TIMER);
}
+150
View File
@@ -0,0 +1,150 @@
#include <os.h>
#include <hypervisor.h>
#include <lib.h>
/*
* These are assembler stubs in entry.S.
* They are the actual entry points for virtual exceptions.
*/
void divide_error(void);
void debug(void);
void int3(void);
void overflow(void);
void bounds(void);
void invalid_op(void);
void device_not_available(void);
void double_fault(void);
void coprocessor_segment_overrun(void);
void invalid_TSS(void);
void segment_not_present(void);
void stack_segment(void);
void general_protection(void);
void page_fault(void);
void coprocessor_error(void);
void simd_coprocessor_error(void);
void alignment_check(void);
void spurious_interrupt_bug(void);
void machine_check(void);
/*
* C handlers here have their parameter-list constructed by the
* assembler stubs above. Each one gets a pointer to a list
* of register values (to be restored at end of exception).
* Some will also receive an error code -- this is the code that
* was generated by the processor for the underlying real exception.
*
* Note that the page-fault exception is special. It also receives
* the faulting linear address. Normally this would be found in
* register CR2, but that is not accessible in a virtualised OS.
*/
static void inline do_trap(int trapnr, char *str,
struct pt_regs * regs, long error_code)
{
printk("Trap\n");
}
#define DO_ERROR(trapnr, str, name) \
void do_##name(struct pt_regs * regs, long error_code) \
{ \
do_trap(trapnr, str, regs, error_code); \
}
#define DO_ERROR_INFO(trapnr, str, name, sicode, siaddr) \
void do_##name(struct pt_regs * regs, long error_code) \
{ \
do_trap(trapnr, str, regs, error_code); \
}
DO_ERROR_INFO( 0, "divide error", divide_error, FPE_INTDIV, regs->eip)
DO_ERROR( 3, "int3", int3)
DO_ERROR( 4, "overflow", overflow)
DO_ERROR( 5, "bounds", bounds)
DO_ERROR_INFO( 6, "invalid operand", invalid_op, ILL_ILLOPN, regs->eip)
DO_ERROR( 7, "device not available", device_not_available)
DO_ERROR( 8, "double fault", double_fault)
DO_ERROR( 9, "coprocessor segment overrun", coprocessor_segment_overrun)
DO_ERROR(10, "invalid TSS", invalid_TSS)
DO_ERROR(11, "segment not present", segment_not_present)
DO_ERROR(12, "stack segment", stack_segment)
DO_ERROR_INFO(17, "alignment check", alignment_check, BUS_ADRALN, 0)
DO_ERROR(18, "machine check", machine_check)
void do_page_fault(struct pt_regs * regs, long error_code,
unsigned long address)
{
printk("Page fault\n");
}
void do_general_protection(struct pt_regs * regs, long error_code)
{
printk("GPF\n");
}
void do_debug(struct pt_regs * regs, long error_code)
{
printk("Debug exception\n");
#define TF_MASK 0x100
regs->eflags &= ~TF_MASK;
}
void do_coprocessor_error(struct pt_regs * regs, long error_code)
{
printk("Copro error\n");
}
void simd_math_error(void *eip)
{
printk("SIMD error\n");
}
void do_simd_coprocessor_error(struct pt_regs * regs,
long error_code)
{
printk("SIMD copro error\n");
}
void do_spurious_interrupt_bug(struct pt_regs * regs,
long error_code)
{
}
/*
* Submit a virtual IDT to teh hypervisor. This consists of tuples
* (interrupt vector, privilege ring, CS:EIP of handler).
* The 'privilege ring' field specifies the least-privileged ring that
* can trap to that vector using a software-interrupt instruction (INT).
*/
static trap_info_t trap_table[] = {
{ 0, 0, __KERNEL_CS, (unsigned long)divide_error },
{ 1, 0, __KERNEL_CS, (unsigned long)debug },
{ 3, 3, __KERNEL_CS, (unsigned long)int3 },
{ 4, 3, __KERNEL_CS, (unsigned long)overflow },
{ 5, 3, __KERNEL_CS, (unsigned long)bounds },
{ 6, 0, __KERNEL_CS, (unsigned long)invalid_op },
{ 7, 0, __KERNEL_CS, (unsigned long)device_not_available },
{ 8, 0, __KERNEL_CS, (unsigned long)double_fault },
{ 9, 0, __KERNEL_CS, (unsigned long)coprocessor_segment_overrun },
{ 10, 0, __KERNEL_CS, (unsigned long)invalid_TSS },
{ 11, 0, __KERNEL_CS, (unsigned long)segment_not_present },
{ 12, 0, __KERNEL_CS, (unsigned long)stack_segment },
{ 13, 0, __KERNEL_CS, (unsigned long)general_protection },
{ 14, 0, __KERNEL_CS, (unsigned long)page_fault },
{ 15, 0, __KERNEL_CS, (unsigned long)spurious_interrupt_bug },
{ 16, 0, __KERNEL_CS, (unsigned long)coprocessor_error },
{ 17, 0, __KERNEL_CS, (unsigned long)alignment_check },
{ 18, 0, __KERNEL_CS, (unsigned long)machine_check },
{ 19, 0, __KERNEL_CS, (unsigned long)simd_coprocessor_error },
{ 0, 0, 0, 0 }
};
void trap_init(void)
{
HYPERVISOR_set_trap_table(trap_table);
}
+82
View File
@@ -0,0 +1,82 @@
/* ld script to make i386 Linux kernel
* Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
*/
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
SECTIONS
{
. = 0xC0000000 + 0x000000;
_text = .; /* Text and read-only data */
.text : {
*(.text)
*(.fixup)
*(.gnu.warning)
} = 0x9090
_etext = .; /* End of text section */
.rodata : { *(.rodata) *(.rodata.*) }
.kstrtab : { *(.kstrtab) }
. = ALIGN(16); /* Exception table */
__start___ex_table = .;
__ex_table : { *(__ex_table) }
__stop___ex_table = .;
__start___ksymtab = .; /* Kernel symbol table */
__ksymtab : { *(__ksymtab) }
__stop___ksymtab = .;
.data : { /* Data */
*(.data)
CONSTRUCTORS
}
_edata = .; /* End of data section */
. = ALIGN(8192); /* init_task */
.data.init_task : { *(.data.init_task) }
. = ALIGN(4096); /* Init code and data */
__init_begin = .;
.text.init : { *(.text.init) }
.data.init : { *(.data.init) }
. = ALIGN(16);
__setup_start = .;
.setup.init : { *(.setup.init) }
__setup_end = .;
__initcall_start = .;
.initcall.init : { *(.initcall.init) }
__initcall_end = .;
. = ALIGN(4096);
__init_end = .;
. = ALIGN(4096);
.data.page_aligned : { *(.data.idt) }
. = ALIGN(32);
.data.cacheline_aligned : { *(.data.cacheline_aligned) }
__bss_start = .; /* BSS */
.bss : {
*(.bss)
}
_end = . ;
/* Sections to be discarded */
/DISCARD/ : {
*(.text.exit)
*(.data.exit)
*(.exitcall.exit)
}
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
}
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.