1/*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * William Jolitz. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * from: @(#)locore.s 7.3 (Berkeley) 5/13/91 33 * 34 * originally from: locore.s, by William F. Jolitz 35 * 36 * Substantially rewritten by David Greenman, Rod Grimes, 37 * Bruce Evans, Wolfgang Solfrank, Poul-Henning Kamp 38 * and many others. 39 */ 40 41#include "opt_bootp.h" 42#include "opt_nfsroot.h" 43#include "opt_pmap.h" 44 45#include <sys/reboot.h> 46 47#include <machine/asmacros.h> 48#include <machine/cputypes.h> 49#include <machine/psl.h> 50#include <machine/pmap.h> 51#include <machine/specialreg.h> 52 53#include "assym.inc" 54 55/* 56 * Compiled KERNBASE location and the kernel load address, now identical. 57 */ 58 .globl kernbase 59 .set kernbase,KERNBASE 60 .globl kernload 61 .set kernload,KERNLOAD 62 63/* 64 * Globals 65 */ 66 .data 67 ALIGN_DATA /* just to be sure */ 68 69 .space 0x2000 /* space for tmpstk - temporary stack */ 70tmpstk: 71 72 .globl bootinfo 73bootinfo: .space BOOTINFO_SIZE /* bootinfo that we can handle */ 74 75 .text 76/********************************************************************** 77 * 78 * This is where the bootblocks start us, set the ball rolling... 79 * 80 */ 81ENTRY(btext) 82 83/* Tell the bios to warmboot next time */ 84 movw $0x1234,0x472 85 86/* Set up a real frame in case the double return in newboot is executed. */ 87 xorl %ebp,%ebp 88 pushl %ebp 89 movl %esp, %ebp 90 91/* Don't trust what the BIOS gives for eflags. */ 92 pushl $PSL_KERNEL 93 popfl 94 95/* 96 * Don't trust what the BIOS gives for %fs and %gs. Trust the bootstrap 97 * to set %cs, %ds, %es and %ss. 98 */ 99 mov %ds, %ax 100 mov %ax, %fs 101 mov %ax, %gs 102 103/* 104 * Clear the bss. Not all boot programs do it, and it is our job anyway. 105 * 106 * XXX we don't check that there is memory for our bss and page tables 107 * before using it. 108 * 109 * Note: we must be careful to not overwrite an active gdt or idt. They 110 * inactive from now until we switch to new ones, since we don't load any 111 * more segment registers or permit interrupts until after the switch. 112 */ 113 movl $__bss_end,%ecx 114 movl $__bss_start,%edi 115 subl %edi,%ecx 116 xorl %eax,%eax 117 cld 118 rep 119 stosb 120 121 call recover_bootinfo 122 123/* Get onto a stack that we can trust. */ 124/* 125 * XXX this step is delayed in case recover_bootinfo needs to return via 126 * the old stack, but it need not be, since recover_bootinfo actually 127 * returns via the old frame. 128 */ 129 movl $tmpstk,%esp 130 131 call identify_cpu 132 call pmap_cold 133 134 /* set up bootstrap stack */ 135 movl proc0kstack,%eax /* location of in-kernel stack */ 136 137 /* 138 * Only use bottom page for init386(). init386() calculates the 139 * PCB + FPU save area size and returns the true top of stack. 140 */ 141 leal PAGE_SIZE(%eax),%esp 142 143 xorl %ebp,%ebp /* mark end of frames */ 144 145 pushl physfree /* value of first for init386(first) */ 146 call init386 /* wire 386 chip for unix operation */ 147 148 /* 149 * Clean up the stack in a way that db_numargs() understands, so 150 * that backtraces in ddb don't underrun the stack. Traps for 151 * inaccessible memory are more fatal than usual this early. 152 */ 153 addl $4,%esp 154 155 /* Switch to true top of stack. */ 156 movl %eax,%esp 157 158 call mi_startup /* autoconfiguration, mountroot etc */ 159 /* NOTREACHED */ 160 addl $0,%esp /* for db_numargs() again */ 161 162/********************************************************************** 163 * 164 * Recover the bootinfo passed to us from the boot program 165 * 166 */ 167recover_bootinfo: 168 /* 169 * This code is called in different ways depending on what loaded 170 * and started the kernel. This is used to detect how we get the 171 * arguments from the other code and what we do with them. 172 * 173 * Old disk boot blocks: 174 * (*btext)(howto, bootdev, cyloffset, esym); 175 * [return address == 0, and can NOT be returned to] 176 * [cyloffset was not supported by the FreeBSD boot code 177 * and always passed in as 0] 178 * [esym is also known as total in the boot code, and 179 * was never properly supported by the FreeBSD boot code] 180 * This code from 1.x/2.x doesn't supply now-required metadata and 181 * likely will fail (we test for it to avoid dereferencing stack 182 * garbage here). 183 * 184 * Old diskless netboot code: 185 * (*btext)(0,0,0,0,&nfsdiskless,0,0,0); 186 * [return address != 0, and can NOT be returned to] 187 * If we are being booted by this code it will NOT work, 188 * so we are just going to halt if we find this case. 189 * 190 * New uniform boot code: 191 * (*btext)(howto, bootdev, 0, 0, 0, &bootinfo) 192 * [return address != 0, and can be returned to] 193 * 194 * There may seem to be a lot of wasted arguments in here, but 195 * that is so the newer boot code can still load very old kernels 196 * and old boot code can load new kernels. 197 */ 198 199 /* 200 * The old style disk boot blocks fake a frame on the stack and did an 201 * lret to get here. The frame on the stack has a return address of 0. 202 * This style of boot (from 1.x / 2.x) almost certainly won't work, 203 * since the kernel has required metadata since about 7.x or so and none 204 * are present. 205 */ 206 cmpl $0,4(%ebp) 207 je olddiskboot 208 209 /* 210 * We have some form of return address, so this is either the 211 * old diskless netboot code, or the new uniform code. That can 212 * be detected by looking at the 5th argument, if it is 0 213 * we are being booted by the new uniform boot code. 214 */ 215 cmpl $0,24(%ebp) 216 je newboot 217 218 /* 219 * Seems we have been loaded by the old 1.x/2.x diskless boot code, we 220 * don't stand a chance of running as the diskless structure changed 221 * considerably between the two, so just halt. 222 */ 223 hlt 224 225 /* 226 * We have been loaded by the new uniform boot code. 227 * Let's check the bootinfo version, and if we do not understand 228 * it we return to the loader with a status of 1 to indicate this error 229 */ 230newboot: 231 movl 28(%ebp),%ebx /* &bootinfo.version */ 232 movl BI_VERSION(%ebx),%eax 233 cmpl $1,%eax /* We only understand version 1 */ 234 je 1f 235 testl $RB_BOOTINFO,8(%ebp) /* bi_size (and bootinfo) valid? */ 236 jne 1f 237 movl $1,%eax /* Return status */ 238 leave 239 /* 240 * XXX this returns to our caller's caller (as is required) since 241 * we didn't set up a frame and our caller did. 242 */ 243 ret 244 2451: 246 /* 247 * If we have a kernelname copy it in 248 */ 249 movl BI_KERNELNAME(%ebx),%esi 250 cmpl $0,%esi 251 je 2f /* No kernelname */ 252 movl $MAXPATHLEN,%ecx /* Brute force!!! */ 253 movl $kernelname,%edi 254 cmpb $'/',(%esi) /* Make sure it starts with a slash */ 255 je 1f 256 movb $'/',(%edi) 257 incl %edi 258 decl %ecx 2591: 260 cld 261 rep 262 movsb 263 2642: 265 /* 266 * Determine the size of the boot loader's copy of the bootinfo 267 * struct. Copy min(our size, loader's size) into our bootinfo. 268 * Incompatible with really old boot loaders from FreeBSD 1.x and 2.0. 269 */ 270 movl %ebx,%esi 271 movl $bootinfo,%edi 272 movl BI_SIZE(%ebx),%ecx 273 cmpl $BOOTINFO_SIZE,%ecx 274 jbe got_common_bi_size 275 movl $BOOTINFO_SIZE,%ecx 276got_common_bi_size: 277 cld 278 rep 279 movsb 280 281#ifdef NFS_ROOT 282#ifndef BOOTP_NFSV3 283 /* 284 * If we have a nfs_diskless structure copy it in 285 */ 286 movl BI_NFS_DISKLESS(%ebx),%esi 287 cmpl $0,%esi 288 je olddiskboot 289 movl $nfs_diskless,%edi 290 movl $NFSDISKLESS_SIZE,%ecx 291 cld 292 rep 293 movsb 294 movl $nfs_diskless_valid,%edi 295 movl $1,(%edi) 296#endif 297#endif 298 299 /* 300 * The old style disk boot. 301 * (*btext)(howto, bootdev, cyloffset, esym); 302 * Note that the newer boot code just falls into here to pick 303 * up howto and bootdev, cyloffset and esym are no longer used 304 */ 305olddiskboot: 306 movl 8(%ebp),%eax 307 movl %eax,boothowto 308 movl 12(%ebp),%eax 309 movl %eax,bootdev 310 311 ret 312 313 314/********************************************************************** 315 * 316 * Identify the CPU and initialize anything special about it 317 * 318 */ 319ENTRY(identify_cpu) 320 321 pushl %ebx 322 323 /* Try to toggle alignment check flag; does not exist on 386. */ 324 pushfl 325 popl %eax 326 movl %eax,%ecx 327 orl $PSL_AC,%eax 328 pushl %eax 329 popfl 330 pushfl 331 popl %eax 332 xorl %ecx,%eax 333 andl $PSL_AC,%eax 334 pushl %ecx 335 popfl 336 337 testl %eax,%eax 338 jnz try486 339 340 /* NexGen CPU does not have alignment check flag. */ 341 pushfl 342 movl $0x5555, %eax 343 xorl %edx, %edx 344 movl $2, %ecx 345 clc 346 divl %ecx 347 jz trynexgen 348 popfl 349 movl $CPU_386,cpu 350 jmp 3f 351 352trynexgen: 353 popfl 354 movl $CPU_NX586,cpu 355 movl $0x4778654e,cpu_vendor # store vendor string 356 movl $0x72446e65,cpu_vendor+4 357 movl $0x6e657669,cpu_vendor+8 358 movl $0,cpu_vendor+12 359 jmp 3f 360 361try486: /* Try to toggle identification flag; does not exist on early 486s. */ 362 pushfl 363 popl %eax 364 movl %eax,%ecx 365 xorl $PSL_ID,%eax 366 pushl %eax 367 popfl 368 pushfl 369 popl %eax 370 xorl %ecx,%eax 371 andl $PSL_ID,%eax 372 pushl %ecx 373 popfl 374 375 testl %eax,%eax 376 jnz trycpuid 377 movl $CPU_486,cpu 378 379 /* 380 * Check Cyrix CPU 381 * Cyrix CPUs do not change the undefined flags following 382 * execution of the divide instruction which divides 5 by 2. 383 * 384 * Note: CPUID is enabled on M2, so it passes another way. 385 */ 386 pushfl 387 movl $0x5555, %eax 388 xorl %edx, %edx 389 movl $2, %ecx 390 clc 391 divl %ecx 392 jnc trycyrix 393 popfl 394 jmp 3f /* You may use Intel CPU. */ 395 396trycyrix: 397 popfl 398 /* 399 * IBM Bluelighting CPU also doesn't change the undefined flags. 400 * Because IBM doesn't disclose the information for Bluelighting 401 * CPU, we couldn't distinguish it from Cyrix's (including IBM 402 * brand of Cyrix CPUs). 403 */ 404 movl $0x69727943,cpu_vendor # store vendor string 405 movl $0x736e4978,cpu_vendor+4 406 movl $0x64616574,cpu_vendor+8 407 jmp 3f 408 409trycpuid: /* Use the `cpuid' instruction. */ 410 xorl %eax,%eax 411 cpuid # cpuid 0 412 movl %eax,cpu_high # highest capability 413 movl %ebx,cpu_vendor # store vendor string 414 movl %edx,cpu_vendor+4 415 movl %ecx,cpu_vendor+8 416 movb $0,cpu_vendor+12 417 418 movl $1,%eax 419 cpuid # cpuid 1 420 movl %eax,cpu_id # store cpu_id 421 movl %ebx,cpu_procinfo # store cpu_procinfo 422 movl %edx,cpu_feature # store cpu_feature 423 movl %ecx,cpu_feature2 # store cpu_feature2 424 rorl $8,%eax # extract family type 425 andl $15,%eax 426 cmpl $5,%eax 427 jae 1f 428 429 /* less than Pentium; must be 486 */ 430 movl $CPU_486,cpu 431 jmp 3f 4321: 433 /* a Pentium? */ 434 cmpl $5,%eax 435 jne 2f 436 movl $CPU_586,cpu 437 jmp 3f 4382: 439 /* Greater than Pentium...call it a Pentium Pro */ 440 movl $CPU_686,cpu 4413: 442 popl %ebx 443 ret 444END(identify_cpu) 445 446#ifdef XENHVM 447/* Xen Hypercall page */ 448 .text 449.p2align PAGE_SHIFT, 0x90 /* Hypercall_page needs to be PAGE aligned */ 450 451ENTRY(hypercall_page) 452 .skip 0x1000, 0x90 /* Fill with "nop"s */ 453#endif 454