ia64/xen-unstable

changeset 19019:67ffce500feb

hvmloader: Reserve BIOS memory and VGA memory at top of 4GB memory hole.

To make memory management easier in hvmloader, defer building a
generic E820 map until the end of hvmloader bootstrap.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jan 08 16:59:21 2009 +0000 (2009-01-08)
parents 61dc77689daf
children f75567adad9b
files tools/firmware/hvmloader/32bitbios_support.c tools/firmware/hvmloader/acpi/build.c tools/firmware/hvmloader/config.h tools/firmware/hvmloader/hvmloader.c tools/firmware/hvmloader/smbios.c tools/firmware/hvmloader/util.c tools/firmware/hvmloader/util.h
line diff
     1.1 --- a/tools/firmware/hvmloader/32bitbios_support.c	Thu Jan 08 16:53:15 2009 +0000
     1.2 +++ b/tools/firmware/hvmloader/32bitbios_support.c	Thu Jan 08 16:59:21 2009 +0000
     1.3 @@ -76,7 +76,7 @@ static void relocate_32bitbios(char *elf
     1.4       */
     1.5      reloc_size = reloc_off;
     1.6      printf("%d bytes of ROMBIOS high-memory extensions:\n", reloc_size);
     1.7 -    highbiosarea = (char *)(long)e820_malloc(reloc_size, 0);
     1.8 +    highbiosarea = mem_alloc(reloc_size, 0);
     1.9      BUG_ON(highbiosarea == NULL);
    1.10      printf("  Relocating to 0x%x-0x%x ... ",
    1.11             (uint32_t)&highbiosarea[0],
     2.1 --- a/tools/firmware/hvmloader/acpi/build.c	Thu Jan 08 16:53:15 2009 +0000
     2.2 +++ b/tools/firmware/hvmloader/acpi/build.c	Thu Jan 08 16:59:21 2009 +0000
     2.3 @@ -199,6 +199,7 @@ static int construct_secondary_tables(ui
     2.4      struct acpi_20_tcpa *tcpa;
     2.5      static const uint16_t tis_signature[] = {0x0001, 0x0001, 0x0001};
     2.6      uint16_t *tis_hdr;
     2.7 +    void *lasa;
     2.8  
     2.9      /* MADT. */
    2.10      if ( (hvm_info->nr_vcpus > 1) || hvm_info->apic_mode )
    2.11 @@ -246,11 +247,11 @@ static int construct_secondary_tables(ui
    2.12          tcpa->header.oem_revision = ACPI_OEM_REVISION;
    2.13          tcpa->header.creator_id   = ACPI_CREATOR_ID;
    2.14          tcpa->header.creator_revision = ACPI_CREATOR_REVISION;
    2.15 -        tcpa->lasa = e820_malloc(ACPI_2_0_TCPA_LAML_SIZE, 0);
    2.16 -        if ( tcpa->lasa )
    2.17 +        if ( (lasa = mem_alloc(ACPI_2_0_TCPA_LAML_SIZE, 0)) != NULL )
    2.18          {
    2.19 +            tcpa->lasa = virt_to_phys(lasa);
    2.20              tcpa->laml = ACPI_2_0_TCPA_LAML_SIZE;
    2.21 -            memset((char *)(unsigned long)tcpa->lasa, 0, tcpa->laml);
    2.22 +            memset(lasa, 0, tcpa->laml);
    2.23              set_checksum(tcpa,
    2.24                           offsetof(struct acpi_header, checksum),
    2.25                           tcpa->header.length);
    2.26 @@ -376,7 +377,7 @@ void acpi_build_tables(void)
    2.27      memset(buf, 0, high_sz);
    2.28  
    2.29      /* Allocate data area and set up ACPI tables there. */
    2.30 -    buf = (uint8_t *)e820_malloc(high_sz, 0);
    2.31 +    buf = mem_alloc(high_sz, 0);
    2.32      __acpi_build_tables(buf, &low_sz, &high_sz);
    2.33  
    2.34      printf(" - Lo data: %08lx-%08lx\n"
     3.1 --- a/tools/firmware/hvmloader/config.h	Thu Jan 08 16:53:15 2009 +0000
     3.2 +++ b/tools/firmware/hvmloader/config.h	Thu Jan 08 16:59:21 2009 +0000
     3.3 @@ -17,6 +17,10 @@
     3.4  #define PCI_MEMBASE         0xf0000000
     3.5  #define PCI_MEMSIZE         0x0c000000
     3.6  
     3.7 +/* We reserve 16MB at the top of the 4GB memory hole. */
     3.8 +#define RESERVED_MEMBASE    0xff000000
     3.9 +#define RESERVED_MEMSIZE    0x01000000
    3.10 +
    3.11  #define ROMBIOS_SEG            0xF000
    3.12  #define ROMBIOS_BEGIN          0x000F0000
    3.13  #define ROMBIOS_SIZE           0x00010000
     4.1 --- a/tools/firmware/hvmloader/hvmloader.c	Thu Jan 08 16:53:15 2009 +0000
     4.2 +++ b/tools/firmware/hvmloader/hvmloader.c	Thu Jan 08 16:59:21 2009 +0000
     4.3 @@ -488,22 +488,13 @@ static int pci_load_option_roms(uint32_t
     4.4  /* Replace possibly erroneous memory-size CMOS fields with correct values. */
     4.5  static void cmos_write_memory_size(void)
     4.6  {
     4.7 -    struct e820entry *map = E820;
     4.8 -    int i, nr = *E820_NR;
     4.9 -    uint32_t base_mem = 640, ext_mem = 0, alt_mem = 0;
    4.10 -
    4.11 -    for ( i = 0; i < nr; i++ )
    4.12 -        if ( (map[i].addr >= 0x100000) && (map[i].type == E820_RAM) )
    4.13 -            break;
    4.14 +    uint32_t base_mem = 640, ext_mem, alt_mem;
    4.15  
    4.16 -    if ( i != nr )
    4.17 -    {
    4.18 -        alt_mem = ext_mem = map[i].addr + map[i].size;
    4.19 -        ext_mem = (ext_mem > 0x0100000) ? (ext_mem - 0x0100000) >> 10 : 0;
    4.20 -        if ( ext_mem > 0xffff )
    4.21 -            ext_mem = 0xffff;
    4.22 -        alt_mem = (alt_mem > 0x1000000) ? (alt_mem - 0x1000000) >> 16 : 0;
    4.23 -    }
    4.24 +    alt_mem = ext_mem = hvm_info->low_mem_pgend << PAGE_SHIFT;
    4.25 +    ext_mem = (ext_mem > 0x0100000) ? (ext_mem - 0x0100000) >> 10 : 0;
    4.26 +    if ( ext_mem > 0xffff )
    4.27 +        ext_mem = 0xffff;
    4.28 +    alt_mem = (alt_mem > 0x1000000) ? (alt_mem - 0x1000000) >> 16 : 0;
    4.29  
    4.30      /* All BIOSes: conventional memory (CMOS *always* reports 640kB). */
    4.31      cmos_outb(0x15, (uint8_t)(base_mem >> 0));
    4.32 @@ -548,16 +539,16 @@ static uint16_t init_xen_platform_io_bas
    4.33   */
    4.34  static void init_vm86_tss(void)
    4.35  {
    4.36 -    uint32_t tss;
    4.37 +    void *tss;
    4.38      struct xen_hvm_param p;
    4.39  
    4.40 -    tss = e820_malloc(128, 128);
    4.41 -    memset((char *)tss, 0, 128);
    4.42 +    tss = mem_alloc(128, 128);
    4.43 +    memset(tss, 0, 128);
    4.44      p.domid = DOMID_SELF;
    4.45      p.index = HVM_PARAM_VM86_TSS;
    4.46 -    p.value = tss;
    4.47 +    p.value = virt_to_phys(tss);
    4.48      hypercall_hvm_op(HVMOP_set_param, &p);
    4.49 -    printf("vm86 TSS at %08x\n", tss);
    4.50 +    printf("vm86 TSS at %08lx\n", virt_to_phys(tss));
    4.51  }
    4.52  
    4.53  /* Create an E820 table based on memory parameters provided in hvm_info. */
    4.54 @@ -603,14 +594,11 @@ static void build_e820_table(void)
    4.55      e820[nr].type = E820_RAM;
    4.56      nr++;
    4.57  
    4.58 -    if ( hvm_info->reserved_mem_pgstart )
    4.59 -    {
    4.60 -        /* Explicitly reserve space for special pages. */
    4.61 -        e820[nr].addr = hvm_info->reserved_mem_pgstart << PAGE_SHIFT;
    4.62 -        e820[nr].size = (uint32_t)-e820[nr].addr;
    4.63 -        e820[nr].type = E820_RESERVED;
    4.64 -        nr++;
    4.65 -    }
    4.66 +    /* Explicitly reserve space for special pages. */
    4.67 +    e820[nr].addr = RESERVED_MEMBASE;
    4.68 +    e820[nr].size = (uint32_t)-e820[nr].addr;
    4.69 +    e820[nr].type = E820_RESERVED;
    4.70 +    nr++;
    4.71  
    4.72      if ( hvm_info->high_mem_pgend )
    4.73      {
    4.74 @@ -633,8 +621,6 @@ int main(void)
    4.75  
    4.76      printf("HVM Loader\n");
    4.77  
    4.78 -    build_e820_table();
    4.79 -
    4.80      init_hypercalls();
    4.81  
    4.82      printf("CPU speed is %u MHz\n", get_cpu_mhz());
    4.83 @@ -680,7 +666,7 @@ int main(void)
    4.84  
    4.85      if ( virtual_vga != VGA_none )
    4.86      {
    4.87 -        vga_ram = e820_malloc(8 << 20, 4096);
    4.88 +        vga_ram = virt_to_phys(mem_alloc(8 << 20, 4096));
    4.89          printf("VGA RAM at %08x\n", vga_ram);
    4.90      }
    4.91  
    4.92 @@ -728,6 +714,8 @@ int main(void)
    4.93      if ( xen_pfiob && vga_ram )
    4.94          outl(xen_pfiob + 4, vga_ram);
    4.95  
    4.96 +    build_e820_table();
    4.97 +
    4.98      printf("Invoking ROMBIOS ...\n");
    4.99      return 0;
   4.100  }
     5.1 --- a/tools/firmware/hvmloader/smbios.c	Thu Jan 08 16:53:15 2009 +0000
     5.2 +++ b/tools/firmware/hvmloader/smbios.c	Thu Jan 08 16:59:21 2009 +0000
     5.3 @@ -143,28 +143,18 @@ write_smbios_tables(void *start,
     5.4  static uint64_t
     5.5  get_memsize(void)
     5.6  {
     5.7 -    struct e820entry *map = E820;
     5.8 -    uint8_t num_entries = *E820_NR;
     5.9 -    uint64_t memsize = 0;
    5.10 -    int i;
    5.11 +    uint64_t sz;
    5.12  
    5.13 -    /*
    5.14 -     * Walk through e820map, ignoring any entries that aren't marked
    5.15 -     * as usable or reserved.
    5.16 -     */
    5.17 -    for ( i = 0; i < num_entries; i++ )
    5.18 -    {
    5.19 -        if ( (map->type == E820_RAM) || (map->type == E820_RESERVED) )
    5.20 -            memsize += map->size;
    5.21 -        map++;
    5.22 -    }
    5.23 +    sz = (uint64_t)hvm_info->low_mem_pgend << PAGE_SHIFT;
    5.24 +    if ( hvm_info->high_mem_pgend )
    5.25 +        sz += (hvm_info->high_mem_pgend << PAGE_SHIFT) - (1ull << 32);
    5.26  
    5.27      /*
    5.28       * Round up to the nearest MB.  The user specifies domU pseudo-physical 
    5.29       * memory in megabytes, so not doing this could easily lead to reporting 
    5.30       * one less MB than the user specified.
    5.31       */
    5.32 -    return (memsize + (1 << 20) - 1) >> 20;
    5.33 +    return (sz + (1ul << 20) - 1) >> 20;
    5.34  }
    5.35  
    5.36  int
     6.1 --- a/tools/firmware/hvmloader/util.c	Thu Jan 08 16:53:15 2009 +0000
     6.2 +++ b/tools/firmware/hvmloader/util.c	Thu Jan 08 16:59:21 2009 +0000
     6.3 @@ -303,63 +303,62 @@ uuid_to_string(char *dest, uint8_t *uuid
     6.4      *p = '\0';
     6.5  }
     6.6  
     6.7 -static void e820_collapse(void)
     6.8 +void *mem_alloc(uint32_t size, uint32_t align)
     6.9  {
    6.10 -    int i = 0;
    6.11 -    struct e820entry *ent = E820;
    6.12 -
    6.13 -    while ( i < (*E820_NR-1) )
    6.14 -    {
    6.15 -        if ( (ent[i].type == ent[i+1].type) &&
    6.16 -             ((ent[i].addr + ent[i].size) == ent[i+1].addr) )
    6.17 -        {
    6.18 -            ent[i].size += ent[i+1].size;
    6.19 -            memcpy(&ent[i+1], &ent[i+2], (*E820_NR-i-2) * sizeof(*ent));
    6.20 -            (*E820_NR)--;
    6.21 -        }
    6.22 -        else
    6.23 -        {
    6.24 -            i++;
    6.25 -        }
    6.26 -    }
    6.27 -}
    6.28 -
    6.29 -uint32_t e820_malloc(uint32_t size, uint32_t align)
    6.30 -{
    6.31 -    uint32_t addr;
    6.32 -    int i;
    6.33 -    struct e820entry *ent = E820;
    6.34 +    static uint32_t reserve = RESERVED_MEMBASE - 1;
    6.35 +    static int over_allocated;
    6.36 +    struct xen_memory_reservation xmr;
    6.37 +    xen_pfn_t mfn;
    6.38 +    uint32_t s, e;
    6.39  
    6.40      /* Align to at least one kilobyte. */
    6.41      if ( align < 1024 )
    6.42          align = 1024;
    6.43  
    6.44 -    for ( i = *E820_NR - 1; i >= 0; i-- )
    6.45 +    s = (reserve + align) & ~(align - 1);
    6.46 +    e = s + size - 1;
    6.47 +
    6.48 +    BUG_ON((e < s) || (e >> PAGE_SHIFT) >= hvm_info->reserved_mem_pgstart);
    6.49 +
    6.50 +    while ( (reserve >> PAGE_SHIFT) != (e >> PAGE_SHIFT) )
    6.51      {
    6.52 -        addr = (ent[i].addr + ent[i].size - size) & ~(align-1);
    6.53 -        if ( (ent[i].type != E820_RAM) || /* not ram? */
    6.54 -             (addr < ent[i].addr) ||      /* too small or starts above 4gb? */
    6.55 -             ((addr + size) < addr) )     /* ends above 4gb? */
    6.56 +        reserve += PAGE_SIZE;
    6.57 +
    6.58 +        /* Try to allocate another page in the reserved area. */
    6.59 +        xmr.domid = DOMID_SELF;
    6.60 +        xmr.mem_flags = 0;
    6.61 +        xmr.extent_order = 0;
    6.62 +        xmr.nr_extents = 1;
    6.63 +        set_xen_guest_handle(xmr.extent_start, &mfn);
    6.64 +        mfn = reserve >> PAGE_SHIFT;
    6.65 +        if ( !over_allocated &&
    6.66 +             (hypercall_memory_op(XENMEM_populate_physmap, &xmr) == 1) )
    6.67              continue;
    6.68  
    6.69 -        if ( addr != ent[i].addr )
    6.70 +        /* If we fail, steal a page from the ordinary RAM map. */
    6.71 +        over_allocated = 1;
    6.72 +        if ( hvm_info->high_mem_pgend )
    6.73 +        {
    6.74 +            mfn = --hvm_info->high_mem_pgend;
    6.75 +            if ( mfn == (1ull << (32 - PAGE_SHIFT)) )
    6.76 +                hvm_info->high_mem_pgend = 0;
    6.77 +        }
    6.78 +        else
    6.79          {
    6.80 -            memmove(&ent[i+1], &ent[i], (*E820_NR-i) * sizeof(*ent));
    6.81 -            (*E820_NR)++;
    6.82 -            ent[i].size = addr - ent[i].addr;
    6.83 -            ent[i+1].addr = addr;
    6.84 -            ent[i+1].size -= ent[i].size;
    6.85 -            i++;
    6.86 +            mfn = --hvm_info->low_mem_pgend;
    6.87          }
    6.88 -
    6.89 -        ent[i].type = E820_RESERVED;
    6.90 +        if ( hypercall_memory_op(XENMEM_decrease_reservation, &xmr) != 1 )
    6.91 +            BUG();
    6.92  
    6.93 -        e820_collapse();
    6.94 -
    6.95 -        return addr;
    6.96 +        /* Now try the allocation again. Must not fail. */
    6.97 +        mfn = reserve >> PAGE_SHIFT;
    6.98 +        if ( hypercall_memory_op(XENMEM_populate_physmap, &xmr) != 1 )
    6.99 +            BUG();
   6.100      }
   6.101  
   6.102 -    return 0;
   6.103 +    reserve = e;
   6.104 +
   6.105 +    return (void *)(unsigned long)s;
   6.106  }
   6.107  
   6.108  uint32_t ioapic_read(uint32_t reg)
     7.1 --- a/tools/firmware/hvmloader/util.h	Thu Jan 08 16:53:15 2009 +0000
     7.2 +++ b/tools/firmware/hvmloader/util.h	Thu Jan 08 16:59:21 2009 +0000
     7.3 @@ -131,8 +131,9 @@ void uuid_to_string(char *dest, uint8_t 
     7.4  int printf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
     7.5  int vprintf(const char *fmt, va_list ap);
     7.6  
     7.7 -/* Reserve a RAM region in the e820 table. */
     7.8 -uint32_t e820_malloc(uint32_t size, uint32_t align);
     7.9 +/* Allocate memory in a reserved region below 4GB. */
    7.10 +void *mem_alloc(uint32_t size, uint32_t align);
    7.11 +#define virt_to_phys(v) ((unsigned long)(v))
    7.12  
    7.13  /* Prepare the 32bit BIOS */
    7.14  void highbios_setup(void);