From mboxrd@z Thu Jan 1 00:00:00 1970 From: Asias He Subject: Re: [PATCH 1/3 V4] kvm tools: Add memory gap for larger RAM sizes Date: Thu, 12 May 2011 08:49:37 +0800 Message-ID: <4DCB2EA1.2080805@gmail.com> References: <4dcaa893.5925e30a.0f9e.125c@mx.google.com> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: QUOTED-PRINTABLE Cc: penberg@kernel.org, mingo@elte.hu, prasadjoshi124@gmail.com, avi@redhat.com, gorcunov@gmail.com, kvm@vger.kernel.org To: levinsasha928@gmail.com Return-path: Received: from mail-pz0-f46.google.com ([209.85.210.46]:46540 "EHLO mail-pz0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754839Ab1ELAuz (ORCPT ); Wed, 11 May 2011 20:50:55 -0400 Received: by pzk9 with SMTP id 9so485333pzk.19 for ; Wed, 11 May 2011 17:50:54 -0700 (PDT) In-Reply-To: <4dcaa893.5925e30a.0f9e.125c@mx.google.com> Sender: kvm-owner@vger.kernel.org List-ID: On 05/11/2011 11:17 PM, levinsasha928@gmail.com wrote: > From: Sasha Levin >=20 > e820 is expected to leave a memory gap within the low 32 > bits of RAM space. From the documentation of e820_setup_gap(): > /* > * Search for the biggest gap in the low 32 bits of the e820 > * memory space. We pass this space to PCI to assign MMIO resources > * for hotplug or unconfigured devices in. > * Hopefully the BIOS let enough space left. > */ >=20 > Not leaving such gap causes errors and hangs during the boot > process. >=20 > This patch adds a memory gap between 0xe0000000 and 0x100000000 > when using more than 0xe0000000 bytes for guest RAM. >=20 > This patch updates the e820 table, slot allocations > used for KVM_SET_USER_MEMORY_REGION. >=20 > Changes in V2: > - Allocate RAM with the gap to avoid altering the translation code. > - New patch description. >=20 > Changes in V3: > - Remove unnecessary casts. >=20 > Changes in V4: > - Rewrite kvm__init_ram(). > - Document the 64bit gap within the code. >=20 > Signed-off-by: Sasha Levin > --- > tools/kvm/bios.c | 27 ++++++++++++---- > tools/kvm/include/kvm/e820.h | 2 +- > tools/kvm/include/kvm/kvm.h | 2 + > tools/kvm/kvm.c | 66 ++++++++++++++++++++++++++++++++= +++++---- > 4 files changed, 82 insertions(+), 15 deletions(-) >=20 > diff --git a/tools/kvm/bios.c b/tools/kvm/bios.c > index 2199c0c..3cd9b24 100644 > --- a/tools/kvm/bios.c > +++ b/tools/kvm/bios.c > @@ -61,8 +61,6 @@ static void e820_setup(struct kvm *kvm) > size =3D guest_flat_to_host(kvm, E820_MAP_SIZE); > mem_map =3D guest_flat_to_host(kvm, E820_MAP_START); > =20 > - *size =3D E820_MEM_AREAS; > - > mem_map[i++] =3D (struct e820_entry) { > .addr =3D REAL_MODE_IVT_BEGIN, > .size =3D EBDA_START - REAL_MODE_IVT_BEGIN, > @@ -78,13 +76,28 @@ static void e820_setup(struct kvm *kvm) > .size =3D MB_BIOS_END - MB_BIOS_BEGIN, > .type =3D E820_MEM_RESERVED, > }; > - mem_map[i++] =3D (struct e820_entry) { > - .addr =3D BZ_KERNEL_START, > - .size =3D kvm->ram_size - BZ_KERNEL_START, > - .type =3D E820_MEM_USABLE, > - }; > + if (kvm->ram_size < KVM_32BIT_GAP_START) { > + mem_map[i++] =3D (struct e820_entry) { > + .addr =3D BZ_KERNEL_START, > + .size =3D kvm->ram_size - BZ_KERNEL_START, > + .type =3D E820_MEM_USABLE, > + }; > + } else { > + mem_map[i++] =3D (struct e820_entry) { > + .addr =3D BZ_KERNEL_START, > + .size =3D KVM_32BIT_GAP_START - BZ_KERNEL_START, > + .type =3D E820_MEM_USABLE, > + }; > + mem_map[i++] =3D (struct e820_entry) { > + .addr =3D 0x100000000ULL, > + .size =3D kvm->ram_size - KVM_32BIT_GAP_START, > + .type =3D E820_MEM_USABLE, > + }; > + } > =20 > BUILD_BUG_ON(i > E820_MEM_AREAS); > + > + *size =3D i; > } > =20 > /** > diff --git a/tools/kvm/include/kvm/e820.h b/tools/kvm/include/kvm/e82= 0.h > index 252ae1f..e0f5f2a 100644 > --- a/tools/kvm/include/kvm/e820.h > +++ b/tools/kvm/include/kvm/e820.h > @@ -8,7 +8,7 @@ > #define E820_MEM_USABLE 1 > #define E820_MEM_RESERVED 2 > =20 > -#define E820_MEM_AREAS 4 > +#define E820_MEM_AREAS 5 > =20 > struct e820_entry { > u64 addr; /* start of memory segment */ > diff --git a/tools/kvm/include/kvm/kvm.h b/tools/kvm/include/kvm/kvm.= h > index 3dab78d..5e2e64c 100644 > --- a/tools/kvm/include/kvm/kvm.h > +++ b/tools/kvm/include/kvm/kvm.h > @@ -8,6 +8,8 @@ > #include > =20 > #define KVM_NR_CPUS (255) > +#define KVM_32BIT_GAP_SIZE (512 << 20) > +#define KVM_32BIT_GAP_START ((1ULL << 32) - KVM_32BIT_GAP_SIZE) > =20 > struct kvm { > int sys_fd; /* For system ioctls(), i.e. /dev/kvm */ > diff --git a/tools/kvm/kvm.c b/tools/kvm/kvm.c > index 65793f2..a3d3dd8 100644 > --- a/tools/kvm/kvm.c > +++ b/tools/kvm/kvm.c > @@ -153,23 +153,64 @@ static bool kvm__cpu_supports_vm(void) > return regs.ecx & (1 << feature); > } > =20 > -void kvm__init_ram(struct kvm *self) > +static void kvm_register_mem_slot(struct kvm *kvm, u32 slot, u64 gue= st_phys, u64 size, void *userspace_addr) > { > struct kvm_userspace_memory_region mem; > int ret; > =20 > mem =3D (struct kvm_userspace_memory_region) { > - .slot =3D 0, > - .guest_phys_addr =3D 0x0UL, > - .memory_size =3D self->ram_size, > - .userspace_addr =3D (unsigned long) self->ram_start, > + .slot =3D slot, > + .guest_phys_addr =3D guest_phys, > + .memory_size =3D size, > + .userspace_addr =3D (u64)userspace_addr, I am seeing: CC kvm.o kvm.c: In function =E2=80=98kvm_register_mem_slot=E2=80=99: kvm.c:165:22: error: cast from pointer to integer of different size [-Werror=3Dpointer-to-int-cast] cc1: all warnings being treated as errors make: *** [kvm.o] Error 1 with this patch on 32-bit box. > }; > =20 > - ret =3D ioctl(self->vm_fd, KVM_SET_USER_MEMORY_REGION, &mem); > + ret =3D ioctl(kvm->vm_fd, KVM_SET_USER_MEMORY_REGION, &mem); > if (ret < 0) > die_perror("KVM_SET_USER_MEMORY_REGION ioctl"); > } > =20 > +/* > + * Allocating RAM size bigger than 4GB requires us to leave a gap > + * in the RAM which is used for PCI MMIO, hotplug, and unconfigured > + * devices (see documentation of e820_setup_gap() for details). > + * > + * If we're required to initialize RAM bigger than 4GB, we will crea= te > + * a gap between 0xe0000000 and 0x100000000 in the guest virtual mem= space. > + */ > + > +void kvm__init_ram(struct kvm *self) > +{ > + u64 phys_start, phys_size; > + void *host_mem; > + > + if (self->ram_size < KVM_32BIT_GAP_START) { > + /* Use a single block of RAM for 32bit RAM */ > + > + phys_start =3D 0; > + phys_size =3D self->ram_size; > + host_mem =3D self->ram_start; > + > + kvm_register_mem_slot(self, 0, 0, self->ram_size, self->ram_start)= ; > + } else { > + /* First RAM range from zero to the PCI gap: */ > + > + phys_start =3D 0; > + phys_size =3D KVM_32BIT_GAP_START; > + host_mem =3D self->ram_start; > + > + kvm_register_mem_slot(self, 0, phys_start, phys_size, host_mem); > + > + /* Second RAM range from 4GB to the end of RAM: */ > + > + phys_start =3D 0x100000000ULL; > + phys_size =3D self->ram_size - phys_size; > + host_mem =3D self->ram_start + phys_start; > + > + kvm_register_mem_slot(self, 1, phys_start, phys_size, host_mem); > + } > +} > + > int kvm__max_cpus(struct kvm *self) > { > int ret; > @@ -225,7 +266,18 @@ struct kvm *kvm__init(const char *kvm_dev, unsig= ned long ram_size) > =20 > self->ram_size =3D ram_size; > =20 > - self->ram_start =3D mmap(NULL, ram_size, PROT_READ | PROT_WRITE, MA= P_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); > + if (self->ram_size < KVM_32BIT_GAP_START) { > + self->ram_start =3D mmap(NULL, ram_size, PROT_READ | PROT_WRITE, M= AP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); > + } else { > + self->ram_start =3D mmap(NULL, ram_size + KVM_32BIT_GAP_SIZE, PROT= _READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0)= ; > + if (self->ram_start !=3D MAP_FAILED) { > + /* > + * We mprotect the gap (see kvm__init_ram() for details) PROT_NON= E so that > + * if we accidently write to it, we will know. > + */ > + mprotect(self->ram_start + KVM_32BIT_GAP_START, KVM_32BIT_GAP_SIZ= E, PROT_NONE); > + } > + } > if (self->ram_start =3D=3D MAP_FAILED) > die("out of memory"); > =20 --=20 Best Regards, Asias He