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 <machine/metadata.h> 38 #include <machine/pc/bios.h> 39 #include "libi386.h" 40 #include "btxv86.h" 41 #include "bootstrap.h" 42 43 /* 44 * Verify the address is not in use by existing modules. 45 */ 46 static vm_offset_t 47 addr_verify(struct preloaded_file *fp, vm_offset_t addr, size_t size) 48 { 49 vm_offset_t f_addr; 50 51 while (fp != NULL) { 52 f_addr = fp->f_addr; 53 54 if ((f_addr <= addr) && 55 (f_addr + fp->f_size >= addr)) { 56 return (0); 57 } 58 if ((f_addr >= addr) && (f_addr <= addr + size)) { 59 return (0); 60 } 61 fp = fp->f_next; 62 } 63 return (addr); 64 } 65 66 /* 67 * Find smap entry above 1MB, able to contain size bytes from addr. 68 */ 69 static vm_offset_t 70 smap_find(struct bios_smap *smap, int smaplen, vm_offset_t addr, size_t size) 71 { 72 int i; 73 74 for (i = 0; i < smaplen; i++) { 75 if (smap[i].type != SMAP_TYPE_MEMORY) 76 continue; 77 78 /* We do not want address below 1MB. */ 79 if (smap[i].base < 0x100000) 80 continue; 81 82 /* Do we fit into current entry? */ 83 if ((smap[i].base <= addr) && 84 (smap[i].base + smap[i].length >= addr + size)) { 85 return (addr); 86 } 87 88 /* Do we fit into new entry? */ 89 if ((smap[i].base > addr) && (smap[i].length >= size)) { 90 return (smap[i].base); 91 } 92 } 93 return (0); 94 } 95 96 /* 97 * Find usable address for loading. The address for the kernel is fixed, as 98 * it is determined by kernel linker map (dboot PT_LOAD address). 99 * For modules, we need to consult smap, the module address has to be 100 * aligned to page boundary and we have to fit into smap entry. 101 */ 102 vm_offset_t 103 i386_loadaddr(u_int type, void *data, vm_offset_t addr) 104 { 105 struct stat st; 106 size_t size, smaplen; 107 struct preloaded_file *fp, *mfp; 108 struct file_metadata *md; 109 struct bios_smap *smap; 110 vm_offset_t off; 111 112 /* 113 * For now, assume we have memory for the kernel, the 114 * required map is [1MB..) This assumption should be safe with x86 BIOS. 115 */ 116 if (type == LOAD_KERN) 117 return (addr); 118 119 if (addr == 0) 120 return (addr); /* nothing to do */ 121 122 if (type == LOAD_ELF) 123 return (0); /* not supported */ 124 125 if (type == LOAD_MEM) { 126 size = *(size_t *)data; 127 } else { 128 stat(data, &st); 129 size = st.st_size; 130 } 131 132 /* 133 * Find our kernel, from it we will find the smap and the list of 134 * loaded modules. 135 */ 136 fp = file_findfile(NULL, NULL); 137 if (fp == NULL) 138 return (0); 139 md = file_findmetadata(fp, MODINFOMD_SMAP); 140 if (md == NULL) 141 return (0); 142 143 smap = (struct bios_smap *)md->md_data; 144 smaplen = md->md_size / sizeof(struct bios_smap); 145 146 /* Start from the end of the kernel. */ 147 mfp = fp; 148 do { 149 if (mfp == NULL) { 150 off = roundup2(addr + 1, MULTIBOOT_MOD_ALIGN); 151 } else { 152 off = roundup2(mfp->f_addr + mfp->f_size + 1, 153 MULTIBOOT_MOD_ALIGN); 154 } 155 off = smap_find(smap, smaplen, off, size); 156 off = addr_verify(fp, off, size); 157 if (off != 0) 158 break; 159 160 if (mfp == NULL) 161 break; 162 mfp = mfp->f_next; 163 } while (off == 0); 164 165 return (off); 166 } 167 168 ssize_t 169 i386_copyin(const void *src, vm_offset_t dest, const size_t len) 170 { 171 if (dest + len >= memtop) { 172 errno = EFBIG; 173 return (-1); 174 } 175 176 bcopy(src, PTOV(dest), len); 177 return (len); 178 } 179 180 ssize_t 181 i386_copyout(const vm_offset_t src, void *dest, const size_t len) 182 { 183 if (src + len >= memtop) { 184 errno = EFBIG; 185 return (-1); 186 } 187 188 bcopy(PTOV(src), dest, len); 189 return (len); 190 } 191 192 193 ssize_t 194 i386_readin(const int fd, vm_offset_t dest, const size_t len) 195 { 196 if (dest + len >= memtop_copyin) { 197 errno = EFBIG; 198 return (-1); 199 } 200 201 return (read(fd, PTOV(dest), len)); 202 } 203