📄 head.s
字号:
/* -*- mode: asm -*-**** head.S -- This file contains the initial boot code for the** Linux/68k kernel.**** Copyright 1993 by Hamish Macdonald**** 68040 fixes by Michael Rausch** 68060 fixes by Roman Hodek** MMU cleanup by Randy Thelen** Final MMU cleanup by Roman Zippel**** Atari support by Andreas Schwab, using ideas of Robert de Vries** and Bjoern Brauel** VME Support by Richard Hirst**** 94/11/14 Andreas Schwab: put kernel at PAGESIZE** 94/11/18 Andreas Schwab: remove identity mapping of STRAM for Atari** ++ Bjoern & Roman: ATARI-68040 support for the Medusa** 95/11/18 Richard Hirst: Added MVME166 support** 96/04/26 Guenther Kelleter: fixed identity mapping for Falcon with** Magnum- and FX-alternate ram** 98/04/25 Phil Blundell: added HP300 support** 1998/08/30 David Kilzer: Added support for fbcon_font_desc structures** for linux-2.1.115** 9/02/11 Richard Zidlicky: added Q40 support (initial vesion 99/01/01) **** This file is subject to the terms and conditions of the GNU General Public** License. See the file README.legal in the main directory of this archive** for more details.***//* * Linux startup code. * * At this point, the boot loader has: * Disabled interrupts * Disabled caches * Put us in supervisor state. * * The kernel setup code takes the following steps: * . Raise interrupt level * . Set up initial kernel memory mapping. * . This sets up a mapping of the 4M of memory the kernel is located in. * . It also does a mapping of any initial machine specific areas. * . Enable the MMU * . Enable cache memories * . Jump to kernel startup * * Much of the file restructuring was to accomplish: * 1) Remove register dependency through-out the file. * 2) Increase use of subroutines to perform functions * 3) Increase readability of the code * * Of course, readability is a subjective issue, so it will never be * argued that that goal was accomplished. It was merely a goal. * A key way to help make code more readable is to give good * documentation. So, the first thing you will find is exaustive * write-ups on the structure of the file, and the features of the * functional subroutines. * * General Structure: * ------------------ * Without a doubt the single largest chunk of head.S is spent * mapping the kernel and I/O physical space into the logical range * for the kernel. * There are new subroutines and data structures to make MMU * support cleaner and easier to understand. * First, you will find a routine call "mmu_map" which maps * a logical to a physical region for some length given a cache * type on behalf of the caller. This routine makes writing the * actual per-machine specific code very simple. * A central part of the code, but not a subroutine in itself, * is the mmu_init code which is broken down into mapping the kernel * (the same for all machines) and mapping machine-specific I/O * regions. * Also, there will be a description of engaging the MMU and * caches. * You will notice that there is a chunk of code which * can emit the entire MMU mapping of the machine. This is present * only in debug modes and can be very helpful. * Further, there is a new console driver in head.S that is * also only engaged in debug mode. Currently, it's only supported * on the Macintosh class of machines. However, it is hoped that * others will plug-in support for specific machines. * * ###################################################################### * * mmu_map * ------- * mmu_map was written for two key reasons. First, it was clear * that it was very difficult to read the previous code for mapping * regions of memory. Second, the Macintosh required such extensive * memory allocations that it didn't make sense to propogate the * existing code any further. * mmu_map requires some parameters: * * mmu_map (logical, physical, length, cache_type) * * While this essentially describes the function in the abstract, you'll * find more indepth description of other parameters at the implementation site. * * mmu_get_root_table_entry * ------------------------ * mmu_get_ptr_table_entry * ----------------------- * mmu_get_page_table_entry * ------------------------ * * These routines are used by other mmu routines to get a pointer into * a table, if necessary a new table is allocated. These routines are working * basically like pmd_alloc() and pte_alloc() in <asm/pgtable.h>. The root * table needs of course only to be allocated once in mmu_get_root_table_entry, * so that here also some mmu specific initialization is done. The second page * at the start of the kernel (the first page is unmapped later) is used for * the kernel_pg_dir. It must be at a position known at link time (as it's used * to initialize the init task struct) and since it needs special cache * settings, it's the easiest to use this page, the rest of the page is used * for further pointer tables. * mmu_get_page_table_entry allocates always a whole page for page tables, this * means 1024 pages and so 4MB of memory can be mapped. It doesn't make sense * to manage page tables in smaller pieces as nearly all mappings have that * size. * * ###################################################################### * * * ###################################################################### * * mmu_engage * ---------- * Thanks to a small helping routine enabling the mmu got quiet simple * and there is only one way left. mmu_engage makes a complete a new mapping * that only includes the absolute necessary to be able to jump to the final * postion and to restore the original mapping. * As this code doesn't need a transparent translation register anymore this * means all registers are free to be used by machines that needs them for * other purposes. * * ###################################################################### * * mmu_print * --------- * This algorithm will print out the page tables of the system as * appropriate for an 030 or an 040. This is useful for debugging purposes * and as such is enclosed in #ifdef MMU_PRINT/#endif clauses. * * ###################################################################### * * console_init * ------------ * The console is also able to be turned off. The console in head.S * is specifically for debugging and can be very useful. It is surrounded by * #ifdef CONSOLE/#endif clauses so it doesn't have to ship in known-good * kernels. It's basic algorithm is to determine the size of the screen * (in height/width and bit depth) and then use that information for * displaying an 8x8 font or an 8x16 (widthxheight). I prefer the 8x8 for * debugging so I can see more good data. But it was trivial to add support * for both fonts, so I included it. * Also, the algorithm for plotting pixels is abstracted so that in * theory other platforms could add support for different kinds of frame * buffers. This could be very useful. * * console_put_penguin * ------------------- * An important part of any Linux bring up is the penguin and there's * nothing like getting the Penguin on the screen! This algorithm will work * on any machine for which there is a console_plot_pixel. * * console_scroll * -------------- * My hope is that the scroll algorithm does the right thing on the * various platforms, but it wouldn't be hard to add the test conditions * and new code if it doesn't. * * console_putc * ------------- * * ###################################################################### * * Register usage has greatly simplified within head.S. Every subroutine * saves and restores all registers that it modifies (except it returns a * value in there of course). So the only register that needs to be initialized * is the stack pointer. * All other init code and data is now placed in the init section, so it will * be automatically freed at the end of the kernel initialization. * * ###################################################################### * * options * ------- * There are many options availble in a build of this file. I've * taken the time to describe them here to save you the time of searching * for them and trying to understand what they mean. * * CONFIG_xxx: These are the obvious machine configuration defines created * during configuration. These are defined in include/linux/autoconf.h. * * CONSOLE: There is support for head.S console in this file. This * console can talk to a Mac frame buffer, but could easily be extrapolated * to extend it to support other platforms. * * TEST_MMU: This is a test harness for running on any given machine but * getting an MMU dump for another class of machine. The classes of machines * that can be tested are any of the makes (Atari, Amiga, Mac, VME, etc.) * and any of the models (030, 040, 060, etc.). * * NOTE: TEST_MMU is NOT permanent! It is scheduled to be removed * When head.S boots on Atari, Amiga, Macintosh, and VME * machines. At that point the underlying logic will be * believed to be solid enough to be trusted, and TEST_MMU * can be dropped. Do note that that will clean up the * head.S code significantly as large blocks of #if/#else * clauses can be removed. * * MMU_NOCACHE_KERNEL: On the Macintosh platform there was an inquiry into * determing why devices don't appear to work. A test case was to remove * the cacheability of the kernel bits. * * MMU_PRINT: There is a routine built into head.S that can display the * MMU data structures. It outputs its result through the serial_putc * interface. So where ever that winds up driving data, that's where the * mmu struct will appear. On the Macintosh that's typically the console. * * SERIAL_DEBUG: There are a series of putc() macro statements * scattered through out the code to give progress of status to the * person sitting at the console. This constant determines whether those * are used. * * DEBUG: This is the standard DEBUG flag that can be set for building * the kernel. It has the effect adding additional tests into * the code. * * FONT_6x11: * FONT_8x8: * FONT_8x16: * In theory these could be determined at run time or handed * over by the booter. But, let's be real, it's a fine hard * coded value. (But, you will notice the code is run-time * flexible!) A pointer to the font's struct fbcon_font_desc * is kept locally in Lconsole_font. It is used to determine * font size information dynamically. * * Atari constants: * USE_PRINTER: Use the printer port for serial debug. * USE_SCC_B: Use the SCC port A (Serial2) for serial debug. * USE_SCC_A: Use the SCC port B (Modem2) for serial debug. * USE_MFP: Use the ST-MFP port (Modem1) for serial debug. * * Macintosh constants: * MAC_SERIAL_DEBUG: Turns on serial debug output for the Macintosh. * MAC_USE_SCC_A: Use the SCC port A (modem) for serial debug. * MAC_USE_SCC_B: Use the SCC port B (printer) for serial debug (default). */#include <linux/config.h>#include <linux/linkage.h>#include <linux/init.h>#include <asm/bootinfo.h>#include <asm/setup.h>#include <asm/entry.h>#include <asm/pgtable.h>#include <asm/page.h>#include "m68k_defs.h"#ifdef CONFIG_MAC#include <asm/machw.h>/* * Macintosh console support */#define CONSOLE/* * Macintosh serial debug support; outputs boot info to the printer * and/or modem serial ports */#undef MAC_SERIAL_DEBUG/* * Macintosh serial debug port selection; define one or both; * requires MAC_SERIAL_DEBUG to be defined */#define MAC_USE_SCC_A /* Macintosh modem serial port */#define MAC_USE_SCC_B /* Macintosh printer serial port */#endif /* CONFIG_MAC */#undef MMU_PRINT#undef MMU_NOCACHE_KERNEL#define SERIAL_DEBUG#undef DEBUG/* * For the head.S console, there are three supported fonts, 6x11, 8x16 and 8x8. * The 8x8 font is harder to read but fits more on the screen. */#define FONT_8x8 /* default *//* #define FONT_8x16 */ /* 2nd choice *//* #define FONT_6x11 */ /* 3rd choice */.globl SYMBOL_NAME(kernel_pg_dir).globl SYMBOL_NAME(availmem).globl SYMBOL_NAME(m68k_pgtable_cachemode).globl SYMBOL_NAME(m68k_supervisor_cachemode)#ifdef CONFIG_MVME16x.globl SYMBOL_NAME(mvme_bdid)#endif#ifdef CONFIG_Q40.globl SYMBOL_NAME(q40_mem_cptr) #endif CPUTYPE_040 = 1 /* indicates an 040 */CPUTYPE_060 = 2 /* indicates an 060 */CPUTYPE_0460 = 3 /* if either above are set, this is set */CPUTYPE_020 = 4 /* indicates an 020 *//* Translation control register */TC_ENABLE = 0x8000TC_PAGE8K = 0x4000TC_PAGE4K = 0x0000/* Transparent translation registers */TTR_ENABLE = 0x8000 /* enable transparent translation */TTR_ANYMODE = 0x4000 /* user and kernel mode access */TTR_KERNELMODE = 0x2000 /* only kernel mode access */TTR_USERMODE = 0x0000 /* only user mode access */TTR_CI = 0x0400 /* inhibit cache */TTR_RW = 0x0200 /* read/write mode */TTR_RWM = 0x0100 /* read/write mask */TTR_FCB2 = 0x0040 /* function code base bit 2 */TTR_FCB1 = 0x0020 /* function code base bit 1 */TTR_FCB0 = 0x0010 /* function code base bit 0 */TTR_FCM2 = 0x0004 /* function code mask bit 2 */TTR_FCM1 = 0x0002 /* function code mask bit 1 */TTR_FCM0 = 0x0001 /* function code mask bit 0 *//* Cache Control registers */CC6_ENABLE_D = 0x80000000 /* enable data cache (680[46]0) */CC6_FREEZE_D = 0x40000000 /* freeze data cache (68060) */CC6_ENABLE_SB = 0x20000000 /* enable store buffer (68060) */CC6_PUSH_DPI = 0x10000000 /* disable CPUSH invalidation (68060) */CC6_HALF_D = 0x08000000 /* half-cache mode for data cache (68060) */CC6_ENABLE_B = 0x00800000 /* enable branch cache (68060) */CC6_CLRA_B = 0x00400000 /* clear all entries in branch cache (68060) */CC6_CLRU_B = 0x00200000 /* clear user entries in branch cache (68060) */CC6_ENABLE_I = 0x00008000 /* enable instruction cache (680[46]0) */CC6_FREEZE_I = 0x00004000 /* freeze instruction cache (68060) */CC6_HALF_I = 0x00002000 /* half-cache mode for instruction cache (68060) */CC3_ALLOC_WRITE = 0x00002000 /* write allocate mode(68030) */CC3_ENABLE_DB = 0x00001000 /* enable data burst (68030) */CC3_CLR_D = 0x00000800 /* clear data cache (68030) */CC3_CLRE_D = 0x00000400 /* clear entry in data cache (68030) */CC3_FREEZE_D = 0x00000200 /* freeze data cache (68030) */CC3_ENABLE_D = 0x00000100 /* enable data cache (68030) */CC3_ENABLE_IB = 0x00000010 /* enable instruction burst (68030) */CC3_CLR_I = 0x00000008 /* clear instruction cache (68030) */CC3_CLRE_I = 0x00000004 /* clear entry in instruction cache (68030) */CC3_FREEZE_I = 0x00000002 /* freeze instruction cache (68030) */CC3_ENABLE_I = 0x00000001 /* enable instruction cache (68030) *//* Miscellaneous definitions */PAGESIZE = 4096PAGESHIFT = 12ROOT_TABLE_SIZE = 128PTR_TABLE_SIZE = 128PAGE_TABLE_SIZE = 64ROOT_INDEX_SHIFT = 25PTR_INDEX_SHIFT = 18PAGE_INDEX_SHIFT = 12#ifdef DEBUG/* When debugging use readable names for labels */#ifdef __STDC__#define L(name) .head.S.##name#else#define L(name) .head.S./**/name#endif#else#ifdef __STDC__#define L(name) .L##name#else#define L(name) .L/**/name#endif#endif/* The __INITDATA stuff is a no-op when ftrace or kgdb are turned on */#ifndef __INITDATA#define __INITDATA .data#define __FINIT .previous#endif/* Several macros to make the writing of subroutines easier: * - func_start marks the beginning of the routine which setups the frame * register and saves the registers, it also defines another macro * to automatically restore the registers again. * - func_return marks the end of the routine and simply calls the prepared * macro to restore registers and jump back to the caller. * - func_define generates another macro to automatically put arguments * onto the stack call the subroutine and cleanup the stack again. *//* Within subroutines these macros can be used to access the arguments * on the stack. With STACK some allocated memory on the stack can be * accessed and ARG0 points to the return address (used by mmu_engage). */#define STACK %a6@(stackstart)#define ARG0 %a6@(4)#define ARG1 %a6@(8)#define ARG2 %a6@(12)#define ARG3 %a6@(16)#define ARG4 %a6@(20).macro func_start name,saveregs,stack=0L(\name): linkw %a6,#-\stack moveml \saveregs,%sp@-.set stackstart,-\stack .macro func_return_\name moveml %sp@+,\saveregs unlk %a6 rts.endm.endm.macro func_return name func_return_\name.endm.macro func_call name jbsr L(\name).endm.macro move_stack nr,arg1,arg2,arg3,arg4.if \nr move_stack "(\nr-1)",\arg2,\arg3,\arg4 movel \arg1,%sp@-.endif.endm.macro func_define name,nr=0.macro \name arg1,arg2,arg3,arg4 move_stack \nr,\arg1,\arg2,\arg3,\arg4 func_call \name.if \nr lea %sp@(\nr*4),%sp.endif.endm.endmfunc_define mmu_map,4func_define mmu_map_tt,4func_define mmu_fixup_page_mmu_cache,1func_define mmu_temp_map,2func_define mmu_engagefunc_define mmu_get_root_table_entry,1func_define mmu_get_ptr_table_entry,2func_define mmu_get_page_table_entry,2func_define mmu_printfunc_define get_new_page#ifdef CONFIG_HP300func_define set_leds#endif.macro mmu_map_eq arg1,arg2,arg3 mmu_map \arg1,\arg1,\arg2,\arg3.endm.macro get_bi_record record pea \record func_call get_bi_record addql #4,%sp.endmfunc_define serial_putc,1func_define console_putc,1.macro putc ch#if defined(CONSOLE) || defined(SERIAL_DEBUG) pea \ch#endif#ifdef CONSOLE func_call console_putc#endif#ifdef SERIAL_DEBUG func_call serial_putc#endif#if defined(CONSOLE) || defined(SERIAL_DEBUG) addql #4,%sp#endif.endm.macro dputc ch#ifdef DEBUG putc \ch#endif.endmfunc_define putn,1.macro dputn nr#ifdef DEBUG putn \nr#endif.endm.macro puts string#if defined(CONSOLE) || defined(SERIAL_DEBUG) __INITDATA.Lstr\@: .string "\string" __FINIT pea %pc@(.Lstr\@) func_call puts addql #4,%sp#endif.endm.macro dputs string#ifdef DEBUG puts "\string"#endif.endm#define is_not_amiga(lab) cmpl &MACH_AMIGA,%pc@(m68k_machtype); jne lab#define is_not_atari(lab) cmpl &MACH_ATARI,%pc@(m68k_machtype); jne lab#define is_not_mac(lab) cmpl &MACH_MAC,%pc@(m68k_machtype); jne lab#define is_not_mvme147(lab) cmpl &MACH_MVME147,%pc@(m68k_machtype); jne lab#define is_not_mvme16x(lab) cmpl &MACH_MVME16x,%pc@(m68k_machtype); jne lab#define is_not_bvme6000(lab) cmpl &MACH_BVME6000,%pc@(m68k_machtype); jne lab#define is_mvme147(lab) cmpl &MACH_MVME147,%pc@(m68k_machtype); jeq lab#define is_mvme16x(lab) cmpl &MACH_MVME16x,%pc@(m68k_machtype); jeq lab#define is_bvme6000(lab) cmpl &MACH_BVME6000,%pc@(m68k_machtype); jeq lab#define is_not_hp300(lab) cmpl &MACH_HP300,%pc@(m68k_machtype); jne lab#define is_not_apollo(lab) cmpl &MACH_APOLLO,%pc@(m68k_machtype); jne lab#define is_not_q40(lab) cmpl &MACH_Q40,%pc@(m68k_machtype); jne lab#define is_not_sun3x(lab) cmpl &MACH_SUN3X,%pc@(m68k_machtype); jne lab
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -