kvmtool: tiny init fox x86_64
cover kvmtool: tiny init fox x86_64
Hello,
Yesterday I discovered kvmtool and it looks really cool! Thanks! Looks like, it does exactly what I need.
But the static /virt/init doesn't look good. This series lessens the size of lkvm binary from 1045952 to 196200 bytes on x86_64, but this is minor. I want to write my /virt/init in shell or perl and this change can help.
I don't really know who should be cc'ed, I've picked some names from git-log guest/init.c.
Oleg.
.gitignore | 1 + Makefile | 26 +++++++++++++++++++++----- builtin-run.c | 4 ++++ builtin-setup.c | 36 ++++++++++++++++++++++++++---------- guest/init.c | 2 ++ x86/init.S | 38 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 92 insertions(+), 15 deletions(-)
PATCH 1/3 kvmtool/setup: Introduce extract_file() helper
Turn kvm_setup_guest_init(guestfs_name) into a more generic helper, extract_file(guestfs_name, filename, data, size) and reimplement kvm_setup_guest_init() as a trivial wrapper.
--- builtin-setup.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-)
builtin-setup.c +14 -10
@@ -122,30 +122,34 @@ static const char *guestfs_symlinks[] = { };#ifdef CONFIG_GUEST_INIT -extern char _binary_guest_init_start; -extern char _binary_guest_init_size; - -int kvm_setup_guest_init (const char *guestfs_name) +static int extract_file (const char *guestfs_name,const char *filename, +const void *data,const void *_size) {char path[PATH_MAX ]; -size_t size;int fd, ret; -char *data; - size = (size_t )&_binary_guest_init_size; - data = (char *)&_binary_guest_init_start; -snprintf (path,PATH_MAX ,"%s%s/virt/init" ,kvm__get_dir (), guestfs_name); +snprintf (path,PATH_MAX ,"%s%s/%s" ,kvm__get_dir (), + guestfs_name, filename);remove (path); fd =open (path,O_CREAT |O_WRONLY ,0755 );if (fd <0 )die ("Fail to setup %s" , path); - ret =xwrite (fd, data, size); + ret =xwrite (fd, data, (size_t )_size);if (ret <0 )die ("Fail to setup %s" , path);close (fd);return 0 ; +} +extern char _binary_guest_init_start; +extern char _binary_guest_init_size; + +int kvm_setup_guest_init (const char *guestfs_name) +{ +return extract_file (guestfs_name,"virt/init" , + &_binary_guest_init_start, + &_binary_guest_init_size); }#else int kvm_setup_guest_init (const char *guestfs_name)
Signature · 1 line
2.4.3
PATCH 2/3 kvmtool/build: introduce GUEST_PRE_INIT target
In reply to Oleg NesterovThis comes as a separate patch because I do not really understand /usr/bin/make, probably it should be updated.
Change the main Makefile so that if an arch defines ARCH_PRE_INIT then we
- build $GUEST_INIT without "-static"
- add -DCONFIG_GUEST_PRE_INIT to $CFLAGS
- build $ARCH_PRE_INIT as guest/guest_pre_init.o and embed it into lkvm the same as we do with guest/guest_init.o
This also means that ARCH_PRE_INIT case doesn't depend on glibc-static, we can relax the SOURCE_STATIC check later.
--- .gitignore | 1 + Makefile | 25 ++++++++++++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-)
.gitignore +1 -0
@@ -9,6 +9,7 @@ include/common-cmds.h tests/boot/boot_test.iso tests/boot/rootfs/ guest/init +guest/pre_init guest/init_stage2 KVMTOOLS-VERSION-FILE /x86/bios/bios.bin
Makefile +20 -5
@@ -281,6 +281,14 @@ ifeq ($(call try-build,$(SOURCE_STATIC),,-static),y) CFLAGS += -DCONFIG_GUEST_INIT GUEST_INIT := guest/init GUEST_OBJS = guest/guest_init.o + ifeq ($(ARCH_PRE_INIT),) + GUEST_INIT_FLAGS += -static + else + CFLAGS += -DCONFIG_GUEST_PRE_INIT + GUEST_INIT_FLAGS += -DCONFIG_GUEST_PRE_INIT + GUEST_PRE_INIT := guest/pre_init + GUEST_OBJS += guest/guest_pre_init.o + endif else $(warning No static libc found. Skipping guest init) NOTFOUND += static-libc
@@ -346,7 +354,7 @@ ifneq ($(WERROR),0) CFLAGS += -Werror endif -all: $(PROGRAM) $(PROGRAM_ALIAS) $(GUEST_INIT) +all: $(PROGRAM) $(PROGRAM_ALIAS) $(GUEST_INIT) $(GUEST_PRE_INIT) # CFLAGS used when building objects # This is intentionally not assigned using :=
@@ -360,11 +368,11 @@ c_flags = -Wp,-MD,$(depfile) $(CFLAGS) # STATIC_OBJS = $(patsubst %.o,%.static.o,$(OBJS) $(OBJS_STATOPT)) -$(PROGRAM)-static: $(STATIC_OBJS) $(OTHEROBJS) $(GUEST_INIT) +$(PROGRAM)-static: $(STATIC_OBJS) $(OTHEROBJS) $(GUEST_INIT) $(GUEST_PRE_INIT) $(E) " LINK " $@ $(Q) $(CC) -static $(CFLAGS) $(STATIC_OBJS) $(OTHEROBJS) $(GUEST_OBJS) $(LIBS) $(LIBS_STATOPT) -o $@ -$(PROGRAM): $(OBJS) $(OBJS_DYNOPT) $(OTHEROBJS) $(GUEST_INIT) +$(PROGRAM): $(OBJS) $(OBJS_DYNOPT) $(OTHEROBJS) $(GUEST_INIT) $(GUEST_PRE_INIT) $(E) " LINK " $@ $(Q) $(CC) $(CFLAGS) $(OBJS) $(OBJS_DYNOPT) $(OTHEROBJS) $(GUEST_OBJS) $(LIBS) $(LIBS_DYNOPT) -o $@
@@ -372,9 +380,16 @@ $(PROGRAM_ALIAS): $(PROGRAM) $(E) " LN " $@ $(Q) ln -f $(PROGRAM) $@ +ifneq ($(ARCH_PRE_INIT),) +$(GUEST_PRE_INIT): $(ARCH_PRE_INIT) + $(E) " LINK " $@ + $(Q) $(CC) -s -nostdlib $(ARCH_PRE_INIT) -o $@ + $(Q) $(LD) $(LDFLAGS) -r -b binary -o guest/guest_pre_init.o $(GUEST_PRE_INIT) +endif + $(GUEST_INIT): guest/init.c $(E) " LINK " $@ - $(Q) $(CC) -static guest/init.c -o $@ + $(Q) $(CC) $(GUEST_INIT_FLAGS) guest/init.c -o $@ $(Q) $(LD) $(LDFLAGS) -r -b binary -o guest/guest_init.o $(GUEST_INIT) %.s: %.c
@@ -473,7 +488,7 @@ clean: $(Q) rm -f x86/bios/bios-rom.h $(Q) rm -f tests/boot/boot_test.iso $(Q) rm -rf tests/boot/rootfs/ - $(Q) rm -f $(DEPS) $(OBJS) $(OTHEROBJS) $(OBJS_DYNOPT) $(STATIC_OBJS) $(PROGRAM) $(PROGRAM_ALIAS) $(PROGRAM)-static $(GUEST_INIT) $(GUEST_OBJS) + $(Q) rm -f $(DEPS) $(OBJS) $(OTHEROBJS) $(OBJS_DYNOPT) $(STATIC_OBJS) $(PROGRAM) $(PROGRAM_ALIAS) $(PROGRAM)-static $(GUEST_INIT) $(GUEST_PRE_INIT) $(GUEST_OBJS) $(Q) rm -f cscope.* $(Q) rm -f tags $(Q) rm -f TAGS
Signature · 1 line
2.4.3
PATCH 3/3 kvmtool/x86: implement guest_pre_init
In reply to Oleg NesterovAdd the tiny x86/init.S which just mounts /host and execs /virt/init.
NOTE: of course, the usage of CONFIG_GUEST_PRE_INIT is ugly, we need to cleanup this code. But I'd prefer to do this on top of this minimal/simple change. And I think this needs cleanups in any case, for example I think lkvm shouldn't abuse the "init=" kernel parameter at all.
TODO: x86/init.S doesn't handle i386, should be simple to add.
--- Makefile | 1 + builtin-run.c | 4 ++++ builtin-setup.c | 14 +++++++++++++- guest/init.c | 2 ++ x86/init.S | 38 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 x86/init.S
Makefile +1 -0
@@ -110,6 +110,7 @@ endif ifeq ($(ARCH),x86_64) ARCH := x86 DEFINES += -DCONFIG_X86_64 + ARCH_PRE_INIT = x86/init.S endif ### Arch-specific stuff
builtin-run.c +4 -0
@@ -600,7 +600,11 @@ static struct kvm *kvm_cmd_run_init(int argc, const char **argv)if (kvm->cfg.custom_rootfs) {kvm_run_set_sandbox (kvm); +#ifdef CONFIG_GUEST_PRE_INIT +strcat (real_cmdline," init=/virt/pre_init" ); +#else strcat (real_cmdline," init=/virt/init" ); +#endif if (!kvm->cfg.no_dhcp)strcat (real_cmdline," ip=dhcp" );
builtin-setup.c +13 -1
@@ -144,12 +144,24 @@ static int extract_file(const char *guestfs_name, const char *filename,extern char _binary_guest_init_start;extern char _binary_guest_init_size; +extern char _binary_guest_pre_init_start; +extern char _binary_guest_pre_init_size;int kvm_setup_guest_init (const char *guestfs_name) { -return extract_file (guestfs_name,"virt/init" , +int err; + +#ifdef CONFIG_GUEST_PRE_INIT + err =extract_file (guestfs_name,"virt/pre_init" , + &_binary_guest_pre_init_start, + &_binary_guest_pre_init_size); +if (err) +return err; +#endif + err =extract_file (guestfs_name,"virt/init" , &_binary_guest_init_start, &_binary_guest_init_size); +return err; }#else int kvm_setup_guest_init (const char *guestfs_name)
guest/init.c +2 -0
@@ -30,7 +30,9 @@ static int run_process_sandbox(char *filename)static void do_mounts (void ) { +#ifndef CONFIG_GUEST_PRE_INIT mount ("hostfs" ,"/host" ,"9p" ,MS_RDONLY ,"trans=virtio,version=9p2000.L" ); +#endif mount ("" ,"/sys" ,"sysfs" ,0 ,NULL );mount ("proc" ,"/proc" ,"proc" ,0 ,NULL );mount ("devtmpfs" ,"/dev" ,"devtmpfs" ,0 ,NULL );
x86/init.S new file +38 -0
@@ -0,0 +1,38 @@ +.data + +.m_dev: +.string "hostfs" +.m_dir: +.string "/host" +.m_typ: +.string "9p" +.m_opt: +.string "trans=virtio,version=9p2000.L" + +.e_nam: +.string "/virt/init" + +.text +.globl _start +_start: + + mov $165, %rax # __NR_mount + mov $.m_dev, %rdi + mov $.m_dir, %rsi + mov $.m_typ, %rdx + mov $1, %r10 # MS_RDONLY + mov $.m_opt, %r8 + syscall + + mov $59, %rax # __NR_execve + mov $.e_nam, %rdi + lea 8(%rsp), %rsi # argv[] + mov %rdi, (%rsi) # change argv[0] + pop %rcx # argc + inc %rcx + lea (%rsi,%rcx,8), %rdx # envp[] + syscall + + mov $60, %rax # __NR_exit + mov $1, %rdi + syscall # panic
Signature · 1 line
2.4.3
Hi Oleg,
Quoted 10 lines · Oleg Nesterov
Yesterday I discovered kvmtool and it looks really cool! Thanks! Looks like, it does exactly what I need.
But the static /virt/init doesn't look good. This series lessens the size of lkvm binary from 1045952 to 196200 bytes on
x86_64, but this is minor. I want to write my /virt/init in shell or perl and this change can help.I don't really know who should be cc'ed, I've picked some names from git-log
guest/init.c.
Will maintains the standalone kvmtool.git tree.
The series looks good to me:
- Pekka
Hi Pekka,
Quoted 4 lines · Pekka Enberg
The series looks good to me:
Acked-by Pekka Enberg <[email protected]>
Thanks! I'll try to send some cleanups later.
But let me send another simple series first.
Oleg.