]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
First part of virtual addr support in relocator
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Wed, 21 Apr 2010 13:25:49 +0000 (15:25 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Wed, 21 Apr 2010 13:25:49 +0000 (15:25 +0200)
include/grub/i386/memory.h
include/grub/relocator_private.h
lib/i386/relocator.c
lib/relocator.c

index fe2f6e4e1e14d6f270f84a9b600ce952f557559a..4f9a3c916409b892ace1a448152deeb999ef8e04 100644 (file)
 #define GRUB_MEMORY_CPU_AMD64_MSR              0xc0000080
 #define GRUB_MEMORY_CPU_AMD64_MSR_ON           0x00000100
 
+#ifndef ASM_FILE
+
+typedef grub_addr_t grub_phys_addr_t;
+
+static inline grub_phys_addr_t
+grub_vtop (void *a)
+{
+  return (grub_phys_addr_t) a;
+}
+
+static inline void *
+grub_map_memory (grub_phys_addr_t a, grub_size_t size __attribute__ ((unused)))
+{
+  return (void *) a;
+}
+
+static inline void
+grub_unmap_memory (void *a __attribute__ ((unused)),
+                  grub_size_t size __attribute__ ((unused)))
+{
+}
+
+#endif
+
 #endif /* ! GRUB_MEMORY_CPU_HEADER */
index a859ec9fd53b8873f194a35f74960a75013d6d65..d12a0f05a433eb76103ae4f3043de7440ad3ba23 100644 (file)
@@ -31,8 +31,9 @@ extern grub_size_t grub_relocator_jumper_size;
 void
 grub_cpu_relocator_init (void);
 grub_err_t
-grub_relocator_prepare_relocs (struct grub_relocator *rel, grub_addr_t addr,
-                              grub_addr_t *relstart, grub_size_t *relsize);
+grub_relocator_prepare_relocs (struct grub_relocator *rel,
+                              void *addr,
+                              void **relstart, grub_size_t *relsize);
 void grub_cpu_relocator_forward (void *rels, void *src, void *tgt,
                                 grub_size_t size);
 void grub_cpu_relocator_backward (void *rels, void *src, void *tgt,
@@ -72,7 +73,7 @@ struct grub_relocator_mmap_event
     COLLISION_START = 10,
     COLLISION_END = COLLISION_START | 1
   } type;
-  grub_addr_t pos;
+  grub_phys_addr_t pos;
   union
   {
     struct
@@ -91,10 +92,12 @@ struct grub_relocator_mmap_event
 /* Return 0 on failure, 1 on success. The failure here 
    can be very time-expensive, so please make sure fill events is accurate.  */
 #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
-int grub_relocator_firmware_alloc_region (grub_addr_t start, grub_size_t size);
+int grub_relocator_firmware_alloc_region (grub_phys_addr_t start,
+                                         grub_size_t size);
 unsigned grub_relocator_firmware_fill_events (struct grub_relocator_mmap_event *events);
 unsigned grub_relocator_firmware_get_max_events (void);
-void grub_relocator_firmware_free_region (grub_addr_t start, grub_size_t size);
+void grub_relocator_firmware_free_region (grub_phys_addr_t start,
+                                         grub_size_t size);
 #endif
 
 #endif
index 5985fac7aefad162fc5f17aa2f43cc3c43dd7b0d..5dd4cde75c4d721dd53819e789cbe8dc00e3b1fd 100644 (file)
@@ -84,6 +84,12 @@ grub_size_t grub_relocator_jumper_size = 12;
 grub_size_t grub_relocator_jumper_size = 7;
 #endif
 
+static inline void *
+ptov (grub_addr_t a)
+{
+  return (void *) a;
+}
+
 void
 grub_cpu_relocator_init (void)
 {
@@ -148,10 +154,10 @@ grub_err_t
 grub_relocator32_boot (struct grub_relocator *rel,
                       struct grub_relocator32_state state)
 {
-  grub_addr_t target;
+  grub_phys_addr_t target;
   void *src;
   grub_err_t err;
-  grub_addr_t relst;
+  void *relst;
 
   err = grub_relocator_alloc_chunk_align (rel, &src, &target, 0,
                                          (0xffffffff - RELOCATOR_SIZEOF (32))
@@ -170,7 +176,7 @@ grub_relocator32_boot (struct grub_relocator *rel,
 
   grub_memmove (src, &grub_relocator32_start, RELOCATOR_SIZEOF (32));
 
-  err = grub_relocator_prepare_relocs (rel, target, &relst, NULL);
+  err = grub_relocator_prepare_relocs (rel, ptov (target), &relst, NULL);
   if (err)
     return err;
 
@@ -185,10 +191,10 @@ grub_err_t
 grub_relocator16_boot (struct grub_relocator *rel,
                       struct grub_relocator16_state state)
 {
-  grub_addr_t target;
+  grub_phys_addr_t target;
   void *src;
   grub_err_t err;
-  grub_addr_t relst;
+  void *relst;
 
   err = grub_relocator_alloc_chunk_align (rel, &src, &target, 0,
                                          0xa0000 - RELOCATOR_SIZEOF (16),
@@ -212,7 +218,7 @@ grub_relocator16_boot (struct grub_relocator *rel,
 
   grub_memmove (src, &grub_relocator16_start, RELOCATOR_SIZEOF (16));
 
-  err = grub_relocator_prepare_relocs (rel, target, &relst, NULL);
+  err = grub_relocator_prepare_relocs (rel, ptov (target), &relst, NULL);
   if (err)
     return err;
 
@@ -228,10 +234,10 @@ grub_relocator64_boot (struct grub_relocator *rel,
                       struct grub_relocator64_state state,
                       grub_addr_t min_addr, grub_addr_t max_addr)
 {
-  grub_addr_t target;
+  grub_phys_addr_t target;
   void *src;
   grub_err_t err;
-  grub_addr_t relst;
+  void *relst;
 
   err = grub_relocator_alloc_chunk_align (rel, &src, &target, min_addr,
                                          max_addr - RELOCATOR_SIZEOF (64),
@@ -251,7 +257,7 @@ grub_relocator64_boot (struct grub_relocator *rel,
 
   grub_memmove (src, &grub_relocator64_start, RELOCATOR_SIZEOF (64));
 
-  err = grub_relocator_prepare_relocs (rel, target, &relst, NULL);
+  err = grub_relocator_prepare_relocs (rel, ptov (target), &relst, NULL);
   if (err)
     return err;
 
index 127b805334e68e44847137f9bc2b56988e05ac88..b559d12eabec062752a8969ba3a145e9f6c09bc4 100644 (file)
@@ -26,9 +26,9 @@
 struct grub_relocator
 {
   struct grub_relocator_chunk *chunks;
-  grub_addr_t postchunks;
-  grub_addr_t highestaddr;
-  grub_addr_t highestnonpostaddr;
+  grub_phys_addr_t postchunks;
+  grub_phys_addr_t highestaddr;
+  grub_phys_addr_t highestnonpostaddr;
   grub_size_t relocators_size;
 };
 
@@ -39,9 +39,11 @@ struct grub_relocator_subchunk
        CHUNK_TYPE_FIRMWARE, CHUNK_TYPE_LEFTOVER
 #endif
   } type;
-  grub_addr_t host_start;
-  grub_addr_t start;
+  grub_mm_region_t reg;
+  grub_mm_header_t head;
+  grub_phys_addr_t start;
   grub_size_t size;
+  grub_size_t pre_size;
   struct grub_relocator_extra_block *extra;
   struct grub_relocator_fw_leftover *pre, *post;
 };
@@ -49,8 +51,9 @@ struct grub_relocator_subchunk
 struct grub_relocator_chunk
 {
   struct grub_relocator_chunk *next;
-  grub_addr_t src;
-  grub_addr_t target;
+  grub_phys_addr_t src;
+  void *srcv;
+  grub_phys_addr_t target;
   grub_size_t size;
   struct grub_relocator_subchunk *subchunks;
   unsigned nsubchunks;
@@ -60,8 +63,8 @@ struct grub_relocator_extra_block
 {
   struct grub_relocator_extra_block *next;
   struct grub_relocator_extra_block **prev;
-  grub_addr_t start;
-  grub_addr_t end;
+  grub_phys_addr_t start;
+  grub_phys_addr_t end;
 };
 
 #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
@@ -69,7 +72,7 @@ struct grub_relocator_fw_leftover
 {
   struct grub_relocator_fw_leftover *next;
   struct grub_relocator_fw_leftover **prev;
-  grub_addr_t quantstart;
+  grub_phys_addr_t quantstart;
   grub_uint8_t freebytes[GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT / 8];
 };
 
@@ -89,7 +92,7 @@ grub_relocator_new (void)
   if (!ret)
     return NULL;
     
-  ret->postchunks = ~(grub_addr_t) 0;
+  ret->postchunks = ~(grub_phys_addr_t) 0;
   ret->relocators_size = grub_relocator_jumper_size;
   grub_dprintf ("relocator", "relocators_size=%lu\n",
                (unsigned long) ret->relocators_size);
@@ -110,10 +113,11 @@ is_start (int type)
 }
 
 static void
-allocate_regstart (grub_addr_t addr, grub_size_t size, grub_mm_region_t rb,
+allocate_regstart (grub_phys_addr_t addr, grub_size_t size, grub_mm_region_t rb,
                   grub_mm_region_t *regancestor, grub_mm_header_t hancestor)
 {
-  grub_addr_t newreg_start, newreg_raw_start = addr + size;
+  grub_addr_t newreg_start, newreg_raw_start
+    = (grub_addr_t) rb + (addr - grub_vtop (rb)) + size;
   grub_addr_t newreg_size, newreg_presize;
   grub_mm_header_t new_header;
   grub_mm_header_t hb = (grub_mm_header_t) (rb + 1);
@@ -176,23 +180,24 @@ allocate_regstart (grub_addr_t addr, grub_size_t size, grub_mm_region_t rb,
 }
 
 static void
-allocate_inreg (grub_addr_t addr, grub_size_t size,
+allocate_inreg (grub_phys_addr_t paddr, grub_size_t size,
                grub_mm_header_t hb, grub_mm_header_t hbp,
                grub_mm_region_t rb)
 {
   struct grub_mm_header *foll = NULL;
+  grub_addr_t vaddr = (grub_addr_t) hb + (paddr - grub_vtop (hb));
     
-  if (ALIGN_UP (addr + size, GRUB_MM_ALIGN) + GRUB_MM_ALIGN
+  if (ALIGN_UP (vaddr + size, GRUB_MM_ALIGN) + GRUB_MM_ALIGN
       <= (grub_addr_t) (hb + hb->size))
     {
-      foll = (void *) ALIGN_UP (addr + size, GRUB_MM_ALIGN);
+      foll = (void *) ALIGN_UP (vaddr + size, GRUB_MM_ALIGN);
       foll->magic = GRUB_MM_FREE_MAGIC;
       foll->size = hb->size - (foll - hb);
     }
 
-  if (addr - (grub_addr_t) hb >= sizeof (*hb))
+  if (vaddr - (grub_addr_t) hb >= sizeof (*hb))
     {
-      hb->size = ((addr - (grub_addr_t) hb) >> GRUB_MM_ALIGN_LOG2);
+      hb->size = ((vaddr - (grub_addr_t) hb) >> GRUB_MM_ALIGN_LOG2);
       if (foll)
        {
          foll->next = hb;
@@ -250,12 +255,13 @@ free_subchunk (const struct grub_relocator_subchunk *subchu)
        grub_mm_region_t r1, r2, *rp;
        grub_mm_header_t h;
        grub_size_t pre_size;
-       r1 = (grub_mm_region_t) ALIGN_UP (subchu->host_start, GRUB_MM_ALIGN);
-       r2 = (grub_mm_region_t) ALIGN_UP (subchu->start + subchu->size,
+       r1 = subchu->reg;
+       r2 = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) subchu->reg
+                                         + (grub_vtop (subchu->reg)
+                                            - subchu->start) + subchu->size,
                                          GRUB_MM_ALIGN);
        for (rp = &grub_mm_base; *rp && *rp != r2; rp = &((*rp)->next));
-       pre_size = ALIGN_UP (subchu->host_start, GRUB_MM_ALIGN)
-         - subchu->host_start;
+       pre_size = subchu->pre_size;
 
        if (*rp)
          {
@@ -328,7 +334,7 @@ free_subchunk (const struct grub_relocator_subchunk *subchu)
       }
     case CHUNK_TYPE_IN_REGION:
       {
-       grub_mm_header_t h = (grub_mm_header_t) ALIGN_DOWN (subchu->start,
+       grub_mm_header_t h = (grub_mm_header_t) ALIGN_DOWN ((grub_addr_t) subchu->head,
                                                            GRUB_MM_ALIGN);
        h->size
          = ((subchu->start + subchu->size + GRUB_MM_ALIGN - 1) / GRUB_MM_ALIGN)
@@ -549,26 +555,26 @@ malloc_in_range (struct grub_relocator *rel,
            {
              pre_added = 1;
              events[N].type = REG_BEG_START;
-             events[N].pos = (grub_addr_t) r - r->pre_size;
+             events[N].pos = grub_vtop (r) - r->pre_size;
              events[N].reg = r;
              events[N].regancestor = ra;
              events[N].head = p;
              events[N].hancestor = pa;
              N++;
              events[N].type = REG_BEG_END;
-             events[N].pos = (grub_addr_t) (p + p->size) - sizeof (*r);
+             events[N].pos = grub_vtop (p + p->size) - sizeof (*r);
              N++;
            }
          else
            {
              events[N].type = IN_REG_START;
-             events[N].pos = (grub_addr_t) p;
+             events[N].pos = grub_vtop (p);
              events[N].head = p;
              events[N].hancestor = pa;
              events[N].reg = r;
              N++;
              events[N].type = IN_REG_END;
-             events[N].pos = (grub_addr_t) (p + p->size);
+             events[N].pos = grub_vtop (p + p->size);
              N++;
            }
          pa = p;
@@ -862,20 +868,6 @@ malloc_in_range (struct grub_relocator *rel,
       }
   }
 
-  grub_memset ((void *) target, 0, size);
-  grub_dprintf ("relocator", "baseptr = %p\n", &base_saved);
-  for (r = base_saved; r; r = r->next)
-    {
-      p = r->first;
-      do
-       {
-         if (!p)
-           grub_fatal ("null in the ring %p\n", r);
-         p = p->next;
-       }
-      while (p != r->first);
-    }
-
   /* Malloc is available again.  */
   grub_mm_base = base_saved;
 
@@ -927,7 +919,13 @@ malloc_in_range (struct grub_relocator *rel,
                curschu->type = typepre;
                curschu->start = alloc_start;
                curschu->size = alloc_end - alloc_start;
-               if (typepre == CHUNK_TYPE_REGION_START)
+               if (typepre == CHUNK_TYPE_REGION_START
+                   || typepre == CHUNK_TYPE_IN_REGION)
+                 {
+                   curschu->reg = events[last_start].reg;
+                   curschu->head = events[last_start].head;
+                   curschu->pre_size = alloc_start - events[j - 1].pos;
+                 }
                if (!oom && (typepre == CHUNK_TYPE_REGION_START
 #if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS
                             || typepre == CHUNK_TYPE_FIRMWARE
@@ -1106,8 +1104,8 @@ malloc_in_range (struct grub_relocator *rel,
 
 static void
 adjust_limits (struct grub_relocator *rel, 
-              grub_addr_t *min_addr, grub_addr_t *max_addr,
-              grub_addr_t in_min, grub_addr_t in_max)
+              grub_phys_addr_t *min_addr, grub_phys_addr_t *max_addr,
+              grub_phys_addr_t in_min, grub_phys_addr_t in_max)
 {
   struct grub_relocator_chunk *chunk;
 
@@ -1129,10 +1127,10 @@ adjust_limits (struct grub_relocator *rel,
 
 grub_err_t
 grub_relocator_alloc_chunk_addr (struct grub_relocator *rel, void **src,
-                                grub_addr_t target, grub_size_t size)
+                                grub_phys_addr_t target, grub_size_t size)
 {
   struct grub_relocator_chunk *chunk;
-  grub_addr_t min_addr = 0, max_addr;
+  grub_phys_addr_t min_addr = 0, max_addr;
 
   if (target > ~size)
     return grub_error (GRUB_ERR_OUT_OF_RANGE, "address is out of range");
@@ -1223,14 +1221,15 @@ grub_relocator_alloc_chunk_addr (struct grub_relocator *rel, void **src,
   grub_dprintf ("relocator", "cur = %p, next = %p\n", rel->chunks,
                rel->chunks->next);
 
-  *src = (void *) chunk->src;
+  *src = chunk->srcv = grub_map_memory (chunk->src, chunk->size);
   return GRUB_ERR_NONE;
 }
 
 grub_err_t
 grub_relocator_alloc_chunk_align (struct grub_relocator *rel, void **src,
-                                 grub_addr_t *target,
-                                 grub_addr_t min_addr, grub_addr_t max_addr,
+                                 grub_phys_addr_t *target,
+                                 grub_phys_addr_t min_addr,
+                                 grub_phys_addr_t max_addr,
                                  grub_size_t size, grub_size_t align,
                                  int preference)
 {
@@ -1354,7 +1353,7 @@ grub_relocator_alloc_chunk_align (struct grub_relocator *rel, void **src,
   rel->chunks = chunk;
   grub_dprintf ("relocator", "cur = %p, next = %p\n", rel->chunks,
                rel->chunks->next);
-  *src = (void *) chunk->src;
+  *src = chunk->srcv = grub_map_memory (chunk->src, chunk->size);
   *target = chunk->target;
   return GRUB_ERR_NONE;
 }
@@ -1370,6 +1369,7 @@ grub_relocator_unload (struct grub_relocator *rel)
       unsigned i;
       for (i = 0; i < chunk->nsubchunks; i++) 
        free_subchunk (&chunk->subchunks[i]);
+      grub_unmap_memory (chunk->srcv, chunk->size);
       next = chunk->next;
       grub_free (chunk->subchunks);
       grub_free (chunk);
@@ -1378,11 +1378,11 @@ grub_relocator_unload (struct grub_relocator *rel)
 }
 
 grub_err_t
-grub_relocator_prepare_relocs (struct grub_relocator *rel, grub_addr_t addr,
-                              grub_addr_t *relstart, grub_size_t *relsize)
+grub_relocator_prepare_relocs (struct grub_relocator *rel, void *addr,
+                              void **relstart, grub_size_t *relsize)
 {
-  grub_addr_t rels;
-  grub_addr_t rels0;
+  grub_uint8_t *rels;
+  grub_uint8_t *rels0;
   struct grub_relocator_chunk *sorted;
   grub_size_t nchunks = 0;
   unsigned j;
@@ -1395,7 +1395,7 @@ grub_relocator_prepare_relocs (struct grub_relocator *rel, grub_addr_t addr,
                        grub_relocator_align,
                        rel->relocators_size, &movers_chunk, 1, 1))
     return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
-  rels = rels0 = movers_chunk.src;
+  rels = rels0 = movers_chunk.srcv;
 
   if (relsize)
     *relsize = rel->relocators_size;
@@ -1463,23 +1463,25 @@ grub_relocator_prepare_relocs (struct grub_relocator *rel, grub_addr_t addr,
       if (sorted[j].src < sorted[j].target)
        {
          grub_cpu_relocator_backward ((void *) rels,
-                                      (void *) sorted[j].src,
-                                      (void *) sorted[j].target,
+                                      sorted[j].srcv,
+                                      grub_map_memory (sorted[j].target,
+                                                       sorted[j].size),
                                       sorted[j].size);
          rels += grub_relocator_backward_size;
        }
       if (sorted[j].src > sorted[j].target)
        {
          grub_cpu_relocator_forward ((void *) rels,
-                                     (void *) sorted[j].src,
-                                     (void *) sorted[j].target,
+                                     sorted[j].srcv,
+                                     grub_map_memory (sorted[j].target,
+                                                      sorted[j].size),
                                      sorted[j].size);
          rels += grub_relocator_forward_size;
        }
       if (sorted[j].src == sorted[j].target)
-       grub_arch_sync_caches ((void *) sorted[j].src, sorted[j].size);
+       grub_arch_sync_caches (sorted[j].srcv, sorted[j].size);
     }
-  grub_cpu_relocator_jumper ((void *) rels, addr);
+  grub_cpu_relocator_jumper ((void *) rels, (grub_addr_t) addr);
   *relstart = rels0;
   grub_free (sorted);
   return GRUB_ERR_NONE;