1 /* 2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 29 /* 30 * MD primitives supporting placement of module data 31 * 32 * XXX should check load address/size against memory top. 33 */ 34 #include <stand.h> 35 #include <sys/param.h> 36 #include <sys/multiboot2.h> 37 #include <sys/consplat.h> 38 #include <machine/metadata.h> 39 #include <machine/pc/bios.h> 40 #include "libi386.h" 41 #include "btxv86.h" 42 #include "bootstrap.h" 43 44 extern multiboot_tag_framebuffer_t gfx_fb; 45 46 /* 47 * Verify the address is not in use by existing modules. 48 */ 49 static vm_offset_t 50 addr_verify(struct preloaded_file *fp, vm_offset_t addr, size_t size) 51 { 52 vm_offset_t f_addr; 53 54 while (fp != NULL) { 55 f_addr = fp->f_addr; 56 57 if ((f_addr <= addr) && 58 (f_addr + fp->f_size >= addr)) { 59 return (0); 60 } 61 if ((f_addr >= addr) && (f_addr <= addr + size)) { 62 return (0); 63 } 64 fp = fp->f_next; 65 } 66 return (addr); 67 } 68 69 /* 70 * Find smap entry above 1MB, able to contain size bytes from addr. 71 */ 72 static vm_offset_t 73 smap_find(struct bios_smap *smap, int smaplen, vm_offset_t addr, size_t size) 74 { 75 int i; 76 77 for (i = 0; i < smaplen; i++) { 78 if (smap[i].type != SMAP_TYPE_MEMORY) 79 continue; 80 81 /* We do not want address below 1MB. */ 82 if (smap[i].base < 0x100000) 83 continue; 84 85 /* Do we fit into current entry? */ 86 if ((smap[i].base <= addr) && 87 (smap[i].base + smap[i].length >= addr + size)) { 88 return (addr); 89 } 90 91 /* Do we fit into new entry? */ 92 if ((smap[i].base > addr) && (smap[i].length >= size)) { 93 return (smap[i].base); 94 } 95 } 96 return (0); 97 } 98 99 /* 100 * Find usable address for loading. The address for the kernel is fixed, as 101 * it is determined by kernel linker map (dboot PT_LOAD address). 102 * For modules, we need to consult smap, the module address has to be 103 * aligned to page boundary and we have to fit into smap entry. 104 */ 105 vm_offset_t 106 i386_loadaddr(uint_t type, void *data, vm_offset_t addr) 107 { 108 struct stat st; 109 size_t size, smaplen; 110 struct preloaded_file *fp, *mfp; 111 struct file_metadata *md; 112 struct bios_smap *smap; 113 vm_offset_t off; 114 115 /* 116 * For now, assume we have memory for the kernel, the 117 * required map is [1MB..) This assumption should be safe with x86 BIOS. 118 */ 119 if (type == LOAD_KERN) 120 return (addr); 121 122 if (addr == 0) 123 return (addr); /* nothing to do */ 124 125 if (type == LOAD_ELF) 126 return (0); /* not supported */ 127 128 if (type == LOAD_MEM) { 129 size = *(size_t *)data; 130 } else { 131 stat(data, &st); 132 size = st.st_size; 133 } 134 135 /* 136 * Find our kernel, from it we will find the smap and the list of 137 * loaded modules. 138 */ 139 fp = file_findfile(NULL, NULL); 140 if (fp == NULL) 141 return (0); 142 md = file_findmetadata(fp, MODINFOMD_SMAP); 143 if (md == NULL) 144 return (0); 145 146 smap = (struct bios_smap *)md->md_data; 147 smaplen = md->md_size / sizeof (struct bios_smap); 148 149 /* Start from the end of the kernel. */ 150 mfp = fp; 151 do { 152 if (mfp == NULL) { 153 off = roundup2(addr + 1, MULTIBOOT_MOD_ALIGN); 154 } else { 155 off = roundup2(mfp->f_addr + mfp->f_size + 1, 156 MULTIBOOT_MOD_ALIGN); 157 } 158 /* Avoid possible framebuffer memory */ 159 if (plat_stdout_is_framebuffer()) { 160 vm_offset_t fb_addr; 161 size_t fb_size; 162 163 fb_addr = gfx_fb.framebuffer_common.framebuffer_addr; 164 fb_size = gfx_fb.framebuffer_common.framebuffer_height * 165 gfx_fb.framebuffer_common.framebuffer_pitch; 166 167 if ((off >= fb_addr && off <= fb_addr + fb_size) || 168 (off + size >= fb_addr && 169 off + size <= fb_addr + fb_size)) { 170 printf("\nSkipping framebuffer memory %#x " 171 "size %#x\n", fb_addr, fb_size); 172 off = roundup2(fb_addr + fb_size + 1, 173 MULTIBOOT_MOD_ALIGN); 174 } 175 } 176 off = smap_find(smap, smaplen, off, size); 177 off = addr_verify(fp, off, size); 178 if (off != 0) 179 break; 180 181 if (mfp == NULL) 182 break; 183 mfp = mfp->f_next; 184 } while (off == 0); 185 186 return (off); 187 } 188 189 ssize_t 190 i386_copyin(const void *src, vm_offset_t dest, const size_t len) 191 { 192 if (dest + len >= memtop) { 193 errno = EFBIG; 194 return (-1); 195 } 196 197 bcopy(src, PTOV(dest), len); 198 return (len); 199 } 200 201 ssize_t 202 i386_copyout(const vm_offset_t src, void *dest, const size_t len) 203 { 204 if (src + len >= memtop) { 205 errno = EFBIG; 206 return (-1); 207 } 208 209 bcopy(PTOV(src), dest, len); 210 return (len); 211 } 212 213 214 ssize_t 215 i386_readin(const int fd, vm_offset_t dest, const size_t len) 216 { 217 if (dest + len >= memtop_copyin) { 218 errno = EFBIG; 219 return (-1); 220 } 221 222 return (read(fd, PTOV(dest), len)); 223 } 224