📄 head.s
字号:
/* * Here is where the ball gets rolling as far as the kernel is concerned. * When control is transferred to _start, the bootload has already * loaded us to the correct address. All that's left to do here is * to set up the kernel's global pointer and jump to the kernel * entry point. * * Copyright (C) 1998-2001, 2003, 2005 Hewlett-Packard Co * David Mosberger-Tang <davidm@hpl.hp.com> * Stephane Eranian <eranian@hpl.hp.com> * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> * Copyright (C) 1999 Intel Corp. * Copyright (C) 1999 Asit Mallick <Asit.K.Mallick@intel.com> * Copyright (C) 1999 Don Dugger <Don.Dugger@intel.com> * Copyright (C) 2002 Fenghua Yu <fenghua.yu@intel.com> * -Optimize __ia64_save_fpu() and __ia64_load_fpu() for Itanium 2. * Copyright (C) 2004 Ashok Raj <ashok.raj@intel.com> * Support for CPU Hotplug */#include <linux/config.h>#include <asm/asmmacro.h>#include <asm/fpu.h>#include <asm/kregs.h>#include <asm/mmu_context.h>#include <asm/offsets.h>#include <asm/pal.h>#include <asm/pgtable.h>#include <asm/processor.h>#include <asm/ptrace.h>#include <asm/system.h>#include <asm/mca_asm.h>#ifdef CONFIG_HOTPLUG_CPU#define SAL_PSR_BITS_TO_SET \ (IA64_PSR_AC | IA64_PSR_BN | IA64_PSR_MFH | IA64_PSR_MFL)#define SAVE_FROM_REG(src, ptr, dest) \ mov dest=src;; \ st8 [ptr]=dest,0x08#define RESTORE_REG(reg, ptr, _tmp) \ ld8 _tmp=[ptr],0x08;; \ mov reg=_tmp#define SAVE_BREAK_REGS(ptr, _idx, _breg, _dest)\ mov ar.lc=IA64_NUM_DBG_REGS-1;; \ mov _idx=0;; \1: \ SAVE_FROM_REG(_breg[_idx], ptr, _dest);; \ add _idx=1,_idx;; \ br.cloop.sptk.many 1b#define RESTORE_BREAK_REGS(ptr, _idx, _breg, _tmp, _lbl)\ mov ar.lc=IA64_NUM_DBG_REGS-1;; \ mov _idx=0;; \_lbl: RESTORE_REG(_breg[_idx], ptr, _tmp);; \ add _idx=1, _idx;; \ br.cloop.sptk.many _lbl#define SAVE_ONE_RR(num, _reg, _tmp) \ movl _tmp=(num<<61);; \ mov _reg=rr[_tmp]#define SAVE_REGION_REGS(_tmp, _r0, _r1, _r2, _r3, _r4, _r5, _r6, _r7) \ SAVE_ONE_RR(0,_r0, _tmp);; \ SAVE_ONE_RR(1,_r1, _tmp);; \ SAVE_ONE_RR(2,_r2, _tmp);; \ SAVE_ONE_RR(3,_r3, _tmp);; \ SAVE_ONE_RR(4,_r4, _tmp);; \ SAVE_ONE_RR(5,_r5, _tmp);; \ SAVE_ONE_RR(6,_r6, _tmp);; \ SAVE_ONE_RR(7,_r7, _tmp);;#define STORE_REGION_REGS(ptr, _r0, _r1, _r2, _r3, _r4, _r5, _r6, _r7) \ st8 [ptr]=_r0, 8;; \ st8 [ptr]=_r1, 8;; \ st8 [ptr]=_r2, 8;; \ st8 [ptr]=_r3, 8;; \ st8 [ptr]=_r4, 8;; \ st8 [ptr]=_r5, 8;; \ st8 [ptr]=_r6, 8;; \ st8 [ptr]=_r7, 8;;#define RESTORE_REGION_REGS(ptr, _idx1, _idx2, _tmp) \ mov ar.lc=0x08-1;; \ movl _idx1=0x00;; \RestRR: \ dep.z _idx2=_idx1,61,3;; \ ld8 _tmp=[ptr],8;; \ mov rr[_idx2]=_tmp;; \ srlz.d;; \ add _idx1=1,_idx1;; \ br.cloop.sptk.few RestRR#define SET_AREA_FOR_BOOTING_CPU(reg1, reg2) \ movl reg1=sal_state_for_booting_cpu;; \ ld8 reg2=[reg1];;/* * Adjust region registers saved before starting to save * break regs and rest of the states that need to be preserved. */#define SAL_TO_OS_BOOT_HANDOFF_STATE_SAVE(_reg1,_reg2,_pred) \ SAVE_FROM_REG(b0,_reg1,_reg2);; \ SAVE_FROM_REG(b1,_reg1,_reg2);; \ SAVE_FROM_REG(b2,_reg1,_reg2);; \ SAVE_FROM_REG(b3,_reg1,_reg2);; \ SAVE_FROM_REG(b4,_reg1,_reg2);; \ SAVE_FROM_REG(b5,_reg1,_reg2);; \ st8 [_reg1]=r1,0x08;; \ st8 [_reg1]=r12,0x08;; \ st8 [_reg1]=r13,0x08;; \ SAVE_FROM_REG(ar.fpsr,_reg1,_reg2);; \ SAVE_FROM_REG(ar.pfs,_reg1,_reg2);; \ SAVE_FROM_REG(ar.rnat,_reg1,_reg2);; \ SAVE_FROM_REG(ar.unat,_reg1,_reg2);; \ SAVE_FROM_REG(ar.bspstore,_reg1,_reg2);; \ SAVE_FROM_REG(cr.dcr,_reg1,_reg2);; \ SAVE_FROM_REG(cr.iva,_reg1,_reg2);; \ SAVE_FROM_REG(cr.pta,_reg1,_reg2);; \ SAVE_FROM_REG(cr.itv,_reg1,_reg2);; \ SAVE_FROM_REG(cr.pmv,_reg1,_reg2);; \ SAVE_FROM_REG(cr.cmcv,_reg1,_reg2);; \ SAVE_FROM_REG(cr.lrr0,_reg1,_reg2);; \ SAVE_FROM_REG(cr.lrr1,_reg1,_reg2);; \ st8 [_reg1]=r4,0x08;; \ st8 [_reg1]=r5,0x08;; \ st8 [_reg1]=r6,0x08;; \ st8 [_reg1]=r7,0x08;; \ st8 [_reg1]=_pred,0x08;; \ SAVE_FROM_REG(ar.lc, _reg1, _reg2);; \ stf.spill.nta [_reg1]=f2,16;; \ stf.spill.nta [_reg1]=f3,16;; \ stf.spill.nta [_reg1]=f4,16;; \ stf.spill.nta [_reg1]=f5,16;; \ stf.spill.nta [_reg1]=f16,16;; \ stf.spill.nta [_reg1]=f17,16;; \ stf.spill.nta [_reg1]=f18,16;; \ stf.spill.nta [_reg1]=f19,16;; \ stf.spill.nta [_reg1]=f20,16;; \ stf.spill.nta [_reg1]=f21,16;; \ stf.spill.nta [_reg1]=f22,16;; \ stf.spill.nta [_reg1]=f23,16;; \ stf.spill.nta [_reg1]=f24,16;; \ stf.spill.nta [_reg1]=f25,16;; \ stf.spill.nta [_reg1]=f26,16;; \ stf.spill.nta [_reg1]=f27,16;; \ stf.spill.nta [_reg1]=f28,16;; \ stf.spill.nta [_reg1]=f29,16;; \ stf.spill.nta [_reg1]=f30,16;; \ stf.spill.nta [_reg1]=f31,16;;#else#define SET_AREA_FOR_BOOTING_CPU(a1, a2)#define SAL_TO_OS_BOOT_HANDOFF_STATE_SAVE(a1,a2, a3)#define SAVE_REGION_REGS(_tmp, _r0, _r1, _r2, _r3, _r4, _r5, _r6, _r7)#define STORE_REGION_REGS(ptr, _r0, _r1, _r2, _r3, _r4, _r5, _r6, _r7)#endif#ifdef XEN#define SET_ONE_RR(num, pgsize, _tmp1, _tmp2, vhpt) \ movl _tmp1=(num << 61);; \ movl _tmp2=((ia64_rid(IA64_REGION_ID_KERNEL, (num<<61)) << 8) | (pgsize << 2) | vhpt);; \ mov rr[_tmp1]=_tmp2#else#define SET_ONE_RR(num, pgsize, _tmp1, _tmp2, vhpt) \ movl _tmp1=(num << 61);; \ mov _tmp2=((ia64_rid(IA64_REGION_ID_KERNEL, (num<<61)) << 8) | (pgsize << 2) | vhpt);; \ mov rr[_tmp1]=_tmp2#endif .section __special_page_section,"ax" .global empty_zero_pageempty_zero_page: .skip PAGE_SIZE#ifndef XEN .global swapper_pg_dirswapper_pg_dir: .skip PAGE_SIZE#endif#if defined(XEN) && defined(CONFIG_VIRTUAL_FRAME_TABLE) .global frametable_pg_dirframetable_pg_dir: .skip PAGE_SIZE#endif .rodatahalt_msg: stringz "Halting kernel\n" .text .global start_ap /* * Start the kernel. When the bootloader passes control to _start(), r28 * points to the address of the boot parameter area. Execution reaches * here in physical mode. */GLOBAL_ENTRY(_start)start_ap: .prologue .save rp, r0 // terminate unwind chain with a NULL rp .body rsm psr.i | psr.ic ;; srlz.i ;; /* * Save the region registers, predicate before they get clobbered */ SAVE_REGION_REGS(r2, r8,r9,r10,r11,r12,r13,r14,r15); mov r25=pr;; /* * Initialize kernel region registers: * rr[0]: VHPT enabled, page size = PAGE_SHIFT * rr[1]: VHPT enabled, page size = PAGE_SHIFT * rr[2]: VHPT enabled, page size = PAGE_SHIFT * rr[3]: VHPT enabled, page size = PAGE_SHIFT * rr[4]: VHPT enabled, page size = PAGE_SHIFT * rr[5]: VHPT enabled, page size = PAGE_SHIFT * rr[6]: VHPT disabled, page size = IA64_GRANULE_SHIFT * rr[7]: VHPT disabled, page size = IA64_GRANULE_SHIFT * We initialize all of them to prevent inadvertently assuming * something about the state of address translation early in boot. */ SET_ONE_RR(0, PAGE_SHIFT, r2, r16, 1);; SET_ONE_RR(1, PAGE_SHIFT, r2, r16, 1);; SET_ONE_RR(2, PAGE_SHIFT, r2, r16, 1);; SET_ONE_RR(3, PAGE_SHIFT, r2, r16, 1);; SET_ONE_RR(4, PAGE_SHIFT, r2, r16, 1);; SET_ONE_RR(5, PAGE_SHIFT, r2, r16, 1);; SET_ONE_RR(6, IA64_GRANULE_SHIFT, r2, r16, 0);; SET_ONE_RR(7, IA64_GRANULE_SHIFT, r2, r16, 0);; /* * Now pin mappings into the TLB for kernel text and data */ mov r18=KERNEL_TR_PAGE_SHIFT<<2 movl r17=KERNEL_START ;; mov cr.itir=r18 mov cr.ifa=r17 mov r16=IA64_TR_KERNEL mov r3=ip movl r18=PAGE_KERNEL ;; dep r2=0,r3,0,KERNEL_TR_PAGE_SHIFT ;; or r18=r2,r18 ;; srlz.i ;; itr.i itr[r16]=r18 ;; itr.d dtr[r16]=r18 ;; srlz.i /* * Switch into virtual mode: */ movl r16=(IA64_PSR_IT|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFH|IA64_PSR_BN \ |IA64_PSR_DI) ;; mov cr.ipsr=r16 movl r17=1f ;; mov cr.iip=r17 mov cr.ifs=r0 ;; rfi ;;1: // now we are in virtual mode SET_AREA_FOR_BOOTING_CPU(r2, r16); STORE_REGION_REGS(r16, r8,r9,r10,r11,r12,r13,r14,r15); SAL_TO_OS_BOOT_HANDOFF_STATE_SAVE(r16,r17,r25) ;; // set IVT entry point---can't access I/O ports without it movl r3=ia64_ivt ;; mov cr.iva=r3 movl r2=FPSR_DEFAULT ;; srlz.i movl gp=__gp ;; mov ar.fpsr=r2 ;;#define isAP p2 // are we an Application Processor?#define isBP p3 // are we the Bootstrap Processor?#ifdef XEN# define init_task init_task_mem#endif#ifdef CONFIG_SMP /* * Find the init_task for the currently booting CPU. At poweron, and in * UP mode, task_for_booting_cpu is NULL. */ movl r3=task_for_booting_cpu ;; ld8 r3=[r3] movl r2=init_task ;; cmp.eq isBP,isAP=r3,r0 ;;(isAP) mov r2=r3#else movl r2=init_task cmp.eq isBP,isAP=r0,r0#endif ;; tpa r3=r2 // r3 == phys addr of task struct mov r16=-1#ifndef XEN(isBP) br.cond.dpnt .load_current // BP stack is on region 5 --- no need to map it#endif // load mapping for stack (virtaddr in r2, physaddr in r3) rsm psr.ic movl r17=PAGE_KERNEL ;; srlz.d dep r18=0,r3,0,12 ;; or r18=r17,r18#ifdef XEN dep r2=-1,r3,60,4 // IMVA of task #else dep r2=-1,r3,61,3 // IMVA of task#endif ;; mov r17=rr[r2] shr.u r16=r3,IA64_GRANULE_SHIFT ;; dep r17=0,r17,8,24 ;; mov cr.itir=r17 mov cr.ifa=r2 mov r19=IA64_TR_CURRENT_STACK ;; itr.d dtr[r19]=r18 ;; ssm psr.ic srlz.d ;; .load_current: // load the "current" pointer (r13) and ar.k6 with the current task mov IA64_KR(CURRENT)=r2 // virtual address mov IA64_KR(CURRENT_STACK)=r16 mov r13=r2 /* * Reserve space at the top of the stack for "struct pt_regs". Kernel * threads don't store interesting values in that structure, but the space * still needs to be there because time-critical stuff such as the context * switching can be implemented more efficiently (for example, __switch_to() * always sets the psr.dfh bit of the task it is switching to). */ addl r12=IA64_STK_OFFSET-IA64_PT_REGS_SIZE-16,r2 addl r2=IA64_RBS_OFFSET,r2 // initialize the RSE mov ar.rsc=0 // place RSE in enforced lazy mode ;; loadrs // clear the dirty partition ;; mov ar.bspstore=r2 // establish the new RSE stack ;; mov ar.rsc=0x3 // place RSE in eager mode#ifdef XEN(isBP) dep r28=-1,r28,60,4 // make address virtual#else(isBP) dep r28=-1,r28,61,3 // make address virtual#endif(isBP) movl r2=ia64_boot_param ;;(isBP) st8 [r2]=r28 // save the address of the boot param area passed by the bootloader#ifdef CONFIG_SMP(isAP) br.call.sptk.many rp=start_secondary.ret0:(isAP) br.cond.sptk self#endif // This is executed by the bootstrap processor (bsp) only:#ifdef CONFIG_IA64_FW_EMU // initialize PAL & SAL emulator: br.call.sptk.many rp=sys_fw_init.ret1:#endif br.call.sptk.many rp=start_kernel.ret2: addl r3=@ltoff(halt_msg),gp ;; alloc r2=ar.pfs,8,0,2,0 ;; ld8 out0=[r3] br.call.sptk.many b0=console_printself: hint @pause#ifdef XEN ;; br.sptk.many self // endless loop ;;#else br.sptk.many self // endless loop#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -