diff options
| -rw-r--r-- | drivers/firmware/efi/fake_mem.c | 229 |
1 files changed, 134 insertions, 95 deletions
diff --git a/drivers/firmware/efi/fake_mem.c b/drivers/firmware/efi/fake_mem.c index 939eec47139f..446c669431c0 100644 --- a/drivers/firmware/efi/fake_mem.c +++ b/drivers/firmware/efi/fake_mem.c | |||
| @@ -54,43 +54,151 @@ static int __init cmp_fake_mem(const void *x1, const void *x2) | |||
| 54 | return 0; | 54 | return 0; |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | /** | ||
| 58 | * efi_fake_memmap_split_count - Count number of additional EFI memmap entries | ||
| 59 | * @md: EFI memory descriptor to split | ||
| 60 | * @range: Address range (start, end) to split around | ||
| 61 | * | ||
| 62 | * Returns the number of additional EFI memmap entries required to | ||
| 63 | * accomodate @range. | ||
| 64 | */ | ||
| 65 | static int efi_fake_memmap_split_count(efi_memory_desc_t *md, struct range *range) | ||
| 66 | { | ||
| 67 | u64 m_start, m_end; | ||
| 68 | u64 start, end; | ||
| 69 | int count = 0; | ||
| 70 | |||
| 71 | start = md->phys_addr; | ||
| 72 | end = start + (md->num_pages << EFI_PAGE_SHIFT) - 1; | ||
| 73 | |||
| 74 | /* modifying range */ | ||
| 75 | m_start = range->start; | ||
| 76 | m_end = range->end; | ||
| 77 | |||
| 78 | if (m_start <= start) { | ||
| 79 | /* split into 2 parts */ | ||
| 80 | if (start < m_end && m_end < end) | ||
| 81 | count++; | ||
| 82 | } | ||
| 83 | |||
| 84 | if (start < m_start && m_start < end) { | ||
| 85 | /* split into 3 parts */ | ||
| 86 | if (m_end < end) | ||
| 87 | count += 2; | ||
| 88 | /* split into 2 parts */ | ||
| 89 | if (end <= m_end) | ||
| 90 | count++; | ||
| 91 | } | ||
| 92 | |||
| 93 | return count; | ||
| 94 | } | ||
| 95 | |||
| 96 | /** | ||
| 97 | * efi_fake_memmap_insert - Insert a fake memory region in an EFI memmap | ||
| 98 | * @old_memmap: The existing EFI memory map structure | ||
| 99 | * @buf: Address of buffer to store new map | ||
| 100 | * @mem: Fake memory map entry to insert | ||
| 101 | * | ||
| 102 | * It is suggested that you call efi_fake_memmap_split_count() first | ||
| 103 | * to see how large @buf needs to be. | ||
| 104 | */ | ||
| 105 | static void efi_fake_memmap_insert(struct efi_memory_map *old_memmap, | ||
| 106 | void *buf, struct fake_mem *mem) | ||
| 107 | { | ||
| 108 | u64 m_start, m_end, m_attr; | ||
| 109 | efi_memory_desc_t *md; | ||
| 110 | u64 start, end; | ||
| 111 | void *old, *new; | ||
| 112 | |||
| 113 | /* modifying range */ | ||
| 114 | m_start = mem->range.start; | ||
| 115 | m_end = mem->range.end; | ||
| 116 | m_attr = mem->attribute; | ||
| 117 | |||
| 118 | for (old = old_memmap->map, new = buf; | ||
| 119 | old < old_memmap->map_end; | ||
| 120 | old += old_memmap->desc_size, new += old_memmap->desc_size) { | ||
| 121 | |||
| 122 | /* copy original EFI memory descriptor */ | ||
| 123 | memcpy(new, old, old_memmap->desc_size); | ||
| 124 | md = new; | ||
| 125 | start = md->phys_addr; | ||
| 126 | end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1; | ||
| 127 | |||
| 128 | if (m_start <= start && end <= m_end) | ||
| 129 | md->attribute |= m_attr; | ||
| 130 | |||
| 131 | if (m_start <= start && | ||
| 132 | (start < m_end && m_end < end)) { | ||
| 133 | /* first part */ | ||
| 134 | md->attribute |= m_attr; | ||
| 135 | md->num_pages = (m_end - md->phys_addr + 1) >> | ||
| 136 | EFI_PAGE_SHIFT; | ||
| 137 | /* latter part */ | ||
| 138 | new += old_memmap->desc_size; | ||
| 139 | memcpy(new, old, old_memmap->desc_size); | ||
| 140 | md = new; | ||
| 141 | md->phys_addr = m_end + 1; | ||
| 142 | md->num_pages = (end - md->phys_addr + 1) >> | ||
| 143 | EFI_PAGE_SHIFT; | ||
| 144 | } | ||
| 145 | |||
| 146 | if ((start < m_start && m_start < end) && m_end < end) { | ||
| 147 | /* first part */ | ||
| 148 | md->num_pages = (m_start - md->phys_addr) >> | ||
| 149 | EFI_PAGE_SHIFT; | ||
| 150 | /* middle part */ | ||
| 151 | new += old_memmap->desc_size; | ||
| 152 | memcpy(new, old, old_memmap->desc_size); | ||
| 153 | md = new; | ||
| 154 | md->attribute |= m_attr; | ||
| 155 | md->phys_addr = m_start; | ||
| 156 | md->num_pages = (m_end - m_start + 1) >> | ||
| 157 | EFI_PAGE_SHIFT; | ||
| 158 | /* last part */ | ||
| 159 | new += old_memmap->desc_size; | ||
| 160 | memcpy(new, old, old_memmap->desc_size); | ||
| 161 | md = new; | ||
| 162 | md->phys_addr = m_end + 1; | ||
| 163 | md->num_pages = (end - m_end) >> | ||
| 164 | EFI_PAGE_SHIFT; | ||
| 165 | } | ||
| 166 | |||
| 167 | if ((start < m_start && m_start < end) && | ||
| 168 | (end <= m_end)) { | ||
| 169 | /* first part */ | ||
| 170 | md->num_pages = (m_start - md->phys_addr) >> | ||
| 171 | EFI_PAGE_SHIFT; | ||
| 172 | /* latter part */ | ||
| 173 | new += old_memmap->desc_size; | ||
| 174 | memcpy(new, old, old_memmap->desc_size); | ||
| 175 | md = new; | ||
| 176 | md->phys_addr = m_start; | ||
| 177 | md->num_pages = (end - md->phys_addr + 1) >> | ||
| 178 | EFI_PAGE_SHIFT; | ||
| 179 | md->attribute |= m_attr; | ||
| 180 | } | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 57 | void __init efi_fake_memmap(void) | 184 | void __init efi_fake_memmap(void) |
| 58 | { | 185 | { |
| 59 | u64 start, end, m_start, m_end, m_attr; | ||
| 60 | struct efi_memory_map_data data; | 186 | struct efi_memory_map_data data; |
| 61 | int new_nr_map = efi.memmap.nr_map; | 187 | int new_nr_map = efi.memmap.nr_map; |
| 62 | efi_memory_desc_t *md; | 188 | efi_memory_desc_t *md; |
| 63 | phys_addr_t new_memmap_phy; | 189 | phys_addr_t new_memmap_phy; |
| 64 | void *new_memmap; | 190 | void *new_memmap; |
| 65 | void *old, *new; | ||
| 66 | int i; | 191 | int i; |
| 67 | 192 | ||
| 68 | if (!nr_fake_mem) | 193 | if (!nr_fake_mem) |
| 69 | return; | 194 | return; |
| 70 | 195 | ||
| 71 | /* count up the number of EFI memory descriptor */ | 196 | /* count up the number of EFI memory descriptor */ |
| 72 | for_each_efi_memory_desc(md) { | 197 | for (i = 0; i < nr_fake_mem; i++) { |
| 73 | start = md->phys_addr; | 198 | for_each_efi_memory_desc(md) { |
| 74 | end = start + (md->num_pages << EFI_PAGE_SHIFT) - 1; | 199 | struct range *r = &fake_mems[i].range; |
| 75 | 200 | ||
| 76 | for (i = 0; i < nr_fake_mem; i++) { | 201 | new_nr_map += efi_fake_memmap_split_count(md, r); |
| 77 | /* modifying range */ | ||
| 78 | m_start = fake_mems[i].range.start; | ||
| 79 | m_end = fake_mems[i].range.end; | ||
| 80 | |||
| 81 | if (m_start <= start) { | ||
| 82 | /* split into 2 parts */ | ||
| 83 | if (start < m_end && m_end < end) | ||
| 84 | new_nr_map++; | ||
| 85 | } | ||
| 86 | if (start < m_start && m_start < end) { | ||
| 87 | /* split into 3 parts */ | ||
| 88 | if (m_end < end) | ||
| 89 | new_nr_map += 2; | ||
| 90 | /* split into 2 parts */ | ||
| 91 | if (end <= m_end) | ||
| 92 | new_nr_map++; | ||
| 93 | } | ||
| 94 | } | 202 | } |
| 95 | } | 203 | } |
| 96 | 204 | ||
| @@ -108,77 +216,8 @@ void __init efi_fake_memmap(void) | |||
| 108 | return; | 216 | return; |
| 109 | } | 217 | } |
| 110 | 218 | ||
| 111 | for (old = efi.memmap.map, new = new_memmap; | 219 | for (i = 0; i < nr_fake_mem; i++) |
| 112 | old < efi.memmap.map_end; | 220 | efi_fake_memmap_insert(&efi.memmap, new_memmap, &fake_mems[i]); |
| 113 | old += efi.memmap.desc_size, new += efi.memmap.desc_size) { | ||
| 114 | |||
| 115 | /* copy original EFI memory descriptor */ | ||
| 116 | memcpy(new, old, efi.memmap.desc_size); | ||
| 117 | md = new; | ||
| 118 | start = md->phys_addr; | ||
| 119 | end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1; | ||
| 120 | |||
| 121 | for (i = 0; i < nr_fake_mem; i++) { | ||
| 122 | /* modifying range */ | ||
| 123 | m_start = fake_mems[i].range.start; | ||
| 124 | m_end = fake_mems[i].range.end; | ||
| 125 | m_attr = fake_mems[i].attribute; | ||
| 126 | |||
| 127 | if (m_start <= start && end <= m_end) | ||
| 128 | md->attribute |= m_attr; | ||
| 129 | |||
| 130 | if (m_start <= start && | ||
| 131 | (start < m_end && m_end < end)) { | ||
| 132 | /* first part */ | ||
| 133 | md->attribute |= m_attr; | ||
| 134 | md->num_pages = (m_end - md->phys_addr + 1) >> | ||
| 135 | EFI_PAGE_SHIFT; | ||
| 136 | /* latter part */ | ||
| 137 | new += efi.memmap.desc_size; | ||
| 138 | memcpy(new, old, efi.memmap.desc_size); | ||
| 139 | md = new; | ||
| 140 | md->phys_addr = m_end + 1; | ||
| 141 | md->num_pages = (end - md->phys_addr + 1) >> | ||
| 142 | EFI_PAGE_SHIFT; | ||
| 143 | } | ||
| 144 | |||
| 145 | if ((start < m_start && m_start < end) && m_end < end) { | ||
| 146 | /* first part */ | ||
| 147 | md->num_pages = (m_start - md->phys_addr) >> | ||
| 148 | EFI_PAGE_SHIFT; | ||
| 149 | /* middle part */ | ||
| 150 | new += efi.memmap.desc_size; | ||
| 151 | memcpy(new, old, efi.memmap.desc_size); | ||
| 152 | md = new; | ||
| 153 | md->attribute |= m_attr; | ||
| 154 | md->phys_addr = m_start; | ||
| 155 | md->num_pages = (m_end - m_start + 1) >> | ||
| 156 | EFI_PAGE_SHIFT; | ||
| 157 | /* last part */ | ||
| 158 | new += efi.memmap.desc_size; | ||
| 159 | memcpy(new, old, efi.memmap.desc_size); | ||
| 160 | md = new; | ||
| 161 | md->phys_addr = m_end + 1; | ||
| 162 | md->num_pages = (end - m_end) >> | ||
| 163 | EFI_PAGE_SHIFT; | ||
| 164 | } | ||
| 165 | |||
| 166 | if ((start < m_start && m_start < end) && | ||
| 167 | (end <= m_end)) { | ||
| 168 | /* first part */ | ||
| 169 | md->num_pages = (m_start - md->phys_addr) >> | ||
| 170 | EFI_PAGE_SHIFT; | ||
| 171 | /* latter part */ | ||
| 172 | new += efi.memmap.desc_size; | ||
| 173 | memcpy(new, old, efi.memmap.desc_size); | ||
| 174 | md = new; | ||
| 175 | md->phys_addr = m_start; | ||
| 176 | md->num_pages = (end - md->phys_addr + 1) >> | ||
| 177 | EFI_PAGE_SHIFT; | ||
| 178 | md->attribute |= m_attr; | ||
| 179 | } | ||
| 180 | } | ||
| 181 | } | ||
| 182 | 221 | ||
| 183 | /* swap into new EFI memmap */ | 222 | /* swap into new EFI memmap */ |
| 184 | early_memunmap(new_memmap, efi.memmap.desc_size * new_nr_map); | 223 | early_memunmap(new_memmap, efi.memmap.desc_size * new_nr_map); |
