mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
Add PV-GRUB
This fetches GRUB1 sources, applies the {graphical, print function,
save default, and ext3_256byte} patches from debian, and applies a
patch to make it work on x86_64 and port it to Mini-OS. By using
libxc, PV-GRUB can then "kexec" the loaded kernel from inside the
domain itself, hence permitting to avoid the security-concerned
pygrub.
Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
This commit is contained in:
1 parent
7074b13cee
commit
a2c7db64f5
24 files changed
+5654
-24
No files matched your search
+34
-7
@@ -14,6 +14,7 @@ ZLIB_VERSION=1.2.3
|
||||
LIBPCI_VERSION=2.2.9
|
||||
NEWLIB_DATE=2008-01-01
|
||||
LWIP_DATE=2008-06-01
|
||||
GRUB_DATE=2008-06-01
|
||||
|
||||
WGET=wget -c
|
||||
|
||||
@@ -39,10 +40,10 @@ CROSS_PREFIX=$(CURDIR)/$(CROSS_ROOT)
|
||||
export CROSS_COMPILE=$(GNU_TARGET_ARCH)-xen-elf-
|
||||
export PATH:=$(CROSS_PREFIX)/bin:$(PATH)
|
||||
|
||||
TARGETS=ioemu c caml
|
||||
TARGETS=ioemu c caml grub
|
||||
|
||||
.PHONY: all
|
||||
all: ioemu-stubdom c-stubdom
|
||||
all: ioemu-stubdom c-stubdom pv-grub
|
||||
|
||||
################
|
||||
# Cross-binutils
|
||||
@@ -221,30 +222,53 @@ caml: cross-newlib mk-symlinks
|
||||
c: cross-newlib mk-symlinks
|
||||
$(MAKE) -C $@ LWIPDIR=$(CURDIR)/lwip-cvs
|
||||
|
||||
######
|
||||
# Grub
|
||||
######
|
||||
|
||||
grub-cvs:
|
||||
cvs -z 9 -d :pserver:anonymous@cvs.sv.gnu.org:/sources/grub co -D $(GRUB_DATE) -d $@ grub
|
||||
for i in grub.patches/* ; do \
|
||||
patch -d $@ -p1 < $$i ; \
|
||||
done
|
||||
|
||||
.PHONY: grub
|
||||
grub: grub-cvs cross-newlib mk-symlinks
|
||||
$(MAKE) -C $@
|
||||
|
||||
########
|
||||
# minios
|
||||
########
|
||||
|
||||
.PHONY: ioemu-stubdom
|
||||
ioemu-stubdom: mini-os-ioemu lwip-cvs libxc ioemu
|
||||
$(MAKE) -C $(MINI_OS) OBJ_DIR=$(CURDIR)/$< LWIPDIR=$(CURDIR)/lwip-cvs APP_OBJS="$(CURDIR)/ioemu/i386-dm-stubdom/qemu.a $(CURDIR)/ioemu/i386-dm-stubdom/libqemu.a" CFLAGS=-DCONFIG_QEMU
|
||||
DEF_CFLAGS=-DCONFIG_QEMU $(MAKE) -C $(MINI_OS) OBJ_DIR=$(CURDIR)/$< LWIPDIR=$(CURDIR)/lwip-cvs APP_OBJS="$(CURDIR)/ioemu/i386-dm-stubdom/qemu.a $(CURDIR)/ioemu/i386-dm-stubdom/libqemu.a"
|
||||
|
||||
CAMLLIB = $(shell ocamlc -where)
|
||||
.PHONY: caml-stubdom
|
||||
caml-stubdom: mini-os-caml lwip-cvs libxc caml
|
||||
$(MAKE) -C $(MINI_OS) OBJ_DIR=$(CURDIR)/$< LWIPDIR=$(CURDIR)/lwip-cvs APP_OBJS="$(CURDIR)/caml/main-caml.o $(CURDIR)/caml/caml.o $(CAMLLIB)/libasmrun.a" CFLAGS=-DCONFIG_CAML
|
||||
DEF_CFLAGS=-DCONFIG_CAML $(MAKE) -C $(MINI_OS) OBJ_DIR=$(CURDIR)/$< LWIPDIR=$(CURDIR)/lwip-cvs APP_OBJS="$(CURDIR)/caml/main-caml.o $(CURDIR)/caml/caml.o $(CAMLLIB)/libasmrun.a"
|
||||
|
||||
.PHONY: c-stubdom
|
||||
c-stubdom: mini-os-c lwip-cvs libxc c
|
||||
$(MAKE) -C $(MINI_OS) OBJ_DIR=$(CURDIR)/$< LWIPDIR=$(CURDIR)/lwip-cvs APP_OBJS=$(CURDIR)/c/main.a CFLAGS=-DCONFIG_C
|
||||
DEF_CFLAGS=-DCONFIG_C $(MAKE) -C $(MINI_OS) OBJ_DIR=$(CURDIR)/$< LWIPDIR=$(CURDIR)/lwip-cvs APP_OBJS=$(CURDIR)/c/main.a
|
||||
|
||||
.PHONY: pv-grub
|
||||
pv-grub: mini-os-grub libxc grub
|
||||
DEF_CFLAGS=-DCONFIG_GRUB $(MAKE) -C $(MINI_OS) OBJ_DIR=$(CURDIR)/$< APP_OBJS=$(CURDIR)/grub/main.a
|
||||
|
||||
#########
|
||||
# install
|
||||
#########
|
||||
|
||||
install: mini-os-ioemu/mini-os.gz
|
||||
install: install-ioemu install-grub
|
||||
|
||||
install-ioemu: mini-os-ioemu/mini-os.gz
|
||||
$(INSTALL_PROG) stubdom-dm "$(DESTDIR)/usr/lib/xen/bin"
|
||||
$(INSTALL_PROG) $< "$(DESTDIR)/usr/lib/xen/boot/stubdom.gz"
|
||||
$(INSTALL_PROG) $< "$(DESTDIR)/usr/lib/xen/boot/ioemu-stubdom.gz"
|
||||
|
||||
install-grub: mini-os-grub/mini-os.gz
|
||||
$(INSTALL_PROG) $< "$(DESTDIR)/usr/lib/xen/boot/pv-grub.gz"
|
||||
|
||||
#######
|
||||
# clean
|
||||
@@ -256,8 +280,10 @@ clean:
|
||||
rm -fr mini-os-ioemu
|
||||
rm -fr mini-os-c
|
||||
rm -fr mini-os-caml
|
||||
rm -fr mini-os-grub
|
||||
$(MAKE) -C caml clean
|
||||
$(MAKE) -C c clean
|
||||
$(MAKE) -C grub clean
|
||||
rm -fr libxc ioemu mini-os include
|
||||
|
||||
# clean the cross-compilation result
|
||||
@@ -274,6 +300,7 @@ patchclean: crossclean
|
||||
rm -fr gcc-$(GCC_VERSION)
|
||||
rm -fr newlib-cvs
|
||||
rm -fr lwip-cvs
|
||||
rm -fr grub-cvs
|
||||
|
||||
# clean downloads
|
||||
.PHONY: downloadclean
|
||||
|
||||
+59
-10
@@ -6,12 +6,19 @@ Then make install to install the result.
|
||||
|
||||
Also, run make and make install in $XEN_ROOT/tools/fs-back
|
||||
|
||||
|
||||
|
||||
IOEMU stubdom
|
||||
=============
|
||||
|
||||
This boosts HVM performance by putting ioemu in its own lightweight domain.
|
||||
|
||||
General Configuration
|
||||
=====================
|
||||
|
||||
In your HVM config "hvmconfig",
|
||||
|
||||
- use /usr/lib/xen/bin/stubdom-dm as dm script
|
||||
- use /usr/lib/xen/bin/stubdom-dm as dm script:
|
||||
|
||||
device_model = '/usr/lib/xen/bin/stubdom-dm'
|
||||
|
||||
@@ -25,7 +32,7 @@ device_model = '/usr/lib/xen/bin/stubdom-dm'
|
||||
Create /etc/xen/stubdom-hvmconfig (where "hvmconfig" is the name of your HVM
|
||||
guest) with
|
||||
|
||||
kernel = "/usr/lib/xen/boot/stubdom.gz"
|
||||
kernel = "/usr/lib/xen/boot/ioemu-stubdom.gz"
|
||||
vif = [ '', 'ip=10.0.1.1,mac=aa:00:00:12:23:34']
|
||||
disk = [ 'file:/tmp/install.iso,hdc:cdrom,r', 'phy:/dev/sda6,hda,w', 'file:/tmp/test,hdb,r' ]
|
||||
|
||||
@@ -42,34 +49,36 @@ There are three posibilities
|
||||
|
||||
* Using SDL
|
||||
|
||||
In hvmconfig, disable vnc:
|
||||
- In hvmconfig, disable vnc and sdl:
|
||||
|
||||
vnc = 0
|
||||
sdl = 0
|
||||
|
||||
In stubdom-hvmconfig, set a vfb:
|
||||
- In stubdom-hvmconfig, set an sdl vfb:
|
||||
|
||||
vfb = [ 'type=sdl' ]
|
||||
|
||||
* Using a VNC server in the stub domain
|
||||
|
||||
In hvmconfig, set vnclisten to "172.30.206.1" for instance. Do not use a host
|
||||
name as Mini-OS does not have a name resolver. Do not use 127.0.0.1 since then
|
||||
you will not be able to connect to it.
|
||||
- In hvmconfig, set vnclisten to "172.30.206.1" for instance. Do not use a
|
||||
host name as Mini-OS does not have a name resolver. Do not use 127.0.0.1 since
|
||||
then you will not be able to connect to it.
|
||||
|
||||
vnc = 1
|
||||
vnclisten = "172.30.206.1"
|
||||
|
||||
In stubdom-hvmconfig, fill the reserved vif with the same IP, for instance:
|
||||
- In stubdom-hvmconfig, fill the reserved vif with the same IP, for instance:
|
||||
|
||||
vif = [ 'ip=172.30.206.1', 'ip=10.0.1.1,mac=aa:00:00:12:23:34']
|
||||
|
||||
* Using a VNC server in dom0
|
||||
|
||||
In hvmconfig, disable vnc:
|
||||
- In hvmconfig, disable vnc and sdl:
|
||||
|
||||
vnc = 0
|
||||
sdl = 0
|
||||
|
||||
In stubdom-hvmconfig, set a vfb:
|
||||
- In stubdom-hvmconfig, set a vnc vfb:
|
||||
|
||||
vfb = [ 'type=vnc' ]
|
||||
|
||||
@@ -85,3 +94,43 @@ ln -s /var/lib/xen /exports/var/lib
|
||||
/usr/sbin/fs-backend &
|
||||
|
||||
xm create hvmconfig
|
||||
|
||||
|
||||
|
||||
PV-GRUB
|
||||
=======
|
||||
|
||||
This replaces pygrub to boot domU images safely: it runs the regular grub
|
||||
inside the created domain itself and uses regular domU facilities to read the
|
||||
disk / fetch files from network etc. ; it eventually loads the PV kernel and
|
||||
chain-boots it.
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
In your PV config,
|
||||
|
||||
- use /usr/lib/xen/boot/pv-grub.gz as kernel:
|
||||
|
||||
kernel = "/usr/lib/xen/boot/pv-grub.gz"
|
||||
|
||||
- set the path to menu.lst, as seen from the domU, in extra:
|
||||
|
||||
extra = "(hd0,0)/boot/grub/menu.lst"
|
||||
|
||||
you can also use a tftp path (dhcp will be automatically performed):
|
||||
|
||||
extra = "(nd)/somepath/menu.lst"
|
||||
|
||||
or you can set it in option 150 of your dhcp server and leave extra empty
|
||||
|
||||
Limitations
|
||||
===========
|
||||
|
||||
- You can not boot a 64bit kernel with a 32bit-compiled PV-GRUB and vice-versa.
|
||||
To cross-compile a 32bit PV-GRUB,
|
||||
|
||||
export XEN_TARGET_ARCH=x86_32
|
||||
|
||||
- bootsplash is supported, but the ioemu backend does not yet support restart
|
||||
for use by the booted kernel.
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,80 @@
|
||||
2006-01-05 Otavio Salvador <otavio@debian.org>
|
||||
|
||||
* Rediff.
|
||||
|
||||
2005-16-10 Samuel Thibault <samuel.thibault@ens-lyon.org>
|
||||
|
||||
* docs/grub.texi: Added print command description.
|
||||
* stage2/builtins.c(print_func): New function.
|
||||
(builtin_print): New variable.
|
||||
(builtin_table): Added builtin_print in table.
|
||||
|
||||
Debian Status Following:
|
||||
Added by: Otavio Salvador
|
||||
Date: 2006-01-05
|
||||
|
||||
diff -Nur grub-0.97-bkp/docs/grub.texi grub-0.97/docs/grub.texi
|
||||
--- grub-0.97-bkp/docs/grub.texi 2006-01-05 10:59:05.564347912 -0200
|
||||
+++ grub-0.97/docs/grub.texi 2006-01-05 11:18:59.033912960 -0200
|
||||
@@ -2685,6 +2685,7 @@
|
||||
* module:: Load a module
|
||||
* modulenounzip:: Load a module without decompression
|
||||
* pause:: Wait for a key press
|
||||
+* print:: Print a message
|
||||
* quit:: Exit from the grub shell
|
||||
* reboot:: Reboot your computer
|
||||
* read:: Read data from memory
|
||||
@@ -3091,6 +3092,16 @@
|
||||
@end deffn
|
||||
|
||||
|
||||
+@node print
|
||||
+@subsection print
|
||||
+
|
||||
+@deffn Command print message @dots{}
|
||||
+Print the @var{message}. Note that placing @key{^G} (ASCII code 7) in the
|
||||
+message will cause the speaker to emit the standard beep sound, which is
|
||||
+useful for visually impaired people.
|
||||
+@end deffn
|
||||
+
|
||||
+
|
||||
@node quit
|
||||
@subsection quit
|
||||
|
||||
diff -Nur grub-0.97-bkp/stage2/builtins.c grub-0.97/stage2/builtins.c
|
||||
--- grub-0.97-bkp/stage2/builtins.c 2006-01-05 10:59:05.550350040 -0200
|
||||
+++ grub-0.97/stage2/builtins.c 2006-01-05 11:19:28.422445224 -0200
|
||||
@@ -2323,6 +2323,25 @@
|
||||
"Probe I/O ports used for the drive DRIVE."
|
||||
};
|
||||
|
||||
+/* print */
|
||||
+static int
|
||||
+print_func (char *arg, int flags)
|
||||
+{
|
||||
+ printf("%s\n", arg);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct builtin builtin_print =
|
||||
+{
|
||||
+ "print",
|
||||
+ print_func,
|
||||
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_NO_ECHO,
|
||||
+ "print [MESSAGE ...]",
|
||||
+ "Print MESSAGE."
|
||||
+};
|
||||
+
|
||||
+
|
||||
|
||||
/* kernel */
|
||||
static int
|
||||
@@ -4848,6 +4867,7 @@
|
||||
&builtin_parttype,
|
||||
&builtin_password,
|
||||
&builtin_pause,
|
||||
+ &builtin_print,
|
||||
#ifdef GRUB_UTIL
|
||||
&builtin_quit,
|
||||
#endif /* GRUB_UTIL */
|
||||
@@ -0,0 +1,186 @@
|
||||
Index: grub/stage2/builtins.c
|
||||
===================================================================
|
||||
--- grub.orig/stage2/builtins.c 2008-06-02 18:06:08.942580000 +0100
|
||||
+++ grub/stage2/builtins.c 2008-06-06 18:35:07.548390000 +0100
|
||||
@@ -86,6 +86,10 @@
|
||||
inside other functions. */
|
||||
static int configfile_func (char *arg, int flags);
|
||||
|
||||
+static int savedefault_helper (char *arg, int flags);
|
||||
+
|
||||
+static int savedefault_shell (char *arg, int flags);
|
||||
+
|
||||
/* Initialize the data for builtins. */
|
||||
void
|
||||
init_builtins (void)
|
||||
@@ -3512,7 +3516,109 @@
|
||||
static int
|
||||
savedefault_func (char *arg, int flags)
|
||||
{
|
||||
-#if !defined(SUPPORT_DISKLESS) && !defined(GRUB_UTIL)
|
||||
+#if !defined(SUPPORT_DISKLESS)
|
||||
+ #if !defined(GRUB_UTIL)
|
||||
+ return savedefault_helper(arg, flags);
|
||||
+ #else
|
||||
+ return savedefault_shell(arg, flags);
|
||||
+ #endif
|
||||
+#else /* !SUPPORT_DISKLESS */
|
||||
+ errnum = ERR_UNRECOGNIZED;
|
||||
+ return 1;
|
||||
+#endif /* !SUPPORT_DISKLESS */
|
||||
+}
|
||||
+
|
||||
+#if !defined(SUPPORT_DISKLESS) && defined(GRUB_UTIL)
|
||||
+/* savedefault_shell */
|
||||
+static int
|
||||
+savedefault_shell(char *arg, int flags)
|
||||
+ {
|
||||
+ int once_only = 0;
|
||||
+ int new_default;
|
||||
+ int curr_default = -1;
|
||||
+ int curr_prev_default = -1;
|
||||
+ int new_prev_default = -1;
|
||||
+ FILE *fp;
|
||||
+ size_t bytes = 10;
|
||||
+ char line[bytes];
|
||||
+ char *default_file = (char *) DEFAULT_FILE_BUF;
|
||||
+ char buf[bytes];
|
||||
+ int i;
|
||||
+
|
||||
+ while (1)
|
||||
+ {
|
||||
+ if (grub_memcmp ("--default=", arg, sizeof ("--default=") - 1) == 0)
|
||||
+ {
|
||||
+ char *p = arg + sizeof ("--default=") - 1;
|
||||
+ if (! safe_parse_maxint (&p, &new_default))
|
||||
+ return 1;
|
||||
+ arg = skip_to (0, arg);
|
||||
+ }
|
||||
+ else if (grub_memcmp ("--once", arg, sizeof ("--once") - 1) == 0)
|
||||
+ {
|
||||
+ once_only = 1;
|
||||
+ arg = skip_to (0, arg);
|
||||
+ }
|
||||
+ else
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ *default_file = 0;
|
||||
+ grub_strncat (default_file, config_file, DEFAULT_FILE_BUFLEN);
|
||||
+ for (i = grub_strlen(default_file); i >= 0; i--)
|
||||
+ if (default_file[i] == '/')
|
||||
+ {
|
||||
+ i++;
|
||||
+ break;
|
||||
+ }
|
||||
+ default_file[i] = 0;
|
||||
+ grub_strncat (default_file + i, "default", DEFAULT_FILE_BUFLEN - i);
|
||||
+
|
||||
+ if(!(fp = fopen(default_file,"r")))
|
||||
+ {
|
||||
+ errnum = ERR_READ;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ fgets(line, bytes, fp);
|
||||
+ fclose(fp);
|
||||
+
|
||||
+ sscanf(line, "%d:%d", &curr_prev_default, &curr_default);
|
||||
+
|
||||
+ if(curr_default != -1)
|
||||
+ new_prev_default = curr_default;
|
||||
+ else
|
||||
+ {
|
||||
+ if(curr_prev_default != -1)
|
||||
+ new_prev_default = curr_prev_default;
|
||||
+ else
|
||||
+ new_prev_default = 0;
|
||||
+ }
|
||||
+
|
||||
+ if(once_only)
|
||||
+ sprintf(buf, "%d:%d", new_prev_default, new_default);
|
||||
+ else
|
||||
+ sprintf(buf, "%d", new_default);
|
||||
+
|
||||
+ if(!(fp = fopen(default_file,"w")))
|
||||
+ {
|
||||
+ errnum = ERR_READ;
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ fprintf(fp, buf);
|
||||
+
|
||||
+fail:
|
||||
+ fclose(fp);
|
||||
+ return errnum;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+/* savedefault_helper */
|
||||
+static int
|
||||
+savedefault_helper (char *arg, int flags)
|
||||
+{
|
||||
+#if !defined(SUPPORT_DISKLESS)
|
||||
unsigned long tmp_drive = saved_drive;
|
||||
unsigned long tmp_partition = saved_partition;
|
||||
char *default_file = (char *) DEFAULT_FILE_BUF;
|
||||
@@ -3588,22 +3694,26 @@
|
||||
|
||||
disk_read_hook = disk_read_savesect_func;
|
||||
len = grub_read (buf, sizeof (buf));
|
||||
+ buf[9]='\0';/* Make sure grub_strstr() below terminates */
|
||||
disk_read_hook = 0;
|
||||
grub_close ();
|
||||
|
||||
- if (len != sizeof (buf))
|
||||
- {
|
||||
- /* This is too small. Do not modify the file manually, please! */
|
||||
- errnum = ERR_READ;
|
||||
- goto fail;
|
||||
- }
|
||||
-
|
||||
if (sector_count > 2)
|
||||
{
|
||||
/* Is this possible?! Too fragmented! */
|
||||
errnum = ERR_FSYS_CORRUPT;
|
||||
goto fail;
|
||||
}
|
||||
+
|
||||
+ char *tmp;
|
||||
+ if((tmp = grub_strstr(buf, ":")) != NULL)
|
||||
+ {
|
||||
+ int f_len = grub_strlen(buf) - grub_strlen(tmp);
|
||||
+ char *def;
|
||||
+ buf[f_len] = '\0';
|
||||
+ def = buf;
|
||||
+ safe_parse_maxint (&def, &entryno);
|
||||
+ }
|
||||
|
||||
/* Set up a string to be written. */
|
||||
grub_memset (buf, '\n', sizeof (buf));
|
||||
Index: grub/stage2/stage2.c
|
||||
===================================================================
|
||||
--- grub.orig/stage2/stage2.c 2008-06-02 18:06:08.858579000 +0100
|
||||
+++ grub/stage2/stage2.c 2008-06-06 18:04:03.585354000 +0100
|
||||
@@ -49,7 +49,8 @@
|
||||
return 0;
|
||||
#endif /* GRUB_UTIL */
|
||||
|
||||
- preset_menu_offset = 0;
|
||||
+ if (preset_menu_offset)
|
||||
+ return 0;
|
||||
return preset_menu != 0;
|
||||
}
|
||||
|
||||
@@ -934,7 +935,11 @@
|
||||
len = grub_read (buf, sizeof (buf));
|
||||
if (len > 0)
|
||||
{
|
||||
+ char *tmp;
|
||||
buf[sizeof (buf) - 1] = 0;
|
||||
+ if((tmp = grub_strstr(p, ":")) != NULL)
|
||||
+ p = tmp + 1;
|
||||
+
|
||||
safe_parse_maxint (&p, &saved_entryno);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
|
||||
Patch from Red Hat. See #463236, #463123.
|
||||
|
||||
Index: grub/stage2/fsys_ext2fs.c
|
||||
===================================================================
|
||||
--- grub.orig/stage2/fsys_ext2fs.c 2008-05-27 18:47:19.045183000 +0100
|
||||
+++ grub/stage2/fsys_ext2fs.c 2008-05-27 19:09:21.293187000 +0100
|
||||
@@ -79,7 +79,52 @@
|
||||
__u32 s_rev_level; /* Revision level */
|
||||
__u16 s_def_resuid; /* Default uid for reserved blocks */
|
||||
__u16 s_def_resgid; /* Default gid for reserved blocks */
|
||||
- __u32 s_reserved[235]; /* Padding to the end of the block */
|
||||
+ /*
|
||||
+ * These fields are for EXT2_DYNAMIC_REV superblocks only.
|
||||
+ *
|
||||
+ * Note: the difference between the compatible feature set and
|
||||
+ * the incompatible feature set is that if there is a bit set
|
||||
+ * in the incompatible feature set that the kernel doesn't
|
||||
+ * know about, it should refuse to mount the filesystem.
|
||||
+ *
|
||||
+ * e2fsck's requirements are more strict; if it doesn't know
|
||||
+ * about a feature in either the compatible or incompatible
|
||||
+ * feature set, it must abort and not try to meddle with
|
||||
+ * things it doesn't understand...
|
||||
+ */
|
||||
+ __u32 s_first_ino; /* First non-reserved inode */
|
||||
+ __u16 s_inode_size; /* size of inode structure */
|
||||
+ __u16 s_block_group_nr; /* block group # of this superblock */
|
||||
+ __u32 s_feature_compat; /* compatible feature set */
|
||||
+ __u32 s_feature_incompat; /* incompatible feature set */
|
||||
+ __u32 s_feature_ro_compat; /* readonly-compatible feature set */
|
||||
+ __u8 s_uuid[16]; /* 128-bit uuid for volume */
|
||||
+ char s_volume_name[16]; /* volume name */
|
||||
+ char s_last_mounted[64]; /* directory where last mounted */
|
||||
+ __u32 s_algorithm_usage_bitmap; /* For compression */
|
||||
+ /*
|
||||
+ * Performance hints. Directory preallocation should only
|
||||
+ * happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on.
|
||||
+ */
|
||||
+ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
|
||||
+ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
|
||||
+ __u16 s_reserved_gdt_blocks;/* Per group table for online growth */
|
||||
+ /*
|
||||
+ * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set.
|
||||
+ */
|
||||
+ __u8 s_journal_uuid[16]; /* uuid of journal superblock */
|
||||
+ __u32 s_journal_inum; /* inode number of journal file */
|
||||
+ __u32 s_journal_dev; /* device number of journal file */
|
||||
+ __u32 s_last_orphan; /* start of list of inodes to delete */
|
||||
+ __u32 s_hash_seed[4]; /* HTREE hash seed */
|
||||
+ __u8 s_def_hash_version; /* Default hash version to use */
|
||||
+ __u8 s_jnl_backup_type; /* Default type of journal backup */
|
||||
+ __u16 s_reserved_word_pad;
|
||||
+ __u32 s_default_mount_opts;
|
||||
+ __u32 s_first_meta_bg; /* First metablock group */
|
||||
+ __u32 s_mkfs_time; /* When the filesystem was created */
|
||||
+ __u32 s_jnl_blocks[17]; /* Backup of the journal inode */
|
||||
+ __u32 s_reserved[172]; /* Padding to the end of the block */
|
||||
};
|
||||
|
||||
struct ext2_group_desc
|
||||
@@ -218,6 +263,9 @@
|
||||
#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32))
|
||||
#define EXT2_ADDR_PER_BLOCK_BITS(s) (log2(EXT2_ADDR_PER_BLOCK(s)))
|
||||
|
||||
+#define EXT2_INODE_SIZE(s) (SUPERBLOCK->s_inode_size)
|
||||
+#define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s)/EXT2_INODE_SIZE(s))
|
||||
+
|
||||
/* linux/ext2_fs.h */
|
||||
#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
|
||||
/* kind of from ext2/super.c */
|
||||
@@ -242,7 +290,14 @@
|
||||
static __inline__ unsigned long
|
||||
ffz (unsigned long word)
|
||||
{
|
||||
- __asm__ ("bsfl %1,%0"
|
||||
+ __asm__ ("bsf"
|
||||
+#ifdef __i386__
|
||||
+ "l"
|
||||
+#endif
|
||||
+#ifdef __x86_64__
|
||||
+ "q"
|
||||
+#endif
|
||||
+ " %1,%0"
|
||||
: "=r" (word)
|
||||
: "r" (~word));
|
||||
return word;
|
||||
@@ -553,7 +608,7 @@
|
||||
gdp = GROUP_DESC;
|
||||
ino_blk = gdp[desc].bg_inode_table +
|
||||
(((current_ino - 1) % (SUPERBLOCK->s_inodes_per_group))
|
||||
- >> log2 (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode)));
|
||||
+ >> log2 (EXT2_INODES_PER_BLOCK (SUPERBLOCK)));
|
||||
#ifdef E2DEBUG
|
||||
printf ("inode table fsblock=%d\n", ino_blk);
|
||||
#endif /* E2DEBUG */
|
||||
@@ -565,13 +620,12 @@
|
||||
/* reset indirect blocks! */
|
||||
mapblock2 = mapblock1 = -1;
|
||||
|
||||
- raw_inode = INODE +
|
||||
- ((current_ino - 1)
|
||||
- & (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode) - 1));
|
||||
+ raw_inode = (struct ext2_inode *)((char *)INODE +
|
||||
+ ((current_ino - 1) & (EXT2_INODES_PER_BLOCK (SUPERBLOCK) - 1)) *
|
||||
+ EXT2_INODE_SIZE (SUPERBLOCK));
|
||||
#ifdef E2DEBUG
|
||||
printf ("ipb=%d, sizeof(inode)=%d\n",
|
||||
- (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode)),
|
||||
- sizeof (struct ext2_inode));
|
||||
+ EXT2_INODES_PER_BLOCK (SUPERBLOCK), EXT2_INODE_SIZE (SUPERBLOCK));
|
||||
printf ("inode=%x, raw_inode=%x\n", INODE, raw_inode);
|
||||
printf ("offset into inode table block=%d\n", (int) raw_inode - (int) INODE);
|
||||
for (i = (unsigned char *) INODE; i <= (unsigned char *) raw_inode;
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,76 @@
|
||||
XEN_ROOT = ../..
|
||||
|
||||
include $(XEN_ROOT)/Config.mk
|
||||
vpath %.c ../grub-cvs
|
||||
|
||||
BOOT=boot-$(XEN_TARGET_ARCH).o
|
||||
|
||||
DEF_CPPFLAGS += -I$(XEN_ROOT)/tools/libxc -I.
|
||||
DEF_CPPFLAGS += -I../grub-cvs/stage1
|
||||
DEF_CPPFLAGS += -I../grub-cvs/stage2
|
||||
DEF_CPPFLAGS += -I../grub-cvs/netboot
|
||||
DEF_CPPFLAGS += -I$(XEN_ROOT)/tools/firmware/vgabios
|
||||
DEF_CPPFLAGS += -DWITHOUT_LIBC_STUBS
|
||||
DEF_CPPFLAGS += -DSUPPORT_NETBOOT
|
||||
DEF_CPPFLAGS += -DSUPPORT_GRAPHICS
|
||||
DEF_CPPFLAGS += -DSUPPORT_SERIAL
|
||||
DEF_CPPFLAGS += -DPRESET_MENU_STRING='""'
|
||||
DEF_CPPFLAGS += -DPACKAGE='"grubdom"' -DVERSION='"0.97"'
|
||||
|
||||
all: main.a
|
||||
|
||||
STAGE2_SOURCES=builtins.c char_io.c cmdline.c common.c console.c disk_io.c graphics.c gunzip.c md5.c serial.c stage2.c terminfo.c tparm.c
|
||||
|
||||
NETBOOT_SOURCES=fsys_tftp.c main.c misc.c
|
||||
CPPFLAGS += -DFSYS_TFTP=1
|
||||
|
||||
STAGE2_SOURCES+=fsys_ext2fs.c
|
||||
CPPFLAGS += -DFSYS_EXT2FS=1
|
||||
|
||||
STAGE2_SOURCES+=fsys_fat.c
|
||||
CPPFLAGS += -DFSYS_FAT=1
|
||||
|
||||
STAGE2_SOURCES+=fsys_ffs.c
|
||||
CPPFLAGS += -DFSYS_FFS=1
|
||||
|
||||
STAGE2_SOURCES+=fsys_iso9660.c
|
||||
CPPFLAGS += -DFSYS_ISO9660=1
|
||||
|
||||
STAGE2_SOURCES+=fsys_jfs.c
|
||||
CPPFLAGS += -DFSYS_JFS=1
|
||||
|
||||
STAGE2_SOURCES+=fsys_minix.c
|
||||
CPPFLAGS += -DFSYS_MINIX=1
|
||||
|
||||
STAGE2_SOURCES+=fsys_reiserfs.c
|
||||
CPPFLAGS += -DFSYS_REISERFS=1
|
||||
|
||||
STAGE2_SOURCES+=fsys_ufs2.c
|
||||
CPPFLAGS += -DFSYS_UFS2=1
|
||||
|
||||
STAGE2_SOURCES+=fsys_vstafs.c
|
||||
CPPFLAGS += -DFSYS_VSTAFS=1
|
||||
|
||||
ifeq (0,1)
|
||||
STAGE2_SOURCES+=fsys_xfs.c
|
||||
CPPFLAGS += -DFSYS_XFS=1
|
||||
endif
|
||||
|
||||
STAGE2_SOURCES:=$(addprefix stage2/,$(STAGE2_SOURCES))
|
||||
NETBOOT_SOURCES:=$(addprefix netboot/,$(NETBOOT_SOURCES))
|
||||
|
||||
$(BOOT): DEF_CPPFLAGS+=-D__ASSEMBLY__
|
||||
|
||||
OBJS = $(NETBOOT_SOURCES:.c=.o) $(STAGE2_SOURCES:.c=.o) kexec.o mini-os.o
|
||||
|
||||
dirs:
|
||||
mkdir -p netboot stage2
|
||||
touch $@
|
||||
|
||||
$(OBJS): dirs
|
||||
|
||||
main.a: $(BOOT) $(OBJS)
|
||||
$(AR) cr $@ $^
|
||||
|
||||
clean:
|
||||
rm -fr dirs *.a *.o stage2 netboot
|
||||
@@ -0,0 +1,112 @@
|
||||
#include <os.h>
|
||||
#include <arch_limits.h>
|
||||
#include <xen/arch-x86_32.h>
|
||||
|
||||
/* For simplicity, we keep all of this into just one data page */
|
||||
.data
|
||||
.globl _boot_page
|
||||
_boot_page:
|
||||
.align __PAGE_SIZE
|
||||
|
||||
/*
|
||||
* The following data is initialized from C code
|
||||
*/
|
||||
|
||||
/* Pte of this page */
|
||||
.globl _boot_page_entry
|
||||
_boot_page_entry:
|
||||
_boot_page_entry_lo:
|
||||
.long 0
|
||||
_boot_page_entry_hi:
|
||||
.long 0
|
||||
|
||||
/* mmuext_op structure */
|
||||
/* Set new page directory */
|
||||
_boot_mmuext:
|
||||
/* Op # */
|
||||
.long MMUEXT_NEW_BASEPTR
|
||||
|
||||
/* MFN of target page table directory */
|
||||
.globl _boot_pdmfn
|
||||
_boot_pdmfn:
|
||||
.long 0
|
||||
|
||||
/* Unused */
|
||||
.long 0
|
||||
|
||||
/* Unpin old page directory */
|
||||
/* Op # */
|
||||
.long MMUEXT_UNPIN_TABLE
|
||||
|
||||
/* MFN of old page table directory */
|
||||
.globl _boot_oldpdmfn
|
||||
_boot_oldpdmfn:
|
||||
.long 0
|
||||
|
||||
/* Unused */
|
||||
.long 0
|
||||
|
||||
/* Target stack address, also target virtual address of this page */
|
||||
.globl _boot_stack
|
||||
_boot_stack:
|
||||
.long 0
|
||||
.long __KERNEL_SS
|
||||
.globl _boot_target
|
||||
_boot_target:
|
||||
.long 0
|
||||
|
||||
/* Target start info */
|
||||
.globl _boot_start_info
|
||||
_boot_start_info:
|
||||
.long 0
|
||||
|
||||
/* Target start address */
|
||||
.globl _boot_start
|
||||
_boot_start:
|
||||
.long 0
|
||||
|
||||
/*
|
||||
* Boot target OS, does not return
|
||||
*/
|
||||
.globl _boot
|
||||
_boot:
|
||||
/* Project ourselves at the target place. */
|
||||
movl _boot_target, %ebx
|
||||
movl %ebx, %ebp /* also keep it in ebp for relative addressing */
|
||||
movl _boot_page_entry_lo, %ecx
|
||||
movl _boot_page_entry_hi, %edx
|
||||
movl $2, %esi /* UVMF_INVLPG */
|
||||
movl $__HYPERVISOR_update_va_mapping, %eax
|
||||
int $0x82
|
||||
testl %eax, %eax
|
||||
jz 0f
|
||||
ud2
|
||||
|
||||
0:
|
||||
/* Go there. */
|
||||
movl $(0f - _boot_page), %eax
|
||||
movl _boot_target, %ebx
|
||||
addl %ebx, %eax
|
||||
jmpl *%eax
|
||||
0:
|
||||
|
||||
/* Load target page table and unpin old page table. */
|
||||
/* We shouldn't have any problem since in the new page table our page is
|
||||
mapped at the same place. */
|
||||
leal (_boot_mmuext-_boot_page)(%ebp), %ebx
|
||||
movl $2, %ecx
|
||||
xorl %edx, %edx
|
||||
movl $0x7FF0, %esi /* DOMID_SELF */
|
||||
movl $__HYPERVISOR_mmuext_op, %eax
|
||||
int $0x82
|
||||
testl %eax, %eax
|
||||
jns 0f
|
||||
ud2
|
||||
|
||||
0:
|
||||
/* Initialize registers. */
|
||||
lss (_boot_stack-_boot_page)(%ebp), %esp
|
||||
movl (_boot_start_info-_boot_page)(%ebp), %esi
|
||||
|
||||
/* Jump! */
|
||||
jmpl *(_boot_start-_boot_page)(%ebp)
|
||||
@@ -0,0 +1,108 @@
|
||||
#include <os.h>
|
||||
#include <arch_limits.h>
|
||||
#include <xen/arch-x86_64.h>
|
||||
|
||||
/* For simplicity, we keep all of this into just one data page */
|
||||
.data
|
||||
.globl _boot_page
|
||||
_boot_page:
|
||||
.align __PAGE_SIZE
|
||||
|
||||
/*
|
||||
* The following data is initialized from C code
|
||||
*/
|
||||
|
||||
/* Pte of this page */
|
||||
.globl _boot_page_entry
|
||||
_boot_page_entry:
|
||||
.quad 0
|
||||
|
||||
/* mmuext_op structure */
|
||||
/* Set new page directory */
|
||||
_boot_mmuext:
|
||||
/* Op # */
|
||||
.long MMUEXT_NEW_BASEPTR
|
||||
.long 0 /* pad */
|
||||
|
||||
/* MFN of target page table directory */
|
||||
.globl _boot_pdmfn
|
||||
_boot_pdmfn:
|
||||
.quad 0
|
||||
|
||||
/* Unused */
|
||||
.quad 0
|
||||
|
||||
/* Unpin old page directory */
|
||||
/* Op # */
|
||||
.long MMUEXT_UNPIN_TABLE
|
||||
.long 0 /* pad */
|
||||
|
||||
/* MFN of old page table directory */
|
||||
.globl _boot_oldpdmfn
|
||||
_boot_oldpdmfn:
|
||||
.quad 0
|
||||
|
||||
/* Unused */
|
||||
.quad 0
|
||||
|
||||
/* Target stack address, also target virtual address of this page */
|
||||
.globl _boot_stack
|
||||
_boot_stack:
|
||||
.quad 0
|
||||
.globl _boot_target
|
||||
_boot_target:
|
||||
.quad 0
|
||||
|
||||
/* Target start info */
|
||||
.globl _boot_start_info
|
||||
_boot_start_info:
|
||||
.quad 0
|
||||
|
||||
/* Target start address */
|
||||
.globl _boot_start
|
||||
_boot_start:
|
||||
.quad 0
|
||||
|
||||
/*
|
||||
* Boot target OS, does not return
|
||||
*/
|
||||
.globl _boot
|
||||
_boot:
|
||||
/* Project ourselves at the target place. */
|
||||
movq _boot_target, %rdi
|
||||
movq _boot_page_entry, %rsi
|
||||
movq $2, %rdx /* UVMF_INVLPG */
|
||||
movq $__HYPERVISOR_update_va_mapping, %rax
|
||||
syscall
|
||||
testq %rax, %rax
|
||||
jz 0f
|
||||
ud2
|
||||
|
||||
0:
|
||||
/* Go there. */
|
||||
movq $(0f - _boot_page), %rax
|
||||
movq _boot_target, %rbx
|
||||
addq %rbx, %rax
|
||||
jmpq *%rax
|
||||
0:
|
||||
|
||||
/* Load target page table and unpin old page table. */
|
||||
/* We shouldn't have any problem since in the new page table our page is
|
||||
mapped at the same place. */
|
||||
leaq _boot_mmuext(%rip), %rdi
|
||||
movq $2, %rsi
|
||||
xorq %rdx, %rdx
|
||||
movq $0x7FF0, %r10 /* DOMID_SELF */
|
||||
movq $__HYPERVISOR_mmuext_op, %rax
|
||||
syscall
|
||||
testq %rax, %rax
|
||||
jns 0f
|
||||
ud2
|
||||
|
||||
0:
|
||||
/* Initialize registers. */
|
||||
movq _boot_stack(%rip), %rsp
|
||||
movq _boot_start_info(%rip), %rsi
|
||||
|
||||
/* Jump! */
|
||||
jmpq *_boot_start(%rip)
|
||||
@@ -0,0 +1,11 @@
|
||||
#include <stdio.h>
|
||||
#undef putchar
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#define debug _debug
|
||||
#define grub_halt(a) do_exit()
|
||||
#define printf grub_printf
|
||||
void kexec(void *kernel, long kernel_size, void *module, long module_size, char *cmdline);
|
||||
struct fbfront_dev *fb_open(void *fb, int width, int height, int depth);
|
||||
void fb_close(void);
|
||||
void pv_boot (void);
|
||||
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
* This supports booting another PV kernel from Mini-OS
|
||||
*
|
||||
* The idea is to setup it using libxc, answer to day0 memory allocation
|
||||
* requests, and using a trampoline boot page to switch to the new page table.
|
||||
*
|
||||
* The procedure of the boot page is:
|
||||
* - map itself at the target position (that may overwrite some C stuff, but we
|
||||
* do not care any more)
|
||||
* - jump there
|
||||
* - switch to the target page table
|
||||
* - unpin the old page table
|
||||
* - jump to the new kernel
|
||||
*
|
||||
* Samuel Thibault <Samuel.Thibault@eu.citrix.com>, May 2008
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <xenctrl.h>
|
||||
#include <xc_dom.h>
|
||||
|
||||
#include <kernel.h>
|
||||
#include <console.h>
|
||||
#include <os.h>
|
||||
#include <blkfront.h>
|
||||
#include <netfront.h>
|
||||
#include <fbfront.h>
|
||||
#include <shared.h>
|
||||
|
||||
#include "mini-os.h"
|
||||
|
||||
#if 0
|
||||
#define DEBUG(fmt, ...) printk(fmt, ## __VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG(fmt, ...) (void)0
|
||||
#endif
|
||||
|
||||
/* Assembly boot page from boot.S */
|
||||
extern void _boot_page;
|
||||
extern pgentry_t _boot_page_entry;
|
||||
extern unsigned long _boot_pdmfn;
|
||||
extern unsigned long _boot_stack, _boot_target, _boot_start_info, _boot_start;
|
||||
extern xen_pfn_t _boot_oldpdmfn;
|
||||
extern void _boot(void);
|
||||
|
||||
static unsigned long *pages;
|
||||
static unsigned long *pages_mfns;
|
||||
static unsigned long allocated;
|
||||
|
||||
int pin_table(int xc_handle, unsigned int type, unsigned long mfn,
|
||||
domid_t dom);
|
||||
|
||||
/* We need mfn to appear as target_pfn, so exchange with the MFN there */
|
||||
static void do_exchange(struct xc_dom_image *dom, xen_pfn_t target_pfn, xen_pfn_t source_mfn)
|
||||
{
|
||||
xen_pfn_t source_pfn;
|
||||
xen_pfn_t target_mfn;
|
||||
|
||||
for (source_pfn = 0; source_pfn < start_info.nr_pages; source_pfn++)
|
||||
if (dom->p2m_host[source_pfn] == source_mfn)
|
||||
break;
|
||||
ASSERT(source_pfn < start_info.nr_pages);
|
||||
|
||||
target_mfn = dom->p2m_host[target_pfn];
|
||||
|
||||
/* Put target MFN at source PFN */
|
||||
dom->p2m_host[source_pfn] = target_mfn;
|
||||
|
||||
/* Put source MFN at target PFN */
|
||||
dom->p2m_host[target_pfn] = source_mfn;
|
||||
}
|
||||
|
||||
int kexec_allocate(struct xc_dom_image *dom, xen_vaddr_t up_to)
|
||||
{
|
||||
unsigned long new_allocated = (up_to - dom->parms.virt_base) / PAGE_SIZE;
|
||||
unsigned long i;
|
||||
|
||||
pages = realloc(pages, new_allocated * sizeof(*pages));
|
||||
pages_mfns = realloc(pages_mfns, new_allocated * sizeof(*pages_mfns));
|
||||
for (i = allocated; i < new_allocated; i++) {
|
||||
/* Exchange old page of PFN i with a newly allocated page. */
|
||||
xen_pfn_t old_mfn = dom->p2m_host[i];
|
||||
xen_pfn_t new_pfn;
|
||||
xen_pfn_t new_mfn;
|
||||
|
||||
pages[i] = alloc_page();
|
||||
memset((void*) pages[i], 0, PAGE_SIZE);
|
||||
new_pfn = PHYS_PFN(to_phys(pages[i]));
|
||||
pages_mfns[i] = new_mfn = pfn_to_mfn(new_pfn);
|
||||
|
||||
/* Put old page at new PFN */
|
||||
dom->p2m_host[new_pfn] = old_mfn;
|
||||
|
||||
/* Put new page at PFN i */
|
||||
dom->p2m_host[i] = new_mfn;
|
||||
}
|
||||
|
||||
allocated = new_allocated;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kexec(void *kernel, long kernel_size, void *module, long module_size, char *cmdline)
|
||||
{
|
||||
struct xc_dom_image *dom;
|
||||
int rc;
|
||||
domid_t domid = DOMID_SELF;
|
||||
xen_pfn_t pfn;
|
||||
int xc_handle;
|
||||
unsigned long i;
|
||||
void *seg;
|
||||
xen_pfn_t boot_page_mfn = virt_to_mfn(&_boot_page);
|
||||
char features[] = "";
|
||||
struct mmu_update *m2p_updates;
|
||||
unsigned long nr_m2p_updates;
|
||||
|
||||
DEBUG("booting with cmdline %s\n", cmdline);
|
||||
xc_handle = xc_interface_open();
|
||||
|
||||
dom = xc_dom_allocate(cmdline, features);
|
||||
dom->allocate = kexec_allocate;
|
||||
|
||||
dom->kernel_blob = kernel;
|
||||
dom->kernel_size = kernel_size;
|
||||
|
||||
dom->ramdisk_blob = module;
|
||||
dom->ramdisk_size = module_size;
|
||||
|
||||
dom->flags = 0;
|
||||
dom->console_evtchn = start_info.console.domU.evtchn;
|
||||
dom->xenstore_evtchn = start_info.store_evtchn;
|
||||
|
||||
if ( (rc = xc_dom_boot_xen_init(dom, xc_handle, domid)) != 0 ) {
|
||||
grub_printf("xc_dom_boot_xen_init returned %d\n", rc);
|
||||
errnum = ERR_BOOT_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
if ( (rc = xc_dom_parse_image(dom)) != 0 ) {
|
||||
grub_printf("xc_dom_parse_image returned %d\n", rc);
|
||||
errnum = ERR_BOOT_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef __i386__
|
||||
if (strcmp(dom->guest_type, "xen-3.0-x86_32p")) {
|
||||
grub_printf("can only boot x86 32 PAE kernels, not %s\n", dom->guest_type);
|
||||
errnum = ERR_EXEC_FORMAT;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
#ifdef __x86_64__
|
||||
if (strcmp(dom->guest_type, "xen-3.0-x86_64")) {
|
||||
grub_printf("can only boot x86 64 kernels, not %s\n", dom->guest_type);
|
||||
errnum = ERR_EXEC_FORMAT;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* equivalent of xc_dom_mem_init */
|
||||
dom->arch_hooks = xc_dom_find_arch_hooks(dom->guest_type);
|
||||
dom->total_pages = start_info.nr_pages;
|
||||
|
||||
/* equivalent of arch_setup_meminit */
|
||||
|
||||
/* setup initial p2m */
|
||||
dom->p2m_host = malloc(sizeof(*dom->p2m_host) * dom->total_pages);
|
||||
|
||||
/* Start with our current P2M */
|
||||
for (i = 0; i < dom->total_pages; i++)
|
||||
dom->p2m_host[i] = pfn_to_mfn(i);
|
||||
|
||||
if ( (rc = xc_dom_build_image(dom)) != 0 ) {
|
||||
grub_printf("xc_dom_build_image returned %d\n", rc);
|
||||
errnum = ERR_BOOT_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* copy hypercall page */
|
||||
/* TODO: domctl instead, but requires privileges */
|
||||
if (dom->parms.virt_hypercall != -1) {
|
||||
pfn = PHYS_PFN(dom->parms.virt_hypercall - dom->parms.virt_base);
|
||||
memcpy((void *) pages[pfn], hypercall_page, PAGE_SIZE);
|
||||
}
|
||||
|
||||
/* Equivalent of xc_dom_boot_image */
|
||||
dom->shared_info_mfn = PHYS_PFN(start_info.shared_info);
|
||||
|
||||
if (!xc_dom_compat_check(dom)) {
|
||||
grub_printf("xc_dom_compat_check failed\n");
|
||||
errnum = ERR_EXEC_FORMAT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Move current console, xenstore and boot MFNs to the allocated place */
|
||||
do_exchange(dom, dom->console_pfn, start_info.console.domU.mfn);
|
||||
do_exchange(dom, dom->xenstore_pfn, start_info.store_mfn);
|
||||
DEBUG("virt base at %llx\n", dom->parms.virt_base);
|
||||
DEBUG("bootstack_pfn %lx\n", dom->bootstack_pfn);
|
||||
_boot_target = dom->parms.virt_base + PFN_PHYS(dom->bootstack_pfn);
|
||||
DEBUG("_boot_target %lx\n", _boot_target);
|
||||
do_exchange(dom, PHYS_PFN(_boot_target - dom->parms.virt_base),
|
||||
virt_to_mfn(&_boot_page));
|
||||
|
||||
/* Make sure the bootstrap page table does not RW-map any of our current
|
||||
* page table frames */
|
||||
kexec_allocate(dom, dom->virt_pgtab_end);
|
||||
|
||||
if ( (rc = xc_dom_update_guest_p2m(dom))) {
|
||||
grub_printf("xc_dom_update_guest_p2m returned %d\n", rc);
|
||||
errnum = ERR_BOOT_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ( dom->arch_hooks->setup_pgtables )
|
||||
if ( (rc = dom->arch_hooks->setup_pgtables(dom))) {
|
||||
grub_printf("setup_pgtables returned %d\n", rc);
|
||||
errnum = ERR_BOOT_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* start info page */
|
||||
#undef start_info
|
||||
if ( dom->arch_hooks->start_info )
|
||||
dom->arch_hooks->start_info(dom);
|
||||
#define start_info (start_info_union.start_info)
|
||||
|
||||
xc_dom_log_memory_footprint(dom);
|
||||
|
||||
/* Unmap libxc's projection of the boot page table */
|
||||
seg = xc_dom_seg_to_ptr(dom, &dom->pgtables_seg);
|
||||
munmap(seg, dom->pgtables_seg.vend - dom->pgtables_seg.vstart);
|
||||
|
||||
/* Unmap day0 pages to avoid having a r/w mapping of the future page table */
|
||||
for (pfn = 0; pfn < allocated; pfn++)
|
||||
munmap((void*) pages[pfn], PAGE_SIZE);
|
||||
|
||||
/* Pin the boot page table base */
|
||||
if ( (rc = pin_table(dom->guest_xc,
|
||||
#ifdef __i386__
|
||||
MMUEXT_PIN_L3_TABLE,
|
||||
#endif
|
||||
#ifdef __x86_64__
|
||||
MMUEXT_PIN_L4_TABLE,
|
||||
#endif
|
||||
xc_dom_p2m_host(dom, dom->pgtables_seg.pfn),
|
||||
dom->guest_domid)) != 0 ) {
|
||||
grub_printf("pin_table(%lx) returned %d\n", xc_dom_p2m_host(dom,
|
||||
dom->pgtables_seg.pfn), rc);
|
||||
errnum = ERR_BOOT_FAILURE;
|
||||
goto out_remap;
|
||||
}
|
||||
|
||||
/* We populate the Mini-OS page table here so that boot.S can just call
|
||||
* update_va_mapping to project itself there. */
|
||||
need_pgt(_boot_target);
|
||||
DEBUG("day0 pages %lx\n", allocated);
|
||||
DEBUG("boot target page %lx\n", _boot_target);
|
||||
DEBUG("boot page %p\n", &_boot_page);
|
||||
DEBUG("boot page mfn %lx\n", boot_page_mfn);
|
||||
_boot_page_entry = PFN_PHYS(boot_page_mfn) | L1_PROT;
|
||||
DEBUG("boot page entry %llx\n", _boot_page_entry);
|
||||
_boot_oldpdmfn = virt_to_mfn(start_info.pt_base);
|
||||
DEBUG("boot old pd mfn %lx\n", _boot_oldpdmfn);
|
||||
DEBUG("boot pd virt %lx\n", dom->pgtables_seg.vstart);
|
||||
_boot_pdmfn = dom->p2m_host[PHYS_PFN(dom->pgtables_seg.vstart - dom->parms.virt_base)];
|
||||
DEBUG("boot pd mfn %lx\n", _boot_pdmfn);
|
||||
_boot_stack = _boot_target + PAGE_SIZE;
|
||||
DEBUG("boot stack %lx\n", _boot_stack);
|
||||
_boot_start_info = dom->parms.virt_base + PFN_PHYS(dom->start_info_pfn);
|
||||
DEBUG("boot start info %lx\n", _boot_start_info);
|
||||
_boot_start = dom->parms.virt_entry;
|
||||
DEBUG("boot start %lx\n", _boot_start);
|
||||
|
||||
/* Keep only useful entries */
|
||||
for (nr_m2p_updates = pfn = 0; pfn < start_info.nr_pages; pfn++)
|
||||
if (dom->p2m_host[pfn] != pfn_to_mfn(pfn))
|
||||
nr_m2p_updates++;
|
||||
|
||||
m2p_updates = malloc(sizeof(*m2p_updates) * nr_m2p_updates);
|
||||
for (i = pfn = 0; pfn < start_info.nr_pages; pfn++)
|
||||
if (dom->p2m_host[pfn] != pfn_to_mfn(pfn)) {
|
||||
m2p_updates[i].ptr = PFN_PHYS(dom->p2m_host[pfn]) | MMU_MACHPHYS_UPDATE;
|
||||
m2p_updates[i].val = pfn;
|
||||
i++;
|
||||
}
|
||||
|
||||
for (i = 0; i < blk_nb; i++)
|
||||
shutdown_blkfront(blk_dev[i]);
|
||||
if (net_dev)
|
||||
shutdown_netfront(net_dev);
|
||||
if (kbd_dev)
|
||||
shutdown_kbdfront(kbd_dev);
|
||||
stop_kernel();
|
||||
|
||||
/* Update M2P */
|
||||
if ((rc = HYPERVISOR_mmu_update(m2p_updates, nr_m2p_updates, NULL, DOMID_SELF)) < 0) {
|
||||
xprintk("Could not update M2P\n");
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
xprintk("go!\n");
|
||||
|
||||
/* Jump to trampoline boot page */
|
||||
_boot();
|
||||
|
||||
ASSERT(0);
|
||||
|
||||
out_remap:
|
||||
for (pfn = 0; pfn < allocated; pfn++)
|
||||
do_map_frames(pages[pfn], &pages_mfns[pfn], 1, 0, 0, DOMID_SELF, 0, L1_PROT);
|
||||
out:
|
||||
xc_dom_release(dom);
|
||||
for (pfn = 0; pfn < allocated; pfn++)
|
||||
free_page((void*)pages[pfn]);
|
||||
free(pages);
|
||||
free(pages_mfns);
|
||||
pages = NULL;
|
||||
pages_mfns = NULL;
|
||||
allocated = 0;
|
||||
xc_interface_close(xc_handle );
|
||||
}
|
||||
@@ -0,0 +1,702 @@
|
||||
/*
|
||||
* Mini-OS support for GRUB.
|
||||
*
|
||||
* Samuel Thibault <Samuel.Thibault@eu.citrix.com>, May 2008
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <hypervisor.h>
|
||||
#include <blkfront.h>
|
||||
#include <netfront.h>
|
||||
#include <fbfront.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#include <osdep.h>
|
||||
#include <shared.h>
|
||||
#include <nic.h>
|
||||
#include <etherboot.h>
|
||||
#include <terminfo.h>
|
||||
#include <term.h>
|
||||
|
||||
#include "mini-os.h"
|
||||
|
||||
extern const char *preset_menu;
|
||||
char config_file[DEFAULT_FILE_BUFLEN] = "(hd0,0)/boot/grub/menu.lst";
|
||||
unsigned long boot_drive = NETWORK_DRIVE;
|
||||
unsigned long install_partition = 0xFFFFFF;
|
||||
|
||||
char version_string[] = VERSION;
|
||||
|
||||
/* Variables from asm.S */
|
||||
int saved_entryno;
|
||||
|
||||
/*
|
||||
* Disk
|
||||
*/
|
||||
|
||||
struct blkfront_dev **blk_dev;
|
||||
int blk_nb;
|
||||
static struct blkfront_info *blk_info;
|
||||
|
||||
static int vbdcmp(const void *_vbd1, const void *_vbd2) {
|
||||
char *vbd1 = *(char **)_vbd1;
|
||||
char *vbd2 = *(char **)_vbd2;
|
||||
int vbdn1 = atoi(vbd1);
|
||||
int vbdn2 = atoi(vbd2);
|
||||
return vbdn1 - vbdn2;
|
||||
}
|
||||
|
||||
void init_disk (void)
|
||||
{
|
||||
char **list;
|
||||
char *msg;
|
||||
int i;
|
||||
char *path;
|
||||
|
||||
msg = xenbus_ls(XBT_NIL, "device/vbd", &list);
|
||||
if (msg) {
|
||||
printk("Error %s while reading list of disks\n", msg);
|
||||
free(msg);
|
||||
return;
|
||||
}
|
||||
blk_nb = 0;
|
||||
while (list[blk_nb])
|
||||
blk_nb++;
|
||||
blk_dev = malloc(blk_nb * sizeof(*blk_dev));
|
||||
blk_info = malloc(blk_nb * sizeof(*blk_info));
|
||||
|
||||
qsort(list, blk_nb, sizeof(*list), vbdcmp);
|
||||
|
||||
for (i = 0; i < blk_nb; i++) {
|
||||
printk("vbd %s is hd%d\n", list[i], i);
|
||||
asprintf(&path, "device/vbd/%s", list[i]);
|
||||
blk_dev[i] = init_blkfront(path, &blk_info[i]);
|
||||
free(path);
|
||||
free(list[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the geometry of DRIVE in GEOMETRY. If an error occurs, return
|
||||
non-zero, otherwise zero. */
|
||||
int get_diskinfo (int drive, struct geometry *geometry)
|
||||
{
|
||||
int i;
|
||||
if (!(drive & 0x80))
|
||||
return -1;
|
||||
|
||||
i = drive - 0x80;
|
||||
if (i >= blk_nb)
|
||||
return -1;
|
||||
|
||||
/* Bogus geometry */
|
||||
geometry->cylinders = 65535;
|
||||
geometry->heads = 255;
|
||||
geometry->sectors = 63;
|
||||
|
||||
geometry->total_sectors = blk_info[i].sectors;
|
||||
geometry->sector_size = blk_info[i].sector_size;
|
||||
geometry->flags = BIOSDISK_FLAG_LBA_EXTENSION;
|
||||
if (blk_info[i].info & VDISK_CDROM)
|
||||
geometry->flags |= BIOSDISK_FLAG_CDROM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read/write NSEC sectors starting from SECTOR in DRIVE disk with GEOMETRY
|
||||
from/into SEGMENT segment. If READ is BIOSDISK_READ, then read it,
|
||||
else if READ is BIOSDISK_WRITE, then write it. If an geometry error
|
||||
occurs, return BIOSDISK_ERROR_GEOMETRY, and if other error occurs, then
|
||||
return the error number. Otherwise, return 0. */
|
||||
int
|
||||
biosdisk (int read, int drive, struct geometry *geometry,
|
||||
unsigned int sector, int nsec, int segment)
|
||||
{
|
||||
void *addr = (void *) ((unsigned long)segment << 4);
|
||||
struct blkfront_aiocb aiocb;
|
||||
int i;
|
||||
|
||||
if (!(drive & 0x80))
|
||||
return -1;
|
||||
|
||||
i = drive - 0x80;
|
||||
if (i >= blk_nb)
|
||||
return -1;
|
||||
|
||||
aiocb.aio_dev = blk_dev[i];
|
||||
aiocb.aio_buf = addr;
|
||||
aiocb.aio_nbytes = (size_t)nsec * blk_info[i].sector_size;
|
||||
aiocb.aio_offset = (off_t)sector * blk_info[i].sector_size;
|
||||
aiocb.aio_cb = NULL;
|
||||
|
||||
blkfront_io(&aiocb, read == BIOSDISK_WRITE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
load_file(char *name, void **ptr, long *size)
|
||||
{
|
||||
char *buf = NULL;
|
||||
int allocated = 1 * 1024 * 1024;
|
||||
int len, filled = 0;
|
||||
|
||||
if (!grub_open (name))
|
||||
return -1;
|
||||
|
||||
buf = malloc(allocated);
|
||||
|
||||
errnum = 0;
|
||||
while (1) {
|
||||
len = grub_read (buf + filled, allocated - filled);
|
||||
if (! len) {
|
||||
if (!errnum)
|
||||
break;
|
||||
grub_close ();
|
||||
return -1;
|
||||
}
|
||||
filled += len;
|
||||
if (filled < allocated)
|
||||
break;
|
||||
allocated *= 2;
|
||||
buf = realloc(buf, allocated);
|
||||
}
|
||||
grub_close ();
|
||||
*ptr = buf;
|
||||
*size = filled;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *kernel_image, *module_image;
|
||||
long kernel_size, module_size;
|
||||
char *kernel_arg, *module_arg;
|
||||
|
||||
kernel_t
|
||||
load_image (char *kernel, char *arg, kernel_t suggested_type,
|
||||
unsigned long load_flags)
|
||||
{
|
||||
arg = skip_to(0, arg);
|
||||
if (kernel_image)
|
||||
free(kernel_image);
|
||||
kernel_image = NULL;
|
||||
if (load_file (kernel, &kernel_image, &kernel_size))
|
||||
return KERNEL_TYPE_NONE;
|
||||
if (kernel_arg)
|
||||
free(kernel_arg);
|
||||
kernel_arg = strdup(arg);
|
||||
return KERNEL_TYPE_PV;
|
||||
}
|
||||
|
||||
int
|
||||
load_initrd (char *initrd)
|
||||
{
|
||||
if (module_image)
|
||||
free(module_image);
|
||||
module_image = NULL;
|
||||
load_file (initrd, &module_image, &module_size);
|
||||
return ! errnum;
|
||||
}
|
||||
|
||||
int
|
||||
load_module (char *module, char *arg)
|
||||
{
|
||||
if (module_image)
|
||||
free(module_image);
|
||||
module_image = NULL;
|
||||
load_file (module, &module_image, &module_size);
|
||||
if (module_arg)
|
||||
free(module_arg);
|
||||
module_arg = strdup(arg);
|
||||
return ! errnum;
|
||||
}
|
||||
|
||||
void
|
||||
pv_boot (void)
|
||||
{
|
||||
kexec(kernel_image, kernel_size, module_image, module_size, kernel_arg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Network
|
||||
*/
|
||||
|
||||
struct netfront_dev *net_dev;
|
||||
|
||||
int
|
||||
minios_probe (struct nic *nic)
|
||||
{
|
||||
char *ip;
|
||||
|
||||
if (net_dev)
|
||||
return 1;
|
||||
|
||||
/* Clear the ARP table. */
|
||||
grub_memset ((char *) arptable, 0,
|
||||
MAX_ARP * sizeof (struct arptable_t));
|
||||
|
||||
net_dev = init_netfront(NULL, (void*) -1, nic->node_addr, &ip);
|
||||
if (!net_dev)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* reset adapter */
|
||||
static void minios_reset(struct nic *nic)
|
||||
{
|
||||
/* TODO? */
|
||||
}
|
||||
|
||||
static void minios_disable(struct nic *nic)
|
||||
{
|
||||
}
|
||||
|
||||
/* Wait for a frame */
|
||||
static int minios_poll(struct nic *nic)
|
||||
{
|
||||
return !! (nic->packetlen = netfront_receive(net_dev, (void*) nic->packet, ETH_FRAME_LEN));
|
||||
}
|
||||
|
||||
/* Transmit a frame */
|
||||
struct frame {
|
||||
uint8_t dest[ETH_ALEN];
|
||||
uint8_t src[ETH_ALEN];
|
||||
uint16_t type;
|
||||
unsigned char data[];
|
||||
};
|
||||
static void minios_transmit (struct nic *nic, const char *d, unsigned int t,
|
||||
unsigned int s, const char *p)
|
||||
{
|
||||
struct frame *frame = alloca(sizeof(frame) + s);
|
||||
|
||||
memcpy(frame->dest, d, ETH_ALEN);
|
||||
memcpy(frame->src, nic->node_addr, ETH_ALEN);
|
||||
frame->type = htons(t);
|
||||
memcpy(frame->data, p, s);
|
||||
|
||||
netfront_xmit(net_dev, (void*) frame, sizeof(*frame) + s);
|
||||
}
|
||||
|
||||
static char packet[ETH_FRAME_LEN];
|
||||
|
||||
struct nic nic = {
|
||||
.reset = minios_reset,
|
||||
.poll = minios_poll,
|
||||
.transmit = minios_transmit,
|
||||
.disable = minios_disable,
|
||||
.flags = 0,
|
||||
.rom_info = NULL,
|
||||
.node_addr = arptable[ARP_CLIENT].node,
|
||||
.packet = packet,
|
||||
.packetlen = 0,
|
||||
.priv_data = NULL,
|
||||
};
|
||||
|
||||
int
|
||||
eth_probe (void)
|
||||
{
|
||||
return minios_probe(&nic);
|
||||
}
|
||||
|
||||
int
|
||||
eth_poll (void)
|
||||
{
|
||||
return minios_poll (&nic);
|
||||
}
|
||||
|
||||
void
|
||||
eth_disable (void)
|
||||
{
|
||||
minios_disable (&nic);
|
||||
}
|
||||
|
||||
void
|
||||
eth_transmit (const char *d, unsigned int t,
|
||||
unsigned int s, const void *p)
|
||||
{
|
||||
minios_transmit (&nic, d, t, s, p);
|
||||
if (t == IP)
|
||||
twiddle();
|
||||
}
|
||||
|
||||
/*
|
||||
* Console
|
||||
*/
|
||||
void
|
||||
serial_hw_put (int _c)
|
||||
{
|
||||
char c = _c;
|
||||
console_print(&c, 1);
|
||||
}
|
||||
|
||||
int
|
||||
serial_hw_fetch (void)
|
||||
{
|
||||
char key;
|
||||
|
||||
if (!xencons_ring_avail())
|
||||
return -1;
|
||||
|
||||
read(STDIN_FILENO, &key, 1);
|
||||
switch (key) {
|
||||
case 0x7f: key = '\b'; break;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
/*
|
||||
* PVFB
|
||||
*/
|
||||
struct kbdfront_dev *kbd_dev;
|
||||
struct fbfront_dev *fb_dev;
|
||||
static union xenkbd_in_event ev;
|
||||
static int has_ev;
|
||||
int console_checkkey (void)
|
||||
{
|
||||
if (has_ev)
|
||||
return 1;
|
||||
has_ev = kbdfront_receive(kbd_dev, &ev, 1);
|
||||
return has_ev;
|
||||
}
|
||||
|
||||
/* static QWERTY layout, that's what most PC BIOSes do anyway */
|
||||
static char linux2ascii[] = {
|
||||
[ 1 ] = 27,
|
||||
[ 2 ] = '1',
|
||||
[ 3 ] = '2',
|
||||
[ 4 ] = '3',
|
||||
[ 5 ] = '4',
|
||||
[ 6 ] = '5',
|
||||
[ 7 ] = '6',
|
||||
[ 8 ] = '7',
|
||||
[ 9 ] = '8',
|
||||
[ 10 ] = '9',
|
||||
[ 11 ] = '0',
|
||||
[ 12 ] = '-',
|
||||
[ 13 ] = '=',
|
||||
[ 14 ] = '\b',
|
||||
[ 15 ] = '\t',
|
||||
[ 16 ] = 'q',
|
||||
[ 17 ] = 'w',
|
||||
[ 18 ] = 'e',
|
||||
[ 19 ] = 'r',
|
||||
[ 20 ] = 't',
|
||||
[ 21 ] = 'y',
|
||||
[ 22 ] = 'u',
|
||||
[ 23 ] = 'i',
|
||||
[ 24 ] = 'o',
|
||||
[ 25 ] = 'p',
|
||||
[ 26 ] = '[',
|
||||
[ 27 ] = ']',
|
||||
[ 28 ] = '\n',
|
||||
|
||||
[ 30 ] = 'a',
|
||||
[ 31 ] = 's',
|
||||
[ 32 ] = 'd',
|
||||
[ 33 ] = 'f',
|
||||
[ 34 ] = 'g',
|
||||
[ 35 ] = 'h',
|
||||
[ 36 ] = 'j',
|
||||
[ 37 ] = 'k',
|
||||
[ 38 ] = 'l',
|
||||
[ 39 ] = ';',
|
||||
[ 40 ] = '\'',
|
||||
[ 41 ] = '`',
|
||||
|
||||
[ 43 ] = '\\',
|
||||
[ 44 ] = 'z',
|
||||
[ 45 ] = 'x',
|
||||
[ 46 ] = 'c',
|
||||
[ 47 ] = 'v',
|
||||
[ 48 ] = 'b',
|
||||
[ 49 ] = 'n',
|
||||
[ 50 ] = 'm',
|
||||
[ 51 ] = ',',
|
||||
[ 52 ] = '.',
|
||||
[ 53 ] = '/',
|
||||
|
||||
[ 55 ] = '*',
|
||||
[ 57 ] = ' ',
|
||||
|
||||
[ 71 ] = '7',
|
||||
[ 72 ] = '8',
|
||||
[ 73 ] = '9',
|
||||
[ 74 ] = '-',
|
||||
[ 75 ] = '4',
|
||||
[ 76 ] = '5',
|
||||
[ 77 ] = '6',
|
||||
[ 78 ] = '+',
|
||||
[ 79 ] = '1',
|
||||
[ 80 ] = '2',
|
||||
[ 81 ] = '3',
|
||||
[ 82 ] = '0',
|
||||
[ 83 ] = '.',
|
||||
|
||||
[ 86 ] = '<',
|
||||
|
||||
[ 96 ] = '\n',
|
||||
|
||||
[ 98 ] = '/',
|
||||
|
||||
[ 102 ] = 1, /* home */
|
||||
[ 103 ] = 16, /* up */
|
||||
[ 104 ] = 7, /* page up */
|
||||
[ 105 ] = 2, /* left */
|
||||
[ 106 ] = 6, /* right */
|
||||
[ 107 ] = 5, /* end */
|
||||
[ 108 ] = 14, /* down */
|
||||
[ 109 ] = 3, /* page down */
|
||||
|
||||
[ 111 ] = 4, /* delete */
|
||||
};
|
||||
|
||||
static char linux2ascii_shifted[] = {
|
||||
[ 1 ] = 27,
|
||||
[ 2 ] = '!',
|
||||
[ 3 ] = '@',
|
||||
[ 4 ] = '#',
|
||||
[ 5 ] = '$',
|
||||
[ 6 ] = '%',
|
||||
[ 7 ] = '^',
|
||||
[ 8 ] = '&',
|
||||
[ 9 ] = '*',
|
||||
[ 10 ] = '(',
|
||||
[ 11 ] = ')',
|
||||
[ 12 ] = '_',
|
||||
[ 13 ] = '+',
|
||||
[ 14 ] = '\b',
|
||||
[ 15 ] = '\t',
|
||||
[ 16 ] = 'Q',
|
||||
[ 17 ] = 'W',
|
||||
[ 18 ] = 'E',
|
||||
[ 19 ] = 'R',
|
||||
[ 20 ] = 'T',
|
||||
[ 21 ] = 'Y',
|
||||
[ 22 ] = 'U',
|
||||
[ 23 ] = 'I',
|
||||
[ 24 ] = 'O',
|
||||
[ 25 ] = 'P',
|
||||
[ 26 ] = '{',
|
||||
[ 27 ] = '}',
|
||||
[ 28 ] = '\n',
|
||||
|
||||
[ 30 ] = 'A',
|
||||
[ 31 ] = 'S',
|
||||
[ 32 ] = 'D',
|
||||
[ 33 ] = 'F',
|
||||
[ 34 ] = 'G',
|
||||
[ 35 ] = 'H',
|
||||
[ 36 ] = 'J',
|
||||
[ 37 ] = 'K',
|
||||
[ 38 ] = 'L',
|
||||
[ 39 ] = ':',
|
||||
[ 40 ] = '"',
|
||||
[ 41 ] = '~',
|
||||
|
||||
[ 43 ] = '|',
|
||||
[ 44 ] = 'Z',
|
||||
[ 45 ] = 'X',
|
||||
[ 46 ] = 'C',
|
||||
[ 47 ] = 'V',
|
||||
[ 48 ] = 'B',
|
||||
[ 49 ] = 'N',
|
||||
[ 50 ] = 'M',
|
||||
[ 51 ] = '<',
|
||||
[ 52 ] = '>',
|
||||
[ 53 ] = '?',
|
||||
|
||||
[ 55 ] = '*',
|
||||
[ 57 ] = ' ',
|
||||
|
||||
[ 71 ] = '7',
|
||||
[ 72 ] = '8',
|
||||
[ 73 ] = '9',
|
||||
[ 74 ] = '-',
|
||||
[ 75 ] = '4',
|
||||
[ 76 ] = '5',
|
||||
[ 77 ] = '6',
|
||||
[ 78 ] = '+',
|
||||
[ 79 ] = '1',
|
||||
[ 80 ] = '2',
|
||||
[ 81 ] = '3',
|
||||
[ 82 ] = '0',
|
||||
[ 83 ] = '.',
|
||||
|
||||
[ 86 ] = '>',
|
||||
|
||||
[ 96 ] = '\n',
|
||||
|
||||
[ 98 ] = '/',
|
||||
|
||||
[ 102 ] = 1, /* home */
|
||||
[ 103 ] = 16, /* up */
|
||||
[ 104 ] = 7, /* page up */
|
||||
[ 105 ] = 2, /* left */
|
||||
[ 106 ] = 6, /* right */
|
||||
[ 107 ] = 5, /* end */
|
||||
[ 108 ] = 14, /* down */
|
||||
[ 109 ] = 3, /* page down */
|
||||
|
||||
[ 111 ] = 4, /* delete */
|
||||
};
|
||||
|
||||
int console_getkey (void)
|
||||
{
|
||||
static int shift, control, alt, caps_lock;
|
||||
|
||||
if (!has_ev)
|
||||
has_ev = kbdfront_receive(kbd_dev, &ev, 1);
|
||||
if (!has_ev)
|
||||
return 0;
|
||||
|
||||
has_ev = 0;
|
||||
if (ev.type != XENKBD_TYPE_KEY)
|
||||
return 0;
|
||||
|
||||
if (ev.key.keycode == 42 || ev.key.keycode == 54) {
|
||||
caps_lock = 0;
|
||||
shift = ev.key.pressed;
|
||||
return 0;
|
||||
}
|
||||
if (ev.key.keycode == 58) {
|
||||
caps_lock ^= 1;
|
||||
return 0;
|
||||
}
|
||||
if (ev.key.keycode == 29 || ev.key.keycode == 97) {
|
||||
control = ev.key.pressed;
|
||||
return 0;
|
||||
}
|
||||
if (ev.key.keycode == 56) {
|
||||
alt = ev.key.pressed;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ev.key.pressed)
|
||||
return 0;
|
||||
|
||||
if (ev.key.keycode < sizeof(linux2ascii) / sizeof(*linux2ascii)) {
|
||||
char val;
|
||||
if (shift || caps_lock)
|
||||
val = linux2ascii_shifted[ev.key.keycode];
|
||||
else
|
||||
val = linux2ascii[ev.key.keycode];
|
||||
if (control)
|
||||
val &= ~0x60;
|
||||
return val;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kbd_thread(void *p)
|
||||
{
|
||||
struct semaphore *sem = p;
|
||||
|
||||
kbd_dev = init_kbdfront(NULL, 1);
|
||||
up(sem);
|
||||
}
|
||||
|
||||
struct fbfront_dev *fb_open(void *fb, int width, int height, int depth)
|
||||
{
|
||||
unsigned long *mfns;
|
||||
int linesize = width * (depth / 8);
|
||||
int memsize = linesize * height;
|
||||
int numpages = (memsize + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||
DECLARE_MUTEX_LOCKED(sem);
|
||||
int i;
|
||||
|
||||
create_thread("kbdfront", kbd_thread, &sem);
|
||||
|
||||
mfns = malloc(numpages * sizeof(*mfns));
|
||||
for (i = 0; i < numpages; i++) {
|
||||
memset(fb + i * PAGE_SIZE, 0, PAGE_SIZE);
|
||||
mfns[i] = virtual_to_mfn(fb + i * PAGE_SIZE);
|
||||
}
|
||||
fb_dev = init_fbfront(NULL, mfns, width, height, depth, linesize, numpages);
|
||||
free(mfns);
|
||||
|
||||
if (!fb_dev)
|
||||
return NULL;
|
||||
|
||||
down(&sem);
|
||||
if (!kbd_dev)
|
||||
return NULL;
|
||||
|
||||
return fb_dev;
|
||||
}
|
||||
|
||||
void kbd_close(void *foo)
|
||||
{
|
||||
shutdown_kbdfront(kbd_dev);
|
||||
kbd_dev = NULL;
|
||||
}
|
||||
|
||||
void fb_close(void)
|
||||
{
|
||||
create_thread("kbdfront close", kbd_close, NULL);
|
||||
shutdown_fbfront(fb_dev);
|
||||
fb_dev = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Misc
|
||||
*/
|
||||
|
||||
int getrtsecs (void)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return tv.tv_sec;
|
||||
}
|
||||
|
||||
int currticks (void)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return ((tv.tv_sec * 1000000ULL + tv.tv_usec) * TICKS_PER_SEC) / 1000000;
|
||||
}
|
||||
|
||||
void __attribute__ ((noreturn)) grub_reboot (void)
|
||||
{
|
||||
for ( ;; )
|
||||
{
|
||||
struct sched_shutdown sched_shutdown = { .reason = SHUTDOWN_reboot };
|
||||
HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown);
|
||||
}
|
||||
}
|
||||
|
||||
#define SCRATCH_MEMSIZE (4 * 1024 * 1024)
|
||||
|
||||
/* Note: not allocating it dynamically permits to make sure it lays below 4G
|
||||
* for grub's 32bit pointers to work */
|
||||
char grub_scratch_mem[SCRATCH_MEMSIZE] __attribute__((aligned(PAGE_SIZE)));
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc > 1) {
|
||||
strncpy(config_file, argv[1], sizeof(config_file) - 1);
|
||||
config_file[sizeof(config_file) - 1] = 0;
|
||||
if (!strncmp(config_file, "(nd)", 4))
|
||||
preset_menu = "dhcp";
|
||||
} else
|
||||
preset_menu = "dhcp --with-configfile";
|
||||
|
||||
mbi.drives_addr = BOOTSEC_LOCATION + (60 * 1024);
|
||||
mbi.drives_length = 0;
|
||||
|
||||
mbi.boot_loader_name = (unsigned long) "GNU GRUB " VERSION;
|
||||
mbi.mem_lower = (start_info.nr_pages * PAGE_SIZE) / 1024;
|
||||
mbi.mem_upper = 0;
|
||||
saved_drive = boot_drive;
|
||||
saved_partition = install_partition;
|
||||
|
||||
init_disk();
|
||||
|
||||
/* Try to make sure the client part got launched */
|
||||
sleep(1);
|
||||
cmain();
|
||||
printk("cmain returned!\n");
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
extern int blk_nb;
|
||||
extern struct blkfront_dev **blk_dev;
|
||||
extern struct netfront_dev *net_dev;
|
||||
extern struct kbdfront_dev *kbd_dev;
|
||||
extern struct fbfront_dev *fb_dev;
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef __OSDEP_H__
|
||||
#define __OSDEP_H__
|
||||
|
||||
#include <byteswap.h>
|
||||
#define swap32(x) bswap_32(x)
|
||||
#define swap16(x) bswap_16(x)
|
||||
|
||||
#include <machine/endian.h>
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
#define htons(x) (x)
|
||||
#define ntohs(x) (x)
|
||||
#define htonl(x) (x)
|
||||
#define ntohl(x) (x)
|
||||
#else
|
||||
#define htons(x) swap16(x)
|
||||
#define ntohs(x) swap16(x)
|
||||
#define htonl(x) swap32(x)
|
||||
#define ntohl(x) swap32(x)
|
||||
#endif
|
||||
|
||||
typedef unsigned long Address;
|
||||
|
||||
/* ANSI prototyping macro */
|
||||
#ifdef __STDC__
|
||||
#define P(x) x
|
||||
#else
|
||||
#define P(x) ()
|
||||
#endif
|
||||
|
||||
#endif
|
||||