/* * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights * Reserved. This file contains Original Code and/or Modifications of * Original Code as defined in and that are subject to the Apple Public * Source License Version 2.0 (the "License"). You may not use this file * except in compliance with the License. Please obtain a copy of the * License at http://www.apple.com/publicsource and read it before using * this file. * * The Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * Mach Operating System * Copyright (c) 1990 Carnegie-Mellon University * Copyright (c) 1989 Carnegie-Mellon University * All rights reserved. The CMU software License Agreement specifies * the terms and conditions for use and redistribution. */ /* * HISTORY * $Log: asm.s,v $ * Revision 1.8 2005/06/24 22:47:12 curtisg * Merging changes for 4159531 to pass data to the kernel in EFI format. * * Revision 1.7 2004/05/13 17:58:38 curtisg * Integrating: * : (Silent boot) * : (5 sec boot timeout is too short) * : (Boot option to display graphics modes) * : (Default graphics mode should be 32-bit) * : (Booter should always find a video mode) * : (Booter displays "0MB" VRAM) * * Revision 1.6 2003/11/05 20:51:02 curtisg * Integrated 3069695,3331770,3370488,3371823 * * Revision 1.5.26.1 2003/10/27 23:57:59 curtisg * Added printing of volume names, better handling of extended * partitions, and updated Apple license strings. * New chain booter should work better with foreign operating * systems. * * Revision 1.5 2002/11/05 20:34:26 jliu * Integrating: * 3051234 boot shouldnt require Graphics = Yes * 3091627 Need support for refresh rate adjustment * * Revision 1.4 2002/10/02 00:06:18 curtisg * Integrating PR-3032510. * * Revision 1.3.6.1 2002/08/30 21:16:29 curtisg * KERNBOOTSTRUCT is going away in favor of KernelBootArgs_t in . * * Revision 1.3 2002/07/09 14:06:21 jliu * Merging changes from PR-2954224 branch in boot/i386. * * Revision 1.2.30.1 2002/07/05 16:24:51 jliu * Merged UFS/HFS/HFS+ filesystem support from BootX. * Moved boot2 load address due to increased size. boot0/boot1 also changed. * Updated boot graphics and CLUT. * Added support to chain load foreign booters. * Fixed param passing bug in network loader. * Misc cleanup in libsaio. * * Revision 1.2 2000/05/23 23:01:11 lindak * Merged PR-2309530 into Kodiak (liu i386 booter: does not support label-less * ufs partitions) * * Revision 1.1.1.2.4.1 2000/05/13 17:07:39 jliu * New boot0 (boot1 has been deprecated). Booter must now reside in its own partition, no disk label required. * * Revision 1.1.1.2 1999/08/04 21:16:57 wsanchez * Impoort of boot-66 * * Revision 1.3 1999/08/04 21:12:12 wsanchez * Update APSL * * Revision 1.2 1999/03/25 05:48:30 wsanchez * Add APL. * Remove unused gzip code. * Remove unused Adobe fonts. * * Revision 1.1.1.1.66.2 1999/03/16 16:08:54 wsanchez * Substitute License * * Revision 1.1.1.1.66.1 1999/03/16 07:33:21 wsanchez * Add APL * * Revision 1.1.1.1 1997/12/05 21:57:57 wsanchez * Import of boot-25 (~mwatson) * * Revision 2.1.1.2 90//03//22 17:59:50 rvb * Added _sp() => where is the stack at. [kupfer] * * Revision 2.1.1.1 90//02//09 17:25:04 rvb * Add Intel copyright * [90//02//09 rvb] * */ // INTEL CORPORATION PROPRIETARY INFORMATION // // This software is supplied under the terms of a license agreement or // nondisclosure agreement with Intel Corporation and may not be copied // nor disclosed except in accordance with the terms of that agreement. // // Copyright 1988 Intel Corporation // Copyright 1988, 1989 by Intel Corporation // #include #include "memory.h" #include "machsections.h" .file "asm.s" CR0_PE_ON = 0x1 #ifdef BOOT1 CR0_PE_OFF = 0x7ffffffe #else CR0_PE_OFF = 0x7ffffff0 #endif STACK32_BASE = ADDR32(STACK_SEG, 0) STACK16_SEG = STACK_SEG CODE32_BASE = ADDR32(BASE_SEG, 0) CODE16_SEG = BASE_SEG // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Pointer to 6-bytes in memory that contains the base address and the limit // (size of GDT table in bytes) of the GDT. The LGDT is the only instruction // that directly loads a linear address (not a segment relative address) and // a limit in protected mode. .globl _Gdtr SECTION_FOR_LODATA_OR_DATA .align 2, 0x90 _Gdtr: .word GDTLIMIT .long vtop(_Gdt) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // IDTR representing real-mode IVT. The values are constant. SECTION_FOR_LOCONST_OR_CONST // Real mode IDT .align 2 .globl _Idtr_real _Idtr_real: .word 0x03ff .long 0x00000000 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // IDTR representing protected-mode IDT. It is initially NULL which tells the // procesor that no IDT is available. After we get into protected mode we can // allocate memory for a proper IDT and update this IDTR to point to it. SECTION_FOR_LODATA_OR_DATA .align 2 .globl _Idtr_prot _Idtr_prot: .word 0 .long 0 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Data area for __switch_stack. // SECTION_FOR_LODATA_OR_DATA // HACK: align these on a 4-byte boundary and export them so // verify_bigboot_csum can account for their values. .globl save_sp .globl save_ss .p2align 2, 0 save_sp: .long STACK_OFS save_ss: .long STACK_SEG SECTION_FOR_LOTEXT_OR_TEXT // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // real_to_prot() // // Transfer from real mode to protected mode. // Preserves all registers except EAX. // LABEL(__real_to_prot) .code16 // Interrupts are disabled in protected mode. cli // Load the Global Descriptor Table Register (GDTR). Lgas_workaround_lgdtl = 0 # Prevents invalid character '(' in mnemonic addr32 \ lgdtl OFFSET16(_Gdtr) // Enter protected mode by setting the PE bit in CR0. mov %cr0, %eax orl $CR0_PE_ON, %eax mov %eax, %cr0 // Make intrasegment jump to flush the processor pipeline and // reload CS register. data32 \ ljmp $0x08, $xprot xprot: .code32 // we are in USE32 mode now // set up the protected mode segment registers : DS, SS, ES, FS, GS mov $0x10, %eax movw %ax, %ds movw %ax, %ss movw %ax, %es movw %ax, %fs movw %ax, %gs // set up the PM IDT lidt _Idtr_prot // Convert STACK_SEG:SP to 32-bit linear stack pointer. movzwl %sp, %eax addl $STACK32_BASE, %eax movl %eax, %esp // Convert STACK_SEG:BP to 32-bit linear base pointer. movzwl %bp, %eax addl $STACK32_BASE, %eax movl %eax, %ebp // Modify the caller's return address on the stack from // segment offset to linear address. popl %eax addl $CODE32_BASE, %eax pushl %eax ret // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // prot_to_real() // // Transfer from protected mode to real mode. // Preserves all registers except EAX. // LABEL(__prot_to_real) // Load real-mode IDT while we're still in USE32 mode so we don't need // 32-bit addressing prefixes. lidt _Idtr_real // Set up segment registers appropriate for real mode. movw $0x30, %ax movw %ax, %ds movw %ax, %es movw %ax, %fs movw %ax, %gs movw %ax, %ss ljmp $0x18, $x16 // change to USE16 mode x16: .code16 mov %cr0, %eax // clear the PE bit of CR0 andl $CR0_PE_OFF, %eax mov %eax, %cr0 // make intersegment jmp to flush the processor pipeline // and reload CS register data32 \ ljmp $CODE16_SEG, $xreal - CODE32_BASE xreal: // we are in real mode now // set up the real mode segment registers : DS, DS, ES, FS, GS movl %cs, %eax movw %ax, %ds movw %ax, %es movw %ax, %fs movw %ax, %gs // load stack segment register SS. movl $STACK16_SEG, %eax movw %ax, %ss // clear top 16-bits of ESP and EBP. movzwl %sp, %esp movzwl %bp, %ebp // Modify caller's return address on the stack // from linear address to segment offset. popl %eax movzwl %ax, %eax pushl %eax // Reenable maskable interrupts. sti data32 \ ret .code32 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // halt() // LABEL(_halt) #ifdef BOOT1 hlt #else call _bgetc #endif jmp _halt #ifndef BOOT1 // Back to __TEXT,__text in case __LOSEG,__text was used, no need to keep this low .text // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // startprog(phyaddr, arg) // Start the program on protected mode where phyaddr is the entry point. // Passes arg to the program in %eax. // LABEL(_startprog) push %ebp mov %esp, %ebp mov 0xc(%ebp), %eax // argument to program mov 0x8(%ebp), %ecx // entry offset mov $0x28, %ebx // segment push %ebx push %ecx // set up %ds and %es mov $0x20, %ebx movw %bx, %ds movw %bx, %es lret #endif #ifndef BOOT1 .text // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // int rdmsr_safe(uint32_t msr, uint64_t *val); // // Reads the MSR safely. If rdmsr is successful the result is copied such // that *val = (EDX << 32) + EAX then 0 (no error) is returned // // If rdmsr causes #GP, EFAULT is returned. // // NOTE: This is the FreeBSD-style rdmsr_safe LABEL(_rdmsr_safe) mov 4(%esp), %ecx L_rdmsr_safe_rdmsr: rdmsr mov 8(%esp), %ecx mov %eax, 0(%ecx) mov %edx, 4(%ecx) xor %eax, %eax ret L_rdmsr_safe_gp_fault_handlered: movl $14, %eax // EFAULT ret // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // gp_fault_handler() // // Handles the #GP CPU exception // For now this exists solely to catch #GP in rdmsr_safe() // All other #GP invoke halt() LABEL(_gp_fault_handler) // ESP -> 0: error code // 4: EIP // 8: CS // 12: EFLAGS cmpl $L_rdmsr_safe_rdmsr, 4(%esp) je L_gp_fault_handler_rdmsr // Well, we could cause a double fault which is what would happen without // this. But it's probably more useful to halt at this point. jmp _halt L_gp_fault_handler_rdmsr: // Overwrite the return address movl $L_rdmsr_safe_gp_fault_handlered, 4(%esp) // Drop the error code from the stack addl $4, %esp // Return to program iretl #elif defined(CDPREBOOT) // HACK: Even though cdpreboot doesn't use initIdt() it's in the // misc.c file which we don't want to compile separately because // there are things in the BOOT1-disabled sections we do need. // Therefore we need some implementation of gp_fault_handler(). // Alternatively, if rdmsr_safe is needed we could compile // the real code for CDPREBOOT and call initIdt() which would // actually make it work. LABEL(_gp_fault_handler) jmp _halt #endif SECTION_FOR_LOTEXT_OR_TEXT // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Returns the current stack pointer. // LABEL(__sp) mov %esp, %eax ret // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Returns the current frame pointer. // LABEL(__bp) mov %ebp, %eax ret // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // switch_stack() // // Switches stack pointer between SS:SP and memory save_ss:save_sp. // Call this function from real mode only!!! // // AX, DI, and SI are clobbered. // LABEL(__switch_stack) .code16 popw %ax # save return address popw %di # discard upper 16-bit Lgas_workaround_movl_esi = 0 # Prevents invalid character '(' in mnemonic addr32 \ movl OFFSET16(save_ss), %esi # new SS to SI addr32 \ movl OFFSET16(save_sp), %edi # new SP to DI addr32 \ mov %ss, OFFSET16(save_ss) # save current SS to memory addr32 \ movl %esp, OFFSET16(save_sp) # save current SP to memory cli mov %si, %ss # switch stack movl %edi, %esp sti pushw %ax # push IP of caller onto the new stack xorw %ax, %ax xorw %si, %si xorw %di, %di ret .code32 #ifndef BOOT1 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // loader() // // Issue a request to the network loader. // LABEL(_loader) enter $0, $0 pushal # # Pass a far pointer to the command structure # to the INT call through DX:CX. # # The command code is in BX. # movw 8(%ebp), %bx # 8[EBP] = command code movw 12(%ebp), %cx # 12[EBP] = command structure offset movw 14(%ebp), %dx # 14[EBP] = command structure segment call __prot_to_real # Revert to real mode .code16 ###### Real Mode Begin ###### data32 \ call __switch_stack # Switch to NBP stack int $0x2b # Call NBP data32 \ call __switch_stack # Restore stack data32 \ call __real_to_prot # Back to protected mode .code32 ###### Real Mode End ###### popal leave ret #endif #if UNUSED // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // pcpy(src, dst, cnt) // where src is a virtual address and dst is a physical address // LABEL(_pcpy) push %ebp mov %esp, %ebp push %es push %esi push %edi push %ecx cld // set %es to point at the flat segment mov $0x20, %eax movw %ax , %es mov 0x8(%ebp), %esi // source mov 0xc(%ebp), %edi // destination mov 0x10(%ebp), %ecx // count rep movsb pop %ecx pop %edi pop %esi pop %es pop %ebp ret #endif